jstar-reviewer 2.2.0 → 2.4.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/bin/jstar.js CHANGED
@@ -29,7 +29,7 @@ function log(msg) {
29
29
 
30
30
  function printHelp() {
31
31
  log(`
32
- ${COLORS.bold}🌟 J-Star Reviewer v2.2.0${COLORS.reset}
32
+ ${COLORS.bold}🌟 J-Star Reviewer v2.4.0${COLORS.reset}
33
33
 
34
34
  ${COLORS.dim}AI-powered code review with local embeddings${COLORS.reset}
35
35
 
@@ -91,6 +91,32 @@ function chunkDiffByFile(diff) {
91
91
  function sleep(ms) {
92
92
  return new Promise(resolve => setTimeout(resolve, ms));
93
93
  }
94
+ async function getDefaultBranch() {
95
+ try {
96
+ // Method 1: Check remote HEAD (most reliable)
97
+ try {
98
+ const remote = await git.remote(['show', 'origin']);
99
+ if (typeof remote === 'string') {
100
+ const match = remote.match(/HEAD branch: (\S+)/);
101
+ if (match)
102
+ return match[1];
103
+ }
104
+ }
105
+ catch (e) {
106
+ // No remote or network issue, proceed to local check
107
+ }
108
+ // Method 2: Check which common branch exists locally
109
+ const branches = await git.branchLocal();
110
+ if (branches.all.includes('main'))
111
+ return 'main';
112
+ if (branches.all.includes('master'))
113
+ return 'master';
114
+ }
115
+ catch (e) {
116
+ // Fallback
117
+ }
118
+ return 'main';
119
+ }
94
120
  /**
95
121
  * Filter issues by confidence threshold and log what was removed
96
122
  */
@@ -172,12 +198,89 @@ async function main() {
172
198
  const detective = new detective_1.Detective(SOURCE_DIR);
173
199
  await detective.scan();
174
200
  detective.report();
175
- // 1. Get the Diff
176
- const diff = await git.diff(["--staged"]);
201
+ // 1. Determine Diff Target
202
+ const args = process.argv.slice(2);
203
+ let diff;
204
+ let reviewTarget = "Staged Changes";
205
+ if (args.includes('--last')) {
206
+ reviewTarget = "Last Commit";
207
+ diff = await git.diff(["HEAD~1", "HEAD"]);
208
+ }
209
+ else if (args.includes('--commit')) {
210
+ const hashIndex = args.indexOf('--commit') + 1;
211
+ if (hashIndex < args.length) {
212
+ const hash = args[hashIndex];
213
+ reviewTarget = `Commit ${hash}`;
214
+ diff = await git.diff([`${hash}~1`, `${hash}`]);
215
+ }
216
+ else {
217
+ logger_1.Logger.error(chalk_1.default.red("āŒ Missing commit hash for --commit"));
218
+ return;
219
+ }
220
+ }
221
+ else if (args.includes('--range')) {
222
+ const rangeIndex = args.indexOf('--range') + 1;
223
+ if (rangeIndex + 1 < args.length) {
224
+ const start = args[rangeIndex];
225
+ const end = args[rangeIndex + 1];
226
+ reviewTarget = `Range ${start}..${end}`;
227
+ diff = await git.diff([start, end]);
228
+ }
229
+ else {
230
+ logger_1.Logger.error(chalk_1.default.red("āŒ Missing arguments for --range (usage: --range <start> <end>)"));
231
+ return;
232
+ }
233
+ }
234
+ else if (args.includes('--pr')) {
235
+ const prIndex = args.indexOf('--pr');
236
+ // Check for --base flag first
237
+ let baseBranch = 'main';
238
+ if (args.includes('--base')) {
239
+ const baseIndex = args.indexOf('--base') + 1;
240
+ if (baseIndex < args.length) {
241
+ baseBranch = args[baseIndex];
242
+ }
243
+ else {
244
+ logger_1.Logger.error(chalk_1.default.red("āŒ Missing branch name for --base"));
245
+ return;
246
+ }
247
+ }
248
+ else {
249
+ // Check positional argument (backward compatibility)
250
+ const potentialBase = args[prIndex + 1];
251
+ if (potentialBase && !potentialBase.startsWith('--')) {
252
+ baseBranch = potentialBase;
253
+ }
254
+ else {
255
+ // Auto-detect
256
+ baseBranch = await getDefaultBranch();
257
+ }
258
+ }
259
+ reviewTarget = `PR (HEAD vs ${baseBranch})`;
260
+ // Use triple-dot for merge-base difference (what a PR shows)
261
+ try {
262
+ diff = await git.diff([`${baseBranch}...HEAD`]);
263
+ }
264
+ catch (e) {
265
+ logger_1.Logger.error(chalk_1.default.red(`āŒ Failed to diff against ${baseBranch}. Does the branch exist?`));
266
+ return;
267
+ }
268
+ }
269
+ else {
270
+ // Default: Staged changes
271
+ diff = await git.diff(["--staged"]);
272
+ }
177
273
  if (!diff) {
178
- logger_1.Logger.info(chalk_1.default.green("\nāœ… No staged changes to review. (Did you 'git add'?)"));
274
+ if (reviewTarget === "Staged Changes") {
275
+ logger_1.Logger.info(chalk_1.default.green("\nāœ… No staged changes to review. (Did you 'git add'?)"));
276
+ logger_1.Logger.info(chalk_1.default.dim(" Tip: Use '--last' to review the previous commit."));
277
+ }
278
+ else {
279
+ logger_1.Logger.info(chalk_1.default.green(`\nāœ… No changes found in ${reviewTarget}.`));
280
+ }
179
281
  return;
180
282
  }
283
+ logger_1.Logger.info(chalk_1.default.blue(`\nšŸ“ Reviewing: ${reviewTarget}`));
181
284
  // 2. Load the Brain
182
285
  if (!fs.existsSync(STORAGE_DIR)) {
183
286
  logger_1.Logger.error(chalk_1.default.red("āŒ Local Brain not found. Run 'pnpm run index:init' first."));
package/package.json CHANGED
@@ -1,19 +1,10 @@
1
1
  {
2
2
  "name": "jstar-reviewer",
3
- "version": "2.2.0",
3
+ "version": "2.4.0",
4
4
  "description": "Local-First, Context-Aware AI Code Reviewer - Works with any language",
5
5
  "bin": {
6
6
  "jstar": "bin/jstar.js"
7
7
  },
8
- "scripts": {
9
- "build": "tsc",
10
- "index:init": "ts-node scripts/indexer.ts --init",
11
- "index:watch": "ts-node scripts/indexer.ts --watch",
12
- "review": "ts-node scripts/reviewer.ts",
13
- "chat": "ts-node scripts/chat.ts",
14
- "detect": "ts-node scripts/detective.ts",
15
- "prepare": "husky install"
16
- },
17
8
  "keywords": [
18
9
  "code-review",
19
10
  "ai",
@@ -65,5 +56,13 @@
65
56
  "type": "commonjs",
66
57
  "bugs": {
67
58
  "url": "https://github.com/JStaRFilms/jstar-code-review/issues"
59
+ },
60
+ "scripts": {
61
+ "build": "tsc",
62
+ "index:init": "ts-node scripts/indexer.ts --init",
63
+ "index:watch": "ts-node scripts/indexer.ts --watch",
64
+ "review": "ts-node scripts/reviewer.ts",
65
+ "chat": "ts-node scripts/chat.ts",
66
+ "detect": "ts-node scripts/detective.ts"
68
67
  }
69
68
  }
@@ -69,6 +69,30 @@ function sleep(ms: number): Promise<void> {
69
69
  return new Promise(resolve => setTimeout(resolve, ms));
70
70
  }
71
71
 
72
+ async function getDefaultBranch(): Promise<string> {
73
+ try {
74
+ // Method 1: Check remote HEAD (most reliable)
75
+ try {
76
+ const remote = await git.remote(['show', 'origin']);
77
+ if (typeof remote === 'string') {
78
+ const match = remote.match(/HEAD branch: (\S+)/);
79
+ if (match) return match[1];
80
+ }
81
+ } catch (e) {
82
+ // No remote or network issue, proceed to local check
83
+ }
84
+
85
+ // Method 2: Check which common branch exists locally
86
+ const branches = await git.branchLocal();
87
+ if (branches.all.includes('main')) return 'main';
88
+ if (branches.all.includes('master')) return 'master';
89
+
90
+ } catch (e) {
91
+ // Fallback
92
+ }
93
+ return 'main';
94
+ }
95
+
72
96
  /**
73
97
  * Filter issues by confidence threshold and log what was removed
74
98
  */
@@ -165,13 +189,84 @@ async function main() {
165
189
  await detective.scan();
166
190
  detective.report();
167
191
 
168
- // 1. Get the Diff
169
- const diff = await git.diff(["--staged"]);
192
+ // 1. Determine Diff Target
193
+ const args = process.argv.slice(2);
194
+ let diff: string;
195
+ let reviewTarget = "Staged Changes";
196
+
197
+ if (args.includes('--last')) {
198
+ reviewTarget = "Last Commit";
199
+ diff = await git.diff(["HEAD~1", "HEAD"]);
200
+ } else if (args.includes('--commit')) {
201
+ const hashIndex = args.indexOf('--commit') + 1;
202
+ if (hashIndex < args.length) {
203
+ const hash = args[hashIndex];
204
+ reviewTarget = `Commit ${hash}`;
205
+ diff = await git.diff([`${hash}~1`, `${hash}`]);
206
+ } else {
207
+ Logger.error(chalk.red("āŒ Missing commit hash for --commit"));
208
+ return;
209
+ }
210
+ } else if (args.includes('--range')) {
211
+ const rangeIndex = args.indexOf('--range') + 1;
212
+ if (rangeIndex + 1 < args.length) {
213
+ const start = args[rangeIndex];
214
+ const end = args[rangeIndex + 1];
215
+ reviewTarget = `Range ${start}..${end}`;
216
+ diff = await git.diff([start, end]);
217
+ } else {
218
+ Logger.error(chalk.red("āŒ Missing arguments for --range (usage: --range <start> <end>)"));
219
+ return;
220
+ }
221
+ } else if (args.includes('--pr')) {
222
+ const prIndex = args.indexOf('--pr');
223
+ // Check for --base flag first
224
+ let baseBranch = 'main';
225
+
226
+ if (args.includes('--base')) {
227
+ const baseIndex = args.indexOf('--base') + 1;
228
+ if (baseIndex < args.length) {
229
+ baseBranch = args[baseIndex];
230
+ } else {
231
+ Logger.error(chalk.red("āŒ Missing branch name for --base"));
232
+ return;
233
+ }
234
+ } else {
235
+ // Check positional argument (backward compatibility)
236
+ const potentialBase = args[prIndex + 1];
237
+ if (potentialBase && !potentialBase.startsWith('--')) {
238
+ baseBranch = potentialBase;
239
+ } else {
240
+ // Auto-detect
241
+ baseBranch = await getDefaultBranch();
242
+ }
243
+ }
244
+
245
+ reviewTarget = `PR (HEAD vs ${baseBranch})`;
246
+ // Use triple-dot for merge-base difference (what a PR shows)
247
+ try {
248
+ diff = await git.diff([`${baseBranch}...HEAD`]);
249
+ } catch (e) {
250
+ Logger.error(chalk.red(`āŒ Failed to diff against ${baseBranch}. Does the branch exist?`));
251
+ return;
252
+ }
253
+ } else {
254
+ // Default: Staged changes
255
+ diff = await git.diff(["--staged"]);
256
+ }
257
+
170
258
  if (!diff) {
171
- Logger.info(chalk.green("\nāœ… No staged changes to review. (Did you 'git add'?)"));
259
+ if (reviewTarget === "Staged Changes") {
260
+ Logger.info(chalk.green("\nāœ… No staged changes to review. (Did you 'git add'?)"));
261
+ Logger.info(chalk.dim(" Tip: Use '--last' to review the previous commit."));
262
+ } else {
263
+ Logger.info(chalk.green(`\nāœ… No changes found in ${reviewTarget}.`));
264
+ }
172
265
  return;
173
266
  }
174
267
 
268
+ Logger.info(chalk.blue(`\nšŸ“ Reviewing: ${reviewTarget}`));
269
+
175
270
  // 2. Load the Brain
176
271
  if (!fs.existsSync(STORAGE_DIR)) {
177
272
  Logger.error(chalk.red("āŒ Local Brain not found. Run 'pnpm run index:init' first."));