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.
@@ -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
- binPath = devBin;
128
- } else {
129
- let searchDir = thisDir;
130
- while (searchDir !== path2.dirname(searchDir)) {
131
- const candidate = path2.join(
132
- searchDir,
133
- "node_modules",
134
- ".bin",
135
- "diffprism"
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
- const args = [process.execPath, binPath, "server", "--_daemon"];
145
- if (options.dev) {
146
- args.push("--dev");
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);
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ensureServer,
3
3
  submitReviewToServer
4
- } from "./chunk-4IQOTAHD.js";
4
+ } from "./chunk-PQWU5NW4.js";
5
5
  import {
6
6
  parseDiff
7
7
  } from "./chunk-QGWYCEJN.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  demo
3
- } from "./chunk-LH6H3QSC.js";
4
- import "./chunk-4IQOTAHD.js";
3
+ } from "./chunk-TZ5SGWHP.js";
4
+ import "./chunk-PQWU5NW4.js";
5
5
  import "./chunk-QGWYCEJN.js";
6
6
  import "./chunk-DHCVZGHE.js";
7
7
  import "./chunk-JSBRDJBE.js";