@gxp-dev/tools 2.0.63 → 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.
Files changed (182) hide show
  1. package/README.md +32 -31
  2. package/bin/gx-devtools.js +74 -54
  3. package/bin/lib/cli.js +23 -21
  4. package/bin/lib/commands/add-dependency.js +366 -325
  5. package/bin/lib/commands/assets.js +137 -139
  6. package/bin/lib/commands/build.js +169 -174
  7. package/bin/lib/commands/datastore.js +181 -183
  8. package/bin/lib/commands/dev.js +127 -131
  9. package/bin/lib/commands/extensions.js +147 -149
  10. package/bin/lib/commands/extract-config.js +73 -67
  11. package/bin/lib/commands/index.js +12 -12
  12. package/bin/lib/commands/init.js +342 -240
  13. package/bin/lib/commands/publish.js +69 -75
  14. package/bin/lib/commands/socket.js +69 -69
  15. package/bin/lib/commands/ssl.js +14 -14
  16. package/bin/lib/constants.js +10 -24
  17. package/bin/lib/tui/App.tsx +761 -705
  18. package/bin/lib/tui/components/AIPanel.tsx +191 -171
  19. package/bin/lib/tui/components/CommandInput.tsx +394 -343
  20. package/bin/lib/tui/components/GeminiPanel.tsx +175 -151
  21. package/bin/lib/tui/components/Header.tsx +23 -21
  22. package/bin/lib/tui/components/LogPanel.tsx +244 -220
  23. package/bin/lib/tui/components/TabBar.tsx +50 -48
  24. package/bin/lib/tui/components/WelcomeScreen.tsx +126 -71
  25. package/bin/lib/tui/index.tsx +37 -39
  26. package/bin/lib/tui/services/AIService.ts +518 -462
  27. package/bin/lib/tui/services/ExtensionService.ts +140 -129
  28. package/bin/lib/tui/services/GeminiService.ts +367 -337
  29. package/bin/lib/tui/services/ServiceManager.ts +344 -322
  30. package/bin/lib/tui/services/SocketService.ts +168 -168
  31. package/bin/lib/tui/services/ViteService.ts +88 -88
  32. package/bin/lib/tui/services/index.ts +47 -22
  33. package/bin/lib/utils/ai-scaffold.js +291 -280
  34. package/bin/lib/utils/extract-config.js +157 -140
  35. package/bin/lib/utils/files.js +82 -86
  36. package/bin/lib/utils/index.js +7 -7
  37. package/bin/lib/utils/paths.js +34 -34
  38. package/bin/lib/utils/prompts.js +194 -169
  39. package/bin/lib/utils/ssl.js +79 -81
  40. package/browser-extensions/README.md +0 -1
  41. package/browser-extensions/chrome/background.js +244 -237
  42. package/browser-extensions/chrome/content.js +32 -29
  43. package/browser-extensions/chrome/devtools.html +7 -7
  44. package/browser-extensions/chrome/devtools.js +19 -19
  45. package/browser-extensions/chrome/inspector.js +802 -767
  46. package/browser-extensions/chrome/manifest.json +71 -63
  47. package/browser-extensions/chrome/panel.html +674 -636
  48. package/browser-extensions/chrome/panel.js +722 -712
  49. package/browser-extensions/chrome/popup.html +586 -543
  50. package/browser-extensions/chrome/popup.js +282 -244
  51. package/browser-extensions/chrome/rules.json +1 -1
  52. package/browser-extensions/chrome/test-chrome.html +216 -136
  53. package/browser-extensions/chrome/test-mixed-content.html +284 -189
  54. package/browser-extensions/chrome/test-uri-pattern.html +221 -198
  55. package/browser-extensions/firefox/README.md +9 -6
  56. package/browser-extensions/firefox/background.js +221 -218
  57. package/browser-extensions/firefox/content.js +55 -52
  58. package/browser-extensions/firefox/debug-errors.html +386 -228
  59. package/browser-extensions/firefox/debug-https.html +153 -105
  60. package/browser-extensions/firefox/devtools.html +7 -7
  61. package/browser-extensions/firefox/devtools.js +23 -20
  62. package/browser-extensions/firefox/inspector.js +802 -767
  63. package/browser-extensions/firefox/manifest.json +68 -68
  64. package/browser-extensions/firefox/panel.html +674 -636
  65. package/browser-extensions/firefox/panel.js +722 -712
  66. package/browser-extensions/firefox/popup.html +572 -535
  67. package/browser-extensions/firefox/popup.js +281 -236
  68. package/browser-extensions/firefox/test-gramercy.html +170 -125
  69. package/browser-extensions/firefox/test-imports.html +59 -55
  70. package/browser-extensions/firefox/test-masking.html +231 -140
  71. package/browser-extensions/firefox/test-uri-pattern.html +221 -198
  72. package/dist/tui/App.d.ts +1 -1
  73. package/dist/tui/App.d.ts.map +1 -1
  74. package/dist/tui/App.js +154 -150
  75. package/dist/tui/App.js.map +1 -1
  76. package/dist/tui/components/AIPanel.d.ts.map +1 -1
  77. package/dist/tui/components/AIPanel.js +42 -35
  78. package/dist/tui/components/AIPanel.js.map +1 -1
  79. package/dist/tui/components/CommandInput.d.ts +1 -1
  80. package/dist/tui/components/CommandInput.d.ts.map +1 -1
  81. package/dist/tui/components/CommandInput.js +92 -62
  82. package/dist/tui/components/CommandInput.js.map +1 -1
  83. package/dist/tui/components/GeminiPanel.d.ts.map +1 -1
  84. package/dist/tui/components/GeminiPanel.js +37 -30
  85. package/dist/tui/components/GeminiPanel.js.map +1 -1
  86. package/dist/tui/components/Header.d.ts.map +1 -1
  87. package/dist/tui/components/Header.js +1 -1
  88. package/dist/tui/components/Header.js.map +1 -1
  89. package/dist/tui/components/LogPanel.d.ts +1 -1
  90. package/dist/tui/components/LogPanel.d.ts.map +1 -1
  91. package/dist/tui/components/LogPanel.js +26 -24
  92. package/dist/tui/components/LogPanel.js.map +1 -1
  93. package/dist/tui/components/TabBar.d.ts +2 -2
  94. package/dist/tui/components/TabBar.d.ts.map +1 -1
  95. package/dist/tui/components/TabBar.js +11 -11
  96. package/dist/tui/components/TabBar.js.map +1 -1
  97. package/dist/tui/components/WelcomeScreen.d.ts.map +1 -1
  98. package/dist/tui/components/WelcomeScreen.js +6 -6
  99. package/dist/tui/components/WelcomeScreen.js.map +1 -1
  100. package/dist/tui/index.d.ts.map +1 -1
  101. package/dist/tui/index.js +8 -8
  102. package/dist/tui/index.js.map +1 -1
  103. package/dist/tui/services/AIService.d.ts +2 -2
  104. package/dist/tui/services/AIService.d.ts.map +1 -1
  105. package/dist/tui/services/AIService.js +165 -125
  106. package/dist/tui/services/AIService.js.map +1 -1
  107. package/dist/tui/services/ExtensionService.d.ts +1 -1
  108. package/dist/tui/services/ExtensionService.d.ts.map +1 -1
  109. package/dist/tui/services/ExtensionService.js +33 -26
  110. package/dist/tui/services/ExtensionService.js.map +1 -1
  111. package/dist/tui/services/GeminiService.d.ts +1 -1
  112. package/dist/tui/services/GeminiService.d.ts.map +1 -1
  113. package/dist/tui/services/GeminiService.js +87 -76
  114. package/dist/tui/services/GeminiService.js.map +1 -1
  115. package/dist/tui/services/ServiceManager.d.ts +3 -3
  116. package/dist/tui/services/ServiceManager.d.ts.map +1 -1
  117. package/dist/tui/services/ServiceManager.js +72 -58
  118. package/dist/tui/services/ServiceManager.js.map +1 -1
  119. package/dist/tui/services/SocketService.d.ts.map +1 -1
  120. package/dist/tui/services/SocketService.js +32 -32
  121. package/dist/tui/services/SocketService.js.map +1 -1
  122. package/dist/tui/services/ViteService.d.ts.map +1 -1
  123. package/dist/tui/services/ViteService.js +26 -28
  124. package/dist/tui/services/ViteService.js.map +1 -1
  125. package/dist/tui/services/index.d.ts +6 -6
  126. package/dist/tui/services/index.d.ts.map +1 -1
  127. package/dist/tui/services/index.js +6 -6
  128. package/dist/tui/services/index.js.map +1 -1
  129. package/mcp/gxp-api-server.js +83 -81
  130. package/package.json +109 -93
  131. package/runtime/PortalContainer.vue +258 -234
  132. package/runtime/dev-tools/DevToolsModal.vue +153 -155
  133. package/runtime/dev-tools/LayoutSwitcher.vue +144 -140
  134. package/runtime/dev-tools/MockDataEditor.vue +456 -433
  135. package/runtime/dev-tools/SocketSimulator.vue +379 -371
  136. package/runtime/dev-tools/StoreInspector.vue +517 -455
  137. package/runtime/dev-tools/index.js +5 -5
  138. package/runtime/fallback-layouts/PrivateLayout.vue +2 -2
  139. package/runtime/fallback-layouts/PublicLayout.vue +2 -2
  140. package/runtime/fallback-layouts/SystemLayout.vue +2 -2
  141. package/runtime/gxpStringsPlugin.js +159 -134
  142. package/runtime/index.html +17 -19
  143. package/runtime/main.js +24 -22
  144. package/runtime/mock-api/auth-middleware.js +15 -15
  145. package/runtime/mock-api/image-generator.js +46 -46
  146. package/runtime/mock-api/index.js +55 -55
  147. package/runtime/mock-api/response-generator.js +116 -105
  148. package/runtime/mock-api/route-generator.js +107 -84
  149. package/runtime/mock-api/socket-triggers.js +94 -93
  150. package/runtime/mock-api/spec-loader.js +79 -80
  151. package/runtime/package.json +3 -0
  152. package/runtime/server.js +68 -68
  153. package/runtime/stores/gxpPortalConfigStore.js +204 -186
  154. package/runtime/stores/index.js +2 -2
  155. package/runtime/vite-inspector-plugin.js +858 -707
  156. package/runtime/vite-source-tracker-plugin.js +132 -113
  157. package/runtime/vite.config.js +191 -139
  158. package/scripts/launch-chrome.js +41 -41
  159. package/scripts/pack-chrome.js +38 -39
  160. package/socket-events/AiSessionMessageCreated.json +17 -17
  161. package/socket-events/SocialStreamPostCreated.json +23 -23
  162. package/socket-events/SocialStreamPostVariantCompleted.json +22 -22
  163. package/template/.claude/agents/gxp-developer.md +100 -99
  164. package/template/.claude/settings.json +7 -7
  165. package/template/AGENTS.md +30 -23
  166. package/template/GEMINI.md +20 -20
  167. package/template/README.md +70 -53
  168. package/template/app-manifest.json +2 -4
  169. package/template/configuration.json +10 -10
  170. package/template/default-styling.css +1 -1
  171. package/template/index.html +18 -20
  172. package/template/main.js +24 -22
  173. package/template/src/DemoPage.vue +415 -362
  174. package/template/src/Plugin.vue +76 -85
  175. package/template/src/stores/index.js +3 -3
  176. package/template/src/stores/test-data.json +164 -172
  177. package/template/theme-layouts/AdditionalStyling.css +50 -50
  178. package/template/theme-layouts/PrivateLayout.vue +8 -12
  179. package/template/theme-layouts/PublicLayout.vue +8 -12
  180. package/template/theme-layouts/SystemLayout.vue +8 -12
  181. package/template/vite.extend.js +45 -0
  182. 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("The AI response was shown above but couldn't be parsed into scaffold data.");
316
- resolve(null);
317
- return;
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("The AI response was shown above but couldn't be parsed into scaffold data.");
399
- resolve(null);
400
- return;
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("The AI response was shown above but couldn't be parsed into scaffold data.");
505
- resolve(null);
506
- return;
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("The AI response was shown above but couldn't be parsed into scaffold data.");
583
- return null;
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("The AI response was shown above but couldn't be parsed into scaffold data.");
713
- resolve(null);
714
- return;
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 kiosk plugin"}
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 || scaffoldData.manifest.strings
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
+ }