diffprism 0.44.0 → 0.47.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 +134 -34
- package/dist/bin.js +271 -81
- package/dist/{chunk-4IQOTAHD.js → chunk-PQWU5NW4.js} +170 -19
- package/dist/{chunk-LH6H3QSC.js → chunk-TZ5SGWHP.js} +1 -1
- package/dist/{demo-MDPKCAXZ.js → demo-H2NAMKCT.js} +2 -2
- package/dist/mcp-server.js +430 -72
- package/dist/src-KF5HRJPX.js +23 -0
- package/package.json +1 -1
- package/ui-dist/assets/index-AgilKYdG.css +1 -0
- package/ui-dist/assets/index-BV9fRDP_.js +335 -0
- package/ui-dist/index.html +2 -2
- package/ui-dist/assets/index-DOhngwbV.css +0 -1
- package/ui-dist/assets/index-Dw_IuVjX.js +0 -335
- /package/dist/{chunk-6J6PSBL2.js → chunk-24B33UN6.js} +0 -0
|
@@ -122,30 +122,45 @@ function buildDefaultSpawnCommand(options) {
|
|
|
122
122
|
const thisDir = path2.dirname(thisFile);
|
|
123
123
|
const workspaceRoot = path2.resolve(thisDir, "..", "..", "..");
|
|
124
124
|
const devBin = path2.join(workspaceRoot, "cli", "bin", "diffprism.mjs");
|
|
125
|
-
let binPath = "diffprism";
|
|
126
125
|
if (fs2.existsSync(devBin)) {
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
126
|
+
return withDevFlag([process.execPath, devBin, "server", "--_daemon"], options);
|
|
127
|
+
}
|
|
128
|
+
let searchDir = thisDir;
|
|
129
|
+
while (searchDir !== path2.dirname(searchDir)) {
|
|
130
|
+
const ownBin = readOwnBinPath(searchDir);
|
|
131
|
+
if (ownBin) {
|
|
132
|
+
return withDevFlag(
|
|
133
|
+
[process.execPath, ownBin, "server", "--_daemon"],
|
|
134
|
+
options
|
|
136
135
|
);
|
|
137
|
-
if (fs2.existsSync(candidate)) {
|
|
138
|
-
binPath = candidate;
|
|
139
|
-
break;
|
|
140
|
-
}
|
|
141
|
-
searchDir = path2.dirname(searchDir);
|
|
142
136
|
}
|
|
137
|
+
const shim = path2.join(searchDir, "node_modules", ".bin", "diffprism");
|
|
138
|
+
if (fs2.existsSync(shim)) {
|
|
139
|
+
return withDevFlag([shim, "server", "--_daemon"], options);
|
|
140
|
+
}
|
|
141
|
+
searchDir = path2.dirname(searchDir);
|
|
143
142
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
return withDevFlag(["diffprism", "server", "--_daemon"], options);
|
|
144
|
+
}
|
|
145
|
+
function withDevFlag(args, options) {
|
|
146
|
+
return options.dev ? [...args, "--dev"] : args;
|
|
147
|
+
}
|
|
148
|
+
function readOwnBinPath(dir) {
|
|
149
|
+
const manifestPath = path2.join(dir, "package.json");
|
|
150
|
+
if (!fs2.existsSync(manifestPath)) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
const manifest = JSON.parse(fs2.readFileSync(manifestPath, "utf8"));
|
|
155
|
+
const entry = typeof manifest.bin === "string" ? manifest.bin : manifest.bin?.diffprism;
|
|
156
|
+
if (!entry) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
const resolved = path2.resolve(dir, entry);
|
|
160
|
+
return fs2.existsSync(resolved) ? resolved : null;
|
|
161
|
+
} catch {
|
|
162
|
+
return null;
|
|
147
163
|
}
|
|
148
|
-
return args;
|
|
149
164
|
}
|
|
150
165
|
async function submitReviewToServer(serverInfo, diffRef, options = {}) {
|
|
151
166
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -851,6 +866,96 @@ async function handleApiRequest(req, res) {
|
|
|
851
866
|
}
|
|
852
867
|
return true;
|
|
853
868
|
}
|
|
869
|
+
if (method === "POST" && url === "/api/pr/open") {
|
|
870
|
+
try {
|
|
871
|
+
const body = await readBody(req);
|
|
872
|
+
const { prUrl } = JSON.parse(body);
|
|
873
|
+
if (!prUrl) {
|
|
874
|
+
jsonResponse(res, 400, { error: "Missing prUrl" });
|
|
875
|
+
return true;
|
|
876
|
+
}
|
|
877
|
+
const {
|
|
878
|
+
isPrRef,
|
|
879
|
+
parsePrRef,
|
|
880
|
+
resolveGitHubToken,
|
|
881
|
+
createGitHubClient,
|
|
882
|
+
fetchPullRequest,
|
|
883
|
+
fetchPullRequestDiff,
|
|
884
|
+
normalizePr
|
|
885
|
+
} = await import("./src-KF5HRJPX.js");
|
|
886
|
+
if (!isPrRef(prUrl)) {
|
|
887
|
+
jsonResponse(res, 400, {
|
|
888
|
+
error: "Invalid PR URL. Expected https://github.com/owner/repo/pull/123 or owner/repo#123"
|
|
889
|
+
});
|
|
890
|
+
return true;
|
|
891
|
+
}
|
|
892
|
+
let token;
|
|
893
|
+
try {
|
|
894
|
+
token = resolveGitHubToken();
|
|
895
|
+
} catch (err) {
|
|
896
|
+
jsonResponse(res, 401, {
|
|
897
|
+
error: err instanceof Error ? err.message : "GitHub token not found"
|
|
898
|
+
});
|
|
899
|
+
return true;
|
|
900
|
+
}
|
|
901
|
+
const { owner, repo, number: prNumber } = parsePrRef(prUrl);
|
|
902
|
+
const client = createGitHubClient(token);
|
|
903
|
+
const [prMetadata, rawDiff] = await Promise.all([
|
|
904
|
+
fetchPullRequest(client, owner, repo, prNumber),
|
|
905
|
+
fetchPullRequestDiff(client, owner, repo, prNumber)
|
|
906
|
+
]);
|
|
907
|
+
const normalized = normalizePr(rawDiff, prMetadata);
|
|
908
|
+
let localRepoPath = null;
|
|
909
|
+
try {
|
|
910
|
+
const { execSync } = await import("child_process");
|
|
911
|
+
const remoteOutput = execSync("git remote -v", {
|
|
912
|
+
cwd: process.cwd(),
|
|
913
|
+
encoding: "utf-8",
|
|
914
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
915
|
+
});
|
|
916
|
+
const repoPattern = new RegExp(`github\\.com[:/]${owner}/${repo}(\\.git)?\\s`, "i");
|
|
917
|
+
if (repoPattern.test(remoteOutput)) {
|
|
918
|
+
localRepoPath = process.cwd();
|
|
919
|
+
}
|
|
920
|
+
} catch {
|
|
921
|
+
}
|
|
922
|
+
const sessionId = `session-${randomUUID2().slice(0, 8)}`;
|
|
923
|
+
normalized.payload.reviewId = sessionId;
|
|
924
|
+
const session = {
|
|
925
|
+
id: sessionId,
|
|
926
|
+
payload: normalized.payload,
|
|
927
|
+
projectPath: localRepoPath ?? `github:${owner}/${repo}#${prNumber}`,
|
|
928
|
+
source: "manual",
|
|
929
|
+
status: "pending",
|
|
930
|
+
createdAt: Date.now(),
|
|
931
|
+
result: null,
|
|
932
|
+
hasNewChanges: false,
|
|
933
|
+
annotations: []
|
|
934
|
+
};
|
|
935
|
+
sessions.set(sessionId, session);
|
|
936
|
+
broadcastToAll({
|
|
937
|
+
type: "session:added",
|
|
938
|
+
payload: toSummary(session)
|
|
939
|
+
});
|
|
940
|
+
jsonResponse(res, 201, {
|
|
941
|
+
sessionId,
|
|
942
|
+
fileCount: normalized.diffSet.files.length,
|
|
943
|
+
localRepoPath,
|
|
944
|
+
pr: {
|
|
945
|
+
title: prMetadata.title,
|
|
946
|
+
author: prMetadata.author,
|
|
947
|
+
url: prMetadata.url,
|
|
948
|
+
baseBranch: prMetadata.baseBranch,
|
|
949
|
+
headBranch: prMetadata.headBranch
|
|
950
|
+
}
|
|
951
|
+
});
|
|
952
|
+
} catch (err) {
|
|
953
|
+
jsonResponse(res, 500, {
|
|
954
|
+
error: err instanceof Error ? err.message : "Failed to fetch PR"
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
return true;
|
|
958
|
+
}
|
|
854
959
|
if (method === "GET" && req.url) {
|
|
855
960
|
const parsedUrl = new URL(req.url, "http://localhost");
|
|
856
961
|
if (parsedUrl.pathname === "/api/fs/list") {
|
|
@@ -903,6 +1008,20 @@ async function handleApiRequest(req, res) {
|
|
|
903
1008
|
jsonResponse(res, 200, toSummary(session));
|
|
904
1009
|
return true;
|
|
905
1010
|
}
|
|
1011
|
+
const getPayloadParams = matchRoute(method, url, "GET", "/api/reviews/:id/payload");
|
|
1012
|
+
if (getPayloadParams) {
|
|
1013
|
+
const session = sessions.get(getPayloadParams.id);
|
|
1014
|
+
if (!session) {
|
|
1015
|
+
jsonResponse(res, 404, { error: "Session not found" });
|
|
1016
|
+
return true;
|
|
1017
|
+
}
|
|
1018
|
+
jsonResponse(res, 200, {
|
|
1019
|
+
payload: session.payload,
|
|
1020
|
+
projectPath: session.projectPath,
|
|
1021
|
+
annotations: session.annotations
|
|
1022
|
+
});
|
|
1023
|
+
return true;
|
|
1024
|
+
}
|
|
906
1025
|
const postResultParams = matchRoute(method, url, "POST", "/api/reviews/:id/result");
|
|
907
1026
|
if (postResultParams) {
|
|
908
1027
|
const session = sessions.get(postResultParams.id);
|
|
@@ -1033,6 +1152,38 @@ async function handleApiRequest(req, res) {
|
|
|
1033
1152
|
jsonResponse(res, 200, { ok: true });
|
|
1034
1153
|
return true;
|
|
1035
1154
|
}
|
|
1155
|
+
const postFocusParams = matchRoute(method, url, "POST", "/api/reviews/:id/focus");
|
|
1156
|
+
if (postFocusParams) {
|
|
1157
|
+
const session = sessions.get(postFocusParams.id);
|
|
1158
|
+
if (!session) {
|
|
1159
|
+
jsonResponse(res, 404, { error: "Session not found" });
|
|
1160
|
+
return true;
|
|
1161
|
+
}
|
|
1162
|
+
try {
|
|
1163
|
+
const body = await readBody(req);
|
|
1164
|
+
const { file, lineStart, lineEnd } = JSON.parse(body);
|
|
1165
|
+
session.userFocus = {
|
|
1166
|
+
file,
|
|
1167
|
+
lineStart,
|
|
1168
|
+
lineEnd,
|
|
1169
|
+
updatedAt: Date.now()
|
|
1170
|
+
};
|
|
1171
|
+
jsonResponse(res, 200, { ok: true });
|
|
1172
|
+
} catch {
|
|
1173
|
+
jsonResponse(res, 400, { error: "Invalid request body" });
|
|
1174
|
+
}
|
|
1175
|
+
return true;
|
|
1176
|
+
}
|
|
1177
|
+
const getFocusParams = matchRoute(method, url, "GET", "/api/reviews/:id/focus");
|
|
1178
|
+
if (getFocusParams) {
|
|
1179
|
+
const session = sessions.get(getFocusParams.id);
|
|
1180
|
+
if (!session) {
|
|
1181
|
+
jsonResponse(res, 404, { error: "Session not found" });
|
|
1182
|
+
return true;
|
|
1183
|
+
}
|
|
1184
|
+
jsonResponse(res, 200, { focus: session.userFocus ?? null });
|
|
1185
|
+
return true;
|
|
1186
|
+
}
|
|
1036
1187
|
const deleteParams = matchRoute(method, url, "DELETE", "/api/reviews/:id");
|
|
1037
1188
|
if (deleteParams) {
|
|
1038
1189
|
stopSessionWatcher(deleteParams.id);
|