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.
- package/bin/ensure-electron.js +47 -0
- package/bin/linux-sandbox.js +27 -18
- package/bin/postinstall.js +55 -33
- package/out/main/index.js +209 -417
- package/out/renderer/assets/{_basePickBy-Duzo68Xw.js → _basePickBy-FfClaKQg.js} +1 -1
- package/out/renderer/assets/{_baseUniq-BeJmcE9M.js → _baseUniq-C9SvGZui.js} +1 -1
- package/out/renderer/assets/{agent-details-page-B-rZ1RvZ.js → agent-details-page-AoSG_fVH.js} +1 -1
- package/out/renderer/assets/{agent-hub-page-CBL3Npvq.js → agent-hub-page-CaZjaTZe.js} +1 -1
- package/out/renderer/assets/{agents-page-7rG5Vl9M.js → agents-page-RS6PE_fF.js} +2 -2
- package/out/renderer/assets/{architectureDiagram-IEHRJDOE-BsT5wnLG.js → architectureDiagram-IEHRJDOE-Be7LQKHg.js} +1 -1
- package/out/renderer/assets/{blockDiagram-JOT3LUYC-JEwDyed4.js → blockDiagram-JOT3LUYC-iWnvArS2.js} +1 -1
- package/out/renderer/assets/{c4Diagram-VJAJSXHY-C4pGCoOs.js → c4Diagram-VJAJSXHY-BBuir5yQ.js} +1 -1
- package/out/renderer/assets/channel-D4JK8GjQ.js +1 -0
- package/out/renderer/assets/{chunk-4BMEZGHF-CNXrCcWD.js → chunk-4BMEZGHF-DzRvFZnz.js} +1 -1
- package/out/renderer/assets/{chunk-A2AXSNBT-Cs3JTrFa.js → chunk-A2AXSNBT-4uP9DbW7.js} +1 -1
- package/out/renderer/assets/{chunk-AEK57VVT-Cf3YXadW.js → chunk-AEK57VVT-BL3rbHq4.js} +1 -1
- package/out/renderer/assets/{chunk-D6G4REZN-Broh2kYr.js → chunk-D6G4REZN-D6wbdfUw.js} +1 -1
- package/out/renderer/assets/{chunk-RZ5BOZE2-CidGAd_y.js → chunk-RZ5BOZE2-D2Fl_NaB.js} +1 -1
- package/out/renderer/assets/{chunk-XZIHB7SX-BMBZY-Ob.js → chunk-XZIHB7SX-DN5jo0Xq.js} +1 -1
- package/out/renderer/assets/classDiagram-GIVACNV2-yxaMQW5a.js +1 -0
- package/out/renderer/assets/classDiagram-v2-COTLJTTW-yxaMQW5a.js +1 -0
- package/out/renderer/assets/clone-B7rlppnW.js +1 -0
- package/out/renderer/assets/{compact-pagination-n3Xl8pZ8.js → compact-pagination-20O8NjDK.js} +1 -1
- package/out/renderer/assets/{dagre-OKDRZEBW-Bz_ICygp.js → dagre-OKDRZEBW-BYIesx33.js} +1 -1
- package/out/renderer/assets/{diagram-SSKATNLV-BTVMb1kE.js → diagram-SSKATNLV-DP6lL-Te.js} +1 -1
- package/out/renderer/assets/{diagram-VNBRO52H-DfljiV4G.js → diagram-VNBRO52H-bmsCnWFr.js} +1 -1
- package/out/renderer/assets/{erDiagram-Q7BY3M3F-BRUMJB0F.js → erDiagram-Q7BY3M3F-EsgbzeoI.js} +1 -1
- package/out/renderer/assets/{flowDiagram-4HSFHLVR-BjcUuq_P.js → flowDiagram-4HSFHLVR-DOiNzXZN.js} +1 -1
- package/out/renderer/assets/{ganttDiagram-APWFNJXF-ovQikGsn.js → ganttDiagram-APWFNJXF-DJmMxmWH.js} +1 -1
- package/out/renderer/assets/{gitGraphDiagram-7IBYFJ6S-CrDG1pZY.js → gitGraphDiagram-7IBYFJ6S-CsW8qQBE.js} +1 -1
- package/out/renderer/assets/{graph-kwCSE5gm.js → graph-DPdUvm6W.js} +1 -1
- package/out/renderer/assets/{icon-DaedMBiD.css → icon-HSrrv8O-.css} +1 -1
- package/out/renderer/assets/{index-BbTvTNw0.js → index-BHWYYomf.js} +1 -1
- package/out/renderer/assets/{index-D3g23Ep3.js → index-C2JWjezT.js} +1 -1
- package/out/renderer/assets/{index-DOpsBDAL.js → index-DTxYU-h1.js} +310 -310
- package/out/renderer/assets/{infoDiagram-PH2N3AL5-CBAvcVVb.js → infoDiagram-PH2N3AL5-DlGp0OAs.js} +1 -1
- package/out/renderer/assets/{installer-poO56j69.js → installer-Ck14_4Oh.js} +1 -1
- package/out/renderer/assets/{journeyDiagram-U35MCT3I-kxtnE0E0.js → journeyDiagram-U35MCT3I-BMKeuZdQ.js} +1 -1
- package/out/renderer/assets/{kanban-definition-NDS4AKOZ-Cp_ZcAfm.js → kanban-definition-NDS4AKOZ-CBMkFWiV.js} +1 -1
- package/out/renderer/assets/{layout-DkMOECVe.js → layout-CQLCCDdm.js} +1 -1
- package/out/renderer/assets/{legacy-agents-page-Bm9y4VzQ.js → legacy-agents-page-DaL-s8eO.js} +1 -1
- package/out/renderer/assets/{mermaid.core-BdThqeRN.js → mermaid.core-zhMaqo9l.js} +5 -5
- package/out/renderer/assets/{mindmap-definition-ALO5MXBD-CmnY7qkU.js → mindmap-definition-ALO5MXBD-ChxcwGV6.js} +1 -1
- package/out/renderer/assets/{page-header-zecAylNs.js → page-header-D-uc8qqA.js} +1 -1
- package/out/renderer/assets/{parseISO-BBQqU7gh.js → parseISO-Bgv71POy.js} +1 -1
- package/out/renderer/assets/{pieDiagram-IB7DONF6-CT6aweg_.js → pieDiagram-IB7DONF6-BMEW9BJi.js} +1 -1
- package/out/renderer/assets/{quadrantDiagram-7GDLP6J5-B9mprDDC.js → quadrantDiagram-7GDLP6J5-D-ErPCKs.js} +1 -1
- package/out/renderer/assets/{radar-MK3ICKWK-BbnAUJmd.js → radar-MK3ICKWK-2tp4r77h.js} +1 -1
- package/out/renderer/assets/{radient-auth-buttons-DQwcB7Kb.js → radient-auth-buttons-klNSjDud.js} +1 -1
- package/out/renderer/assets/{requirementDiagram-KVF5MWMF-vDOfXFEQ.js → requirementDiagram-KVF5MWMF-nNjxV4M0.js} +1 -1
- package/out/renderer/assets/{sankeyDiagram-QLVOVGJD-B4f16uUk.js → sankeyDiagram-QLVOVGJD-HK65A8n7.js} +1 -1
- package/out/renderer/assets/{schedules-page-B8xcfay1.js → schedules-page-CLrcFhCL.js} +1 -1
- package/out/renderer/assets/{sequenceDiagram-X6HHIX6F-B99VW_Zk.js → sequenceDiagram-X6HHIX6F-D3VDaA9I.js} +1 -1
- package/out/renderer/assets/{settings-page-DCLwiyj6.js → settings-page-CKVWBbsu.js} +1 -1
- package/out/renderer/assets/{square-pen-CdJTC74b.js → square-pen-CQEKS3JT.js} +1 -1
- package/out/renderer/assets/{stateDiagram-DGXRK772-DrhFdhdz.js → stateDiagram-DGXRK772-BJMfya--.js} +1 -1
- package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-CmCw0Yzl.js +1 -0
- package/out/renderer/assets/{timeline-definition-BDJGKUSR-D_VVC3lo.js → timeline-definition-BDJGKUSR-wvXoFLOl.js} +1 -1
- package/out/renderer/assets/{use-agent-like-mutation-C8Hn5OU7.js → use-agent-like-mutation-DAmS19om.js} +1 -1
- package/out/renderer/assets/{xychartDiagram-VJFVF3MP-CHmZVi_C.js → xychartDiagram-VJFVF3MP-DnyQ060j.js} +1 -1
- package/out/renderer/index.html +3 -3
- package/out/renderer/installer.html +3 -3
- package/package.json +69 -58
- package/out/renderer/assets/channel-C4lq_kmR.js +0 -1
- package/out/renderer/assets/classDiagram-GIVACNV2-BpO5Iy7a.js +0 -1
- package/out/renderer/assets/classDiagram-v2-COTLJTTW-BpO5Iy7a.js +0 -1
- package/out/renderer/assets/clone-CuQYVeZK.js +0 -1
- package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-uaCZR48L.js +0 -1
- /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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
4076
|
+
setNotificationContract(version) {
|
|
4330
4077
|
this.contractGeneration++;
|
|
4331
|
-
this.applyNotificationContract(
|
|
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(
|
|
4341
|
-
this.notificationContract = typeof
|
|
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,
|
|
4399
|
+
function installedBundleSealBlock(appBundlePath, detail, version) {
|
|
4638
4400
|
return {
|
|
4639
4401
|
code: "installed-bundle-not-sealed",
|
|
4640
|
-
message:
|
|
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(
|
|
4428
|
+
function canonicalPath(path2) {
|
|
4667
4429
|
try {
|
|
4668
|
-
return fs.realpathSync(
|
|
4430
|
+
return fs.realpathSync(path2);
|
|
4669
4431
|
} catch {
|
|
4670
4432
|
try {
|
|
4671
|
-
return path.join(fs.realpathSync(path.dirname(
|
|
4433
|
+
return path$1.join(fs.realpathSync(path$1.dirname(path2)), path$1.basename(path2));
|
|
4672
4434
|
} catch {
|
|
4673
|
-
return
|
|
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
|
|
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 (!
|
|
4686
|
-
const segments =
|
|
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) =>
|
|
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(
|
|
4804
|
-
return
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
5575
|
-
return
|
|
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(
|
|
5592
|
-
return
|
|
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,
|
|
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:
|
|
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(
|
|
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,
|
|
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,
|
|
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
|
|
6681
|
+
const version = match[1].trim();
|
|
6920
6682
|
logger.info(
|
|
6921
|
-
`Backend version from pip: ${
|
|
6683
|
+
`Backend version from pip: ${version}`,
|
|
6922
6684
|
LogFileType.UPDATE_SERVICE
|
|
6923
6685
|
);
|
|
6924
|
-
return
|
|
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
|
|
7252
|
-
if (
|
|
7253
|
-
last =
|
|
7254
|
-
if (target2 == null ||
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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 {
|