jstar-reviewer 2.1.4 → 2.2.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 +12 -1
- package/dist/scripts/chat.js +150 -0
- package/dist/scripts/config.js +5 -1
- package/dist/scripts/core/critique.js +137 -0
- package/dist/scripts/core/debate.js +95 -0
- package/dist/scripts/detective.js +5 -4
- package/dist/scripts/reviewer.js +136 -41
- package/dist/scripts/session.js +273 -0
- package/dist/scripts/ui/interaction.js +43 -0
- package/dist/scripts/utils/logger.js +110 -0
- package/package.json +14 -10
- package/scripts/chat.ts +130 -0
- package/scripts/config.ts +5 -1
- package/scripts/core/critique.ts +162 -0
- package/scripts/core/debate.ts +111 -0
- package/scripts/detective.ts +5 -4
- package/scripts/reviewer.ts +151 -41
- package/scripts/session.ts +312 -0
- package/scripts/types.ts +9 -0
- package/scripts/ui/interaction.ts +38 -0
- package/scripts/utils/logger.ts +118 -0
- package/setup.js +1 -1
- package/scripts/local-embedding.ts +0 -55
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import prompts from 'prompts';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
|
|
4
|
+
export type UserAction = 'accept' | 'discuss' | 'ignore' | 'exit';
|
|
5
|
+
|
|
6
|
+
export async function showActionMenu(issueTitle: string): Promise<UserAction> {
|
|
7
|
+
try {
|
|
8
|
+
const response = await prompts({
|
|
9
|
+
type: 'select',
|
|
10
|
+
name: 'action',
|
|
11
|
+
message: `Action for: ${chalk.yellow(issueTitle)}`,
|
|
12
|
+
choices: [
|
|
13
|
+
{ title: '✅ Accept', value: 'accept', description: 'Mark as valid issue' },
|
|
14
|
+
{ title: '💬 Discuss', value: 'discuss', description: 'Debate this finding with AI' },
|
|
15
|
+
{ title: '❌ Ignore', value: 'ignore', description: 'Discard this issue' },
|
|
16
|
+
{ title: '🚪 Exit', value: 'exit', description: 'Stop review session' }
|
|
17
|
+
],
|
|
18
|
+
initial: 0
|
|
19
|
+
});
|
|
20
|
+
return response.action || 'exit';
|
|
21
|
+
} catch (e) {
|
|
22
|
+
return 'exit';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function askForArgument(): Promise<string> {
|
|
27
|
+
try {
|
|
28
|
+
const response = await prompts({
|
|
29
|
+
type: 'text',
|
|
30
|
+
name: 'argument',
|
|
31
|
+
message: 'Your argument (e.g., "Check utils.ts, logic is handled there"):',
|
|
32
|
+
validate: value => value.length < 5 ? 'Please provide more context' : true
|
|
33
|
+
});
|
|
34
|
+
return response.argument || '';
|
|
35
|
+
} catch (e) {
|
|
36
|
+
return '';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Logger Utility
|
|
5
|
+
* Centralizes all CLI output to support both human-readable (TTY) and machine-readable (JSON) modes.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* Logger.init(); // Auto-detects --json flag
|
|
9
|
+
* Logger.info("Starting..."); // Suppressed in JSON mode
|
|
10
|
+
* Logger.json({ status: "ok" }); // Only outputs in JSON mode
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
let jsonMode = false;
|
|
14
|
+
|
|
15
|
+
export const Logger = {
|
|
16
|
+
/**
|
|
17
|
+
* Initialize the logger.
|
|
18
|
+
* Auto-detects --json or --headless flags from process.argv.
|
|
19
|
+
*/
|
|
20
|
+
init() {
|
|
21
|
+
jsonMode = process.argv.includes('--json') || process.argv.includes('--headless');
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Check if we are in headless/JSON mode.
|
|
26
|
+
*/
|
|
27
|
+
isHeadless() {
|
|
28
|
+
return jsonMode;
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Alias for isHeadless for backwards compatibility.
|
|
33
|
+
*/
|
|
34
|
+
isJsonMode() {
|
|
35
|
+
return jsonMode;
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Standard informational message (suppressed in JSON mode).
|
|
40
|
+
*/
|
|
41
|
+
info(message: string) {
|
|
42
|
+
if (!jsonMode) {
|
|
43
|
+
console.log(message);
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Success message with green styling (suppressed in JSON mode).
|
|
49
|
+
*/
|
|
50
|
+
success(message: string) {
|
|
51
|
+
if (!jsonMode) {
|
|
52
|
+
console.log(chalk.green(message));
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Warning message with yellow styling (suppressed in JSON mode).
|
|
58
|
+
*/
|
|
59
|
+
warn(message: string) {
|
|
60
|
+
if (!jsonMode) {
|
|
61
|
+
console.log(chalk.yellow(message));
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Error message - always outputs to stderr.
|
|
67
|
+
*/
|
|
68
|
+
error(message: string) {
|
|
69
|
+
console.error(chalk.red(message));
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Dim/faded message for secondary info (suppressed in JSON mode).
|
|
74
|
+
*/
|
|
75
|
+
dim(message: string) {
|
|
76
|
+
if (!jsonMode) {
|
|
77
|
+
console.log(chalk.dim(message));
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Write inline (no newline) for progress indicators (suppressed in JSON mode).
|
|
83
|
+
* Alias: progress()
|
|
84
|
+
*/
|
|
85
|
+
inline(message: string) {
|
|
86
|
+
if (!jsonMode) {
|
|
87
|
+
process.stdout.write(message);
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Progress indicator - writes inline without newline.
|
|
93
|
+
*/
|
|
94
|
+
progress(message: string) {
|
|
95
|
+
if (!jsonMode) {
|
|
96
|
+
process.stdout.write(message);
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Output structured JSON to stdout.
|
|
102
|
+
* Only outputs in JSON mode. For API/AI consumption.
|
|
103
|
+
*/
|
|
104
|
+
json(data: object) {
|
|
105
|
+
if (jsonMode) {
|
|
106
|
+
console.log(JSON.stringify(data, null, 2));
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Output a single-line JSON object (for streaming events).
|
|
112
|
+
*/
|
|
113
|
+
jsonLine(data: object) {
|
|
114
|
+
if (jsonMode) {
|
|
115
|
+
console.log(JSON.stringify(data));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
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.
|
|
118
|
+
const BASE_URL = 'https://raw.githubusercontent.com/JStaRFilms/jstar-code-review/v2.2.0';
|
|
119
119
|
|
|
120
120
|
// Validate URL matches our exact expected pattern (defense in depth)
|
|
121
121
|
function isValidUrl(url) {
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { pipeline, env } from "@xenova/transformers";
|
|
2
|
-
|
|
3
|
-
// Skip local model checks if needed, or let it download
|
|
4
|
-
env.allowLocalModels = false;
|
|
5
|
-
env.useBrowserCache = false;
|
|
6
|
-
|
|
7
|
-
export class LocalEmbedding {
|
|
8
|
-
private pipe: any;
|
|
9
|
-
private modelName: string;
|
|
10
|
-
|
|
11
|
-
constructor() {
|
|
12
|
-
this.modelName = "Xenova/bge-small-en-v1.5";
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async init() {
|
|
16
|
-
if (!this.pipe) {
|
|
17
|
-
console.log("📥 Loading local embedding model (Xenova/bge-small-en-v1.5)...");
|
|
18
|
-
this.pipe = await pipeline("feature-extraction", this.modelName);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async getTextEmbedding(text: string): Promise<number[]> {
|
|
23
|
-
await this.init();
|
|
24
|
-
const result = await this.pipe(text, { pooling: "mean", normalize: true });
|
|
25
|
-
return Array.from(result.data);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async getQueryEmbedding(query: string): Promise<number[]> {
|
|
29
|
-
return this.getTextEmbedding(query);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Batch method (Required by LlamaIndex)
|
|
33
|
-
async getTextEmbeddings(texts: string[]): Promise<number[][]> {
|
|
34
|
-
await this.init();
|
|
35
|
-
const embeddings: number[][] = [];
|
|
36
|
-
for (const text of texts) {
|
|
37
|
-
embeddings.push(await this.getTextEmbedding(text));
|
|
38
|
-
}
|
|
39
|
-
return embeddings;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Stubs for BaseEmbedding interface compliance
|
|
43
|
-
embedBatchSize = 10;
|
|
44
|
-
similarity(embedding1: number[], embedding2: number[]): number {
|
|
45
|
-
// Simple dot product for normalized vectors
|
|
46
|
-
return embedding1.reduce((sum, val, i) => sum + val * embedding2[i], 0);
|
|
47
|
-
}
|
|
48
|
-
async transform(nodes: any[], _options?: any): Promise<any[]> {
|
|
49
|
-
for (const node of nodes) {
|
|
50
|
-
node.embedding = await this.getTextEmbedding(node.getContent("text"));
|
|
51
|
-
}
|
|
52
|
-
return nodes;
|
|
53
|
-
}
|
|
54
|
-
async getTextEmbeddingsBatch(texts: string[]): Promise<number[][]> { return this.getTextEmbeddings(texts); }
|
|
55
|
-
}
|