@micropress/theme-sdk 0.0.1

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.
@@ -0,0 +1,714 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
32
+
33
+ // cli/commands/build.ts
34
+ var build_exports = {};
35
+ __export(build_exports, {
36
+ buildCommand: () => buildCommand
37
+ });
38
+ async function buildCommand(options) {
39
+ const cwd = process.cwd();
40
+ const outputDir = path2.resolve(cwd, options.output);
41
+ console.log("Building theme...");
42
+ console.log(`Output: ${outputDir}`);
43
+ console.log();
44
+ const manifestPath = path2.join(cwd, "manifest.json");
45
+ const tsconfigPath = path2.join(cwd, "tsconfig.json");
46
+ if (!fs2.existsSync(manifestPath)) {
47
+ console.error("Error: manifest.json not found");
48
+ console.error("Run this command from your theme directory");
49
+ process.exit(1);
50
+ }
51
+ if (!fs2.existsSync(outputDir)) {
52
+ fs2.mkdirSync(outputDir, { recursive: true });
53
+ }
54
+ fs2.copyFileSync(manifestPath, path2.join(outputDir, "manifest.json"));
55
+ console.log(" Copied: manifest.json");
56
+ const srcDir = path2.join(cwd, "src");
57
+ if (fs2.existsSync(srcDir)) {
58
+ const cssFiles = findFiles(srcDir, ".css");
59
+ for (const cssFile of cssFiles) {
60
+ const relativePath = path2.relative(srcDir, cssFile);
61
+ const destPath = path2.join(outputDir, relativePath);
62
+ const destDir = path2.dirname(destPath);
63
+ if (!fs2.existsSync(destDir)) {
64
+ fs2.mkdirSync(destDir, { recursive: true });
65
+ }
66
+ fs2.copyFileSync(cssFile, destPath);
67
+ console.log(` Copied: ${relativePath}`);
68
+ }
69
+ }
70
+ const assetsDir = path2.join(cwd, "assets");
71
+ if (fs2.existsSync(assetsDir)) {
72
+ const destAssetsDir = path2.join(outputDir, "assets");
73
+ copyDirectory(assetsDir, destAssetsDir);
74
+ console.log(" Copied: assets/");
75
+ }
76
+ if (fs2.existsSync(tsconfigPath)) {
77
+ console.log(" Compiling TypeScript...");
78
+ try {
79
+ (0, import_child_process2.execSync)(`npx tsc --outDir "${outputDir}"`, { cwd, stdio: "pipe" });
80
+ console.log(" TypeScript compiled successfully");
81
+ } catch (error) {
82
+ const err = error;
83
+ if (err.stderr) {
84
+ console.error("TypeScript compilation failed:");
85
+ console.error(err.stderr.toString());
86
+ }
87
+ process.exit(1);
88
+ }
89
+ } else {
90
+ const jsFiles = findFiles(srcDir, ".js");
91
+ for (const jsFile of jsFiles) {
92
+ const relativePath = path2.relative(srcDir, jsFile);
93
+ const destPath = path2.join(outputDir, relativePath);
94
+ const destDir = path2.dirname(destPath);
95
+ if (!fs2.existsSync(destDir)) {
96
+ fs2.mkdirSync(destDir, { recursive: true });
97
+ }
98
+ fs2.copyFileSync(jsFile, destPath);
99
+ console.log(` Copied: ${relativePath}`);
100
+ }
101
+ }
102
+ console.log();
103
+ console.log("Build complete!");
104
+ if (options.watch) {
105
+ console.log();
106
+ console.log("Watching for changes... (press Ctrl+C to stop)");
107
+ watchDirectory(cwd, async () => {
108
+ console.log();
109
+ console.log("Changes detected, rebuilding...");
110
+ await buildCommand({ ...options, watch: false });
111
+ });
112
+ }
113
+ }
114
+ function findFiles(dir, extension) {
115
+ const files = [];
116
+ if (!fs2.existsSync(dir)) {
117
+ return files;
118
+ }
119
+ const entries = fs2.readdirSync(dir, { withFileTypes: true });
120
+ for (const entry of entries) {
121
+ const fullPath = path2.join(dir, entry.name);
122
+ if (entry.isDirectory()) {
123
+ files.push(...findFiles(fullPath, extension));
124
+ } else if (entry.name.endsWith(extension)) {
125
+ files.push(fullPath);
126
+ }
127
+ }
128
+ return files;
129
+ }
130
+ function copyDirectory(src, dest) {
131
+ if (!fs2.existsSync(dest)) {
132
+ fs2.mkdirSync(dest, { recursive: true });
133
+ }
134
+ const entries = fs2.readdirSync(src, { withFileTypes: true });
135
+ for (const entry of entries) {
136
+ const srcPath = path2.join(src, entry.name);
137
+ const destPath = path2.join(dest, entry.name);
138
+ if (entry.isDirectory()) {
139
+ copyDirectory(srcPath, destPath);
140
+ } else {
141
+ fs2.copyFileSync(srcPath, destPath);
142
+ }
143
+ }
144
+ }
145
+ function watchDirectory(dir, callback) {
146
+ const watchDirs = ["src", "assets"];
147
+ let debounceTimer = null;
148
+ const debouncedCallback = () => {
149
+ if (debounceTimer) {
150
+ clearTimeout(debounceTimer);
151
+ }
152
+ debounceTimer = setTimeout(callback, 100);
153
+ };
154
+ for (const watchDir of watchDirs) {
155
+ const fullPath = path2.join(dir, watchDir);
156
+ if (fs2.existsSync(fullPath)) {
157
+ fs2.watch(fullPath, { recursive: true }, debouncedCallback);
158
+ }
159
+ }
160
+ const manifestPath = path2.join(dir, "manifest.json");
161
+ if (fs2.existsSync(manifestPath)) {
162
+ fs2.watch(manifestPath, debouncedCallback);
163
+ }
164
+ }
165
+ var fs2, path2, import_child_process2;
166
+ var init_build = __esm({
167
+ "cli/commands/build.ts"() {
168
+ "use strict";
169
+ fs2 = __toESM(require("fs"));
170
+ path2 = __toESM(require("path"));
171
+ import_child_process2 = require("child_process");
172
+ }
173
+ });
174
+
175
+ // cli/index.ts
176
+ var import_commander = require("commander");
177
+
178
+ // cli/commands/init.ts
179
+ var fs = __toESM(require("fs"));
180
+ var path = __toESM(require("path"));
181
+ var import_child_process = require("child_process");
182
+ var MANIFEST_TEMPLATE = `{
183
+ "id": "{{name}}",
184
+ "name": "{{displayName}}",
185
+ "version": "1.0.0",
186
+ "description": "A custom MicroPress theme",
187
+ "author": "Your Name",
188
+ "homepage": "",
189
+ "breakpoints": {
190
+ "sm": "640px",
191
+ "md": "768px",
192
+ "lg": "1024px",
193
+ "xl": "1280px"
194
+ },
195
+ "customizable": {
196
+ "primaryColor": {
197
+ "type": "color",
198
+ "label": "Primary Color",
199
+ "default": "#3b82f6"
200
+ },
201
+ "fontFamily": {
202
+ "type": "select",
203
+ "label": "Font Family",
204
+ "default": "system-ui",
205
+ "options": ["system-ui", "Georgia", "Helvetica"]
206
+ }
207
+ }
208
+ }`;
209
+ var THEME_CSS_TEMPLATE = `/* {{displayName}} - Main Styles */
210
+
211
+ :root {
212
+ --primary: var(--theme-primaryColor, #3b82f6);
213
+ --font-family: var(--theme-fontFamily, system-ui);
214
+ }
215
+
216
+ /* Base styles */
217
+ body {
218
+ font-family: var(--font-family), sans-serif;
219
+ line-height: 1.6;
220
+ color: #1f2937;
221
+ }
222
+
223
+ /* Header */
224
+ .theme-header {
225
+ padding: 1rem 2rem;
226
+ border-bottom: 1px solid #e5e7eb;
227
+ }
228
+
229
+ .theme-header__brand {
230
+ font-weight: 600;
231
+ font-size: 1.25rem;
232
+ text-decoration: none;
233
+ color: inherit;
234
+ }
235
+
236
+ /* Navigation */
237
+ .theme-nav {
238
+ padding: 0.5rem 2rem;
239
+ }
240
+
241
+ .theme-nav__list {
242
+ display: flex;
243
+ gap: 1.5rem;
244
+ list-style: none;
245
+ margin: 0;
246
+ padding: 0;
247
+ }
248
+
249
+ .theme-nav__link {
250
+ color: #6b7280;
251
+ text-decoration: none;
252
+ transition: color 0.2s;
253
+ }
254
+
255
+ .theme-nav__link:hover,
256
+ .theme-nav__link.is-active {
257
+ color: var(--primary);
258
+ }
259
+
260
+ /* Main content */
261
+ .theme-content {
262
+ max-width: 800px;
263
+ margin: 0 auto;
264
+ padding: 2rem;
265
+ }
266
+
267
+ /* Footer */
268
+ .theme-footer {
269
+ padding: 2rem;
270
+ background: #f9fafb;
271
+ text-align: center;
272
+ color: #6b7280;
273
+ font-size: 0.875rem;
274
+ }
275
+
276
+ /* Responsive */
277
+ @media (max-width: 768px) {
278
+ .theme-nav__list {
279
+ flex-direction: column;
280
+ gap: 0.5rem;
281
+ }
282
+ }
283
+ `;
284
+ var RENDERERS_TEMPLATE = `import { defineTheme, html, css, raw, when } from '@micropress/theme-sdk';
285
+ import type { HeaderDTO, NavigationDTO, FooterDTO } from '@micropress/theme-sdk';
286
+
287
+ export default defineTheme({
288
+ config: {
289
+ id: '{{name}}',
290
+ name: '{{displayName}}',
291
+ version: '1.0.0',
292
+ },
293
+
294
+ renderers: {
295
+ // Custom header renderer
296
+ header: {
297
+ render: (data: HeaderDTO) => html\`
298
+ <header class="theme-header">
299
+ <a href="/" class="theme-header__brand">
300
+ \${data.logo
301
+ ? html\`<img src="\${data.logo.src}" alt="\${data.logo.alt}" />\`
302
+ : html\`<span>\${data.siteName}</span>\`
303
+ }
304
+ </a>
305
+ \${when(data.showMenuToggle, html\`
306
+ <button class="theme-header__toggle" aria-label="Toggle menu">
307
+ <span></span>
308
+ </button>
309
+ \`)}
310
+ </header>
311
+ \`.html,
312
+ },
313
+
314
+ // Custom navigation renderer
315
+ navigation: {
316
+ render: (data: NavigationDTO) => html\`
317
+ <nav class="theme-nav">
318
+ <ul class="theme-nav__list">
319
+ \${raw(data.items.map(item => html\`
320
+ <li class="theme-nav__item">
321
+ <a
322
+ href="\${item.href}"
323
+ class="theme-nav__link \${item.active ? 'is-active' : ''}"
324
+ >
325
+ \${item.label}
326
+ </a>
327
+ </li>
328
+ \`.html).join(''))}
329
+ </ul>
330
+ </nav>
331
+ \`.html,
332
+ },
333
+
334
+ // Custom footer renderer
335
+ footer: {
336
+ render: (data: FooterDTO) => html\`
337
+ <footer class="theme-footer">
338
+ <p>&copy; \${data.year} \${data.copyright}</p>
339
+ \${when(data.links.length > 0, html\`
340
+ <nav>
341
+ \${raw(data.links.map(link => html\`
342
+ <a href="\${link.href}">\${link.label}</a>
343
+ \`.html).join(' \xB7 '))}
344
+ </nav>
345
+ \`)}
346
+ </footer>
347
+ \`.html,
348
+ },
349
+ },
350
+ });
351
+ `;
352
+ var PACKAGE_JSON_TEMPLATE = `{
353
+ "name": "{{name}}",
354
+ "version": "1.0.0",
355
+ "description": "A custom MicroPress theme",
356
+ "main": "dist/renderers.js",
357
+ "types": "dist/renderers.d.ts",
358
+ "scripts": {
359
+ "build": "micropress-theme build",
360
+ "validate": "micropress-theme validate",
361
+ "package": "micropress-theme package"
362
+ },
363
+ "devDependencies": {
364
+ "@micropress/theme-sdk": "^1.0.0",
365
+ "typescript": "^5.0.0"
366
+ },
367
+ "keywords": ["micropress", "theme"],
368
+ "license": "MIT"
369
+ }`;
370
+ var TSCONFIG_TEMPLATE = `{
371
+ "compilerOptions": {
372
+ "target": "ES2020",
373
+ "module": "ESNext",
374
+ "moduleResolution": "bundler",
375
+ "declaration": true,
376
+ "declarationMap": true,
377
+ "outDir": "dist",
378
+ "rootDir": "src",
379
+ "strict": true,
380
+ "esModuleInterop": true,
381
+ "skipLibCheck": true,
382
+ "forceConsistentCasingInFileNames": true
383
+ },
384
+ "include": ["src/**/*"],
385
+ "exclude": ["node_modules", "dist"]
386
+ }`;
387
+ var GITIGNORE_TEMPLATE = `node_modules/
388
+ dist/
389
+ *.zip
390
+ .DS_Store
391
+ `;
392
+ function toDisplayName(name) {
393
+ return name.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
394
+ }
395
+ function replaceTemplateVars(template, vars) {
396
+ return template.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] || "");
397
+ }
398
+ async function initCommand(name, options) {
399
+ const targetDir = path.resolve(options.directory === "." ? name : path.join(options.directory, name));
400
+ console.log(`Creating theme: ${name}`);
401
+ console.log(`Location: ${targetDir}`);
402
+ console.log();
403
+ if (fs.existsSync(targetDir)) {
404
+ console.error(`Error: Directory already exists: ${targetDir}`);
405
+ process.exit(1);
406
+ }
407
+ fs.mkdirSync(targetDir, { recursive: true });
408
+ fs.mkdirSync(path.join(targetDir, "src"));
409
+ fs.mkdirSync(path.join(targetDir, "assets"));
410
+ const vars = {
411
+ name,
412
+ displayName: toDisplayName(name)
413
+ };
414
+ const files = [
415
+ { path: "manifest.json", content: replaceTemplateVars(MANIFEST_TEMPLATE, vars) },
416
+ { path: "src/theme.css", content: replaceTemplateVars(THEME_CSS_TEMPLATE, vars) },
417
+ { path: "src/renderers.ts", content: replaceTemplateVars(RENDERERS_TEMPLATE, vars) },
418
+ { path: "package.json", content: replaceTemplateVars(PACKAGE_JSON_TEMPLATE, vars) },
419
+ { path: "tsconfig.json", content: TSCONFIG_TEMPLATE },
420
+ { path: ".gitignore", content: GITIGNORE_TEMPLATE }
421
+ ];
422
+ for (const file of files) {
423
+ const filePath = path.join(targetDir, file.path);
424
+ const dir = path.dirname(filePath);
425
+ if (!fs.existsSync(dir)) {
426
+ fs.mkdirSync(dir, { recursive: true });
427
+ }
428
+ fs.writeFileSync(filePath, file.content);
429
+ console.log(` Created: ${file.path}`);
430
+ }
431
+ if (options.git) {
432
+ try {
433
+ (0, import_child_process.execSync)("git init", { cwd: targetDir, stdio: "ignore" });
434
+ console.log(" Initialized git repository");
435
+ } catch {
436
+ console.log(" Warning: Could not initialize git repository");
437
+ }
438
+ }
439
+ console.log();
440
+ console.log("Theme created successfully!");
441
+ console.log();
442
+ console.log("Next steps:");
443
+ console.log(` cd ${name}`);
444
+ console.log(" npm install");
445
+ console.log(" npm run build");
446
+ console.log();
447
+ }
448
+
449
+ // cli/index.ts
450
+ init_build();
451
+
452
+ // cli/commands/validate.ts
453
+ var fs3 = __toESM(require("fs"));
454
+ var path3 = __toESM(require("path"));
455
+ async function validateCommand(options) {
456
+ const cwd = process.cwd();
457
+ console.log("Validating theme...");
458
+ console.log();
459
+ const result = {
460
+ valid: true,
461
+ errors: [],
462
+ warnings: []
463
+ };
464
+ const manifestPath = path3.join(cwd, "manifest.json");
465
+ if (!fs3.existsSync(manifestPath)) {
466
+ result.errors.push("manifest.json not found");
467
+ result.valid = false;
468
+ } else {
469
+ const manifestResult = validateManifest(manifestPath, options.fix);
470
+ result.errors.push(...manifestResult.errors);
471
+ result.warnings.push(...manifestResult.warnings);
472
+ if (!manifestResult.valid) {
473
+ result.valid = false;
474
+ }
475
+ }
476
+ const srcDir = path3.join(cwd, "src");
477
+ if (!fs3.existsSync(srcDir)) {
478
+ result.errors.push("src/ directory not found");
479
+ result.valid = false;
480
+ }
481
+ const cssFiles = findFiles2(srcDir, ".css");
482
+ if (cssFiles.length === 0) {
483
+ result.warnings.push("No CSS files found in src/");
484
+ }
485
+ const renderersTs = path3.join(srcDir, "renderers.ts");
486
+ const renderersJs = path3.join(srcDir, "renderers.js");
487
+ if (!fs3.existsSync(renderersTs) && !fs3.existsSync(renderersJs)) {
488
+ result.warnings.push("No renderers.ts or renderers.js found in src/");
489
+ }
490
+ const packagePath = path3.join(cwd, "package.json");
491
+ if (!fs3.existsSync(packagePath)) {
492
+ result.warnings.push("package.json not found");
493
+ } else {
494
+ const packageResult = validatePackageJson(packagePath);
495
+ result.warnings.push(...packageResult.warnings);
496
+ }
497
+ if (result.errors.length > 0) {
498
+ console.log("Errors:");
499
+ for (const error of result.errors) {
500
+ console.log(` \x1B[31m\u2717\x1B[0m ${error}`);
501
+ }
502
+ console.log();
503
+ }
504
+ if (result.warnings.length > 0) {
505
+ console.log("Warnings:");
506
+ for (const warning of result.warnings) {
507
+ console.log(` \x1B[33m!\x1B[0m ${warning}`);
508
+ }
509
+ console.log();
510
+ }
511
+ if (result.valid && result.errors.length === 0) {
512
+ console.log("\x1B[32m\u2713\x1B[0m Theme is valid!");
513
+ if (result.warnings.length > 0) {
514
+ console.log(` (${result.warnings.length} warning${result.warnings.length === 1 ? "" : "s"})`);
515
+ }
516
+ } else {
517
+ console.log("\x1B[31m\u2717\x1B[0m Theme validation failed");
518
+ process.exit(1);
519
+ }
520
+ }
521
+ function validateManifest(manifestPath, fix) {
522
+ const result = {
523
+ valid: true,
524
+ errors: [],
525
+ warnings: []
526
+ };
527
+ let manifest;
528
+ try {
529
+ const content = fs3.readFileSync(manifestPath, "utf-8");
530
+ manifest = JSON.parse(content);
531
+ } catch (error) {
532
+ result.errors.push(`Invalid JSON in manifest.json: ${error.message}`);
533
+ result.valid = false;
534
+ return result;
535
+ }
536
+ const requiredFields = ["id", "name", "version", "description", "author"];
537
+ for (const field of requiredFields) {
538
+ if (!manifest[field]) {
539
+ result.errors.push(`Missing required field in manifest.json: ${field}`);
540
+ result.valid = false;
541
+ }
542
+ }
543
+ if (manifest.id && !/^[a-z][a-z0-9-]*$/.test(manifest.id)) {
544
+ result.errors.push("Invalid theme ID: must start with a letter and contain only lowercase letters, numbers, and hyphens");
545
+ result.valid = false;
546
+ }
547
+ if (manifest.version && !/^\d+\.\d+\.\d+(-[a-z0-9.]+)?$/.test(manifest.version)) {
548
+ result.warnings.push("Version should follow semver format (e.g., 1.0.0)");
549
+ }
550
+ if (manifest.customizable) {
551
+ for (const [key, field] of Object.entries(manifest.customizable)) {
552
+ if (!field.type) {
553
+ result.errors.push(`Missing type for customizable field: ${key}`);
554
+ result.valid = false;
555
+ } else if (!["color", "font", "size", "select"].includes(field.type)) {
556
+ result.errors.push(`Invalid type for customizable field ${key}: ${field.type}`);
557
+ result.valid = false;
558
+ }
559
+ if (!field.label) {
560
+ result.warnings.push(`Missing label for customizable field: ${key}`);
561
+ }
562
+ if (field.default === void 0) {
563
+ result.warnings.push(`Missing default value for customizable field: ${key}`);
564
+ }
565
+ if (field.type === "select" && (!field.options || field.options.length === 0)) {
566
+ result.errors.push(`Select field ${key} must have options array`);
567
+ result.valid = false;
568
+ }
569
+ }
570
+ }
571
+ return result;
572
+ }
573
+ function validatePackageJson(packagePath) {
574
+ const result = {
575
+ valid: true,
576
+ errors: [],
577
+ warnings: []
578
+ };
579
+ try {
580
+ const content = fs3.readFileSync(packagePath, "utf-8");
581
+ const pkg = JSON.parse(content);
582
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
583
+ if (!deps["@micropress/theme-sdk"]) {
584
+ result.warnings.push("@micropress/theme-sdk not found in dependencies");
585
+ }
586
+ } catch (error) {
587
+ result.warnings.push(`Could not parse package.json: ${error.message}`);
588
+ }
589
+ return result;
590
+ }
591
+ function findFiles2(dir, extension) {
592
+ const files = [];
593
+ if (!fs3.existsSync(dir)) {
594
+ return files;
595
+ }
596
+ const entries = fs3.readdirSync(dir, { withFileTypes: true });
597
+ for (const entry of entries) {
598
+ const fullPath = path3.join(dir, entry.name);
599
+ if (entry.isDirectory()) {
600
+ files.push(...findFiles2(fullPath, extension));
601
+ } else if (entry.name.endsWith(extension)) {
602
+ files.push(fullPath);
603
+ }
604
+ }
605
+ return files;
606
+ }
607
+
608
+ // cli/commands/package.ts
609
+ var fs4 = __toESM(require("fs"));
610
+ var path4 = __toESM(require("path"));
611
+ var import_child_process3 = require("child_process");
612
+ async function packageCommand(options) {
613
+ const cwd = process.cwd();
614
+ console.log("Packaging theme...");
615
+ console.log();
616
+ const manifestPath = path4.join(cwd, "manifest.json");
617
+ if (!fs4.existsSync(manifestPath)) {
618
+ console.error("Error: manifest.json not found");
619
+ console.error("Run this command from your theme directory");
620
+ process.exit(1);
621
+ }
622
+ let manifest;
623
+ try {
624
+ const content = fs4.readFileSync(manifestPath, "utf-8");
625
+ manifest = JSON.parse(content);
626
+ } catch (error) {
627
+ console.error("Error: Invalid manifest.json");
628
+ process.exit(1);
629
+ }
630
+ if (!manifest.id || !manifest.version) {
631
+ console.error("Error: manifest.json must have id and version fields");
632
+ process.exit(1);
633
+ }
634
+ const distDir = path4.join(cwd, "dist");
635
+ if (!fs4.existsSync(distDir)) {
636
+ console.log("Build directory not found. Running build first...");
637
+ console.log();
638
+ try {
639
+ const { buildCommand: buildCommand2 } = await Promise.resolve().then(() => (init_build(), build_exports));
640
+ await buildCommand2({ watch: false, output: "dist" });
641
+ console.log();
642
+ } catch (error) {
643
+ console.error("Build failed");
644
+ process.exit(1);
645
+ }
646
+ }
647
+ const requiredFiles = ["manifest.json"];
648
+ for (const file of requiredFiles) {
649
+ if (!fs4.existsSync(path4.join(distDir, file))) {
650
+ console.error(`Error: ${file} not found in dist/`);
651
+ console.error("Please run build first");
652
+ process.exit(1);
653
+ }
654
+ }
655
+ const outputFile = options.output || `${manifest.id}-${manifest.version}.zip`;
656
+ const outputPath = path4.resolve(cwd, outputFile);
657
+ console.log(`Creating: ${outputFile}`);
658
+ try {
659
+ const files = getAllFiles(distDir);
660
+ const fileList = files.map((f) => path4.relative(distDir, f)).join(" ");
661
+ (0, import_child_process3.execSync)(`zip -r "${outputPath}" ${fileList}`, {
662
+ cwd: distDir,
663
+ stdio: "pipe"
664
+ });
665
+ } catch {
666
+ console.log("Native zip not available, creating package manually...");
667
+ createZipManually(distDir, outputPath);
668
+ }
669
+ const stats = fs4.statSync(outputPath);
670
+ const sizeKB = (stats.size / 1024).toFixed(1);
671
+ console.log();
672
+ console.log(`\x1B[32m\u2713\x1B[0m Package created: ${outputFile} (${sizeKB} KB)`);
673
+ console.log();
674
+ console.log("Upload this file to MicroPress to install your theme.");
675
+ }
676
+ function getAllFiles(dir) {
677
+ const files = [];
678
+ const entries = fs4.readdirSync(dir, { withFileTypes: true });
679
+ for (const entry of entries) {
680
+ const fullPath = path4.join(dir, entry.name);
681
+ if (entry.isDirectory()) {
682
+ files.push(...getAllFiles(fullPath));
683
+ } else {
684
+ files.push(fullPath);
685
+ }
686
+ }
687
+ return files;
688
+ }
689
+ function createZipManually(sourceDir, outputPath) {
690
+ try {
691
+ (0, import_child_process3.execSync)(`tar -czf "${outputPath.replace(".zip", ".tar.gz")}" -C "${sourceDir}" .`, {
692
+ stdio: "pipe"
693
+ });
694
+ console.log("Note: Created tar.gz instead of zip (zip command not available)");
695
+ fs4.renameSync(outputPath.replace(".zip", ".tar.gz"), outputPath);
696
+ } catch (error) {
697
+ const files = getAllFiles(sourceDir);
698
+ const listing = files.map((f) => path4.relative(sourceDir, f)).join("\n");
699
+ fs4.writeFileSync(outputPath.replace(".zip", ".txt"), listing);
700
+ console.error("Warning: Could not create archive. Created file listing instead.");
701
+ console.error("Please install zip or tar to create proper packages.");
702
+ }
703
+ }
704
+
705
+ // cli/index.ts
706
+ var VERSION = "0.0.1";
707
+ var program = new import_commander.Command();
708
+ program.name("micropress-theme").description("CLI for building MicroPress themes").version(VERSION);
709
+ program.command("init <name>").description("Initialize a new theme project").option("-d, --directory <dir>", "Directory to create theme in", ".").option("--no-git", "Skip git initialization").action(initCommand);
710
+ program.command("build").description("Build the theme for distribution").option("-w, --watch", "Watch for changes").option("-o, --output <dir>", "Output directory", "dist").action(buildCommand);
711
+ program.command("validate").description("Validate theme structure and manifest").option("--fix", "Attempt to fix simple issues").action(validateCommand);
712
+ program.command("package").description("Create a distributable ZIP file").option("-o, --output <file>", "Output file path").action(packageCommand);
713
+ program.parse();
714
+ //# sourceMappingURL=index.js.map