jstar-reviewer 2.0.4 → 2.1.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/README.md CHANGED
@@ -37,10 +37,13 @@ curl -fsSL https://raw.githubusercontent.com/JStaRFilms/jstar-code-review/v2.0.0
37
37
 
38
38
  ### After Install:
39
39
 
40
- 1. Copy `.env.example` `.env.local`
41
- 2. Add your `GOOGLE_API_KEY` and `GROQ_API_KEY`
42
- 3. Run `jstar init` to build the brain
43
- 4. Run `jstar review` to review staged changes
40
+ 1. **Check Config**: The tool now **auto-creates** `.env.example` and `.jstar/` when you run it.
41
+ 2. **Add Keys**: Copy `.env.example` → `.env.local` and add your `GOOGLE_API_KEY` and `GROQ_API_KEY`.
42
+ 3. **Index**: Run `jstar init` (or `pnpm run index:init`) to build the brain.
43
+ 4. **Review**: Stage changes (`git add`) and run `jstar review` (or `pnpm run review`).
44
+
45
+ For a detailed walkthrough, see **[ONBOARDING.md](./ONBOARDING.md)**.
46
+
44
47
 
45
48
  ---
46
49
 
package/bin/jstar.js CHANGED
@@ -134,35 +134,48 @@ function runScript(scriptName) {
134
134
  });
135
135
  }
136
136
 
137
+ const REQUIRED_ENV_VARS = {
138
+ 'GOOGLE_API_KEY': '# Required: Google API key for Gemini embeddings\nGOOGLE_API_KEY=your_google_api_key_here',
139
+ 'GROQ_API_KEY': '# Required: Groq API key for LLM reviews\nGROQ_API_KEY=your_groq_api_key_here',
140
+ 'REVIEW_MODEL_NAME': '# Optional: Override the default model\n# REVIEW_MODEL_NAME=moonshotai/kimi-k2-instruct-0905'
141
+ };
142
+
137
143
  function createSetupFiles() {
138
144
  const cwd = process.cwd();
139
145
 
140
- // Create .jstar directory
146
+ // 1. Create .jstar directory
141
147
  const jstarDir = path.join(cwd, '.jstar');
142
148
  if (!fs.existsSync(jstarDir)) {
143
149
  fs.mkdirSync(jstarDir, { recursive: true });
144
150
  log(`${COLORS.green}✓${COLORS.reset} Created .jstar/`);
145
151
  }
146
152
 
147
- // Create .env.example
148
- const envExample = `# J-Star Reviewer Configuration
149
- # Copy this to .env.local and fill in your keys
150
-
151
- # Required: Google API key for Gemini embeddings
152
- GOOGLE_API_KEY=your_google_api_key_here
153
+ // 2. Create/Update .env.example
154
+ const envExamplePath = path.join(cwd, '.env.example');
155
+ if (fs.existsSync(envExamplePath)) {
156
+ let content = fs.readFileSync(envExamplePath, 'utf-8');
157
+ let addedKeys = [];
153
158
 
154
- # Required: Groq API key for LLM reviews
155
- GROQ_API_KEY=your_groq_api_key_here
156
- `;
159
+ for (const [key, template] of Object.entries(REQUIRED_ENV_VARS)) {
160
+ if (!content.includes(key)) {
161
+ content += '\n' + template + '\n';
162
+ addedKeys.push(key);
163
+ }
164
+ }
157
165
 
158
- const envPath = path.join(cwd, '.env.example');
159
- if (!fs.existsSync(envPath)) {
160
- fs.writeFileSync(envPath, envExample);
161
- log(`${COLORS.green}✓${COLORS.reset} Created .env.example`);
166
+ if (addedKeys.length > 0) {
167
+ fs.writeFileSync(envExamplePath, content);
168
+ log(`${COLORS.green}✓${COLORS.reset} Updated .env.example with missing keys: ${addedKeys.join(', ')}`);
169
+ } else {
170
+ log(`${COLORS.dim} .env.example already exists and is up to date${COLORS.reset}`);
171
+ }
162
172
  } else {
163
- log(`${COLORS.dim} .env.example already exists${COLORS.reset}`);
173
+ const initialEnv = "# J-Star Code Reviewer\n" + Object.values(REQUIRED_ENV_VARS).join("\n") + "\n";
174
+ fs.writeFileSync(envExamplePath, initialEnv);
175
+ log(`${COLORS.green}✓${COLORS.reset} Created .env.example`);
164
176
  }
165
177
 
178
+
166
179
  // Update .gitignore
167
180
  const gitignorePath = path.join(cwd, '.gitignore');
168
181
  const gitignoreAdditions = `
@@ -1,17 +1,85 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
5
38
  Object.defineProperty(exports, "__esModule", { value: true });
6
39
  exports.Config = void 0;
7
40
  const dotenv_1 = __importDefault(require("dotenv"));
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ // --- Auto-Setup Logic ---
44
+ const REQUIRED_ENV_VARS = {
45
+ 'GOOGLE_API_KEY': '# Required: Google API key for Gemini embeddings\nGOOGLE_API_KEY=your_google_api_key_here',
46
+ 'GROQ_API_KEY': '# Required: Groq API key for LLM reviews\nGROQ_API_KEY=your_groq_api_key_here',
47
+ 'REVIEW_MODEL_NAME': '# Optional: Override the default model\n# REVIEW_MODEL_NAME=moonshotai/kimi-k2-instruct-0905'
48
+ };
49
+ function ensureSetup() {
50
+ const cwd = process.cwd();
51
+ const jstarDir = path.join(cwd, ".jstar");
52
+ const envExamplePath = path.join(cwd, ".env.example");
53
+ // 1. Ensure .jstar exists
54
+ if (!fs.existsSync(jstarDir)) {
55
+ fs.mkdirSync(jstarDir, { recursive: true });
56
+ }
57
+ // 2. Ensure .env.example is up to date
58
+ if (fs.existsSync(envExamplePath)) {
59
+ let content = fs.readFileSync(envExamplePath, 'utf-8');
60
+ let missing = false;
61
+ for (const [key, template] of Object.entries(REQUIRED_ENV_VARS)) {
62
+ if (!content.includes(key)) {
63
+ content += `\n${template}\n`;
64
+ missing = true;
65
+ }
66
+ }
67
+ if (missing) {
68
+ fs.writeFileSync(envExamplePath, content);
69
+ }
70
+ }
71
+ else {
72
+ const initialEnv = "# J-Star Code Reviewer\n" + Object.values(REQUIRED_ENV_VARS).join("\n") + "\n";
73
+ fs.writeFileSync(envExamplePath, initialEnv);
74
+ }
75
+ }
76
+ // Run setup check
77
+ ensureSetup();
8
78
  // Load .env.local first, then .env
9
79
  dotenv_1.default.config({ path: ".env.local" });
10
80
  dotenv_1.default.config();
11
81
  /**
12
82
  * Default fallback values.
13
- * These are intentional fallbacks when environment variables are not configured.
14
- * Override via REVIEW_MODEL_NAME env var for production use.
15
83
  */
16
84
  const DEFAULT_MODEL = "moonshotai/kimi-k2-instruct-0905";
17
85
  exports.Config = {
@@ -42,19 +42,16 @@ const mock_llm_1 = require("./mock-llm");
42
42
  const path = __importStar(require("path"));
43
43
  const fs = __importStar(require("fs"));
44
44
  const chalk_1 = __importDefault(require("chalk"));
45
- const dotenv_1 = __importDefault(require("dotenv"));
46
- // Load .env.local first, then .env
47
- dotenv_1.default.config({ path: ".env.local" });
48
- dotenv_1.default.config();
49
45
  // Configuration
50
46
  const STORAGE_DIR = path.join(process.cwd(), ".jstar", "storage");
51
47
  const SOURCE_DIR = path.join(process.cwd(), "scripts"); // Changed from src/ to scripts/
52
- // Ensure OpenAI Key exists (LlamaIndex default) or fallback if we configured something else
53
- // (We are using local now, so this check is less critical, but good to have if we revert)
54
- // if (!process.env.OPENAI_API_KEY) {
55
- // console.warn(chalk.yellow("⚠️ OPENAI_API_KEY not found. Embeddings may fail unless you have configured a local model."));
56
- // }
57
48
  async function main() {
49
+ // 0. Environment Validation
50
+ if (!process.env.GOOGLE_API_KEY) {
51
+ console.error(chalk_1.default.red("❌ Missing GOOGLE_API_KEY!"));
52
+ console.log(chalk_1.default.yellow("\nPlease ensure you have a .env.local file. Check .env.example for a template.\n"));
53
+ process.exit(1);
54
+ }
58
55
  const args = process.argv.slice(2);
59
56
  const isWatch = args.includes("--watch");
60
57
  console.log(chalk_1.default.blue("🧠 J-Star Indexer: Scanning codebase..."));
@@ -125,7 +125,16 @@ function parseReviewResponse(text) {
125
125
  // --- Main ---
126
126
  async function main() {
127
127
  console.log(chalk_1.default.blue("🕵️ J-Star Reviewer: Analyzing your changes...\n"));
128
- // 0. Detective
128
+ // 0. Environment Validation
129
+ if (!process.env.GOOGLE_API_KEY || !process.env.GROQ_API_KEY) {
130
+ console.error(chalk_1.default.red("❌ Missing API Keys!"));
131
+ console.log(chalk_1.default.yellow("\nPlease ensure you have a .env.local file with:"));
132
+ console.log(chalk_1.default.white("- GOOGLE_API_KEY"));
133
+ console.log(chalk_1.default.white("- GROQ_API_KEY"));
134
+ console.log(chalk_1.default.white("\nCheck .env.example for a template.\n"));
135
+ return;
136
+ }
137
+ // 1. Detective
129
138
  console.log(chalk_1.default.blue("🔎 Running Detective Engine..."));
130
139
  const detective = new detective_1.Detective(SOURCE_DIR);
131
140
  await detective.scan();
package/package.json CHANGED
@@ -1,18 +1,10 @@
1
1
  {
2
2
  "name": "jstar-reviewer",
3
- "version": "2.0.4",
3
+ "version": "2.1.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
- "detect": "ts-node scripts/detective.ts",
14
- "prepare": "husky install"
15
- },
16
8
  "keywords": [
17
9
  "code-review",
18
10
  "ai",
@@ -62,5 +54,12 @@
62
54
  "type": "commonjs",
63
55
  "bugs": {
64
56
  "url": "https://github.com/JStaRFilms/jstar-code-review/issues"
57
+ },
58
+ "scripts": {
59
+ "build": "tsc",
60
+ "index:init": "ts-node scripts/indexer.ts --init",
61
+ "index:watch": "ts-node scripts/indexer.ts --watch",
62
+ "review": "ts-node scripts/reviewer.ts",
63
+ "detect": "ts-node scripts/detective.ts"
65
64
  }
66
65
  }
package/scripts/config.ts CHANGED
@@ -1,14 +1,53 @@
1
1
  import dotenv from "dotenv";
2
+ import * as fs from "fs";
3
+ import * as path from "path";
2
4
  import { Severity } from "./types";
3
5
 
6
+ // --- Auto-Setup Logic ---
7
+ const REQUIRED_ENV_VARS = {
8
+ 'GOOGLE_API_KEY': '# Required: Google API key for Gemini embeddings\nGOOGLE_API_KEY=your_google_api_key_here',
9
+ 'GROQ_API_KEY': '# Required: Groq API key for LLM reviews\nGROQ_API_KEY=your_groq_api_key_here',
10
+ 'REVIEW_MODEL_NAME': '# Optional: Override the default model\n# REVIEW_MODEL_NAME=moonshotai/kimi-k2-instruct-0905'
11
+ };
12
+
13
+ function ensureSetup() {
14
+ const cwd = process.cwd();
15
+ const jstarDir = path.join(cwd, ".jstar");
16
+ const envExamplePath = path.join(cwd, ".env.example");
17
+
18
+ // 1. Ensure .jstar exists
19
+ if (!fs.existsSync(jstarDir)) {
20
+ fs.mkdirSync(jstarDir, { recursive: true });
21
+ }
22
+
23
+ // 2. Ensure .env.example is up to date
24
+ if (fs.existsSync(envExamplePath)) {
25
+ let content = fs.readFileSync(envExamplePath, 'utf-8');
26
+ let missing = false;
27
+ for (const [key, template] of Object.entries(REQUIRED_ENV_VARS)) {
28
+ if (!content.includes(key)) {
29
+ content += `\n${template}\n`;
30
+ missing = true;
31
+ }
32
+ }
33
+ if (missing) {
34
+ fs.writeFileSync(envExamplePath, content);
35
+ }
36
+ } else {
37
+ const initialEnv = "# J-Star Code Reviewer\n" + Object.values(REQUIRED_ENV_VARS).join("\n") + "\n";
38
+ fs.writeFileSync(envExamplePath, initialEnv);
39
+ }
40
+ }
41
+
42
+ // Run setup check
43
+ ensureSetup();
44
+
4
45
  // Load .env.local first, then .env
5
46
  dotenv.config({ path: ".env.local" });
6
47
  dotenv.config();
7
48
 
8
49
  /**
9
50
  * Default fallback values.
10
- * These are intentional fallbacks when environment variables are not configured.
11
- * Override via REVIEW_MODEL_NAME env var for production use.
12
51
  */
13
52
  const DEFAULT_MODEL = "moonshotai/kimi-k2-instruct-0905";
14
53
 
@@ -19,3 +58,4 @@ export const Config = {
19
58
  MEDIUM: 5
20
59
  }
21
60
  };
61
+
@@ -9,28 +9,26 @@ import { MockLLM } from "./mock-llm";
9
9
  import * as path from "path";
10
10
  import * as fs from "fs";
11
11
  import chalk from "chalk";
12
- import dotenv from "dotenv";
13
-
14
- // Load .env.local first, then .env
15
- dotenv.config({ path: ".env.local" });
16
- dotenv.config();
12
+ import { Config } from "./config";
17
13
 
18
14
  // Configuration
19
15
  const STORAGE_DIR = path.join(process.cwd(), ".jstar", "storage");
20
16
  const SOURCE_DIR = path.join(process.cwd(), "scripts"); // Changed from src/ to scripts/
21
17
 
22
- // Ensure OpenAI Key exists (LlamaIndex default) or fallback if we configured something else
23
- // (We are using local now, so this check is less critical, but good to have if we revert)
24
- // if (!process.env.OPENAI_API_KEY) {
25
- // console.warn(chalk.yellow("⚠️ OPENAI_API_KEY not found. Embeddings may fail unless you have configured a local model."));
26
- // }
27
-
28
18
  async function main() {
19
+ // 0. Environment Validation
20
+ if (!process.env.GOOGLE_API_KEY) {
21
+ console.error(chalk.red("❌ Missing GOOGLE_API_KEY!"));
22
+ console.log(chalk.yellow("\nPlease ensure you have a .env.local file. Check .env.example for a template.\n"));
23
+ process.exit(1);
24
+ }
25
+
29
26
  const args = process.argv.slice(2);
30
27
  const isWatch = args.includes("--watch");
31
28
 
32
29
  console.log(chalk.blue("🧠 J-Star Indexer: Scanning codebase..."));
33
30
 
31
+
34
32
  // 1. Load documents (Your Code)
35
33
  if (!fs.existsSync(SOURCE_DIR)) {
36
34
  console.error(chalk.red(`❌ Source directory not found: ${SOURCE_DIR}`));
@@ -109,8 +109,19 @@ function parseReviewResponse(text: string): LLMReviewResponse {
109
109
  async function main() {
110
110
  console.log(chalk.blue("🕵️ J-Star Reviewer: Analyzing your changes...\n"));
111
111
 
112
- // 0. Detective
112
+ // 0. Environment Validation
113
+ if (!process.env.GOOGLE_API_KEY || !process.env.GROQ_API_KEY) {
114
+ console.error(chalk.red("❌ Missing API Keys!"));
115
+ console.log(chalk.yellow("\nPlease ensure you have a .env.local file with:"));
116
+ console.log(chalk.white("- GOOGLE_API_KEY"));
117
+ console.log(chalk.white("- GROQ_API_KEY"));
118
+ console.log(chalk.white("\nCheck .env.example for a template.\n"));
119
+ return;
120
+ }
121
+
122
+ // 1. Detective
113
123
  console.log(chalk.blue("🔎 Running Detective Engine..."));
124
+
114
125
  const detective = new Detective(SOURCE_DIR);
115
126
  await detective.scan();
116
127
  detective.report();
package/setup.js CHANGED
@@ -115,7 +115,7 @@ async function main() {
115
115
 
116
116
  // HARDCODED: Tagged release URL - NOT configurable for security
117
117
  // To update, modify this constant and publish a new version of setup.js
118
- const BASE_URL = 'https://raw.githubusercontent.com/JStaRFilms/jstar-code-review/v2.0.0';
118
+ const BASE_URL = 'https://raw.githubusercontent.com/JStaRFilms/jstar-code-review/v2.1.0';
119
119
 
120
120
  // Validate URL matches our exact expected pattern (defense in depth)
121
121
  function isValidUrl(url) {