@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.
- package/.github/workflows/npm-publish.yml +48 -0
- package/CLAUDE.md +400 -0
- package/README.md +247 -0
- package/REFACTOR_PLAN.md +194 -0
- package/bin/gx-devtools.js +87 -0
- package/bin/lib/cli.js +251 -0
- package/bin/lib/commands/assets.js +337 -0
- package/bin/lib/commands/build.js +259 -0
- package/bin/lib/commands/datastore.js +433 -0
- package/bin/lib/commands/dev.js +328 -0
- package/bin/lib/commands/extensions.js +298 -0
- package/bin/lib/commands/index.js +35 -0
- package/bin/lib/commands/init.js +307 -0
- package/bin/lib/commands/publish.js +189 -0
- package/bin/lib/commands/socket.js +158 -0
- package/bin/lib/commands/ssl.js +47 -0
- package/bin/lib/constants.js +120 -0
- package/bin/lib/tui/App.tsx +600 -0
- package/bin/lib/tui/components/CommandInput.tsx +278 -0
- package/bin/lib/tui/components/GeminiPanel.tsx +161 -0
- package/bin/lib/tui/components/Header.tsx +27 -0
- package/bin/lib/tui/components/LogPanel.tsx +122 -0
- package/bin/lib/tui/components/TabBar.tsx +56 -0
- package/bin/lib/tui/components/WelcomeScreen.tsx +80 -0
- package/bin/lib/tui/index.tsx +63 -0
- package/bin/lib/tui/services/ExtensionService.ts +122 -0
- package/bin/lib/tui/services/GeminiService.ts +395 -0
- package/bin/lib/tui/services/ServiceManager.ts +336 -0
- package/bin/lib/tui/services/SocketService.ts +204 -0
- package/bin/lib/tui/services/ViteService.ts +107 -0
- package/bin/lib/tui/services/index.ts +13 -0
- package/bin/lib/utils/files.js +180 -0
- package/bin/lib/utils/index.js +17 -0
- package/bin/lib/utils/paths.js +138 -0
- package/bin/lib/utils/prompts.js +71 -0
- package/bin/lib/utils/ssl.js +233 -0
- package/browser-extensions/README.md +1 -0
- package/browser-extensions/chrome/background.js +857 -0
- package/browser-extensions/chrome/content.js +51 -0
- package/browser-extensions/chrome/devtools.html +9 -0
- package/browser-extensions/chrome/devtools.js +23 -0
- package/browser-extensions/chrome/icons/gx_off_128.png +0 -0
- package/browser-extensions/chrome/icons/gx_off_16.png +0 -0
- package/browser-extensions/chrome/icons/gx_off_32.png +0 -0
- package/browser-extensions/chrome/icons/gx_off_64.png +0 -0
- package/browser-extensions/chrome/icons/gx_on_128.png +0 -0
- package/browser-extensions/chrome/icons/gx_on_16.png +0 -0
- package/browser-extensions/chrome/icons/gx_on_32.png +0 -0
- package/browser-extensions/chrome/icons/gx_on_64.png +0 -0
- package/browser-extensions/chrome/inspector.js +1087 -0
- package/browser-extensions/chrome/manifest.json +70 -0
- package/browser-extensions/chrome/panel.html +638 -0
- package/browser-extensions/chrome/panel.js +862 -0
- package/browser-extensions/chrome/popup.html +399 -0
- package/browser-extensions/chrome/popup.js +515 -0
- package/browser-extensions/chrome/rules.json +1 -0
- package/browser-extensions/chrome/test-chrome.html +145 -0
- package/browser-extensions/chrome/test-mixed-content.html +190 -0
- package/browser-extensions/chrome/test-uri-pattern.html +199 -0
- package/browser-extensions/firefox/README.md +134 -0
- package/browser-extensions/firefox/background.js +804 -0
- package/browser-extensions/firefox/content.js +120 -0
- package/browser-extensions/firefox/debug-errors.html +229 -0
- package/browser-extensions/firefox/debug-https.html +113 -0
- package/browser-extensions/firefox/devtools.html +9 -0
- package/browser-extensions/firefox/devtools.js +24 -0
- package/browser-extensions/firefox/icons/gx_off_128.png +0 -0
- package/browser-extensions/firefox/icons/gx_off_16.png +0 -0
- package/browser-extensions/firefox/icons/gx_off_32.png +0 -0
- package/browser-extensions/firefox/icons/gx_off_64.png +0 -0
- package/browser-extensions/firefox/icons/gx_on_128.png +0 -0
- package/browser-extensions/firefox/icons/gx_on_16.png +0 -0
- package/browser-extensions/firefox/icons/gx_on_32.png +0 -0
- package/browser-extensions/firefox/icons/gx_on_64.png +0 -0
- package/browser-extensions/firefox/inspector.js +1087 -0
- package/browser-extensions/firefox/manifest.json +67 -0
- package/browser-extensions/firefox/panel.html +638 -0
- package/browser-extensions/firefox/panel.js +862 -0
- package/browser-extensions/firefox/popup.html +525 -0
- package/browser-extensions/firefox/popup.js +536 -0
- package/browser-extensions/firefox/test-gramercy.html +126 -0
- package/browser-extensions/firefox/test-imports.html +58 -0
- package/browser-extensions/firefox/test-masking.html +147 -0
- package/browser-extensions/firefox/test-uri-pattern.html +199 -0
- package/docs/DOCUSAURUS_IMPORT.md +378 -0
- package/docs/_category_.json +8 -0
- package/docs/app-manifest.md +272 -0
- package/docs/building-for-platform.md +315 -0
- package/docs/dev-tools.md +291 -0
- package/docs/getting-started.md +180 -0
- package/docs/gxp-store.md +305 -0
- package/docs/index.md +44 -0
- package/package.json +77 -0
- package/runtime/PortalContainer.vue +326 -0
- package/runtime/dev-tools/DevToolsModal.vue +217 -0
- package/runtime/dev-tools/LayoutSwitcher.vue +221 -0
- package/runtime/dev-tools/MockDataEditor.vue +621 -0
- package/runtime/dev-tools/SocketSimulator.vue +562 -0
- package/runtime/dev-tools/StoreInspector.vue +644 -0
- package/runtime/dev-tools/index.js +6 -0
- package/runtime/gxpStringsPlugin.js +428 -0
- package/runtime/index.html +22 -0
- package/runtime/main.js +32 -0
- package/runtime/mock-api/auth-middleware.js +97 -0
- package/runtime/mock-api/image-generator.js +221 -0
- package/runtime/mock-api/index.js +197 -0
- package/runtime/mock-api/response-generator.js +394 -0
- package/runtime/mock-api/route-generator.js +323 -0
- package/runtime/mock-api/socket-triggers.js +371 -0
- package/runtime/mock-api/spec-loader.js +300 -0
- package/runtime/server.js +180 -0
- package/runtime/stores/gxpPortalConfigStore.js +554 -0
- package/runtime/stores/index.js +6 -0
- package/runtime/vite-inspector-plugin.js +749 -0
- package/runtime/vite-source-tracker-plugin.js +232 -0
- package/runtime/vite.config.js +402 -0
- package/scripts/launch-chrome.js +90 -0
- package/scripts/pack-chrome.js +91 -0
- package/socket-events/AiSessionMessageCreated.json +18 -0
- package/socket-events/SocialStreamPostCreated.json +24 -0
- package/socket-events/SocialStreamPostVariantCompleted.json +23 -0
- package/template/README.md +332 -0
- package/template/app-manifest.json +32 -0
- package/template/dev-assets/images/avatar-placeholder.png +0 -0
- package/template/dev-assets/images/background-placeholder.jpg +0 -0
- package/template/dev-assets/images/banner-placeholder.jpg +0 -0
- package/template/dev-assets/images/icon-placeholder.png +0 -0
- package/template/dev-assets/images/logo-placeholder.png +0 -0
- package/template/dev-assets/images/product-placeholder.jpg +0 -0
- package/template/dev-assets/images/thumbnail-placeholder.jpg +0 -0
- package/template/env.example +51 -0
- package/template/gitignore +53 -0
- package/template/index.html +22 -0
- package/template/main.js +28 -0
- package/template/src/DemoPage.vue +459 -0
- package/template/src/Plugin.vue +38 -0
- package/template/src/stores/index.js +9 -0
- package/template/src/stores/test-data.json +173 -0
- package/template/theme-layouts/AdditionalStyling.css +0 -0
- package/template/theme-layouts/PrivateLayout.vue +39 -0
- package/template/theme-layouts/PublicLayout.vue +39 -0
- package/template/theme-layouts/SystemLayout.vue +39 -0
- package/template/vite.config.js +333 -0
- package/tsconfig.tui.json +21 -0
- package/vite.config.js +164 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assets Command
|
|
3
|
+
*
|
|
4
|
+
* Manages development assets and placeholder image generation.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const path = require("path");
|
|
8
|
+
const fs = require("fs");
|
|
9
|
+
const shell = require("shelljs");
|
|
10
|
+
const {
|
|
11
|
+
findProjectRoot,
|
|
12
|
+
resolveGxPaths,
|
|
13
|
+
safeCopyFile,
|
|
14
|
+
isImageMagickInstalled,
|
|
15
|
+
ensureImageMagickInstalled,
|
|
16
|
+
} = require("../utils");
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Assets management command - manages development assets and placeholder generation
|
|
20
|
+
*/
|
|
21
|
+
async function assetsCommand(argv) {
|
|
22
|
+
const action = argv.action;
|
|
23
|
+
|
|
24
|
+
if (action === "list") {
|
|
25
|
+
listDevelopmentAssets(argv);
|
|
26
|
+
} else if (action === "generate") {
|
|
27
|
+
await generatePlaceholderImage(argv);
|
|
28
|
+
} else if (action === "init") {
|
|
29
|
+
await initDevelopmentAssets();
|
|
30
|
+
} else {
|
|
31
|
+
console.error(
|
|
32
|
+
"❌ Invalid assets action. Use 'list', 'generate', or 'init'"
|
|
33
|
+
);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function listDevelopmentAssets(argv) {
|
|
39
|
+
const projectPath = findProjectRoot();
|
|
40
|
+
const devAssetsDir = path.join(projectPath, "dev-assets");
|
|
41
|
+
|
|
42
|
+
if (!fs.existsSync(devAssetsDir)) {
|
|
43
|
+
console.log("❌ No dev-assets directory found");
|
|
44
|
+
console.log("💡 Run 'gxdev assets init' to set up development assets");
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const finalPort = argv.port || process.env.NODE_PORT || 3000;
|
|
48
|
+
|
|
49
|
+
console.log("📁 Development Assets:");
|
|
50
|
+
console.log("");
|
|
51
|
+
|
|
52
|
+
const dirs = ["images", "videos"];
|
|
53
|
+
dirs.forEach((dir) => {
|
|
54
|
+
const dirPath = path.join(devAssetsDir, dir);
|
|
55
|
+
if (fs.existsSync(dirPath)) {
|
|
56
|
+
const files = fs.readdirSync(dirPath);
|
|
57
|
+
if (files.length > 0) {
|
|
58
|
+
console.log(`📸 ${dir}/`);
|
|
59
|
+
files.forEach((file) => {
|
|
60
|
+
const stats = fs.statSync(path.join(dirPath, file));
|
|
61
|
+
const size = (stats.size / 1024).toFixed(1);
|
|
62
|
+
console.log(` • ${file} (${size} KB)`);
|
|
63
|
+
console.log(
|
|
64
|
+
` URL: https://localhost:${finalPort}/dev-assets/${dir}/${file}`
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
console.log("");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
console.log("💡 Usage:");
|
|
73
|
+
console.log(" Add assets to your store:");
|
|
74
|
+
console.log(
|
|
75
|
+
` gxpStore.updateAsset("my_image", "https://localhost:${finalPort}/dev-assets/images/my-image.jpg")`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function generatePlaceholderImage(argv) {
|
|
80
|
+
if (!ensureImageMagickInstalled()) {
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const projectPath = findProjectRoot();
|
|
85
|
+
const size = argv.size || "400x300";
|
|
86
|
+
const name = argv.name || "placeholder";
|
|
87
|
+
const format = argv.format || "png";
|
|
88
|
+
const count = Math.max(1, argv.count || 1);
|
|
89
|
+
|
|
90
|
+
const devAssetsDir = path.join(projectPath, "dev-assets", "images");
|
|
91
|
+
if (!fs.existsSync(devAssetsDir)) {
|
|
92
|
+
fs.mkdirSync(devAssetsDir, { recursive: true });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Use magick command (ImageMagick 7) or convert (ImageMagick 6)
|
|
96
|
+
const magickCmd = shell.which("magick") ? "magick" : "convert";
|
|
97
|
+
const finalPort = argv.port || process.env.NODE_PORT || 3000;
|
|
98
|
+
|
|
99
|
+
const generatedAssets = [];
|
|
100
|
+
|
|
101
|
+
console.log(`🎨 Generating ${count} placeholder${count > 1 ? "s" : ""}...`);
|
|
102
|
+
console.log(`📐 Size: ${size}`);
|
|
103
|
+
|
|
104
|
+
for (let i = 0; i < count; i++) {
|
|
105
|
+
const color = argv.color || getRandomColor();
|
|
106
|
+
const style = getRandomStyle();
|
|
107
|
+
const suffix = count > 1 ? `-${i + 1}` : "";
|
|
108
|
+
const filename = `${name}${suffix}.${format}`;
|
|
109
|
+
const text =
|
|
110
|
+
argv.text ||
|
|
111
|
+
(count > 1 ? `${name} ${i + 1}\n${size}` : `${name}\n${size}`);
|
|
112
|
+
const outputPath = path.join(devAssetsDir, filename);
|
|
113
|
+
|
|
114
|
+
// Create command with style variations
|
|
115
|
+
const styleOptions = getStyleOptions(style, color);
|
|
116
|
+
const command = `${magickCmd} -size ${size} ${styleOptions.background} -gravity center ${styleOptions.text} -annotate +0+0 "${text}" "${outputPath}"`;
|
|
117
|
+
|
|
118
|
+
console.log(`🎨 Generating: ${filename} (${color}, ${style.name})`);
|
|
119
|
+
|
|
120
|
+
const result = shell.exec(command, { silent: true });
|
|
121
|
+
|
|
122
|
+
if (result.code === 0) {
|
|
123
|
+
console.log(`✅ Generated: ${filename}`);
|
|
124
|
+
generatedAssets.push({
|
|
125
|
+
name: count > 1 ? `${name}_${i + 1}` : name,
|
|
126
|
+
filename,
|
|
127
|
+
url: `https://localhost:${finalPort}/dev-assets/images/${filename}`,
|
|
128
|
+
color,
|
|
129
|
+
style: style.name,
|
|
130
|
+
});
|
|
131
|
+
} else {
|
|
132
|
+
console.error(`❌ Failed to generate ${filename}: ${result.stderr}`);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
console.log("");
|
|
138
|
+
console.log("📁 Generated assets:");
|
|
139
|
+
generatedAssets.forEach((asset) => {
|
|
140
|
+
console.log(` • ${asset.filename} (${asset.color}, ${asset.style})`);
|
|
141
|
+
console.log(` URL: ${asset.url}`);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
console.log("");
|
|
145
|
+
console.log("💡 Add to your store:");
|
|
146
|
+
generatedAssets.forEach((asset) => {
|
|
147
|
+
console.log(` gxpStore.updateAsset("${asset.name}", "${asset.url}")`);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function getRandomColor() {
|
|
152
|
+
const colors = [
|
|
153
|
+
"#FF6B6B",
|
|
154
|
+
"#4ECDC4",
|
|
155
|
+
"#45B7D1",
|
|
156
|
+
"#96CEB4",
|
|
157
|
+
"#FFEAA7",
|
|
158
|
+
"#DDA0DD",
|
|
159
|
+
"#98D8C8",
|
|
160
|
+
"#F7DC6F",
|
|
161
|
+
"#BB8FCE",
|
|
162
|
+
"#85C1E9",
|
|
163
|
+
];
|
|
164
|
+
return colors[Math.floor(Math.random() * colors.length)];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function getRandomStyle() {
|
|
168
|
+
const styles = [
|
|
169
|
+
{
|
|
170
|
+
name: "solid",
|
|
171
|
+
description: "Solid background with white text",
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
name: "bright",
|
|
175
|
+
description: "Bright background with contrasting text",
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: "outline",
|
|
179
|
+
description: "Solid background with outlined text",
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
name: "shadow",
|
|
183
|
+
description: "Solid background with shadowed text",
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: "minimal",
|
|
187
|
+
description: "Clean minimal style with dark text",
|
|
188
|
+
},
|
|
189
|
+
];
|
|
190
|
+
return styles[Math.floor(Math.random() * styles.length)];
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function getStyleOptions(style, color) {
|
|
194
|
+
const darkerColor = adjustColor(color, -30);
|
|
195
|
+
const lighterColor = adjustColor(color, 30);
|
|
196
|
+
|
|
197
|
+
switch (style.name) {
|
|
198
|
+
case "bright":
|
|
199
|
+
return {
|
|
200
|
+
background: `"xc:${lighterColor}"`,
|
|
201
|
+
text: `-pointsize 24 -fill "${darkerColor}"`,
|
|
202
|
+
};
|
|
203
|
+
case "outline":
|
|
204
|
+
return {
|
|
205
|
+
background: `"xc:${color}"`,
|
|
206
|
+
text: `-pointsize 24 -fill none -stroke white -strokewidth 2`,
|
|
207
|
+
};
|
|
208
|
+
case "shadow":
|
|
209
|
+
return {
|
|
210
|
+
background: `"xc:${color}"`,
|
|
211
|
+
text: `-pointsize 24 -fill white -stroke black -strokewidth 1`,
|
|
212
|
+
};
|
|
213
|
+
case "minimal":
|
|
214
|
+
return {
|
|
215
|
+
background: `"xc:${lighterColor}"`,
|
|
216
|
+
text: `-pointsize 20 -fill "${darkerColor}"`,
|
|
217
|
+
};
|
|
218
|
+
default: // solid
|
|
219
|
+
return {
|
|
220
|
+
background: `"xc:${color}"`,
|
|
221
|
+
text: `-pointsize 24 -fill white`,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function adjustColor(hex, percent) {
|
|
227
|
+
// Remove # if present
|
|
228
|
+
hex = hex.replace("#", "");
|
|
229
|
+
|
|
230
|
+
// Ensure we have a valid 6-character hex
|
|
231
|
+
if (hex.length !== 6) {
|
|
232
|
+
console.error(`Invalid hex color: ${hex}`);
|
|
233
|
+
return "#000000";
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Parse RGB values
|
|
237
|
+
const r = parseInt(hex.substr(0, 2), 16);
|
|
238
|
+
const g = parseInt(hex.substr(2, 2), 16);
|
|
239
|
+
const b = parseInt(hex.substr(4, 2), 16);
|
|
240
|
+
|
|
241
|
+
// Check for NaN values
|
|
242
|
+
if (isNaN(r) || isNaN(g) || isNaN(b)) {
|
|
243
|
+
console.error(`Failed to parse hex color: ${hex}`);
|
|
244
|
+
return "#000000";
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Adjust brightness
|
|
248
|
+
const adjustValue = (value, percent) => {
|
|
249
|
+
const adjusted = value + (percent * 255) / 100;
|
|
250
|
+
return Math.max(0, Math.min(255, Math.round(adjusted)));
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const newR = adjustValue(r, percent);
|
|
254
|
+
const newG = adjustValue(g, percent);
|
|
255
|
+
const newB = adjustValue(b, percent);
|
|
256
|
+
|
|
257
|
+
// Convert back to hex
|
|
258
|
+
const toHex = (value) => value.toString(16).padStart(2, "0");
|
|
259
|
+
return `#${toHex(newR)}${toHex(newG)}${toHex(newB)}`;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async function initDevelopmentAssets() {
|
|
263
|
+
const projectPath = findProjectRoot();
|
|
264
|
+
const devAssetsDir = path.join(projectPath, "dev-assets");
|
|
265
|
+
|
|
266
|
+
console.log("🎨 Setting up development assets...");
|
|
267
|
+
|
|
268
|
+
// Create directories
|
|
269
|
+
const dirs = ["images", "videos"];
|
|
270
|
+
dirs.forEach((dir) => {
|
|
271
|
+
const dirPath = path.join(devAssetsDir, dir);
|
|
272
|
+
if (!fs.existsSync(dirPath)) {
|
|
273
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
274
|
+
console.log(`✓ Created ${dir}/ directory`);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// Copy starter assets from toolkit
|
|
279
|
+
const paths = resolveGxPaths();
|
|
280
|
+
const sourceAssetsDir = path.join(paths.templateDir, "dev-assets");
|
|
281
|
+
|
|
282
|
+
if (fs.existsSync(sourceAssetsDir)) {
|
|
283
|
+
console.log("📋 Copying starter assets...");
|
|
284
|
+
|
|
285
|
+
// Copy image assets
|
|
286
|
+
const sourceImagesDir = path.join(sourceAssetsDir, "images");
|
|
287
|
+
const destImagesDir = path.join(devAssetsDir, "images");
|
|
288
|
+
|
|
289
|
+
if (fs.existsSync(sourceImagesDir)) {
|
|
290
|
+
const imageFiles = fs.readdirSync(sourceImagesDir);
|
|
291
|
+
imageFiles.forEach((file) => {
|
|
292
|
+
const srcPath = path.join(sourceImagesDir, file);
|
|
293
|
+
const destPath = path.join(destImagesDir, file);
|
|
294
|
+
if (!fs.existsSync(destPath)) {
|
|
295
|
+
safeCopyFile(srcPath, destPath, `Asset: ${file}`);
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Add to .gitignore
|
|
302
|
+
const gitignorePath = path.join(projectPath, ".gitignore");
|
|
303
|
+
if (fs.existsSync(gitignorePath)) {
|
|
304
|
+
let gitignoreContent = fs.readFileSync(gitignorePath, "utf-8");
|
|
305
|
+
if (!gitignoreContent.includes("dev-assets/")) {
|
|
306
|
+
gitignoreContent +=
|
|
307
|
+
"\n# Development assets (add your own files here)\ndev-assets/\n";
|
|
308
|
+
fs.writeFileSync(gitignorePath, gitignoreContent);
|
|
309
|
+
console.log("✓ Added dev-assets/ to .gitignore");
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
console.log("✅ Development assets setup complete!");
|
|
314
|
+
console.log("");
|
|
315
|
+
console.log("📁 Directory structure:");
|
|
316
|
+
console.log(" dev-assets/");
|
|
317
|
+
console.log(" ├── images/ # Image placeholders");
|
|
318
|
+
console.log(" └── videos/ # Video placeholders");
|
|
319
|
+
console.log("");
|
|
320
|
+
console.log("💡 Commands:");
|
|
321
|
+
console.log(
|
|
322
|
+
" gxdev assets list # List all assets"
|
|
323
|
+
);
|
|
324
|
+
console.log(
|
|
325
|
+
" gxdev assets generate --size 800x600 # Generate placeholder"
|
|
326
|
+
);
|
|
327
|
+
console.log(
|
|
328
|
+
" gxdev assets generate --name logo --size 200x200 # Custom placeholder"
|
|
329
|
+
);
|
|
330
|
+
console.log(
|
|
331
|
+
" gxdev assets generate --name banner --count 5 # Generate 5 variants"
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
module.exports = {
|
|
336
|
+
assetsCommand,
|
|
337
|
+
};
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build Command
|
|
3
|
+
*
|
|
4
|
+
* Builds the plugin for production and packages it as a .gxp file.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const path = require("path");
|
|
8
|
+
const fs = require("fs");
|
|
9
|
+
const shell = require("shelljs");
|
|
10
|
+
const archiver = require("archiver");
|
|
11
|
+
const { exportCmd } = require("../constants");
|
|
12
|
+
const { findProjectRoot, resolveGxPaths } = require("../utils");
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get the plugin name from package.json
|
|
16
|
+
*/
|
|
17
|
+
function getPluginName(projectPath) {
|
|
18
|
+
try {
|
|
19
|
+
const packageJsonPath = path.join(projectPath, "package.json");
|
|
20
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
21
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
22
|
+
// Clean the name for use as a filename
|
|
23
|
+
const name = packageJson.name || "plugin";
|
|
24
|
+
return name
|
|
25
|
+
.replace(/^@[^/]+\//, "") // Remove scope like @company/
|
|
26
|
+
.replace(/[^a-zA-Z0-9-_]/g, "-"); // Replace invalid chars with dash
|
|
27
|
+
}
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.warn("Could not read package.json, using default plugin name");
|
|
30
|
+
}
|
|
31
|
+
return "plugin";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Package the built plugin into a .gxp file
|
|
36
|
+
* @param {string} projectPath - Project root path
|
|
37
|
+
* @param {string} buildPath - Path where built files are (dist/build/)
|
|
38
|
+
* @param {string} outputPath - Path where .gxp file should be created (dist/)
|
|
39
|
+
*/
|
|
40
|
+
async function packagePlugin(projectPath, buildPath, outputPath) {
|
|
41
|
+
const pluginName = getPluginName(projectPath);
|
|
42
|
+
|
|
43
|
+
console.log("\n📦 Packaging plugin...");
|
|
44
|
+
|
|
45
|
+
// Read app-manifest.json to get asset_dir
|
|
46
|
+
const manifestPath = path.join(projectPath, "app-manifest.json");
|
|
47
|
+
let assetDir = "/src/assets/"; // Default
|
|
48
|
+
|
|
49
|
+
if (fs.existsSync(manifestPath)) {
|
|
50
|
+
try {
|
|
51
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
52
|
+
if (manifest.asset_dir) {
|
|
53
|
+
assetDir = manifest.asset_dir;
|
|
54
|
+
}
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.warn("⚠️ Could not parse app-manifest.json, using default asset_dir");
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
console.warn("⚠️ app-manifest.json not found");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Resolve asset directory path (remove leading slash for path.join)
|
|
63
|
+
const assetDirClean = assetDir.replace(/^\//, "").replace(/\/$/, "");
|
|
64
|
+
const assetSourcePath = path.join(projectPath, assetDirClean);
|
|
65
|
+
const assetDestPath = path.join(buildPath, "assets");
|
|
66
|
+
|
|
67
|
+
// Copy assets to dist/build/assets
|
|
68
|
+
if (fs.existsSync(assetSourcePath)) {
|
|
69
|
+
console.log(`📂 Copying assets from ${assetDirClean}/ to dist/build/assets/`);
|
|
70
|
+
|
|
71
|
+
// Create assets directory in build
|
|
72
|
+
if (!fs.existsSync(assetDestPath)) {
|
|
73
|
+
fs.mkdirSync(assetDestPath, { recursive: true });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Copy all files from asset source to build/assets
|
|
77
|
+
copyDirectorySync(assetSourcePath, assetDestPath);
|
|
78
|
+
console.log("✓ Assets copied");
|
|
79
|
+
} else {
|
|
80
|
+
console.log(`ℹ️ No assets directory found at ${assetDirClean}/`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Copy app-manifest.json to dist/build/
|
|
84
|
+
if (fs.existsSync(manifestPath)) {
|
|
85
|
+
const manifestDestPath = path.join(buildPath, "app-manifest.json");
|
|
86
|
+
fs.copyFileSync(manifestPath, manifestDestPath);
|
|
87
|
+
console.log("✓ app-manifest.json copied to dist/build/");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Create the .gxp package (zip file) in dist/
|
|
91
|
+
const gxpFileName = `${pluginName}.gxp`;
|
|
92
|
+
const gxpFilePath = path.join(outputPath, gxpFileName);
|
|
93
|
+
|
|
94
|
+
console.log(`📦 Creating ${gxpFileName}...`);
|
|
95
|
+
|
|
96
|
+
await createGxpPackage(buildPath, gxpFilePath);
|
|
97
|
+
|
|
98
|
+
console.log(`\n✅ Plugin packaged successfully!`);
|
|
99
|
+
console.log(`📁 Build files: dist/build/`);
|
|
100
|
+
console.log(`📁 Package: dist/${gxpFileName}`);
|
|
101
|
+
|
|
102
|
+
return gxpFilePath;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Recursively copy a directory
|
|
107
|
+
*/
|
|
108
|
+
function copyDirectorySync(src, dest) {
|
|
109
|
+
if (!fs.existsSync(dest)) {
|
|
110
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
114
|
+
|
|
115
|
+
for (const entry of entries) {
|
|
116
|
+
const srcPath = path.join(src, entry.name);
|
|
117
|
+
const destPath = path.join(dest, entry.name);
|
|
118
|
+
|
|
119
|
+
// Skip .gitkeep files
|
|
120
|
+
if (entry.name === ".gitkeep") continue;
|
|
121
|
+
|
|
122
|
+
if (entry.isDirectory()) {
|
|
123
|
+
copyDirectorySync(srcPath, destPath);
|
|
124
|
+
} else {
|
|
125
|
+
fs.copyFileSync(srcPath, destPath);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Create the .gxp package (zip file containing plugin files)
|
|
132
|
+
*/
|
|
133
|
+
function createGxpPackage(distPath, outputPath) {
|
|
134
|
+
return new Promise((resolve, reject) => {
|
|
135
|
+
const output = fs.createWriteStream(outputPath);
|
|
136
|
+
const archive = archiver("zip", {
|
|
137
|
+
zlib: { level: 9 } // Maximum compression
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
output.on("close", () => {
|
|
141
|
+
const sizeKB = (archive.pointer() / 1024).toFixed(2);
|
|
142
|
+
console.log(`✓ Package created (${sizeKB} KB)`);
|
|
143
|
+
resolve();
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
archive.on("error", (err) => {
|
|
147
|
+
reject(err);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
archive.pipe(output);
|
|
151
|
+
|
|
152
|
+
// Add all JS files from dist
|
|
153
|
+
const jsFiles = fs.readdirSync(distPath).filter(f => f.endsWith(".js"));
|
|
154
|
+
jsFiles.forEach(file => {
|
|
155
|
+
archive.file(path.join(distPath, file), { name: file });
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Add all CSS files from dist
|
|
159
|
+
const cssFiles = fs.readdirSync(distPath).filter(f => f.endsWith(".css"));
|
|
160
|
+
cssFiles.forEach(file => {
|
|
161
|
+
archive.file(path.join(distPath, file), { name: file });
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Add app-manifest.json
|
|
165
|
+
const manifestPath = path.join(distPath, "app-manifest.json");
|
|
166
|
+
if (fs.existsSync(manifestPath)) {
|
|
167
|
+
archive.file(manifestPath, { name: "app-manifest.json" });
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Add assets directory
|
|
171
|
+
const assetsPath = path.join(distPath, "assets");
|
|
172
|
+
if (fs.existsSync(assetsPath)) {
|
|
173
|
+
archive.directory(assetsPath, "assets");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
archive.finalize();
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Build command - builds the plugin for production
|
|
182
|
+
*/
|
|
183
|
+
async function buildCommand(argv) {
|
|
184
|
+
const projectPath = findProjectRoot();
|
|
185
|
+
const paths = resolveGxPaths();
|
|
186
|
+
const distPath = path.join(projectPath, "dist");
|
|
187
|
+
const buildPath = path.join(distPath, "build");
|
|
188
|
+
|
|
189
|
+
console.log("🔨 Building plugin...\n");
|
|
190
|
+
|
|
191
|
+
const envVars = [];
|
|
192
|
+
|
|
193
|
+
// check if vite.config.js exists locally
|
|
194
|
+
let viteConfigPath = paths.viteConfigPath;
|
|
195
|
+
const localViteConfigPath = path.join(projectPath, "vite.config.js");
|
|
196
|
+
if (fs.existsSync(localViteConfigPath)) {
|
|
197
|
+
viteConfigPath = localViteConfigPath;
|
|
198
|
+
console.log(`📁 Using local vite.config.js: ${viteConfigPath}`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Set variables only if not already defined in environment
|
|
202
|
+
if (!process.env.NODE_LOG_LEVEL) {
|
|
203
|
+
envVars.push(
|
|
204
|
+
`${exportCmd} NODE_LOG_LEVEL=${argv["node-log-level"] || "error"}`
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
if (!process.env.COMPONENT_PATH) {
|
|
208
|
+
envVars.push(
|
|
209
|
+
`${exportCmd} COMPONENT_PATH=${argv["component-path"] || "./src/Plugin.vue"}`
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const command = [
|
|
214
|
+
...envVars,
|
|
215
|
+
`npx vite build --config "${viteConfigPath}"`,
|
|
216
|
+
].join(" && ");
|
|
217
|
+
|
|
218
|
+
const result = shell.exec(command);
|
|
219
|
+
|
|
220
|
+
// Only proceed with packaging if build succeeded
|
|
221
|
+
if (result.code === 0) {
|
|
222
|
+
try {
|
|
223
|
+
// Move built files from dist/ to dist/build/
|
|
224
|
+
await moveBuildFiles(distPath, buildPath);
|
|
225
|
+
// Package the plugin (reads from buildPath, outputs .gxp to distPath)
|
|
226
|
+
await packagePlugin(projectPath, buildPath, distPath);
|
|
227
|
+
} catch (error) {
|
|
228
|
+
console.error("❌ Error packaging plugin:", error.message);
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
} else {
|
|
232
|
+
console.error("❌ Build failed");
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Move built JS/CSS files from dist/ to dist/build/
|
|
239
|
+
*/
|
|
240
|
+
async function moveBuildFiles(distPath, buildPath) {
|
|
241
|
+
// Create build directory
|
|
242
|
+
if (!fs.existsSync(buildPath)) {
|
|
243
|
+
fs.mkdirSync(buildPath, { recursive: true });
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Move all JS and CSS files to build directory
|
|
247
|
+
const files = fs.readdirSync(distPath);
|
|
248
|
+
for (const file of files) {
|
|
249
|
+
if (file.endsWith(".js") || file.endsWith(".css")) {
|
|
250
|
+
const srcFile = path.join(distPath, file);
|
|
251
|
+
const destFile = path.join(buildPath, file);
|
|
252
|
+
fs.renameSync(srcFile, destFile);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
module.exports = {
|
|
258
|
+
buildCommand,
|
|
259
|
+
};
|