pake-cli 3.3.0 → 3.3.2

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/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  <img src=https://gw.alipayobjects.com/zos/k/fa/logo-modified.png width=138/>
4
4
  </p>
5
5
  <h1 align="center">Pake</h1>
6
- <p align="center"><strong>Turn any webpage into a desktop app with Rust <em>with ease</em>.</strong></p>
6
+ <p align="center"><strong>Turn any webpage into a desktop app with one command, supports macOS, Windows, and Linux</strong></p>
7
7
  <div align="center">
8
8
  <a href="https://twitter.com/HiTw93" target="_blank">
9
9
  <img alt="twitter" src="https://img.shields.io/badge/follow-Tw93-red?style=flat-square&logo=Twitter"></a>
@@ -15,19 +15,20 @@
15
15
  <img alt="GitHub commit" src="https://img.shields.io/github/commit-activity/m/tw93/Pake?style=flat-square"></a>
16
16
  <a href="https://github.com/tw93/Pake/issues?q=is%3Aissue+is%3Aclosed" target="_blank">
17
17
  <img alt="GitHub closed issues" src="https://img.shields.io/github/issues-closed/tw93/Pake.svg?style=flat-square"></a>
18
- <a href="https://colab.research.google.com/drive/1bX345znvDZ30848xjRtpgtU8eypWwXrp?usp=sharing" target="_blank">
19
- <img alt="Open in Colab" src="https://colab.research.google.com/assets/colab-badge.svg"></a>
20
18
  </div>
21
19
 
22
- <div align="left">Pake supports Mac, Windows, and Linux. Check out README for <a href="#popular-packages">Popular Packages</a>, <a href="#command-line-packaging">Command-Line Packaging</a>, and <a href="#development">Customized Development</a> information. Feel free to share your suggestions in <a href=https://github.com/tw93/Pake/discussions>Discussions</a>.</div>
23
-
24
20
  ## Features
25
21
 
26
- - 🎐 Nearly 20 times smaller than an Electron package (around 5M!)
27
- - 🚀 With Rust Tauri, Pake is much more lightweight and faster than JS-based frameworks.
28
- - 📦 Battery-included package shortcut pass-through, immersive windows, and minimalist customization.
29
- - 🖱️ Smart right-click context menus with download support for images, videos, and files.
30
- - 👻 Pake is just a simple tool — replaces the old bundle approach with Tauri (though PWA is also a good alternative).
22
+ - 🎐 **Lightweight**: Nearly 20 times smaller than Electron packages, typically around 5M
23
+ - 🚀 **Fast**: Built with Rust Tauri, much faster than traditional JS frameworks with lower memory usage
24
+ - **Easy to use**: One-command packaging via CLI or online building, no complex configuration needed
25
+ - 📦 **Feature-rich**: Supports shortcut pass-through, immersive windows, drag & drop, style customization, ad removal
26
+
27
+ ## Getting Started
28
+
29
+ - **Beginners**: Download ready-made [Popular Packages](#popular-packages) or use [Online Building](docs/github-actions-usage.md) with no environment setup required
30
+ - **Developers**: Install [CLI Tool](docs/cli-usage.md) for one-command packaging of any website with customizable icons, window settings, and more
31
+ - **Advanced Users**: Clone the project locally for [Custom Development](#development), or check [Advanced Usage](docs/advanced-usage.md) for style customization and feature enhancement
31
32
 
32
33
  ## Popular Packages
33
34
 
@@ -152,58 +153,39 @@ In addition, double-click the title bar to switch to full-screen mode. For Mac u
152
153
 
153
154
  </details>
154
155
 
155
- ## Before starting
156
-
157
- 1. **For beginners**: Play with Popular Packages to find out Pake's capabilities, or try to pack your application with [GitHub Actions](docs/github-actions-usage.md). Don't hesitate to reach for assistance at [Discussion](https://github.com/tw93/Pake/discussions)!
158
- 2. **For developers**: “Command-Line Packaging” supports macOS fully. For Windows/Linux users, it requires some tinkering. [Configure your environment](https://tauri.app/start/prerequisites/) before getting started.
159
- 3. **For hackers**: For people who are good at both front-end development and Rust, how about customizing your apps' function more with the following [Customized Development](#development)?
160
-
161
156
  ## Command-Line Packaging
162
157
 
163
158
  ![Pake](https://raw.githubusercontent.com/tw93/static/main/pake/pake.gif)
164
159
 
165
- **Pake provides a command line tool, making the flow of package customization quicker and easier. See the [CLI usage guide](docs/cli-usage.md) for more information.**
166
-
167
160
  ```bash
168
- # Recommended (pnpm)
161
+ # Install
169
162
  pnpm install -g pake-cli
170
163
 
171
- # Alternative (npm)
172
- npm install -g pake-cli
173
-
174
- # Command usage
175
- pake url [OPTIONS]...
164
+ # Basic usage (auto-fetch website icon)
165
+ pake https://weekly.tw93.fun --name Weekly
176
166
 
177
- # Feel free to play with Pake! It might take a while to prepare the environment the first time you launch Pake.
178
- pake https://weekly.tw93.fun --name Weekly --hide-title-bar
167
+ # Common options: --name app name, --icon custom icon, --width/--height window size, --hide-title-bar macOS immersive
168
+ pake https://weekly.tw93.fun --name Weekly --icon https://cdn.tw93.fun/pake/weekly.icns --hide-title-bar
179
169
  ```
180
170
 
181
- If you are new to the command line, you can compile packages online with _GitHub Actions_. See our [documentation](#documentation) for detailed guides.
171
+ First-time packaging requires environment setup and may be slower, subsequent builds are fast. For complete parameter documentation, see [CLI Usage Guide](docs/cli-usage.md). Don't want to use CLI? Try [GitHub Actions Online Building](docs/github-actions-usage.md).
182
172
 
183
173
  ## Development
184
174
 
185
- Prepare your environment before starting. Make sure you have Rust `>=1.89` and Node `>=18` (e.g., `22.11.0`) installed on your computer. _Note: Latest stable versions are recommended._ For installation guidance, see [Tauri documentation](https://tauri.app/start/prerequisites/).
175
+ Requires Rust `>=1.89` and Node `>=22`. For detailed installation guide, see [Tauri documentation](https://tauri.app/start/prerequisites/). If unfamiliar with development environment, use the CLI tool instead.
186
176
 
187
- If you are unfamiliar with these, it is better to try out the above tool to pack with one click.
188
-
189
- ```sh
177
+ ```bash
190
178
  # Install dependencies
191
179
  pnpm i
192
180
 
193
- # Local development (right-click to open debug mode)
181
+ # Local development [right-click to open debug mode]
194
182
  pnpm run dev
195
183
 
196
184
  # Build application
197
185
  pnpm run build
198
186
  ```
199
187
 
200
- ## Documentation
201
-
202
- - **[CLI Usage](docs/cli-usage.md)** | [中文](docs/cli-usage_CN.md) - Command-line interface reference
203
- - **[Advanced Usage](docs/advanced-usage.md)** | [中文](docs/advanced-usage_CN.md) - Customization and advanced features
204
- - **[GitHub Actions](docs/github-actions-usage.md)** | [中文](docs/github-actions-usage_CN.md) - Build apps online
205
- - **[Pake Action](docs/pake-action.md)** - Use Pake as GitHub Action in your projects
206
- - **[Contributing](CONTRIBUTING.md)** - How to contribute to development
188
+ For style customization, feature enhancement, container communication and other advanced features, see [Advanced Usage Documentation](docs/advanced-usage.md).
207
189
 
208
190
  ## Developers
209
191
 
@@ -306,6 +288,15 @@ Pake's development can not be without these Hackers. They contributed a lot of c
306
288
  <sub><b>GoodbyeNJN</b></sub>
307
289
  </a>
308
290
  </td>
291
+ <td align="center">
292
+ <a href="https://github.com/eltociear">
293
+ <img src="https://avatars.githubusercontent.com/u/22633385?v=4" width="90;" alt="eltociear"/>
294
+ <br />
295
+ <sub><b>Ikko Eltociear Ashimine</b></sub>
296
+ </a>
297
+ </td>
298
+ </tr>
299
+ <tr>
309
300
  <td align="center">
310
301
  <a href="https://github.com/kittizz">
311
302
  <img src="https://avatars.githubusercontent.com/u/62899732?v=4" width="90;" alt="kittizz"/>
@@ -313,8 +304,6 @@ Pake's development can not be without these Hackers. They contributed a lot of c
313
304
  <sub><b>Kittizz</b></sub>
314
305
  </a>
315
306
  </td>
316
- </tr>
317
- <tr>
318
307
  <td align="center">
319
308
  <a href="https://github.com/mattbajorek">
320
309
  <img src="https://avatars.githubusercontent.com/u/17235301?v=4" width="90;" alt="mattbajorek"/>
@@ -357,6 +346,8 @@ Pake's development can not be without these Hackers. They contributed a lot of c
357
346
  <sub><b>Yue Yang</b></sub>
358
347
  </a>
359
348
  </td>
349
+ </tr>
350
+ <tr>
360
351
  <td align="center">
361
352
  <a href="https://github.com/lkieryan">
362
353
  <img src="https://avatars.githubusercontent.com/u/187804088?v=4" width="90;" alt="lkieryan"/>
@@ -364,8 +355,6 @@ Pake's development can not be without these Hackers. They contributed a lot of c
364
355
  <sub><b>Kieran</b></sub>
365
356
  </a>
366
357
  </td>
367
- </tr>
368
- <tr>
369
358
  <td align="center">
370
359
  <a href="https://github.com/exposir">
371
360
  <img src="https://avatars.githubusercontent.com/u/33340988?v=4" width="90;" alt="exposir"/>
@@ -408,6 +397,8 @@ Pake's development can not be without these Hackers. They contributed a lot of c
408
397
  <sub><b>Ayaka Neko</b></sub>
409
398
  </a>
410
399
  </td>
400
+ </tr>
401
+ <tr>
411
402
  <td align="center">
412
403
  <a href="https://github.com/turkyden">
413
404
  <img src="https://avatars.githubusercontent.com/u/24560160?v=4" width="90;" alt="turkyden"/>
@@ -415,8 +406,6 @@ Pake's development can not be without these Hackers. They contributed a lot of c
415
406
  <sub><b>Dengju Deng</b></sub>
416
407
  </a>
417
408
  </td>
418
- </tr>
419
- <tr>
420
409
  <td align="center">
421
410
  <a href="https://github.com/fvn-elmy">
422
411
  <img src="https://avatars.githubusercontent.com/u/71275745?v=4" width="90;" alt="fvn-elmy"/>
@@ -459,6 +448,8 @@ Pake's development can not be without these Hackers. They contributed a lot of c
459
448
  <sub><b>Milo</b></sub>
460
449
  </a>
461
450
  </td>
451
+ </tr>
452
+ <tr>
462
453
  <td align="center">
463
454
  <a href="https://github.com/princemaple">
464
455
  <img src="https://avatars.githubusercontent.com/u/1329716?v=4" width="90;" alt="princemaple"/>
@@ -466,8 +457,6 @@ Pake's development can not be without these Hackers. They contributed a lot of c
466
457
  <sub><b>Po Chen</b></sub>
467
458
  </a>
468
459
  </td>
469
- </tr>
470
- <tr>
471
460
  <td align="center">
472
461
  <a href="https://github.com/beautifulrem">
473
462
  <img src="https://avatars.githubusercontent.com/u/98527099?v=4" width="90;" alt="beautifulrem"/>
@@ -510,6 +499,8 @@ Pake's development can not be without these Hackers. They contributed a lot of c
510
499
  <sub><b>Liudonghua</b></sub>
511
500
  </a>
512
501
  </td>
502
+ </tr>
503
+ <tr>
513
504
  <td align="center">
514
505
  <a href="https://github.com/liusishan">
515
506
  <img src="https://avatars.githubusercontent.com/u/33129823?v=4" width="90;" alt="liusishan"/>
@@ -517,8 +508,6 @@ Pake's development can not be without these Hackers. They contributed a lot of c
517
508
  <sub><b>Liusishan</b></sub>
518
509
  </a>
519
510
  </td>
520
- </tr>
521
- <tr>
522
511
  <td align="center">
523
512
  <a href="https://github.com/piaoyidage">
524
513
  <img src="https://avatars.githubusercontent.com/u/5135405?v=4" width="90;" alt="piaoyidage"/>
@@ -541,6 +530,6 @@ Pake's development can not be without these Hackers. They contributed a lot of c
541
530
  ## Support
542
531
 
543
532
  1. I have two cats, TangYuan and Coke. If you think Pake delights your life, you can feed them <a href="https://miaoyan.app/cats.html?name=Pake" target="_blank">some canned food 🥩</a>.
544
- 2. If you like Pake, you can star it on GitHub. Also, welcome to [recommend Pake](https://twitter.com/intent/tweet?url=https://github.com/tw93/Pake&text=%23Pake%20-%20A%20simple%20Rust%20packaged%20web%20pages%20to%20generate%20Mac%20App%20tool,%20compared%20to%20traditional%20Electron%20package,%20the%20size%20of%20nearly%2040%20times%20smaller,%20generally%20about%202M,%20the%20underlying%20use%20of%20Tauri,%20performance%20experience%20than%20the%20JS%20framework%20is%20much%20lighter~) to your friends.
533
+ 2. If you like Pake, you can star it on GitHub. Also, welcome to [recommend Pake](https://twitter.com/intent/tweet?url=https://github.com/tw93/Pake&text=Pake%20-%20Turn%20any%20webpage%20into%20a%20desktop%20app%20with%20one%20command.%20Nearly%2020x%20smaller%20than%20Electron%20packages,%20supports%20macOS%20Windows%20Linux) to your friends.
545
534
  3. You can follow my [Twitter](https://twitter.com/HiTw93) to get the latest news of Pake or join our [Telegram](https://t.me/+GclQS9ZnxyI2ODQ1) chat group.
546
535
  4. I hope that you enjoy playing with it. Let us know if you find a website that would be great for a Mac App!
package/dist/cli.js CHANGED
@@ -22,8 +22,8 @@ import sharp from 'sharp';
22
22
  import * as psl from 'psl';
23
23
 
24
24
  var name = "pake-cli";
25
- var version = "3.3.0";
26
- var description = "🤱🏻 Turn any webpage into a desktop app with Rust. 🤱🏻 利用 Rust 轻松构建轻量级多端桌面应用。";
25
+ var version = "3.3.2";
26
+ var description = "🤱🏻 Turn any webpage into a desktop app with one command. 🤱🏻 一键打包网页生成轻量桌面应用。";
27
27
  var engines = {
28
28
  node: ">=18.0.0"
29
29
  };
@@ -73,7 +73,7 @@ var exports = "./dist/cli.js";
73
73
  var license = "MIT";
74
74
  var dependencies = {
75
75
  "@tauri-apps/api": "^2.8.0",
76
- "@tauri-apps/cli": "^2.8.3",
76
+ "@tauri-apps/cli": "^2.8.4",
77
77
  axios: "^1.11.0",
78
78
  chalk: "^5.6.0",
79
79
  commander: "^12.1.0",
@@ -85,7 +85,7 @@ var dependencies = {
85
85
  ora: "^8.2.0",
86
86
  prompts: "^2.4.2",
87
87
  psl: "^1.15.0",
88
- sharp: "^0.34.3",
88
+ sharp: "^0.33.5",
89
89
  "tmp-promise": "^3.0.3",
90
90
  "update-notifier": "^7.3.1"
91
91
  };
@@ -96,7 +96,7 @@ var devDependencies = {
96
96
  "@rollup/plugin-replace": "^6.0.2",
97
97
  "@rollup/plugin-terser": "^0.4.4",
98
98
  "@types/fs-extra": "^11.0.4",
99
- "@types/node": "^20.19.11",
99
+ "@types/node": "^20.19.13",
100
100
  "@types/page-icon": "^0.3.6",
101
101
  "@types/prompts": "^2.4.9",
102
102
  "@types/tmp": "^0.2.6",
@@ -104,7 +104,7 @@ var devDependencies = {
104
104
  "app-root-path": "^3.1.0",
105
105
  "cross-env": "^7.0.3",
106
106
  prettier: "^3.6.2",
107
- rollup: "^4.49.0",
107
+ rollup: "^4.50.0",
108
108
  "rollup-plugin-typescript2": "^0.36.0",
109
109
  tslib: "^2.8.1",
110
110
  typescript: "^5.9.2"
@@ -1150,20 +1150,54 @@ async function checkUpdateTips() {
1150
1150
  });
1151
1151
  }
1152
1152
 
1153
- // Constants
1154
1153
  const ICON_CONFIG = {
1155
1154
  minFileSize: 100,
1156
- downloadTimeout: 10000,
1157
- supportedFormats: ['png', 'ico', 'jpeg', 'jpg', 'webp'],
1155
+ supportedFormats: ['png', 'ico', 'jpeg', 'jpg', 'webp', 'icns'],
1158
1156
  whiteBackground: { r: 255, g: 255, b: 255 },
1157
+ transparentBackground: { r: 255, g: 255, b: 255, alpha: 0 },
1158
+ downloadTimeout: {
1159
+ ci: 5000,
1160
+ default: 15000,
1161
+ },
1162
+ };
1163
+ const PLATFORM_CONFIG = {
1164
+ win: { format: '.ico', sizes: [16, 32, 48, 64, 128, 256] },
1165
+ linux: { format: '.png', size: 512 },
1166
+ macos: { format: '.icns', sizes: [16, 32, 64, 128, 256, 512, 1024] },
1159
1167
  };
1160
- // API Configuration
1161
- const API_TOKENS = {
1162
- // cspell:disable-next-line
1168
+ const API_KEYS = {
1163
1169
  logoDev: ['pk_JLLMUKGZRpaG5YclhXaTkg', 'pk_Ph745P8mQSeYFfW2Wk039A'],
1164
- // cspell:disable-next-line
1165
1170
  brandfetch: ['1idqvJC0CeFSeyp3Yf7', '1idej-yhU_ThggIHFyG'],
1166
1171
  };
1172
+ /**
1173
+ * Generates platform-specific icon paths and handles copying for Windows
1174
+ */
1175
+ function generateIconPath(appName, isDefault = false) {
1176
+ const safeName = appName.toLowerCase().replace(/[^a-z0-9-_]/g, '_');
1177
+ const baseName = isDefault ? 'icon' : safeName;
1178
+ if (IS_WIN) {
1179
+ return path.join(npmDirectory, 'src-tauri', 'png', `${baseName}_256.ico`);
1180
+ }
1181
+ if (IS_LINUX) {
1182
+ return path.join(npmDirectory, 'src-tauri', 'png', `${baseName}_512.png`);
1183
+ }
1184
+ return path.join(npmDirectory, 'src-tauri', 'icons', `${baseName}.icns`);
1185
+ }
1186
+ async function copyWindowsIconIfNeeded(convertedPath, appName) {
1187
+ if (!IS_WIN || !convertedPath.endsWith('.ico')) {
1188
+ return convertedPath;
1189
+ }
1190
+ try {
1191
+ const finalIconPath = generateIconPath(appName);
1192
+ await fsExtra.ensureDir(path.dirname(finalIconPath));
1193
+ await fsExtra.copy(convertedPath, finalIconPath);
1194
+ return finalIconPath;
1195
+ }
1196
+ catch (error) {
1197
+ logger.warn(`Failed to copy Windows icon: ${error instanceof Error ? error.message : 'Unknown error'}`);
1198
+ return convertedPath;
1199
+ }
1200
+ }
1167
1201
  /**
1168
1202
  * Adds white background to transparent icons only
1169
1203
  */
@@ -1206,23 +1240,34 @@ async function convertIconFormat(inputPath, appName) {
1206
1240
  const iconName = appName.toLowerCase();
1207
1241
  // Generate platform-specific format
1208
1242
  if (IS_WIN) {
1243
+ // Support multiple sizes for better Windows compatibility
1209
1244
  await icongen(processedInputPath, platformOutputDir, {
1210
1245
  report: false,
1211
- ico: { name: `${iconName}_256`, sizes: [256] },
1246
+ ico: {
1247
+ name: `${iconName}_256`,
1248
+ sizes: PLATFORM_CONFIG.win.sizes,
1249
+ },
1212
1250
  });
1213
- return path.join(platformOutputDir, `${iconName}_256.ico`);
1251
+ return path.join(platformOutputDir, `${iconName}_256${PLATFORM_CONFIG.win.format}`);
1214
1252
  }
1215
1253
  if (IS_LINUX) {
1216
- const outputPath = path.join(platformOutputDir, `${iconName}_512.png`);
1217
- await fsExtra.copy(processedInputPath, outputPath);
1254
+ const outputPath = path.join(platformOutputDir, `${iconName}_${PLATFORM_CONFIG.linux.size}${PLATFORM_CONFIG.linux.format}`);
1255
+ // Ensure we convert to proper PNG format with correct size
1256
+ await sharp(processedInputPath)
1257
+ .resize(PLATFORM_CONFIG.linux.size, PLATFORM_CONFIG.linux.size, {
1258
+ fit: 'contain',
1259
+ background: ICON_CONFIG.transparentBackground,
1260
+ })
1261
+ .png()
1262
+ .toFile(outputPath);
1218
1263
  return outputPath;
1219
1264
  }
1220
1265
  // macOS
1221
1266
  await icongen(processedInputPath, platformOutputDir, {
1222
1267
  report: false,
1223
- icns: { name: iconName, sizes: [16, 32, 64, 128, 256, 512, 1024] },
1268
+ icns: { name: iconName, sizes: PLATFORM_CONFIG.macos.sizes },
1224
1269
  });
1225
- const outputPath = path.join(platformOutputDir, `${iconName}.icns`);
1270
+ const outputPath = path.join(platformOutputDir, `${iconName}${PLATFORM_CONFIG.macos.format}`);
1226
1271
  return (await fsExtra.pathExists(outputPath)) ? outputPath : null;
1227
1272
  }
1228
1273
  catch (error) {
@@ -1230,97 +1275,113 @@ async function convertIconFormat(inputPath, appName) {
1230
1275
  return null;
1231
1276
  }
1232
1277
  }
1233
- async function handleIcon(options, url) {
1234
- if (options.icon) {
1235
- if (options.icon.startsWith('http')) {
1236
- const downloadedPath = await downloadIcon(options.icon);
1237
- if (downloadedPath && options.name) {
1238
- // Convert downloaded icon to platform-specific format
1239
- const convertedPath = await convertIconFormat(downloadedPath, options.name);
1240
- if (convertedPath) {
1241
- // For Windows, copy the converted ico to the expected location
1242
- if (IS_WIN && convertedPath.endsWith('.ico')) {
1243
- const finalIconPath = path.join(npmDirectory, `src-tauri/png/${options.name.toLowerCase()}_256.ico`);
1244
- await fsExtra.ensureDir(path.dirname(finalIconPath));
1245
- await fsExtra.copy(convertedPath, finalIconPath);
1246
- return finalIconPath;
1247
- }
1248
- return convertedPath;
1249
- }
1250
- }
1251
- return downloadedPath;
1252
- }
1253
- return path.resolve(options.icon);
1254
- }
1255
- // Try to get favicon from website if URL is provided
1256
- if (url && url.startsWith('http') && options.name) {
1257
- const faviconPath = await tryGetFavicon(url, options.name);
1258
- if (faviconPath)
1259
- return faviconPath;
1278
+ /**
1279
+ * Processes downloaded or local icon for platform-specific format
1280
+ */
1281
+ async function processIcon(iconPath, appName) {
1282
+ if (!iconPath || !appName)
1283
+ return iconPath;
1284
+ // Check if already in correct platform format
1285
+ const ext = path.extname(iconPath).toLowerCase();
1286
+ const isCorrectFormat = (IS_WIN && ext === '.ico') ||
1287
+ (IS_LINUX && ext === '.png') ||
1288
+ (!IS_WIN && !IS_LINUX && ext === '.icns');
1289
+ if (isCorrectFormat) {
1290
+ return await copyWindowsIconIfNeeded(iconPath, appName);
1291
+ }
1292
+ // Convert to platform format
1293
+ const convertedPath = await convertIconFormat(iconPath, appName);
1294
+ if (convertedPath) {
1295
+ return await copyWindowsIconIfNeeded(convertedPath, appName);
1260
1296
  }
1297
+ return iconPath;
1298
+ }
1299
+ /**
1300
+ * Gets default icon with platform-specific fallback logic
1301
+ */
1302
+ async function getDefaultIcon() {
1261
1303
  logger.info('✼ No icon provided, using default icon.');
1262
- // For Windows, ensure we have proper fallback handling
1263
1304
  if (IS_WIN) {
1264
- const defaultIcoPath = path.join(npmDirectory, 'src-tauri/png/icon_256.ico');
1305
+ const defaultIcoPath = generateIconPath('icon', true);
1265
1306
  const defaultPngPath = path.join(npmDirectory, 'src-tauri/png/icon_512.png');
1266
- // First try default ico
1307
+ // Try default ico first
1267
1308
  if (await fsExtra.pathExists(defaultIcoPath)) {
1268
1309
  return defaultIcoPath;
1269
1310
  }
1270
- // If ico doesn't exist, try to convert from png
1311
+ // Convert from png if ico doesn't exist
1271
1312
  if (await fsExtra.pathExists(defaultPngPath)) {
1272
1313
  logger.info('✼ Default ico not found, converting from png...');
1273
1314
  try {
1274
1315
  const convertedPath = await convertIconFormat(defaultPngPath, 'icon');
1275
1316
  if (convertedPath && (await fsExtra.pathExists(convertedPath))) {
1276
- // Copy converted icon to the expected location for Windows
1277
- const finalIconPath = path.join(npmDirectory, 'src-tauri/png/icon_256.ico');
1278
- await fsExtra.ensureDir(path.dirname(finalIconPath));
1279
- await fsExtra.copy(convertedPath, finalIconPath);
1280
- return finalIconPath;
1317
+ return await copyWindowsIconIfNeeded(convertedPath, 'icon');
1281
1318
  }
1282
1319
  }
1283
1320
  catch (error) {
1284
- logger.warn(`Failed to convert default png to ico: ${error.message}`);
1321
+ logger.warn(`Failed to convert default png to ico: ${error instanceof Error ? error.message : 'Unknown error'}`);
1285
1322
  }
1286
1323
  }
1287
- // Last resort: return png path if it exists (Windows can handle png in some cases)
1324
+ // Fallback to png or empty
1288
1325
  if (await fsExtra.pathExists(defaultPngPath)) {
1289
1326
  logger.warn('✼ Using png as fallback for Windows (may cause issues).');
1290
1327
  return defaultPngPath;
1291
1328
  }
1292
- // If nothing exists, return empty string to let merge.ts handle default icon
1293
1329
  logger.warn('✼ No default icon found, will use pake default.');
1294
1330
  return '';
1295
1331
  }
1332
+ // Linux and macOS defaults
1296
1333
  const iconPath = IS_LINUX
1297
1334
  ? 'src-tauri/png/icon_512.png'
1298
1335
  : 'src-tauri/icons/icon.icns';
1299
1336
  return path.join(npmDirectory, iconPath);
1300
1337
  }
1338
+ /**
1339
+ * Main icon handling function with simplified logic flow
1340
+ */
1341
+ async function handleIcon(options, url) {
1342
+ // Handle custom icon (local file or remote URL)
1343
+ if (options.icon) {
1344
+ if (options.icon.startsWith('http')) {
1345
+ const downloadedPath = await downloadIcon(options.icon);
1346
+ if (downloadedPath) {
1347
+ const result = await processIcon(downloadedPath, options.name || '');
1348
+ if (result)
1349
+ return result;
1350
+ }
1351
+ return '';
1352
+ }
1353
+ // Local file path
1354
+ const resolvedPath = path.resolve(options.icon);
1355
+ const result = await processIcon(resolvedPath, options.name || '');
1356
+ return result || resolvedPath;
1357
+ }
1358
+ // Try favicon from website
1359
+ if (url && options.name) {
1360
+ const faviconPath = await tryGetFavicon(url, options.name);
1361
+ if (faviconPath)
1362
+ return faviconPath;
1363
+ }
1364
+ // Use default icon
1365
+ return await getDefaultIcon();
1366
+ }
1301
1367
  /**
1302
1368
  * Generates icon service URLs for a domain
1303
1369
  */
1304
1370
  function generateIconServiceUrls(domain) {
1305
- const logoDevUrls = API_TOKENS.logoDev
1371
+ const logoDevUrls = API_KEYS.logoDev
1306
1372
  .sort(() => Math.random() - 0.5)
1307
1373
  .map((token) => `https://img.logo.dev/${domain}?token=${token}&format=png&size=256`);
1308
- const brandfetchUrls = API_TOKENS.brandfetch
1374
+ const brandfetchUrls = API_KEYS.brandfetch
1309
1375
  .sort(() => Math.random() - 0.5)
1310
1376
  .map((key) => `https://cdn.brandfetch.io/${domain}/w/400/h/400?c=${key}`);
1311
1377
  return [
1312
1378
  ...logoDevUrls,
1313
1379
  ...brandfetchUrls,
1314
1380
  `https://logo.clearbit.com/${domain}?size=256`,
1315
- `https://logo.uplead.com/${domain}`,
1316
1381
  `https://www.google.com/s2/favicons?domain=${domain}&sz=256`,
1317
1382
  `https://favicon.is/${domain}`,
1318
- `https://icons.duckduckgo.com/ip3/${domain}.ico`,
1319
- `https://icon.horse/icon/${domain}`,
1320
1383
  `https://${domain}/favicon.ico`,
1321
1384
  `https://www.${domain}/favicon.ico`,
1322
- `https://${domain}/apple-touch-icon.png`,
1323
- `https://${domain}/apple-touch-icon-precomposed.png`,
1324
1385
  ];
1325
1386
  }
1326
1387
  /**
@@ -1331,9 +1392,10 @@ async function tryGetFavicon(url, appName) {
1331
1392
  const domain = new URL(url).hostname;
1332
1393
  const spinner = getSpinner(`Fetching icon from ${domain}...`);
1333
1394
  const serviceUrls = generateIconServiceUrls(domain);
1334
- // Use shorter timeout for CI environments
1335
1395
  const isCI = process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true';
1336
- const downloadTimeout = isCI ? 5000 : ICON_CONFIG.downloadTimeout;
1396
+ const downloadTimeout = isCI
1397
+ ? ICON_CONFIG.downloadTimeout.ci
1398
+ : ICON_CONFIG.downloadTimeout.default;
1337
1399
  for (const serviceUrl of serviceUrls) {
1338
1400
  try {
1339
1401
  const faviconPath = await downloadIcon(serviceUrl, false, downloadTimeout);
@@ -1341,22 +1403,20 @@ async function tryGetFavicon(url, appName) {
1341
1403
  continue;
1342
1404
  const convertedPath = await convertIconFormat(faviconPath, appName);
1343
1405
  if (convertedPath) {
1344
- // For Windows, copy the converted ico to the expected location
1345
- if (IS_WIN && convertedPath.endsWith('.ico')) {
1346
- const finalIconPath = path.join(npmDirectory, `src-tauri/png/${appName.toLowerCase()}_256.ico`);
1347
- await fsExtra.ensureDir(path.dirname(finalIconPath));
1348
- await fsExtra.copy(convertedPath, finalIconPath);
1349
- spinner.succeed(chalk.green('Icon fetched and converted successfully!'));
1350
- return finalIconPath;
1351
- }
1406
+ const finalPath = await copyWindowsIconIfNeeded(convertedPath, appName);
1352
1407
  spinner.succeed(chalk.green('Icon fetched and converted successfully!'));
1353
- return convertedPath;
1408
+ return finalPath;
1354
1409
  }
1355
1410
  }
1356
1411
  catch (error) {
1357
- // Log specific errors in CI for debugging
1358
- if (isCI) {
1359
- logger.debug(`Icon service ${serviceUrl} failed: ${error.message}`);
1412
+ logger.debug(`Icon service ${serviceUrl} failed: ${error.message}`);
1413
+ // Platform-specific error handling
1414
+ if ((IS_LINUX || IS_WIN) && error.code === 'ENOTFOUND') {
1415
+ logger.debug(`DNS resolution failed for ${serviceUrl}, trying next service...`);
1416
+ }
1417
+ // Windows-specific icon conversion errors
1418
+ if (IS_WIN && error.message.includes('icongen')) {
1419
+ logger.debug(`Windows icon conversion failed for ${serviceUrl}, trying next service...`);
1360
1420
  }
1361
1421
  continue;
1362
1422
  }
@@ -1376,7 +1436,7 @@ async function downloadIcon(iconUrl, showSpinner = true, customTimeout) {
1376
1436
  try {
1377
1437
  const response = await axios.get(iconUrl, {
1378
1438
  responseType: 'arraybuffer',
1379
- timeout: customTimeout || ICON_CONFIG.downloadTimeout,
1439
+ timeout: customTimeout || 10000,
1380
1440
  });
1381
1441
  const iconData = response.data;
1382
1442
  if (!iconData || iconData.byteLength < ICON_CONFIG.minFileSize)
@@ -1400,15 +1460,11 @@ async function downloadIcon(iconUrl, showSpinner = true, customTimeout) {
1400
1460
  */
1401
1461
  async function saveIconFile(iconData, extension) {
1402
1462
  const buffer = Buffer.from(iconData);
1403
- if (IS_LINUX) {
1404
- const iconPath = 'png/linux_temp.png';
1405
- await fsExtra.outputFile(`${npmDirectory}/src-tauri/${iconPath}`, buffer);
1406
- return iconPath;
1407
- }
1408
1463
  const { path: tempPath } = await dir();
1409
- const iconPath = `${tempPath}/icon.${extension}`;
1410
- await fsExtra.outputFile(iconPath, buffer);
1411
- return iconPath;
1464
+ // Always save with the original extension first
1465
+ const originalIconPath = path.join(tempPath, `icon.${extension}`);
1466
+ await fsExtra.outputFile(originalIconPath, buffer);
1467
+ return originalIconPath;
1412
1468
  }
1413
1469
 
1414
1470
  // Extracts the domain from a given URL.
@@ -1546,7 +1602,7 @@ program
1546
1602
  .option('--fullscreen', 'Start in full screen', DEFAULT_PAKE_OPTIONS.fullscreen)
1547
1603
  .option('--hide-title-bar', 'For Mac, hide title bar', DEFAULT_PAKE_OPTIONS.hideTitleBar)
1548
1604
  .option('--multi-arch', 'For Mac, both Intel and M1', DEFAULT_PAKE_OPTIONS.multiArch)
1549
- .option('--inject <./style.css,./script.js,...>', 'Injection of .js or .css files', (val, previous) => {
1605
+ .option('--inject <files>', 'Inject local CSS/JS files into the page', (val, previous) => {
1550
1606
  if (!val)
1551
1607
  return DEFAULT_PAKE_OPTIONS.inject;
1552
1608
  // Split by comma and trim whitespace, filter out empty strings
@@ -1564,7 +1620,7 @@ program
1564
1620
  .addOption(new Option('--user-agent <string>', 'Custom user agent')
1565
1621
  .default(DEFAULT_PAKE_OPTIONS.userAgent)
1566
1622
  .hideHelp())
1567
- .addOption(new Option('--targets <string>', 'Build target: Linux: "deb", "rpm", "appimage", "deb-arm64", "rpm-arm64", "appimage-arm64"; Windows: "x64", "arm64"; macOS: "intel", "apple", "universal"').default(DEFAULT_PAKE_OPTIONS.targets))
1623
+ .addOption(new Option('--targets <string>', 'Build target format for your system').default(DEFAULT_PAKE_OPTIONS.targets))
1568
1624
  .addOption(new Option('--app-version <string>', 'App version, the same as package.json version')
1569
1625
  .default(DEFAULT_PAKE_OPTIONS.appVersion)
1570
1626
  .hideHelp())