zobro-cli 1.1.4 → 1.1.6
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 +79 -42
- package/package.json +1 -1
- package/.env +0 -1
package/index.js
CHANGED
|
@@ -2,77 +2,116 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const readline = require('readline');
|
|
7
|
+
|
|
8
|
+
// ---------------- CONFIG ----------------
|
|
9
|
+
const CONFIG_DIR = path.join(os.homedir(), '.projectgen');
|
|
10
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
11
|
+
|
|
12
|
+
// ---------------- HELPERS ----------------
|
|
13
|
+
function askQuestion(question) {
|
|
14
|
+
const rl = readline.createInterface({
|
|
15
|
+
input: process.stdin,
|
|
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
|
+
}
|
|
5
31
|
|
|
6
|
-
//
|
|
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
|
+
}
|
|
7
46
|
|
|
8
|
-
|
|
47
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
48
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify({ apiKey: key }, null, 2));
|
|
9
49
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
// ... rest of your error message
|
|
50
|
+
console.log('✅ API key saved securely for future use.');
|
|
51
|
+
return key;
|
|
13
52
|
}
|
|
53
|
+
|
|
54
|
+
// ---------------- CORE ----------------
|
|
14
55
|
async function generateProject(prompt, directoryName) {
|
|
15
|
-
|
|
16
|
-
console.error('❌ ERROR: API Key not found on this system.');
|
|
17
|
-
console.log('👉 To fix this, run: setx GEMINI_API_KEY "your_real_key_here"');
|
|
18
|
-
console.log('Then restart your terminal.');
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
56
|
+
const API_KEY = await getApiKey();
|
|
21
57
|
|
|
22
|
-
const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.
|
|
58
|
+
const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent`;
|
|
23
59
|
|
|
24
60
|
const newPrompt = `
|
|
25
61
|
You are an expert software developer and project scaffolder.
|
|
26
62
|
Based on the user's prompt, generate a complete file structure as a JSON array.
|
|
27
|
-
Each object in the array must have
|
|
28
|
-
|
|
29
|
-
|
|
63
|
+
Each object in the array must have:
|
|
64
|
+
- filename
|
|
65
|
+
- code
|
|
30
66
|
|
|
31
|
-
|
|
32
|
-
User Prompt: "${prompt}"
|
|
67
|
+
Return ONLY raw JSON.
|
|
68
|
+
User Prompt: "${prompt}"
|
|
69
|
+
`;
|
|
33
70
|
|
|
34
|
-
const body = {
|
|
71
|
+
const body = {
|
|
72
|
+
contents: [{ parts: [{ text: newPrompt }] }]
|
|
73
|
+
};
|
|
35
74
|
|
|
36
75
|
try {
|
|
37
76
|
console.log(`🤖 Building project in "${directoryName}"...`);
|
|
38
77
|
|
|
39
78
|
const response = await fetch(url, {
|
|
40
79
|
method: 'POST',
|
|
41
|
-
headers: {
|
|
42
|
-
|
|
80
|
+
headers: {
|
|
81
|
+
'Content-Type': 'application/json',
|
|
82
|
+
'x-goog-api-key': API_KEY // 🔐 SECURE
|
|
83
|
+
},
|
|
84
|
+
body: JSON.stringify(body)
|
|
43
85
|
});
|
|
44
86
|
|
|
45
87
|
if (!response.ok) {
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
return;
|
|
88
|
+
const err = await response.text();
|
|
89
|
+
throw new Error(err);
|
|
49
90
|
}
|
|
50
91
|
|
|
51
92
|
const data = await response.json();
|
|
52
93
|
let responseText = data.candidates[0].content.parts[0].text;
|
|
53
|
-
|
|
54
|
-
// Clean up markdown if AI adds it
|
|
55
|
-
responseText = responseText.replace(/```json|```/g, "").trim();
|
|
94
|
+
responseText = responseText.replace(/```json|```/g, '').trim();
|
|
56
95
|
|
|
57
96
|
const files = JSON.parse(responseText);
|
|
97
|
+
|
|
58
98
|
fs.mkdirSync(directoryName, { recursive: true });
|
|
59
99
|
|
|
60
100
|
for (const file of files) {
|
|
61
101
|
const filePath = path.join(directoryName, file.filename);
|
|
62
|
-
|
|
63
|
-
if (!fs.existsSync(fileDir)) fs.mkdirSync(fileDir, { recursive: true });
|
|
102
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
64
103
|
fs.writeFileSync(filePath, file.code);
|
|
65
104
|
console.log(`✅ Created: ${file.filename}`);
|
|
66
105
|
}
|
|
67
106
|
|
|
68
|
-
console.log(
|
|
107
|
+
console.log(`🎉 Project ready in "${directoryName}"`);
|
|
69
108
|
|
|
70
|
-
} catch (
|
|
71
|
-
console.error('❌
|
|
109
|
+
} catch (err) {
|
|
110
|
+
console.error('❌ Error:', err.message);
|
|
72
111
|
}
|
|
73
112
|
}
|
|
74
113
|
|
|
75
|
-
//
|
|
114
|
+
// ---------------- CLI ----------------
|
|
76
115
|
async function startCLI() {
|
|
77
116
|
const yargs = (await import('yargs/yargs')).default;
|
|
78
117
|
const { hideBin } = await import('yargs/helpers');
|
|
@@ -80,17 +119,15 @@ async function startCLI() {
|
|
|
80
119
|
yargs(hideBin(process.argv))
|
|
81
120
|
.command(
|
|
82
121
|
'$0 <prompt>',
|
|
83
|
-
'
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
},
|
|
89
|
-
|
|
90
|
-
generateProject(argv.prompt, argv.directory);
|
|
91
|
-
}
|
|
122
|
+
'Generate a full project',
|
|
123
|
+
y => y.option('directory', {
|
|
124
|
+
alias: 'd',
|
|
125
|
+
type: 'string',
|
|
126
|
+
demandOption: true
|
|
127
|
+
}),
|
|
128
|
+
argv => generateProject(argv.prompt, argv.directory)
|
|
92
129
|
)
|
|
93
130
|
.parse();
|
|
94
131
|
}
|
|
95
132
|
|
|
96
|
-
startCLI();
|
|
133
|
+
startCLI();
|
package/package.json
CHANGED
package/.env
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
GEMINI_API_KEY=AIzaSyBY0LrIq4HTmCfgN-1XuuiKpYUpTAeSiKU
|