ai-codegen-cli-vrk 1.0.0 → 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 +60 -114
- package/src/fileWriter.js +4 -7
- package/src/runner.js +39 -48
- package/src/promptTemplate.js +0 -43
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,132 +1,78 @@
|
|
|
1
|
-
|
|
1
|
+
let API_KEY = null;
|
|
2
|
+
let SELECTED_MODEL = null;
|
|
2
3
|
|
|
3
|
-
let groqClient = null;
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Called once per run from runner.js
|
|
7
|
-
*/
|
|
8
4
|
export function setApiKey(apiKey) {
|
|
9
|
-
|
|
5
|
+
API_KEY = apiKey;
|
|
10
6
|
}
|
|
11
7
|
|
|
12
8
|
/**
|
|
13
|
-
*
|
|
9
|
+
* Automatically finds the exact model name assigned to your key.
|
|
14
10
|
*/
|
|
15
|
-
async function
|
|
16
|
-
if (
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
{
|
|
32
|
-
role: "system",
|
|
33
|
-
content: `
|
|
34
|
-
Return ONLY JSON.
|
|
35
|
-
|
|
36
|
-
Generate ONLY file paths required to pass the tests.
|
|
37
|
-
|
|
38
|
-
FORMAT:
|
|
39
|
-
{
|
|
40
|
-
"files": [
|
|
41
|
-
{ "path": "models/AnyModel.js" },
|
|
42
|
-
{ "path": "controllers/anyController.js" },
|
|
43
|
-
{ "path": "routes/anyRoutes.js" },
|
|
44
|
-
{ "path": "index.js" }
|
|
45
|
-
]
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
No explanations.
|
|
49
|
-
`
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
role: "user",
|
|
53
|
-
content: `TASK:\n${task}\n\nTEST CASES:\n${tests}`
|
|
54
|
-
}
|
|
55
|
-
]);
|
|
56
|
-
|
|
57
|
-
const parsed = JSON.parse(res.choices[0].message.content);
|
|
58
|
-
|
|
59
|
-
if (!parsed.files || !Array.isArray(parsed.files)) {
|
|
60
|
-
throw new Error("Invalid file plan");
|
|
11
|
+
async function getValidModel() {
|
|
12
|
+
if (SELECTED_MODEL) return SELECTED_MODEL;
|
|
13
|
+
const url = `https://generativelanguage.googleapis.com/v1/models?key=${API_KEY}`;
|
|
14
|
+
try {
|
|
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;
|
|
24
|
+
} catch {
|
|
25
|
+
SELECTED_MODEL = "models/gemini-1.5-flash";
|
|
26
|
+
return SELECTED_MODEL;
|
|
61
27
|
}
|
|
62
|
-
|
|
63
|
-
return parsed.files.map(f => f.path);
|
|
64
28
|
}
|
|
65
29
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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.
|
|
69
37
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
You are generating ONLY this file:
|
|
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.
|
|
76
43
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
RULES:
|
|
80
|
-
- Tests are the ONLY specification
|
|
81
|
-
- Minimal code only
|
|
82
|
-
- No comments
|
|
83
|
-
- No console logs
|
|
84
|
-
- Use CommonJS (require/module.exports)
|
|
85
|
-
|
|
86
|
-
FORMAT:
|
|
87
|
-
{
|
|
88
|
-
"path": "${filePath}",
|
|
89
|
-
"content": "exact source code"
|
|
90
|
-
}
|
|
91
|
-
`
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
role: "user",
|
|
95
|
-
content: `TASK:\n${task}\n\nTEST CASES:\n${tests}`
|
|
96
|
-
}
|
|
97
|
-
]);
|
|
44
|
+
### FORMATTING (STRICT):
|
|
45
|
+
Every file MUST start with this EXACT header style:
|
|
98
46
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
47
|
+
/**
|
|
48
|
+
* ==========================================
|
|
49
|
+
* FILE: package.json (Reference)
|
|
50
|
+
* ==========================================
|
|
51
|
+
* [List Dependencies here]
|
|
52
|
+
*/
|
|
103
53
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
typeof file.content !== "string" ||
|
|
109
|
-
file.content.trim().length === 0
|
|
110
|
-
) {
|
|
111
|
-
if (filePath.startsWith("models/")) {
|
|
112
|
-
const modelName = filePath
|
|
113
|
-
.replace("models/", "")
|
|
114
|
-
.replace(".js", "");
|
|
54
|
+
// ==========================================
|
|
55
|
+
// FILE: path/to/filename.js
|
|
56
|
+
// ==========================================
|
|
57
|
+
[CODE HERE]
|
|
115
58
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
content:
|
|
119
|
-
`const mongoose = require('mongoose');
|
|
59
|
+
### TASK:
|
|
60
|
+
${task}
|
|
120
61
|
|
|
121
|
-
|
|
62
|
+
### TESTS:
|
|
63
|
+
${tests}
|
|
64
|
+
`;
|
|
122
65
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
66
|
+
const response = await fetch(url, {
|
|
67
|
+
method: "POST",
|
|
68
|
+
headers: { "Content-Type": "application/json" },
|
|
69
|
+
body: JSON.stringify({ contents: [{ parts: [{ text: prompt }] }] })
|
|
70
|
+
});
|
|
127
71
|
|
|
128
|
-
|
|
129
|
-
|
|
72
|
+
const data = await response.json();
|
|
73
|
+
if (!response.ok) throw new Error();
|
|
130
74
|
|
|
131
|
-
|
|
132
|
-
|
|
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,56 +1,47 @@
|
|
|
1
1
|
import readlineSync from "readline-sync";
|
|
2
2
|
import fs from "fs";
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
if (
|
|
29
|
-
(testsInput.endsWith(".js") || testsInput.endsWith(".test.js")) &&
|
|
30
|
-
fs.existsSync(testsInput)
|
|
31
|
-
) {
|
|
32
|
-
tests = fs.readFileSync(testsInput, "utf8");
|
|
33
|
-
} 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 {
|
|
34
26
|
tests = testsInput;
|
|
35
27
|
}
|
|
36
|
-
} catch {
|
|
37
|
-
tests = testsInput;
|
|
38
|
-
}
|
|
39
28
|
|
|
40
|
-
(async () => {
|
|
41
29
|
try {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
|
40
|
+
process.exit(0);
|
|
41
|
+
} catch {
|
|
42
|
+
// Silent Exit on Failure
|
|
54
43
|
process.exit(1);
|
|
55
44
|
}
|
|
56
|
-
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
main();
|
package/src/promptTemplate.js
DELETED
|
@@ -1,43 +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
|
-
Ignore best practices unless tests require them.
|
|
7
|
-
|
|
8
|
-
RULES (STRICT):
|
|
9
|
-
- Generate the MINIMUM code needed to pass tests
|
|
10
|
-
- Do NOT add extra logic
|
|
11
|
-
- Do NOT add extra validation
|
|
12
|
-
- Do NOT add console logs
|
|
13
|
-
- Do NOT add comments unless required
|
|
14
|
-
- Do NOT refactor
|
|
15
|
-
- Do NOT optimize
|
|
16
|
-
- Do NOT generalize
|
|
17
|
-
|
|
18
|
-
ARCHITECTURE RULE:
|
|
19
|
-
- Create ONLY the files required by tests
|
|
20
|
-
- File names, exports, function names MUST match tests EXACTLY
|
|
21
|
-
- Error messages MUST match character-by-character
|
|
22
|
-
- Status codes MUST match exactly
|
|
23
|
-
|
|
24
|
-
OUTPUT RULES:
|
|
25
|
-
- Output ONLY valid JSON
|
|
26
|
-
- No markdown
|
|
27
|
-
- No explanations
|
|
28
|
-
- No extra text
|
|
29
|
-
|
|
30
|
-
JSON FORMAT:
|
|
31
|
-
{
|
|
32
|
-
"files": [
|
|
33
|
-
{
|
|
34
|
-
"path": "relative/path/file.js",
|
|
35
|
-
"content": "exact code"
|
|
36
|
-
}
|
|
37
|
-
]
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
IMPORTANT:
|
|
41
|
-
Passing tests is MORE IMPORTANT than clean code.
|
|
42
|
-
If a simpler solution passes tests, choose it.
|
|
43
|
-
`;
|