diffprism 1.3.3 → 1.4.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 +6 -2
- package/dist/bin.js +42 -35
- package/dist/{chunk-4PXCENR6.js → chunk-GF455BBV.js} +2 -2
- package/dist/{chunk-3GMPE2ZR.js → chunk-GGK6TIQZ.js} +22 -0
- package/dist/{chunk-EPU4F7WT.js → chunk-RFDSC6MC.js} +1 -1
- package/dist/{chunk-UWIDAULW.js → chunk-YGUHES4P.js} +56 -41
- package/dist/{demo-WOT5AZBP.js → demo-F47GIDSV.js} +3 -3
- package/dist/mcp-server.js +11 -6
- package/dist/{src-DNNNQ2RD.js → src-LLACFIIT.js} +2 -2
- package/dist/{src-OZQ32NDN.js → src-XT4XP6TC.js} +3 -1
- package/package.json +2 -1
- package/ui-dist/assets/index-C_mA2r7X.js +350 -0
- package/ui-dist/assets/index-DrWM7I5e.css +1 -0
- package/ui-dist/index.html +2 -2
- package/ui-dist/assets/index-BulxhOr3.css +0 -1
- package/ui-dist/assets/index-DPjdYQ0h.js +0 -345
package/README.md
CHANGED
|
@@ -89,7 +89,7 @@ Reviews are **one per repo**: opening a review for a repo that already has one u
|
|
|
89
89
|
|
|
90
90
|
In a local review, **Ask agent now** in a line's comment form asks the agent while you're still reviewing: the agent's wait for your decision ends with your question, it answers in the thread, and goes back to waiting.
|
|
91
91
|
|
|
92
|
-
PR reviews are opened with `diffprism review <PR URL>` or the dashboard — not by `open_review` — and your AI then works inside them with the tools above. Click a line to ask the agent about it; an agent listening with `wait_for_comments` answers in the thread.
|
|
92
|
+
PR reviews are opened with `diffprism review <PR URL>` or the dashboard — not by `open_review` — and your AI then works inside them with the tools above. Click a line to ask the agent about it; an agent listening with `wait_for_comments` answers in the thread. Nothing starts an agent for you: if none has picked a question up, the thread says so and names the session to ask Claude Code about.
|
|
93
93
|
|
|
94
94
|
When you're done, **Approve**, **Request changes** or **Comment** from the bar at the bottom: DiffPrism posts it to GitHub as a pull request review. Your threads are a conversation with the agent, so none of them goes to GitHub unless you tick it; a ticked thread posts your opening message as an inline review comment. The token comes from `GITHUB_TOKEN`, `gh auth token`, or `~/.diffprism/config.json`.
|
|
95
95
|
|
|
@@ -113,7 +113,7 @@ DiffPrism also works for reviewing local agent-generated changes:
|
|
|
113
113
|
```bash
|
|
114
114
|
diffprism review # Review all changes (staged + unstaged)
|
|
115
115
|
diffprism review --staged # Staged changes only
|
|
116
|
-
diffprism review HEAD~3
|
|
116
|
+
diffprism review HEAD~3..HEAD # Last 3 commits
|
|
117
117
|
diffprism review main..feature # Branch diff
|
|
118
118
|
```
|
|
119
119
|
|
|
@@ -181,6 +181,7 @@ skill tells them so.
|
|
|
181
181
|
## CLI Reference
|
|
182
182
|
|
|
183
183
|
```bash
|
|
184
|
+
diffprism demo # Open a sample review
|
|
184
185
|
diffprism review <ref> # Open a review (PR URL, git ref, or flags)
|
|
185
186
|
diffprism setup # Configure Claude Code integration
|
|
186
187
|
diffprism setup --global # Global setup (no git repo needed)
|
|
@@ -189,10 +190,12 @@ diffprism server status # Check server status
|
|
|
189
190
|
diffprism server stop # Stop the server
|
|
190
191
|
diffprism hook install # Gate commits on a review
|
|
191
192
|
diffprism hook uninstall # Remove the gate
|
|
193
|
+
diffprism hook pre-commit # Run the gate (what the installed hook calls)
|
|
192
194
|
diffprism reply --session <id> <annotation-id> "…" # Answer a reviewer's question, as the agent
|
|
193
195
|
diffprism feedback # Share feedback as a prefilled GitHub issue
|
|
194
196
|
diffprism feedback --bug # Report a bug, including the last error
|
|
195
197
|
diffprism teardown # Remove configuration
|
|
198
|
+
diffprism serve # Run the MCP server over stdio (your MCP client launches this)
|
|
196
199
|
```
|
|
197
200
|
|
|
198
201
|
## Feedback
|
|
@@ -215,6 +218,7 @@ cd diffprism
|
|
|
215
218
|
pnpm install
|
|
216
219
|
pnpm test
|
|
217
220
|
pnpm run build
|
|
221
|
+
pnpm docs:check # Fail if docs disagree with the code (runs in CI)
|
|
218
222
|
pnpm cli review --staged # Run CLI from source
|
|
219
223
|
```
|
|
220
224
|
|
package/dist/bin.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
isPrRef,
|
|
4
4
|
parsePrRef
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-RFDSC6MC.js";
|
|
6
6
|
import {
|
|
7
7
|
demo
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-GF455BBV.js";
|
|
9
9
|
import {
|
|
10
10
|
COMMIT_GATE_DIFF_REF,
|
|
11
11
|
DEFAULT_DIFF_REF,
|
|
@@ -26,14 +26,14 @@ import {
|
|
|
26
26
|
recordError,
|
|
27
27
|
startGlobalServer,
|
|
28
28
|
submitReviewToServer
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-YGUHES4P.js";
|
|
30
30
|
import {
|
|
31
31
|
getDiff
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-GGK6TIQZ.js";
|
|
33
33
|
import "./chunk-DHCVZGHE.js";
|
|
34
34
|
import "./chunk-JSBRDJBE.js";
|
|
35
35
|
|
|
36
|
-
// cli/src/
|
|
36
|
+
// cli/src/program.ts
|
|
37
37
|
import { Command } from "commander";
|
|
38
38
|
|
|
39
39
|
// cli/src/commands/hook.ts
|
|
@@ -518,6 +518,8 @@ The reviewer can also ask you questions on lines of the PR. Hold that conversati
|
|
|
518
518
|
2. \`mcp__diffprism__reply\` \u2014 answer each thread, passing its \`annotation_id\`.
|
|
519
519
|
3. Wait again. On \`timed_out\`, nothing new was said \u2014 keep waiting until the user tells you to stop.
|
|
520
520
|
|
|
521
|
+
When no agent has read a question, the dashboard tells the reviewer so, and to ask you to answer their DiffPrism comments on a session id. When they do, run this loop with that \`session_id\`.
|
|
522
|
+
|
|
521
523
|
A PR review and a working-copy review can be open for the same clone at once. If a tool reports more than one session, pass the \`session_id\` of the one you mean.
|
|
522
524
|
|
|
523
525
|
## Tool Reference
|
|
@@ -719,7 +721,7 @@ async function setupInteractive(flags) {
|
|
|
719
721
|
}
|
|
720
722
|
async function runDemo(dev) {
|
|
721
723
|
console.log("");
|
|
722
|
-
const { demo: demo2 } = await import("./demo-
|
|
724
|
+
const { demo: demo2 } = await import("./demo-F47GIDSV.js");
|
|
723
725
|
await demo2({ dev });
|
|
724
726
|
}
|
|
725
727
|
async function setupBatch(flags) {
|
|
@@ -1216,33 +1218,38 @@ ${url}`
|
|
|
1216
1218
|
}
|
|
1217
1219
|
}
|
|
1218
1220
|
|
|
1221
|
+
// cli/src/program.ts
|
|
1222
|
+
function createProgram() {
|
|
1223
|
+
const program = new Command();
|
|
1224
|
+
program.name("diffprism").description("Local-first code review tool for agent-generated changes").version(describeVersion(currentVersion()));
|
|
1225
|
+
program.action(defaultAction);
|
|
1226
|
+
program.command("demo").description("Open a sample review to see DiffPrism in action").option("--dev", "Use Vite dev server").action(demo);
|
|
1227
|
+
program.command("review [ref]").description("Open a browser-based diff review (local git ref or GitHub PR ref like owner/repo#123)").option("--staged", "Review staged changes").option("--unstaged", "Review unstaged changes").option("-t, --title <title>", "Review title").option("--reasoning <text>", "Agent reasoning about the changes").option("--dev", "Use Vite dev server with HMR instead of static files").option("--post-to-github", "Automatically post review back to GitHub without prompting").action(review);
|
|
1228
|
+
program.command("review-pr <pr>", { hidden: true }).action((pr, flags) => review(pr, flags));
|
|
1229
|
+
const hookCmd = program.command("hook").description("Git hook integration \u2014 gate commits on a human review");
|
|
1230
|
+
hookCmd.command("pre-commit").description("Run the review gate for the staged changes (called from a git hook)").option("--min-lines <n>", "Staged lines required to trigger a review (default: 120)").option("--dev", "Use Vite dev server").action((flags) => {
|
|
1231
|
+
void preCommitHook(flags);
|
|
1232
|
+
});
|
|
1233
|
+
hookCmd.command("install").description("Add the diffprism gate to this repo's pre-commit hook").action(() => {
|
|
1234
|
+
installHook();
|
|
1235
|
+
});
|
|
1236
|
+
hookCmd.command("uninstall").description("Remove the diffprism gate from this repo's pre-commit hook").action(() => {
|
|
1237
|
+
uninstallHook();
|
|
1238
|
+
});
|
|
1239
|
+
program.command("feedback").description("Open a prefilled GitHub issue to share feedback or report a bug \u2014 you review it before anything is sent").option("--bug", "Report a bug, including the last error DiffPrism hit").option("-m, --message <text>", "Start the issue with this text").option("--print", "Print the issue URL instead of opening a browser").action((flags) => feedback(flags));
|
|
1240
|
+
program.command("reply <annotation-id> <message...>").description("Answer a reviewer's question on an open review, as the agent").requiredOption("--session <id>", "The review the question is on").option("--agent <name>", "Name shown on the reply", "agent").action((annotationId, message2, flags) => reply(annotationId, message2, flags));
|
|
1241
|
+
program.command("serve").description("Start the MCP server for Claude Code integration").action(serve);
|
|
1242
|
+
program.command("setup").description("Configure DiffPrism for Claude Code integration").option("--global", "Configure globally (skill + permissions, no git repo required)").option("--force", "Overwrite existing configuration files").option("--dev", "Use Vite dev server").option("--no-demo", "Skip the demo review after setup").action((flags) => {
|
|
1243
|
+
setup(flags);
|
|
1244
|
+
});
|
|
1245
|
+
program.command("teardown").description("Remove DiffPrism configuration from the current project").option("--global", "Remove global configuration (skill + permissions at ~/.claude/)").option("-q, --quiet", "Suppress output").action((flags) => {
|
|
1246
|
+
teardown(flags);
|
|
1247
|
+
});
|
|
1248
|
+
const serverCmd = program.command("server").description("Start the global DiffPrism server for multi-session reviews").option("-p, --port <port>", "HTTP API port (default: 24680)").option("--ws-port <port>", "WebSocket port (default: 24681)").option("--dev", "Use Vite dev server with HMR instead of static files").option("--background", "Start server as a background daemon").option("--_daemon", "Internal: run as spawned daemon (do not use directly)").action(server);
|
|
1249
|
+
serverCmd.command("status").description("Check if the global server is running and list active sessions").action(serverStatus);
|
|
1250
|
+
serverCmd.command("stop").description("Stop the running global server").action(serverStop);
|
|
1251
|
+
return program;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1219
1254
|
// cli/src/index.ts
|
|
1220
|
-
|
|
1221
|
-
program.name("diffprism").description("Local-first code review tool for agent-generated changes").version(describeVersion(currentVersion()));
|
|
1222
|
-
program.action(defaultAction);
|
|
1223
|
-
program.command("demo").description("Open a sample review to see DiffPrism in action").option("--dev", "Use Vite dev server").action(demo);
|
|
1224
|
-
program.command("review [ref]").description("Open a browser-based diff review (local git ref or GitHub PR ref like owner/repo#123)").option("--staged", "Review staged changes").option("--unstaged", "Review unstaged changes").option("-t, --title <title>", "Review title").option("--reasoning <text>", "Agent reasoning about the changes").option("--dev", "Use Vite dev server with HMR instead of static files").option("--post-to-github", "Automatically post review back to GitHub without prompting").action(review);
|
|
1225
|
-
program.command("review-pr <pr>", { hidden: true }).action((pr, flags) => review(pr, flags));
|
|
1226
|
-
var hookCmd = program.command("hook").description("Git hook integration \u2014 gate commits on a human review");
|
|
1227
|
-
hookCmd.command("pre-commit").description("Run the review gate for the staged changes (called from a git hook)").option("--min-lines <n>", "Staged lines required to trigger a review (default: 120)").option("--dev", "Use Vite dev server").action((flags) => {
|
|
1228
|
-
void preCommitHook(flags);
|
|
1229
|
-
});
|
|
1230
|
-
hookCmd.command("install").description("Add the diffprism gate to this repo's pre-commit hook").action(() => {
|
|
1231
|
-
installHook();
|
|
1232
|
-
});
|
|
1233
|
-
hookCmd.command("uninstall").description("Remove the diffprism gate from this repo's pre-commit hook").action(() => {
|
|
1234
|
-
uninstallHook();
|
|
1235
|
-
});
|
|
1236
|
-
program.command("feedback").description("Open a prefilled GitHub issue to share feedback or report a bug \u2014 you review it before anything is sent").option("--bug", "Report a bug, including the last error DiffPrism hit").option("-m, --message <text>", "Start the issue with this text").option("--print", "Print the issue URL instead of opening a browser").action((flags) => feedback(flags));
|
|
1237
|
-
program.command("reply <annotation-id> <message...>").description("Answer a reviewer's question on an open review, as the agent").requiredOption("--session <id>", "The review the question is on").option("--agent <name>", "Name shown on the reply", "agent").action((annotationId, message2, flags) => reply(annotationId, message2, flags));
|
|
1238
|
-
program.command("serve").description("Start the MCP server for Claude Code integration").action(serve);
|
|
1239
|
-
program.command("setup").description("Configure DiffPrism for Claude Code integration").option("--global", "Configure globally (skill + permissions, no git repo required)").option("--force", "Overwrite existing configuration files").option("--dev", "Use Vite dev server").option("--no-demo", "Skip the demo review after setup").action((flags) => {
|
|
1240
|
-
setup(flags);
|
|
1241
|
-
});
|
|
1242
|
-
program.command("teardown").description("Remove DiffPrism configuration from the current project").option("--global", "Remove global configuration (skill + permissions at ~/.claude/)").option("-q, --quiet", "Suppress output").action((flags) => {
|
|
1243
|
-
teardown(flags);
|
|
1244
|
-
});
|
|
1245
|
-
var serverCmd = program.command("server").description("Start the global DiffPrism server for multi-session reviews").option("-p, --port <port>", "HTTP API port (default: 24680)").option("--ws-port <port>", "WebSocket port (default: 24681)").option("--dev", "Use Vite dev server with HMR instead of static files").option("--background", "Start server as a background daemon").option("--_daemon", "Internal: run as spawned daemon (do not use directly)").action(server);
|
|
1246
|
-
serverCmd.command("status").description("Check if the global server is running and list active sessions").action(serverStatus);
|
|
1247
|
-
serverCmd.command("stop").description("Stop the running global server").action(serverStop);
|
|
1248
|
-
program.parse();
|
|
1255
|
+
createProgram().parse();
|
|
@@ -210,6 +210,27 @@ function getRepoRoot(options) {
|
|
|
210
210
|
return null;
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
|
+
function getGitHubRemotes(options) {
|
|
214
|
+
const cwd = options?.cwd ?? process.cwd();
|
|
215
|
+
let output;
|
|
216
|
+
try {
|
|
217
|
+
output = execSync("git remote -v", {
|
|
218
|
+
cwd,
|
|
219
|
+
encoding: "utf-8",
|
|
220
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
221
|
+
});
|
|
222
|
+
} catch {
|
|
223
|
+
return [];
|
|
224
|
+
}
|
|
225
|
+
const repos = /* @__PURE__ */ new Set();
|
|
226
|
+
for (const line of output.split("\n")) {
|
|
227
|
+
const match = /github\.com[:/]([^/\s]+)\/([^/\s]+?)(?:\.git)?\s/i.exec(line);
|
|
228
|
+
if (match) {
|
|
229
|
+
repos.add(`${match[1]}/${match[2]}`.toLowerCase());
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return Array.from(repos);
|
|
233
|
+
}
|
|
213
234
|
|
|
214
235
|
// packages/git/src/parser.ts
|
|
215
236
|
import path2 from "path";
|
|
@@ -456,6 +477,7 @@ export {
|
|
|
456
477
|
listCommits,
|
|
457
478
|
detectWorktree,
|
|
458
479
|
getRepoRoot,
|
|
480
|
+
getGitHubRemotes,
|
|
459
481
|
parseDiff,
|
|
460
482
|
getDiff
|
|
461
483
|
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getCurrentBranch,
|
|
3
3
|
getDiff,
|
|
4
|
+
getGitHubRemotes,
|
|
4
5
|
getRepoRoot,
|
|
5
6
|
listBranches,
|
|
6
7
|
listCommits
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-GGK6TIQZ.js";
|
|
8
9
|
import {
|
|
9
10
|
analyze
|
|
10
11
|
} from "./chunk-DHCVZGHE.js";
|
|
@@ -79,12 +80,38 @@ async function isServerAlive() {
|
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
|
|
83
|
+
// packages/core/src/threads.ts
|
|
84
|
+
function lastAuthor(annotation) {
|
|
85
|
+
const replies = annotation.replies ?? [];
|
|
86
|
+
return replies.length > 0 ? replies[replies.length - 1].author : annotation.author ?? "agent";
|
|
87
|
+
}
|
|
88
|
+
function awaitingAgent(annotation) {
|
|
89
|
+
return !annotation.dismissed && lastAuthor(annotation) === "reviewer";
|
|
90
|
+
}
|
|
91
|
+
function lastMessageAt(annotation) {
|
|
92
|
+
const replies = annotation.replies ?? [];
|
|
93
|
+
return replies.length > 0 ? replies[replies.length - 1].createdAt : annotation.createdAt;
|
|
94
|
+
}
|
|
95
|
+
function pickedUpByAgent(annotation, agentReadAt) {
|
|
96
|
+
return agentReadAt !== void 0 && agentReadAt > lastMessageAt(annotation);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// packages/core/src/diff-scope.ts
|
|
100
|
+
var DEFAULT_DIFF_REF = "working-copy";
|
|
101
|
+
var COMMIT_GATE_DIFF_REF = "staged";
|
|
102
|
+
var DIFF_REF_DESCRIPTION = 'Which changes to review. "working-copy" (the default): everything not yet committed, staged and unstaged shown as separate groups. "staged": only what the next commit would contain. "unstaged": only edits not yet staged. Or a ref range such as "HEAD~3..HEAD" or "main..feature".';
|
|
103
|
+
|
|
104
|
+
// packages/core/src/feedback.ts
|
|
105
|
+
import fs3 from "fs";
|
|
106
|
+
import os2 from "os";
|
|
107
|
+
import path3 from "path";
|
|
108
|
+
|
|
82
109
|
// packages/core/src/build-info.ts
|
|
83
110
|
import fs2 from "fs";
|
|
84
111
|
import path2 from "path";
|
|
85
112
|
import { fileURLToPath } from "url";
|
|
86
113
|
function builtAt() {
|
|
87
|
-
return true ?
|
|
114
|
+
return true ? 1789619886717 : null;
|
|
88
115
|
}
|
|
89
116
|
function getBuildInfo() {
|
|
90
117
|
let dir = path2.dirname(fileURLToPath(import.meta.url));
|
|
@@ -110,19 +137,11 @@ function describeVersion(version) {
|
|
|
110
137
|
return info.dev ? `${version} (dev build \u2014 ${info.root})` : version;
|
|
111
138
|
}
|
|
112
139
|
|
|
113
|
-
// packages/core/src/diff-scope.ts
|
|
114
|
-
var DEFAULT_DIFF_REF = "working-copy";
|
|
115
|
-
var COMMIT_GATE_DIFF_REF = "staged";
|
|
116
|
-
var DIFF_REF_DESCRIPTION = 'Which changes to review. "working-copy" (the default): everything not yet committed, staged and unstaged shown as separate groups. "staged": only what the next commit would contain. "unstaged": only edits not yet staged. Or a ref range such as "HEAD~3..HEAD" or "main..feature".';
|
|
117
|
-
|
|
118
140
|
// packages/core/src/feedback.ts
|
|
119
|
-
import fs3 from "fs";
|
|
120
|
-
import os2 from "os";
|
|
121
|
-
import path3 from "path";
|
|
122
141
|
var ISSUES_NEW_URL = "https://github.com/CodeJonesW/diffprism/issues/new";
|
|
123
142
|
var MAX_ERROR_CHARS = 1500;
|
|
124
143
|
function currentVersion() {
|
|
125
|
-
return true ? "1.
|
|
144
|
+
return true ? "1.4.1" : "0.0.0-dev";
|
|
126
145
|
}
|
|
127
146
|
function describeEnvironment() {
|
|
128
147
|
return {
|
|
@@ -211,15 +230,6 @@ ${errorText}
|
|
|
211
230
|
return `${ISSUES_NEW_URL}?${params.toString()}`;
|
|
212
231
|
}
|
|
213
232
|
|
|
214
|
-
// packages/core/src/threads.ts
|
|
215
|
-
function lastAuthor(annotation) {
|
|
216
|
-
const replies = annotation.replies ?? [];
|
|
217
|
-
return replies.length > 0 ? replies[replies.length - 1].author : annotation.author ?? "agent";
|
|
218
|
-
}
|
|
219
|
-
function awaitingAgent(annotation) {
|
|
220
|
-
return !annotation.dismissed && lastAuthor(annotation) === "reviewer";
|
|
221
|
-
}
|
|
222
|
-
|
|
223
233
|
// packages/core/src/server-client.ts
|
|
224
234
|
import { spawn } from "child_process";
|
|
225
235
|
import fs4 from "fs";
|
|
@@ -393,7 +403,7 @@ async function waitForDecision(serverInfo, sessionId, maxWaitMs, pollIntervalMs
|
|
|
393
403
|
if (result) {
|
|
394
404
|
return result;
|
|
395
405
|
}
|
|
396
|
-
const annotationsResponse = await fetch(`${base}/annotations`);
|
|
406
|
+
const annotationsResponse = await fetch(`${base}/annotations?reader=agent`);
|
|
397
407
|
if (!annotationsResponse.ok) {
|
|
398
408
|
throw new Error(`Could not read threads for ${sessionId}: server returned ${annotationsResponse.status}`);
|
|
399
409
|
}
|
|
@@ -413,7 +423,7 @@ async function submitReviewToServer(serverInfo, diffRef, options = {}) {
|
|
|
413
423
|
if (options.injectedPayload) {
|
|
414
424
|
payload = options.injectedPayload;
|
|
415
425
|
} else {
|
|
416
|
-
const { getDiff: getDiff2, getCurrentBranch: getCurrentBranch2, detectWorktree } = await import("./src-
|
|
426
|
+
const { getDiff: getDiff2, getCurrentBranch: getCurrentBranch2, detectWorktree } = await import("./src-XT4XP6TC.js");
|
|
417
427
|
const { analyze: analyze2 } = await import("./src-JMPTSU3P.js");
|
|
418
428
|
const { diffSet, rawDiff } = getDiff2(diffRef, { cwd });
|
|
419
429
|
if (diffSet.files.length === 0) {
|
|
@@ -800,6 +810,14 @@ var IDLE_SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
|
800
810
|
function touch(session) {
|
|
801
811
|
session.lastActivityAt = Date.now();
|
|
802
812
|
}
|
|
813
|
+
function recordAgentRead(session) {
|
|
814
|
+
const previous = session.agentReadAt;
|
|
815
|
+
session.agentReadAt = Date.now();
|
|
816
|
+
touch(session);
|
|
817
|
+
if (session.annotations.some((a) => awaitingAgent(a) && !pickedUpByAgent(a, previous))) {
|
|
818
|
+
broadcastSessionUpdate(session);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
803
821
|
var sessions = /* @__PURE__ */ new Map();
|
|
804
822
|
function listedSummaries() {
|
|
805
823
|
return Array.from(sessions.values()).filter((session) => session.closedAt === void 0).map(toSummary);
|
|
@@ -943,7 +961,8 @@ function toSummary(session) {
|
|
|
943
961
|
hasNewChanges: session.hasNewChanges,
|
|
944
962
|
needsAttention: needsAttention(session),
|
|
945
963
|
diffRef: session.diffRef,
|
|
946
|
-
source: session.source
|
|
964
|
+
source: session.source,
|
|
965
|
+
agentReadAt: session.agentReadAt
|
|
947
966
|
};
|
|
948
967
|
}
|
|
949
968
|
function readBody(req) {
|
|
@@ -1260,7 +1279,7 @@ async function handleApiRequest(req, res) {
|
|
|
1260
1279
|
fetchPullRequest,
|
|
1261
1280
|
fetchPullRequestDiff,
|
|
1262
1281
|
normalizePr
|
|
1263
|
-
} = await import("./src-
|
|
1282
|
+
} = await import("./src-LLACFIIT.js");
|
|
1264
1283
|
if (!isPrRef(prUrl)) {
|
|
1265
1284
|
jsonResponse(res, 400, {
|
|
1266
1285
|
error: "Invalid PR URL. Expected https://github.com/owner/repo/pull/123 or owner/repo#123"
|
|
@@ -1283,20 +1302,7 @@ async function handleApiRequest(req, res) {
|
|
|
1283
1302
|
fetchPullRequestDiff(client, owner, repo, prNumber)
|
|
1284
1303
|
]);
|
|
1285
1304
|
const normalized = normalizePr(rawDiff, prMetadata);
|
|
1286
|
-
|
|
1287
|
-
try {
|
|
1288
|
-
const { execSync } = await import("child_process");
|
|
1289
|
-
const remoteOutput = execSync("git remote -v", {
|
|
1290
|
-
cwd: process.cwd(),
|
|
1291
|
-
encoding: "utf-8",
|
|
1292
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
1293
|
-
});
|
|
1294
|
-
const repoPattern = new RegExp(`github\\.com[:/]${owner}/${repo}(\\.git)?\\s`, "i");
|
|
1295
|
-
if (repoPattern.test(remoteOutput)) {
|
|
1296
|
-
localRepoPath = process.cwd();
|
|
1297
|
-
}
|
|
1298
|
-
} catch {
|
|
1299
|
-
}
|
|
1305
|
+
const localRepoPath = getGitHubRemotes({ cwd: process.cwd() }).includes(`${owner}/${repo}`.toLowerCase()) ? process.cwd() : null;
|
|
1300
1306
|
const { session, reused } = openSession({
|
|
1301
1307
|
key: `pr:${owner}/${repo}#${prNumber}`.toLowerCase(),
|
|
1302
1308
|
repoRoot: localRepoPath ? getRepoRoot({ cwd: localRepoPath }) ?? localRepoPath : null,
|
|
@@ -1373,7 +1379,13 @@ async function handleApiRequest(req, res) {
|
|
|
1373
1379
|
return true;
|
|
1374
1380
|
}
|
|
1375
1381
|
const repoRoot = getRepoRoot({ cwd: rawPath }) ?? path7.resolve(rawPath);
|
|
1376
|
-
const
|
|
1382
|
+
const remotes = getGitHubRemotes({ cwd: repoRoot });
|
|
1383
|
+
const matches = Array.from(sessions.values()).filter((session) => {
|
|
1384
|
+
if (session.closedAt !== void 0) return false;
|
|
1385
|
+
if (session.repoRoot === repoRoot) return true;
|
|
1386
|
+
const pr = session.payload.metadata.githubPr;
|
|
1387
|
+
return pr !== void 0 && remotes.includes(`${pr.owner}/${pr.repo}`.toLowerCase());
|
|
1388
|
+
}).map(toSummary);
|
|
1377
1389
|
jsonResponse(res, 200, { repoRoot, sessions: matches });
|
|
1378
1390
|
return true;
|
|
1379
1391
|
}
|
|
@@ -1527,6 +1539,9 @@ async function handleApiRequest(req, res) {
|
|
|
1527
1539
|
jsonResponse(res, 404, { error: "Session not found" });
|
|
1528
1540
|
return true;
|
|
1529
1541
|
}
|
|
1542
|
+
if (new URL(req.url ?? "/", "http://localhost").searchParams.get("reader") === "agent") {
|
|
1543
|
+
recordAgentRead(session);
|
|
1544
|
+
}
|
|
1530
1545
|
jsonResponse(res, 200, { annotations: session.annotations });
|
|
1531
1546
|
return true;
|
|
1532
1547
|
}
|
|
@@ -1592,7 +1607,7 @@ async function handleApiRequest(req, res) {
|
|
|
1592
1607
|
jsonResponse(res, 400, { error: built.error });
|
|
1593
1608
|
return true;
|
|
1594
1609
|
}
|
|
1595
|
-
const { resolveGitHubToken, createGitHubClient, submitGitHubReview } = await import("./src-
|
|
1610
|
+
const { resolveGitHubToken, createGitHubClient, submitGitHubReview } = await import("./src-LLACFIIT.js");
|
|
1596
1611
|
let token;
|
|
1597
1612
|
try {
|
|
1598
1613
|
token = resolveGitHubToken();
|
|
@@ -2072,6 +2087,7 @@ function mcpToolPermission(name) {
|
|
|
2072
2087
|
export {
|
|
2073
2088
|
readServerFile,
|
|
2074
2089
|
isServerAlive,
|
|
2090
|
+
awaitingAgent,
|
|
2075
2091
|
getBuildInfo,
|
|
2076
2092
|
describeVersion,
|
|
2077
2093
|
DEFAULT_DIFF_REF,
|
|
@@ -2083,7 +2099,6 @@ export {
|
|
|
2083
2099
|
REPORT_HINT,
|
|
2084
2100
|
buildFeedbackUrl,
|
|
2085
2101
|
startGlobalServer,
|
|
2086
|
-
awaitingAgent,
|
|
2087
2102
|
ensureServer,
|
|
2088
2103
|
ReviewTimeoutError,
|
|
2089
2104
|
ReviewerAskedError,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
demo
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-GF455BBV.js";
|
|
4
|
+
import "./chunk-YGUHES4P.js";
|
|
5
|
+
import "./chunk-GGK6TIQZ.js";
|
|
6
6
|
import "./chunk-DHCVZGHE.js";
|
|
7
7
|
import "./chunk-JSBRDJBE.js";
|
|
8
8
|
export {
|
package/dist/mcp-server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isPrRef
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-RFDSC6MC.js";
|
|
4
4
|
import {
|
|
5
5
|
DEFAULT_DIFF_REF,
|
|
6
6
|
DIFF_REF_DESCRIPTION,
|
|
@@ -14,10 +14,10 @@ import {
|
|
|
14
14
|
recordError,
|
|
15
15
|
submitReviewToServer,
|
|
16
16
|
waitForDecision
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-YGUHES4P.js";
|
|
18
18
|
import {
|
|
19
19
|
getDiff
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-GGK6TIQZ.js";
|
|
21
21
|
import {
|
|
22
22
|
analyze
|
|
23
23
|
} from "./chunk-DHCVZGHE.js";
|
|
@@ -73,7 +73,7 @@ ${candidates}`
|
|
|
73
73
|
}
|
|
74
74
|
async function readThreads(serverInfo, sessionId) {
|
|
75
75
|
const response = await fetch(
|
|
76
|
-
`http://localhost:${serverInfo.httpPort}/api/reviews/${sessionId}/annotations`
|
|
76
|
+
`http://localhost:${serverInfo.httpPort}/api/reviews/${sessionId}/annotations?reader=agent`
|
|
77
77
|
);
|
|
78
78
|
if (!response.ok) {
|
|
79
79
|
return null;
|
|
@@ -124,7 +124,7 @@ var annotationSchema = z.object({
|
|
|
124
124
|
"other"
|
|
125
125
|
]).optional().describe("Category of the finding (defaults to 'other')")
|
|
126
126
|
});
|
|
127
|
-
|
|
127
|
+
function createMcpServer() {
|
|
128
128
|
const server = new McpServer({
|
|
129
129
|
name: "diffprism",
|
|
130
130
|
version: currentVersion()
|
|
@@ -354,7 +354,7 @@ ${REPORT_HINT}`);
|
|
|
354
354
|
async ({ session_id, repo_path }) => withSession({ session_id, repo_path }, async ({ serverInfo, sessionId }) => {
|
|
355
355
|
const [sessionResponse, annotationsResponse] = await Promise.all([
|
|
356
356
|
fetch(`http://localhost:${serverInfo.httpPort}/api/reviews/${sessionId}`),
|
|
357
|
-
fetch(`http://localhost:${serverInfo.httpPort}/api/reviews/${sessionId}/annotations`)
|
|
357
|
+
fetch(`http://localhost:${serverInfo.httpPort}/api/reviews/${sessionId}/annotations?reader=agent`)
|
|
358
358
|
]);
|
|
359
359
|
if (!sessionResponse.ok) {
|
|
360
360
|
return toolError(`Session not found: ${sessionId}`);
|
|
@@ -568,11 +568,16 @@ ${available.join("\n")}`);
|
|
|
568
568
|
});
|
|
569
569
|
})
|
|
570
570
|
);
|
|
571
|
+
return server;
|
|
572
|
+
}
|
|
573
|
+
async function startMcpServer() {
|
|
574
|
+
const server = createMcpServer();
|
|
571
575
|
const transport = new StdioServerTransport();
|
|
572
576
|
await server.connect(transport);
|
|
573
577
|
}
|
|
574
578
|
export {
|
|
575
579
|
DEFAULT_WAIT_MS,
|
|
580
|
+
createMcpServer,
|
|
576
581
|
resolveTarget,
|
|
577
582
|
startMcpServer
|
|
578
583
|
};
|
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
parsePrRef,
|
|
8
8
|
resolveGitHubToken,
|
|
9
9
|
submitGitHubReview
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-RFDSC6MC.js";
|
|
11
|
+
import "./chunk-GGK6TIQZ.js";
|
|
12
12
|
import "./chunk-DHCVZGHE.js";
|
|
13
13
|
import "./chunk-JSBRDJBE.js";
|
|
14
14
|
export {
|
|
@@ -3,17 +3,19 @@ import {
|
|
|
3
3
|
getCurrentBranch,
|
|
4
4
|
getDiff,
|
|
5
5
|
getGitDiff,
|
|
6
|
+
getGitHubRemotes,
|
|
6
7
|
getRepoRoot,
|
|
7
8
|
listBranches,
|
|
8
9
|
listCommits,
|
|
9
10
|
parseDiff
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-GGK6TIQZ.js";
|
|
11
12
|
import "./chunk-JSBRDJBE.js";
|
|
12
13
|
export {
|
|
13
14
|
detectWorktree,
|
|
14
15
|
getCurrentBranch,
|
|
15
16
|
getDiff,
|
|
16
17
|
getGitDiff,
|
|
18
|
+
getGitHubRemotes,
|
|
17
19
|
getRepoRoot,
|
|
18
20
|
listBranches,
|
|
19
21
|
listCommits,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "diffprism",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Local-first code review tool for agent-generated code changes",
|
|
6
6
|
"bin": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"dev": "pnpm -r run dev",
|
|
17
17
|
"lint": "pnpm -r run lint",
|
|
18
18
|
"test": "pnpm -r run test",
|
|
19
|
+
"docs:check": "pnpm -F diffprism-cli docs:check",
|
|
19
20
|
"cli": "pnpm -F @diffprism/ui build && tsx cli/src/index.ts",
|
|
20
21
|
"prepublishOnly": "pnpm run build"
|
|
21
22
|
},
|