@wrongstack/desktop 0.287.0 → 0.289.0

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/main/main.js CHANGED
@@ -3,7 +3,7 @@ import * as path4 from "node:path";
3
3
  import * as fs3 from "node:fs/promises";
4
4
  import { wstackGlobalRoot as wstackGlobalRoot3 } from "@wrongstack/core/utils";
5
5
  import {
6
- app,
6
+ app as app2,
7
7
  BaseWindow,
8
8
  dialog,
9
9
  ipcMain as ipcMain2,
@@ -13,6 +13,52 @@ import {
13
13
  WebContentsView
14
14
  } from "electron";
15
15
 
16
+ // src/main/macos-platform.ts
17
+ import { app, Menu } from "electron";
18
+ function initMacOS() {
19
+ if (process.platform !== "darwin") return;
20
+ app.setActivationPolicy("regular");
21
+ app.on("open-file", (_event, filePath) => {
22
+ if (app.isReady()) {
23
+ handleFileOpen(filePath);
24
+ }
25
+ });
26
+ app.dock?.setMenu(
27
+ Menu.buildFromTemplate([
28
+ {
29
+ label: "New Window",
30
+ click: () => {
31
+ }
32
+ }
33
+ ])
34
+ );
35
+ app.setAboutPanelOptions({
36
+ applicationName: "WrongStack Desktop",
37
+ applicationVersion: app.getVersion(),
38
+ version: process.versions.electron ? `Electron ${process.versions.electron}` : ""
39
+ });
40
+ }
41
+ function handleFileOpen(filePath) {
42
+ pendingOpenFilePath = filePath;
43
+ }
44
+ var pendingOpenFilePath = null;
45
+ function drainPendingOpenFilePath() {
46
+ const path5 = pendingOpenFilePath;
47
+ pendingOpenFilePath = null;
48
+ return path5;
49
+ }
50
+ function firstOpenFileArg(argv) {
51
+ if (process.platform !== "darwin") return null;
52
+ for (let index = 1; index < argv.length; index++) {
53
+ const arg = argv[index];
54
+ if (arg == null) continue;
55
+ if (arg.startsWith("-")) continue;
56
+ if (arg === "." || arg === "--") continue;
57
+ return arg;
58
+ }
59
+ return null;
60
+ }
61
+
16
62
  // src/main/agent-bridge.ts
17
63
  import { randomUUID } from "node:crypto";
18
64
  import { EventEmitter } from "node:events";
@@ -398,7 +444,11 @@ var IPC = {
398
444
  // Embedded WebUI view side — the desktop shell pushes locale changes here
399
445
  // so the React WebUI inside Electron can swap i18n instantly, without waiting
400
446
  // for the config-file watcher → WS prefs.updated round-trip.
401
- webuiLocaleChanged: "desktop:webui-locale-changed"
447
+ webuiLocaleChanged: "desktop:webui-locale-changed",
448
+ // macOS open-file event forwarded from main process to shell renderer.
449
+ // The shell uses this to decide whether to open a dragged/double-clicked
450
+ // path as a project directory.
451
+ openFile: "desktop:open-file"
402
452
  };
403
453
 
404
454
  // src/main/i18n-main.ts
@@ -1187,6 +1237,26 @@ async function terminateProcessTree(child) {
1187
1237
  if (!child || child.killed || !child.pid) return;
1188
1238
  if (process.platform !== "win32") {
1189
1239
  child.kill("SIGTERM");
1240
+ const deadline = Date.now() + 5e3;
1241
+ await new Promise((resolve2) => {
1242
+ const check = () => {
1243
+ if (child.killed || !child.pid) {
1244
+ resolve2();
1245
+ return;
1246
+ }
1247
+ if (Date.now() >= deadline) {
1248
+ try {
1249
+ process.kill(-child.pid, "SIGKILL");
1250
+ } catch {
1251
+ child.kill("SIGKILL");
1252
+ }
1253
+ resolve2();
1254
+ return;
1255
+ }
1256
+ setTimeout(check, 100);
1257
+ };
1258
+ check();
1259
+ });
1190
1260
  return;
1191
1261
  }
1192
1262
  await new Promise((resolve2) => {
@@ -1526,7 +1596,7 @@ var DESKTOP_WEBUI_ACTIONS = /* @__PURE__ */ new Set([
1526
1596
  var DESKTOP_WEBUI_VIEWS = /* @__PURE__ */ new Set([
1527
1597
  "chat",
1528
1598
  "settings",
1529
- "autophase",
1599
+ "goal",
1530
1600
  "specs",
1531
1601
  "sddboard",
1532
1602
  "sddwizard",
@@ -1561,7 +1631,6 @@ var DESKTOP_WEBUI_OVERLAYS = /* @__PURE__ */ new Set([
1561
1631
  "queue"
1562
1632
  ]);
1563
1633
  var DESKTOP_WEBUI_DOCKS = /* @__PURE__ */ new Set([
1564
- "autophase",
1565
1634
  "goal",
1566
1635
  "fleet",
1567
1636
  "work",
@@ -1685,7 +1754,7 @@ function getSidebarWidth(windowWidth, collapsed) {
1685
1754
  }
1686
1755
 
1687
1756
  // src/main/menu/index.ts
1688
- import { Menu } from "electron";
1757
+ import { Menu as Menu2 } from "electron";
1689
1758
 
1690
1759
  // src/main/menu/projects-menu.ts
1691
1760
  import path3 from "node:path";
@@ -2018,7 +2087,7 @@ function configureApplicationMenu(ctx) {
2018
2087
  buildWorkspaceMenu(ctx, actions, hasActiveWebui, activeWebuiPrefs, navigate),
2019
2088
  buildViewMenu(ctx)
2020
2089
  ];
2021
- Menu.setApplicationMenu(Menu.buildFromTemplate(template));
2090
+ Menu2.setApplicationMenu(Menu2.buildFromTemplate(template));
2022
2091
  }
2023
2092
 
2024
2093
  // src/main/ipc-handlers/index.ts
@@ -2308,8 +2377,11 @@ function isRecord2(value) {
2308
2377
  }
2309
2378
 
2310
2379
  // src/main/main.ts
2311
- app.setAppUserModelId("com.wrongstack.desktop");
2312
- app.setPath("userData", path4.join(wstackGlobalRoot3(), "desktop", "electron-profile"));
2380
+ initMacOS();
2381
+ if (process.platform === "win32") {
2382
+ app2.setAppUserModelId("com.wrongstack.desktop");
2383
+ }
2384
+ app2.setPath("userData", path4.join(wstackGlobalRoot3(), "desktop", "electron-profile"));
2313
2385
  var manager = new DesktopRuntimeManager();
2314
2386
  var bridge = new DesktopAgentBridge();
2315
2387
  var mainWindow = null;
@@ -2341,6 +2413,22 @@ function sameOrigin(candidate, base) {
2341
2413
  return false;
2342
2414
  }
2343
2415
  }
2416
+ function revealInExplorer(root) {
2417
+ shell.openPath(root).catch((err) => {
2418
+ if (process.platform === "darwin") {
2419
+ void shell.openPath(path4.dirname(root)).catch(() => void 0);
2420
+ }
2421
+ console.error(
2422
+ JSON.stringify({
2423
+ level: "warn",
2424
+ event: "desktop.reveal_in_explorer_failed",
2425
+ root,
2426
+ message: err instanceof Error ? err.message : String(err),
2427
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2428
+ })
2429
+ );
2430
+ });
2431
+ }
2344
2432
  function setShellSidebarCollapsed(collapsed) {
2345
2433
  shellSidebarCollapsed = collapsed;
2346
2434
  layoutWebuiViews();
@@ -2885,7 +2973,7 @@ function createMenuContext() {
2885
2973
  shell.openExternal(url);
2886
2974
  },
2887
2975
  revealInExplorer: (root) => {
2888
- void shell.openPath(root);
2976
+ revealInExplorer(root);
2889
2977
  }
2890
2978
  };
2891
2979
  }
@@ -2922,7 +3010,7 @@ function buildIpcHandlerContext() {
2922
3010
  abortRuntime: (id, wsUrl) => bridge.abort(id, wsUrl),
2923
3011
  openExternal: (url) => safeOpenExternal(url),
2924
3012
  revealInExplorer: (root) => {
2925
- void shell.openPath(root);
3013
+ revealInExplorer(root);
2926
3014
  },
2927
3015
  findWebuiEntryBySenderId: (senderId) => findWebuiEntryBySenderId(senderId),
2928
3016
  getPendingWebuiCommandAcks: () => pendingWebuiCommandAcks,
@@ -2953,12 +3041,29 @@ async function boot() {
2953
3041
  const defaultWidth = 1180;
2954
3042
  const defaultHeight = 720;
2955
3043
  let appIcon;
2956
- try {
2957
- const iconPath = new URL("../../assets/icon.svg", import.meta.url).pathname;
2958
- await fs3.stat(iconPath);
2959
- appIcon = nativeImage.createFromPath(iconPath);
2960
- if (appIcon.isEmpty()) appIcon = void 0;
2961
- } catch {
3044
+ if (process.platform !== "darwin") {
3045
+ try {
3046
+ const iconPath = new URL("../../assets/icon.svg", import.meta.url).pathname;
3047
+ await fs3.stat(iconPath);
3048
+ appIcon = nativeImage.createFromPath(iconPath);
3049
+ if (appIcon.isEmpty()) appIcon = void 0;
3050
+ } catch {
3051
+ }
3052
+ } else {
3053
+ try {
3054
+ const pngPath = new URL("../../assets/icon.png", import.meta.url).pathname;
3055
+ await fs3.stat(pngPath);
3056
+ appIcon = nativeImage.createFromPath(pngPath);
3057
+ if (appIcon.isEmpty()) appIcon = void 0;
3058
+ } catch {
3059
+ try {
3060
+ const icnsPath = new URL("../../assets/icon.icns", import.meta.url).pathname;
3061
+ await fs3.stat(icnsPath);
3062
+ appIcon = nativeImage.createFromPath(icnsPath);
3063
+ if (appIcon.isEmpty()) appIcon = void 0;
3064
+ } catch {
3065
+ }
3066
+ }
2962
3067
  }
2963
3068
  const winOptions = {
2964
3069
  width: prevState?.width ?? defaultWidth,
@@ -2994,6 +3099,11 @@ async function boot() {
2994
3099
  configureApplicationMenu2();
2995
3100
  broadcastState();
2996
3101
  });
3102
+ app2.on("open-file", (_event, filePath) => {
3103
+ if (shellView && !shellView.webContents.isDestroyed()) {
3104
+ shellView.webContents.send(IPC.openFile, filePath);
3105
+ }
3106
+ });
2997
3107
  let lastWatchedLocale;
2998
3108
  watchProviderConfig(
2999
3109
  desktopConfigPaths.globalConfigPath,
@@ -3017,17 +3127,25 @@ async function boot() {
3017
3127
  disposeAllWebuiEntries();
3018
3128
  void saveWindowState();
3019
3129
  quittingAfterCleanup = true;
3020
- app.exit(0);
3130
+ app2.exit(0);
3021
3131
  });
3022
3132
  await restoreLastWorkspace();
3133
+ const argvOpenPath = firstOpenFileArg(process.argv);
3134
+ const queuedOpenPath = drainPendingOpenFilePath();
3135
+ const openPath = argvOpenPath ?? queuedOpenPath;
3136
+ if (openPath && shellView && !shellView.webContents.isDestroyed()) {
3137
+ shellView.webContents.send(IPC.openFile, openPath);
3138
+ }
3023
3139
  mainWindow.show();
3024
3140
  shellView.webContents.focus();
3025
3141
  }
3026
- app.whenReady().then(boot);
3027
- app.on("window-all-closed", () => {
3028
- app.quit();
3142
+ app2.whenReady().then(boot);
3143
+ app2.on("window-all-closed", () => {
3144
+ if (process.platform !== "darwin") {
3145
+ app2.quit();
3146
+ }
3029
3147
  });
3030
- app.on("before-quit", () => {
3148
+ app2.on("before-quit", () => {
3031
3149
  if (mainWindow) {
3032
3150
  mainWindow.removeAllListeners("close");
3033
3151
  void saveWindowState();
@@ -3035,7 +3153,7 @@ app.on("before-quit", () => {
3035
3153
  bridge.closeAll();
3036
3154
  disposeAllWebuiEntries();
3037
3155
  });
3038
- app.on("activate", () => {
3156
+ app2.on("activate", () => {
3039
3157
  if (!mainWindow) return;
3040
3158
  mainWindow.show();
3041
3159
  shellView?.webContents.focus();