local-operator-ui 0.19.6 → 0.20.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.
Files changed (69) hide show
  1. package/bin/ensure-electron.js +47 -0
  2. package/bin/linux-sandbox.js +27 -18
  3. package/bin/postinstall.js +55 -33
  4. package/out/main/index.js +209 -417
  5. package/out/renderer/assets/{_basePickBy-Duzo68Xw.js → _basePickBy-FfClaKQg.js} +1 -1
  6. package/out/renderer/assets/{_baseUniq-BeJmcE9M.js → _baseUniq-C9SvGZui.js} +1 -1
  7. package/out/renderer/assets/{agent-details-page-B-rZ1RvZ.js → agent-details-page-AoSG_fVH.js} +1 -1
  8. package/out/renderer/assets/{agent-hub-page-CBL3Npvq.js → agent-hub-page-CaZjaTZe.js} +1 -1
  9. package/out/renderer/assets/{agents-page-7rG5Vl9M.js → agents-page-RS6PE_fF.js} +2 -2
  10. package/out/renderer/assets/{architectureDiagram-IEHRJDOE-BsT5wnLG.js → architectureDiagram-IEHRJDOE-Be7LQKHg.js} +1 -1
  11. package/out/renderer/assets/{blockDiagram-JOT3LUYC-JEwDyed4.js → blockDiagram-JOT3LUYC-iWnvArS2.js} +1 -1
  12. package/out/renderer/assets/{c4Diagram-VJAJSXHY-C4pGCoOs.js → c4Diagram-VJAJSXHY-BBuir5yQ.js} +1 -1
  13. package/out/renderer/assets/channel-D4JK8GjQ.js +1 -0
  14. package/out/renderer/assets/{chunk-4BMEZGHF-CNXrCcWD.js → chunk-4BMEZGHF-DzRvFZnz.js} +1 -1
  15. package/out/renderer/assets/{chunk-A2AXSNBT-Cs3JTrFa.js → chunk-A2AXSNBT-4uP9DbW7.js} +1 -1
  16. package/out/renderer/assets/{chunk-AEK57VVT-Cf3YXadW.js → chunk-AEK57VVT-BL3rbHq4.js} +1 -1
  17. package/out/renderer/assets/{chunk-D6G4REZN-Broh2kYr.js → chunk-D6G4REZN-D6wbdfUw.js} +1 -1
  18. package/out/renderer/assets/{chunk-RZ5BOZE2-CidGAd_y.js → chunk-RZ5BOZE2-D2Fl_NaB.js} +1 -1
  19. package/out/renderer/assets/{chunk-XZIHB7SX-BMBZY-Ob.js → chunk-XZIHB7SX-DN5jo0Xq.js} +1 -1
  20. package/out/renderer/assets/classDiagram-GIVACNV2-yxaMQW5a.js +1 -0
  21. package/out/renderer/assets/classDiagram-v2-COTLJTTW-yxaMQW5a.js +1 -0
  22. package/out/renderer/assets/clone-B7rlppnW.js +1 -0
  23. package/out/renderer/assets/{compact-pagination-n3Xl8pZ8.js → compact-pagination-20O8NjDK.js} +1 -1
  24. package/out/renderer/assets/{dagre-OKDRZEBW-Bz_ICygp.js → dagre-OKDRZEBW-BYIesx33.js} +1 -1
  25. package/out/renderer/assets/{diagram-SSKATNLV-BTVMb1kE.js → diagram-SSKATNLV-DP6lL-Te.js} +1 -1
  26. package/out/renderer/assets/{diagram-VNBRO52H-DfljiV4G.js → diagram-VNBRO52H-bmsCnWFr.js} +1 -1
  27. package/out/renderer/assets/{erDiagram-Q7BY3M3F-BRUMJB0F.js → erDiagram-Q7BY3M3F-EsgbzeoI.js} +1 -1
  28. package/out/renderer/assets/{flowDiagram-4HSFHLVR-BjcUuq_P.js → flowDiagram-4HSFHLVR-DOiNzXZN.js} +1 -1
  29. package/out/renderer/assets/{ganttDiagram-APWFNJXF-ovQikGsn.js → ganttDiagram-APWFNJXF-DJmMxmWH.js} +1 -1
  30. package/out/renderer/assets/{gitGraphDiagram-7IBYFJ6S-CrDG1pZY.js → gitGraphDiagram-7IBYFJ6S-CsW8qQBE.js} +1 -1
  31. package/out/renderer/assets/{graph-kwCSE5gm.js → graph-DPdUvm6W.js} +1 -1
  32. package/out/renderer/assets/{icon-DaedMBiD.css → icon-HSrrv8O-.css} +1 -1
  33. package/out/renderer/assets/{index-BbTvTNw0.js → index-BHWYYomf.js} +1 -1
  34. package/out/renderer/assets/{index-D3g23Ep3.js → index-C2JWjezT.js} +1 -1
  35. package/out/renderer/assets/{index-DOpsBDAL.js → index-DTxYU-h1.js} +310 -310
  36. package/out/renderer/assets/{infoDiagram-PH2N3AL5-CBAvcVVb.js → infoDiagram-PH2N3AL5-DlGp0OAs.js} +1 -1
  37. package/out/renderer/assets/{installer-poO56j69.js → installer-Ck14_4Oh.js} +1 -1
  38. package/out/renderer/assets/{journeyDiagram-U35MCT3I-kxtnE0E0.js → journeyDiagram-U35MCT3I-BMKeuZdQ.js} +1 -1
  39. package/out/renderer/assets/{kanban-definition-NDS4AKOZ-Cp_ZcAfm.js → kanban-definition-NDS4AKOZ-CBMkFWiV.js} +1 -1
  40. package/out/renderer/assets/{layout-DkMOECVe.js → layout-CQLCCDdm.js} +1 -1
  41. package/out/renderer/assets/{legacy-agents-page-Bm9y4VzQ.js → legacy-agents-page-DaL-s8eO.js} +1 -1
  42. package/out/renderer/assets/{mermaid.core-BdThqeRN.js → mermaid.core-zhMaqo9l.js} +5 -5
  43. package/out/renderer/assets/{mindmap-definition-ALO5MXBD-CmnY7qkU.js → mindmap-definition-ALO5MXBD-ChxcwGV6.js} +1 -1
  44. package/out/renderer/assets/{page-header-zecAylNs.js → page-header-D-uc8qqA.js} +1 -1
  45. package/out/renderer/assets/{parseISO-BBQqU7gh.js → parseISO-Bgv71POy.js} +1 -1
  46. package/out/renderer/assets/{pieDiagram-IB7DONF6-CT6aweg_.js → pieDiagram-IB7DONF6-BMEW9BJi.js} +1 -1
  47. package/out/renderer/assets/{quadrantDiagram-7GDLP6J5-B9mprDDC.js → quadrantDiagram-7GDLP6J5-D-ErPCKs.js} +1 -1
  48. package/out/renderer/assets/{radar-MK3ICKWK-BbnAUJmd.js → radar-MK3ICKWK-2tp4r77h.js} +1 -1
  49. package/out/renderer/assets/{radient-auth-buttons-DQwcB7Kb.js → radient-auth-buttons-klNSjDud.js} +1 -1
  50. package/out/renderer/assets/{requirementDiagram-KVF5MWMF-vDOfXFEQ.js → requirementDiagram-KVF5MWMF-nNjxV4M0.js} +1 -1
  51. package/out/renderer/assets/{sankeyDiagram-QLVOVGJD-B4f16uUk.js → sankeyDiagram-QLVOVGJD-HK65A8n7.js} +1 -1
  52. package/out/renderer/assets/{schedules-page-B8xcfay1.js → schedules-page-CLrcFhCL.js} +1 -1
  53. package/out/renderer/assets/{sequenceDiagram-X6HHIX6F-B99VW_Zk.js → sequenceDiagram-X6HHIX6F-D3VDaA9I.js} +1 -1
  54. package/out/renderer/assets/{settings-page-DCLwiyj6.js → settings-page-CKVWBbsu.js} +1 -1
  55. package/out/renderer/assets/{square-pen-CdJTC74b.js → square-pen-CQEKS3JT.js} +1 -1
  56. package/out/renderer/assets/{stateDiagram-DGXRK772-DrhFdhdz.js → stateDiagram-DGXRK772-BJMfya--.js} +1 -1
  57. package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-CmCw0Yzl.js +1 -0
  58. package/out/renderer/assets/{timeline-definition-BDJGKUSR-D_VVC3lo.js → timeline-definition-BDJGKUSR-wvXoFLOl.js} +1 -1
  59. package/out/renderer/assets/{use-agent-like-mutation-C8Hn5OU7.js → use-agent-like-mutation-DAmS19om.js} +1 -1
  60. package/out/renderer/assets/{xychartDiagram-VJFVF3MP-CHmZVi_C.js → xychartDiagram-VJFVF3MP-DnyQ060j.js} +1 -1
  61. package/out/renderer/index.html +3 -3
  62. package/out/renderer/installer.html +3 -3
  63. package/package.json +69 -58
  64. package/out/renderer/assets/channel-C4lq_kmR.js +0 -1
  65. package/out/renderer/assets/classDiagram-GIVACNV2-BpO5Iy7a.js +0 -1
  66. package/out/renderer/assets/classDiagram-v2-COTLJTTW-BpO5Iy7a.js +0 -1
  67. package/out/renderer/assets/clone-CuQYVeZK.js +0 -1
  68. package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-uaCZR48L.js +0 -1
  69. /package/out/renderer/assets/{icon-DMNb6cX-.js → icon-RIkwUxL5.js} +0 -0
package/out/main/index.js CHANGED
@@ -1,19 +1,17 @@
1
1
  "use strict";
2
2
  const fs = require("node:fs");
3
- const path = require("node:path");
3
+ const path$1 = require("node:path");
4
4
  const node_url = require("node:url");
5
5
  const utils = require("@electron-toolkit/utils");
6
6
  const electron = require("electron");
7
7
  const posthogNode = require("posthog-node");
8
- const require$$1 = require("path");
8
+ const path = require("path");
9
9
  const node_child_process = require("node:child_process");
10
10
  const node_crypto = require("node:crypto");
11
11
  const os = require("node:os");
12
12
  const node_util = require("node:util");
13
13
  const zod = require("zod");
14
- const require$$0 = require("fs");
15
- const require$$2 = require("os");
16
- const require$$3 = require("crypto");
14
+ const dotenv = require("dotenv");
17
15
  const electronLog = require("electron-log");
18
16
  const https = require("node:https");
19
17
  const electronUpdater = require("electron-updater");
@@ -33,9 +31,9 @@ function _interopNamespaceDefault(e) {
33
31
  n.default = e;
34
32
  return Object.freeze(n);
35
33
  }
36
- const path__namespace = /* @__PURE__ */ _interopNamespaceDefault(path);
34
+ const path__namespace = /* @__PURE__ */ _interopNamespaceDefault(path$1);
37
35
  const https__namespace = /* @__PURE__ */ _interopNamespaceDefault(https);
38
- const icon = require$$1.join(__dirname, "../../resources/icon.png");
36
+ const icon = path.join(__dirname, "../../resources/icon.png");
39
37
  const id$1 = zod.z.string().min(1).max(128).regex(/^[a-zA-Z0-9_-]+$/);
40
38
  const MAX_UPLOAD_BYTES = 16 * 1024 * 1024;
41
39
  const MAX_DOWNLOAD_BYTES = 32 * 1024 * 1024;
@@ -475,6 +473,11 @@ const desktopRequestSchema = zod.z.discriminatedUnion("op", [
475
473
  visible: zod.z.boolean(),
476
474
  canNotify: zod.z.boolean()
477
475
  }).strict(),
476
+ // Speculative runtime engage. Carries no payload BY DESIGN: it admits no
477
+ // work, so it is not receipt-keyed and not a `MESSAGE_OPS` member - see
478
+ // `desktopRequestByteBudget`. Firing it costs the control budget and a
479
+ // 2-byte body, which is what lets the renderer issue it from a keystroke.
480
+ zod.z.object({ op: zod.z.literal("sessions.warm"), sessionId }).strict(),
478
481
  // The legacy surface, reached through the same authenticated vocabulary as
479
482
  // everything else. These routes are gated in managed mode (agent inventory,
480
483
  // cwd paths, job history and conversation content are the same tenant's data
@@ -944,6 +947,16 @@ function desktopEndpoint(request) {
944
947
  can_notify: request.canNotify
945
948
  }
946
949
  };
950
+ case "sessions.warm":
951
+ return {
952
+ path: `/v1/desktop/sessions/${request.sessionId}/warm`,
953
+ method: "POST",
954
+ // `{}` rather than `undefined`: the transport only sets
955
+ // Content-Type when a body exists, and the route's pydantic input
956
+ // forbids extras but still wants a JSON OBJECT. An omitted body
957
+ // makes a legal call answer 422.
958
+ body: {}
959
+ };
947
960
  case "legacy.models": {
948
961
  const query = new URLSearchParams();
949
962
  if (request.provider) query.set("provider", request.provider);
@@ -1329,7 +1342,7 @@ function insideAppBundle(path2) {
1329
1342
  return path2.split(PATH_SEPARATORS).some((segment) => segment.length > 4 && segment.endsWith(".app"));
1330
1343
  }
1331
1344
  function pythonBytecodeCacheDir(userDataDir) {
1332
- return path.join(userDataDir, PYTHON_BYTECODE_CACHE_DIR_NAME);
1345
+ return path$1.join(userDataDir, PYTHON_BYTECODE_CACHE_DIR_NAME);
1333
1346
  }
1334
1347
  function withPythonBytecodeCache(env, userDataDir) {
1335
1348
  const existing = env.PYTHONPYCACHEPREFIX?.trim();
@@ -1338,7 +1351,7 @@ function withPythonBytecodeCache(env, userDataDir) {
1338
1351
  }
1339
1352
  const BUNDLED_PYTHON_TREE_NAMES = ["python", "python_aarch64"];
1340
1353
  function bundledPythonTreePaths(resourcesPath) {
1341
- return BUNDLED_PYTHON_TREE_NAMES.map((name) => path.join(resourcesPath, name));
1354
+ return BUNDLED_PYTHON_TREE_NAMES.map((name) => path$1.join(resourcesPath, name));
1342
1355
  }
1343
1356
  const FIND = "/usr/bin/find";
1344
1357
  const CHMOD = "/bin/chmod";
@@ -1411,279 +1424,6 @@ function applyAce(tree, selector, ace, failures) {
1411
1424
  for (const byte of run.stdout) if (byte === 0) selected += 1;
1412
1425
  return selected;
1413
1426
  }
1414
- var main = { exports: {} };
1415
- const version = "16.5.0";
1416
- const require$$4 = {
1417
- version
1418
- };
1419
- var hasRequiredMain;
1420
- function requireMain() {
1421
- if (hasRequiredMain) return main.exports;
1422
- hasRequiredMain = 1;
1423
- const fs2 = require$$0;
1424
- const path2 = require$$1;
1425
- const os2 = require$$2;
1426
- const crypto = require$$3;
1427
- const packageJson = require$$4;
1428
- const version2 = packageJson.version;
1429
- const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
1430
- function parse(src) {
1431
- const obj = {};
1432
- let lines = src.toString();
1433
- lines = lines.replace(/\r\n?/mg, "\n");
1434
- let match;
1435
- while ((match = LINE.exec(lines)) != null) {
1436
- const key = match[1];
1437
- let value = match[2] || "";
1438
- value = value.trim();
1439
- const maybeQuote = value[0];
1440
- value = value.replace(/^(['"`])([\s\S]*)\1$/mg, "$2");
1441
- if (maybeQuote === '"') {
1442
- value = value.replace(/\\n/g, "\n");
1443
- value = value.replace(/\\r/g, "\r");
1444
- }
1445
- obj[key] = value;
1446
- }
1447
- return obj;
1448
- }
1449
- function _parseVault(options) {
1450
- const vaultPath = _vaultPath(options);
1451
- const result = DotenvModule.configDotenv({ path: vaultPath });
1452
- if (!result.parsed) {
1453
- const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
1454
- err.code = "MISSING_DATA";
1455
- throw err;
1456
- }
1457
- const keys = _dotenvKey(options).split(",");
1458
- const length = keys.length;
1459
- let decrypted;
1460
- for (let i = 0; i < length; i++) {
1461
- try {
1462
- const key = keys[i].trim();
1463
- const attrs = _instructions(result, key);
1464
- decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
1465
- break;
1466
- } catch (error) {
1467
- if (i + 1 >= length) {
1468
- throw error;
1469
- }
1470
- }
1471
- }
1472
- return DotenvModule.parse(decrypted);
1473
- }
1474
- function _warn(message) {
1475
- console.log(`[dotenv@${version2}][WARN] ${message}`);
1476
- }
1477
- function _debug(message) {
1478
- console.log(`[dotenv@${version2}][DEBUG] ${message}`);
1479
- }
1480
- function _dotenvKey(options) {
1481
- if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {
1482
- return options.DOTENV_KEY;
1483
- }
1484
- if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {
1485
- return process.env.DOTENV_KEY;
1486
- }
1487
- return "";
1488
- }
1489
- function _instructions(result, dotenvKey) {
1490
- let uri;
1491
- try {
1492
- uri = new URL(dotenvKey);
1493
- } catch (error) {
1494
- if (error.code === "ERR_INVALID_URL") {
1495
- const err = new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development");
1496
- err.code = "INVALID_DOTENV_KEY";
1497
- throw err;
1498
- }
1499
- throw error;
1500
- }
1501
- const key = uri.password;
1502
- if (!key) {
1503
- const err = new Error("INVALID_DOTENV_KEY: Missing key part");
1504
- err.code = "INVALID_DOTENV_KEY";
1505
- throw err;
1506
- }
1507
- const environment = uri.searchParams.get("environment");
1508
- if (!environment) {
1509
- const err = new Error("INVALID_DOTENV_KEY: Missing environment part");
1510
- err.code = "INVALID_DOTENV_KEY";
1511
- throw err;
1512
- }
1513
- const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
1514
- const ciphertext = result.parsed[environmentKey];
1515
- if (!ciphertext) {
1516
- const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
1517
- err.code = "NOT_FOUND_DOTENV_ENVIRONMENT";
1518
- throw err;
1519
- }
1520
- return { ciphertext, key };
1521
- }
1522
- function _vaultPath(options) {
1523
- let possibleVaultPath = null;
1524
- if (options && options.path && options.path.length > 0) {
1525
- if (Array.isArray(options.path)) {
1526
- for (const filepath of options.path) {
1527
- if (fs2.existsSync(filepath)) {
1528
- possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
1529
- }
1530
- }
1531
- } else {
1532
- possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
1533
- }
1534
- } else {
1535
- possibleVaultPath = path2.resolve(process.cwd(), ".env.vault");
1536
- }
1537
- if (fs2.existsSync(possibleVaultPath)) {
1538
- return possibleVaultPath;
1539
- }
1540
- return null;
1541
- }
1542
- function _resolveHome(envPath) {
1543
- return envPath[0] === "~" ? path2.join(os2.homedir(), envPath.slice(1)) : envPath;
1544
- }
1545
- function _configVault(options) {
1546
- const debug = Boolean(options && options.debug);
1547
- if (debug) {
1548
- _debug("Loading env from encrypted .env.vault");
1549
- }
1550
- const parsed = DotenvModule._parseVault(options);
1551
- let processEnv = process.env;
1552
- if (options && options.processEnv != null) {
1553
- processEnv = options.processEnv;
1554
- }
1555
- DotenvModule.populate(processEnv, parsed, options);
1556
- return { parsed };
1557
- }
1558
- function configDotenv(options) {
1559
- const dotenvPath = path2.resolve(process.cwd(), ".env");
1560
- let encoding = "utf8";
1561
- const debug = Boolean(options && options.debug);
1562
- if (options && options.encoding) {
1563
- encoding = options.encoding;
1564
- } else {
1565
- if (debug) {
1566
- _debug("No encoding is specified. UTF-8 is used by default");
1567
- }
1568
- }
1569
- let optionPaths = [dotenvPath];
1570
- if (options && options.path) {
1571
- if (!Array.isArray(options.path)) {
1572
- optionPaths = [_resolveHome(options.path)];
1573
- } else {
1574
- optionPaths = [];
1575
- for (const filepath of options.path) {
1576
- optionPaths.push(_resolveHome(filepath));
1577
- }
1578
- }
1579
- }
1580
- let lastError;
1581
- const parsedAll = {};
1582
- for (const path22 of optionPaths) {
1583
- try {
1584
- const parsed = DotenvModule.parse(fs2.readFileSync(path22, { encoding }));
1585
- DotenvModule.populate(parsedAll, parsed, options);
1586
- } catch (e) {
1587
- if (debug) {
1588
- _debug(`Failed to load ${path22} ${e.message}`);
1589
- }
1590
- lastError = e;
1591
- }
1592
- }
1593
- let processEnv = process.env;
1594
- if (options && options.processEnv != null) {
1595
- processEnv = options.processEnv;
1596
- }
1597
- DotenvModule.populate(processEnv, parsedAll, options);
1598
- if (lastError) {
1599
- return { parsed: parsedAll, error: lastError };
1600
- } else {
1601
- return { parsed: parsedAll };
1602
- }
1603
- }
1604
- function config(options) {
1605
- if (_dotenvKey(options).length === 0) {
1606
- return DotenvModule.configDotenv(options);
1607
- }
1608
- const vaultPath = _vaultPath(options);
1609
- if (!vaultPath) {
1610
- _warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`);
1611
- return DotenvModule.configDotenv(options);
1612
- }
1613
- return DotenvModule._configVault(options);
1614
- }
1615
- function decrypt(encrypted, keyStr) {
1616
- const key = Buffer.from(keyStr.slice(-64), "hex");
1617
- let ciphertext = Buffer.from(encrypted, "base64");
1618
- const nonce = ciphertext.subarray(0, 12);
1619
- const authTag = ciphertext.subarray(-16);
1620
- ciphertext = ciphertext.subarray(12, -16);
1621
- try {
1622
- const aesgcm = crypto.createDecipheriv("aes-256-gcm", key, nonce);
1623
- aesgcm.setAuthTag(authTag);
1624
- return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
1625
- } catch (error) {
1626
- const isRange = error instanceof RangeError;
1627
- const invalidKeyLength = error.message === "Invalid key length";
1628
- const decryptionFailed = error.message === "Unsupported state or unable to authenticate data";
1629
- if (isRange || invalidKeyLength) {
1630
- const err = new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");
1631
- err.code = "INVALID_DOTENV_KEY";
1632
- throw err;
1633
- } else if (decryptionFailed) {
1634
- const err = new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");
1635
- err.code = "DECRYPTION_FAILED";
1636
- throw err;
1637
- } else {
1638
- throw error;
1639
- }
1640
- }
1641
- }
1642
- function populate(processEnv, parsed, options = {}) {
1643
- const debug = Boolean(options && options.debug);
1644
- const override = Boolean(options && options.override);
1645
- if (typeof parsed !== "object") {
1646
- const err = new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
1647
- err.code = "OBJECT_REQUIRED";
1648
- throw err;
1649
- }
1650
- for (const key of Object.keys(parsed)) {
1651
- if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
1652
- if (override === true) {
1653
- processEnv[key] = parsed[key];
1654
- }
1655
- if (debug) {
1656
- if (override === true) {
1657
- _debug(`"${key}" is already defined and WAS overwritten`);
1658
- } else {
1659
- _debug(`"${key}" is already defined and was NOT overwritten`);
1660
- }
1661
- }
1662
- } else {
1663
- processEnv[key] = parsed[key];
1664
- }
1665
- }
1666
- }
1667
- const DotenvModule = {
1668
- configDotenv,
1669
- _configVault,
1670
- _parseVault,
1671
- config,
1672
- decrypt,
1673
- parse,
1674
- populate
1675
- };
1676
- main.exports.configDotenv = DotenvModule.configDotenv;
1677
- main.exports._configVault = DotenvModule._configVault;
1678
- main.exports._parseVault = DotenvModule._parseVault;
1679
- main.exports.config = DotenvModule.config;
1680
- main.exports.decrypt = DotenvModule.decrypt;
1681
- main.exports.parse = DotenvModule.parse;
1682
- main.exports.populate = DotenvModule.populate;
1683
- main.exports = DotenvModule;
1684
- return main.exports;
1685
- }
1686
- var mainExports = requireMain();
1687
1427
  var LogFileType = /* @__PURE__ */ ((LogFileType2) => {
1688
1428
  LogFileType2["INSTALLER"] = "backend-installer.log";
1689
1429
  LogFileType2["BACKEND"] = "backend-service.log";
@@ -1700,9 +1440,9 @@ class Logger {
1700
1440
  */
1701
1441
  constructor() {
1702
1442
  if (process.platform === "win32") {
1703
- this.logPath = path.join(electron.app.getPath("userData"), "logs");
1443
+ this.logPath = path$1.join(electron.app.getPath("userData"), "logs");
1704
1444
  } else if (process.platform === "darwin") {
1705
- this.logPath = path.join(
1445
+ this.logPath = path$1.join(
1706
1446
  electron.app.getPath("home"),
1707
1447
  "Library",
1708
1448
  "Application Support",
@@ -1710,7 +1450,7 @@ class Logger {
1710
1450
  "logs"
1711
1451
  );
1712
1452
  } else {
1713
- this.logPath = path.join(
1453
+ this.logPath = path$1.join(
1714
1454
  electron.app.getPath("home"),
1715
1455
  ".config",
1716
1456
  "local-operator",
@@ -1723,7 +1463,7 @@ class Logger {
1723
1463
  this.loggers = /* @__PURE__ */ new Map();
1724
1464
  for (const logFileType of Object.values(LogFileType)) {
1725
1465
  const logger2 = electronLog.create(`logger-${logFileType}`);
1726
- logger2.transports.file.resolvePath = () => path.join(this.logPath, logFileType);
1466
+ logger2.transports.file.resolvePath = () => path$1.join(this.logPath, logFileType);
1727
1467
  logger2.transports.file.level = "debug";
1728
1468
  logger2.transports.file.format = "[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}] {text}";
1729
1469
  logger2.transports.file.maxSize = 10 * 1024 * 1024;
@@ -1837,8 +1577,8 @@ class Logger {
1837
1577
  }
1838
1578
  }
1839
1579
  const logger = Logger.getInstance();
1840
- const envResult = mainExports.config({
1841
- path: path.join(process.cwd(), ".env"),
1580
+ const envResult = dotenv.config({
1581
+ path: path$1.join(process.cwd(), ".env"),
1842
1582
  override: true
1843
1583
  });
1844
1584
  if (envResult.error) {
@@ -2027,9 +1767,9 @@ class BackendServiceManager {
2027
1767
  );
2028
1768
  }
2029
1769
  if (process.platform === "win32") {
2030
- this.venvPath = path.join(this.appDataPath, "local-operator-venv");
1770
+ this.venvPath = path$1.join(this.appDataPath, "local-operator-venv");
2031
1771
  } else if (process.platform === "darwin") {
2032
- this.venvPath = path.join(
1772
+ this.venvPath = path$1.join(
2033
1773
  electron.app.getPath("home"),
2034
1774
  "Library",
2035
1775
  "Application Support",
@@ -2037,7 +1777,7 @@ class BackendServiceManager {
2037
1777
  "local-operator-venv"
2038
1778
  );
2039
1779
  } else {
2040
- this.venvPath = path.join(
1780
+ this.venvPath = path$1.join(
2041
1781
  electron.app.getPath("home"),
2042
1782
  ".config",
2043
1783
  "local-operator",
@@ -2120,10 +1860,10 @@ class BackendServiceManager {
2120
1860
  async loadMacOSEnvironment() {
2121
1861
  const home = os.homedir();
2122
1862
  const possibleFiles = [
2123
- path.join(home, ".zshrc"),
2124
- path.join(home, ".bash_profile"),
2125
- path.join(home, ".bashrc"),
2126
- path.join(home, ".profile")
1863
+ path$1.join(home, ".zshrc"),
1864
+ path$1.join(home, ".bash_profile"),
1865
+ path$1.join(home, ".bashrc"),
1866
+ path$1.join(home, ".profile")
2127
1867
  ];
2128
1868
  let shellConfigFile = null;
2129
1869
  for (const file of possibleFiles) {
@@ -2170,9 +1910,9 @@ class BackendServiceManager {
2170
1910
  async loadLinuxEnvironment() {
2171
1911
  const home = os.homedir();
2172
1912
  const possibleFiles = [
2173
- path.join(home, ".bashrc"),
2174
- path.join(home, ".zshrc"),
2175
- path.join(home, ".profile")
1913
+ path$1.join(home, ".bashrc"),
1914
+ path$1.join(home, ".zshrc"),
1915
+ path$1.join(home, ".profile")
2176
1916
  ];
2177
1917
  let shellConfigFile = null;
2178
1918
  for (const file of possibleFiles) {
@@ -2228,9 +1968,9 @@ class BackendServiceManager {
2228
1968
  }
2229
1969
  }
2230
1970
  const userProfile = process.env.USERPROFILE || os.homedir();
2231
- const pyenvDir = path.join(userProfile, ".pyenv");
2232
- const pyenvBinPath = path.join(pyenvDir, "pyenv-win", "bin");
2233
- const pyenvShimsPath = path.join(pyenvDir, "pyenv-win", "shims");
1971
+ const pyenvDir = path$1.join(userProfile, ".pyenv");
1972
+ const pyenvBinPath = path$1.join(pyenvDir, "pyenv-win", "bin");
1973
+ const pyenvShimsPath = path$1.join(pyenvDir, "pyenv-win", "shims");
2234
1974
  if (fs.existsSync(pyenvBinPath) && fs.existsSync(pyenvShimsPath)) {
2235
1975
  logger.info(
2236
1976
  `Found pyenv-win directories at ${pyenvBinPath} and ${pyenvShimsPath}`,
@@ -2243,7 +1983,7 @@ class BackendServiceManager {
2243
1983
  if (!currentPath.includes(pyenvShimsPath)) {
2244
1984
  this.shellEnv.PATH = `${pyenvShimsPath};${this.shellEnv.PATH}`;
2245
1985
  }
2246
- const pyenvWinPath = path.join(pyenvDir, "pyenv-win");
1986
+ const pyenvWinPath = path$1.join(pyenvDir, "pyenv-win");
2247
1987
  this.shellEnv.PYENV = pyenvWinPath;
2248
1988
  this.shellEnv.PYENV_HOME = pyenvWinPath;
2249
1989
  logger.info(
@@ -2256,7 +1996,7 @@ class BackendServiceManager {
2256
1996
  LogFileType.BACKEND
2257
1997
  );
2258
1998
  }
2259
- const venvScriptsPath = path.join(this.venvPath, "Scripts");
1999
+ const venvScriptsPath = path$1.join(this.venvPath, "Scripts");
2260
2000
  if (fs.existsSync(venvScriptsPath)) {
2261
2001
  const currentPath = this.shellEnv.PATH || "";
2262
2002
  if (!currentPath.includes(venvScriptsPath)) {
@@ -2445,7 +2185,7 @@ class BackendServiceManager {
2445
2185
  let cmd;
2446
2186
  let args;
2447
2187
  if (process.platform === "win32") {
2448
- const localOperatorExe = path.join(
2188
+ const localOperatorExe = path$1.join(
2449
2189
  this.venvPath,
2450
2190
  "Scripts",
2451
2191
  "local-operator.exe"
@@ -2454,7 +2194,7 @@ class BackendServiceManager {
2454
2194
  cmd = localOperatorExe;
2455
2195
  args = ["serve", "--port", this.port.toString()];
2456
2196
  } else {
2457
- const pythonExe = path.join(this.venvPath, "Scripts", "python.exe");
2197
+ const pythonExe = path$1.join(this.venvPath, "Scripts", "python.exe");
2458
2198
  if (fs.existsSync(pythonExe)) {
2459
2199
  cmd = pythonExe;
2460
2200
  args = [
@@ -2465,7 +2205,7 @@ class BackendServiceManager {
2465
2205
  this.port.toString()
2466
2206
  ];
2467
2207
  } else {
2468
- const activateScript = path.join(
2208
+ const activateScript = path$1.join(
2469
2209
  this.venvPath,
2470
2210
  "Scripts",
2471
2211
  "Activate.ps1"
@@ -2480,7 +2220,7 @@ class BackendServiceManager {
2480
2220
  }
2481
2221
  }
2482
2222
  } else {
2483
- const activateScript = path.join(this.venvPath, "bin", "activate");
2223
+ const activateScript = path$1.join(this.venvPath, "bin", "activate");
2484
2224
  cmd = "bash";
2485
2225
  args = [
2486
2226
  "-c",
@@ -3550,9 +3290,9 @@ class BackendInstaller {
3550
3290
  */
3551
3291
  constructor() {
3552
3292
  if (process.platform === "win32") {
3553
- this.venvPath = path.join(this.appDataPath, "local-operator-venv");
3293
+ this.venvPath = path$1.join(this.appDataPath, "local-operator-venv");
3554
3294
  } else if (process.platform === "darwin") {
3555
- this.venvPath = path.join(
3295
+ this.venvPath = path$1.join(
3556
3296
  electron.app.getPath("home"),
3557
3297
  "Library",
3558
3298
  "Application Support",
@@ -3560,14 +3300,14 @@ class BackendInstaller {
3560
3300
  "local-operator-venv"
3561
3301
  );
3562
3302
  } else {
3563
- this.venvPath = path.join(
3303
+ this.venvPath = path$1.join(
3564
3304
  electron.app.getPath("home"),
3565
3305
  ".config",
3566
3306
  "local-operator",
3567
3307
  "local-operator-venv"
3568
3308
  );
3569
3309
  }
3570
- this.resourcesPath = process.env.NODE_ENV === "development" ? path.join(process.cwd(), "resources") : path.join(process.resourcesPath);
3310
+ this.resourcesPath = process.env.NODE_ENV === "development" ? path$1.join(process.cwd(), "resources") : path$1.join(process.resourcesPath);
3571
3311
  if (electron.app.isPackaged) {
3572
3312
  const seal = sealPythonInterpreterTrees(
3573
3313
  bundledPythonTreePaths(process.resourcesPath)
@@ -3598,31 +3338,31 @@ class BackendInstaller {
3598
3338
  const possibilities = [];
3599
3339
  if (process.arch === "arm64") {
3600
3340
  possibilities.push(
3601
- path.join(process.resourcesPath, "python_aarch64", "bin", "python3"),
3341
+ path$1.join(process.resourcesPath, "python_aarch64", "bin", "python3"),
3602
3342
  // Packaged app (aarch64)
3603
- path.join(process.cwd(), "resources", "python_aarch64", "bin", "python3")
3343
+ path$1.join(process.cwd(), "resources", "python_aarch64", "bin", "python3")
3604
3344
  // Development (aarch64)
3605
3345
  );
3606
3346
  } else if (process.arch === "x64") {
3607
3347
  possibilities.push(
3608
- path.join(process.resourcesPath, "python", "bin", "python3"),
3348
+ path$1.join(process.resourcesPath, "python", "bin", "python3"),
3609
3349
  // Packaged app (x86_64)
3610
- path.join(process.cwd(), "resources", "python", "bin", "python3")
3350
+ path$1.join(process.cwd(), "resources", "python", "bin", "python3")
3611
3351
  // Development (x86_64)
3612
3352
  );
3613
3353
  }
3614
3354
  if (process.platform === "win32") {
3615
3355
  const userProfile = process.env.USERPROFILE || electron.app.getPath("home");
3616
- const pyenvDir = path.join(userProfile, ".pyenv");
3356
+ const pyenvDir = path$1.join(userProfile, ".pyenv");
3617
3357
  possibilities.push(
3618
3358
  // In packaged app (Windows)
3619
- path.join(process.resourcesPath, "python", "python.exe"),
3359
+ path$1.join(process.resourcesPath, "python", "python.exe"),
3620
3360
  // In development (Windows)
3621
- path.join(process.cwd(), "resources", "python", "python.exe"),
3361
+ path$1.join(process.cwd(), "resources", "python", "python.exe"),
3622
3362
  // Check for pyenv-win Python
3623
- path.join(pyenvDir, "pyenv-win", "versions", "3.12.0", "python.exe"),
3363
+ path$1.join(pyenvDir, "pyenv-win", "versions", "3.12.0", "python.exe"),
3624
3364
  // Check for pyenv-win shims
3625
- path.join(pyenvDir, "pyenv-win", "shims", "python.exe")
3365
+ path$1.join(pyenvDir, "pyenv-win", "shims", "python.exe")
3626
3366
  );
3627
3367
  }
3628
3368
  for (const path2 of possibilities) {
@@ -3652,7 +3392,7 @@ class BackendInstaller {
3652
3392
  }
3653
3393
  let localOperatorPath;
3654
3394
  if (process.platform === "win32") {
3655
- localOperatorPath = path.join(
3395
+ localOperatorPath = path$1.join(
3656
3396
  this.venvPath,
3657
3397
  "Scripts",
3658
3398
  "local-operator.exe"
@@ -3665,7 +3405,7 @@ class BackendInstaller {
3665
3405
  return false;
3666
3406
  }
3667
3407
  } else {
3668
- localOperatorPath = path.join(this.venvPath, "bin", "local-operator");
3408
+ localOperatorPath = path$1.join(this.venvPath, "bin", "local-operator");
3669
3409
  if (!fs.existsSync(localOperatorPath)) {
3670
3410
  logger.info(
3671
3411
  `local-operator executable not found at ${localOperatorPath}`,
@@ -3714,18 +3454,18 @@ class BackendInstaller {
3714
3454
  let args;
3715
3455
  const tempDir = os.tmpdir();
3716
3456
  if (process.platform === "win32") {
3717
- scriptPath = path.join(tempDir, "install-backend-windows.ps1");
3457
+ scriptPath = path$1.join(tempDir, "install-backend-windows.ps1");
3718
3458
  fs.writeFileSync(scriptPath, windowsInstallScript);
3719
3459
  cmd = "powershell.exe";
3720
3460
  args = ["-ExecutionPolicy", "Bypass", "-File", scriptPath];
3721
3461
  } else if (process.platform === "darwin") {
3722
- scriptPath = path.join(tempDir, "install-backend-macos.sh");
3462
+ scriptPath = path$1.join(tempDir, "install-backend-macos.sh");
3723
3463
  fs.writeFileSync(scriptPath, macosInstallScript);
3724
3464
  cmd = "bash";
3725
3465
  args = [scriptPath];
3726
3466
  fs.chmodSync(scriptPath, "755");
3727
3467
  } else {
3728
- scriptPath = path.join(tempDir, "install-backend-linux.sh");
3468
+ scriptPath = path$1.join(tempDir, "install-backend-linux.sh");
3729
3469
  fs.writeFileSync(scriptPath, linuxInstallScript);
3730
3470
  cmd = "bash";
3731
3471
  args = [scriptPath];
@@ -3753,7 +3493,7 @@ class BackendInstaller {
3753
3493
  moves with it. */
3754
3494
  backgroundColor: "#16130e",
3755
3495
  webPreferences: {
3756
- preload: path.join(__dirname, "../preload/index.js"),
3496
+ preload: path$1.join(__dirname, "../preload/index.js"),
3757
3497
  sandbox: false
3758
3498
  }
3759
3499
  });
@@ -3762,7 +3502,7 @@ class BackendInstaller {
3762
3502
  `${process.env.ELECTRON_RENDERER_URL}/installer`
3763
3503
  );
3764
3504
  } else {
3765
- progressWindow.loadFile(path.join(__dirname, "../renderer/installer.html"));
3505
+ progressWindow.loadFile(path$1.join(__dirname, "../renderer/installer.html"));
3766
3506
  }
3767
3507
  progressWindow.setMenuBarVisibility(false);
3768
3508
  let installationCancelled = false;
@@ -3926,7 +3666,7 @@ class BackendInstaller {
3926
3666
  "Backend installation completed successfully",
3927
3667
  LogFileType.INSTALLER
3928
3668
  );
3929
- const localOperatorPath = process.platform === "win32" ? path.join(this.venvPath, "Scripts", "local-operator.exe") : path.join(this.venvPath, "bin", "local-operator");
3669
+ const localOperatorPath = process.platform === "win32" ? path$1.join(this.venvPath, "Scripts", "local-operator.exe") : path$1.join(this.venvPath, "bin", "local-operator");
3930
3670
  if (!fs.existsSync(localOperatorPath)) {
3931
3671
  logger.error(
3932
3672
  `Installation verification failed: ${localOperatorPath} not found`,
@@ -3960,7 +3700,7 @@ class BackendInstaller {
3960
3700
  }
3961
3701
  await new Promise((resolve) => setTimeout(resolve, 500));
3962
3702
  if (process.platform === "win32") {
3963
- const transcriptPath = path.join(
3703
+ const transcriptPath = path$1.join(
3964
3704
  this.appDataPath,
3965
3705
  "backend-install-shell.log"
3966
3706
  );
@@ -4040,6 +3780,13 @@ function guardForegroundReceipts(window, send) {
4040
3780
  return send(input);
4041
3781
  };
4042
3782
  }
3783
+ function relayedBytes(value) {
3784
+ if (value instanceof ArrayBuffer) return new Uint8Array(value);
3785
+ if (!(value instanceof Uint8Array)) return null;
3786
+ const { buffer, byteOffset, byteLength } = value;
3787
+ if (!(buffer instanceof ArrayBuffer)) return null;
3788
+ return new Uint8Array(buffer, byteOffset, byteLength);
3789
+ }
4043
3790
  function registerDesktopIPC(window, expectedUrl, request, streams, media, notifier) {
4044
3791
  const opened = /* @__PURE__ */ new Map();
4045
3792
  function authorize(event) {
@@ -4076,7 +3823,7 @@ function registerDesktopIPC(window, expectedUrl, request, streams, media, notifi
4076
3823
  if (media) {
4077
3824
  electron.ipcMain.handle("desktop-media", (event, input, bytes) => {
4078
3825
  authorize(event);
4079
- const payload = bytes instanceof Uint8Array ? bytes : bytes instanceof ArrayBuffer ? new Uint8Array(bytes) : null;
3826
+ const payload = relayedBytes(bytes);
4080
3827
  return media(input, payload);
4081
3828
  });
4082
3829
  }
@@ -4326,9 +4073,9 @@ class DesktopNotifier {
4326
4073
  * reading of the backend, so an older probe still in flight must not settle
4327
4074
  * on top of it.
4328
4075
  */
4329
- setNotificationContract(version2) {
4076
+ setNotificationContract(version) {
4330
4077
  this.contractGeneration++;
4331
- this.applyNotificationContract(version2);
4078
+ this.applyNotificationContract(version);
4332
4079
  this.contractAnswered = true;
4333
4080
  }
4334
4081
  /**
@@ -4337,8 +4084,8 @@ class DesktopNotifier {
4337
4084
  * That invariant is the fix for R2-1, so a third caller that resets the
4338
4085
  * value without answering re-opens it.
4339
4086
  */
4340
- applyNotificationContract(version2) {
4341
- this.notificationContract = typeof version2 === "number" && Number.isFinite(version2) && version2 > 0 ? version2 : 0;
4087
+ applyNotificationContract(version) {
4088
+ this.notificationContract = typeof version === "number" && Number.isFinite(version) && version > 0 ? version : 0;
4342
4089
  }
4343
4090
  /**
4344
4091
  * Renderer heartbeat. Forwarded to the backend as the watch lease for the
@@ -4595,6 +4342,21 @@ class DesktopNotifier {
4595
4342
  notification.show();
4596
4343
  }
4597
4344
  }
4345
+ const lastPickedDirectory = /* @__PURE__ */ new Map();
4346
+ function withRememberedDirectory(kind, options, fallbackDirectory) {
4347
+ if (options.defaultPath) return options;
4348
+ const remembered = lastPickedDirectory.get(kind);
4349
+ if (remembered && fs.existsSync(remembered)) {
4350
+ return { ...options, defaultPath: remembered };
4351
+ }
4352
+ if (remembered) lastPickedDirectory.delete(kind);
4353
+ return { ...options, defaultPath: fallbackDirectory };
4354
+ }
4355
+ function rememberPickedDirectory(kind, filePaths, directoryPicked = false) {
4356
+ const [first] = filePaths;
4357
+ if (!first) return;
4358
+ lastPickedDirectory.set(kind, directoryPicked ? first : path$1.dirname(first));
4359
+ }
4598
4360
  const PENDING_INSTALL_MARKER_FILE = "pending-update-install.json";
4599
4361
  const INSTALL_DISK_SLACK_BYTES = 256 * 1024 * 1024;
4600
4362
  const DOWNLOAD_PAGE_URL = "https://local-operator.com/download";
@@ -4611,7 +4373,7 @@ const BAD_BUNDLE_MARKERS = [
4611
4373
  "-67062"
4612
4374
  ];
4613
4375
  function appBundleFromExecutable(execPath) {
4614
- const marker = `${path.join("Contents", "MacOS")}/`;
4376
+ const marker = `${path$1.join("Contents", "MacOS")}/`;
4615
4377
  const index = execPath.lastIndexOf(marker);
4616
4378
  if (index <= 0) return null;
4617
4379
  return execPath.slice(0, index - 1);
@@ -4634,10 +4396,10 @@ ${probe.stderr}`.trim();
4634
4396
  detail: marker ? `${marker}: ${output || "no output"}` : `codesign --verify exited ${probe.exitCode}: ${output || "no output"}`
4635
4397
  };
4636
4398
  }
4637
- function installedBundleSealBlock(appBundlePath, detail, version2) {
4399
+ function installedBundleSealBlock(appBundlePath, detail, version) {
4638
4400
  return {
4639
4401
  code: "installed-bundle-not-sealed",
4640
- message: version2 ? `This install of Local Operator can't be updated in place, so the update to version ${version2} was stopped before the app quit.` : "This install of Local Operator can't be updated in place, so the update was stopped before the app quit.",
4402
+ message: version ? `This install of Local Operator can't be updated in place, so the update to version ${version} was stopped before the app quit.` : "This install of Local Operator can't be updated in place, so the update was stopped before the app quit.",
4641
4403
  remedy: {
4642
4404
  text: "Quit Local Operator, then download a fresh copy and replace the app in Applications.",
4643
4405
  url: DOWNLOAD_PAGE_URL
@@ -4663,29 +4425,29 @@ function parseSealViolations(output) {
4663
4425
  }
4664
4426
  return violations;
4665
4427
  }
4666
- function canonicalPath(path$1) {
4428
+ function canonicalPath(path2) {
4667
4429
  try {
4668
- return fs.realpathSync(path$1);
4430
+ return fs.realpathSync(path2);
4669
4431
  } catch {
4670
4432
  try {
4671
- return path.join(fs.realpathSync(path.dirname(path$1)), path.basename(path$1));
4433
+ return path$1.join(fs.realpathSync(path$1.dirname(path2)), path$1.basename(path2));
4672
4434
  } catch {
4673
- return path$1;
4435
+ return path2;
4674
4436
  }
4675
4437
  }
4676
4438
  }
4677
4439
  const BUNDLED_PYTHON_DIRS = ["python", "python_aarch64"];
4678
4440
  function isPythonBytecodePath(bundlePath, candidate) {
4679
4441
  const bundle = canonicalPath(bundlePath);
4680
- const path$1 = canonicalPath(candidate);
4442
+ const path2 = canonicalPath(candidate);
4681
4443
  const dirs = BUNDLED_PYTHON_DIRS.map(
4682
- (name) => path.join(bundle, "Contents", "Resources", name)
4444
+ (name) => path$1.join(bundle, "Contents", "Resources", name)
4683
4445
  );
4684
4446
  const separator = "/";
4685
- if (!path$1.endsWith(".pyc")) return false;
4686
- const segments = path$1.split(separator);
4447
+ if (!path2.endsWith(".pyc")) return false;
4448
+ const segments = path2.split(separator);
4687
4449
  if (!segments.includes("__pycache__")) return false;
4688
- return dirs.some((dir) => path$1.startsWith(`${dir}${separator}`));
4450
+ return dirs.some((dir) => path2.startsWith(`${dir}${separator}`));
4689
4451
  }
4690
4452
  function planPythonBytecodeHeal(bundlePath, violations) {
4691
4453
  const added = violations.filter((violation) => violation.kind === "added");
@@ -4751,8 +4513,8 @@ function healPythonBytecode(bundlePath, violations, remove = (path2) => fs.rmSyn
4751
4513
  return { ...plan, removed };
4752
4514
  }
4753
4515
  function metadataBasenames(filePath, updatePath) {
4754
- const names = [path.basename(filePath)];
4755
- if (updatePath) names.push(path.basename(updatePath));
4516
+ const names = [path$1.basename(filePath)];
4517
+ if (updatePath) names.push(path$1.basename(updatePath));
4756
4518
  return names;
4757
4519
  }
4758
4520
  function matchArtifactMetadata(filePath, files, updatePath) {
@@ -4764,7 +4526,7 @@ function matchArtifactMetadata(filePath, files, updatePath) {
4764
4526
  url = decodeURIComponent(url);
4765
4527
  } catch {
4766
4528
  }
4767
- if (path.basename(url) === name) return file;
4529
+ if (path$1.basename(url) === name) return file;
4768
4530
  }
4769
4531
  }
4770
4532
  return null;
@@ -4781,7 +4543,7 @@ function measureDirectoryBytes(root) {
4781
4543
  if (!stats.isDirectory()) return stats.size;
4782
4544
  let total = 0;
4783
4545
  for (const entry of fs.readdirSync(root)) {
4784
- const child = path.join(root, entry);
4546
+ const child = path$1.join(root, entry);
4785
4547
  let childStats;
4786
4548
  try {
4787
4549
  childStats = fs.lstatSync(child);
@@ -4800,18 +4562,18 @@ function measureDirectoryBytes(root) {
4800
4562
  return null;
4801
4563
  }
4802
4564
  }
4803
- function versionClause(version2) {
4804
- return version2 ? ` to version ${version2}` : "";
4565
+ function versionClause(version) {
4566
+ return version ? ` to version ${version}` : "";
4805
4567
  }
4806
4568
  function verifyStagedArtifact(input) {
4807
- const name = path.basename(input.filePath);
4808
- const version2 = input.version ?? null;
4569
+ const name = path$1.basename(input.filePath);
4570
+ const version = input.version ?? null;
4809
4571
  if (input.metadata == null) {
4810
4572
  return {
4811
4573
  ok: false,
4812
4574
  block: {
4813
4575
  code: "artifact-metadata-missing",
4814
- message: `The downloaded update${versionClause(version2)} isn't listed in the release metadata, so it wasn't installed.`,
4576
+ message: `The downloaded update${versionClause(version)} isn't listed in the release metadata, so it wasn't installed.`,
4815
4577
  remedy: {
4816
4578
  text: "Check for updates again to re-download the release."
4817
4579
  },
@@ -4825,7 +4587,7 @@ function verifyStagedArtifact(input) {
4825
4587
  ok: false,
4826
4588
  block: {
4827
4589
  code: "download-verification-failed",
4828
- message: `The downloaded update${versionClause(version2)} doesn't match the published release, so it wasn't installed.`,
4590
+ message: `The downloaded update${versionClause(version)} doesn't match the published release, so it wasn't installed.`,
4829
4591
  remedy: {
4830
4592
  text: "Check for updates again to re-download the release."
4831
4593
  },
@@ -4839,7 +4601,7 @@ function verifyStagedArtifact(input) {
4839
4601
  ok: false,
4840
4602
  block: {
4841
4603
  code: "download-verification-failed",
4842
- message: `The downloaded update${versionClause(version2)} doesn't match the published release, so it wasn't installed.`,
4604
+ message: `The downloaded update${versionClause(version)} doesn't match the published release, so it wasn't installed.`,
4843
4605
  remedy: {
4844
4606
  text: "Check for updates again to re-download the release."
4845
4607
  },
@@ -4858,7 +4620,7 @@ function verifyStagedArtifact(input) {
4858
4620
  ok: false,
4859
4621
  block: {
4860
4622
  code: "insufficient-disk-space",
4861
- message: `There isn't enough free disk space to install the update${versionClause(version2)}, so it wasn't installed.`,
4623
+ message: `There isn't enough free disk space to install the update${versionClause(version)}, so it wasn't installed.`,
4862
4624
  remedy: {
4863
4625
  text: `Free up about ${formatGiB(needed - input.freeBytes)}, then check for updates again.`
4864
4626
  },
@@ -4878,12 +4640,12 @@ function resolveStagedArtifactPath(input) {
4878
4640
  const entries = input.listDir(input.pendingDir);
4879
4641
  for (const name of input.candidateNames) {
4880
4642
  const match = entries.find((entry) => entry === name);
4881
- if (match) return path.join(input.pendingDir, match);
4643
+ if (match) return path$1.join(input.pendingDir, match);
4882
4644
  }
4883
4645
  return null;
4884
4646
  }
4885
4647
  function pendingInstallMarkerPath(dir) {
4886
- return path.join(dir, PENDING_INSTALL_MARKER_FILE);
4648
+ return path$1.join(dir, PENDING_INSTALL_MARKER_FILE);
4887
4649
  }
4888
4650
  function writePendingInstallMarker(dir, marker) {
4889
4651
  fs.mkdirSync(dir, { recursive: true });
@@ -4927,7 +4689,7 @@ function clearPendingInstallMarker(dir) {
4927
4689
  }
4928
4690
  const LAST_INSTALL_ATTEMPT_FILE = "last-update-install.json";
4929
4691
  function lastInstallAttemptPath(dir) {
4930
- return path.join(dir, LAST_INSTALL_ATTEMPT_FILE);
4692
+ return path$1.join(dir, LAST_INSTALL_ATTEMPT_FILE);
4931
4693
  }
4932
4694
  function readLastInstallAttempt(dir) {
4933
4695
  const path2 = lastInstallAttemptPath(dir);
@@ -5014,7 +4776,7 @@ function shipItJobLabel(bundleId) {
5014
4776
  return `${bundleId}.ShipIt`;
5015
4777
  }
5016
4778
  function shipItCacheDir(cacheRoot, bundleId) {
5017
- return path.join(cacheRoot, shipItJobLabel(bundleId));
4779
+ return path$1.join(cacheRoot, shipItJobLabel(bundleId));
5018
4780
  }
5019
4781
  function watchdogSwapTarget(input) {
5020
4782
  if (!input.target) return null;
@@ -5304,7 +5066,7 @@ function reapFailedInstall(input) {
5304
5066
  if (!input.exists(cacheDir)) return result;
5305
5067
  for (const entry of input.listDir(cacheDir)) {
5306
5068
  if (!entry.startsWith("update.")) continue;
5307
- const staging = path.join(cacheDir, entry);
5069
+ const staging = path$1.join(cacheDir, entry);
5308
5070
  try {
5309
5071
  input.removeDir(staging);
5310
5072
  result.removedStaging.push(staging);
@@ -5337,14 +5099,14 @@ const LOCAL_OPERATOR_DIST_INFO = /^local[-_]operator[-_]/;
5337
5099
  function resolveDistributionMarkers(prefix) {
5338
5100
  const sitePackages = [];
5339
5101
  try {
5340
- for (const entry of fs.readdirSync(path.join(prefix, "lib"))) {
5102
+ for (const entry of fs.readdirSync(path$1.join(prefix, "lib"))) {
5341
5103
  if (!PYTHON_LIB_DIR.test(entry)) continue;
5342
- const candidate = path.join(prefix, "lib", entry, "site-packages");
5104
+ const candidate = path$1.join(prefix, "lib", entry, "site-packages");
5343
5105
  if (fs.existsSync(candidate)) sitePackages.push(candidate);
5344
5106
  }
5345
5107
  } catch {
5346
5108
  }
5347
- const windowsSitePackages = path.join(prefix, "Lib", "site-packages");
5109
+ const windowsSitePackages = path$1.join(prefix, "Lib", "site-packages");
5348
5110
  if (fs.existsSync(windowsSitePackages)) sitePackages.push(windowsSitePackages);
5349
5111
  let installer = null;
5350
5112
  let editable = false;
@@ -5358,15 +5120,15 @@ function resolveDistributionMarkers(prefix) {
5358
5120
  for (const entry of entries) {
5359
5121
  if (!LOCAL_OPERATOR_DIST_INFO.test(entry)) continue;
5360
5122
  if (!entry.endsWith(".dist-info")) continue;
5361
- const distInfo = path.join(dir, entry);
5123
+ const distInfo = path$1.join(dir, entry);
5362
5124
  try {
5363
- const installerText = fs.readFileSync(path.join(distInfo, "INSTALLER"), "utf8");
5125
+ const installerText = fs.readFileSync(path$1.join(distInfo, "INSTALLER"), "utf8");
5364
5126
  installer = installerText.trim().toLowerCase() || installer;
5365
5127
  } catch {
5366
5128
  }
5367
5129
  try {
5368
5130
  const payload = JSON.parse(
5369
- fs.readFileSync(path.join(distInfo, "direct_url.json"), "utf8")
5131
+ fs.readFileSync(path$1.join(distInfo, "direct_url.json"), "utf8")
5370
5132
  );
5371
5133
  if (payload.editable === true || payload.dir_info?.editable === true) {
5372
5134
  editable = true;
@@ -5386,11 +5148,11 @@ function commandSearchDirs(env, home) {
5386
5148
  if (trimmed.length === 0 || dirs.includes(trimmed)) return;
5387
5149
  dirs.push(trimmed);
5388
5150
  };
5389
- for (const dir of (env.PATH ?? "").split(path.delimiter)) add(dir);
5151
+ for (const dir of (env.PATH ?? "").split(path$1.delimiter)) add(dir);
5390
5152
  add(env.UV_TOOL_BIN_DIR);
5391
5153
  add(env.XDG_BIN_HOME);
5392
- if (env.XDG_DATA_HOME) add(path.join(env.XDG_DATA_HOME, "..", "bin"));
5393
- add(path.join(home, ".local", "bin"));
5154
+ if (env.XDG_DATA_HOME) add(path$1.join(env.XDG_DATA_HOME, "..", "bin"));
5155
+ add(path$1.join(home, ".local", "bin"));
5394
5156
  add("/opt/homebrew/bin");
5395
5157
  add("/usr/local/bin");
5396
5158
  add("/usr/bin");
@@ -5398,12 +5160,12 @@ function commandSearchDirs(env, home) {
5398
5160
  return dirs;
5399
5161
  }
5400
5162
  function uvToolBinDirs(env, home, listDir, platform) {
5401
- const root = env.UV_TOOL_DIR ?? (env.XDG_DATA_HOME ? path.join(env.XDG_DATA_HOME, "uv", "tools") : path.join(home, ".local", "share", "uv", "tools"));
5163
+ const root = env.UV_TOOL_DIR ?? (env.XDG_DATA_HOME ? path$1.join(env.XDG_DATA_HOME, "uv", "tools") : path$1.join(home, ".local", "share", "uv", "tools"));
5402
5164
  const scriptDir = platform === "win32" ? "Scripts" : "bin";
5403
5165
  const dirs = [];
5404
5166
  try {
5405
5167
  for (const entry of listDir(root)) {
5406
- dirs.push(path.join(root, entry, scriptDir));
5168
+ dirs.push(path$1.join(root, entry, scriptDir));
5407
5169
  }
5408
5170
  } catch {
5409
5171
  }
@@ -5422,10 +5184,10 @@ function windowsCommandExtensions(env) {
5422
5184
  return extensions;
5423
5185
  }
5424
5186
  function commandCandidates(dir, name, env, platform) {
5425
- const candidates = [path.join(dir, name)];
5187
+ const candidates = [path$1.join(dir, name)];
5426
5188
  if (platform !== "win32") return candidates;
5427
5189
  for (const extension of windowsCommandExtensions(env)) {
5428
- candidates.push(path.join(dir, name + extension));
5190
+ candidates.push(path$1.join(dir, name + extension));
5429
5191
  }
5430
5192
  return candidates;
5431
5193
  }
@@ -5471,15 +5233,15 @@ function readInstallIdentity(shimPath) {
5471
5233
  shebang = null;
5472
5234
  }
5473
5235
  const executable = realPath ?? shimPath;
5474
- const prefix = path.dirname(path.dirname(executable));
5236
+ const prefix = path$1.dirname(path$1.dirname(executable));
5475
5237
  const existing = (candidate) => fs.existsSync(candidate) ? candidate : null;
5476
5238
  const markers = resolveDistributionMarkers(prefix);
5477
5239
  return {
5478
5240
  path: shimPath,
5479
5241
  realPath,
5480
5242
  shebang,
5481
- uvReceipt: existing(path.join(prefix, "uv-receipt.toml")),
5482
- venvPrefix: fs.existsSync(path.join(prefix, "pyvenv.cfg")) ? prefix : null,
5243
+ uvReceipt: existing(path$1.join(prefix, "uv-receipt.toml")),
5244
+ venvPrefix: fs.existsSync(path$1.join(prefix, "pyvenv.cfg")) ? prefix : null,
5483
5245
  installer: markers.installer,
5484
5246
  editable: markers.editable
5485
5247
  };
@@ -5571,8 +5333,8 @@ const PIP_SHOW_VERSION_REGEX = /^Version:\s*(.+)$/m;
5571
5333
  function parsePipShowVersion(stdout) {
5572
5334
  const match = stdout.match(PIP_SHOW_VERSION_REGEX);
5573
5335
  if (!match) return null;
5574
- const version2 = match[1].trim();
5575
- return version2.length > 0 ? version2 : null;
5336
+ const version = match[1].trim();
5337
+ return version.length > 0 ? version : null;
5576
5338
  }
5577
5339
  function didUpgradeLand(input) {
5578
5340
  const { before, after, target: target2 } = input;
@@ -5588,8 +5350,8 @@ const BETA_VERSION_REGEX = /v\d+\.\d+\.\d+\.beta\.\d+/;
5588
5350
  const BUNDLE_ID_REGEX = /^[\w.-]+$/;
5589
5351
  const LAUNCHCTL_NOT_LOADED_REGEX = /could not find|no such process/i;
5590
5352
  const SEAL_PROBE_TIMEOUT_MS = 45e3;
5591
- function versionSuffix(version2) {
5592
- return version2 ? ` to version ${version2}` : "";
5353
+ function versionSuffix(version) {
5354
+ return version ? ` to version ${version}` : "";
5593
5355
  }
5594
5356
  function runCommand(command, args, options = {}) {
5595
5357
  return new Promise((resolve) => {
@@ -5766,14 +5528,14 @@ class UpdateService {
5766
5528
  * forgets, and the whole point of these checks is that the user gets an
5767
5529
  * explanation instead of an app that quits and never returns.
5768
5530
  */
5769
- sendInstallBlock(block, version2) {
5531
+ sendInstallBlock(block, version) {
5770
5532
  logger.error(
5771
5533
  `Update refused (${block.code}): ${block.detail}`,
5772
5534
  LogFileType.UPDATE_SERVICE
5773
5535
  );
5774
5536
  this.sendToRenderer("update-install-blocked", {
5775
5537
  code: block.code,
5776
- version: version2 ?? null,
5538
+ version: version ?? null,
5777
5539
  message: block.message,
5778
5540
  remedy: block.remedy,
5779
5541
  detail: block.detail
@@ -5852,7 +5614,7 @@ class UpdateService {
5852
5614
  if (!bundlePath) return null;
5853
5615
  const value = readCommandOutput("/usr/bin/defaults", [
5854
5616
  "read",
5855
- path.join(bundlePath, "Contents", "Info.plist"),
5617
+ path$1.join(bundlePath, "Contents", "Info.plist"),
5856
5618
  "CFBundleIdentifier"
5857
5619
  ]);
5858
5620
  return value && BUNDLE_ID_REGEX.test(value) ? value : null;
@@ -5874,8 +5636,8 @@ class UpdateService {
5874
5636
  shipItLog() {
5875
5637
  const bundleId = this.bundleIdentifier();
5876
5638
  if (!bundleId) return null;
5877
- const candidate = path.join(
5878
- shipItCacheDir(path.join(os.homedir(), "Library", "Caches"), bundleId),
5639
+ const candidate = path$1.join(
5640
+ shipItCacheDir(path$1.join(os.homedir(), "Library", "Caches"), bundleId),
5879
5641
  "ShipIt_stderr.log"
5880
5642
  );
5881
5643
  return fs.existsSync(candidate) ? candidate : null;
@@ -5897,7 +5659,7 @@ class UpdateService {
5897
5659
  try {
5898
5660
  const result = reapFailedInstall({
5899
5661
  bundleId: this.bundleIdentifier(),
5900
- cacheRoot: path.join(os.homedir(), "Library", "Caches"),
5662
+ cacheRoot: path$1.join(os.homedir(), "Library", "Caches"),
5901
5663
  removeJob: (label) => {
5902
5664
  const result2 = node_child_process.spawnSync("/bin/launchctl", ["remove", label], {
5903
5665
  encoding: "utf8",
@@ -6025,7 +5787,7 @@ class UpdateService {
6025
5787
  * those files restores the seal (measured; see `healPythonBytecode`), where a
6026
5788
  * bundle broken any other way still gets the reinstall refusal below.
6027
5789
  */
6028
- async probeInstalledBundleSeal(version2) {
5790
+ async probeInstalledBundleSeal(version) {
6029
5791
  if (process.platform !== "darwin" || !electron.app.isPackaged) return null;
6030
5792
  const bundlePath = appBundleFromExecutable(process.execPath);
6031
5793
  if (!bundlePath) {
@@ -6075,7 +5837,7 @@ class UpdateService {
6075
5837
  `Installed bundle is not healable in place: ${heal.reason}`,
6076
5838
  LogFileType.UPDATE_SERVICE
6077
5839
  );
6078
- return installedBundleSealBlock(bundlePath, seal.detail, version2);
5840
+ return installedBundleSealBlock(bundlePath, seal.detail, version);
6079
5841
  }
6080
5842
  logger.info(
6081
5843
  `Removed ${heal.removed.length} bytecode file(s) our own interpreter had written into the sealed bundle: ${heal.reason}. Paths:
@@ -6094,17 +5856,17 @@ ${heal.removed.join("\n")}`,
6094
5856
  `Installed bundle still fails its seal check after healing: ${healed.detail}`,
6095
5857
  LogFileType.UPDATE_SERVICE
6096
5858
  );
6097
- return installedBundleSealBlock(bundlePath, healed.detail, version2);
5859
+ return installedBundleSealBlock(bundlePath, healed.detail, version);
6098
5860
  }
6099
5861
  /** File names the updater's metadata knows this update by. */
6100
5862
  stagedArtifactCandidates(info) {
6101
5863
  const names = /* @__PURE__ */ new Set();
6102
- if (info?.path) names.add(path.basename(info.path));
5864
+ if (info?.path) names.add(path$1.basename(info.path));
6103
5865
  for (const file of info?.files ?? []) {
6104
- if (file.url) names.add(path.basename(decodeURIComponent(file.url)));
5866
+ if (file.url) names.add(path$1.basename(decodeURIComponent(file.url)));
6105
5867
  }
6106
5868
  if (this.downloadedArtifactPath) {
6107
- names.add(path.basename(this.downloadedArtifactPath));
5869
+ names.add(path$1.basename(this.downloadedArtifactPath));
6108
5870
  }
6109
5871
  return [...names];
6110
5872
  }
@@ -6253,7 +6015,7 @@ ${heal.removed.join("\n")}`,
6253
6015
  if (!bundlePath) return null;
6254
6016
  const plan = buildWatchdogPlan({
6255
6017
  appBundlePath: bundlePath,
6256
- executableName: path.basename(process.execPath),
6018
+ executableName: path$1.basename(process.execPath),
6257
6019
  // The app's own pid, captured here - before the quit - because the
6258
6020
  // watchdog cannot ask a name about its own ancestor (review R1).
6259
6021
  appPid: process.pid,
@@ -6916,12 +6678,12 @@ ${heal.removed.join("\n")}`,
6916
6678
  const { stdout } = await execAsync("pip show local-operator");
6917
6679
  const match = stdout.match(VERSION_LINE_REGEX);
6918
6680
  if (match) {
6919
- const version2 = match[1].trim();
6681
+ const version = match[1].trim();
6920
6682
  logger.info(
6921
- `Backend version from pip: ${version2}`,
6683
+ `Backend version from pip: ${version}`,
6922
6684
  LogFileType.UPDATE_SERVICE
6923
6685
  );
6924
- return version2;
6686
+ return version;
6925
6687
  }
6926
6688
  } catch (pipError) {
6927
6689
  logger.error(
@@ -7248,10 +7010,10 @@ ${heal.removed.join("\n")}`,
7248
7010
  const deadline = Date.now() + timeoutMs;
7249
7011
  let last = null;
7250
7012
  while (Date.now() < deadline) {
7251
- const version2 = await this.getInstalledBackendVersion();
7252
- if (version2 && version2 !== "Unknown") {
7253
- last = version2;
7254
- if (target2 == null || version2 === target2) return version2;
7013
+ const version = await this.getInstalledBackendVersion();
7014
+ if (version && version !== "Unknown") {
7015
+ last = version;
7016
+ if (target2 == null || version === target2) return version;
7255
7017
  }
7256
7018
  await new Promise((resolve) => setTimeout(resolve, intervalMs));
7257
7019
  }
@@ -7340,7 +7102,7 @@ ${heal.removed.join("\n")}`,
7340
7102
  if (venvPath && electron.app.isPackaged) {
7341
7103
  const venvBinDir = process.platform === "win32" ? "Scripts" : "bin";
7342
7104
  const pythonName = process.platform === "win32" ? "python.exe" : "python3";
7343
- pythonPath = path.join(venvPath, venvBinDir, pythonName);
7105
+ pythonPath = path$1.join(venvPath, venvBinDir, pythonName);
7344
7106
  }
7345
7107
  if (!pythonPath || !fs.existsSync(pythonPath)) {
7346
7108
  logger.error(
@@ -7739,6 +7501,9 @@ const posthogClient = new posthogNode.PostHog(backendConfig.VITE_PUBLIC_POSTHOG_
7739
7501
  host: backendConfig.VITE_PUBLIC_POSTHOG_HOST,
7740
7502
  enableExceptionAutocapture: true
7741
7503
  });
7504
+ function pickerFallbackDirectory() {
7505
+ return electron.app.getPath("home");
7506
+ }
7742
7507
  function createApplicationMenu() {
7743
7508
  const isDev = Boolean(process.env.ELECTRON_RENDERER_URL);
7744
7509
  const zoomInHandler = () => {
@@ -7892,7 +7657,7 @@ function createWindow() {
7892
7657
  title: "Local Operator",
7893
7658
  icon,
7894
7659
  webPreferences: {
7895
- preload: path.join(__dirname, "../preload/index.js"),
7660
+ preload: path$1.join(__dirname, "../preload/index.js"),
7896
7661
  sandbox: false,
7897
7662
  // Only enable devTools when running with 'pnpm dev'
7898
7663
  // Disable for 'pnpm start' and production builds
@@ -7963,7 +7728,7 @@ function createWindow() {
7963
7728
  if (isTrustedAuthDomain) {
7964
7729
  return {
7965
7730
  action: "allow",
7966
- features: {
7731
+ overrideBrowserWindowOptions: {
7967
7732
  width: 800,
7968
7733
  height: 700,
7969
7734
  // Increased height for better visibility
@@ -7994,7 +7759,7 @@ function createWindow() {
7994
7759
  if (utils.is.dev && process.env.ELECTRON_RENDERER_URL) {
7995
7760
  mainWindow2.loadURL(process.env.ELECTRON_RENDERER_URL);
7996
7761
  } else {
7997
- mainWindow2.loadFile(path.join(__dirname, "../renderer/index.html"));
7762
+ mainWindow2.loadFile(path$1.join(__dirname, "../renderer/index.html"));
7998
7763
  }
7999
7764
  return mainWindow2;
8000
7765
  }
@@ -8074,7 +7839,7 @@ electron.app.whenReady().then(async () => {
8074
7839
  });
8075
7840
  registerDesktopIPC(
8076
7841
  () => mainWindow,
8077
- process.env.ELECTRON_RENDERER_URL || node_url.pathToFileURL(path.join(__dirname, "../renderer/index.html")).href,
7842
+ process.env.ELECTRON_RENDERER_URL || node_url.pathToFileURL(path$1.join(__dirname, "../renderer/index.html")).href,
8078
7843
  sendDesktop,
8079
7844
  () => backendService.getStreamRelay(),
8080
7845
  (input, bytes) => backendService.requestDesktopMedia(input, bytes),
@@ -8091,7 +7856,7 @@ electron.app.whenReady().then(async () => {
8091
7856
  "read-file",
8092
7857
  async (_, filePath, encoding = "utf-8") => {
8093
7858
  try {
8094
- const normalizedPath = filePath.startsWith("~/") ? path.join(electron.app.getPath("home"), filePath.slice(2)) : filePath;
7859
+ const normalizedPath = filePath.startsWith("~/") ? path$1.join(electron.app.getPath("home"), filePath.slice(2)) : filePath;
8095
7860
  const data = fs.readFileSync(normalizedPath, encoding);
8096
7861
  return { success: true, data };
8097
7862
  } catch (error) {
@@ -8118,7 +7883,7 @@ electron.app.whenReady().then(async () => {
8118
7883
  "save-file",
8119
7884
  async (_, filePath, content, encoding = "utf-8") => {
8120
7885
  try {
8121
- const normalizedPath = filePath.startsWith("~/") ? path.join(electron.app.getPath("home"), filePath.slice(2)) : filePath;
7886
+ const normalizedPath = filePath.startsWith("~/") ? path$1.join(electron.app.getPath("home"), filePath.slice(2)) : filePath;
8122
7887
  fs.writeFileSync(normalizedPath, content, encoding);
8123
7888
  } catch (error) {
8124
7889
  logger.error("Error saving file:", LogFileType.BACKEND, error);
@@ -8127,12 +7892,12 @@ electron.app.whenReady().then(async () => {
8127
7892
  }
8128
7893
  );
8129
7894
  electron.ipcMain.handle("file-exists", async (_, filePath) => {
8130
- const normalizedPath = filePath.startsWith("~/") ? path.join(electron.app.getPath("home"), filePath.slice(2)) : filePath;
7895
+ const normalizedPath = filePath.startsWith("~/") ? path$1.join(electron.app.getPath("home"), filePath.slice(2)) : filePath;
8131
7896
  return fs.existsSync(normalizedPath);
8132
7897
  });
8133
7898
  electron.ipcMain.handle("directory-exists", async (_, dirPath) => {
8134
7899
  const home = electron.app.getPath("home");
8135
- const normalizedPath = dirPath === "~" ? home : dirPath.startsWith("~/") ? path.join(home, dirPath.slice(2)) : dirPath;
7900
+ const normalizedPath = dirPath === "~" ? home : dirPath.startsWith("~/") ? path$1.join(home, dirPath.slice(2)) : dirPath;
8136
7901
  try {
8137
7902
  return fs.statSync(normalizedPath, { throwIfNoEntry: false })?.isDirectory() ?? false;
8138
7903
  } catch {
@@ -8147,7 +7912,16 @@ electron.app.whenReady().then(async () => {
8147
7912
  );
8148
7913
  return { canceled: true, filePaths: [] };
8149
7914
  }
8150
- return electron.dialog.showOpenDialog(mainWindow, options);
7915
+ const result = await electron.dialog.showOpenDialog(
7916
+ mainWindow,
7917
+ withRememberedDirectory(
7918
+ "open-file",
7919
+ options,
7920
+ pickerFallbackDirectory()
7921
+ )
7922
+ );
7923
+ rememberPickedDirectory("open-file", result.filePaths);
7924
+ return result;
8151
7925
  });
8152
7926
  electron.ipcMain.handle("select-directory", async () => {
8153
7927
  if (!mainWindow) {
@@ -8157,13 +7931,22 @@ electron.app.whenReady().then(async () => {
8157
7931
  );
8158
7932
  return void 0;
8159
7933
  }
8160
- const result = await electron.dialog.showOpenDialog(mainWindow, {
7934
+ const directoryOptions = {
8161
7935
  properties: ["openDirectory"],
8162
7936
  title: "Select Working Directory",
8163
7937
  // More appropriate title
8164
7938
  buttonLabel: "Select Folder"
8165
7939
  // Correct button label
8166
- });
7940
+ };
7941
+ const result = await electron.dialog.showOpenDialog(
7942
+ mainWindow,
7943
+ withRememberedDirectory(
7944
+ "select-directory",
7945
+ directoryOptions,
7946
+ pickerFallbackDirectory()
7947
+ )
7948
+ );
7949
+ rememberPickedDirectory("select-directory", result.filePaths, true);
8167
7950
  if (!result.canceled && result.filePaths.length > 0) {
8168
7951
  return result.filePaths[0];
8169
7952
  }
@@ -8177,11 +7960,20 @@ electron.app.whenReady().then(async () => {
8177
7960
  );
8178
7961
  return void 0;
8179
7962
  }
8180
- const result = await electron.dialog.showOpenDialog(mainWindow, {
7963
+ const fileOptions = {
8181
7964
  properties: ["openFile"],
8182
7965
  title: "Select File",
8183
7966
  buttonLabel: "Open"
8184
- });
7967
+ };
7968
+ const result = await electron.dialog.showOpenDialog(
7969
+ mainWindow,
7970
+ withRememberedDirectory(
7971
+ "select-file",
7972
+ fileOptions,
7973
+ pickerFallbackDirectory()
7974
+ )
7975
+ );
7976
+ rememberPickedDirectory("select-file", result.filePaths);
8185
7977
  if (!result.canceled && result.filePaths.length > 0) {
8186
7978
  const filePath = result.filePaths[0];
8187
7979
  try {