zobro-cli 1.1.6 → 1.1.7
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/index.js +88 -94
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,70 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
//
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
output: process.stdout
|
|
17
|
-
});
|
|
18
|
-
return new Promise(resolve =>
|
|
19
|
-
rl.question(question, answer => {
|
|
20
|
-
rl.close();
|
|
21
|
-
resolve(answer.trim());
|
|
22
|
-
})
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async function getApiKey() {
|
|
27
|
-
// 1️⃣ ENV variable (preferred)
|
|
28
|
-
if (process.env.GEMINI_API_KEY) {
|
|
29
|
-
return process.env.GEMINI_API_KEY;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// 2️⃣ Local config file
|
|
33
|
-
if (fs.existsSync(CONFIG_FILE)) {
|
|
34
|
-
const saved = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
35
|
-
if (saved.apiKey) return saved.apiKey;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// 3️⃣ Ask user once
|
|
39
|
-
console.log('🔐 Gemini API key not found.');
|
|
40
|
-
const key = await askQuestion('👉 Please enter your Gemini API Key: ');
|
|
41
|
-
|
|
42
|
-
if (!key) {
|
|
43
|
-
console.error('❌ API key is required.');
|
|
44
|
-
process.exit(1);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
48
|
-
fs.writeFileSync(CONFIG_FILE, JSON.stringify({ apiKey: key }, null, 2));
|
|
49
|
-
|
|
50
|
-
console.log('✅ API key saved securely for future use.');
|
|
51
|
-
return key;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// ---------------- CORE ----------------
|
|
3
|
+
const fs = require('fs'); // Node.js File System
|
|
4
|
+
const path = require('path'); // Node.js Path module
|
|
5
|
+
const yargs = require('yargs/yargs');
|
|
6
|
+
const { hideBin } = require('yargs/helpers');
|
|
7
|
+
|
|
8
|
+
// ⚠️ Paste your official Google Gemini API key here.
|
|
9
|
+
const API_KEY = "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";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Generates a full project structure based on a prompt.
|
|
13
|
+
* @param {string} prompt - The user's project request.
|
|
14
|
+
* @param {string} directoryName - The name of the folder to create the project in.
|
|
15
|
+
*/
|
|
55
16
|
async function generateProject(prompt, directoryName) {
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent`;
|
|
17
|
+
const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=${API_KEY}`;
|
|
59
18
|
|
|
19
|
+
// --- This is the new, "smarter" prompt ---
|
|
20
|
+
// We are asking the AI to act as a file structure generator
|
|
21
|
+
// and return a specific JSON format.
|
|
60
22
|
const newPrompt = `
|
|
61
23
|
You are an expert software developer and project scaffolder.
|
|
62
24
|
Based on the user's prompt, generate a complete file structure as a JSON array.
|
|
63
|
-
Each object in the array must have:
|
|
64
|
-
|
|
65
|
-
|
|
25
|
+
Each object in the array must have two keys:
|
|
26
|
+
1. "filename": (string) The full relative path for the file (e.g., "index.html", "src/styles.css", "js/app.js").
|
|
27
|
+
2. "code": (string) The complete code for that file.
|
|
28
|
+
|
|
29
|
+
Only return the raw JSON array, with no other text, explanations, or markdown fences.
|
|
66
30
|
|
|
67
|
-
Return ONLY raw JSON.
|
|
68
31
|
User Prompt: "${prompt}"
|
|
69
32
|
`;
|
|
70
33
|
|
|
@@ -73,61 +36,92 @@ User Prompt: "${prompt}"
|
|
|
73
36
|
};
|
|
74
37
|
|
|
75
38
|
try {
|
|
76
|
-
console.log(
|
|
39
|
+
console.log(`Code Running in Expresss`);
|
|
77
40
|
|
|
78
41
|
const response = await fetch(url, {
|
|
79
42
|
method: 'POST',
|
|
80
|
-
headers: {
|
|
81
|
-
|
|
82
|
-
'x-goog-api-key': API_KEY // 🔐 SECURE
|
|
83
|
-
},
|
|
84
|
-
body: JSON.stringify(body)
|
|
43
|
+
headers: { 'Content-Type': 'application/json' },
|
|
44
|
+
body: JSON.stringify(body),
|
|
85
45
|
});
|
|
86
46
|
|
|
87
47
|
if (!response.ok) {
|
|
88
|
-
const
|
|
89
|
-
|
|
48
|
+
const errorData = await response.json();
|
|
49
|
+
console.error('❌ API Error Details:', JSON.stringify(errorData.error, null, 2));
|
|
50
|
+
throw new Error(`API request failed with status ${response.status}`);
|
|
90
51
|
}
|
|
91
52
|
|
|
92
53
|
const data = await response.json();
|
|
93
54
|
let responseText = data.candidates[0].content.parts[0].text;
|
|
94
|
-
responseText = responseText.replace(/```json|```/g, '').trim();
|
|
95
55
|
|
|
96
|
-
|
|
56
|
+
// --- NEW JSON PARSING & FILE CREATION LOGIC ---
|
|
57
|
+
// console.log("Building project...");
|
|
58
|
+
|
|
59
|
+
// Clean up potential markdown fences from the AI's response
|
|
60
|
+
if (responseText.startsWith("```json")) {
|
|
61
|
+
responseText = responseText.substring(7, responseText.length - 3).trim();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let files;
|
|
65
|
+
try {
|
|
66
|
+
files = JSON.parse(responseText);
|
|
67
|
+
if (!Array.isArray(files)) throw new Error("AI did not return a JSON array.");
|
|
68
|
+
} catch (parseError) {
|
|
69
|
+
console.error("❌ ERROR: Failed to parse the AI's response. The response was not valid JSON.");
|
|
70
|
+
console.error("Raw AI Response:", responseText);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
97
73
|
|
|
74
|
+
// Create the main project directory
|
|
98
75
|
fs.mkdirSync(directoryName, { recursive: true });
|
|
76
|
+
console.log(``);
|
|
99
77
|
|
|
78
|
+
// Loop through the files array and create each file
|
|
100
79
|
for (const file of files) {
|
|
101
80
|
const filePath = path.join(directoryName, file.filename);
|
|
102
|
-
|
|
81
|
+
const fileDir = path.dirname(filePath);
|
|
82
|
+
|
|
83
|
+
// Create subdirectories if they don't exist
|
|
84
|
+
if (!fs.existsSync(fileDir)) {
|
|
85
|
+
fs.mkdirSync(fileDir, { recursive: true });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Write the code to the file
|
|
103
89
|
fs.writeFileSync(filePath, file.code);
|
|
104
|
-
console.log(
|
|
90
|
+
//console.log(`Created file: ${filePath}`);
|
|
105
91
|
}
|
|
106
92
|
|
|
107
|
-
|
|
93
|
+
// console.log(`\n🎉 Project "${directoryName}" created successfully!`);
|
|
108
94
|
|
|
109
|
-
} catch (
|
|
110
|
-
console.error('❌
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error('❌ An error occurred:', error.message);
|
|
111
97
|
}
|
|
112
98
|
}
|
|
113
99
|
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
100
|
+
// --- NEW YARGS SETUP ---
|
|
101
|
+
yargs(hideBin(process.argv))
|
|
102
|
+
.command(
|
|
103
|
+
'$0 <prompt>', // The default command
|
|
104
|
+
'Generates a full project structure from a text prompt.',
|
|
105
|
+
(yargs) => {
|
|
106
|
+
return yargs
|
|
107
|
+
.positional('prompt', {
|
|
108
|
+
describe: 'The project you want to generate',
|
|
109
|
+
type: 'string',
|
|
110
|
+
})
|
|
111
|
+
.option('directory', { // Replaces the old 'output' flag
|
|
112
|
+
alias: 'd',
|
|
113
|
+
describe: 'The name of the new directory to create the project in',
|
|
114
|
+
type: 'string',
|
|
115
|
+
demandOption: true, // This flag is now required
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
(argv) => {
|
|
119
|
+
if (!API_KEY || API_KEY === "YOUR_GEMINI_API_KEY_HERE") {
|
|
120
|
+
console.error('❌ ERROR: Please add your API key to the index.js file.');
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
generateProject(argv.prompt, argv.directory);
|
|
124
|
+
}
|
|
125
|
+
)
|
|
126
|
+
.demandCommand(1, 'Please provide a prompt.')
|
|
127
|
+
.parse();
|