@gxp-dev/tools 2.0.5

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 (145) hide show
  1. package/.github/workflows/npm-publish.yml +48 -0
  2. package/CLAUDE.md +400 -0
  3. package/README.md +247 -0
  4. package/REFACTOR_PLAN.md +194 -0
  5. package/bin/gx-devtools.js +87 -0
  6. package/bin/lib/cli.js +251 -0
  7. package/bin/lib/commands/assets.js +337 -0
  8. package/bin/lib/commands/build.js +259 -0
  9. package/bin/lib/commands/datastore.js +433 -0
  10. package/bin/lib/commands/dev.js +328 -0
  11. package/bin/lib/commands/extensions.js +298 -0
  12. package/bin/lib/commands/index.js +35 -0
  13. package/bin/lib/commands/init.js +307 -0
  14. package/bin/lib/commands/publish.js +189 -0
  15. package/bin/lib/commands/socket.js +158 -0
  16. package/bin/lib/commands/ssl.js +47 -0
  17. package/bin/lib/constants.js +120 -0
  18. package/bin/lib/tui/App.tsx +600 -0
  19. package/bin/lib/tui/components/CommandInput.tsx +278 -0
  20. package/bin/lib/tui/components/GeminiPanel.tsx +161 -0
  21. package/bin/lib/tui/components/Header.tsx +27 -0
  22. package/bin/lib/tui/components/LogPanel.tsx +122 -0
  23. package/bin/lib/tui/components/TabBar.tsx +56 -0
  24. package/bin/lib/tui/components/WelcomeScreen.tsx +80 -0
  25. package/bin/lib/tui/index.tsx +63 -0
  26. package/bin/lib/tui/services/ExtensionService.ts +122 -0
  27. package/bin/lib/tui/services/GeminiService.ts +395 -0
  28. package/bin/lib/tui/services/ServiceManager.ts +336 -0
  29. package/bin/lib/tui/services/SocketService.ts +204 -0
  30. package/bin/lib/tui/services/ViteService.ts +107 -0
  31. package/bin/lib/tui/services/index.ts +13 -0
  32. package/bin/lib/utils/files.js +180 -0
  33. package/bin/lib/utils/index.js +17 -0
  34. package/bin/lib/utils/paths.js +138 -0
  35. package/bin/lib/utils/prompts.js +71 -0
  36. package/bin/lib/utils/ssl.js +233 -0
  37. package/browser-extensions/README.md +1 -0
  38. package/browser-extensions/chrome/background.js +857 -0
  39. package/browser-extensions/chrome/content.js +51 -0
  40. package/browser-extensions/chrome/devtools.html +9 -0
  41. package/browser-extensions/chrome/devtools.js +23 -0
  42. package/browser-extensions/chrome/icons/gx_off_128.png +0 -0
  43. package/browser-extensions/chrome/icons/gx_off_16.png +0 -0
  44. package/browser-extensions/chrome/icons/gx_off_32.png +0 -0
  45. package/browser-extensions/chrome/icons/gx_off_64.png +0 -0
  46. package/browser-extensions/chrome/icons/gx_on_128.png +0 -0
  47. package/browser-extensions/chrome/icons/gx_on_16.png +0 -0
  48. package/browser-extensions/chrome/icons/gx_on_32.png +0 -0
  49. package/browser-extensions/chrome/icons/gx_on_64.png +0 -0
  50. package/browser-extensions/chrome/inspector.js +1087 -0
  51. package/browser-extensions/chrome/manifest.json +70 -0
  52. package/browser-extensions/chrome/panel.html +638 -0
  53. package/browser-extensions/chrome/panel.js +862 -0
  54. package/browser-extensions/chrome/popup.html +399 -0
  55. package/browser-extensions/chrome/popup.js +515 -0
  56. package/browser-extensions/chrome/rules.json +1 -0
  57. package/browser-extensions/chrome/test-chrome.html +145 -0
  58. package/browser-extensions/chrome/test-mixed-content.html +190 -0
  59. package/browser-extensions/chrome/test-uri-pattern.html +199 -0
  60. package/browser-extensions/firefox/README.md +134 -0
  61. package/browser-extensions/firefox/background.js +804 -0
  62. package/browser-extensions/firefox/content.js +120 -0
  63. package/browser-extensions/firefox/debug-errors.html +229 -0
  64. package/browser-extensions/firefox/debug-https.html +113 -0
  65. package/browser-extensions/firefox/devtools.html +9 -0
  66. package/browser-extensions/firefox/devtools.js +24 -0
  67. package/browser-extensions/firefox/icons/gx_off_128.png +0 -0
  68. package/browser-extensions/firefox/icons/gx_off_16.png +0 -0
  69. package/browser-extensions/firefox/icons/gx_off_32.png +0 -0
  70. package/browser-extensions/firefox/icons/gx_off_64.png +0 -0
  71. package/browser-extensions/firefox/icons/gx_on_128.png +0 -0
  72. package/browser-extensions/firefox/icons/gx_on_16.png +0 -0
  73. package/browser-extensions/firefox/icons/gx_on_32.png +0 -0
  74. package/browser-extensions/firefox/icons/gx_on_64.png +0 -0
  75. package/browser-extensions/firefox/inspector.js +1087 -0
  76. package/browser-extensions/firefox/manifest.json +67 -0
  77. package/browser-extensions/firefox/panel.html +638 -0
  78. package/browser-extensions/firefox/panel.js +862 -0
  79. package/browser-extensions/firefox/popup.html +525 -0
  80. package/browser-extensions/firefox/popup.js +536 -0
  81. package/browser-extensions/firefox/test-gramercy.html +126 -0
  82. package/browser-extensions/firefox/test-imports.html +58 -0
  83. package/browser-extensions/firefox/test-masking.html +147 -0
  84. package/browser-extensions/firefox/test-uri-pattern.html +199 -0
  85. package/docs/DOCUSAURUS_IMPORT.md +378 -0
  86. package/docs/_category_.json +8 -0
  87. package/docs/app-manifest.md +272 -0
  88. package/docs/building-for-platform.md +315 -0
  89. package/docs/dev-tools.md +291 -0
  90. package/docs/getting-started.md +180 -0
  91. package/docs/gxp-store.md +305 -0
  92. package/docs/index.md +44 -0
  93. package/package.json +77 -0
  94. package/runtime/PortalContainer.vue +326 -0
  95. package/runtime/dev-tools/DevToolsModal.vue +217 -0
  96. package/runtime/dev-tools/LayoutSwitcher.vue +221 -0
  97. package/runtime/dev-tools/MockDataEditor.vue +621 -0
  98. package/runtime/dev-tools/SocketSimulator.vue +562 -0
  99. package/runtime/dev-tools/StoreInspector.vue +644 -0
  100. package/runtime/dev-tools/index.js +6 -0
  101. package/runtime/gxpStringsPlugin.js +428 -0
  102. package/runtime/index.html +22 -0
  103. package/runtime/main.js +32 -0
  104. package/runtime/mock-api/auth-middleware.js +97 -0
  105. package/runtime/mock-api/image-generator.js +221 -0
  106. package/runtime/mock-api/index.js +197 -0
  107. package/runtime/mock-api/response-generator.js +394 -0
  108. package/runtime/mock-api/route-generator.js +323 -0
  109. package/runtime/mock-api/socket-triggers.js +371 -0
  110. package/runtime/mock-api/spec-loader.js +300 -0
  111. package/runtime/server.js +180 -0
  112. package/runtime/stores/gxpPortalConfigStore.js +554 -0
  113. package/runtime/stores/index.js +6 -0
  114. package/runtime/vite-inspector-plugin.js +749 -0
  115. package/runtime/vite-source-tracker-plugin.js +232 -0
  116. package/runtime/vite.config.js +402 -0
  117. package/scripts/launch-chrome.js +90 -0
  118. package/scripts/pack-chrome.js +91 -0
  119. package/socket-events/AiSessionMessageCreated.json +18 -0
  120. package/socket-events/SocialStreamPostCreated.json +24 -0
  121. package/socket-events/SocialStreamPostVariantCompleted.json +23 -0
  122. package/template/README.md +332 -0
  123. package/template/app-manifest.json +32 -0
  124. package/template/dev-assets/images/avatar-placeholder.png +0 -0
  125. package/template/dev-assets/images/background-placeholder.jpg +0 -0
  126. package/template/dev-assets/images/banner-placeholder.jpg +0 -0
  127. package/template/dev-assets/images/icon-placeholder.png +0 -0
  128. package/template/dev-assets/images/logo-placeholder.png +0 -0
  129. package/template/dev-assets/images/product-placeholder.jpg +0 -0
  130. package/template/dev-assets/images/thumbnail-placeholder.jpg +0 -0
  131. package/template/env.example +51 -0
  132. package/template/gitignore +53 -0
  133. package/template/index.html +22 -0
  134. package/template/main.js +28 -0
  135. package/template/src/DemoPage.vue +459 -0
  136. package/template/src/Plugin.vue +38 -0
  137. package/template/src/stores/index.js +9 -0
  138. package/template/src/stores/test-data.json +173 -0
  139. package/template/theme-layouts/AdditionalStyling.css +0 -0
  140. package/template/theme-layouts/PrivateLayout.vue +39 -0
  141. package/template/theme-layouts/PublicLayout.vue +39 -0
  142. package/template/theme-layouts/SystemLayout.vue +39 -0
  143. package/template/vite.config.js +333 -0
  144. package/tsconfig.tui.json +21 -0
  145. package/vite.config.js +164 -0
@@ -0,0 +1,328 @@
1
+ /**
2
+ * Dev Command
3
+ *
4
+ * Starts the development server with optional Socket.IO support
5
+ * and browser extension launching.
6
+ */
7
+
8
+ const path = require("path");
9
+ const fs = require("fs");
10
+ const shell = require("shelljs");
11
+ const dotenv = require("dotenv");
12
+ const { exportCmd } = require("../constants");
13
+ const {
14
+ findProjectRoot,
15
+ resolveGxPaths,
16
+ resolveFilePath,
17
+ findExistingCertificates,
18
+ } = require("../utils");
19
+
20
+ /**
21
+ * Get browser extension paths and commands
22
+ * @param {string} browser - "firefox" or "chrome"
23
+ * @param {string} projectPath - Project root path
24
+ * @param {Object} paths - Resolved GxP paths
25
+ * @param {Object} options - Additional options
26
+ * @param {boolean} options.useHttps - Whether HTTPS is enabled
27
+ * @param {number|string} options.port - Dev server port
28
+ */
29
+ function getBrowserExtensionConfig(browser, projectPath, paths, options = {}) {
30
+ const { useHttps = true, port = 3060 } = options;
31
+ const protocol = useHttps ? "https" : "http";
32
+ const startUrl = `${protocol}://localhost:${port}`;
33
+
34
+ if (browser === "firefox") {
35
+ let extensionPath = path.join(projectPath, "browser-extensions", "firefox");
36
+
37
+ if (!fs.existsSync(extensionPath)) {
38
+ const toolkitExtensionPath = path.join(
39
+ paths.packageRoot,
40
+ "browser-extensions",
41
+ "firefox"
42
+ );
43
+ if (fs.existsSync(toolkitExtensionPath)) {
44
+ extensionPath = toolkitExtensionPath;
45
+ } else {
46
+ return null;
47
+ }
48
+ }
49
+
50
+ return {
51
+ name: "FIREFOX",
52
+ color: "yellow",
53
+ command: `npx web-ext run --source-dir "${extensionPath}" --start-url "${startUrl}"`,
54
+ extensionPath,
55
+ startUrl,
56
+ };
57
+ }
58
+
59
+ if (browser === "chrome") {
60
+ let extensionPath = path.join(projectPath, "browser-extensions", "chrome");
61
+ let scriptPath = path.join(projectPath, "scripts", "launch-chrome.js");
62
+
63
+ if (!fs.existsSync(extensionPath)) {
64
+ const toolkitExtensionPath = path.join(
65
+ paths.packageRoot,
66
+ "browser-extensions",
67
+ "chrome"
68
+ );
69
+ if (fs.existsSync(toolkitExtensionPath)) {
70
+ extensionPath = toolkitExtensionPath;
71
+ scriptPath = path.join(
72
+ paths.packageRoot,
73
+ "scripts",
74
+ "launch-chrome.js"
75
+ );
76
+ } else {
77
+ return null;
78
+ }
79
+ }
80
+
81
+ if (!fs.existsSync(scriptPath)) {
82
+ return null;
83
+ }
84
+
85
+ return {
86
+ name: "CHROME",
87
+ color: "blue",
88
+ command: `CHROME_EXTENSION_PATH="${extensionPath}" USE_HTTPS="${useHttps}" NODE_PORT="${port}" node "${scriptPath}"`,
89
+ extensionPath,
90
+ startUrl,
91
+ };
92
+ }
93
+
94
+ return null;
95
+ }
96
+
97
+ /**
98
+ * Development command - starts the dev server
99
+ */
100
+ function devCommand(argv) {
101
+ const paths = resolveGxPaths();
102
+ const projectPath = findProjectRoot();
103
+
104
+ // Load .env file if it exists for default values
105
+ const envPath = path.join(projectPath, ".env");
106
+ const envExamplePath = path.join(projectPath, ".env.example");
107
+
108
+ // Load .env file into process.env
109
+ if (fs.existsSync(envPath)) {
110
+ console.log("📋 Loading environment variables from .env file");
111
+ dotenv.config({ path: envPath });
112
+ } else if (fs.existsSync(envExamplePath)) {
113
+ console.log(
114
+ "💡 Tip: Create .env file from .env.example to customize your environment settings"
115
+ );
116
+ console.log(" cp .env.example .env");
117
+ }
118
+
119
+ // Check for SSL certificates unless explicitly disabled
120
+ let useHttps = !argv["no-https"];
121
+ let certPath = "";
122
+ let keyPath = "";
123
+
124
+ if (useHttps) {
125
+ const certsDir = path.join(projectPath, ".certs");
126
+ const existingCerts = findExistingCertificates(certsDir);
127
+
128
+ if (!existingCerts) {
129
+ console.log(
130
+ "⚠ SSL certificates not found. Run 'npm run setup-ssl' to enable HTTPS"
131
+ );
132
+ console.log("🌐 Starting HTTP development server...");
133
+ useHttps = false;
134
+ } else {
135
+ console.log("🔒 Starting HTTPS development server...");
136
+ console.log(
137
+ `📁 Using certificate: ${path.basename(existingCerts.certPath)}`
138
+ );
139
+ console.log(`🔑 Using key: ${path.basename(existingCerts.keyPath)}`);
140
+ certPath = existingCerts.certPath;
141
+ keyPath = existingCerts.keyPath;
142
+ }
143
+ } else {
144
+ console.log("🌐 Starting HTTP development server...");
145
+ }
146
+
147
+ // Determine final port value (priority: CLI arg > .env > default)
148
+ const finalPort = argv.port || process.env.NODE_PORT || 3000;
149
+ console.log(`🌐 Development server will start on port: ${finalPort}`);
150
+
151
+ // Check if mock API should be enabled
152
+ const withMock = argv["with-mock"];
153
+ if (withMock) {
154
+ console.log("🎭 Mock API will be enabled");
155
+ }
156
+
157
+ // Check if socket server should be started
158
+ const withSocket = argv["with-socket"];
159
+ let serverJsPath = "";
160
+ if (withSocket) {
161
+ // Check for local server.js first, then runtime directory
162
+ const serverJs = resolveFilePath("server.js", "", "runtime");
163
+ if (!fs.existsSync(serverJs.path)) {
164
+ console.error("❌ server.js not found. Cannot start Socket.IO server.");
165
+ console.log(
166
+ "💡 Run 'gxdev publish server.js' to create a local copy, or ensure you're in a GxP project directory"
167
+ );
168
+ process.exit(1);
169
+ }
170
+ serverJsPath = serverJs.path;
171
+ console.log(
172
+ `📡 Starting Socket.IO server with nodemon... (${
173
+ serverJs.isLocal ? "local" : "package"
174
+ } version)`
175
+ );
176
+ console.log(`📁 Using: ${serverJsPath}`);
177
+ }
178
+
179
+ // Check for local dev files, otherwise use runtime versions
180
+ // These files can be published for customization: gxdev publish vite.config.js
181
+ let viteConfigPath = paths.viteConfigPath;
182
+ const localViteConfigPath = path.join(projectPath, "vite.config.js");
183
+ const localIndexHtml = path.join(projectPath, "index.html");
184
+ const localMainJs = path.join(projectPath, "main.js");
185
+
186
+ const hasLocalViteConfig = fs.existsSync(localViteConfigPath);
187
+ const hasLocalIndexHtml = fs.existsSync(localIndexHtml);
188
+ const hasLocalMainJs = fs.existsSync(localMainJs);
189
+
190
+ if (hasLocalViteConfig) {
191
+ viteConfigPath = localViteConfigPath;
192
+ console.log("📁 Using local vite.config.js");
193
+ }
194
+ if (hasLocalIndexHtml) {
195
+ console.log("📁 Using local index.html");
196
+ }
197
+ if (hasLocalMainJs) {
198
+ console.log("📁 Using local main.js");
199
+ }
200
+
201
+ // Log if using all runtime files (default)
202
+ if (!hasLocalViteConfig && !hasLocalIndexHtml && !hasLocalMainJs) {
203
+ console.log("📦 Using runtime dev files (publish to customize)");
204
+ }
205
+
206
+ // Only set environment variables if they're not already set (allows .env to take precedence)
207
+ const envVars = [];
208
+
209
+ // Set variables only if not already defined in environment
210
+ if (!process.env.NODE_LOG_LEVEL) {
211
+ envVars.push(
212
+ `${exportCmd} NODE_LOG_LEVEL=${argv["node-log-level"] || "info"}`
213
+ );
214
+ }
215
+ if (!process.env.NODE_PORT) {
216
+ envVars.push(`${exportCmd} NODE_PORT=${finalPort}`);
217
+ }
218
+ if (!process.env.COMPONENT_PATH) {
219
+ envVars.push(
220
+ `${exportCmd} COMPONENT_PATH=${
221
+ argv["component-path"] || "./src/Plugin.vue"
222
+ }`
223
+ );
224
+ }
225
+
226
+ // Always set HTTPS-related variables (these are dynamic)
227
+ envVars.push(`${exportCmd} USE_HTTPS=${useHttps ? "true" : "false"}`);
228
+ envVars.push(`${exportCmd} CERT_PATH=${certPath}`);
229
+ envVars.push(`${exportCmd} KEY_PATH=${keyPath}`);
230
+
231
+ // Set mock API flag if requested
232
+ if (withMock) {
233
+ envVars.push(`${exportCmd} MOCK_API_ENABLED=true`);
234
+ }
235
+
236
+ // Check for browser extension flags
237
+ const launchFirefox = argv.firefox;
238
+ const launchChrome = argv.chrome;
239
+
240
+ // Get browser extension configurations
241
+ let firefoxConfig = null;
242
+ let chromeConfig = null;
243
+
244
+ if (launchFirefox) {
245
+ firefoxConfig = getBrowserExtensionConfig("firefox", projectPath, paths, {
246
+ useHttps,
247
+ port: finalPort,
248
+ });
249
+ if (firefoxConfig) {
250
+ console.log("🦊 Firefox extension will launch with dev server");
251
+ console.log(`📁 Extension path: ${firefoxConfig.extensionPath}`);
252
+ console.log(`🌐 Start URL: ${firefoxConfig.startUrl}`);
253
+ } else {
254
+ console.warn("⚠️ Firefox extension not found, skipping");
255
+ }
256
+ }
257
+
258
+ if (launchChrome) {
259
+ chromeConfig = getBrowserExtensionConfig("chrome", projectPath, paths, {
260
+ useHttps,
261
+ port: finalPort,
262
+ });
263
+ if (chromeConfig) {
264
+ console.log("🚀 Chrome extension will launch with dev server");
265
+ console.log(`📁 Extension path: ${chromeConfig.extensionPath}`);
266
+ console.log(`🌐 Start URL: ${chromeConfig.startUrl}`);
267
+ } else {
268
+ console.warn("⚠️ Chrome extension not found, skipping");
269
+ }
270
+ }
271
+
272
+ // Build the command based on what's requested
273
+ let command;
274
+
275
+ // Collect all processes to run
276
+ const processes = [];
277
+ const names = [];
278
+ const colors = [];
279
+
280
+ // Vite is always included
281
+ const viteCommand = [
282
+ ...envVars,
283
+ `npx vite dev --config "${viteConfigPath}"`,
284
+ ].join(" && ");
285
+ processes.push(`"${viteCommand}"`);
286
+ names.push("VITE");
287
+ colors.push("cyan");
288
+
289
+ // Socket server (optional)
290
+ if (withSocket && serverJsPath) {
291
+ processes.push(`"npx nodemon \\"${serverJsPath}\\""`);
292
+ names.push("SOCKET");
293
+ colors.push("green");
294
+ }
295
+
296
+ // Firefox extension (optional)
297
+ if (firefoxConfig) {
298
+ processes.push(`"${firefoxConfig.command}"`);
299
+ names.push(firefoxConfig.name);
300
+ colors.push(firefoxConfig.color);
301
+ }
302
+
303
+ // Chrome extension (optional)
304
+ if (chromeConfig) {
305
+ processes.push(`"${chromeConfig.command}"`);
306
+ names.push(chromeConfig.name);
307
+ colors.push(chromeConfig.color);
308
+ }
309
+
310
+ // Build the final command
311
+ if (processes.length > 1) {
312
+ // Use concurrently to run multiple processes
313
+ command = `npx concurrently --names "${names.join(
314
+ ","
315
+ )}" --prefix-colors "${colors.join(",")}" ${processes.join(" ")}`;
316
+ } else {
317
+ // Just run Vite dev server alone
318
+ command = [...envVars, `npx vite dev --config "${viteConfigPath}"`].join(
319
+ " && "
320
+ );
321
+ }
322
+
323
+ shell.exec(command);
324
+ }
325
+
326
+ module.exports = {
327
+ devCommand,
328
+ };
@@ -0,0 +1,298 @@
1
+ /**
2
+ * Extensions Command
3
+ *
4
+ * Manages browser extensions for Firefox and Chrome.
5
+ */
6
+
7
+ const path = require("path");
8
+ const fs = require("fs");
9
+ const shell = require("shelljs");
10
+ const { findProjectRoot, resolveGxPaths } = require("../utils");
11
+
12
+ /**
13
+ * Launch Firefox with extension command
14
+ */
15
+ function extensionFirefoxCommand() {
16
+ const projectPath = findProjectRoot();
17
+ let extensionPath = path.join(projectPath, "browser-extensions", "firefox");
18
+
19
+ // If local extension doesn't exist, try to use the toolkit's own extensions
20
+ if (!fs.existsSync(extensionPath)) {
21
+ const paths = resolveGxPaths();
22
+ const toolkitExtensionPath = path.join(
23
+ paths.packageRoot,
24
+ "browser-extensions",
25
+ "firefox"
26
+ );
27
+
28
+ if (fs.existsSync(toolkitExtensionPath)) {
29
+ console.log("🔍 Using GxToolkit's built-in Firefox extension");
30
+ extensionPath = toolkitExtensionPath;
31
+ } else {
32
+ console.error("❌ Firefox extension directory not found");
33
+ console.log(
34
+ "📁 Looking for extensions in:",
35
+ path.join(projectPath, "browser-extensions", "firefox")
36
+ );
37
+ console.log(
38
+ "💡 Run 'gxdev init' to create a project with browser extensions"
39
+ );
40
+ process.exit(1);
41
+ }
42
+ } else {
43
+ console.log("🔍 Using project's Firefox extension");
44
+ }
45
+
46
+ console.log("🦊 Launching Firefox with extension...");
47
+ console.log("📁 Extension path:", extensionPath);
48
+ shell.exec(`npx web-ext run --source-dir "${extensionPath}"`);
49
+ }
50
+
51
+ /**
52
+ * Launch Chrome with extension command
53
+ */
54
+ function extensionChromeCommand() {
55
+ const projectPath = findProjectRoot();
56
+ let extensionPath = path.join(projectPath, "browser-extensions", "chrome");
57
+ let scriptPath = path.join(projectPath, "scripts", "launch-chrome.js");
58
+
59
+ // Check if we have a local extension first
60
+ if (!fs.existsSync(extensionPath)) {
61
+ const paths = resolveGxPaths();
62
+ const toolkitExtensionPath = path.join(
63
+ paths.packageRoot,
64
+ "browser-extensions",
65
+ "chrome"
66
+ );
67
+
68
+ if (fs.existsSync(toolkitExtensionPath)) {
69
+ console.log("🔍 Using GxToolkit's built-in Chrome extension");
70
+ extensionPath = toolkitExtensionPath;
71
+ // Use the toolkit's script instead
72
+ scriptPath = path.join(paths.packageRoot, "scripts", "launch-chrome.js");
73
+ } else {
74
+ console.error("❌ Chrome extension directory not found");
75
+ console.log(
76
+ "📁 Looking for extensions in:",
77
+ path.join(projectPath, "browser-extensions", "chrome")
78
+ );
79
+ console.log(
80
+ "💡 Run 'gxdev init' to create a project with browser extensions"
81
+ );
82
+ process.exit(1);
83
+ }
84
+ } else {
85
+ console.log("🔍 Using project's Chrome extension");
86
+ }
87
+
88
+ // Verify script exists
89
+ if (!fs.existsSync(scriptPath)) {
90
+ console.error(
91
+ "❌ Chrome launcher script not found. Run 'gxdev init' to create it."
92
+ );
93
+ process.exit(1);
94
+ }
95
+
96
+ console.log("🚀 Launching Chrome with extension...");
97
+ console.log("📁 Extension path:", extensionPath);
98
+
99
+ // Set the extension path as an environment variable for the script
100
+ process.env.CHROME_EXTENSION_PATH = extensionPath;
101
+ shell.exec(`node "${scriptPath}"`);
102
+ }
103
+
104
+ /**
105
+ * Install extension permanently in local browser
106
+ */
107
+ function extensionInstallCommand(argv) {
108
+ const browser = argv.browser;
109
+ const paths = resolveGxPaths();
110
+
111
+ if (!browser || !["chrome", "firefox"].includes(browser)) {
112
+ console.log("Usage: gxdev ext:install <chrome|firefox>");
113
+ console.log("");
114
+ console.log("This command helps you permanently install the extension");
115
+ console.log("in your local browser for development.");
116
+ process.exit(1);
117
+ }
118
+
119
+ const extensionPath = path.join(
120
+ paths.packageRoot,
121
+ "browser-extensions",
122
+ browser
123
+ );
124
+
125
+ if (!fs.existsSync(extensionPath)) {
126
+ console.error(
127
+ `❌ ${browser} extension directory not found at:`,
128
+ extensionPath
129
+ );
130
+ process.exit(1);
131
+ }
132
+
133
+ console.log("");
134
+ console.log(`📦 Extension path: ${extensionPath}`);
135
+ console.log("");
136
+
137
+ if (browser === "chrome") {
138
+ console.log("🚀 Chrome Permanent Installation Instructions:");
139
+ console.log("─".repeat(50));
140
+ console.log("");
141
+ console.log("1. Open Chrome and navigate to:");
142
+ console.log(" chrome://extensions/");
143
+ console.log("");
144
+ console.log('2. Enable "Developer mode" (toggle in top right corner)');
145
+ console.log("");
146
+ console.log('3. Click "Load unpacked" button');
147
+ console.log("");
148
+ console.log("4. Select this directory:");
149
+ console.log(` ${extensionPath}`);
150
+ console.log("");
151
+ console.log("─".repeat(50));
152
+ console.log("✅ The extension will persist across browser restarts.");
153
+ console.log("🔄 After code changes, click the refresh icon on the");
154
+ console.log(" extension card in chrome://extensions/ to reload.");
155
+ console.log("");
156
+
157
+ // Try to open Chrome to the extensions page
158
+ const openCommand =
159
+ process.platform === "darwin"
160
+ ? 'open -a "Google Chrome" "chrome://extensions/"'
161
+ : process.platform === "win32"
162
+ ? 'start chrome "chrome://extensions/"'
163
+ : 'google-chrome "chrome://extensions/"';
164
+
165
+ console.log("🌐 Attempting to open Chrome extensions page...");
166
+ shell.exec(openCommand, { silent: true });
167
+ } else if (browser === "firefox") {
168
+ console.log("🦊 Firefox Installation Instructions:");
169
+ console.log("─".repeat(50));
170
+ console.log("");
171
+ console.log("Option 1: Temporary Add-on (easiest, but doesn't persist)");
172
+ console.log("─".repeat(50));
173
+ console.log("1. Open Firefox and navigate to:");
174
+ console.log(" about:debugging#/runtime/this-firefox");
175
+ console.log("");
176
+ console.log('2. Click "Load Temporary Add-on..."');
177
+ console.log("");
178
+ console.log("3. Select any file in this directory:");
179
+ console.log(` ${extensionPath}`);
180
+ console.log("");
181
+ console.log("⚠️ Note: Temporary add-ons are removed when Firefox closes.");
182
+ console.log("");
183
+ console.log("─".repeat(50));
184
+ console.log(
185
+ "Option 2: Persistent Installation (Firefox Developer/Nightly)"
186
+ );
187
+ console.log("─".repeat(50));
188
+ console.log("1. Use Firefox Developer Edition or Firefox Nightly");
189
+ console.log("");
190
+ console.log("2. Go to about:config and set:");
191
+ console.log(" xpinstall.signatures.required = false");
192
+ console.log("");
193
+ console.log("3. Then go to about:addons");
194
+ console.log("");
195
+ console.log("4. Click the gear icon and select:");
196
+ console.log(' "Install Add-on From File..."');
197
+ console.log("");
198
+ console.log("5. Select the manifest.json in:");
199
+ console.log(` ${extensionPath}`);
200
+ console.log("");
201
+
202
+ // Try to open Firefox to the debugging page
203
+ const openCommand =
204
+ process.platform === "darwin"
205
+ ? 'open -a "Firefox" "about:debugging#/runtime/this-firefox"'
206
+ : process.platform === "win32"
207
+ ? 'start firefox "about:debugging#/runtime/this-firefox"'
208
+ : 'firefox "about:debugging#/runtime/this-firefox"';
209
+
210
+ console.log("🌐 Attempting to open Firefox debugging page...");
211
+ shell.exec(openCommand, { silent: true });
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Build extensions command
217
+ */
218
+ function extensionBuildCommand() {
219
+ const projectPath = findProjectRoot();
220
+ const paths = resolveGxPaths();
221
+
222
+ console.log("📦 Building browser extensions...");
223
+
224
+ // Build Firefox extension
225
+ let firefoxPath = path.join(projectPath, "browser-extensions", "firefox");
226
+ let useProjectExtensions = true;
227
+
228
+ if (!fs.existsSync(firefoxPath)) {
229
+ // Try toolkit's extensions
230
+ const toolkitFirefoxPath = path.join(
231
+ paths.packageRoot,
232
+ "browser-extensions",
233
+ "firefox"
234
+ );
235
+ if (fs.existsSync(toolkitFirefoxPath)) {
236
+ firefoxPath = toolkitFirefoxPath;
237
+ useProjectExtensions = false;
238
+ console.log("🔍 Using GxToolkit's built-in Firefox extension");
239
+ }
240
+ }
241
+
242
+ if (fs.existsSync(firefoxPath)) {
243
+ console.log("🦊 Building Firefox extension...");
244
+ const outputDir = useProjectExtensions
245
+ ? "dist/firefox"
246
+ : path.join(projectPath, "dist/firefox");
247
+ shell.exec(
248
+ `npx web-ext build --source-dir "${firefoxPath}" --artifacts-dir "${outputDir}"`
249
+ );
250
+ } else {
251
+ console.log("⚠️ No Firefox extension found to build");
252
+ }
253
+
254
+ // Build Chrome extension
255
+ let chromeScriptPath = path.join(projectPath, "scripts", "pack-chrome.js");
256
+ let chromeExtensionPath = path.join(
257
+ projectPath,
258
+ "browser-extensions",
259
+ "chrome"
260
+ );
261
+
262
+ if (!fs.existsSync(chromeScriptPath) || !fs.existsSync(chromeExtensionPath)) {
263
+ // Try toolkit's scripts and extensions
264
+ const toolkitScriptPath = path.join(
265
+ paths.packageRoot,
266
+ "scripts",
267
+ "pack-chrome.js"
268
+ );
269
+ const toolkitChromePath = path.join(
270
+ paths.packageRoot,
271
+ "browser-extensions",
272
+ "chrome"
273
+ );
274
+
275
+ if (fs.existsSync(toolkitScriptPath) && fs.existsSync(toolkitChromePath)) {
276
+ chromeScriptPath = toolkitScriptPath;
277
+ chromeExtensionPath = toolkitChromePath;
278
+ console.log("🔍 Using GxToolkit's built-in Chrome extension");
279
+ }
280
+ }
281
+
282
+ if (fs.existsSync(chromeScriptPath)) {
283
+ console.log("🚀 Building Chrome extension...");
284
+ // Set environment variable for the script to know where the extension is
285
+ process.env.CHROME_EXTENSION_PATH = chromeExtensionPath;
286
+ process.env.CHROME_BUILD_OUTPUT = path.join(projectPath, "dist/chrome");
287
+ shell.exec(`node "${chromeScriptPath}"`);
288
+ } else {
289
+ console.log("⚠️ No Chrome extension found to build");
290
+ }
291
+ }
292
+
293
+ module.exports = {
294
+ extensionFirefoxCommand,
295
+ extensionChromeCommand,
296
+ extensionBuildCommand,
297
+ extensionInstallCommand,
298
+ };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Commands Index
3
+ *
4
+ * Re-exports all command modules for convenient importing.
5
+ */
6
+
7
+ const { initCommand } = require("./init");
8
+ const { devCommand } = require("./dev");
9
+ const { buildCommand } = require("./build");
10
+ const { publishCommand } = require("./publish");
11
+ const { setupSSLCommand } = require("./ssl");
12
+ const { datastoreCommand } = require("./datastore");
13
+ const { socketCommand } = require("./socket");
14
+ const { assetsCommand } = require("./assets");
15
+ const {
16
+ extensionFirefoxCommand,
17
+ extensionChromeCommand,
18
+ extensionBuildCommand,
19
+ extensionInstallCommand,
20
+ } = require("./extensions");
21
+
22
+ module.exports = {
23
+ initCommand,
24
+ devCommand,
25
+ buildCommand,
26
+ publishCommand,
27
+ setupSSLCommand,
28
+ datastoreCommand,
29
+ socketCommand,
30
+ assetsCommand,
31
+ extensionFirefoxCommand,
32
+ extensionChromeCommand,
33
+ extensionBuildCommand,
34
+ extensionInstallCommand,
35
+ };