@wrongstack/desktop 0.287.0 → 0.291.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 +161 -30
- package/dist/main/main.js.map +4 -4
- package/dist/preload/preload.cjs +5 -1
- package/dist/preload/preload.cjs.map +2 -2
- package/dist/preload/webui-preload.cjs +5 -1
- package/dist/preload/webui-preload.cjs.map +2 -2
- package/dist/renderer/assets/index-Bih3lXdg.js.map +1 -1
- package/package.json +8 -8
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
|
|
@@ -753,8 +803,8 @@ async function writeUiLocale(code) {
|
|
|
753
803
|
import { spawn } from "node:child_process";
|
|
754
804
|
import { randomBytes } from "node:crypto";
|
|
755
805
|
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
756
|
-
import * as fs2 from "node:fs/promises";
|
|
757
806
|
import { existsSync } from "node:fs";
|
|
807
|
+
import * as fs2 from "node:fs/promises";
|
|
758
808
|
import * as http from "node:http";
|
|
759
809
|
import { createRequire } from "node:module";
|
|
760
810
|
import * as net from "node:net";
|
|
@@ -1183,10 +1233,42 @@ var DesktopRuntimeManager = class extends EventEmitter2 {
|
|
|
1183
1233
|
}, 250);
|
|
1184
1234
|
}
|
|
1185
1235
|
};
|
|
1236
|
+
function hasChildExited(child) {
|
|
1237
|
+
return child.exitCode !== null || child.signalCode !== null;
|
|
1238
|
+
}
|
|
1239
|
+
function waitForChildExit(child, timeoutMs) {
|
|
1240
|
+
if (hasChildExited(child)) return Promise.resolve(true);
|
|
1241
|
+
return new Promise((resolve2) => {
|
|
1242
|
+
let settled = false;
|
|
1243
|
+
const finish = (exited) => {
|
|
1244
|
+
if (settled) return;
|
|
1245
|
+
settled = true;
|
|
1246
|
+
clearTimeout(timer);
|
|
1247
|
+
child.off("exit", onExit);
|
|
1248
|
+
resolve2(exited);
|
|
1249
|
+
};
|
|
1250
|
+
const onExit = () => finish(true);
|
|
1251
|
+
const timer = setTimeout(() => finish(hasChildExited(child)), timeoutMs);
|
|
1252
|
+
timer.unref?.();
|
|
1253
|
+
child.once("exit", onExit);
|
|
1254
|
+
if (hasChildExited(child)) finish(true);
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1186
1257
|
async function terminateProcessTree(child) {
|
|
1187
|
-
if (!child || child
|
|
1258
|
+
if (!child?.pid || hasChildExited(child)) return;
|
|
1188
1259
|
if (process.platform !== "win32") {
|
|
1260
|
+
const pid = child.pid;
|
|
1261
|
+
const exited = waitForChildExit(child, 5e3);
|
|
1189
1262
|
child.kill("SIGTERM");
|
|
1263
|
+
if (await exited) return;
|
|
1264
|
+
if (!hasChildExited(child)) {
|
|
1265
|
+
try {
|
|
1266
|
+
process.kill(-pid, "SIGKILL");
|
|
1267
|
+
} catch {
|
|
1268
|
+
child.kill("SIGKILL");
|
|
1269
|
+
}
|
|
1270
|
+
await waitForChildExit(child, 1e3);
|
|
1271
|
+
}
|
|
1190
1272
|
return;
|
|
1191
1273
|
}
|
|
1192
1274
|
await new Promise((resolve2) => {
|
|
@@ -1471,10 +1553,14 @@ async function touchGlobalProjectManifest(entry) {
|
|
|
1471
1553
|
} else {
|
|
1472
1554
|
projects.push({ ...entry, createdAt: entry.lastSeen });
|
|
1473
1555
|
}
|
|
1474
|
-
const sorted = projects.sort(
|
|
1556
|
+
const sorted = projects.sort(
|
|
1557
|
+
(a, b) => (b.lastSeen ?? b.createdAt ?? "").localeCompare(a.lastSeen ?? a.createdAt ?? "")
|
|
1558
|
+
).slice(0, 80);
|
|
1475
1559
|
await fs2.mkdir(path2.dirname(manifestFile), { recursive: true });
|
|
1476
1560
|
await atomicWrite2(manifestFile, `${JSON.stringify({ projects: sorted }, null, 2)}
|
|
1477
|
-
`, {
|
|
1561
|
+
`, {
|
|
1562
|
+
mode: 384
|
|
1563
|
+
});
|
|
1478
1564
|
return sorted;
|
|
1479
1565
|
}
|
|
1480
1566
|
async function removeGlobalProjectManifest(projectRoot) {
|
|
@@ -1526,10 +1612,8 @@ var DESKTOP_WEBUI_ACTIONS = /* @__PURE__ */ new Set([
|
|
|
1526
1612
|
var DESKTOP_WEBUI_VIEWS = /* @__PURE__ */ new Set([
|
|
1527
1613
|
"chat",
|
|
1528
1614
|
"settings",
|
|
1529
|
-
"
|
|
1530
|
-
"
|
|
1531
|
-
"sddboard",
|
|
1532
|
-
"sddwizard",
|
|
1615
|
+
"goal",
|
|
1616
|
+
"sddhub",
|
|
1533
1617
|
"files",
|
|
1534
1618
|
"changes",
|
|
1535
1619
|
"sessions",
|
|
@@ -1561,7 +1645,6 @@ var DESKTOP_WEBUI_OVERLAYS = /* @__PURE__ */ new Set([
|
|
|
1561
1645
|
"queue"
|
|
1562
1646
|
]);
|
|
1563
1647
|
var DESKTOP_WEBUI_DOCKS = /* @__PURE__ */ new Set([
|
|
1564
|
-
"autophase",
|
|
1565
1648
|
"goal",
|
|
1566
1649
|
"fleet",
|
|
1567
1650
|
"work",
|
|
@@ -1685,7 +1768,7 @@ function getSidebarWidth(windowWidth, collapsed) {
|
|
|
1685
1768
|
}
|
|
1686
1769
|
|
|
1687
1770
|
// src/main/menu/index.ts
|
|
1688
|
-
import { Menu } from "electron";
|
|
1771
|
+
import { Menu as Menu2 } from "electron";
|
|
1689
1772
|
|
|
1690
1773
|
// src/main/menu/projects-menu.ts
|
|
1691
1774
|
import path3 from "node:path";
|
|
@@ -2018,7 +2101,7 @@ function configureApplicationMenu(ctx) {
|
|
|
2018
2101
|
buildWorkspaceMenu(ctx, actions, hasActiveWebui, activeWebuiPrefs, navigate),
|
|
2019
2102
|
buildViewMenu(ctx)
|
|
2020
2103
|
];
|
|
2021
|
-
|
|
2104
|
+
Menu2.setApplicationMenu(Menu2.buildFromTemplate(template));
|
|
2022
2105
|
}
|
|
2023
2106
|
|
|
2024
2107
|
// src/main/ipc-handlers/index.ts
|
|
@@ -2074,7 +2157,6 @@ import { z } from "zod";
|
|
|
2074
2157
|
var RUNTIME_ID_PATTERN = /^[a-zA-Z0-9._:-]{3,120}$/;
|
|
2075
2158
|
var runtimeIdSchema = z.string().regex(RUNTIME_ID_PATTERN, "Invalid runtime ID format");
|
|
2076
2159
|
var pathSchema = z.string().min(1).max(1e4);
|
|
2077
|
-
var nonEmptyStringSchema = z.string().min(1);
|
|
2078
2160
|
var booleanSchema = z.boolean();
|
|
2079
2161
|
var numberSchema = z.number().int().finite();
|
|
2080
2162
|
var openProjectSchema = z.object({
|
|
@@ -2308,8 +2390,11 @@ function isRecord2(value) {
|
|
|
2308
2390
|
}
|
|
2309
2391
|
|
|
2310
2392
|
// src/main/main.ts
|
|
2311
|
-
|
|
2312
|
-
|
|
2393
|
+
initMacOS();
|
|
2394
|
+
if (process.platform === "win32") {
|
|
2395
|
+
app2.setAppUserModelId("com.wrongstack.desktop");
|
|
2396
|
+
}
|
|
2397
|
+
app2.setPath("userData", path4.join(wstackGlobalRoot3(), "desktop", "electron-profile"));
|
|
2313
2398
|
var manager = new DesktopRuntimeManager();
|
|
2314
2399
|
var bridge = new DesktopAgentBridge();
|
|
2315
2400
|
var mainWindow = null;
|
|
@@ -2341,6 +2426,22 @@ function sameOrigin(candidate, base) {
|
|
|
2341
2426
|
return false;
|
|
2342
2427
|
}
|
|
2343
2428
|
}
|
|
2429
|
+
function revealInExplorer(root) {
|
|
2430
|
+
shell.openPath(root).catch((err) => {
|
|
2431
|
+
if (process.platform === "darwin") {
|
|
2432
|
+
void shell.openPath(path4.dirname(root)).catch(() => void 0);
|
|
2433
|
+
}
|
|
2434
|
+
console.error(
|
|
2435
|
+
JSON.stringify({
|
|
2436
|
+
level: "warn",
|
|
2437
|
+
event: "desktop.reveal_in_explorer_failed",
|
|
2438
|
+
root,
|
|
2439
|
+
message: err instanceof Error ? err.message : String(err),
|
|
2440
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2441
|
+
})
|
|
2442
|
+
);
|
|
2443
|
+
});
|
|
2444
|
+
}
|
|
2344
2445
|
function setShellSidebarCollapsed(collapsed) {
|
|
2345
2446
|
shellSidebarCollapsed = collapsed;
|
|
2346
2447
|
layoutWebuiViews();
|
|
@@ -2885,7 +2986,7 @@ function createMenuContext() {
|
|
|
2885
2986
|
shell.openExternal(url);
|
|
2886
2987
|
},
|
|
2887
2988
|
revealInExplorer: (root) => {
|
|
2888
|
-
|
|
2989
|
+
revealInExplorer(root);
|
|
2889
2990
|
}
|
|
2890
2991
|
};
|
|
2891
2992
|
}
|
|
@@ -2922,7 +3023,7 @@ function buildIpcHandlerContext() {
|
|
|
2922
3023
|
abortRuntime: (id, wsUrl) => bridge.abort(id, wsUrl),
|
|
2923
3024
|
openExternal: (url) => safeOpenExternal(url),
|
|
2924
3025
|
revealInExplorer: (root) => {
|
|
2925
|
-
|
|
3026
|
+
revealInExplorer(root);
|
|
2926
3027
|
},
|
|
2927
3028
|
findWebuiEntryBySenderId: (senderId) => findWebuiEntryBySenderId(senderId),
|
|
2928
3029
|
getPendingWebuiCommandAcks: () => pendingWebuiCommandAcks,
|
|
@@ -2953,12 +3054,29 @@ async function boot() {
|
|
|
2953
3054
|
const defaultWidth = 1180;
|
|
2954
3055
|
const defaultHeight = 720;
|
|
2955
3056
|
let appIcon;
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
3057
|
+
if (process.platform !== "darwin") {
|
|
3058
|
+
try {
|
|
3059
|
+
const iconPath = new URL("../../assets/icon.svg", import.meta.url).pathname;
|
|
3060
|
+
await fs3.stat(iconPath);
|
|
3061
|
+
appIcon = nativeImage.createFromPath(iconPath);
|
|
3062
|
+
if (appIcon.isEmpty()) appIcon = void 0;
|
|
3063
|
+
} catch {
|
|
3064
|
+
}
|
|
3065
|
+
} else {
|
|
3066
|
+
try {
|
|
3067
|
+
const pngPath = new URL("../../assets/icon.png", import.meta.url).pathname;
|
|
3068
|
+
await fs3.stat(pngPath);
|
|
3069
|
+
appIcon = nativeImage.createFromPath(pngPath);
|
|
3070
|
+
if (appIcon.isEmpty()) appIcon = void 0;
|
|
3071
|
+
} catch {
|
|
3072
|
+
try {
|
|
3073
|
+
const icnsPath = new URL("../../assets/icon.icns", import.meta.url).pathname;
|
|
3074
|
+
await fs3.stat(icnsPath);
|
|
3075
|
+
appIcon = nativeImage.createFromPath(icnsPath);
|
|
3076
|
+
if (appIcon.isEmpty()) appIcon = void 0;
|
|
3077
|
+
} catch {
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
2962
3080
|
}
|
|
2963
3081
|
const winOptions = {
|
|
2964
3082
|
width: prevState?.width ?? defaultWidth,
|
|
@@ -2994,6 +3112,11 @@ async function boot() {
|
|
|
2994
3112
|
configureApplicationMenu2();
|
|
2995
3113
|
broadcastState();
|
|
2996
3114
|
});
|
|
3115
|
+
app2.on("open-file", (_event, filePath) => {
|
|
3116
|
+
if (shellView && !shellView.webContents.isDestroyed()) {
|
|
3117
|
+
shellView.webContents.send(IPC.openFile, filePath);
|
|
3118
|
+
}
|
|
3119
|
+
});
|
|
2997
3120
|
let lastWatchedLocale;
|
|
2998
3121
|
watchProviderConfig(
|
|
2999
3122
|
desktopConfigPaths.globalConfigPath,
|
|
@@ -3017,17 +3140,25 @@ async function boot() {
|
|
|
3017
3140
|
disposeAllWebuiEntries();
|
|
3018
3141
|
void saveWindowState();
|
|
3019
3142
|
quittingAfterCleanup = true;
|
|
3020
|
-
|
|
3143
|
+
app2.exit(0);
|
|
3021
3144
|
});
|
|
3022
3145
|
await restoreLastWorkspace();
|
|
3146
|
+
const argvOpenPath = firstOpenFileArg(process.argv);
|
|
3147
|
+
const queuedOpenPath = drainPendingOpenFilePath();
|
|
3148
|
+
const openPath = argvOpenPath ?? queuedOpenPath;
|
|
3149
|
+
if (openPath && shellView && !shellView.webContents.isDestroyed()) {
|
|
3150
|
+
shellView.webContents.send(IPC.openFile, openPath);
|
|
3151
|
+
}
|
|
3023
3152
|
mainWindow.show();
|
|
3024
3153
|
shellView.webContents.focus();
|
|
3025
3154
|
}
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3155
|
+
app2.whenReady().then(boot);
|
|
3156
|
+
app2.on("window-all-closed", () => {
|
|
3157
|
+
if (process.platform !== "darwin") {
|
|
3158
|
+
app2.quit();
|
|
3159
|
+
}
|
|
3029
3160
|
});
|
|
3030
|
-
|
|
3161
|
+
app2.on("before-quit", () => {
|
|
3031
3162
|
if (mainWindow) {
|
|
3032
3163
|
mainWindow.removeAllListeners("close");
|
|
3033
3164
|
void saveWindowState();
|
|
@@ -3035,7 +3166,7 @@ app.on("before-quit", () => {
|
|
|
3035
3166
|
bridge.closeAll();
|
|
3036
3167
|
disposeAllWebuiEntries();
|
|
3037
3168
|
});
|
|
3038
|
-
|
|
3169
|
+
app2.on("activate", () => {
|
|
3039
3170
|
if (!mainWindow) return;
|
|
3040
3171
|
mainWindow.show();
|
|
3041
3172
|
shellView?.webContents.focus();
|