pake-cli 3.4.0 โ†’ 3.4.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.
package/dist/cli.js CHANGED
@@ -23,7 +23,7 @@ import sharp from 'sharp';
23
23
  import * as psl from 'psl';
24
24
 
25
25
  var name = "pake-cli";
26
- var version = "3.4.0";
26
+ var version = "3.4.1";
27
27
  var description = "๐Ÿคฑ๐Ÿป Turn any webpage into a desktop app with one command. ๐Ÿคฑ๐Ÿป ไธ€้”ฎๆ‰“ๅŒ…็ฝ‘้กต็”Ÿๆˆ่ฝป้‡ๆกŒ้ขๅบ”็”จใ€‚";
28
28
  var engines = {
29
29
  node: ">=18.0.0"
@@ -201,11 +201,13 @@ const IS_MAC = platform$1 === 'darwin';
201
201
  const IS_WIN = platform$1 === 'win32';
202
202
  const IS_LINUX = platform$1 === 'linux';
203
203
 
204
- async function shellExec(command, timeout = 300000, env, showOutput = false) {
204
+ async function shellExec(command, timeout = 300000, env) {
205
205
  try {
206
206
  const { exitCode } = await execa(command, {
207
207
  cwd: npmDirectory,
208
- stdio: showOutput ? 'inherit' : ['inherit', 'pipe', 'inherit'],
208
+ // Use 'inherit' to show all output directly to user in real-time.
209
+ // This ensures linuxdeploy and other tool outputs are visible during builds.
210
+ stdio: 'inherit',
209
211
  shell: true,
210
212
  timeout,
211
213
  env: env ? { ...process.env, ...env } : process.env,
@@ -219,15 +221,25 @@ async function shellExec(command, timeout = 300000, env, showOutput = false) {
219
221
  throw new Error(`Command timed out after ${timeout}ms: "${command}". Try increasing timeout or check network connectivity.`);
220
222
  }
221
223
  let errorMsg = `Error occurred while executing command "${command}". Exit code: ${exitCode}. Details: ${errorMessage}`;
224
+ // Provide helpful guidance for common Linux AppImage build failures
225
+ // caused by strip tool incompatibility with modern glibc (2.38+)
222
226
  if (process.platform === 'linux' &&
223
227
  (errorMessage.includes('linuxdeploy') ||
224
228
  errorMessage.includes('appimage') ||
225
229
  errorMessage.includes('strip'))) {
226
230
  errorMsg +=
227
- '\n\nLinux AppImage build error. Try one of these solutions:\n' +
228
- ' 1. Run with: NO_STRIP=true pake <url> --targets appimage\n' +
229
- ' 2. Use DEB format instead: pake <url> --targets deb\n' +
230
- ' 3. See detailed solutions: https://github.com/tw93/Pake/blob/main/docs/faq.md';
231
+ '\n\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n' +
232
+ 'Linux AppImage Build Failed\n' +
233
+ 'โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n' +
234
+ 'Cause: Strip tool incompatibility with glibc 2.38+\n' +
235
+ ' (affects Debian Trixie, Arch Linux, and other modern distros)\n\n' +
236
+ 'Quick fix:\n' +
237
+ ' NO_STRIP=1 pake <url> --targets appimage --debug\n\n' +
238
+ 'Alternatives:\n' +
239
+ ' โ€ข Use DEB format: pake <url> --targets deb\n' +
240
+ ' โ€ข Update binutils: sudo apt install binutils (or pacman -S binutils)\n' +
241
+ ' โ€ข Detailed guide: https://github.com/tw93/Pake/blob/main/docs/faq.md\n' +
242
+ 'โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”';
231
243
  }
232
244
  throw new Error(errorMsg);
233
245
  }
@@ -351,7 +363,7 @@ async function installRust() {
351
363
  const rustInstallScriptForWindows = 'winget install --id Rustlang.Rustup';
352
364
  const spinner = getSpinner('Downloading Rust...');
353
365
  try {
354
- await shellExec(IS_WIN ? rustInstallScriptForWindows : rustInstallScriptForMac, 300000, undefined, true);
366
+ await shellExec(IS_WIN ? rustInstallScriptForWindows : rustInstallScriptForMac, 300000, undefined);
355
367
  spinner.succeed(chalk.green('โœ” Rust installed successfully!'));
356
368
  ensureRustEnv();
357
369
  }
@@ -448,13 +460,14 @@ async function mergeConfig(url, options, tauriConf) {
448
460
  await fsExtra.copy(sourcePath, destPath);
449
461
  }
450
462
  }));
451
- const { width, height, fullscreen, hideTitleBar, alwaysOnTop, appVersion, darkMode, disabledWebShortcuts, activationShortcut, userAgent, showSystemTray, systemTrayIcon, useLocalFile, identifier, name, resizable = true, inject, proxyUrl, installerLanguage, hideOnClose, incognito, title, wasm, enableDragDrop, multiInstance, } = options;
463
+ 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, } = options;
452
464
  const { platform } = process;
453
465
  const platformHideOnClose = hideOnClose ?? platform === 'darwin';
454
466
  const tauriConfWindowOptions = {
455
467
  width,
456
468
  height,
457
469
  fullscreen,
470
+ maximize,
458
471
  resizable,
459
472
  hide_title_bar: hideTitleBar,
460
473
  activation_shortcut: activationShortcut,
@@ -466,6 +479,7 @@ async function mergeConfig(url, options, tauriConf) {
466
479
  title: title || null,
467
480
  enable_wasm: wasm,
468
481
  enable_drag_drop: enableDragDrop,
482
+ start_to_tray: startToTray && showSystemTray,
469
483
  };
470
484
  Object.assign(tauriConf.pake.windows[0], { url, ...tauriConfWindowOptions });
471
485
  tauriConf.productName = name;
@@ -774,10 +788,10 @@ class BaseBuilder {
774
788
  logger.info(`โœบ Located in China, using ${packageManager}/rsProxy CN mirror.`);
775
789
  const projectCnConf = path.join(tauriSrcPath, 'rust_proxy.toml');
776
790
  await fsExtra.copy(projectCnConf, projectConf);
777
- await shellExec(`cd "${npmDirectory}" && ${packageManager} install${registryOption}${peerDepsOption}`, timeout, buildEnv, this.options.debug);
791
+ await shellExec(`cd "${npmDirectory}" && ${packageManager} install${registryOption}${peerDepsOption}`, timeout, buildEnv);
778
792
  }
779
793
  else {
780
- await shellExec(`cd "${npmDirectory}" && ${packageManager} install${peerDepsOption}`, timeout, buildEnv, this.options.debug);
794
+ await shellExec(`cd "${npmDirectory}" && ${packageManager} install${peerDepsOption}`, timeout, buildEnv);
781
795
  }
782
796
  spinner.succeed(chalk.green('Package installed!'));
783
797
  if (!tauriTargetPathExists) {
@@ -806,7 +820,16 @@ class BaseBuilder {
806
820
  ...this.getBuildEnvironment(),
807
821
  ...(process.env.NO_STRIP && { NO_STRIP: process.env.NO_STRIP }),
808
822
  };
809
- await shellExec(`cd "${npmDirectory}" && ${this.getBuildCommand(packageManager)}`, this.getBuildTimeout(), buildEnv, this.options.debug);
823
+ // Warn users about potential AppImage build failures on modern Linux systems.
824
+ // The linuxdeploy tool bundled in Tauri uses an older strip tool that doesn't
825
+ // recognize the .relr.dyn section introduced in glibc 2.38+.
826
+ if (process.platform === 'linux' && this.options.targets === 'appimage') {
827
+ if (!buildEnv.NO_STRIP) {
828
+ logger.warn('โš  Building AppImage on Linux may fail due to strip incompatibility with glibc 2.38+');
829
+ logger.warn('โš  If build fails, retry with: NO_STRIP=1 pake <url> --targets appimage');
830
+ }
831
+ }
832
+ await shellExec(`cd "${npmDirectory}" && ${this.getBuildCommand(packageManager)}`, this.getBuildTimeout(), buildEnv);
810
833
  // Copy app
811
834
  const fileName = this.getFileName();
812
835
  const fileType = this.getFileType(target);
@@ -865,6 +888,11 @@ class BaseBuilder {
865
888
  if (target) {
866
889
  fullCommand += ` --target ${target}`;
867
890
  }
891
+ // Enable verbose output in debug mode to help diagnose build issues.
892
+ // This provides detailed logs from Tauri CLI and bundler tools.
893
+ if (this.options.debug) {
894
+ fullCommand += ' --verbose';
895
+ }
868
896
  return fullCommand;
869
897
  }
870
898
  /**
@@ -1178,6 +1206,12 @@ class LinuxBuilder extends BaseBuilder {
1178
1206
  if (features.length > 0) {
1179
1207
  fullCommand += ` --features ${features.join(',')}`;
1180
1208
  }
1209
+ // Enable verbose output for AppImage builds when debugging or PAKE_VERBOSE is set.
1210
+ // AppImage builds often fail with minimal error messages from linuxdeploy,
1211
+ // so verbose mode helps diagnose issues like strip failures and missing dependencies.
1212
+ if (this.options.targets === 'appimage' && (this.options.debug || process.env.PAKE_VERBOSE)) {
1213
+ fullCommand += ' --verbose';
1214
+ }
1181
1215
  return fullCommand;
1182
1216
  }
1183
1217
  getBasePath() {
@@ -1227,6 +1261,7 @@ const DEFAULT_PAKE_OPTIONS = {
1227
1261
  height: 780,
1228
1262
  width: 1200,
1229
1263
  fullscreen: false,
1264
+ maximize: false,
1230
1265
  hideTitleBar: false,
1231
1266
  alwaysOnTop: false,
1232
1267
  appVersion: '1.0.0',
@@ -1249,6 +1284,7 @@ const DEFAULT_PAKE_OPTIONS = {
1249
1284
  enableDragDrop: false,
1250
1285
  keepBinary: false,
1251
1286
  multiInstance: false,
1287
+ startToTray: false,
1252
1288
  };
1253
1289
 
1254
1290
  async function checkUpdateTips() {
@@ -1731,6 +1767,9 @@ program
1731
1767
  .addOption(new Option('--always-on-top', 'Always on the top level')
1732
1768
  .default(DEFAULT_PAKE_OPTIONS.alwaysOnTop)
1733
1769
  .hideHelp())
1770
+ .addOption(new Option('--maximize', 'Start window maximized')
1771
+ .default(DEFAULT_PAKE_OPTIONS.maximize)
1772
+ .hideHelp())
1734
1773
  .addOption(new Option('--dark-mode', 'Force Mac app to use dark mode')
1735
1774
  .default(DEFAULT_PAKE_OPTIONS.darkMode)
1736
1775
  .hideHelp())
@@ -1774,6 +1813,9 @@ program
1774
1813
  .addOption(new Option('--multi-instance', 'Allow multiple app instances')
1775
1814
  .default(DEFAULT_PAKE_OPTIONS.multiInstance)
1776
1815
  .hideHelp())
1816
+ .addOption(new Option('--start-to-tray', 'Start app minimized to tray')
1817
+ .default(DEFAULT_PAKE_OPTIONS.startToTray)
1818
+ .hideHelp())
1777
1819
  .addOption(new Option('--installer-language <string>', 'Installer language')
1778
1820
  .default(DEFAULT_PAKE_OPTIONS.installerLanguage)
1779
1821
  .hideHelp())
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pake-cli",
3
- "version": "3.4.0",
3
+ "version": "3.4.1",
4
4
  "description": "๐Ÿคฑ๐Ÿป Turn any webpage into a desktop app with one command. ๐Ÿคฑ๐Ÿป ไธ€้”ฎๆ‰“ๅŒ…็ฝ‘้กต็”Ÿๆˆ่ฝป้‡ๆกŒ้ขๅบ”็”จใ€‚",
5
5
  "engines": {
6
6
  "node": ">=18.0.0"
@@ -16,6 +16,8 @@
16
16
  "incognito": false,
17
17
  "enable_wasm": false,
18
18
  "enable_drag_drop": false,
19
+ "maximize": false,
20
+ "start_to_tray": false,
19
21
  "title": null
20
22
  }
21
23
  ],
@@ -15,7 +15,9 @@
15
15
  "hide_on_close": true,
16
16
  "incognito": false,
17
17
  "enable_wasm": false,
18
- "enable_drag_drop": false
18
+ "enable_drag_drop": false,
19
+ "maximize": false,
20
+ "start_to_tray": false
19
21
  }
20
22
  ],
21
23
  "user_agent": {
@@ -5,6 +5,7 @@ pub struct WindowConfig {
5
5
  pub url: String,
6
6
  pub hide_title_bar: bool,
7
7
  pub fullscreen: bool,
8
+ pub maximize: bool,
8
9
  pub width: f64,
9
10
  pub height: f64,
10
11
  pub resizable: bool,
@@ -18,6 +19,7 @@ pub struct WindowConfig {
18
19
  pub title: Option<String>,
19
20
  pub enable_wasm: bool,
20
21
  pub enable_drag_drop: bool,
22
+ pub start_to_tray: bool,
21
23
  }
22
24
 
23
25
  #[derive(Debug, Serialize, Deserialize)]
@@ -3,13 +3,13 @@ use std::sync::{Arc, Mutex};
3
3
  use std::time::{Duration, Instant};
4
4
  use tauri::{
5
5
  menu::{MenuBuilder, MenuItemBuilder},
6
- tray::TrayIconBuilder,
6
+ tray::{TrayIconBuilder, TrayIconEvent},
7
7
  AppHandle, Manager,
8
8
  };
9
9
  use tauri_plugin_global_shortcut::{GlobalShortcutExt, Shortcut};
10
10
  use tauri_plugin_window_state::{AppHandleExt, StateFlags};
11
11
 
12
- pub fn set_system_tray(app: &AppHandle, show_system_tray: bool) -> tauri::Result<()> {
12
+ pub fn set_system_tray(app: &AppHandle, show_system_tray: bool, tray_icon_path: &str) -> tauri::Result<()> {
13
13
  if !show_system_tray {
14
14
  app.remove_tray_by_id("pake-tray");
15
15
  return Ok(());
@@ -44,7 +44,30 @@ pub fn set_system_tray(app: &AppHandle, show_system_tray: bool) -> tauri::Result
44
44
  }
45
45
  _ => (),
46
46
  })
47
- .icon(app.default_window_icon().unwrap().clone())
47
+ .on_tray_icon_event(|tray, event| match event {
48
+ TrayIconEvent::Click { button, .. } => {
49
+ if button == tauri::tray::MouseButton::Left {
50
+ if let Some(window) = tray.app_handle().get_webview_window("pake") {
51
+ let is_visible = window.is_visible().unwrap_or(false);
52
+ if is_visible {
53
+ window.hide().unwrap();
54
+ } else {
55
+ window.show().unwrap();
56
+ window.set_focus().unwrap();
57
+ }
58
+ }
59
+ }
60
+ }
61
+ _ => {}
62
+ })
63
+ .icon(if tray_icon_path.is_empty() {
64
+ app.default_window_icon().unwrap_or_else(|| panic!("Failed to get default window icon")).clone()
65
+ } else {
66
+ tauri::image::Image::from_path(tray_icon_path).unwrap_or_else(|_| {
67
+ // If custom tray icon fails to load, fallback to default
68
+ app.default_window_icon().unwrap_or_else(|| panic!("Failed to get default window icon")).clone()
69
+ })
70
+ })
48
71
  .build(app)?;
49
72
 
50
73
  tray.set_icon_as_template(false)?;
@@ -43,6 +43,7 @@ pub fn set_window(app: &mut App, config: &PakeConfig, tauri_config: &Config) ->
43
43
  .user_agent(user_agent)
44
44
  .resizable(window_config.resizable)
45
45
  .fullscreen(window_config.fullscreen)
46
+ .maximized(window_config.maximize)
46
47
  .inner_size(window_config.width, window_config.height)
47
48
  .always_on_top(window_config.always_on_top)
48
49
  .incognito(window_config.incognito);
@@ -65,14 +66,7 @@ pub fn set_window(app: &mut App, config: &PakeConfig, tauri_config: &Config) ->
65
66
  .additional_browser_args("--enable-unsafe-webgpu");
66
67
  }
67
68
 
68
- if !config.proxy_url.is_empty() {
69
- if let Ok(proxy_url) = Url::from_str(&config.proxy_url) {
70
- window_builder = window_builder.proxy_url(proxy_url);
71
- #[cfg(debug_assertions)]
72
- println!("Proxy configured: {}", config.proxy_url);
73
- }
74
- }
75
-
69
+ // Platform-specific configuration must be set before proxy on Windows/Linux
76
70
  #[cfg(target_os = "macos")]
77
71
  {
78
72
  let title_bar_style = if window_config.hide_title_bar {
@@ -87,7 +81,7 @@ pub fn set_window(app: &mut App, config: &PakeConfig, tauri_config: &Config) ->
87
81
  }
88
82
  }
89
83
 
90
- // Windows and Linux share the same configuration
84
+ // Windows and Linux: set data_directory before proxy_url
91
85
  #[cfg(not(target_os = "macos"))]
92
86
  {
93
87
  window_builder = window_builder
@@ -96,5 +90,14 @@ pub fn set_window(app: &mut App, config: &PakeConfig, tauri_config: &Config) ->
96
90
  .theme(None);
97
91
  }
98
92
 
93
+ // Set proxy after platform-specific configs (required for Windows/Linux)
94
+ if !config.proxy_url.is_empty() {
95
+ if let Ok(proxy_url) = Url::from_str(&config.proxy_url) {
96
+ window_builder = window_builder.proxy_url(proxy_url);
97
+ #[cfg(debug_assertions)]
98
+ println!("Proxy configured: {}", config.proxy_url);
99
+ }
100
+ }
101
+
99
102
  window_builder.build().expect("Failed to build window")
100
103
  }
@@ -24,6 +24,7 @@ pub fn run_app() {
24
24
  let hide_on_close = pake_config.windows[0].hide_on_close;
25
25
  let activation_shortcut = pake_config.windows[0].activation_shortcut.clone();
26
26
  let init_fullscreen = pake_config.windows[0].fullscreen;
27
+ let start_to_tray = pake_config.windows[0].start_to_tray && show_system_tray; // Only valid when tray is enabled
27
28
  let multi_instance = pake_config.multi_instance;
28
29
 
29
30
  let window_state_plugin = WindowStatePlugin::default()
@@ -62,15 +63,18 @@ pub fn run_app() {
62
63
  ])
63
64
  .setup(move |app| {
64
65
  let window = set_window(app, &pake_config, &tauri_config);
65
- set_system_tray(app.app_handle(), show_system_tray).unwrap();
66
+ set_system_tray(app.app_handle(), show_system_tray, &pake_config.system_tray_path).unwrap();
66
67
  set_global_shortcut(app.app_handle(), activation_shortcut).unwrap();
67
68
 
68
69
  // Show window after state restoration to prevent position flashing
69
- let window_clone = window.clone();
70
- tauri::async_runtime::spawn(async move {
71
- tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
72
- window_clone.show().unwrap();
73
- });
70
+ // Unless start_to_tray is enabled, then keep it hidden
71
+ if !start_to_tray {
72
+ let window_clone = window.clone();
73
+ tauri::async_runtime::spawn(async move {
74
+ tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
75
+ window_clone.show().unwrap();
76
+ });
77
+ }
74
78
 
75
79
  Ok(())
76
80
  })