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 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 # Last 3 commits
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-EPU4F7WT.js";
5
+ } from "./chunk-RFDSC6MC.js";
6
6
  import {
7
7
  demo
8
- } from "./chunk-4PXCENR6.js";
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-UWIDAULW.js";
29
+ } from "./chunk-YGUHES4P.js";
30
30
  import {
31
31
  getDiff
32
- } from "./chunk-3GMPE2ZR.js";
32
+ } from "./chunk-GGK6TIQZ.js";
33
33
  import "./chunk-DHCVZGHE.js";
34
34
  import "./chunk-JSBRDJBE.js";
35
35
 
36
- // cli/src/index.ts
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-WOT5AZBP.js");
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
- var program = new Command();
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();
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  ensureServer,
3
3
  submitReviewToServer
4
- } from "./chunk-UWIDAULW.js";
4
+ } from "./chunk-YGUHES4P.js";
5
5
  import {
6
6
  parseDiff
7
- } from "./chunk-3GMPE2ZR.js";
7
+ } from "./chunk-GGK6TIQZ.js";
8
8
  import {
9
9
  analyze
10
10
  } from "./chunk-DHCVZGHE.js";
@@ -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,6 +1,6 @@
1
1
  import {
2
2
  parseDiff
3
- } from "./chunk-3GMPE2ZR.js";
3
+ } from "./chunk-GGK6TIQZ.js";
4
4
  import {
5
5
  analyze
6
6
  } from "./chunk-DHCVZGHE.js";
@@ -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-3GMPE2ZR.js";
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 ? 1789610984376 : null;
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.3.3" : "0.0.0-dev";
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-OZQ32NDN.js");
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-DNNNQ2RD.js");
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
- let localRepoPath = null;
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 matches = Array.from(sessions.values()).filter((session) => session.closedAt === void 0 && session.repoRoot === repoRoot).map(toSummary);
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-DNNNQ2RD.js");
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-4PXCENR6.js";
4
- import "./chunk-UWIDAULW.js";
5
- import "./chunk-3GMPE2ZR.js";
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 {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isPrRef
3
- } from "./chunk-EPU4F7WT.js";
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-UWIDAULW.js";
17
+ } from "./chunk-YGUHES4P.js";
18
18
  import {
19
19
  getDiff
20
- } from "./chunk-3GMPE2ZR.js";
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
- async function startMcpServer() {
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-EPU4F7WT.js";
11
- import "./chunk-3GMPE2ZR.js";
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-3GMPE2ZR.js";
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.3",
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
  },