diffprism 1.2.0 → 1.3.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
|
@@ -218,6 +218,26 @@ pnpm run build
|
|
|
218
218
|
pnpm cli review --staged # Run CLI from source
|
|
219
219
|
```
|
|
220
220
|
|
|
221
|
+
### Dogfooding a checkout
|
|
222
|
+
|
|
223
|
+
To try unreleased changes in another project without publishing, point your global `diffprism` at a checkout:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
git clone https://github.com/CodeJonesW/diffprism.git diffprism-dogfood
|
|
227
|
+
cd diffprism-dogfood && pnpm install && pnpm build && npm link
|
|
228
|
+
diffprism --version # 1.2.0 (dev build — /path/to/diffprism-dogfood)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Then, for each change you want to try:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
git fetch && git checkout <branch> && git pull && pnpm build
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
The next `diffprism` command — a review, the commit gate — replaces the running server with the new build, unless a review is open in it. The dashboard picks up a rebuilt UI on reload. Go back to the release with `npm install -g diffprism@latest`.
|
|
238
|
+
|
|
239
|
+
A server is only ever replaced by a **newer** build. Claude Code keeps `diffprism serve` running on the build it started with until you restart it, so restart Claude Code to put its MCP tools on the new build too.
|
|
240
|
+
|
|
221
241
|
### Project Structure
|
|
222
242
|
|
|
223
243
|
```
|
package/dist/bin.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-EPU4F7WT.js";
|
|
6
6
|
import {
|
|
7
7
|
demo
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-7YL3D42S.js";
|
|
9
9
|
import {
|
|
10
10
|
COMMIT_GATE_DIFF_REF,
|
|
11
11
|
DEFAULT_DIFF_REF,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
recordError,
|
|
27
27
|
startGlobalServer,
|
|
28
28
|
submitReviewToServer
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-MSNGZDVF.js";
|
|
30
30
|
import {
|
|
31
31
|
getDiff
|
|
32
32
|
} from "./chunk-3GMPE2ZR.js";
|
|
@@ -79,6 +79,9 @@ ${REPORT_HINT}`);
|
|
|
79
79
|
}
|
|
80
80
|
const where = data.annotation ? ` on ${data.annotation.file}:${data.annotation.line}` : "";
|
|
81
81
|
console.log(`Replied${where}. It shows in the review now.`);
|
|
82
|
+
console.log(
|
|
83
|
+
"The review is still open. Go back to waiting for the decision now: run the same command that opened it again (`git commit` or `diffprism review`). It returns the decision, or the reviewer's next question. Don't ask them in the terminal."
|
|
84
|
+
);
|
|
82
85
|
}
|
|
83
86
|
function fail(message2) {
|
|
84
87
|
console.error(message2);
|
|
@@ -136,7 +139,7 @@ ${REPORT_HINT}`);
|
|
|
136
139
|
if (err instanceof ReviewerAskedError) {
|
|
137
140
|
printQuestions(err.sessionId, err.threads);
|
|
138
141
|
fail2(
|
|
139
|
-
"Commit blocked: the reviewer asked you something before deciding. Answer each question with the command under it \u2014 change the code too if that's what they asked for \u2014 then run git commit again. The review stays open and the decision still comes."
|
|
142
|
+
"Commit blocked: the reviewer asked you something before deciding. Answer each question with the command under it \u2014 change the code too if that's what they asked for \u2014 then run git commit again straight away to keep waiting. The review stays open, the reviewer may ask more, and the decision still comes. Don't stop to ask them in the terminal."
|
|
140
143
|
);
|
|
141
144
|
return;
|
|
142
145
|
}
|
|
@@ -369,7 +372,7 @@ async function reviewLocalFlow(diffRef, flags) {
|
|
|
369
372
|
if (err instanceof ReviewerAskedError) {
|
|
370
373
|
printQuestions(err.sessionId, err.threads);
|
|
371
374
|
console.error(
|
|
372
|
-
"The reviewer asked something before deciding. Answer each question with the command under it, then run diffprism review again \u2014 the review stays open."
|
|
375
|
+
"The reviewer asked something before deciding. Answer each question with the command under it, then run diffprism review again straight away to keep waiting \u2014 the review stays open, and the reviewer may ask more. Don't stop to ask them in the terminal."
|
|
373
376
|
);
|
|
374
377
|
process.exit(1);
|
|
375
378
|
}
|
|
@@ -716,7 +719,7 @@ async function setupInteractive(flags) {
|
|
|
716
719
|
}
|
|
717
720
|
async function runDemo(dev) {
|
|
718
721
|
console.log("");
|
|
719
|
-
const { demo: demo2 } = await import("./demo-
|
|
722
|
+
const { demo: demo2 } = await import("./demo-376MCAK4.js");
|
|
720
723
|
await demo2({ dev });
|
|
721
724
|
}
|
|
722
725
|
async function setupBatch(flags) {
|
|
@@ -79,15 +79,13 @@ async function isServerAlive() {
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
// packages/core/src/diff-scope.ts
|
|
83
|
-
var DEFAULT_DIFF_REF = "working-copy";
|
|
84
|
-
var COMMIT_GATE_DIFF_REF = "staged";
|
|
85
|
-
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".';
|
|
86
|
-
|
|
87
82
|
// packages/core/src/build-info.ts
|
|
88
83
|
import fs2 from "fs";
|
|
89
84
|
import path2 from "path";
|
|
90
85
|
import { fileURLToPath } from "url";
|
|
86
|
+
function builtAt() {
|
|
87
|
+
return true ? 1789607742599 : null;
|
|
88
|
+
}
|
|
91
89
|
function getBuildInfo() {
|
|
92
90
|
let dir = path2.dirname(fileURLToPath(import.meta.url));
|
|
93
91
|
while (dir !== path2.dirname(dir)) {
|
|
@@ -112,6 +110,11 @@ function describeVersion(version) {
|
|
|
112
110
|
return info.dev ? `${version} (dev build \u2014 ${info.root})` : version;
|
|
113
111
|
}
|
|
114
112
|
|
|
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
|
+
|
|
115
118
|
// packages/core/src/feedback.ts
|
|
116
119
|
import fs3 from "fs";
|
|
117
120
|
import os2 from "os";
|
|
@@ -119,7 +122,7 @@ import path3 from "path";
|
|
|
119
122
|
var ISSUES_NEW_URL = "https://github.com/CodeJonesW/diffprism/issues/new";
|
|
120
123
|
var MAX_ERROR_CHARS = 1500;
|
|
121
124
|
function currentVersion() {
|
|
122
|
-
return true ? "1.
|
|
125
|
+
return true ? "1.3.0" : "0.0.0-dev";
|
|
123
126
|
}
|
|
124
127
|
function describeEnvironment() {
|
|
125
128
|
return {
|
|
@@ -226,7 +229,22 @@ import { fileURLToPath as fileURLToPath2 } from "url";
|
|
|
226
229
|
async function ensureServer(options = {}) {
|
|
227
230
|
const existing = await isServerAlive();
|
|
228
231
|
if (existing) {
|
|
229
|
-
|
|
232
|
+
const decision = await decideOnRunningServer(existing, builtAt());
|
|
233
|
+
if (decision.action === "keep") {
|
|
234
|
+
return existing;
|
|
235
|
+
}
|
|
236
|
+
if (decision.action === "keep-busy") {
|
|
237
|
+
if (!options.silent) {
|
|
238
|
+
console.error(
|
|
239
|
+
`The DiffPrism server (PID ${existing.pid}) runs an older build, but ${decision.openReviews} review${decision.openReviews === 1 ? " is" : "s are"} open in it, so it stays up. Finish or close ${decision.openReviews === 1 ? "it" : "them"} and the next command starts the new build \u2014 or run \`diffprism server stop\`.`
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
return existing;
|
|
243
|
+
}
|
|
244
|
+
if (!options.silent) {
|
|
245
|
+
console.error(`Replacing the DiffPrism server (PID ${existing.pid}): it runs an older build than this command.`);
|
|
246
|
+
}
|
|
247
|
+
await stopServer(existing);
|
|
230
248
|
}
|
|
231
249
|
const spawnArgs = options.spawnCommand ?? buildDefaultSpawnCommand(options);
|
|
232
250
|
const logDir = path4.join(os3.homedir(), ".diffprism");
|
|
@@ -256,6 +274,44 @@ async function ensureServer(options = {}) {
|
|
|
256
274
|
`DiffPrism server failed to start within ${timeoutMs / 1e3}s. Check logs at ${logPath}`
|
|
257
275
|
);
|
|
258
276
|
}
|
|
277
|
+
async function decideOnRunningServer(server, ownBuiltAt) {
|
|
278
|
+
if (ownBuiltAt === null) return { action: "keep" };
|
|
279
|
+
if (server.builtAt !== void 0 && server.builtAt >= ownBuiltAt) return { action: "keep" };
|
|
280
|
+
const response = await fetch(`http://localhost:${server.httpPort}/api/reviews`);
|
|
281
|
+
if (!response.ok) {
|
|
282
|
+
throw new Error(`Could not list reviews on the running DiffPrism server: it returned ${response.status}`);
|
|
283
|
+
}
|
|
284
|
+
const { sessions: sessions2 } = await response.json();
|
|
285
|
+
const openReviews = sessions2.filter((s) => s.status === "pending" || s.status === "in_review").length;
|
|
286
|
+
return openReviews > 0 ? { action: "keep-busy", openReviews } : { action: "replace" };
|
|
287
|
+
}
|
|
288
|
+
async function stopServer(server, timeoutMs = 5e3) {
|
|
289
|
+
try {
|
|
290
|
+
process.kill(server.pid, "SIGTERM");
|
|
291
|
+
} catch {
|
|
292
|
+
}
|
|
293
|
+
const start = Date.now();
|
|
294
|
+
while (Date.now() - start < timeoutMs) {
|
|
295
|
+
if (!isProcessRunning(server.pid)) {
|
|
296
|
+
if (readServerFile()?.pid === server.pid) {
|
|
297
|
+
removeServerFile();
|
|
298
|
+
}
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
302
|
+
}
|
|
303
|
+
throw new Error(
|
|
304
|
+
`The old DiffPrism server (PID ${server.pid}) did not stop within ${timeoutMs / 1e3}s. Stop it with \`diffprism server stop\` and try again.`
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
function isProcessRunning(pid) {
|
|
308
|
+
try {
|
|
309
|
+
process.kill(pid, 0);
|
|
310
|
+
return true;
|
|
311
|
+
} catch {
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
259
315
|
function buildDefaultSpawnCommand(options) {
|
|
260
316
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
261
317
|
const thisDir = path4.dirname(thisFile);
|
|
@@ -1913,6 +1969,10 @@ async function startGlobalServer(options = {}) {
|
|
|
1913
1969
|
pid: process.pid,
|
|
1914
1970
|
startedAt: Date.now()
|
|
1915
1971
|
};
|
|
1972
|
+
const serverBuiltAt = builtAt();
|
|
1973
|
+
if (serverBuiltAt !== null) {
|
|
1974
|
+
serverInfo.builtAt = serverBuiltAt;
|
|
1975
|
+
}
|
|
1916
1976
|
writeServerFile(serverInfo);
|
|
1917
1977
|
if (!silent) {
|
|
1918
1978
|
console.log(`
|
|
@@ -1993,11 +2053,11 @@ function mcpToolPermission(name) {
|
|
|
1993
2053
|
export {
|
|
1994
2054
|
readServerFile,
|
|
1995
2055
|
isServerAlive,
|
|
2056
|
+
getBuildInfo,
|
|
2057
|
+
describeVersion,
|
|
1996
2058
|
DEFAULT_DIFF_REF,
|
|
1997
2059
|
COMMIT_GATE_DIFF_REF,
|
|
1998
2060
|
DIFF_REF_DESCRIPTION,
|
|
1999
|
-
getBuildInfo,
|
|
2000
|
-
describeVersion,
|
|
2001
2061
|
currentVersion,
|
|
2002
2062
|
recordError,
|
|
2003
2063
|
readLastError,
|
package/dist/mcp-server.js
CHANGED