@julien-lin/universal-pwa-cli 1.3.2 → 1.3.3

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/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
 
6
6
  // src/index.ts
7
7
  import { Command } from "commander";
8
- import chalk6 from "chalk";
8
+ import chalk7 from "chalk";
9
9
 
10
10
  // src/commands/init.ts
11
11
  import { scanProject, optimizeProject } from "@julien-lin/universal-pwa-core";
@@ -510,7 +510,8 @@ async function initCommand(options = {}) {
510
510
  }
511
511
  let finalOutputDir;
512
512
  if (outputDir) {
513
- finalOutputDir = resolve(outputDir);
513
+ finalOutputDir = outputDir.startsWith("/") || process.platform === "win32" && /^[A-Z]:/.test(outputDir) ? resolve(outputDir) : join2(result.projectPath, outputDir);
514
+ console.log(chalk2.gray(` Using output directory: ${finalOutputDir}`));
514
515
  } else {
515
516
  const distDir = join2(result.projectPath, "dist");
516
517
  const publicDir = join2(result.projectPath, "public");
@@ -1150,24 +1151,253 @@ async function verifyCommand(options = {}) {
1150
1151
  }
1151
1152
  }
1152
1153
 
1154
+ // src/commands/remove.ts
1155
+ import { scanProject as scanProject2, parseHTML } from "@julien-lin/universal-pwa-core";
1156
+ import chalk5 from "chalk";
1157
+ import { existsSync as existsSync5, readFileSync as readFileSync3, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
1158
+ import { glob as glob3 } from "glob";
1159
+ import { join as join5, resolve as resolve4, relative as relative2 } from "path";
1160
+ var PWA_FILES_TO_REMOVE = [
1161
+ "manifest.json",
1162
+ "sw.js",
1163
+ "apple-touch-icon.png",
1164
+ "icon-72x72.png",
1165
+ "icon-96x96.png",
1166
+ "icon-128x128.png",
1167
+ "icon-144x144.png",
1168
+ "icon-152x152.png",
1169
+ "icon-192x192.png",
1170
+ "icon-384x384.png",
1171
+ "icon-512x512.png"
1172
+ ];
1173
+ function isPWAScript(content) {
1174
+ const lowerContent = content.toLowerCase();
1175
+ return lowerContent.includes("serviceworker") || lowerContent.includes("navigator.serviceworker") || lowerContent.includes("register") && lowerContent.includes("sw") || lowerContent.includes("sw.js") || lowerContent.includes("beforeinstallprompt") || lowerContent.includes("window.installpwa") || lowerContent.includes("ispwainstalled") || lowerContent.includes("ispwainstallable") || lowerContent.includes("deferredprompt");
1176
+ }
1177
+ async function removeMetaTags(htmlContent) {
1178
+ const parsed = parseHTML(htmlContent);
1179
+ const removed = [];
1180
+ if (!parsed.head) {
1181
+ return { html: htmlContent, removed: [] };
1182
+ }
1183
+ const head = parsed.head;
1184
+ if (!head.children) {
1185
+ head.children = [];
1186
+ }
1187
+ const tagsToRemove = [
1188
+ { type: "link", attr: "rel", value: "manifest", name: "manifest link" },
1189
+ { type: "meta", attr: "name", value: "theme-color", name: "theme-color meta tag" },
1190
+ { type: "link", attr: "rel", value: "apple-touch-icon", name: "apple-touch-icon link" },
1191
+ { type: "meta", attr: "name", value: "mobile-web-app-capable", name: "mobile-web-app-capable meta tag" }
1192
+ ];
1193
+ for (const tag of tagsToRemove) {
1194
+ const index = head.children.findIndex((child) => {
1195
+ return child.type === "tag" && child.tagName === tag.type && child.attribs?.[tag.attr] === tag.value;
1196
+ });
1197
+ if (index !== -1) {
1198
+ head.children.splice(index, 1);
1199
+ removed.push(tag.name);
1200
+ }
1201
+ }
1202
+ const findAndRemoveScripts = (node) => {
1203
+ if (!node?.children) return;
1204
+ for (let i = node.children.length - 1; i >= 0; i--) {
1205
+ const child = node.children[i];
1206
+ if (child.type === "tag" && child.tagName === "script") {
1207
+ const content = child.children?.[0]?.data || "";
1208
+ if (isPWAScript(content)) {
1209
+ node.children.splice(i, 1);
1210
+ removed.push("service worker registration script");
1211
+ }
1212
+ } else if (child.children) {
1213
+ findAndRemoveScripts(child);
1214
+ }
1215
+ }
1216
+ };
1217
+ if (parsed.document) {
1218
+ findAndRemoveScripts(parsed.document);
1219
+ }
1220
+ const { render } = await import("./esm-BSZHJOVR.js");
1221
+ const html = render(parsed.document);
1222
+ return { html, removed };
1223
+ }
1224
+ async function removeCommand(options = {}) {
1225
+ const {
1226
+ projectPath = process.cwd(),
1227
+ outputDir,
1228
+ skipHtmlRestore = false,
1229
+ skipFiles = false
1230
+ } = options;
1231
+ const result = {
1232
+ success: false,
1233
+ projectPath: resolve4(projectPath),
1234
+ outputDir: "",
1235
+ filesRemoved: [],
1236
+ htmlFilesRestored: 0,
1237
+ warnings: [],
1238
+ errors: []
1239
+ };
1240
+ let transaction = null;
1241
+ try {
1242
+ if (!existsSync5(result.projectPath)) {
1243
+ const errorCode = "E1001" /* PROJECT_PATH_NOT_FOUND */;
1244
+ const errorMessage = formatError(errorCode, result.projectPath);
1245
+ result.errors.push(errorMessage);
1246
+ console.log(chalk5.red(`\u2717 ${errorMessage}`));
1247
+ return result;
1248
+ }
1249
+ console.log(chalk5.blue("\u{1F50D} Scanning project for PWA files..."));
1250
+ const scanResult = await scanProject2({
1251
+ projectPath: result.projectPath,
1252
+ includeAssets: false,
1253
+ includeArchitecture: false
1254
+ });
1255
+ let finalOutputDir;
1256
+ if (outputDir) {
1257
+ finalOutputDir = outputDir.startsWith("/") || process.platform === "win32" && /^[A-Z]:/.test(outputDir) ? resolve4(outputDir) : join5(result.projectPath, outputDir);
1258
+ } else {
1259
+ const envDetection = detectEnvironment(result.projectPath, scanResult.framework.framework);
1260
+ const distDir = join5(result.projectPath, "dist");
1261
+ const publicDir = join5(result.projectPath, "public");
1262
+ if (envDetection.suggestedOutputDir === "dist" && existsSync5(distDir)) {
1263
+ finalOutputDir = distDir;
1264
+ } else if (envDetection.suggestedOutputDir === "build" && existsSync5(join5(result.projectPath, "build"))) {
1265
+ finalOutputDir = join5(result.projectPath, "build");
1266
+ } else if (existsSync5(publicDir)) {
1267
+ finalOutputDir = publicDir;
1268
+ } else if (existsSync5(distDir)) {
1269
+ finalOutputDir = distDir;
1270
+ } else {
1271
+ finalOutputDir = publicDir;
1272
+ }
1273
+ }
1274
+ result.outputDir = finalOutputDir;
1275
+ console.log(chalk5.gray(` Output directory: ${finalOutputDir}`));
1276
+ transaction = new Transaction({
1277
+ projectPath: result.projectPath,
1278
+ outputDir: relative2(result.projectPath, finalOutputDir) || void 0,
1279
+ verbose: false
1280
+ });
1281
+ const pwaFiles = [...PWA_FILES_TO_REMOVE];
1282
+ if (existsSync5(finalOutputDir)) {
1283
+ const workboxFiles = await glob3("workbox-*.js", {
1284
+ cwd: finalOutputDir,
1285
+ absolute: true
1286
+ });
1287
+ pwaFiles.push(...workboxFiles.map((f) => relative2(finalOutputDir, f)));
1288
+ }
1289
+ if (!skipFiles) {
1290
+ console.log(chalk5.blue("\u{1F5D1}\uFE0F Removing PWA files..."));
1291
+ for (const file of pwaFiles) {
1292
+ const filePath = join5(finalOutputDir, file);
1293
+ if (existsSync5(filePath)) {
1294
+ try {
1295
+ const fileRelative = relative2(result.projectPath, filePath);
1296
+ if (fileRelative && !fileRelative.startsWith("..")) {
1297
+ transaction.backupFile(fileRelative);
1298
+ }
1299
+ rmSync2(filePath, { force: true });
1300
+ result.filesRemoved.push(file);
1301
+ console.log(chalk5.green(` \u2713 Removed ${file}`));
1302
+ } catch (error) {
1303
+ const errorMessage = error instanceof Error ? error.message : String(error);
1304
+ result.warnings.push(`Failed to remove ${file}: ${errorMessage}`);
1305
+ console.log(chalk5.yellow(` \u26A0 Failed to remove ${file}: ${errorMessage}`));
1306
+ }
1307
+ }
1308
+ }
1309
+ if (result.filesRemoved.length === 0) {
1310
+ console.log(chalk5.gray(" No PWA files found to remove"));
1311
+ } else {
1312
+ console.log(chalk5.green(`\u2713 Removed ${result.filesRemoved.length} file(s)`));
1313
+ }
1314
+ }
1315
+ if (!skipHtmlRestore) {
1316
+ console.log(chalk5.blue("\u{1F489} Restoring HTML files..."));
1317
+ const htmlFiles = await glob3("**/*.html", {
1318
+ cwd: result.projectPath,
1319
+ ignore: ["**/node_modules/**", "**/.next/**", "**/.nuxt/**"],
1320
+ absolute: true
1321
+ });
1322
+ if (htmlFiles.length > 0) {
1323
+ console.log(chalk5.gray(` Found ${htmlFiles.length} HTML file(s)`));
1324
+ for (const htmlFile of htmlFiles) {
1325
+ try {
1326
+ const htmlRelative = relative2(result.projectPath, htmlFile);
1327
+ if (htmlRelative && !htmlRelative.startsWith("..")) {
1328
+ transaction.backupFile(htmlRelative);
1329
+ }
1330
+ const htmlContent = readFileSync3(htmlFile, "utf-8");
1331
+ const { html: restoredHtml, removed } = await removeMetaTags(htmlContent);
1332
+ if (removed.length > 0) {
1333
+ writeFileSync2(htmlFile, restoredHtml, "utf-8");
1334
+ result.htmlFilesRestored++;
1335
+ console.log(chalk5.green(` \u2713 Restored ${htmlRelative} (removed ${removed.length} PWA element(s))`));
1336
+ }
1337
+ } catch (error) {
1338
+ const errorMessage = error instanceof Error ? error.message : String(error);
1339
+ result.warnings.push(`Failed to restore ${htmlFile}: ${errorMessage}`);
1340
+ console.log(chalk5.yellow(` \u26A0 Failed to restore ${htmlFile}: ${errorMessage}`));
1341
+ }
1342
+ }
1343
+ if (result.htmlFilesRestored > 0) {
1344
+ console.log(chalk5.green(`\u2713 Restored ${result.htmlFilesRestored} HTML file(s)`));
1345
+ } else {
1346
+ console.log(chalk5.gray(" No PWA meta-tags found in HTML files"));
1347
+ }
1348
+ } else {
1349
+ console.log(chalk5.gray(" No HTML files found"));
1350
+ }
1351
+ }
1352
+ result.success = result.errors.length === 0;
1353
+ if (result.success) {
1354
+ if (transaction) {
1355
+ transaction.commit();
1356
+ }
1357
+ console.log(chalk5.green("\n\u2705 PWA removal completed successfully!"));
1358
+ console.log(chalk5.gray(` Files removed: ${result.filesRemoved.length}`));
1359
+ console.log(chalk5.gray(` HTML files restored: ${result.htmlFilesRestored}`));
1360
+ } else {
1361
+ if (transaction) {
1362
+ console.log(chalk5.yellow("\n\u{1F504} Rolling back changes due to errors..."));
1363
+ transaction.rollback();
1364
+ }
1365
+ console.log(chalk5.red(`
1366
+ \u274C PWA removal completed with ${result.errors.length} error(s)`));
1367
+ }
1368
+ return result;
1369
+ } catch (error) {
1370
+ const errorMessage = error instanceof Error ? error.message : String(error);
1371
+ const errorCode = "E9001" /* UNEXPECTED_ERROR */;
1372
+ const formattedError = formatError(errorCode, errorMessage);
1373
+ result.errors.push(formattedError);
1374
+ console.log(chalk5.red(`\u2717 ${formattedError}`));
1375
+ if (transaction) {
1376
+ console.log(chalk5.yellow("\n\u{1F504} Rolling back changes due to unexpected error..."));
1377
+ transaction.rollback();
1378
+ }
1379
+ return result;
1380
+ }
1381
+ }
1382
+
1153
1383
  // src/index.ts
1154
- import { scanProject as scanProject2 } from "@julien-lin/universal-pwa-core";
1384
+ import { scanProject as scanProject3 } from "@julien-lin/universal-pwa-core";
1155
1385
 
1156
1386
  // src/prompts.ts
1157
1387
  import inquirer from "inquirer";
1158
- import { existsSync as existsSync6 } from "fs";
1159
- import { join as join6, extname } from "path";
1160
- import chalk5 from "chalk";
1388
+ import { existsSync as existsSync7 } from "fs";
1389
+ import { join as join7, extname } from "path";
1390
+ import chalk6 from "chalk";
1161
1391
 
1162
1392
  // src/utils/suggestions.ts
1163
- import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
1164
- import { join as join5 } from "path";
1393
+ import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
1394
+ import { join as join6 } from "path";
1165
1395
  import { globSync } from "glob";
1166
1396
  function suggestAppName(projectPath, _framework) {
1167
- const packageJsonPath = join5(projectPath, "package.json");
1168
- if (existsSync5(packageJsonPath)) {
1397
+ const packageJsonPath = join6(projectPath, "package.json");
1398
+ if (existsSync6(packageJsonPath)) {
1169
1399
  try {
1170
- const packageContent = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
1400
+ const packageContent = JSON.parse(readFileSync4(packageJsonPath, "utf-8"));
1171
1401
  const name = packageContent.displayName || packageContent.productName || packageContent.name;
1172
1402
  if (name && typeof name === "string" && name.trim().length > 0) {
1173
1403
  const cleanName = name.trim();
@@ -1183,10 +1413,10 @@ function suggestAppName(projectPath, _framework) {
1183
1413
  } catch {
1184
1414
  }
1185
1415
  }
1186
- const composerJsonPath = join5(projectPath, "composer.json");
1187
- if (existsSync5(composerJsonPath)) {
1416
+ const composerJsonPath = join6(projectPath, "composer.json");
1417
+ if (existsSync6(composerJsonPath)) {
1188
1418
  try {
1189
- const composerContent = JSON.parse(readFileSync3(composerJsonPath, "utf-8"));
1419
+ const composerContent = JSON.parse(readFileSync4(composerJsonPath, "utf-8"));
1190
1420
  if (composerContent.name && typeof composerContent.name === "string") {
1191
1421
  const parts = composerContent.name.split("/");
1192
1422
  const packageName = parts[parts.length - 1] || composerContent.name;
@@ -1234,8 +1464,8 @@ function suggestIconPath(projectPath) {
1234
1464
  "static/icon.png"
1235
1465
  ];
1236
1466
  for (const iconPath of commonIconPaths) {
1237
- const fullPath = join5(projectPath, iconPath);
1238
- if (existsSync5(fullPath)) {
1467
+ const fullPath = join6(projectPath, iconPath);
1468
+ if (existsSync6(fullPath)) {
1239
1469
  suggestions.push({
1240
1470
  path: iconPath,
1241
1471
  confidence: "high",
@@ -1302,18 +1532,18 @@ function suggestColors(_projectPath, framework, _iconPath) {
1302
1532
  };
1303
1533
  }
1304
1534
  function suggestConfiguration(projectPath, framework, _architecture) {
1305
- const distDir = join5(projectPath, "dist");
1306
- const buildDir = join5(projectPath, "build");
1307
- const publicDir = join5(projectPath, "public");
1535
+ const distDir = join6(projectPath, "dist");
1536
+ const buildDir = join6(projectPath, "build");
1537
+ const publicDir = join6(projectPath, "public");
1308
1538
  let outputDir = "public";
1309
1539
  let reason = "Default output directory";
1310
- if (existsSync5(distDir)) {
1540
+ if (existsSync6(distDir)) {
1311
1541
  outputDir = "dist";
1312
1542
  reason = "dist/ directory detected (production build)";
1313
- } else if (existsSync5(buildDir)) {
1543
+ } else if (existsSync6(buildDir)) {
1314
1544
  outputDir = "build";
1315
1545
  reason = "build/ directory detected (production build)";
1316
- } else if (existsSync5(publicDir)) {
1546
+ } else if (existsSync6(publicDir)) {
1317
1547
  outputDir = "public";
1318
1548
  reason = "public/ directory detected";
1319
1549
  } else if (framework === "wordpress" || framework === "drupal" || framework === "joomla") {
@@ -1345,15 +1575,15 @@ async function promptInitOptions(projectPath, framework, architecture = null) {
1345
1575
  const defaultShortName = suggestions.name.shortName;
1346
1576
  const defaultIconSource = suggestions.icons.length > 0 ? suggestions.icons[0].path : void 0;
1347
1577
  const envDetection = detectEnvironment(projectPath, framework);
1348
- console.log(chalk5.blue("\n\u{1F4CB} Configuration PWA\n"));
1578
+ console.log(chalk6.blue("\n\u{1F4CB} Configuration PWA\n"));
1349
1579
  if (suggestions.name.confidence === "high") {
1350
- console.log(chalk5.gray(`\u{1F4A1} Suggestion: Nom "${suggestions.name.name}" (${suggestions.name.source})`));
1580
+ console.log(chalk6.gray(`\u{1F4A1} Suggestion: Nom "${suggestions.name.name}" (${suggestions.name.source})`));
1351
1581
  }
1352
1582
  if (suggestions.icons.length > 0) {
1353
- console.log(chalk5.gray(`\u{1F4A1} Suggestion: ${suggestions.icons.length} ic\xF4ne(s) trouv\xE9e(s)`));
1583
+ console.log(chalk6.gray(`\u{1F4A1} Suggestion: ${suggestions.icons.length} ic\xF4ne(s) trouv\xE9e(s)`));
1354
1584
  }
1355
1585
  if (suggestions.colors.confidence === "high") {
1356
- console.log(chalk5.gray(`\u{1F4A1} Suggestion: Couleurs bas\xE9es sur ${framework}`));
1586
+ console.log(chalk6.gray(`\u{1F4A1} Suggestion: Couleurs bas\xE9es sur ${framework}`));
1357
1587
  }
1358
1588
  const environmentAnswer = await inquirer.prompt([
1359
1589
  {
@@ -1376,7 +1606,7 @@ async function promptInitOptions(projectPath, framework, architecture = null) {
1376
1606
  }
1377
1607
  ]);
1378
1608
  if (envDetection.indicators.length > 0) {
1379
- console.log(chalk5.gray(` ${envDetection.indicators.join(", ")}`));
1609
+ console.log(chalk6.gray(` ${envDetection.indicators.join(", ")}`));
1380
1610
  }
1381
1611
  const configAnswers = await inquirer.prompt([
1382
1612
  {
@@ -1421,8 +1651,8 @@ async function promptInitOptions(projectPath, framework, architecture = null) {
1421
1651
  if (!input || input.trim().length === 0) {
1422
1652
  return true;
1423
1653
  }
1424
- const fullPath = existsSync6(input) ? input : join6(projectPath, input);
1425
- if (!existsSync6(fullPath)) {
1654
+ const fullPath = existsSync7(input) ? input : join7(projectPath, input);
1655
+ if (!existsSync7(fullPath)) {
1426
1656
  const suggestions2 = [
1427
1657
  "public/logo.png",
1428
1658
  "src/assets/icon.png",
@@ -1515,7 +1745,7 @@ Suggestions: ${suggestions2}`;
1515
1745
  // package.json
1516
1746
  var package_default = {
1517
1747
  name: "@julien-lin/universal-pwa-cli",
1518
- version: "1.3.2",
1748
+ version: "1.3.3",
1519
1749
  description: "CLI to transform any web project into a PWA",
1520
1750
  keywords: [
1521
1751
  "pwa",
@@ -1604,14 +1834,14 @@ program.command("init").description("Initialize PWA in your project").option("-p
1604
1834
  const hasOptions = options.name || options.shortName || options.iconSource || options.themeColor || options.backgroundColor || options.skipIcons !== void 0;
1605
1835
  let finalOptions = { ...options };
1606
1836
  if (!hasOptions) {
1607
- console.log(chalk6.blue("\u{1F50D} Scanning project..."));
1608
- const scanResult = await scanProject2({
1837
+ console.log(chalk7.blue("\u{1F50D} Scanning project..."));
1838
+ const scanResult = await scanProject3({
1609
1839
  projectPath,
1610
1840
  includeAssets: false,
1611
1841
  includeArchitecture: false
1612
1842
  });
1613
- console.log(chalk6.green(`\u2713 Framework detected: ${scanResult.framework.framework ?? "Unknown"}`));
1614
- console.log(chalk6.green(`\u2713 Architecture: ${scanResult.architecture.architecture}`));
1843
+ console.log(chalk7.green(`\u2713 Framework detected: ${scanResult.framework.framework ?? "Unknown"}`));
1844
+ console.log(chalk7.green(`\u2713 Architecture: ${scanResult.architecture.architecture}`));
1615
1845
  const promptAnswers = await promptInitOptions(
1616
1846
  projectPath,
1617
1847
  scanResult.framework.framework,
@@ -1626,10 +1856,10 @@ program.command("init").description("Initialize PWA in your project").option("-p
1626
1856
  finalOptions.outputDir = "build";
1627
1857
  } else {
1628
1858
  finalOptions.outputDir = "dist";
1629
- console.log(chalk6.yellow("\u26A0 dist/ directory not found. Run build first:"));
1630
- console.log(chalk6.gray(" npm run build"));
1631
- console.log(chalk6.gray(" or"));
1632
- console.log(chalk6.gray(" pnpm build"));
1859
+ console.log(chalk7.yellow("\u26A0 dist/ directory not found. Run build first:"));
1860
+ console.log(chalk7.gray(" npm run build"));
1861
+ console.log(chalk7.gray(" or"));
1862
+ console.log(chalk7.gray(" pnpm build"));
1633
1863
  }
1634
1864
  } else {
1635
1865
  finalOptions.outputDir = "public";
@@ -1661,7 +1891,7 @@ program.command("init").description("Initialize PWA in your project").option("-p
1661
1891
  });
1662
1892
  process.exit(result.success ? 0 : 1);
1663
1893
  } catch (error) {
1664
- console.error(chalk6.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
1894
+ console.error(chalk7.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
1665
1895
  process.exit(1);
1666
1896
  }
1667
1897
  });
@@ -1674,31 +1904,31 @@ program.command("preview").description("Preview PWA setup").option("-p, --projec
1674
1904
  });
1675
1905
  process.exit(result.success ? 0 : 1);
1676
1906
  } catch (error) {
1677
- console.error(chalk6.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
1907
+ console.error(chalk7.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
1678
1908
  process.exit(1);
1679
1909
  }
1680
1910
  });
1681
1911
  program.command("scan").description("Scan project and detect framework/architecture").option("-p, --project-path <path>", "Project path", process.cwd()).action(async (options) => {
1682
1912
  try {
1683
- console.log(chalk6.blue("\u{1F50D} Scanning project..."));
1684
- const result = await scanProject2({
1913
+ console.log(chalk7.blue("\u{1F50D} Scanning project..."));
1914
+ const result = await scanProject3({
1685
1915
  projectPath: options.projectPath ?? process.cwd(),
1686
1916
  includeAssets: true,
1687
1917
  includeArchitecture: true
1688
1918
  });
1689
- console.log(chalk6.green(`
1919
+ console.log(chalk7.green(`
1690
1920
  \u2713 Framework: ${result.framework.framework ?? "Unknown"}`));
1691
- console.log(chalk6.green(`\u2713 Architecture: ${result.architecture.architecture}`));
1692
- console.log(chalk6.green(`\u2713 Build Tool: ${result.architecture.buildTool ?? "Unknown"}`));
1693
- console.log(chalk6.gray(`
1921
+ console.log(chalk7.green(`\u2713 Architecture: ${result.architecture.architecture}`));
1922
+ console.log(chalk7.green(`\u2713 Build Tool: ${result.architecture.buildTool ?? "Unknown"}`));
1923
+ console.log(chalk7.gray(`
1694
1924
  Assets found:`));
1695
- console.log(chalk6.gray(` - JavaScript: ${result.assets.javascript.length} files`));
1696
- console.log(chalk6.gray(` - CSS: ${result.assets.css.length} files`));
1697
- console.log(chalk6.gray(` - Images: ${result.assets.images.length} files`));
1698
- console.log(chalk6.gray(` - Fonts: ${result.assets.fonts.length} files`));
1925
+ console.log(chalk7.gray(` - JavaScript: ${result.assets.javascript.length} files`));
1926
+ console.log(chalk7.gray(` - CSS: ${result.assets.css.length} files`));
1927
+ console.log(chalk7.gray(` - Images: ${result.assets.images.length} files`));
1928
+ console.log(chalk7.gray(` - Fonts: ${result.assets.fonts.length} files`));
1699
1929
  process.exit(0);
1700
1930
  } catch (error) {
1701
- console.error(chalk6.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
1931
+ console.error(chalk7.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
1702
1932
  process.exit(1);
1703
1933
  }
1704
1934
  });
@@ -1711,7 +1941,22 @@ program.command("verify").description("Verify PWA setup and check for missing fi
1711
1941
  });
1712
1942
  process.exit(result.success ? 0 : 1);
1713
1943
  } catch (error) {
1714
- console.error(chalk6.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
1944
+ console.error(chalk7.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
1945
+ process.exit(1);
1946
+ }
1947
+ });
1948
+ program.command("remove").description("Remove PWA files and restore HTML files").option("-p, --project-path <path>", "Project path", process.cwd()).option("-o, --output-dir <dir>", "Output directory (auto-detected if not specified)").option("--skip-html-restore", "Skip HTML file restoration").option("--skip-files", "Skip PWA file removal").option("--force", "Force removal without confirmation").action(async (options) => {
1949
+ try {
1950
+ const result = await removeCommand({
1951
+ projectPath: options.projectPath,
1952
+ outputDir: options.outputDir,
1953
+ skipHtmlRestore: options.skipHtmlRestore,
1954
+ skipFiles: options.skipFiles,
1955
+ force: options.force
1956
+ });
1957
+ process.exit(result.success ? 0 : 1);
1958
+ } catch (error) {
1959
+ console.error(chalk7.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
1715
1960
  process.exit(1);
1716
1961
  }
1717
1962
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@julien-lin/universal-pwa-cli",
3
- "version": "1.3.2",
3
+ "version": "1.3.3",
4
4
  "description": "CLI to transform any web project into a PWA",
5
5
  "keywords": [
6
6
  "pwa",
@@ -62,7 +62,7 @@
62
62
  "inquirer": "^12.0.0",
63
63
  "pino": "^9.14.0",
64
64
  "zod": "^4.2.1",
65
- "@julien-lin/universal-pwa-core": "^1.3.2"
65
+ "@julien-lin/universal-pwa-core": "^1.3.3"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@vitest/coverage-v8": "^2.1.4",