@gxp-dev/tools 2.0.62 → 2.0.64
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/README.md +32 -31
- package/bin/gx-devtools.js +74 -54
- package/bin/lib/cli.js +23 -21
- package/bin/lib/commands/add-dependency.js +366 -325
- package/bin/lib/commands/assets.js +137 -139
- package/bin/lib/commands/build.js +169 -174
- package/bin/lib/commands/datastore.js +181 -183
- package/bin/lib/commands/dev.js +127 -131
- package/bin/lib/commands/extensions.js +147 -149
- package/bin/lib/commands/extract-config.js +73 -67
- package/bin/lib/commands/index.js +12 -12
- package/bin/lib/commands/init.js +342 -240
- package/bin/lib/commands/publish.js +69 -75
- package/bin/lib/commands/socket.js +69 -69
- package/bin/lib/commands/ssl.js +14 -14
- package/bin/lib/constants.js +10 -24
- package/bin/lib/tui/App.tsx +761 -705
- package/bin/lib/tui/components/AIPanel.tsx +191 -171
- package/bin/lib/tui/components/CommandInput.tsx +394 -343
- package/bin/lib/tui/components/GeminiPanel.tsx +175 -151
- package/bin/lib/tui/components/Header.tsx +23 -21
- package/bin/lib/tui/components/LogPanel.tsx +244 -220
- package/bin/lib/tui/components/TabBar.tsx +50 -48
- package/bin/lib/tui/components/WelcomeScreen.tsx +126 -71
- package/bin/lib/tui/index.tsx +37 -39
- package/bin/lib/tui/services/AIService.ts +518 -462
- package/bin/lib/tui/services/ExtensionService.ts +140 -129
- package/bin/lib/tui/services/GeminiService.ts +367 -337
- package/bin/lib/tui/services/ServiceManager.ts +344 -322
- package/bin/lib/tui/services/SocketService.ts +168 -168
- package/bin/lib/tui/services/ViteService.ts +88 -88
- package/bin/lib/tui/services/index.ts +47 -22
- package/bin/lib/utils/ai-scaffold.js +291 -280
- package/bin/lib/utils/extract-config.js +157 -140
- package/bin/lib/utils/files.js +82 -86
- package/bin/lib/utils/index.js +7 -7
- package/bin/lib/utils/paths.js +34 -34
- package/bin/lib/utils/prompts.js +194 -169
- package/bin/lib/utils/ssl.js +79 -81
- package/browser-extensions/README.md +0 -1
- package/browser-extensions/chrome/background.js +244 -237
- package/browser-extensions/chrome/content.js +32 -29
- package/browser-extensions/chrome/devtools.html +7 -7
- package/browser-extensions/chrome/devtools.js +19 -19
- package/browser-extensions/chrome/inspector.js +802 -767
- package/browser-extensions/chrome/manifest.json +71 -63
- package/browser-extensions/chrome/panel.html +674 -636
- package/browser-extensions/chrome/panel.js +722 -712
- package/browser-extensions/chrome/popup.html +586 -543
- package/browser-extensions/chrome/popup.js +282 -244
- package/browser-extensions/chrome/rules.json +1 -1
- package/browser-extensions/chrome/test-chrome.html +216 -136
- package/browser-extensions/chrome/test-mixed-content.html +284 -189
- package/browser-extensions/chrome/test-uri-pattern.html +221 -198
- package/browser-extensions/firefox/README.md +9 -6
- package/browser-extensions/firefox/background.js +221 -218
- package/browser-extensions/firefox/content.js +55 -52
- package/browser-extensions/firefox/debug-errors.html +386 -228
- package/browser-extensions/firefox/debug-https.html +153 -105
- package/browser-extensions/firefox/devtools.html +7 -7
- package/browser-extensions/firefox/devtools.js +23 -20
- package/browser-extensions/firefox/inspector.js +802 -767
- package/browser-extensions/firefox/manifest.json +68 -68
- package/browser-extensions/firefox/panel.html +674 -636
- package/browser-extensions/firefox/panel.js +722 -712
- package/browser-extensions/firefox/popup.html +572 -535
- package/browser-extensions/firefox/popup.js +281 -236
- package/browser-extensions/firefox/test-gramercy.html +170 -125
- package/browser-extensions/firefox/test-imports.html +59 -55
- package/browser-extensions/firefox/test-masking.html +231 -140
- package/browser-extensions/firefox/test-uri-pattern.html +221 -198
- package/dist/tui/App.d.ts +1 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +154 -150
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/components/AIPanel.d.ts.map +1 -1
- package/dist/tui/components/AIPanel.js +42 -35
- package/dist/tui/components/AIPanel.js.map +1 -1
- package/dist/tui/components/CommandInput.d.ts +1 -1
- package/dist/tui/components/CommandInput.d.ts.map +1 -1
- package/dist/tui/components/CommandInput.js +92 -62
- package/dist/tui/components/CommandInput.js.map +1 -1
- package/dist/tui/components/GeminiPanel.d.ts.map +1 -1
- package/dist/tui/components/GeminiPanel.js +37 -30
- package/dist/tui/components/GeminiPanel.js.map +1 -1
- package/dist/tui/components/Header.d.ts.map +1 -1
- package/dist/tui/components/Header.js +1 -1
- package/dist/tui/components/Header.js.map +1 -1
- package/dist/tui/components/LogPanel.d.ts +1 -1
- package/dist/tui/components/LogPanel.d.ts.map +1 -1
- package/dist/tui/components/LogPanel.js +26 -24
- package/dist/tui/components/LogPanel.js.map +1 -1
- package/dist/tui/components/TabBar.d.ts +2 -2
- package/dist/tui/components/TabBar.d.ts.map +1 -1
- package/dist/tui/components/TabBar.js +11 -11
- package/dist/tui/components/TabBar.js.map +1 -1
- package/dist/tui/components/WelcomeScreen.d.ts.map +1 -1
- package/dist/tui/components/WelcomeScreen.js +6 -6
- package/dist/tui/components/WelcomeScreen.js.map +1 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +8 -8
- package/dist/tui/index.js.map +1 -1
- package/dist/tui/services/AIService.d.ts +2 -2
- package/dist/tui/services/AIService.d.ts.map +1 -1
- package/dist/tui/services/AIService.js +165 -125
- package/dist/tui/services/AIService.js.map +1 -1
- package/dist/tui/services/ExtensionService.d.ts +1 -1
- package/dist/tui/services/ExtensionService.d.ts.map +1 -1
- package/dist/tui/services/ExtensionService.js +33 -26
- package/dist/tui/services/ExtensionService.js.map +1 -1
- package/dist/tui/services/GeminiService.d.ts +1 -1
- package/dist/tui/services/GeminiService.d.ts.map +1 -1
- package/dist/tui/services/GeminiService.js +87 -76
- package/dist/tui/services/GeminiService.js.map +1 -1
- package/dist/tui/services/ServiceManager.d.ts +3 -3
- package/dist/tui/services/ServiceManager.d.ts.map +1 -1
- package/dist/tui/services/ServiceManager.js +72 -58
- package/dist/tui/services/ServiceManager.js.map +1 -1
- package/dist/tui/services/SocketService.d.ts.map +1 -1
- package/dist/tui/services/SocketService.js +32 -32
- package/dist/tui/services/SocketService.js.map +1 -1
- package/dist/tui/services/ViteService.d.ts.map +1 -1
- package/dist/tui/services/ViteService.js +26 -28
- package/dist/tui/services/ViteService.js.map +1 -1
- package/dist/tui/services/index.d.ts +6 -6
- package/dist/tui/services/index.d.ts.map +1 -1
- package/dist/tui/services/index.js +6 -6
- package/dist/tui/services/index.js.map +1 -1
- package/mcp/gxp-api-server.js +83 -81
- package/package.json +109 -93
- package/runtime/PortalContainer.vue +258 -234
- package/runtime/dev-tools/DevToolsModal.vue +153 -155
- package/runtime/dev-tools/LayoutSwitcher.vue +144 -140
- package/runtime/dev-tools/MockDataEditor.vue +456 -433
- package/runtime/dev-tools/SocketSimulator.vue +379 -371
- package/runtime/dev-tools/StoreInspector.vue +517 -455
- package/runtime/dev-tools/index.js +5 -5
- package/runtime/fallback-layouts/PrivateLayout.vue +2 -2
- package/runtime/fallback-layouts/PublicLayout.vue +2 -2
- package/runtime/fallback-layouts/SystemLayout.vue +2 -2
- package/runtime/gxpStringsPlugin.js +159 -134
- package/runtime/index.html +17 -19
- package/runtime/main.js +24 -22
- package/runtime/mock-api/auth-middleware.js +15 -15
- package/runtime/mock-api/image-generator.js +46 -46
- package/runtime/mock-api/index.js +55 -55
- package/runtime/mock-api/response-generator.js +116 -105
- package/runtime/mock-api/route-generator.js +107 -84
- package/runtime/mock-api/socket-triggers.js +94 -93
- package/runtime/mock-api/spec-loader.js +79 -80
- package/runtime/package.json +3 -0
- package/runtime/server.js +68 -68
- package/runtime/stores/gxpPortalConfigStore.js +204 -186
- package/runtime/stores/index.js +2 -2
- package/runtime/vite-inspector-plugin.js +858 -707
- package/runtime/vite-source-tracker-plugin.js +132 -113
- package/runtime/vite.config.js +207 -132
- package/scripts/launch-chrome.js +41 -41
- package/scripts/pack-chrome.js +38 -39
- package/socket-events/AiSessionMessageCreated.json +17 -17
- package/socket-events/SocialStreamPostCreated.json +23 -23
- package/socket-events/SocialStreamPostVariantCompleted.json +22 -22
- package/template/.claude/agents/gxp-developer.md +100 -99
- package/template/.claude/settings.json +7 -7
- package/template/AGENTS.md +30 -23
- package/template/GEMINI.md +20 -20
- package/template/README.md +70 -53
- package/template/app-manifest.json +2 -4
- package/template/configuration.json +10 -10
- package/template/default-styling.css +1 -1
- package/template/index.html +18 -20
- package/template/main.js +24 -22
- package/template/src/DemoPage.vue +415 -362
- package/template/src/Plugin.vue +76 -85
- package/template/src/stores/index.js +3 -3
- package/template/src/stores/test-data.json +164 -172
- package/template/theme-layouts/AdditionalStyling.css +50 -50
- package/template/theme-layouts/PrivateLayout.vue +8 -12
- package/template/theme-layouts/PublicLayout.vue +8 -12
- package/template/theme-layouts/SystemLayout.vue +8 -12
- package/template/vite.extend.js +45 -0
- package/template/vite.config.js +0 -409
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* - Gemini (via API key or gcloud CLI)
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
const fs = require("fs")
|
|
12
|
-
const path = require("path")
|
|
13
|
-
const { spawn, execSync } = require("child_process")
|
|
11
|
+
const fs = require("fs")
|
|
12
|
+
const path = require("path")
|
|
13
|
+
const { spawn, execSync } = require("child_process")
|
|
14
14
|
|
|
15
15
|
// AI scaffolding prompt template
|
|
16
16
|
const SCAFFOLD_SYSTEM_PROMPT = `You are an expert GxP plugin developer assistant. Your task is to help create Vue.js plugin components for the GxP platform.
|
|
@@ -120,7 +120,7 @@ Example response:
|
|
|
120
120
|
6. Add scoped styles for component-specific CSS
|
|
121
121
|
7. Use Composition API with <script setup>
|
|
122
122
|
8. Handle loading and error states appropriately
|
|
123
|
-
|
|
123
|
+
`
|
|
124
124
|
|
|
125
125
|
/**
|
|
126
126
|
* Available AI providers
|
|
@@ -144,7 +144,7 @@ const AI_PROVIDERS = {
|
|
|
144
144
|
checkAvailable: checkGeminiAvailable,
|
|
145
145
|
generate: generateWithGemini,
|
|
146
146
|
},
|
|
147
|
-
}
|
|
147
|
+
}
|
|
148
148
|
|
|
149
149
|
/**
|
|
150
150
|
* Check if Claude CLI is available and logged in
|
|
@@ -153,17 +153,17 @@ const AI_PROVIDERS = {
|
|
|
153
153
|
async function checkClaudeAvailable() {
|
|
154
154
|
try {
|
|
155
155
|
// Check if claude CLI exists
|
|
156
|
-
execSync("which claude", { stdio: "pipe" })
|
|
156
|
+
execSync("which claude", { stdio: "pipe" })
|
|
157
157
|
|
|
158
158
|
// Check if logged in by running a simple command
|
|
159
159
|
// Claude CLI doesn't have a direct "whoami" but we can check if it works
|
|
160
|
-
return { available: true }
|
|
160
|
+
return { available: true }
|
|
161
161
|
} catch (error) {
|
|
162
162
|
return {
|
|
163
163
|
available: false,
|
|
164
164
|
reason:
|
|
165
165
|
"Claude CLI not installed. Install with: npm install -g @anthropic-ai/claude-code",
|
|
166
|
-
}
|
|
166
|
+
}
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
169
|
|
|
@@ -174,14 +174,14 @@ async function checkClaudeAvailable() {
|
|
|
174
174
|
async function checkCodexAvailable() {
|
|
175
175
|
try {
|
|
176
176
|
// Check if codex CLI exists
|
|
177
|
-
execSync("which codex", { stdio: "pipe" })
|
|
178
|
-
return { available: true }
|
|
177
|
+
execSync("which codex", { stdio: "pipe" })
|
|
178
|
+
return { available: true }
|
|
179
179
|
} catch (error) {
|
|
180
180
|
return {
|
|
181
181
|
available: false,
|
|
182
182
|
reason:
|
|
183
183
|
"Codex CLI not installed. Install with: npm install -g @openai/codex",
|
|
184
|
-
}
|
|
184
|
+
}
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
|
|
@@ -192,27 +192,27 @@ async function checkCodexAvailable() {
|
|
|
192
192
|
async function checkGeminiAvailable() {
|
|
193
193
|
// Check for Gemini CLI first (preferred - uses logged-in account)
|
|
194
194
|
try {
|
|
195
|
-
execSync("which gemini", { stdio: "pipe" })
|
|
195
|
+
execSync("which gemini", { stdio: "pipe" })
|
|
196
196
|
// Gemini CLI is installed - it handles its own auth
|
|
197
|
-
return { available: true, method: "cli" }
|
|
197
|
+
return { available: true, method: "cli" }
|
|
198
198
|
} catch (error) {
|
|
199
199
|
// Gemini CLI not installed
|
|
200
200
|
}
|
|
201
201
|
|
|
202
202
|
// Check for API key
|
|
203
|
-
const apiKey = process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY
|
|
203
|
+
const apiKey = process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY
|
|
204
204
|
if (apiKey) {
|
|
205
|
-
return { available: true, method: "api_key" }
|
|
205
|
+
return { available: true, method: "api_key" }
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
// Check for gcloud CLI with auth
|
|
209
209
|
try {
|
|
210
|
-
execSync("which gcloud", { stdio: "pipe" })
|
|
210
|
+
execSync("which gcloud", { stdio: "pipe" })
|
|
211
211
|
const authList = execSync("gcloud auth list --format='value(account)'", {
|
|
212
212
|
stdio: "pipe",
|
|
213
|
-
}).toString()
|
|
213
|
+
}).toString()
|
|
214
214
|
if (authList.trim()) {
|
|
215
|
-
return { available: true, method: "gcloud" }
|
|
215
|
+
return { available: true, method: "gcloud" }
|
|
216
216
|
}
|
|
217
217
|
} catch (error) {
|
|
218
218
|
// gcloud not available or not authenticated
|
|
@@ -225,7 +225,7 @@ async function checkGeminiAvailable() {
|
|
|
225
225
|
" • Gemini CLI logged in (npm i -g @google/gemini-cli && gemini), or\n" +
|
|
226
226
|
" • GEMINI_API_KEY environment variable, or\n" +
|
|
227
227
|
" • gcloud CLI logged in (gcloud auth login)",
|
|
228
|
-
}
|
|
228
|
+
}
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
/**
|
|
@@ -233,10 +233,10 @@ async function checkGeminiAvailable() {
|
|
|
233
233
|
* @returns {Promise<Array<{id: string, name: string, description: string, available: boolean, reason?: string}>>}
|
|
234
234
|
*/
|
|
235
235
|
async function getAvailableProviders() {
|
|
236
|
-
const providers = []
|
|
236
|
+
const providers = []
|
|
237
237
|
|
|
238
238
|
for (const [id, provider] of Object.entries(AI_PROVIDERS)) {
|
|
239
|
-
const status = await provider.checkAvailable()
|
|
239
|
+
const status = await provider.checkAvailable()
|
|
240
240
|
providers.push({
|
|
241
241
|
id,
|
|
242
242
|
name: provider.name,
|
|
@@ -244,10 +244,10 @@ async function getAvailableProviders() {
|
|
|
244
244
|
available: status.available,
|
|
245
245
|
reason: status.reason,
|
|
246
246
|
method: status.method,
|
|
247
|
-
})
|
|
247
|
+
})
|
|
248
248
|
}
|
|
249
249
|
|
|
250
|
-
return providers
|
|
250
|
+
return providers
|
|
251
251
|
}
|
|
252
252
|
|
|
253
253
|
/**
|
|
@@ -258,14 +258,14 @@ async function getAvailableProviders() {
|
|
|
258
258
|
* @returns {Promise<object|null>}
|
|
259
259
|
*/
|
|
260
260
|
async function generateWithClaude(userPrompt, projectName, description) {
|
|
261
|
-
const fullPrompt = buildFullPrompt(userPrompt, projectName, description)
|
|
261
|
+
const fullPrompt = buildFullPrompt(userPrompt, projectName, description)
|
|
262
262
|
|
|
263
263
|
return new Promise((resolve) => {
|
|
264
|
-
console.log("\n🤖 Generating plugin scaffold with Claude...\n")
|
|
265
|
-
console.log("─".repeat(50))
|
|
264
|
+
console.log("\n🤖 Generating plugin scaffold with Claude...\n")
|
|
265
|
+
console.log("─".repeat(50))
|
|
266
266
|
|
|
267
|
-
let output = ""
|
|
268
|
-
let errorOutput = ""
|
|
267
|
+
let output = ""
|
|
268
|
+
let errorOutput = ""
|
|
269
269
|
|
|
270
270
|
// Use claude CLI with --print flag to get direct output
|
|
271
271
|
const claude = spawn(
|
|
@@ -274,63 +274,65 @@ async function generateWithClaude(userPrompt, projectName, description) {
|
|
|
274
274
|
{
|
|
275
275
|
stdio: ["pipe", "pipe", "pipe"],
|
|
276
276
|
shell: true,
|
|
277
|
-
}
|
|
278
|
-
)
|
|
277
|
+
},
|
|
278
|
+
)
|
|
279
279
|
|
|
280
280
|
claude.stdout.on("data", (data) => {
|
|
281
|
-
const chunk = data.toString()
|
|
282
|
-
output += chunk
|
|
281
|
+
const chunk = data.toString()
|
|
282
|
+
output += chunk
|
|
283
283
|
// Stream output to user in real-time
|
|
284
|
-
process.stdout.write(chunk)
|
|
285
|
-
})
|
|
284
|
+
process.stdout.write(chunk)
|
|
285
|
+
})
|
|
286
286
|
|
|
287
287
|
claude.stderr.on("data", (data) => {
|
|
288
|
-
const chunk = data.toString()
|
|
289
|
-
errorOutput += chunk
|
|
288
|
+
const chunk = data.toString()
|
|
289
|
+
errorOutput += chunk
|
|
290
290
|
// Show stderr as well (may contain progress info)
|
|
291
|
-
process.stderr.write(chunk)
|
|
292
|
-
})
|
|
291
|
+
process.stderr.write(chunk)
|
|
292
|
+
})
|
|
293
293
|
|
|
294
294
|
claude.on("close", (code) => {
|
|
295
|
-
console.log("\n" + "─".repeat(50))
|
|
295
|
+
console.log("\n" + "─".repeat(50))
|
|
296
296
|
|
|
297
297
|
if (code !== 0) {
|
|
298
|
-
console.error(`\n❌ Claude CLI error (exit code ${code})`)
|
|
298
|
+
console.error(`\n❌ Claude CLI error (exit code ${code})`)
|
|
299
299
|
if (errorOutput) {
|
|
300
|
-
console.error(errorOutput)
|
|
300
|
+
console.error(errorOutput)
|
|
301
301
|
}
|
|
302
|
-
resolve(null)
|
|
303
|
-
return
|
|
302
|
+
resolve(null)
|
|
303
|
+
return
|
|
304
304
|
}
|
|
305
305
|
|
|
306
306
|
if (!output.trim()) {
|
|
307
|
-
console.error("❌ No response received from Claude")
|
|
308
|
-
resolve(null)
|
|
309
|
-
return
|
|
307
|
+
console.error("❌ No response received from Claude")
|
|
308
|
+
resolve(null)
|
|
309
|
+
return
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
-
const scaffoldData = parseAIResponse(output)
|
|
312
|
+
const scaffoldData = parseAIResponse(output)
|
|
313
313
|
if (!scaffoldData) {
|
|
314
|
-
console.error("\n❌ Could not parse Claude response as JSON")
|
|
315
|
-
console.log(
|
|
316
|
-
|
|
317
|
-
|
|
314
|
+
console.error("\n❌ Could not parse Claude response as JSON")
|
|
315
|
+
console.log(
|
|
316
|
+
"The AI response was shown above but couldn't be parsed into scaffold data.",
|
|
317
|
+
)
|
|
318
|
+
resolve(null)
|
|
319
|
+
return
|
|
318
320
|
}
|
|
319
321
|
|
|
320
322
|
if (scaffoldData.explanation) {
|
|
321
|
-
console.log("\n📝 AI Explanation:")
|
|
322
|
-
console.log(` ${scaffoldData.explanation}`)
|
|
323
|
-
console.log("")
|
|
323
|
+
console.log("\n📝 AI Explanation:")
|
|
324
|
+
console.log(` ${scaffoldData.explanation}`)
|
|
325
|
+
console.log("")
|
|
324
326
|
}
|
|
325
327
|
|
|
326
|
-
resolve(scaffoldData)
|
|
327
|
-
})
|
|
328
|
+
resolve(scaffoldData)
|
|
329
|
+
})
|
|
328
330
|
|
|
329
331
|
claude.on("error", (err) => {
|
|
330
|
-
console.error(`❌ Failed to run Claude CLI: ${err.message}`)
|
|
331
|
-
resolve(null)
|
|
332
|
-
})
|
|
333
|
-
})
|
|
332
|
+
console.error(`❌ Failed to run Claude CLI: ${err.message}`)
|
|
333
|
+
resolve(null)
|
|
334
|
+
})
|
|
335
|
+
})
|
|
334
336
|
}
|
|
335
337
|
|
|
336
338
|
/**
|
|
@@ -341,14 +343,14 @@ async function generateWithClaude(userPrompt, projectName, description) {
|
|
|
341
343
|
* @returns {Promise<object|null>}
|
|
342
344
|
*/
|
|
343
345
|
async function generateWithCodex(userPrompt, projectName, description) {
|
|
344
|
-
const fullPrompt = buildFullPrompt(userPrompt, projectName, description)
|
|
346
|
+
const fullPrompt = buildFullPrompt(userPrompt, projectName, description)
|
|
345
347
|
|
|
346
348
|
return new Promise((resolve) => {
|
|
347
|
-
console.log("\n🤖 Generating plugin scaffold with Codex...\n")
|
|
348
|
-
console.log("─".repeat(50))
|
|
349
|
+
console.log("\n🤖 Generating plugin scaffold with Codex...\n")
|
|
350
|
+
console.log("─".repeat(50))
|
|
349
351
|
|
|
350
|
-
let output = ""
|
|
351
|
-
let errorOutput = ""
|
|
352
|
+
let output = ""
|
|
353
|
+
let errorOutput = ""
|
|
352
354
|
|
|
353
355
|
// Use codex CLI
|
|
354
356
|
const codex = spawn(
|
|
@@ -357,63 +359,65 @@ async function generateWithCodex(userPrompt, projectName, description) {
|
|
|
357
359
|
{
|
|
358
360
|
stdio: ["pipe", "pipe", "pipe"],
|
|
359
361
|
shell: true,
|
|
360
|
-
}
|
|
361
|
-
)
|
|
362
|
+
},
|
|
363
|
+
)
|
|
362
364
|
|
|
363
365
|
codex.stdout.on("data", (data) => {
|
|
364
|
-
const chunk = data.toString()
|
|
365
|
-
output += chunk
|
|
366
|
+
const chunk = data.toString()
|
|
367
|
+
output += chunk
|
|
366
368
|
// Stream output to user in real-time
|
|
367
|
-
process.stdout.write(chunk)
|
|
368
|
-
})
|
|
369
|
+
process.stdout.write(chunk)
|
|
370
|
+
})
|
|
369
371
|
|
|
370
372
|
codex.stderr.on("data", (data) => {
|
|
371
|
-
const chunk = data.toString()
|
|
372
|
-
errorOutput += chunk
|
|
373
|
+
const chunk = data.toString()
|
|
374
|
+
errorOutput += chunk
|
|
373
375
|
// Show stderr as well
|
|
374
|
-
process.stderr.write(chunk)
|
|
375
|
-
})
|
|
376
|
+
process.stderr.write(chunk)
|
|
377
|
+
})
|
|
376
378
|
|
|
377
379
|
codex.on("close", (code) => {
|
|
378
|
-
console.log("\n" + "─".repeat(50))
|
|
380
|
+
console.log("\n" + "─".repeat(50))
|
|
379
381
|
|
|
380
382
|
if (code !== 0) {
|
|
381
|
-
console.error(`\n❌ Codex CLI error (exit code ${code})`)
|
|
383
|
+
console.error(`\n❌ Codex CLI error (exit code ${code})`)
|
|
382
384
|
if (errorOutput) {
|
|
383
|
-
console.error(errorOutput)
|
|
385
|
+
console.error(errorOutput)
|
|
384
386
|
}
|
|
385
|
-
resolve(null)
|
|
386
|
-
return
|
|
387
|
+
resolve(null)
|
|
388
|
+
return
|
|
387
389
|
}
|
|
388
390
|
|
|
389
391
|
if (!output.trim()) {
|
|
390
|
-
console.error("❌ No response received from Codex")
|
|
391
|
-
resolve(null)
|
|
392
|
-
return
|
|
392
|
+
console.error("❌ No response received from Codex")
|
|
393
|
+
resolve(null)
|
|
394
|
+
return
|
|
393
395
|
}
|
|
394
396
|
|
|
395
|
-
const scaffoldData = parseAIResponse(output)
|
|
397
|
+
const scaffoldData = parseAIResponse(output)
|
|
396
398
|
if (!scaffoldData) {
|
|
397
|
-
console.error("\n❌ Could not parse Codex response as JSON")
|
|
398
|
-
console.log(
|
|
399
|
-
|
|
400
|
-
|
|
399
|
+
console.error("\n❌ Could not parse Codex response as JSON")
|
|
400
|
+
console.log(
|
|
401
|
+
"The AI response was shown above but couldn't be parsed into scaffold data.",
|
|
402
|
+
)
|
|
403
|
+
resolve(null)
|
|
404
|
+
return
|
|
401
405
|
}
|
|
402
406
|
|
|
403
407
|
if (scaffoldData.explanation) {
|
|
404
|
-
console.log("\n📝 AI Explanation:")
|
|
405
|
-
console.log(` ${scaffoldData.explanation}`)
|
|
406
|
-
console.log("")
|
|
408
|
+
console.log("\n📝 AI Explanation:")
|
|
409
|
+
console.log(` ${scaffoldData.explanation}`)
|
|
410
|
+
console.log("")
|
|
407
411
|
}
|
|
408
412
|
|
|
409
|
-
resolve(scaffoldData)
|
|
410
|
-
})
|
|
413
|
+
resolve(scaffoldData)
|
|
414
|
+
})
|
|
411
415
|
|
|
412
416
|
codex.on("error", (err) => {
|
|
413
|
-
console.error(`❌ Failed to run Codex CLI: ${err.message}`)
|
|
414
|
-
resolve(null)
|
|
415
|
-
})
|
|
416
|
-
})
|
|
417
|
+
console.error(`❌ Failed to run Codex CLI: ${err.message}`)
|
|
418
|
+
resolve(null)
|
|
419
|
+
})
|
|
420
|
+
})
|
|
417
421
|
}
|
|
418
422
|
|
|
419
423
|
/**
|
|
@@ -428,21 +432,21 @@ async function generateWithGemini(
|
|
|
428
432
|
userPrompt,
|
|
429
433
|
projectName,
|
|
430
434
|
description,
|
|
431
|
-
method
|
|
435
|
+
method,
|
|
432
436
|
) {
|
|
433
|
-
const fullPrompt = buildFullPrompt(userPrompt, projectName, description)
|
|
437
|
+
const fullPrompt = buildFullPrompt(userPrompt, projectName, description)
|
|
434
438
|
|
|
435
439
|
// Use the appropriate method
|
|
436
440
|
if (method === "cli") {
|
|
437
|
-
return generateWithGeminiCli(fullPrompt)
|
|
441
|
+
return generateWithGeminiCli(fullPrompt)
|
|
438
442
|
}
|
|
439
443
|
|
|
440
|
-
const apiKey = process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY
|
|
444
|
+
const apiKey = process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY
|
|
441
445
|
if (method === "api_key" && apiKey) {
|
|
442
|
-
return generateWithGeminiApiKey(fullPrompt, apiKey)
|
|
446
|
+
return generateWithGeminiApiKey(fullPrompt, apiKey)
|
|
443
447
|
}
|
|
444
448
|
|
|
445
|
-
return generateWithGeminiGcloud(fullPrompt)
|
|
449
|
+
return generateWithGeminiGcloud(fullPrompt)
|
|
446
450
|
}
|
|
447
451
|
|
|
448
452
|
/**
|
|
@@ -450,11 +454,11 @@ async function generateWithGemini(
|
|
|
450
454
|
*/
|
|
451
455
|
async function generateWithGeminiCli(fullPrompt) {
|
|
452
456
|
return new Promise((resolve) => {
|
|
453
|
-
console.log("\n🤖 Generating plugin scaffold with Gemini CLI...\n")
|
|
454
|
-
console.log("─".repeat(50))
|
|
457
|
+
console.log("\n🤖 Generating plugin scaffold with Gemini CLI...\n")
|
|
458
|
+
console.log("─".repeat(50))
|
|
455
459
|
|
|
456
|
-
let output = ""
|
|
457
|
-
let errorOutput = ""
|
|
460
|
+
let output = ""
|
|
461
|
+
let errorOutput = ""
|
|
458
462
|
|
|
459
463
|
// Use gemini CLI with -p for prompt mode
|
|
460
464
|
const gemini = spawn(
|
|
@@ -463,63 +467,65 @@ async function generateWithGeminiCli(fullPrompt) {
|
|
|
463
467
|
{
|
|
464
468
|
stdio: ["pipe", "pipe", "pipe"],
|
|
465
469
|
shell: true,
|
|
466
|
-
}
|
|
467
|
-
)
|
|
470
|
+
},
|
|
471
|
+
)
|
|
468
472
|
|
|
469
473
|
gemini.stdout.on("data", (data) => {
|
|
470
|
-
const chunk = data.toString()
|
|
471
|
-
output += chunk
|
|
474
|
+
const chunk = data.toString()
|
|
475
|
+
output += chunk
|
|
472
476
|
// Stream output to user in real-time
|
|
473
|
-
process.stdout.write(chunk)
|
|
474
|
-
})
|
|
477
|
+
process.stdout.write(chunk)
|
|
478
|
+
})
|
|
475
479
|
|
|
476
480
|
gemini.stderr.on("data", (data) => {
|
|
477
|
-
const chunk = data.toString()
|
|
478
|
-
errorOutput += chunk
|
|
481
|
+
const chunk = data.toString()
|
|
482
|
+
errorOutput += chunk
|
|
479
483
|
// Show stderr as well
|
|
480
|
-
process.stderr.write(chunk)
|
|
481
|
-
})
|
|
484
|
+
process.stderr.write(chunk)
|
|
485
|
+
})
|
|
482
486
|
|
|
483
487
|
gemini.on("close", (code) => {
|
|
484
|
-
console.log("\n" + "─".repeat(50))
|
|
488
|
+
console.log("\n" + "─".repeat(50))
|
|
485
489
|
|
|
486
490
|
if (code !== 0) {
|
|
487
|
-
console.error(`\n❌ Gemini CLI error (exit code ${code})`)
|
|
491
|
+
console.error(`\n❌ Gemini CLI error (exit code ${code})`)
|
|
488
492
|
if (errorOutput) {
|
|
489
|
-
console.error(errorOutput)
|
|
493
|
+
console.error(errorOutput)
|
|
490
494
|
}
|
|
491
|
-
resolve(null)
|
|
492
|
-
return
|
|
495
|
+
resolve(null)
|
|
496
|
+
return
|
|
493
497
|
}
|
|
494
498
|
|
|
495
499
|
if (!output.trim()) {
|
|
496
|
-
console.error("❌ No response received from Gemini CLI")
|
|
497
|
-
resolve(null)
|
|
498
|
-
return
|
|
500
|
+
console.error("❌ No response received from Gemini CLI")
|
|
501
|
+
resolve(null)
|
|
502
|
+
return
|
|
499
503
|
}
|
|
500
504
|
|
|
501
|
-
const scaffoldData = parseAIResponse(output)
|
|
505
|
+
const scaffoldData = parseAIResponse(output)
|
|
502
506
|
if (!scaffoldData) {
|
|
503
|
-
console.error("\n❌ Could not parse Gemini response as JSON")
|
|
504
|
-
console.log(
|
|
505
|
-
|
|
506
|
-
|
|
507
|
+
console.error("\n❌ Could not parse Gemini response as JSON")
|
|
508
|
+
console.log(
|
|
509
|
+
"The AI response was shown above but couldn't be parsed into scaffold data.",
|
|
510
|
+
)
|
|
511
|
+
resolve(null)
|
|
512
|
+
return
|
|
507
513
|
}
|
|
508
514
|
|
|
509
515
|
if (scaffoldData.explanation) {
|
|
510
|
-
console.log("\n📝 AI Explanation:")
|
|
511
|
-
console.log(` ${scaffoldData.explanation}`)
|
|
512
|
-
console.log("")
|
|
516
|
+
console.log("\n📝 AI Explanation:")
|
|
517
|
+
console.log(` ${scaffoldData.explanation}`)
|
|
518
|
+
console.log("")
|
|
513
519
|
}
|
|
514
520
|
|
|
515
|
-
resolve(scaffoldData)
|
|
516
|
-
})
|
|
521
|
+
resolve(scaffoldData)
|
|
522
|
+
})
|
|
517
523
|
|
|
518
524
|
gemini.on("error", (err) => {
|
|
519
|
-
console.error(`❌ Failed to run Gemini CLI: ${err.message}`)
|
|
520
|
-
resolve(null)
|
|
521
|
-
})
|
|
522
|
-
})
|
|
525
|
+
console.error(`❌ Failed to run Gemini CLI: ${err.message}`)
|
|
526
|
+
resolve(null)
|
|
527
|
+
})
|
|
528
|
+
})
|
|
523
529
|
}
|
|
524
530
|
|
|
525
531
|
/**
|
|
@@ -527,9 +533,9 @@ async function generateWithGeminiCli(fullPrompt) {
|
|
|
527
533
|
*/
|
|
528
534
|
async function generateWithGeminiApiKey(fullPrompt, apiKey) {
|
|
529
535
|
try {
|
|
530
|
-
console.log("\n🤖 Generating plugin scaffold with Gemini API...\n")
|
|
531
|
-
console.log("─".repeat(50))
|
|
532
|
-
console.log("Sending request to Gemini API...")
|
|
536
|
+
console.log("\n🤖 Generating plugin scaffold with Gemini API...\n")
|
|
537
|
+
console.log("─".repeat(50))
|
|
538
|
+
console.log("Sending request to Gemini API...")
|
|
533
539
|
|
|
534
540
|
const response = await fetch(
|
|
535
541
|
`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`,
|
|
@@ -550,49 +556,51 @@ async function generateWithGeminiApiKey(fullPrompt, apiKey) {
|
|
|
550
556
|
temperature: 0.7,
|
|
551
557
|
},
|
|
552
558
|
}),
|
|
553
|
-
}
|
|
554
|
-
)
|
|
559
|
+
},
|
|
560
|
+
)
|
|
555
561
|
|
|
556
562
|
if (!response.ok) {
|
|
557
|
-
const errorText = await response.text()
|
|
558
|
-
console.error(`\n❌ Gemini API error: ${response.status}`)
|
|
559
|
-
console.error(errorText)
|
|
560
|
-
console.log("─".repeat(50))
|
|
561
|
-
return null
|
|
563
|
+
const errorText = await response.text()
|
|
564
|
+
console.error(`\n❌ Gemini API error: ${response.status}`)
|
|
565
|
+
console.error(errorText)
|
|
566
|
+
console.log("─".repeat(50))
|
|
567
|
+
return null
|
|
562
568
|
}
|
|
563
569
|
|
|
564
|
-
const data = await response.json()
|
|
565
|
-
const responseText = data.candidates?.[0]?.content?.parts?.[0]?.text || ""
|
|
570
|
+
const data = await response.json()
|
|
571
|
+
const responseText = data.candidates?.[0]?.content?.parts?.[0]?.text || ""
|
|
566
572
|
|
|
567
573
|
if (!responseText) {
|
|
568
|
-
console.error("❌ No response from Gemini API")
|
|
569
|
-
console.log("─".repeat(50))
|
|
570
|
-
return null
|
|
574
|
+
console.error("❌ No response from Gemini API")
|
|
575
|
+
console.log("─".repeat(50))
|
|
576
|
+
return null
|
|
571
577
|
}
|
|
572
578
|
|
|
573
579
|
// Show the response to user
|
|
574
|
-
console.log("\nGemini Response:\n")
|
|
575
|
-
console.log(responseText)
|
|
576
|
-
console.log("\n" + "─".repeat(50))
|
|
580
|
+
console.log("\nGemini Response:\n")
|
|
581
|
+
console.log(responseText)
|
|
582
|
+
console.log("\n" + "─".repeat(50))
|
|
577
583
|
|
|
578
|
-
const scaffoldData = parseAIResponse(responseText)
|
|
584
|
+
const scaffoldData = parseAIResponse(responseText)
|
|
579
585
|
|
|
580
586
|
if (!scaffoldData) {
|
|
581
|
-
console.error("\n❌ Could not parse Gemini response as JSON")
|
|
582
|
-
console.log(
|
|
583
|
-
|
|
587
|
+
console.error("\n❌ Could not parse Gemini response as JSON")
|
|
588
|
+
console.log(
|
|
589
|
+
"The AI response was shown above but couldn't be parsed into scaffold data.",
|
|
590
|
+
)
|
|
591
|
+
return null
|
|
584
592
|
}
|
|
585
593
|
|
|
586
594
|
if (scaffoldData.explanation) {
|
|
587
|
-
console.log("\n📝 AI Explanation:")
|
|
588
|
-
console.log(` ${scaffoldData.explanation}`)
|
|
589
|
-
console.log("")
|
|
595
|
+
console.log("\n📝 AI Explanation:")
|
|
596
|
+
console.log(` ${scaffoldData.explanation}`)
|
|
597
|
+
console.log("")
|
|
590
598
|
}
|
|
591
599
|
|
|
592
|
-
return scaffoldData
|
|
600
|
+
return scaffoldData
|
|
593
601
|
} catch (error) {
|
|
594
|
-
console.error(`❌ Gemini API failed: ${error.message}`)
|
|
595
|
-
return null
|
|
602
|
+
console.error(`❌ Gemini API failed: ${error.message}`)
|
|
603
|
+
return null
|
|
596
604
|
}
|
|
597
605
|
}
|
|
598
606
|
|
|
@@ -601,42 +609,42 @@ async function generateWithGeminiApiKey(fullPrompt, apiKey) {
|
|
|
601
609
|
*/
|
|
602
610
|
async function generateWithGeminiGcloud(fullPrompt) {
|
|
603
611
|
return new Promise((resolve) => {
|
|
604
|
-
console.log("\n🤖 Generating plugin scaffold with Gemini (via gcloud)...\n")
|
|
605
|
-
console.log("─".repeat(50))
|
|
612
|
+
console.log("\n🤖 Generating plugin scaffold with Gemini (via gcloud)...\n")
|
|
613
|
+
console.log("─".repeat(50))
|
|
606
614
|
|
|
607
615
|
// Get access token from gcloud
|
|
608
|
-
let accessToken
|
|
616
|
+
let accessToken
|
|
609
617
|
try {
|
|
610
|
-
console.log("Getting gcloud access token...")
|
|
618
|
+
console.log("Getting gcloud access token...")
|
|
611
619
|
accessToken = execSync("gcloud auth print-access-token", {
|
|
612
620
|
stdio: "pipe",
|
|
613
621
|
})
|
|
614
622
|
.toString()
|
|
615
|
-
.trim()
|
|
623
|
+
.trim()
|
|
616
624
|
} catch (error) {
|
|
617
|
-
console.error("❌ Failed to get gcloud access token")
|
|
618
|
-
console.log("─".repeat(50))
|
|
619
|
-
resolve(null)
|
|
620
|
-
return
|
|
625
|
+
console.error("❌ Failed to get gcloud access token")
|
|
626
|
+
console.log("─".repeat(50))
|
|
627
|
+
resolve(null)
|
|
628
|
+
return
|
|
621
629
|
}
|
|
622
630
|
|
|
623
631
|
// Get project ID
|
|
624
|
-
let projectId
|
|
632
|
+
let projectId
|
|
625
633
|
try {
|
|
626
634
|
projectId = execSync("gcloud config get-value project", {
|
|
627
635
|
stdio: "pipe",
|
|
628
636
|
})
|
|
629
637
|
.toString()
|
|
630
|
-
.trim()
|
|
631
|
-
console.log(`Using project: ${projectId}`)
|
|
638
|
+
.trim()
|
|
639
|
+
console.log(`Using project: ${projectId}`)
|
|
632
640
|
} catch (error) {
|
|
633
|
-
console.error("❌ Failed to get gcloud project ID")
|
|
634
|
-
console.log("─".repeat(50))
|
|
635
|
-
resolve(null)
|
|
636
|
-
return
|
|
641
|
+
console.error("❌ Failed to get gcloud project ID")
|
|
642
|
+
console.log("─".repeat(50))
|
|
643
|
+
resolve(null)
|
|
644
|
+
return
|
|
637
645
|
}
|
|
638
646
|
|
|
639
|
-
console.log("Sending request to Gemini...\n")
|
|
647
|
+
console.log("Sending request to Gemini...\n")
|
|
640
648
|
|
|
641
649
|
const requestBody = JSON.stringify({
|
|
642
650
|
contents: [
|
|
@@ -649,7 +657,7 @@ async function generateWithGeminiGcloud(fullPrompt) {
|
|
|
649
657
|
maxOutputTokens: 8192,
|
|
650
658
|
temperature: 0.7,
|
|
651
659
|
},
|
|
652
|
-
})
|
|
660
|
+
})
|
|
653
661
|
|
|
654
662
|
// Use curl to make the request (more reliable than fetch with gcloud auth)
|
|
655
663
|
const curl = spawn(
|
|
@@ -666,70 +674,72 @@ async function generateWithGeminiGcloud(fullPrompt) {
|
|
|
666
674
|
"-d",
|
|
667
675
|
requestBody,
|
|
668
676
|
],
|
|
669
|
-
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
670
|
-
)
|
|
677
|
+
{ stdio: ["pipe", "pipe", "pipe"] },
|
|
678
|
+
)
|
|
671
679
|
|
|
672
|
-
let output = ""
|
|
673
|
-
let errorOutput = ""
|
|
680
|
+
let output = ""
|
|
681
|
+
let errorOutput = ""
|
|
674
682
|
|
|
675
683
|
curl.stdout.on("data", (data) => {
|
|
676
|
-
output += data.toString()
|
|
677
|
-
})
|
|
684
|
+
output += data.toString()
|
|
685
|
+
})
|
|
678
686
|
|
|
679
687
|
curl.stderr.on("data", (data) => {
|
|
680
|
-
errorOutput += data.toString()
|
|
681
|
-
})
|
|
688
|
+
errorOutput += data.toString()
|
|
689
|
+
})
|
|
682
690
|
|
|
683
691
|
curl.on("close", (code) => {
|
|
684
692
|
if (code !== 0) {
|
|
685
|
-
console.error(`❌ Gemini gcloud error: ${errorOutput}`)
|
|
686
|
-
console.log("─".repeat(50))
|
|
687
|
-
resolve(null)
|
|
688
|
-
return
|
|
693
|
+
console.error(`❌ Gemini gcloud error: ${errorOutput}`)
|
|
694
|
+
console.log("─".repeat(50))
|
|
695
|
+
resolve(null)
|
|
696
|
+
return
|
|
689
697
|
}
|
|
690
698
|
|
|
691
699
|
try {
|
|
692
|
-
const data = JSON.parse(output)
|
|
700
|
+
const data = JSON.parse(output)
|
|
693
701
|
const responseText =
|
|
694
|
-
data.candidates?.[0]?.content?.parts?.[0]?.text || ""
|
|
702
|
+
data.candidates?.[0]?.content?.parts?.[0]?.text || ""
|
|
695
703
|
|
|
696
704
|
if (!responseText) {
|
|
697
|
-
console.error("❌ No response from Gemini")
|
|
698
|
-
console.log("─".repeat(50))
|
|
699
|
-
resolve(null)
|
|
700
|
-
return
|
|
705
|
+
console.error("❌ No response from Gemini")
|
|
706
|
+
console.log("─".repeat(50))
|
|
707
|
+
resolve(null)
|
|
708
|
+
return
|
|
701
709
|
}
|
|
702
710
|
|
|
703
711
|
// Show the response to user
|
|
704
|
-
console.log("Gemini Response:\n")
|
|
705
|
-
console.log(responseText)
|
|
706
|
-
console.log("\n" + "─".repeat(50))
|
|
712
|
+
console.log("Gemini Response:\n")
|
|
713
|
+
console.log(responseText)
|
|
714
|
+
console.log("\n" + "─".repeat(50))
|
|
707
715
|
|
|
708
|
-
const scaffoldData = parseAIResponse(responseText)
|
|
716
|
+
const scaffoldData = parseAIResponse(responseText)
|
|
709
717
|
|
|
710
718
|
if (!scaffoldData) {
|
|
711
|
-
console.error("\n❌ Could not parse Gemini response as JSON")
|
|
712
|
-
console.log(
|
|
713
|
-
|
|
714
|
-
|
|
719
|
+
console.error("\n❌ Could not parse Gemini response as JSON")
|
|
720
|
+
console.log(
|
|
721
|
+
"The AI response was shown above but couldn't be parsed into scaffold data.",
|
|
722
|
+
)
|
|
723
|
+
resolve(null)
|
|
724
|
+
return
|
|
715
725
|
}
|
|
716
726
|
|
|
717
727
|
if (scaffoldData.explanation) {
|
|
718
|
-
console.log("\n📝 AI Explanation:")
|
|
719
|
-
console.log(` ${scaffoldData.explanation}`)
|
|
720
|
-
console.log("")
|
|
728
|
+
console.log("\n📝 AI Explanation:")
|
|
729
|
+
console.log(` ${scaffoldData.explanation}`)
|
|
730
|
+
console.log("")
|
|
721
731
|
}
|
|
722
732
|
|
|
723
|
-
resolve(scaffoldData)
|
|
733
|
+
resolve(scaffoldData)
|
|
724
734
|
} catch (parseError) {
|
|
725
735
|
console.error(
|
|
726
|
-
`❌ Failed to parse Gemini response: ${parseError.message}
|
|
727
|
-
)
|
|
728
|
-
console.log("─".repeat(50))
|
|
729
|
-
resolve(null)
|
|
736
|
+
`❌ Failed to parse Gemini response: ${parseError.message}`,
|
|
737
|
+
)
|
|
738
|
+
console.log("─".repeat(50))
|
|
739
|
+
resolve(null)
|
|
730
740
|
}
|
|
731
|
-
})
|
|
732
|
-
})
|
|
741
|
+
})
|
|
742
|
+
})
|
|
733
743
|
}
|
|
734
744
|
|
|
735
745
|
/**
|
|
@@ -738,13 +748,13 @@ async function generateWithGeminiGcloud(fullPrompt) {
|
|
|
738
748
|
function buildFullPrompt(userPrompt, projectName, description) {
|
|
739
749
|
return `
|
|
740
750
|
Project Name: ${projectName}
|
|
741
|
-
Project Description: ${description || "A GxP
|
|
751
|
+
Project Description: ${description || "A GxP plugin"}
|
|
742
752
|
|
|
743
753
|
User Request:
|
|
744
754
|
${userPrompt}
|
|
745
755
|
|
|
746
756
|
Please generate the necessary Vue components and manifest updates for this plugin. Follow the GxP plugin architecture guidelines. Return ONLY a valid JSON object with components, manifest, and explanation fields.
|
|
747
|
-
|
|
757
|
+
`
|
|
748
758
|
}
|
|
749
759
|
|
|
750
760
|
/**
|
|
@@ -755,26 +765,26 @@ Please generate the necessary Vue components and manifest updates for this plugi
|
|
|
755
765
|
function parseAIResponse(response) {
|
|
756
766
|
try {
|
|
757
767
|
// Try to find JSON in the response
|
|
758
|
-
const jsonMatch = response.match(/```json\n?([\s\S]*?)\n?```/)
|
|
768
|
+
const jsonMatch = response.match(/```json\n?([\s\S]*?)\n?```/)
|
|
759
769
|
if (jsonMatch) {
|
|
760
|
-
return JSON.parse(jsonMatch[1])
|
|
770
|
+
return JSON.parse(jsonMatch[1])
|
|
761
771
|
}
|
|
762
772
|
|
|
763
773
|
// Try parsing the entire response as JSON
|
|
764
|
-
return JSON.parse(response)
|
|
774
|
+
return JSON.parse(response)
|
|
765
775
|
} catch (error) {
|
|
766
776
|
// Try to extract JSON object from response
|
|
767
|
-
const jsonStart = response.indexOf("{")
|
|
768
|
-
const jsonEnd = response.lastIndexOf("}")
|
|
777
|
+
const jsonStart = response.indexOf("{")
|
|
778
|
+
const jsonEnd = response.lastIndexOf("}")
|
|
769
779
|
if (jsonStart !== -1 && jsonEnd !== -1) {
|
|
770
780
|
try {
|
|
771
|
-
return JSON.parse(response.slice(jsonStart, jsonEnd + 1))
|
|
781
|
+
return JSON.parse(response.slice(jsonStart, jsonEnd + 1))
|
|
772
782
|
} catch {
|
|
773
783
|
// Parsing failed
|
|
774
784
|
}
|
|
775
785
|
}
|
|
776
786
|
}
|
|
777
|
-
return null
|
|
787
|
+
return null
|
|
778
788
|
}
|
|
779
789
|
|
|
780
790
|
/**
|
|
@@ -788,32 +798,32 @@ function applyScaffold(projectPath, scaffoldData) {
|
|
|
788
798
|
filesCreated: [],
|
|
789
799
|
manifestUpdated: false,
|
|
790
800
|
errors: [],
|
|
791
|
-
}
|
|
801
|
+
}
|
|
792
802
|
|
|
793
803
|
// Create component files
|
|
794
804
|
if (scaffoldData.components && Array.isArray(scaffoldData.components)) {
|
|
795
805
|
for (const component of scaffoldData.components) {
|
|
796
806
|
if (component.path && component.content) {
|
|
797
807
|
try {
|
|
798
|
-
const filePath = path.join(projectPath, component.path)
|
|
799
|
-
const dirPath = path.dirname(filePath)
|
|
808
|
+
const filePath = path.join(projectPath, component.path)
|
|
809
|
+
const dirPath = path.dirname(filePath)
|
|
800
810
|
|
|
801
811
|
// Create directory if needed
|
|
802
812
|
if (!fs.existsSync(dirPath)) {
|
|
803
|
-
fs.mkdirSync(dirPath, { recursive: true })
|
|
813
|
+
fs.mkdirSync(dirPath, { recursive: true })
|
|
804
814
|
}
|
|
805
815
|
|
|
806
816
|
// Write file
|
|
807
|
-
fs.writeFileSync(filePath, component.content)
|
|
808
|
-
result.filesCreated.push(component.path)
|
|
809
|
-
console.log(`✓ Created ${component.path}`)
|
|
817
|
+
fs.writeFileSync(filePath, component.content)
|
|
818
|
+
result.filesCreated.push(component.path)
|
|
819
|
+
console.log(`✓ Created ${component.path}`)
|
|
810
820
|
} catch (error) {
|
|
811
821
|
result.errors.push(
|
|
812
|
-
`Failed to create ${component.path}: ${error.message}
|
|
813
|
-
)
|
|
822
|
+
`Failed to create ${component.path}: ${error.message}`,
|
|
823
|
+
)
|
|
814
824
|
console.error(
|
|
815
|
-
`✗ Failed to create ${component.path}: ${error.message}
|
|
816
|
-
)
|
|
825
|
+
`✗ Failed to create ${component.path}: ${error.message}`,
|
|
826
|
+
)
|
|
817
827
|
}
|
|
818
828
|
}
|
|
819
829
|
}
|
|
@@ -822,45 +832,46 @@ function applyScaffold(projectPath, scaffoldData) {
|
|
|
822
832
|
// Update manifest
|
|
823
833
|
if (scaffoldData.manifest) {
|
|
824
834
|
try {
|
|
825
|
-
const manifestPath = path.join(projectPath, "app-manifest.json")
|
|
826
|
-
let manifest = {}
|
|
835
|
+
const manifestPath = path.join(projectPath, "app-manifest.json")
|
|
836
|
+
let manifest = {}
|
|
827
837
|
|
|
828
838
|
if (fs.existsSync(manifestPath)) {
|
|
829
|
-
manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"))
|
|
839
|
+
manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"))
|
|
830
840
|
}
|
|
831
841
|
|
|
832
842
|
// Merge strings
|
|
833
843
|
if (scaffoldData.manifest.strings) {
|
|
834
|
-
manifest.strings = manifest.strings || {}
|
|
835
|
-
manifest.strings.default = manifest.strings.default || {}
|
|
844
|
+
manifest.strings = manifest.strings || {}
|
|
845
|
+
manifest.strings.default = manifest.strings.default || {}
|
|
836
846
|
Object.assign(
|
|
837
847
|
manifest.strings.default,
|
|
838
|
-
scaffoldData.manifest.strings.default ||
|
|
839
|
-
|
|
848
|
+
scaffoldData.manifest.strings.default ||
|
|
849
|
+
scaffoldData.manifest.strings,
|
|
850
|
+
)
|
|
840
851
|
}
|
|
841
852
|
|
|
842
853
|
// Merge assets
|
|
843
854
|
if (scaffoldData.manifest.assets) {
|
|
844
|
-
manifest.assets = manifest.assets || {}
|
|
845
|
-
Object.assign(manifest.assets, scaffoldData.manifest.assets)
|
|
855
|
+
manifest.assets = manifest.assets || {}
|
|
856
|
+
Object.assign(manifest.assets, scaffoldData.manifest.assets)
|
|
846
857
|
}
|
|
847
858
|
|
|
848
859
|
// Merge settings
|
|
849
860
|
if (scaffoldData.manifest.settings) {
|
|
850
|
-
manifest.settings = manifest.settings || {}
|
|
851
|
-
Object.assign(manifest.settings, scaffoldData.manifest.settings)
|
|
861
|
+
manifest.settings = manifest.settings || {}
|
|
862
|
+
Object.assign(manifest.settings, scaffoldData.manifest.settings)
|
|
852
863
|
}
|
|
853
864
|
|
|
854
|
-
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, "\t"))
|
|
855
|
-
result.manifestUpdated = true
|
|
856
|
-
console.log("✓ Updated app-manifest.json")
|
|
865
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, "\t"))
|
|
866
|
+
result.manifestUpdated = true
|
|
867
|
+
console.log("✓ Updated app-manifest.json")
|
|
857
868
|
} catch (error) {
|
|
858
|
-
result.errors.push(`Failed to update manifest: ${error.message}`)
|
|
859
|
-
console.error(`✗ Failed to update manifest: ${error.message}`)
|
|
869
|
+
result.errors.push(`Failed to update manifest: ${error.message}`)
|
|
870
|
+
console.error(`✗ Failed to update manifest: ${error.message}`)
|
|
860
871
|
}
|
|
861
872
|
}
|
|
862
873
|
|
|
863
|
-
return result
|
|
874
|
+
return result
|
|
864
875
|
}
|
|
865
876
|
|
|
866
877
|
/**
|
|
@@ -875,27 +886,27 @@ async function generateScaffold(
|
|
|
875
886
|
provider,
|
|
876
887
|
userPrompt,
|
|
877
888
|
projectName,
|
|
878
|
-
description
|
|
889
|
+
description,
|
|
879
890
|
) {
|
|
880
|
-
const providerConfig = AI_PROVIDERS[provider]
|
|
891
|
+
const providerConfig = AI_PROVIDERS[provider]
|
|
881
892
|
if (!providerConfig) {
|
|
882
|
-
console.error(`❌ Unknown AI provider: ${provider}`)
|
|
883
|
-
return null
|
|
893
|
+
console.error(`❌ Unknown AI provider: ${provider}`)
|
|
894
|
+
return null
|
|
884
895
|
}
|
|
885
896
|
|
|
886
|
-
const status = await providerConfig.checkAvailable()
|
|
897
|
+
const status = await providerConfig.checkAvailable()
|
|
887
898
|
if (!status.available) {
|
|
888
|
-
console.error(`❌ ${providerConfig.name} is not available:`)
|
|
889
|
-
console.error(` ${status.reason}`)
|
|
890
|
-
return null
|
|
899
|
+
console.error(`❌ ${providerConfig.name} is not available:`)
|
|
900
|
+
console.error(` ${status.reason}`)
|
|
901
|
+
return null
|
|
891
902
|
}
|
|
892
903
|
|
|
893
904
|
return providerConfig.generate(
|
|
894
905
|
userPrompt,
|
|
895
906
|
projectName,
|
|
896
907
|
description,
|
|
897
|
-
status.method
|
|
898
|
-
)
|
|
908
|
+
status.method,
|
|
909
|
+
)
|
|
899
910
|
}
|
|
900
911
|
|
|
901
912
|
/**
|
|
@@ -912,34 +923,34 @@ async function runAIScaffolding(
|
|
|
912
923
|
projectName,
|
|
913
924
|
description,
|
|
914
925
|
buildPrompt,
|
|
915
|
-
provider = "gemini"
|
|
926
|
+
provider = "gemini",
|
|
916
927
|
) {
|
|
917
928
|
const scaffoldData = await generateScaffold(
|
|
918
929
|
provider,
|
|
919
930
|
buildPrompt,
|
|
920
931
|
projectName,
|
|
921
|
-
description
|
|
922
|
-
)
|
|
932
|
+
description,
|
|
933
|
+
)
|
|
923
934
|
|
|
924
935
|
if (!scaffoldData) {
|
|
925
|
-
return false
|
|
936
|
+
return false
|
|
926
937
|
}
|
|
927
938
|
|
|
928
|
-
console.log("📦 Applying scaffold to project...\n")
|
|
929
|
-
const result = applyScaffold(projectPath, scaffoldData)
|
|
939
|
+
console.log("📦 Applying scaffold to project...\n")
|
|
940
|
+
const result = applyScaffold(projectPath, scaffoldData)
|
|
930
941
|
|
|
931
|
-
console.log("")
|
|
942
|
+
console.log("")
|
|
932
943
|
if (result.filesCreated.length > 0) {
|
|
933
|
-
console.log(`✅ Created ${result.filesCreated.length} file(s)`)
|
|
944
|
+
console.log(`✅ Created ${result.filesCreated.length} file(s)`)
|
|
934
945
|
}
|
|
935
946
|
if (result.manifestUpdated) {
|
|
936
|
-
console.log("✅ Updated app-manifest.json")
|
|
947
|
+
console.log("✅ Updated app-manifest.json")
|
|
937
948
|
}
|
|
938
949
|
if (result.errors.length > 0) {
|
|
939
|
-
console.log(`⚠️ ${result.errors.length} error(s) occurred`)
|
|
950
|
+
console.log(`⚠️ ${result.errors.length} error(s) occurred`)
|
|
940
951
|
}
|
|
941
952
|
|
|
942
|
-
return result.errors.length === 0
|
|
953
|
+
return result.errors.length === 0
|
|
943
954
|
}
|
|
944
955
|
|
|
945
956
|
module.exports = {
|
|
@@ -950,4 +961,4 @@ module.exports = {
|
|
|
950
961
|
applyScaffold,
|
|
951
962
|
generateScaffold,
|
|
952
963
|
runAIScaffolding,
|
|
953
|
-
}
|
|
964
|
+
}
|