local-diff-reviewer 1.0.4 → 1.0.6

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
@@ -1,6 +1,6 @@
1
1
  # diff-review
2
2
 
3
- ![Diff 审查台界面截图](./docs/images/diff-review-ui.jpg)
3
+ ![Diff 审查台界面截图](https://cdn.jsdelivr.net/npm/local-diff-reviewer@latest/docs/images/diff-review-ui.jpg)
4
4
 
5
5
  AI chat 里的本地代码审查工具。可以直接用 CLI 打开,也可以安装成 agent skill。
6
6
 
@@ -42,6 +42,7 @@ npx skills add Mone-Lee/diff-review
42
42
  local-diff-reviewer
43
43
  local-diff-reviewer staged
44
44
  local-diff-reviewer HEAD~1 HEAD
45
+ local-diff-reviewer --repo /path/to/project
45
46
  ```
46
47
 
47
48
  这三种模式分别表示:
@@ -50,6 +51,22 @@ local-diff-reviewer HEAD~1 HEAD
50
51
  - `staged`:审查已经 `git add`、但还没有提交的改动。
51
52
  - `revision`:审查两个 revision 之间的差异,例如 `local-diff-reviewer HEAD~1 HEAD` 会比较 `HEAD~1..HEAD`。
52
53
 
54
+ 如果命令不是在目标项目目录里启动,可以用 `--repo <path>` 显式指定要审查的 Git 仓库:
55
+
56
+ ```bash
57
+ local-diff-reviewer --repo /path/to/project
58
+ local-diff-reviewer --repo /path/to/project staged
59
+ ```
60
+
61
+ 每次启动都会创建独立的本地 review 会话。多个项目里分别执行 `local-diff-reviewer` 或 `/diff-review` 时,打开的页面会分别绑定启动时的项目,不会被最后一次启动覆盖。默认优先使用 `127.0.0.1:4966`;如果端口已被占用,会自动选择一个空闲端口。
62
+
63
+ ```text
64
+ 项目 A /diff-review -> http://127.0.0.1:4966 -> 项目 A diff
65
+ 项目 B /diff-review -> http://127.0.0.1:<空闲端口> -> 项目 B diff
66
+ ```
67
+
68
+ 注意:本地开发的 `--dev` 模式仍使用 Vite dev server,端口和 API proxy 是固定的;多项目并行审查请使用默认的构建页面模式。
69
+
53
70
  ## Skill 使用方式
54
71
 
55
72
  在 AI chat 中使用:
@@ -66,7 +83,7 @@ local-diff-reviewer HEAD~1 HEAD
66
83
  npx skills add Mone-Lee/diff-review
67
84
  ```
68
85
 
69
- skill 会从目标 workspace 运行 `npx --yes local-diff-reviewer [args...]`。
86
+ skill 会以目标 workspace 作为命令工作目录运行 `npx --yes local-diff-reviewer [args...]`,因此 `/diff-review` 会审查当前项目,而不是 skill 安装目录。
70
87
 
71
88
  ### 预置 agent 评论
72
89
 
package/SKILL.md CHANGED
@@ -16,12 +16,14 @@ Use this skill when the user asks for `/diff-review`, wants to inspect current w
16
16
  - `/diff-review staged`: review staged diff.
17
17
  - `/diff-review <base> <target>`: review diff between two Git revisions.
18
18
 
19
- Do not ask the user to run a shell CLI manually. Run the package command from the workspace root:
19
+ Do not ask the user to run a shell CLI manually. Determine the target workspace/repository from the user's active environment context, then run the package command with that repository as the command working directory:
20
20
 
21
21
  ```bash
22
22
  npx --yes local-diff-reviewer [args...]
23
23
  ```
24
24
 
25
+ Set the shell/tool `cwd` to `/absolute/path/to/target/workspace` before running the command. Do not pass `--repo` from this skill; older published CLI versions treat unknown args as revision args. Do not use the skill package directory or this skill's install directory as the review target unless that is the workspace the user asked to review.
26
+
25
27
  When you have concrete review findings or answers to existing review comments, preload them with one `--comment` JSON argument per comment before launching the viewer:
26
28
 
27
29
  ```bash
package/dist/cli/start.js CHANGED
@@ -860,12 +860,22 @@ async function startServer(state, port = 4966) {
860
860
  app.use((error, _req, res, _next) => {
861
861
  res.status(500).json({ error: error.message });
862
862
  });
863
- return new Promise((resolve3) => {
863
+ return listen(app, port);
864
+ }
865
+ function listen(app, port) {
866
+ return new Promise((resolve3, reject) => {
864
867
  const server = app.listen(port, "127.0.0.1", () => {
865
868
  const address = server.address();
866
869
  const actualPort = typeof address === "object" && address ? address.port : port;
867
870
  resolve3(`http://127.0.0.1:${actualPort}`);
868
871
  });
872
+ server.once("error", (error) => {
873
+ if (error.code === "EADDRINUSE" && port !== 0) {
874
+ listen(app, 0).then(resolve3, reject);
875
+ return;
876
+ }
877
+ reject(error);
878
+ });
869
879
  });
870
880
  }
871
881
  function selectPromptThreads(threads, scope) {
@@ -880,9 +890,9 @@ function selectPromptThreads(threads, scope) {
880
890
  var packageRoot = resolve2(dirname2(fileURLToPath(import.meta.url)), "../..");
881
891
  var builtWebDist = join4(packageRoot, "dist", "web");
882
892
  async function main() {
883
- const { dev, reviewArgs, comments } = parseCliOptions(process.argv.slice(2));
893
+ const { dev, repo, reviewArgs, comments } = parseCliOptions(process.argv.slice(2));
884
894
  const mode = parseReviewMode(reviewArgs);
885
- const repoRoot = await getRepoRoot(process.cwd());
895
+ const repoRoot = await getRepoRoot(repo ?? process.cwd());
886
896
  const diff = await getDiff(mode, repoRoot);
887
897
  const diffFiles = parseUnifiedDiff(diff);
888
898
  const session = {
@@ -914,6 +924,7 @@ async function main() {
914
924
  function parseCliOptions(args) {
915
925
  const reviewArgs = [];
916
926
  const comments = [];
927
+ let repo;
917
928
  let dev = false;
918
929
  for (let index = 0; index < args.length; index += 1) {
919
930
  const arg = args[index];
@@ -921,6 +932,19 @@ function parseCliOptions(args) {
921
932
  dev = true;
922
933
  continue;
923
934
  }
935
+ if (arg === "--repo") {
936
+ const value = args[index + 1];
937
+ if (!value) throw new Error("--repo requires a path value");
938
+ repo = resolve2(value);
939
+ index += 1;
940
+ continue;
941
+ }
942
+ if (arg.startsWith("--repo=")) {
943
+ const value = arg.slice("--repo=".length);
944
+ if (!value) throw new Error("--repo requires a path value");
945
+ repo = resolve2(value);
946
+ continue;
947
+ }
924
948
  if (arg === "--comment") {
925
949
  const comment = args[index + 1];
926
950
  if (!comment) throw new Error("--comment requires a JSON value");
@@ -936,7 +960,7 @@ function parseCliOptions(args) {
936
960
  }
937
961
  reviewArgs.push(arg);
938
962
  }
939
- return { dev, reviewArgs, comments };
963
+ return { dev, repo, reviewArgs, comments };
940
964
  }
941
965
  function modeLabel(mode) {
942
966
  if (mode.kind === "revision") return `${mode.base}..${mode.target}`;
@@ -944,7 +968,7 @@ function modeLabel(mode) {
944
968
  }
945
969
  function startVite() {
946
970
  const child = spawn("npm", ["run", "web:dev"], {
947
- cwd: process.cwd(),
971
+ cwd: packageRoot,
948
972
  stdio: "inherit",
949
973
  shell: process.platform === "win32",
950
974
  env: { ...process.env, BROWSER: "none" }
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "local-diff-reviewer",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "private": false,
5
5
  "description": "Open a local GitHub-style diff review Web UI for the current repository.",
6
6
  "repository": {
@@ -20,6 +20,7 @@
20
20
  },
21
21
  "files": [
22
22
  "dist",
23
+ "docs/images",
23
24
  "SKILL.md",
24
25
  "README.md"
25
26
  ],