ai-codegen-cli-vrk 1.0.0 → 1.0.1
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/package.json +1 -1
- package/src/aiClient.js +39 -61
- package/src/promptTemplate.js +14 -23
- package/src/runner.js +17 -10
package/package.json
CHANGED
package/src/aiClient.js
CHANGED
|
@@ -2,16 +2,10 @@ import Groq from "groq-sdk";
|
|
|
2
2
|
|
|
3
3
|
let groqClient = null;
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* Called once per run from runner.js
|
|
7
|
-
*/
|
|
8
5
|
export function setApiKey(apiKey) {
|
|
9
6
|
groqClient = new Groq({ apiKey });
|
|
10
7
|
}
|
|
11
8
|
|
|
12
|
-
/**
|
|
13
|
-
* Internal helper to call Groq
|
|
14
|
-
*/
|
|
15
9
|
async function call(messages) {
|
|
16
10
|
if (!groqClient) {
|
|
17
11
|
throw new Error("API key not initialized");
|
|
@@ -20,12 +14,11 @@ async function call(messages) {
|
|
|
20
14
|
return groqClient.chat.completions.create({
|
|
21
15
|
model: "llama-3.1-8b-instant",
|
|
22
16
|
temperature: 0,
|
|
23
|
-
response_format: { type: "json_object" },
|
|
24
17
|
messages
|
|
25
18
|
});
|
|
26
19
|
}
|
|
27
20
|
|
|
28
|
-
/*
|
|
21
|
+
/* ========= PHASE 1: FILE PLAN ========= */
|
|
29
22
|
export async function generateFilePlan(task, tests) {
|
|
30
23
|
const res = await call([
|
|
31
24
|
{
|
|
@@ -33,100 +26,85 @@ export async function generateFilePlan(task, tests) {
|
|
|
33
26
|
content: `
|
|
34
27
|
Return ONLY JSON.
|
|
35
28
|
|
|
36
|
-
Generate ONLY file paths required to
|
|
29
|
+
Generate ONLY file paths required to solve the task.
|
|
37
30
|
|
|
38
31
|
FORMAT:
|
|
39
32
|
{
|
|
40
33
|
"files": [
|
|
41
|
-
{ "path": "
|
|
42
|
-
{ "path": "controllers/anyController.js" },
|
|
43
|
-
{ "path": "routes/anyRoutes.js" },
|
|
44
|
-
{ "path": "index.js" }
|
|
34
|
+
{ "path": "file.ext" }
|
|
45
35
|
]
|
|
46
36
|
}
|
|
47
|
-
|
|
48
|
-
No explanations.
|
|
49
37
|
`
|
|
50
38
|
},
|
|
51
39
|
{
|
|
52
40
|
role: "user",
|
|
53
|
-
content: `TASK:\n${task}\n\
|
|
41
|
+
content: `TASK:\n${task}\n\nTESTS:\n${tests}`
|
|
54
42
|
}
|
|
55
43
|
]);
|
|
56
44
|
|
|
57
45
|
const parsed = JSON.parse(res.choices[0].message.content);
|
|
58
46
|
|
|
59
|
-
if (!
|
|
60
|
-
throw new Error("Invalid file plan");
|
|
47
|
+
if (!Array.isArray(parsed.files)) {
|
|
48
|
+
throw new Error("Invalid file plan from AI");
|
|
61
49
|
}
|
|
62
50
|
|
|
63
51
|
return parsed.files.map(f => f.path);
|
|
64
52
|
}
|
|
65
53
|
|
|
66
|
-
/*
|
|
54
|
+
/* ========= PHASE 2: FILE CONTENT ========= */
|
|
67
55
|
export async function generateFileContent(filePath, task, tests) {
|
|
68
|
-
let file = null;
|
|
69
|
-
|
|
70
56
|
try {
|
|
71
57
|
const res = await call([
|
|
72
58
|
{
|
|
73
59
|
role: "system",
|
|
74
60
|
content: `
|
|
75
|
-
|
|
61
|
+
Generate ONLY the source code for this file:
|
|
76
62
|
|
|
77
63
|
${filePath}
|
|
78
64
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
}
|
|
65
|
+
No explanations.
|
|
66
|
+
No markdown.
|
|
67
|
+
Return RAW CODE ONLY.
|
|
91
68
|
`
|
|
92
69
|
},
|
|
93
70
|
{
|
|
94
71
|
role: "user",
|
|
95
|
-
content: `TASK:\n${task}\n\
|
|
72
|
+
content: `TASK:\n${task}\n\nTESTS:\n${tests}`
|
|
96
73
|
}
|
|
97
74
|
]);
|
|
98
75
|
|
|
99
|
-
|
|
76
|
+
const content = res.choices[0].message.content?.trim();
|
|
77
|
+
|
|
78
|
+
if (content && content.length > 0) {
|
|
79
|
+
return { path: filePath, content };
|
|
80
|
+
}
|
|
100
81
|
} catch {
|
|
101
|
-
|
|
82
|
+
/* fall through */
|
|
102
83
|
}
|
|
103
84
|
|
|
104
|
-
/*
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
.replace(".js", "");
|
|
115
|
-
|
|
116
|
-
return {
|
|
117
|
-
path: filePath,
|
|
118
|
-
content:
|
|
119
|
-
`const mongoose = require('mongoose');
|
|
120
|
-
|
|
121
|
-
const schema = new mongoose.Schema({}, { strict: false });
|
|
122
|
-
|
|
123
|
-
module.exports = mongoose.model('${modelName}', schema);
|
|
85
|
+
/* ========= GENERIC FALLBACK ========= */
|
|
86
|
+
|
|
87
|
+
if (filePath.endsWith(".py")) {
|
|
88
|
+
return {
|
|
89
|
+
path: filePath,
|
|
90
|
+
content: `def main():
|
|
91
|
+
pass
|
|
92
|
+
|
|
93
|
+
if __name__ == "__main__":
|
|
94
|
+
main()
|
|
124
95
|
`
|
|
125
|
-
|
|
126
|
-
|
|
96
|
+
};
|
|
97
|
+
}
|
|
127
98
|
|
|
128
|
-
|
|
99
|
+
if (filePath.endsWith(".js")) {
|
|
100
|
+
return {
|
|
101
|
+
path: filePath,
|
|
102
|
+
content: `module.exports = {};`
|
|
103
|
+
};
|
|
129
104
|
}
|
|
130
105
|
|
|
131
|
-
return
|
|
106
|
+
return {
|
|
107
|
+
path: filePath,
|
|
108
|
+
content: ""
|
|
109
|
+
};
|
|
132
110
|
}
|
package/src/promptTemplate.js
CHANGED
|
@@ -3,31 +3,26 @@ You are solving an automated coding exam.
|
|
|
3
3
|
|
|
4
4
|
ABSOLUTE PRIORITY:
|
|
5
5
|
The given test cases are the ONLY specification.
|
|
6
|
-
Ignore best practices unless tests require them.
|
|
7
6
|
|
|
8
|
-
RULES
|
|
9
|
-
- Generate the MINIMUM code needed
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
- Do NOT optimize
|
|
16
|
-
- Do NOT generalize
|
|
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
|
|
17
14
|
|
|
18
|
-
ARCHITECTURE
|
|
19
|
-
- Create ONLY
|
|
20
|
-
-
|
|
21
|
-
- Error messages
|
|
22
|
-
- Status codes MUST match exactly
|
|
15
|
+
ARCHITECTURE:
|
|
16
|
+
- Create ONLY required files
|
|
17
|
+
- Names must match tests EXACTLY
|
|
18
|
+
- Error messages must match EXACTLY
|
|
23
19
|
|
|
24
|
-
OUTPUT
|
|
25
|
-
-
|
|
20
|
+
OUTPUT:
|
|
21
|
+
- ONLY valid JSON
|
|
26
22
|
- No markdown
|
|
27
23
|
- No explanations
|
|
28
|
-
- No extra text
|
|
29
24
|
|
|
30
|
-
|
|
25
|
+
FORMAT:
|
|
31
26
|
{
|
|
32
27
|
"files": [
|
|
33
28
|
{
|
|
@@ -36,8 +31,4 @@ JSON FORMAT:
|
|
|
36
31
|
}
|
|
37
32
|
]
|
|
38
33
|
}
|
|
39
|
-
|
|
40
|
-
IMPORTANT:
|
|
41
|
-
Passing tests is MORE IMPORTANT than clean code.
|
|
42
|
-
If a simpler solution passes tests, choose it.
|
|
43
34
|
`;
|
package/src/runner.js
CHANGED
|
@@ -1,31 +1,34 @@
|
|
|
1
1
|
import readlineSync from "readline-sync";
|
|
2
2
|
import fs from "fs";
|
|
3
|
-
import path from "path";
|
|
4
3
|
|
|
5
4
|
import { setApiKey, generateFilePlan, generateFileContent } from "./aiClient.js";
|
|
6
5
|
import { writeFiles } from "./fileWriter.js";
|
|
7
6
|
|
|
8
|
-
/*
|
|
7
|
+
/* -------- API KEY (---) -------- */
|
|
9
8
|
const apiKey = readlineSync.question("--- ", {
|
|
10
9
|
hideEchoBack: true
|
|
11
10
|
});
|
|
12
11
|
|
|
13
12
|
if (!apiKey || apiKey.trim().length === 0) {
|
|
14
|
-
console.log("API key is required");
|
|
15
13
|
process.exit(1);
|
|
16
14
|
}
|
|
17
15
|
|
|
18
16
|
setApiKey(apiKey);
|
|
19
17
|
|
|
20
|
-
/*
|
|
18
|
+
/* -------- TASK (-) -------- */
|
|
21
19
|
const task = readlineSync.question("- ");
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
if (!task || task.trim().length === 0) {
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* -------- TESTS (--) OPTIONAL -------- */
|
|
26
|
+
const testsInput = readlineSync.question("-- ");
|
|
27
|
+
let tests = "";
|
|
26
28
|
|
|
27
29
|
try {
|
|
28
30
|
if (
|
|
31
|
+
testsInput &&
|
|
29
32
|
(testsInput.endsWith(".js") || testsInput.endsWith(".test.js")) &&
|
|
30
33
|
fs.existsSync(testsInput)
|
|
31
34
|
) {
|
|
@@ -37,6 +40,11 @@ try {
|
|
|
37
40
|
tests = testsInput;
|
|
38
41
|
}
|
|
39
42
|
|
|
43
|
+
/* ---- SILENT FALLBACK ---- */
|
|
44
|
+
if (!tests || tests.trim().length === 0) {
|
|
45
|
+
tests = "No tests provided. Generate a simple correct implementation.";
|
|
46
|
+
}
|
|
47
|
+
|
|
40
48
|
(async () => {
|
|
41
49
|
try {
|
|
42
50
|
const paths = await generateFilePlan(task, tests);
|
|
@@ -48,9 +56,8 @@ try {
|
|
|
48
56
|
}
|
|
49
57
|
|
|
50
58
|
await writeFiles(process.cwd(), files);
|
|
51
|
-
|
|
52
|
-
} catch
|
|
53
|
-
fs.writeFileSync(".ai_codegen_error", e.message || "error");
|
|
59
|
+
process.exit(0);
|
|
60
|
+
} catch {
|
|
54
61
|
process.exit(1);
|
|
55
62
|
}
|
|
56
63
|
})();
|