ai-codegen-cli-vrk 1.0.1 → 2.0.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/index.js +1 -1
- package/package.json +6 -4
- package/src/aiClient.js +68 -100
- package/src/fileWriter.js +4 -7
- package/src/runner.js +37 -53
- package/src/promptTemplate.js +0 -34
package/bin/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "../src/runner.js";
|
|
2
|
+
import "../src/runner.js";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-codegen-cli-vrk",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Terminal-based AI code generator",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Minimalist Terminal-based AI code generator using Gemini",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"ai-codegen": "bin/index.js"
|
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
],
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"fs-extra": "^11.2.0",
|
|
15
|
-
"groq-sdk": "^0.7.0",
|
|
16
15
|
"readline-sync": "^1.4.10"
|
|
16
|
+
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=18.0.0"
|
|
17
19
|
}
|
|
18
|
-
}
|
|
20
|
+
}
|
package/src/aiClient.js
CHANGED
|
@@ -1,110 +1,78 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
let groqClient = null;
|
|
1
|
+
let API_KEY = null;
|
|
2
|
+
let SELECTED_MODEL = null;
|
|
4
3
|
|
|
5
4
|
export function setApiKey(apiKey) {
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
async function call(messages) {
|
|
10
|
-
if (!groqClient) {
|
|
11
|
-
throw new Error("API key not initialized");
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
return groqClient.chat.completions.create({
|
|
15
|
-
model: "llama-3.1-8b-instant",
|
|
16
|
-
temperature: 0,
|
|
17
|
-
messages
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/* ========= PHASE 1: FILE PLAN ========= */
|
|
22
|
-
export async function generateFilePlan(task, tests) {
|
|
23
|
-
const res = await call([
|
|
24
|
-
{
|
|
25
|
-
role: "system",
|
|
26
|
-
content: `
|
|
27
|
-
Return ONLY JSON.
|
|
28
|
-
|
|
29
|
-
Generate ONLY file paths required to solve the task.
|
|
30
|
-
|
|
31
|
-
FORMAT:
|
|
32
|
-
{
|
|
33
|
-
"files": [
|
|
34
|
-
{ "path": "file.ext" }
|
|
35
|
-
]
|
|
36
|
-
}
|
|
37
|
-
`
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
role: "user",
|
|
41
|
-
content: `TASK:\n${task}\n\nTESTS:\n${tests}`
|
|
42
|
-
}
|
|
43
|
-
]);
|
|
44
|
-
|
|
45
|
-
const parsed = JSON.parse(res.choices[0].message.content);
|
|
46
|
-
|
|
47
|
-
if (!Array.isArray(parsed.files)) {
|
|
48
|
-
throw new Error("Invalid file plan from AI");
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return parsed.files.map(f => f.path);
|
|
5
|
+
API_KEY = apiKey;
|
|
52
6
|
}
|
|
53
7
|
|
|
54
|
-
|
|
55
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Automatically finds the exact model name assigned to your key.
|
|
10
|
+
*/
|
|
11
|
+
async function getValidModel() {
|
|
12
|
+
if (SELECTED_MODEL) return SELECTED_MODEL;
|
|
13
|
+
const url = `https://generativelanguage.googleapis.com/v1/models?key=${API_KEY}`;
|
|
56
14
|
try {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
No markdown.
|
|
67
|
-
Return RAW CODE ONLY.
|
|
68
|
-
`
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
role: "user",
|
|
72
|
-
content: `TASK:\n${task}\n\nTESTS:\n${tests}`
|
|
73
|
-
}
|
|
74
|
-
]);
|
|
75
|
-
|
|
76
|
-
const content = res.choices[0].message.content?.trim();
|
|
77
|
-
|
|
78
|
-
if (content && content.length > 0) {
|
|
79
|
-
return { path: filePath, content };
|
|
80
|
-
}
|
|
15
|
+
const response = await fetch(url);
|
|
16
|
+
const data = await response.json();
|
|
17
|
+
if (!response.ok) throw new Error();
|
|
18
|
+
const found = (data.models || []).find(m =>
|
|
19
|
+
m.supportedGenerationMethods.includes("generateContent") &&
|
|
20
|
+
(m.name.includes("flash") || m.name.includes("pro"))
|
|
21
|
+
);
|
|
22
|
+
SELECTED_MODEL = found ? found.name : "models/gemini-1.5-flash";
|
|
23
|
+
return SELECTED_MODEL;
|
|
81
24
|
} catch {
|
|
82
|
-
|
|
25
|
+
SELECTED_MODEL = "models/gemini-1.5-flash";
|
|
26
|
+
return SELECTED_MODEL;
|
|
83
27
|
}
|
|
28
|
+
}
|
|
84
29
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
30
|
+
export async function generateFullProject(task, tests) {
|
|
31
|
+
const modelPath = await getValidModel();
|
|
32
|
+
const url = `https://generativelanguage.googleapis.com/v1/${modelPath}:generateContent?key=${API_KEY}`;
|
|
33
|
+
|
|
34
|
+
const prompt = `
|
|
35
|
+
You are an expert automated coding exam solver.
|
|
36
|
+
Generate the ENTIRE project in a SINGLE continuous text response.
|
|
37
|
+
|
|
38
|
+
### RULES:
|
|
39
|
+
1. ABSOLUTE PRIORITY: Test cases are the ONLY specification.
|
|
40
|
+
2. MINIMALIST: Generate the bare minimum code to pass. No extra logic, no comments, no console logs.
|
|
41
|
+
3. FLAT STRUCTURE: Use simple, standard patterns.
|
|
42
|
+
4. DEPENDENCIES: Only use 'express', 'mongoose', 'jsonwebtoken', and 'cookie-parser' if needed.
|
|
43
|
+
|
|
44
|
+
### FORMATTING (STRICT):
|
|
45
|
+
Every file MUST start with this EXACT header style:
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* ==========================================
|
|
49
|
+
* FILE: package.json (Reference)
|
|
50
|
+
* ==========================================
|
|
51
|
+
* [List Dependencies here]
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
// ==========================================
|
|
55
|
+
// FILE: path/to/filename.js
|
|
56
|
+
// ==========================================
|
|
57
|
+
[CODE HERE]
|
|
58
|
+
|
|
59
|
+
### TASK:
|
|
60
|
+
${task}
|
|
61
|
+
|
|
62
|
+
### TESTS:
|
|
63
|
+
${tests}
|
|
64
|
+
`;
|
|
65
|
+
|
|
66
|
+
const response = await fetch(url, {
|
|
67
|
+
method: "POST",
|
|
68
|
+
headers: { "Content-Type": "application/json" },
|
|
69
|
+
body: JSON.stringify({ contents: [{ parts: [{ text: prompt }] }] })
|
|
70
|
+
});
|
|
98
71
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
path: filePath,
|
|
102
|
-
content: `module.exports = {};`
|
|
103
|
-
};
|
|
104
|
-
}
|
|
72
|
+
const data = await response.json();
|
|
73
|
+
if (!response.ok) throw new Error();
|
|
105
74
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
75
|
+
const text = data.candidates?.[0]?.content?.parts?.[0]?.text || "";
|
|
76
|
+
// Strip markdown backticks to return clean text
|
|
77
|
+
return text.replace(/```[a-z]*\n([\s\S]*?)\n```/gi, "$1").trim();
|
|
78
|
+
}
|
package/src/fileWriter.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import fs from "fs-extra";
|
|
2
2
|
import path from "path";
|
|
3
3
|
|
|
4
|
-
export async function
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
await fs.writeFile(fullPath, file.content, "utf8");
|
|
9
|
-
}
|
|
10
|
-
}
|
|
4
|
+
export async function writeSingleFile(baseDir, content) {
|
|
5
|
+
const outputPath = path.join(baseDir, "generated_project.txt");
|
|
6
|
+
await fs.writeFile(outputPath, content, "utf8");
|
|
7
|
+
}
|
package/src/runner.js
CHANGED
|
@@ -1,63 +1,47 @@
|
|
|
1
1
|
import readlineSync from "readline-sync";
|
|
2
2
|
import fs from "fs";
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const apiKey = readlineSync.question("--- ", {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const testsInput = readlineSync.question("-- ");
|
|
27
|
-
let tests = "";
|
|
28
|
-
|
|
29
|
-
try {
|
|
30
|
-
if (
|
|
31
|
-
testsInput &&
|
|
32
|
-
(testsInput.endsWith(".js") || testsInput.endsWith(".test.js")) &&
|
|
33
|
-
fs.existsSync(testsInput)
|
|
34
|
-
) {
|
|
35
|
-
tests = fs.readFileSync(testsInput, "utf8");
|
|
36
|
-
} else {
|
|
3
|
+
import { setApiKey, generateFullProject } from "./aiClient.js";
|
|
4
|
+
import { writeSingleFile } from "./fileWriter.js";
|
|
5
|
+
|
|
6
|
+
async function main() {
|
|
7
|
+
// Input: API Key
|
|
8
|
+
const apiKey = readlineSync.question("--- ", { hideEchoBack: true });
|
|
9
|
+
if (!apiKey || apiKey.trim().length === 0) process.exit(1);
|
|
10
|
+
setApiKey(apiKey.trim());
|
|
11
|
+
|
|
12
|
+
// Input: Task
|
|
13
|
+
const task = readlineSync.question("- ");
|
|
14
|
+
if (!task || task.trim().length === 0) process.exit(1);
|
|
15
|
+
|
|
16
|
+
// Input: Test cases (Path or Raw Text)
|
|
17
|
+
const testsInput = readlineSync.question("-- ");
|
|
18
|
+
let tests = "";
|
|
19
|
+
try {
|
|
20
|
+
if (testsInput && fs.existsSync(testsInput)) {
|
|
21
|
+
tests = fs.readFileSync(testsInput, "utf8");
|
|
22
|
+
} else {
|
|
23
|
+
tests = testsInput || "Implement correctly.";
|
|
24
|
+
}
|
|
25
|
+
} catch {
|
|
37
26
|
tests = testsInput;
|
|
38
27
|
}
|
|
39
|
-
} catch {
|
|
40
|
-
tests = testsInput;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/* ---- SILENT FALLBACK ---- */
|
|
44
|
-
if (!tests || tests.trim().length === 0) {
|
|
45
|
-
tests = "No tests provided. Generate a simple correct implementation.";
|
|
46
|
-
}
|
|
47
28
|
|
|
48
|
-
(async () => {
|
|
49
29
|
try {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
30
|
+
// Silent Indicator
|
|
31
|
+
console.log(".....");
|
|
32
|
+
|
|
33
|
+
// Process Single Request
|
|
34
|
+
const projectContent = await generateFullProject(task, tests);
|
|
35
|
+
|
|
36
|
+
// Save to file
|
|
37
|
+
await writeSingleFile(process.cwd(), projectContent);
|
|
38
|
+
|
|
39
|
+
// Silent Exit on Success
|
|
59
40
|
process.exit(0);
|
|
60
41
|
} catch {
|
|
42
|
+
// Silent Exit on Failure
|
|
61
43
|
process.exit(1);
|
|
62
44
|
}
|
|
63
|
-
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
main();
|
package/src/promptTemplate.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export const systemPrompt = `
|
|
2
|
-
You are solving an automated coding exam.
|
|
3
|
-
|
|
4
|
-
ABSOLUTE PRIORITY:
|
|
5
|
-
The given test cases are the ONLY specification.
|
|
6
|
-
|
|
7
|
-
RULES:
|
|
8
|
-
- Generate the MINIMUM code needed
|
|
9
|
-
- No extra logic
|
|
10
|
-
- No comments
|
|
11
|
-
- No console logs
|
|
12
|
-
- No refactoring
|
|
13
|
-
- No optimization
|
|
14
|
-
|
|
15
|
-
ARCHITECTURE:
|
|
16
|
-
- Create ONLY required files
|
|
17
|
-
- Names must match tests EXACTLY
|
|
18
|
-
- Error messages must match EXACTLY
|
|
19
|
-
|
|
20
|
-
OUTPUT:
|
|
21
|
-
- ONLY valid JSON
|
|
22
|
-
- No markdown
|
|
23
|
-
- No explanations
|
|
24
|
-
|
|
25
|
-
FORMAT:
|
|
26
|
-
{
|
|
27
|
-
"files": [
|
|
28
|
-
{
|
|
29
|
-
"path": "relative/path/file.js",
|
|
30
|
-
"content": "exact code"
|
|
31
|
-
}
|
|
32
|
-
]
|
|
33
|
-
}
|
|
34
|
-
`;
|