pake-cli 3.6.1 โ†’ 3.6.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/cli.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import chalk from 'chalk';
3
- import { InvalidArgumentError, program, Option } from 'commander';
4
2
  import log from 'loglevel';
3
+ import updateNotifier from 'update-notifier';
5
4
  import path from 'path';
6
5
  import fsExtra from 'fs-extra';
7
6
  import { fileURLToPath } from 'url';
7
+ import chalk from 'chalk';
8
8
  import prompts from 'prompts';
9
9
  import os from 'os';
10
10
  import { execa, execaSync } from 'execa';
@@ -14,16 +14,15 @@ import dns from 'dns';
14
14
  import http from 'http';
15
15
  import { promisify } from 'util';
16
16
  import fs from 'fs';
17
- import updateNotifier from 'update-notifier';
18
- import axios from 'axios';
19
17
  import { dir } from 'tmp-promise';
20
18
  import { fileTypeFromBuffer } from 'file-type';
21
19
  import icongen from 'icon-gen';
22
20
  import sharp from 'sharp';
23
21
  import * as psl from 'psl';
22
+ import { InvalidArgumentError, program as program$1, Option } from 'commander';
24
23
 
25
24
  var name = "pake-cli";
26
- var version = "3.6.1";
25
+ var version = "3.6.3";
27
26
  var description = "๐Ÿคฑ๐Ÿป Turn any webpage into a desktop app with one command. ๐Ÿคฑ๐Ÿป ไธ€้”ฎๆ‰“ๅŒ…็ฝ‘้กต็”Ÿๆˆ่ฝป้‡ๆกŒ้ขๅบ”็”จใ€‚";
28
27
  var engines = {
29
28
  node: ">=18.0.0"
@@ -58,7 +57,6 @@ var scripts = {
58
57
  build: "tauri build",
59
58
  "build:debug": "tauri build --debug",
60
59
  "build:mac": "tauri build --target universal-apple-darwin",
61
- "build:config": "chmod +x scripts/configure-tauri.mjs && node scripts/configure-tauri.mjs",
62
60
  analyze: "cd src-tauri && cargo bloat --release --crates",
63
61
  tauri: "tauri",
64
62
  cli: "cross-env NODE_ENV=development rollup -c -w",
@@ -75,7 +73,6 @@ var license = "MIT";
75
73
  var dependencies = {
76
74
  "@tauri-apps/api": "^2.9.0",
77
75
  "@tauri-apps/cli": "^2.9.0",
78
- axios: "^1.12.2",
79
76
  chalk: "^5.6.2",
80
77
  commander: "^12.1.0",
81
78
  execa: "^9.6.0",
@@ -108,7 +105,8 @@ var devDependencies = {
108
105
  rollup: "^4.52.5",
109
106
  "rollup-plugin-typescript2": "^0.36.0",
110
107
  tslib: "^2.8.1",
111
- typescript: "^5.9.3"
108
+ typescript: "^5.9.3",
109
+ vitest: "^4.0.15"
112
110
  };
113
111
  var packageJson = {
114
112
  name: name,
@@ -379,7 +377,12 @@ async function installRust() {
379
377
  }
380
378
  catch (error) {
381
379
  spinner.fail(chalk.red('โœ• Rust installation failed!'));
382
- console.error(error.message);
380
+ if (error instanceof Error) {
381
+ console.error(error.message);
382
+ }
383
+ else {
384
+ console.error(error);
385
+ }
383
386
  process.exit(1);
384
387
  }
385
388
  }
@@ -421,6 +424,9 @@ function generateSafeFilename(name) {
421
424
  .replace(/\.+$/g, '')
422
425
  .slice(0, 255);
423
426
  }
427
+ function getSafeAppName(name) {
428
+ return generateSafeFilename(name).toLowerCase();
429
+ }
424
430
  function generateLinuxPackageName(name) {
425
431
  return name
426
432
  .toLowerCase()
@@ -448,12 +454,6 @@ function generateIdentifierSafeName(name) {
448
454
  return cleaned;
449
455
  }
450
456
 
451
- /**
452
- * Helper function to generate safe lowercase app name for file paths
453
- */
454
- function getSafeAppName(name) {
455
- return generateSafeFilename(name).toLowerCase();
456
- }
457
457
  async function mergeConfig(url, options, tauriConf) {
458
458
  // Ensure .pake directory exists and copy source templates if needed
459
459
  const srcTauriDir = path.join(npmDirectory, 'src-tauri');
@@ -474,7 +474,7 @@ async function mergeConfig(url, options, tauriConf) {
474
474
  await fsExtra.copy(sourcePath, destPath);
475
475
  }
476
476
  }));
477
- const { width, height, fullscreen, maximize, hideTitleBar, alwaysOnTop, appVersion, darkMode, disabledWebShortcuts, activationShortcut, userAgent, showSystemTray, systemTrayIcon, useLocalFile, identifier, name, resizable = true, inject, proxyUrl, installerLanguage, hideOnClose, incognito, title, wasm, enableDragDrop, multiInstance, startToTray, forceInternalNavigation, zoom, minWidth, minHeight, ignoreCertificateErrors, } = options;
477
+ const { width, height, fullscreen, maximize, hideTitleBar, alwaysOnTop, appVersion, darkMode, disabledWebShortcuts, activationShortcut, userAgent, showSystemTray, systemTrayIcon, useLocalFile, identifier, name = 'pake-app', resizable = true, inject, proxyUrl, installerLanguage, hideOnClose, incognito, title, wasm, enableDragDrop, multiInstance, startToTray, forceInternalNavigation, zoom, minWidth, minHeight, ignoreCertificateErrors, } = options;
478
478
  const { platform } = process;
479
479
  const platformHideOnClose = hideOnClose ?? platform === 'darwin';
480
480
  const tauriConfWindowOptions = {
@@ -490,7 +490,7 @@ async function mergeConfig(url, options, tauriConf) {
490
490
  disabled_web_shortcuts: disabledWebShortcuts,
491
491
  hide_on_close: platformHideOnClose,
492
492
  incognito: incognito,
493
- title: title || null,
493
+ title: title,
494
494
  enable_wasm: wasm,
495
495
  enable_drag_drop: enableDragDrop,
496
496
  start_to_tray: startToTray && showSystemTray,
@@ -555,10 +555,13 @@ async function mergeConfig(url, options, tauriConf) {
555
555
  const identifier = `com.pake.${appNameSafe}`;
556
556
  const desktopFileName = `${identifier}.desktop`;
557
557
  // Create desktop file content
558
+ // Determine if title contains Chinese characters for Name[zh_CN]
559
+ const chineseName = title && /[\u4e00-\u9fa5]/.test(title) ? title : null;
558
560
  const desktopContent = `[Desktop Entry]
559
561
  Version=1.0
560
562
  Type=Application
561
563
  Name=${name}
564
+ ${chineseName ? `Name[zh_CN]=${chineseName}` : ''}
562
565
  Comment=${name}
563
566
  Exec=pake-${appNameSafe}
564
567
  Icon=${appNameSafe}_512
@@ -822,7 +825,9 @@ class BaseBuilder {
822
825
  }
823
826
  catch (error) {
824
827
  // If installation times out and we haven't tried the mirror yet, retry with mirror
825
- if (error.message?.includes('timed out') && !usedMirror) {
828
+ if (error instanceof Error &&
829
+ error.message.includes('timed out') &&
830
+ !usedMirror) {
826
831
  spinner.fail(chalk.yellow('Installation timed out, retrying with CN mirror...'));
827
832
  logger.info('โœบ Retrying installation with CN mirror for better speed...');
828
833
  const retrySpinner = getSpinner('Retrying installation...');
@@ -851,10 +856,18 @@ class BaseBuilder {
851
856
  await this.buildAndCopy(url, this.options.targets);
852
857
  }
853
858
  async start(url) {
859
+ logger.info('Pake dev server starting...');
854
860
  await mergeConfig(url, this.options, tauriConfig);
861
+ const packageManager = await this.detectPackageManager();
862
+ const configPath = path.join(npmDirectory, 'src-tauri', '.pake', 'tauri.conf.json');
863
+ const features = this.getBuildFeatures();
864
+ const featureArgs = features.length > 0 ? `--features ${features.join(',')}` : '';
865
+ const argSeparator = packageManager === 'npm' ? ' --' : '';
866
+ const command = `cd "${npmDirectory}" && ${packageManager} run tauri${argSeparator} dev --config "${configPath}" ${featureArgs}`;
867
+ await shellExec(command);
855
868
  }
856
869
  async buildAndCopy(url, target) {
857
- const { name } = this.options;
870
+ const { name = 'pake-app' } = this.options;
858
871
  await mergeConfig(url, this.options, tauriConfig);
859
872
  // Detect available package manager
860
873
  const packageManager = await this.detectPackageManager();
@@ -1121,7 +1134,7 @@ class MacBuilder extends BaseBuilder {
1121
1134
  this.buildArch = validArchs.includes(options.targets || '')
1122
1135
  ? options.targets
1123
1136
  : 'auto';
1124
- if (process.env.PAKE_CREATE_APP === '1') {
1137
+ if (options.iterativeBuild || process.env.PAKE_CREATE_APP === '1') {
1125
1138
  this.buildFormat = 'app';
1126
1139
  }
1127
1140
  else {
@@ -1130,7 +1143,7 @@ class MacBuilder extends BaseBuilder {
1130
1143
  this.options.targets = this.buildFormat;
1131
1144
  }
1132
1145
  getFileName() {
1133
- const { name } = this.options;
1146
+ const { name = 'pake-app' } = this.options;
1134
1147
  if (this.buildFormat === 'app') {
1135
1148
  return name;
1136
1149
  }
@@ -1249,7 +1262,7 @@ class LinuxBuilder extends BaseBuilder {
1249
1262
  this.options.targets = this.buildFormat;
1250
1263
  }
1251
1264
  getFileName() {
1252
- const { name, targets } = this.options;
1265
+ const { name = 'pake-app', targets } = this.options;
1253
1266
  const version = tauriConfig.version;
1254
1267
  let arch;
1255
1268
  if (this.buildArch === 'arm64') {
@@ -1283,7 +1296,7 @@ class LinuxBuilder extends BaseBuilder {
1283
1296
  getBuildCommand(packageManager = 'pnpm') {
1284
1297
  const configPath = path.join('src-tauri', '.pake', 'tauri.conf.json');
1285
1298
  const buildTarget = this.buildArch === 'arm64'
1286
- ? this.getTauriTarget(this.buildArch, 'linux')
1299
+ ? (this.getTauriTarget(this.buildArch, 'linux') ?? undefined)
1287
1300
  : undefined;
1288
1301
  let fullCommand = this.buildBaseCommand(packageManager, configPath, buildTarget);
1289
1302
  const features = this.getBuildFeatures();
@@ -1341,48 +1354,6 @@ class BuilderProvider {
1341
1354
  }
1342
1355
  }
1343
1356
 
1344
- const DEFAULT_PAKE_OPTIONS = {
1345
- icon: '',
1346
- height: 780,
1347
- width: 1200,
1348
- fullscreen: false,
1349
- maximize: false,
1350
- hideTitleBar: false,
1351
- alwaysOnTop: false,
1352
- appVersion: '1.0.0',
1353
- darkMode: false,
1354
- disabledWebShortcuts: false,
1355
- activationShortcut: '',
1356
- userAgent: '',
1357
- showSystemTray: false,
1358
- multiArch: false,
1359
- targets: 'deb',
1360
- useLocalFile: false,
1361
- systemTrayIcon: '',
1362
- proxyUrl: '',
1363
- debug: false,
1364
- inject: [],
1365
- installerLanguage: 'en-US',
1366
- hideOnClose: undefined, // Platform-specific: true for macOS, false for others
1367
- incognito: false,
1368
- wasm: false,
1369
- enableDragDrop: false,
1370
- keepBinary: false,
1371
- multiInstance: false,
1372
- startToTray: false,
1373
- forceInternalNavigation: false,
1374
- zoom: 100,
1375
- minWidth: 0,
1376
- minHeight: 0,
1377
- ignoreCertificateErrors: false,
1378
- };
1379
-
1380
- async function checkUpdateTips() {
1381
- updateNotifier({ pkg: packageJson, updateCheckInterval: 1000 * 60 }).notify({
1382
- isGlobal: true,
1383
- });
1384
- }
1385
-
1386
1357
  const ICON_CONFIG = {
1387
1358
  minFileSize: 100,
1388
1359
  supportedFormats: ['png', 'ico', 'jpeg', 'jpg', 'webp', 'icns'],
@@ -1454,7 +1425,57 @@ async function preprocessIcon(inputPath) {
1454
1425
  return outputPath;
1455
1426
  }
1456
1427
  catch (error) {
1457
- logger.warn(`Failed to add background to icon: ${error.message}`);
1428
+ if (error instanceof Error) {
1429
+ logger.warn(`Failed to add background to icon: ${error.message}`);
1430
+ }
1431
+ return inputPath;
1432
+ }
1433
+ }
1434
+ /**
1435
+ * Applies macOS squircle mask to icon
1436
+ */
1437
+ async function applyMacOSMask(inputPath) {
1438
+ try {
1439
+ const { path: tempDir } = await dir();
1440
+ const outputPath = path.join(tempDir, 'icon-macos-rounded.png');
1441
+ // 1. Create a 1024x1024 rounded rect mask
1442
+ // rx="224" is closer to the smooth Apple squircle look for 1024px
1443
+ const mask = Buffer.from('<svg width="1024" height="1024"><rect x="0" y="0" width="1024" height="1024" rx="224" ry="224" fill="white"/></svg>');
1444
+ // 2. Load input, resize to 1024, apply mask
1445
+ const maskedBuffer = await sharp(inputPath)
1446
+ .resize(1024, 1024, {
1447
+ fit: 'contain',
1448
+ background: { r: 0, g: 0, b: 0, alpha: 0 },
1449
+ })
1450
+ .composite([
1451
+ {
1452
+ input: mask,
1453
+ blend: 'dest-in',
1454
+ },
1455
+ ])
1456
+ .png()
1457
+ .toBuffer();
1458
+ // 3. Resize to 840x840 (~18% padding) to solve "too big" visual issue
1459
+ // Native MacOS icons often leave some breathing room
1460
+ await sharp(maskedBuffer)
1461
+ .resize(840, 840, {
1462
+ fit: 'contain',
1463
+ background: { r: 0, g: 0, b: 0, alpha: 0 },
1464
+ })
1465
+ .extend({
1466
+ top: 92,
1467
+ bottom: 92,
1468
+ left: 92,
1469
+ right: 92,
1470
+ background: { r: 0, g: 0, b: 0, alpha: 0 },
1471
+ })
1472
+ .toFile(outputPath);
1473
+ return outputPath;
1474
+ }
1475
+ catch (error) {
1476
+ if (error instanceof Error) {
1477
+ logger.warn(`Failed to apply macOS mask: ${error.message}`);
1478
+ }
1458
1479
  return inputPath;
1459
1480
  }
1460
1481
  }
@@ -1496,7 +1517,8 @@ async function convertIconFormat(inputPath, appName) {
1496
1517
  return outputPath;
1497
1518
  }
1498
1519
  // macOS
1499
- await icongen(processedInputPath, platformOutputDir, {
1520
+ const macIconPath = await applyMacOSMask(processedInputPath);
1521
+ await icongen(macIconPath, platformOutputDir, {
1500
1522
  report: false,
1501
1523
  icns: { name: iconName, sizes: PLATFORM_CONFIG.macos.sizes },
1502
1524
  });
@@ -1504,7 +1526,9 @@ async function convertIconFormat(inputPath, appName) {
1504
1526
  return (await fsExtra.pathExists(outputPath)) ? outputPath : null;
1505
1527
  }
1506
1528
  catch (error) {
1507
- logger.warn(`Icon format conversion failed: ${error.message}`);
1529
+ if (error instanceof Error) {
1530
+ logger.warn(`Icon format conversion failed: ${error.message}`);
1531
+ }
1508
1532
  return null;
1509
1533
  }
1510
1534
  }
@@ -1642,14 +1666,18 @@ async function tryGetFavicon(url, appName) {
1642
1666
  }
1643
1667
  }
1644
1668
  catch (error) {
1645
- logger.debug(`Icon service ${serviceUrl} failed: ${error.message}`);
1646
- // Platform-specific error handling
1669
+ if (error instanceof Error) {
1670
+ logger.debug(`Icon service ${serviceUrl} failed: ${error.message}`);
1671
+ }
1672
+ // Network error handling
1647
1673
  if ((IS_LINUX || IS_WIN) && error.code === 'ENOTFOUND') {
1648
- logger.debug(`DNS resolution failed for ${serviceUrl}, trying next service...`);
1674
+ return null;
1649
1675
  }
1650
- // Windows-specific icon conversion errors
1651
- if (IS_WIN && error.message.includes('icongen')) {
1652
- logger.debug(`Windows icon conversion failed for ${serviceUrl}, trying next service...`);
1676
+ // Icon generation error on Windows
1677
+ if (IS_WIN &&
1678
+ error instanceof Error &&
1679
+ error.message.includes('icongen')) {
1680
+ return null;
1653
1681
  }
1654
1682
  continue;
1655
1683
  }
@@ -1658,7 +1686,9 @@ async function tryGetFavicon(url, appName) {
1658
1686
  return null;
1659
1687
  }
1660
1688
  catch (error) {
1661
- logger.warn(`Failed to fetch favicon: ${error.message}`);
1689
+ if (error instanceof Error) {
1690
+ logger.warn(`Failed to fetch favicon: ${error.message}`);
1691
+ }
1662
1692
  return null;
1663
1693
  }
1664
1694
  }
@@ -1666,24 +1696,40 @@ async function tryGetFavicon(url, appName) {
1666
1696
  * Downloads icon from URL
1667
1697
  */
1668
1698
  async function downloadIcon(iconUrl, showSpinner = true, customTimeout) {
1699
+ const controller = new AbortController();
1700
+ const timeoutId = setTimeout(() => {
1701
+ controller.abort();
1702
+ }, customTimeout || 10000);
1669
1703
  try {
1670
- const response = await axios.get(iconUrl, {
1671
- responseType: 'arraybuffer',
1672
- timeout: customTimeout || 10000,
1704
+ const response = await fetch(iconUrl, {
1705
+ signal: controller.signal,
1673
1706
  });
1674
- const iconData = response.data;
1675
- if (!iconData || iconData.byteLength < ICON_CONFIG.minFileSize)
1707
+ clearTimeout(timeoutId);
1708
+ if (!response.ok) {
1709
+ if (response.status === 404 && !showSpinner) {
1710
+ return null;
1711
+ }
1712
+ throw new Error(`HTTP ${response.status} ${response.statusText}`);
1713
+ }
1714
+ const arrayBuffer = await response.arrayBuffer();
1715
+ if (!arrayBuffer || arrayBuffer.byteLength < ICON_CONFIG.minFileSize)
1676
1716
  return null;
1677
- const fileDetails = await fileTypeFromBuffer(iconData);
1717
+ const fileDetails = await fileTypeFromBuffer(arrayBuffer);
1678
1718
  if (!fileDetails ||
1679
1719
  !ICON_CONFIG.supportedFormats.includes(fileDetails.ext)) {
1680
1720
  return null;
1681
1721
  }
1682
- return await saveIconFile(iconData, fileDetails.ext);
1722
+ return await saveIconFile(arrayBuffer, fileDetails.ext);
1683
1723
  }
1684
1724
  catch (error) {
1685
- if (showSpinner && !(error.response?.status === 404)) {
1686
- throw error;
1725
+ clearTimeout(timeoutId);
1726
+ if (showSpinner) {
1727
+ if (error instanceof Error && error.name === 'AbortError') {
1728
+ logger.error('Icon download timed out!');
1729
+ }
1730
+ else {
1731
+ logger.error('Icon download failed!', error instanceof Error ? error.message : String(error));
1732
+ }
1687
1733
  }
1688
1734
  return null;
1689
1735
  }
@@ -1766,7 +1812,7 @@ async function handleOptions(options, url) {
1766
1812
  if (name && platform === 'linux') {
1767
1813
  name = generateLinuxPackageName(name);
1768
1814
  }
1769
- if (!isValidName(name, platform)) {
1815
+ if (name && !isValidName(name, platform)) {
1770
1816
  const LINUX_NAME_ERROR = `โœ• Name should only include lowercase letters, numbers, and dashes (not leading dashes). Examples: com-123-xxx, 123pan, pan123, weread, we-read, 123.`;
1771
1817
  const DEFAULT_NAME_ERROR = `โœ• Name should only include letters, numbers, dashes, and spaces (not leading dashes and spaces). Examples: 123pan, 123Pan, Pan123, weread, WeRead, WERead, we-read, We Read, 123.`;
1772
1818
  const errorMsg = platform === 'linux' ? LINUX_NAME_ERROR : DEFAULT_NAME_ERROR;
@@ -1785,10 +1831,58 @@ async function handleOptions(options, url) {
1785
1831
  identifier: getIdentifier(url),
1786
1832
  };
1787
1833
  const iconPath = await handleIcon(appOptions, url);
1788
- appOptions.icon = iconPath || undefined;
1834
+ appOptions.icon = iconPath || '';
1789
1835
  return appOptions;
1790
1836
  }
1791
1837
 
1838
+ const DEFAULT_PAKE_OPTIONS = {
1839
+ icon: '',
1840
+ height: 780,
1841
+ width: 1200,
1842
+ fullscreen: false,
1843
+ maximize: false,
1844
+ hideTitleBar: false,
1845
+ alwaysOnTop: false,
1846
+ appVersion: '1.0.0',
1847
+ darkMode: false,
1848
+ disabledWebShortcuts: false,
1849
+ activationShortcut: '',
1850
+ userAgent: '',
1851
+ showSystemTray: false,
1852
+ multiArch: false,
1853
+ targets: (() => {
1854
+ switch (process.platform) {
1855
+ case 'linux':
1856
+ return 'deb';
1857
+ case 'darwin':
1858
+ return 'dmg';
1859
+ case 'win32':
1860
+ return 'msi';
1861
+ default:
1862
+ return 'deb';
1863
+ }
1864
+ })(),
1865
+ useLocalFile: false,
1866
+ systemTrayIcon: '',
1867
+ proxyUrl: '',
1868
+ debug: false,
1869
+ inject: [],
1870
+ installerLanguage: 'en-US',
1871
+ hideOnClose: undefined, // Platform-specific: true for macOS, false for others
1872
+ incognito: false,
1873
+ wasm: false,
1874
+ enableDragDrop: false,
1875
+ keepBinary: false,
1876
+ multiInstance: false,
1877
+ startToTray: false,
1878
+ forceInternalNavigation: false,
1879
+ iterativeBuild: false,
1880
+ zoom: 100,
1881
+ minWidth: 0,
1882
+ minHeight: 0,
1883
+ ignoreCertificateErrors: false,
1884
+ };
1885
+
1792
1886
  function validateNumberInput(value) {
1793
1887
  const parsedValue = Number(value);
1794
1888
  if (isNaN(parsedValue)) {
@@ -1803,152 +1897,163 @@ function validateUrlInput(url) {
1803
1897
  return normalizeUrl(url);
1804
1898
  }
1805
1899
  catch (error) {
1806
- throw new InvalidArgumentError(error.message);
1900
+ if (error instanceof Error) {
1901
+ throw new InvalidArgumentError(error.message);
1902
+ }
1903
+ throw error;
1807
1904
  }
1808
1905
  }
1809
1906
  return url;
1810
1907
  }
1811
1908
 
1812
- const { green, yellow } = chalk;
1813
- const logo = `${chalk.green(' ____ _')}
1909
+ function getCliProgram() {
1910
+ const { green, yellow } = chalk;
1911
+ const logo = `${chalk.green(' ____ _')}
1814
1912
  ${green('| _ \\ __ _| | _____')}
1815
1913
  ${green('| |_) / _` | |/ / _ \\')}
1816
1914
  ${green('| __/ (_| | < __/')} ${yellow('https://github.com/tw93/pake')}
1817
1915
  ${green('|_| \\__,_|_|\\_\\___| can turn any webpage into a desktop app with Rust.')}
1818
1916
  `;
1819
- program
1820
- .addHelpText('beforeAll', logo)
1821
- .usage(`[url] [options]`)
1822
- .showHelpAfterError();
1823
- program
1824
- .argument('[url]', 'The web URL you want to package', validateUrlInput)
1825
- // Refer to https://github.com/tj/commander.js#custom-option-processing, turn string array into a string connected with custom connectors.
1826
- // If the platform is Linux, use `-` as the connector, and convert all characters to lowercase.
1827
- // For example, Google Translate will become google-translate.
1828
- .option('--name <string>', 'Application name')
1829
- .option('--icon <string>', 'Application icon', DEFAULT_PAKE_OPTIONS.icon)
1830
- .option('--width <number>', 'Window width', validateNumberInput, DEFAULT_PAKE_OPTIONS.width)
1831
- .option('--height <number>', 'Window height', validateNumberInput, DEFAULT_PAKE_OPTIONS.height)
1832
- .option('--use-local-file', 'Use local file packaging', DEFAULT_PAKE_OPTIONS.useLocalFile)
1833
- .option('--fullscreen', 'Start in full screen', DEFAULT_PAKE_OPTIONS.fullscreen)
1834
- .option('--hide-title-bar', 'For Mac, hide title bar', DEFAULT_PAKE_OPTIONS.hideTitleBar)
1835
- .option('--multi-arch', 'For Mac, both Intel and M1', DEFAULT_PAKE_OPTIONS.multiArch)
1836
- .option('--inject <files>', 'Inject local CSS/JS files into the page', (val, previous) => {
1837
- if (!val)
1838
- return DEFAULT_PAKE_OPTIONS.inject;
1839
- // Split by comma and trim whitespace, filter out empty strings
1840
- const files = val
1841
- .split(',')
1842
- .map((item) => item.trim())
1843
- .filter((item) => item.length > 0);
1844
- // If previous values exist (from multiple --inject options), merge them
1845
- return previous ? [...previous, ...files] : files;
1846
- }, DEFAULT_PAKE_OPTIONS.inject)
1847
- .option('--debug', 'Debug build and more output', DEFAULT_PAKE_OPTIONS.debug)
1848
- .addOption(new Option('--proxy-url <url>', 'Proxy URL for all network requests (http://, https://, socks5://)')
1849
- .default(DEFAULT_PAKE_OPTIONS.proxyUrl)
1850
- .hideHelp())
1851
- .addOption(new Option('--user-agent <string>', 'Custom user agent')
1852
- .default(DEFAULT_PAKE_OPTIONS.userAgent)
1853
- .hideHelp())
1854
- .addOption(new Option('--targets <string>', 'Build target format for your system').default(DEFAULT_PAKE_OPTIONS.targets))
1855
- .addOption(new Option('--app-version <string>', 'App version, the same as package.json version')
1856
- .default(DEFAULT_PAKE_OPTIONS.appVersion)
1857
- .hideHelp())
1858
- .addOption(new Option('--always-on-top', 'Always on the top level')
1859
- .default(DEFAULT_PAKE_OPTIONS.alwaysOnTop)
1860
- .hideHelp())
1861
- .addOption(new Option('--maximize', 'Start window maximized')
1862
- .default(DEFAULT_PAKE_OPTIONS.maximize)
1863
- .hideHelp())
1864
- .addOption(new Option('--dark-mode', 'Force Mac app to use dark mode')
1865
- .default(DEFAULT_PAKE_OPTIONS.darkMode)
1866
- .hideHelp())
1867
- .addOption(new Option('--disabled-web-shortcuts', 'Disabled webPage shortcuts')
1868
- .default(DEFAULT_PAKE_OPTIONS.disabledWebShortcuts)
1869
- .hideHelp())
1870
- .addOption(new Option('--activation-shortcut <string>', 'Shortcut key to active App')
1871
- .default(DEFAULT_PAKE_OPTIONS.activationShortcut)
1872
- .hideHelp())
1873
- .addOption(new Option('--show-system-tray', 'Show system tray in app')
1874
- .default(DEFAULT_PAKE_OPTIONS.showSystemTray)
1875
- .hideHelp())
1876
- .addOption(new Option('--system-tray-icon <string>', 'Custom system tray icon')
1877
- .default(DEFAULT_PAKE_OPTIONS.systemTrayIcon)
1878
- .hideHelp())
1879
- .addOption(new Option('--hide-on-close [boolean]', 'Hide window on close instead of exiting (default: true for macOS, false for others)')
1880
- .default(DEFAULT_PAKE_OPTIONS.hideOnClose)
1881
- .argParser((value) => {
1882
- if (value === undefined)
1883
- return true; // --hide-on-close without value
1884
- if (value === 'true')
1885
- return true;
1886
- if (value === 'false')
1887
- return false;
1888
- throw new Error('--hide-on-close must be true or false');
1889
- })
1890
- .hideHelp())
1891
- .addOption(new Option('--title <string>', 'Window title').hideHelp())
1892
- .addOption(new Option('--incognito', 'Launch app in incognito/private mode')
1893
- .default(DEFAULT_PAKE_OPTIONS.incognito)
1894
- .hideHelp())
1895
- .addOption(new Option('--wasm', 'Enable WebAssembly support (Flutter Web, etc.)')
1896
- .default(DEFAULT_PAKE_OPTIONS.wasm)
1897
- .hideHelp())
1898
- .addOption(new Option('--enable-drag-drop', 'Enable drag and drop functionality')
1899
- .default(DEFAULT_PAKE_OPTIONS.enableDragDrop)
1900
- .hideHelp())
1901
- .addOption(new Option('--keep-binary', 'Keep raw binary file alongside installer')
1902
- .default(DEFAULT_PAKE_OPTIONS.keepBinary)
1903
- .hideHelp())
1904
- .addOption(new Option('--multi-instance', 'Allow multiple app instances')
1905
- .default(DEFAULT_PAKE_OPTIONS.multiInstance)
1906
- .hideHelp())
1907
- .addOption(new Option('--start-to-tray', 'Start app minimized to tray')
1908
- .default(DEFAULT_PAKE_OPTIONS.startToTray)
1909
- .hideHelp())
1910
- .addOption(new Option('--force-internal-navigation', 'Keep every link inside the Pake window instead of opening external handlers')
1911
- .default(DEFAULT_PAKE_OPTIONS.forceInternalNavigation)
1912
- .hideHelp())
1913
- .addOption(new Option('--installer-language <string>', 'Installer language')
1914
- .default(DEFAULT_PAKE_OPTIONS.installerLanguage)
1915
- .hideHelp())
1916
- .addOption(new Option('--zoom <number>', 'Initial page zoom level (50-200)')
1917
- .default(DEFAULT_PAKE_OPTIONS.zoom)
1918
- .argParser((value) => {
1919
- const zoom = parseInt(value);
1920
- if (isNaN(zoom) || zoom < 50 || zoom > 200) {
1921
- throw new Error('--zoom must be a number between 50 and 200');
1922
- }
1923
- return zoom;
1924
- })
1925
- .hideHelp())
1926
- .addOption(new Option('--min-width <number>', 'Minimum window width')
1927
- .default(DEFAULT_PAKE_OPTIONS.minWidth)
1928
- .argParser(validateNumberInput)
1929
- .hideHelp())
1930
- .addOption(new Option('--min-height <number>', 'Minimum window height')
1931
- .default(DEFAULT_PAKE_OPTIONS.minHeight)
1932
- .argParser(validateNumberInput)
1933
- .hideHelp())
1934
- .addOption(new Option('--ignore-certificate-errors', 'Ignore certificate errors (for self-signed certificates)')
1935
- .default(DEFAULT_PAKE_OPTIONS.ignoreCertificateErrors)
1936
- .hideHelp())
1937
- .version(packageJson.version, '-v, --version')
1938
- .configureHelp({
1939
- sortSubcommands: true,
1940
- optionTerm: (option) => {
1941
- if (option.flags === '-v, --version' || option.flags === '-h, --help')
1942
- return '';
1943
- return option.flags;
1944
- },
1945
- optionDescription: (option) => {
1946
- if (option.flags === '-v, --version' || option.flags === '-h, --help')
1947
- return '';
1948
- return option.description;
1949
- },
1950
- })
1951
- .action(async (url, options) => {
1917
+ return program$1
1918
+ .addHelpText('beforeAll', logo)
1919
+ .usage(`[url] [options]`)
1920
+ .showHelpAfterError()
1921
+ .argument('[url]', 'The web URL you want to package', validateUrlInput)
1922
+ .option('--name <string>', 'Application name')
1923
+ .option('--icon <string>', 'Application icon', DEFAULT_PAKE_OPTIONS.icon)
1924
+ .option('--width <number>', 'Window width', validateNumberInput, DEFAULT_PAKE_OPTIONS.width)
1925
+ .option('--height <number>', 'Window height', validateNumberInput, DEFAULT_PAKE_OPTIONS.height)
1926
+ .option('--use-local-file', 'Use local file packaging', DEFAULT_PAKE_OPTIONS.useLocalFile)
1927
+ .option('--fullscreen', 'Start in full screen', DEFAULT_PAKE_OPTIONS.fullscreen)
1928
+ .option('--hide-title-bar', 'For Mac, hide title bar', DEFAULT_PAKE_OPTIONS.hideTitleBar)
1929
+ .option('--multi-arch', 'For Mac, both Intel and M1', DEFAULT_PAKE_OPTIONS.multiArch)
1930
+ .option('--inject <files>', 'Inject local CSS/JS files into the page', (val, previous) => {
1931
+ if (!val)
1932
+ return DEFAULT_PAKE_OPTIONS.inject;
1933
+ // Split by comma and trim whitespace, filter out empty strings
1934
+ const files = val
1935
+ .split(',')
1936
+ .map((item) => item.trim())
1937
+ .filter((item) => item.length > 0);
1938
+ // If previous values exist (from multiple --inject options), merge them
1939
+ return previous ? [...previous, ...files] : files;
1940
+ }, DEFAULT_PAKE_OPTIONS.inject)
1941
+ .option('--debug', 'Debug build and more output', DEFAULT_PAKE_OPTIONS.debug)
1942
+ .addOption(new Option('--proxy-url <url>', 'Proxy URL for all network requests (http://, https://, socks5://)')
1943
+ .default(DEFAULT_PAKE_OPTIONS.proxyUrl)
1944
+ .hideHelp())
1945
+ .addOption(new Option('--user-agent <string>', 'Custom user agent')
1946
+ .default(DEFAULT_PAKE_OPTIONS.userAgent)
1947
+ .hideHelp())
1948
+ .addOption(new Option('--targets <string>', 'Build target format for your system').default(DEFAULT_PAKE_OPTIONS.targets))
1949
+ .addOption(new Option('--app-version <string>', 'App version, the same as package.json version')
1950
+ .default(DEFAULT_PAKE_OPTIONS.appVersion)
1951
+ .hideHelp())
1952
+ .addOption(new Option('--always-on-top', 'Always on the top level')
1953
+ .default(DEFAULT_PAKE_OPTIONS.alwaysOnTop)
1954
+ .hideHelp())
1955
+ .addOption(new Option('--maximize', 'Start window maximized')
1956
+ .default(DEFAULT_PAKE_OPTIONS.maximize)
1957
+ .hideHelp())
1958
+ .addOption(new Option('--dark-mode', 'Force Mac app to use dark mode')
1959
+ .default(DEFAULT_PAKE_OPTIONS.darkMode)
1960
+ .hideHelp())
1961
+ .addOption(new Option('--disabled-web-shortcuts', 'Disabled webPage shortcuts')
1962
+ .default(DEFAULT_PAKE_OPTIONS.disabledWebShortcuts)
1963
+ .hideHelp())
1964
+ .addOption(new Option('--activation-shortcut <string>', 'Shortcut key to active App')
1965
+ .default(DEFAULT_PAKE_OPTIONS.activationShortcut)
1966
+ .hideHelp())
1967
+ .addOption(new Option('--show-system-tray', 'Show system tray in app')
1968
+ .default(DEFAULT_PAKE_OPTIONS.showSystemTray)
1969
+ .hideHelp())
1970
+ .addOption(new Option('--system-tray-icon <string>', 'Custom system tray icon')
1971
+ .default(DEFAULT_PAKE_OPTIONS.systemTrayIcon)
1972
+ .hideHelp())
1973
+ .addOption(new Option('--hide-on-close [boolean]', 'Hide window on close instead of exiting (default: true for macOS, false for others)')
1974
+ .default(DEFAULT_PAKE_OPTIONS.hideOnClose)
1975
+ .argParser((value) => {
1976
+ if (value === undefined)
1977
+ return true; // --hide-on-close without value
1978
+ if (value === 'true')
1979
+ return true;
1980
+ if (value === 'false')
1981
+ return false;
1982
+ throw new Error('--hide-on-close must be true or false');
1983
+ })
1984
+ .hideHelp())
1985
+ .addOption(new Option('--title <string>', 'Window title').hideHelp())
1986
+ .addOption(new Option('--incognito', 'Launch app in incognito/private mode')
1987
+ .default(DEFAULT_PAKE_OPTIONS.incognito)
1988
+ .hideHelp())
1989
+ .addOption(new Option('--wasm', 'Enable WebAssembly support (Flutter Web, etc.)')
1990
+ .default(DEFAULT_PAKE_OPTIONS.wasm)
1991
+ .hideHelp())
1992
+ .addOption(new Option('--enable-drag-drop', 'Enable drag and drop functionality')
1993
+ .default(DEFAULT_PAKE_OPTIONS.enableDragDrop)
1994
+ .hideHelp())
1995
+ .addOption(new Option('--keep-binary', 'Keep raw binary file alongside installer')
1996
+ .default(DEFAULT_PAKE_OPTIONS.keepBinary)
1997
+ .hideHelp())
1998
+ .addOption(new Option('--multi-instance', 'Allow multiple app instances')
1999
+ .default(DEFAULT_PAKE_OPTIONS.multiInstance)
2000
+ .hideHelp())
2001
+ .addOption(new Option('--start-to-tray', 'Start app minimized to tray')
2002
+ .default(DEFAULT_PAKE_OPTIONS.startToTray)
2003
+ .hideHelp())
2004
+ .addOption(new Option('--force-internal-navigation', 'Keep every link inside the Pake window instead of opening external handlers')
2005
+ .default(DEFAULT_PAKE_OPTIONS.forceInternalNavigation)
2006
+ .hideHelp())
2007
+ .addOption(new Option('--installer-language <string>', 'Installer language')
2008
+ .default(DEFAULT_PAKE_OPTIONS.installerLanguage)
2009
+ .hideHelp())
2010
+ .addOption(new Option('--zoom <number>', 'Initial page zoom level (50-200)')
2011
+ .default(DEFAULT_PAKE_OPTIONS.zoom)
2012
+ .argParser((value) => {
2013
+ const zoom = parseInt(value);
2014
+ if (isNaN(zoom) || zoom < 50 || zoom > 200) {
2015
+ throw new Error('--zoom must be a number between 50 and 200');
2016
+ }
2017
+ return zoom;
2018
+ })
2019
+ .hideHelp())
2020
+ .addOption(new Option('--min-width <number>', 'Minimum window width')
2021
+ .default(DEFAULT_PAKE_OPTIONS.minWidth)
2022
+ .argParser(validateNumberInput)
2023
+ .hideHelp())
2024
+ .addOption(new Option('--min-height <number>', 'Minimum window height')
2025
+ .default(DEFAULT_PAKE_OPTIONS.minHeight)
2026
+ .argParser(validateNumberInput)
2027
+ .hideHelp())
2028
+ .addOption(new Option('--ignore-certificate-errors', 'Ignore certificate errors (for self-signed certificates)')
2029
+ .default(DEFAULT_PAKE_OPTIONS.ignoreCertificateErrors)
2030
+ .hideHelp())
2031
+ .addOption(new Option('--iterative-build', 'Turn on rapid build mode (app only, no dmg/deb/msi), good for debugging')
2032
+ .default(DEFAULT_PAKE_OPTIONS.iterativeBuild)
2033
+ .hideHelp())
2034
+ .version(packageJson.version, '-v, --version')
2035
+ .configureHelp({
2036
+ sortSubcommands: true,
2037
+ optionTerm: (option) => {
2038
+ if (option.flags === '-v, --version' || option.flags === '-h, --help')
2039
+ return '';
2040
+ return option.flags;
2041
+ },
2042
+ optionDescription: (option) => {
2043
+ if (option.flags === '-v, --version' || option.flags === '-h, --help')
2044
+ return '';
2045
+ return option.description;
2046
+ },
2047
+ });
2048
+ }
2049
+
2050
+ const program = getCliProgram();
2051
+ async function checkUpdateTips() {
2052
+ updateNotifier({ pkg: packageJson, updateCheckInterval: 1000 * 60 }).notify({
2053
+ isGlobal: true,
2054
+ });
2055
+ }
2056
+ program.action(async (url, options) => {
1952
2057
  await checkUpdateTips();
1953
2058
  if (!url) {
1954
2059
  program.help({