@plannotator/pi-extension 0.19.15 → 0.19.16
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/generated/code-nav.ts +437 -0
- package/package.json +1 -1
- package/plannotator.html +2 -2
- package/review-editor.html +143 -136
- package/server/serverReview.ts +81 -1
package/server/serverReview.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { execSync } from "node:child_process";
|
|
1
|
+
import { execSync, spawn } from "node:child_process";
|
|
2
2
|
import { readFileSync, existsSync } from "node:fs";
|
|
3
3
|
import { createServer } from "node:http";
|
|
4
4
|
import os from "node:os";
|
|
@@ -84,6 +84,13 @@ import {
|
|
|
84
84
|
transformClaudeFindings,
|
|
85
85
|
} from "../generated/claude-review.js";
|
|
86
86
|
import { createTourSession, TOUR_EMPTY_OUTPUT_ERROR } from "../generated/tour-review.js";
|
|
87
|
+
import {
|
|
88
|
+
type CodeNavRequest,
|
|
89
|
+
type CodeNavRuntime,
|
|
90
|
+
resolveCodeNav,
|
|
91
|
+
validateCodeNavRequest,
|
|
92
|
+
extractChangedFiles,
|
|
93
|
+
} from "../generated/code-nav.js";
|
|
87
94
|
import {
|
|
88
95
|
canStageFiles,
|
|
89
96
|
detectRemoteDefaultCompareTarget,
|
|
@@ -96,6 +103,37 @@ import {
|
|
|
96
103
|
unstageFile,
|
|
97
104
|
} from "./vcs.js";
|
|
98
105
|
|
|
106
|
+
const piCodeNavRuntime: CodeNavRuntime = {
|
|
107
|
+
runCommand(command, args, options) {
|
|
108
|
+
return new Promise((resolve) => {
|
|
109
|
+
const proc = spawn(command, args, {
|
|
110
|
+
cwd: options?.cwd,
|
|
111
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
112
|
+
});
|
|
113
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
114
|
+
if (options?.timeoutMs) {
|
|
115
|
+
timer = setTimeout(() => proc.kill(), options.timeoutMs);
|
|
116
|
+
}
|
|
117
|
+
const stdoutChunks: Buffer[] = [];
|
|
118
|
+
const stderrChunks: Buffer[] = [];
|
|
119
|
+
proc.stdout!.on("data", (chunk: Buffer) => stdoutChunks.push(chunk));
|
|
120
|
+
proc.stderr!.on("data", (chunk: Buffer) => stderrChunks.push(chunk));
|
|
121
|
+
proc.on("close", (code: number | null) => {
|
|
122
|
+
if (timer) clearTimeout(timer);
|
|
123
|
+
resolve({
|
|
124
|
+
stdout: Buffer.concat(stdoutChunks).toString("utf-8"),
|
|
125
|
+
stderr: Buffer.concat(stderrChunks).toString("utf-8"),
|
|
126
|
+
exitCode: code ?? 1,
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
proc.on("error", () => {
|
|
130
|
+
if (timer) clearTimeout(timer);
|
|
131
|
+
resolve({ stdout: "", stderr: "command not found", exitCode: 1 });
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
|
|
99
137
|
/** Detect if running inside WSL (Windows Subsystem for Linux) */
|
|
100
138
|
function detectWSL(): boolean {
|
|
101
139
|
if (process.platform !== "linux") return false;
|
|
@@ -965,6 +1003,48 @@ export async function startReviewServer(options: {
|
|
|
965
1003
|
}
|
|
966
1004
|
|
|
967
1005
|
json(res, { error: "No file access available" }, 400);
|
|
1006
|
+
} else if (url.pathname === "/api/code-nav/resolve" && req.method === "POST") {
|
|
1007
|
+
const hasCodeNavAccess = !!options.gitContext || !!options.agentCwd || !!options.worktreePool;
|
|
1008
|
+
if (!hasCodeNavAccess) {
|
|
1009
|
+
json(res, { error: "Code navigation requires local access" }, 400);
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
try {
|
|
1013
|
+
const body = (await parseBody(req)) as unknown as CodeNavRequest;
|
|
1014
|
+
const error = validateCodeNavRequest(body);
|
|
1015
|
+
if (error) {
|
|
1016
|
+
json(res, { error }, 400);
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
const navCwd = resolveAgentCwd();
|
|
1020
|
+
const changedFiles = extractChangedFiles(currentPatch);
|
|
1021
|
+
const result = await resolveCodeNav(piCodeNavRuntime, body, navCwd, changedFiles);
|
|
1022
|
+
json(res, result);
|
|
1023
|
+
} catch (err) {
|
|
1024
|
+
json(res, { error: err instanceof Error ? err.message : "Code navigation failed" }, 500);
|
|
1025
|
+
}
|
|
1026
|
+
} else if (url.pathname === "/api/code-nav/file" && req.method === "GET") {
|
|
1027
|
+
const hasCodeNavAccess = !!options.gitContext || !!options.agentCwd || !!options.worktreePool;
|
|
1028
|
+
if (!hasCodeNavAccess) {
|
|
1029
|
+
json(res, { error: "Code navigation requires local access" }, 400);
|
|
1030
|
+
return;
|
|
1031
|
+
}
|
|
1032
|
+
const filePath = url.searchParams.get("path");
|
|
1033
|
+
if (!filePath) {
|
|
1034
|
+
json(res, { error: "Missing path" }, 400);
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
try { validateFilePath(filePath); } catch {
|
|
1038
|
+
json(res, { error: "Invalid path" }, 400);
|
|
1039
|
+
return;
|
|
1040
|
+
}
|
|
1041
|
+
try {
|
|
1042
|
+
const navCwd = resolveAgentCwd();
|
|
1043
|
+
const content = readFileSync(`${navCwd}/${filePath}`, "utf-8");
|
|
1044
|
+
json(res, { content });
|
|
1045
|
+
} catch {
|
|
1046
|
+
json(res, { error: "File not found" }, 404);
|
|
1047
|
+
}
|
|
968
1048
|
} else if (url.pathname === "/api/config" && req.method === "POST") {
|
|
969
1049
|
try {
|
|
970
1050
|
const body = (await parseBody(req)) as { displayName?: string; diffOptions?: Record<string, unknown>; conventionalComments?: boolean };
|