@mrclrchtr/supi-review 0.2.0 → 1.1.2

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-core",
3
- "version": "0.2.0",
3
+ "version": "1.1.2",
4
4
  "description": "SuPi core — shared infrastructure for SuPi extensions (XML context tags, config system)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -22,9 +22,5 @@
22
22
  "@earendil-works/pi-coding-agent": "*",
23
23
  "@earendil-works/pi-tui": "*"
24
24
  },
25
- "devDependencies": {
26
- "@types/node": "25.6.2",
27
- "vitest": "4.1.5"
28
- },
29
25
  "main": "src/index.ts"
30
26
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-review",
3
- "version": "0.2.0",
3
+ "version": "1.1.2",
4
4
  "description": "SuPi Review extension — structured code review via /supi-review command",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -20,7 +20,7 @@
20
20
  "README.md"
21
21
  ],
22
22
  "dependencies": {
23
- "@mrclrchtr/supi-core": "workspace:*"
23
+ "@mrclrchtr/supi-core": "1.1.2"
24
24
  },
25
25
  "bundledDependencies": [
26
26
  "@mrclrchtr/supi-core"
@@ -31,9 +31,6 @@
31
31
  "@earendil-works/pi-tui": "*",
32
32
  "typebox": "*"
33
33
  },
34
- "devDependencies": {
35
- "vitest": "4.1.5"
36
- },
37
34
  "pi": {
38
35
  "extensions": [
39
36
  "./src/review.ts"
package/src/git.ts CHANGED
@@ -5,12 +5,31 @@ const execFileAsync = promisify(execFile);
5
5
 
6
6
  const GIT_TIMEOUT_MS = 30_000;
7
7
 
8
+ function scrubGitEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
9
+ const next = { ...env };
10
+ for (const key of Object.keys(next)) {
11
+ if (key.startsWith("GIT_")) {
12
+ delete next[key];
13
+ }
14
+ }
15
+ return next;
16
+ }
17
+
18
+ function gitExecOptions(repoPath: string) {
19
+ return {
20
+ cwd: repoPath,
21
+ env: scrubGitEnv(process.env),
22
+ timeout: GIT_TIMEOUT_MS,
23
+ };
24
+ }
25
+
8
26
  export async function getMergeBase(repoPath: string, branch: string): Promise<string | undefined> {
9
27
  try {
10
- const { stdout } = await execFileAsync("git", ["merge-base", "HEAD", branch], {
11
- cwd: repoPath,
12
- timeout: GIT_TIMEOUT_MS,
13
- });
28
+ const { stdout } = await execFileAsync(
29
+ "git",
30
+ ["merge-base", "HEAD", branch],
31
+ gitExecOptions(repoPath),
32
+ );
14
33
  return stdout.trim() || undefined;
15
34
  } catch {
16
35
  return undefined;
@@ -18,27 +37,25 @@ export async function getMergeBase(repoPath: string, branch: string): Promise<st
18
37
  }
19
38
 
20
39
  export async function getDiff(repoPath: string, baseSha: string): Promise<string> {
21
- const { stdout } = await execFileAsync("git", ["diff", baseSha], {
22
- cwd: repoPath,
23
- timeout: GIT_TIMEOUT_MS,
24
- });
40
+ const { stdout } = await execFileAsync("git", ["diff", baseSha], gitExecOptions(repoPath));
25
41
  return stdout;
26
42
  }
27
43
 
28
44
  export async function getUncommittedDiff(repoPath: string): Promise<string> {
29
45
  const [staged, unstaged, untracked] = await Promise.all([
30
- execFileAsync("git", ["diff", "--cached"], { cwd: repoPath, timeout: GIT_TIMEOUT_MS }).then(
46
+ execFileAsync("git", ["diff", "--cached"], gitExecOptions(repoPath)).then(
31
47
  (r) => r.stdout,
32
48
  () => "",
33
49
  ),
34
- execFileAsync("git", ["diff"], { cwd: repoPath, timeout: GIT_TIMEOUT_MS }).then(
50
+ execFileAsync("git", ["diff"], gitExecOptions(repoPath)).then(
35
51
  (r) => r.stdout,
36
52
  () => "",
37
53
  ),
38
- execFileAsync("git", ["ls-files", "--others", "--exclude-standard"], {
39
- cwd: repoPath,
40
- timeout: GIT_TIMEOUT_MS,
41
- }).then(
54
+ execFileAsync(
55
+ "git",
56
+ ["ls-files", "--others", "--exclude-standard"],
57
+ gitExecOptions(repoPath),
58
+ ).then(
42
59
  (r) => r.stdout,
43
60
  () => "",
44
61
  ),
@@ -73,7 +90,7 @@ export async function getRecentCommits(repoPath: string, limit = 20): Promise<Co
73
90
  const { stdout } = await execFileAsync(
74
91
  "git",
75
92
  ["log", `--max-count=${limit}`, "--pretty=format:%H %s"],
76
- { cwd: repoPath, timeout: GIT_TIMEOUT_MS },
93
+ gitExecOptions(repoPath),
77
94
  );
78
95
  return stdout
79
96
  .split("\n")
@@ -86,18 +103,16 @@ export async function getRecentCommits(repoPath: string, limit = 20): Promise<Co
86
103
  }
87
104
 
88
105
  export async function getCommitShow(repoPath: string, sha: string): Promise<string> {
89
- const { stdout } = await execFileAsync("git", ["show", sha], {
90
- cwd: repoPath,
91
- timeout: GIT_TIMEOUT_MS,
92
- });
106
+ const { stdout } = await execFileAsync("git", ["show", sha], gitExecOptions(repoPath));
93
107
  return stdout;
94
108
  }
95
109
 
96
110
  export async function getDiffFileNames(repoPath: string, baseSha: string): Promise<string[]> {
97
- const { stdout } = await execFileAsync("git", ["diff", "--name-only", baseSha], {
98
- cwd: repoPath,
99
- timeout: GIT_TIMEOUT_MS,
100
- });
111
+ const { stdout } = await execFileAsync(
112
+ "git",
113
+ ["diff", "--name-only", baseSha],
114
+ gitExecOptions(repoPath),
115
+ );
101
116
  return stdout
102
117
  .trim()
103
118
  .split("\n")
@@ -107,21 +122,19 @@ export async function getDiffFileNames(repoPath: string, baseSha: string): Promi
107
122
 
108
123
  export async function getUncommittedFileNames(repoPath: string): Promise<string[]> {
109
124
  const [unstaged, staged, untracked] = await Promise.all([
110
- execFileAsync("git", ["diff", "--name-only"], { cwd: repoPath, timeout: GIT_TIMEOUT_MS }).then(
125
+ execFileAsync("git", ["diff", "--name-only"], gitExecOptions(repoPath)).then(
111
126
  (r) => r.stdout,
112
127
  () => "",
113
128
  ),
114
- execFileAsync("git", ["diff", "--cached", "--name-only"], {
115
- cwd: repoPath,
116
- timeout: GIT_TIMEOUT_MS,
117
- }).then(
129
+ execFileAsync("git", ["diff", "--cached", "--name-only"], gitExecOptions(repoPath)).then(
118
130
  (r) => r.stdout,
119
131
  () => "",
120
132
  ),
121
- execFileAsync("git", ["ls-files", "--others", "--exclude-standard"], {
122
- cwd: repoPath,
123
- timeout: GIT_TIMEOUT_MS,
124
- }).then(
133
+ execFileAsync(
134
+ "git",
135
+ ["ls-files", "--others", "--exclude-standard"],
136
+ gitExecOptions(repoPath),
137
+ ).then(
125
138
  (r) => r.stdout,
126
139
  () => "",
127
140
  ),
@@ -151,7 +164,7 @@ export async function getCommitFileNames(repoPath: string, sha: string): Promise
151
164
  const { stdout } = await execFileAsync(
152
165
  "git",
153
166
  ["diff-tree", "--no-commit-id", "--name-only", "-r", sha],
154
- { cwd: repoPath, timeout: GIT_TIMEOUT_MS },
167
+ gitExecOptions(repoPath),
155
168
  );
156
169
  return stdout
157
170
  .trim()
@@ -162,14 +175,8 @@ export async function getCommitFileNames(repoPath: string, sha: string): Promise
162
175
 
163
176
  export async function getLocalBranches(repoPath: string): Promise<string[]> {
164
177
  const [{ stdout: local }, { stdout: current }] = await Promise.all([
165
- execFileAsync("git", ["branch", "--format=%(refname:short)"], {
166
- cwd: repoPath,
167
- timeout: GIT_TIMEOUT_MS,
168
- }),
169
- execFileAsync("git", ["branch", "--show-current"], {
170
- cwd: repoPath,
171
- timeout: GIT_TIMEOUT_MS,
172
- }),
178
+ execFileAsync("git", ["branch", "--format=%(refname:short)"], gitExecOptions(repoPath)),
179
+ execFileAsync("git", ["branch", "--show-current"], gitExecOptions(repoPath)),
173
180
  ]);
174
181
 
175
182
  const names = local
@@ -182,7 +189,6 @@ export async function getLocalBranches(repoPath: string): Promise<string[]> {
182
189
  const set = new Set(names);
183
190
  const sorted: string[] = [];
184
191
 
185
- // Put default candidates first
186
192
  for (const candidate of ["main", "master", currentBranch]) {
187
193
  if (candidate && set.has(candidate)) {
188
194
  sorted.push(candidate);
@@ -190,7 +196,6 @@ export async function getLocalBranches(repoPath: string): Promise<string[]> {
190
196
  }
191
197
  }
192
198
 
193
- // Then remaining alphabetically
194
199
  const remaining = Array.from(set).sort((a, b) => a.localeCompare(b));
195
200
  sorted.push(...remaining);
196
201
  return sorted;