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 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": "1.0.1",
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
- import Groq from "groq-sdk";
2
-
3
- let groqClient = null;
1
+ let API_KEY = null;
2
+ let SELECTED_MODEL = null;
4
3
 
5
4
  export function setApiKey(apiKey) {
6
- groqClient = new Groq({ apiKey });
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
- /* ========= PHASE 2: FILE CONTENT ========= */
55
- export async function generateFileContent(filePath, task, tests) {
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 res = await call([
58
- {
59
- role: "system",
60
- content: `
61
- Generate ONLY the source code for this file:
62
-
63
- ${filePath}
64
-
65
- No explanations.
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
- /* fall through */
25
+ SELECTED_MODEL = "models/gemini-1.5-flash";
26
+ return SELECTED_MODEL;
83
27
  }
28
+ }
84
29
 
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()
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
- if (filePath.endsWith(".js")) {
100
- return {
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
- return {
107
- path: filePath,
108
- content: ""
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 writeFiles(baseDir, files) {
5
- for (const file of files) {
6
- const fullPath = path.join(baseDir, file.path);
7
- await fs.ensureDir(path.dirname(fullPath));
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 { setApiKey, generateFilePlan, generateFileContent } from "./aiClient.js";
5
- import { writeFiles } from "./fileWriter.js";
6
-
7
- /* -------- API KEY (---) -------- */
8
- const apiKey = readlineSync.question("--- ", {
9
- hideEchoBack: true
10
- });
11
-
12
- if (!apiKey || apiKey.trim().length === 0) {
13
- process.exit(1);
14
- }
15
-
16
- setApiKey(apiKey);
17
-
18
- /* -------- TASK (-) -------- */
19
- const task = readlineSync.question("- ");
20
-
21
- if (!task || task.trim().length === 0) {
22
- process.exit(1);
23
- }
24
-
25
- /* -------- TESTS (--) OPTIONAL -------- */
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
- const paths = await generateFilePlan(task, tests);
51
-
52
- const files = [];
53
- for (const p of paths) {
54
- const file = await generateFileContent(p, task, tests);
55
- files.push(file);
56
- }
57
-
58
- await writeFiles(process.cwd(), files);
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();
@@ -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
- `;