@linzumi/cli 0.0.44-beta → 0.0.46-beta
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/README.md +1 -1
- package/dist/index.js +402 -125
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
3
|
-
import { existsSync as existsSync11, readFileSync as
|
|
3
|
+
import { existsSync as existsSync11, readFileSync as readFileSync11, realpathSync as realpathSync6 } from "node:fs";
|
|
4
4
|
import { homedir as homedir9 } from "node:os";
|
|
5
5
|
import { resolve as resolve9 } from "node:path";
|
|
6
6
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
@@ -1488,7 +1488,6 @@ var defaultIntervalMs = 2000;
|
|
|
1488
1488
|
var defaultDebounceMs = 750;
|
|
1489
1489
|
function startPortForwardWatcher(options) {
|
|
1490
1490
|
const rootPid = options.rootPid ?? process.pid;
|
|
1491
|
-
const rootCwd = normalizeCwd(options.rootCwd);
|
|
1492
1491
|
const intervalMs = options.intervalMs ?? defaultIntervalMs;
|
|
1493
1492
|
const debounceMs = options.debounceMs ?? defaultDebounceMs;
|
|
1494
1493
|
const lostDebounceMs = options.lostDebounceMs ?? intervalMs * 2 + debounceMs;
|
|
@@ -1508,8 +1507,8 @@ function startPortForwardWatcher(options) {
|
|
|
1508
1507
|
Promise.resolve().then(async () => {
|
|
1509
1508
|
const descendants = descendantPidSet(scanProcesses(), rootPid);
|
|
1510
1509
|
const sockets = scanListenSockets();
|
|
1511
|
-
const candidatePids =
|
|
1512
|
-
const candidates = detectedForwardCandidates(sockets, descendants, scanProcessCwds(candidatePids)
|
|
1510
|
+
const candidatePids = sockets.filter((socket) => descendants.has(socket.pid)).map((socket) => socket.pid);
|
|
1511
|
+
const candidates = detectedForwardCandidates(sockets, descendants, scanProcessCwds(candidatePids));
|
|
1513
1512
|
const scanTimeMs = nowMs();
|
|
1514
1513
|
const stable = stableForwardCandidates(candidateStabilityByPort, candidates, scanTimeMs, debounceMs);
|
|
1515
1514
|
const changes = debouncedForwardCandidateChanges(emittedByPort, missingByPort, stable.stableCandidates, scanTimeMs, lostDebounceMs);
|
|
@@ -1613,17 +1612,8 @@ function descendantPidSet(rows, rootPid) {
|
|
|
1613
1612
|
}
|
|
1614
1613
|
return descendants;
|
|
1615
1614
|
}
|
|
1616
|
-
function detectedForwardCandidates(sockets, descendantPids, processCwds = new Map
|
|
1617
|
-
|
|
1618
|
-
return sockets.filter((socket) => {
|
|
1619
|
-
if (descendantPids.has(socket.pid)) {
|
|
1620
|
-
return true;
|
|
1621
|
-
}
|
|
1622
|
-
if (rootCwd === undefined) {
|
|
1623
|
-
return false;
|
|
1624
|
-
}
|
|
1625
|
-
return cwdMatchesRoot(processCwds.get(socket.pid), rootCwd);
|
|
1626
|
-
}).filter((socket) => socket.port > 0 && socket.port < 65536).sort((left, right) => left.port - right.port).map((socket) => {
|
|
1615
|
+
function detectedForwardCandidates(sockets, descendantPids, processCwds = new Map) {
|
|
1616
|
+
return sockets.filter((socket) => descendantPids.has(socket.pid)).filter((socket) => socket.port > 0 && socket.port < 65536).sort((left, right) => left.port - right.port).map((socket) => {
|
|
1627
1617
|
const cwd = processCwds.get(socket.pid);
|
|
1628
1618
|
return {
|
|
1629
1619
|
port: socket.port,
|
|
@@ -1633,20 +1623,6 @@ function detectedForwardCandidates(sockets, descendantPids, processCwds = new Ma
|
|
|
1633
1623
|
};
|
|
1634
1624
|
});
|
|
1635
1625
|
}
|
|
1636
|
-
function normalizeCwd(cwd) {
|
|
1637
|
-
if (cwd === undefined) {
|
|
1638
|
-
return;
|
|
1639
|
-
}
|
|
1640
|
-
const normalized = cwd.trim().replace(/\/+$/, "");
|
|
1641
|
-
return normalized === "" ? undefined : normalized;
|
|
1642
|
-
}
|
|
1643
|
-
function cwdMatchesRoot(candidateCwd, rootCwd) {
|
|
1644
|
-
const normalizedCandidate = normalizeCwd(candidateCwd);
|
|
1645
|
-
if (normalizedCandidate === undefined) {
|
|
1646
|
-
return false;
|
|
1647
|
-
}
|
|
1648
|
-
return normalizedCandidate === rootCwd || normalizedCandidate.startsWith(`${rootCwd}/`);
|
|
1649
|
-
}
|
|
1650
1626
|
function parseProcessRows(output) {
|
|
1651
1627
|
return output.split(`
|
|
1652
1628
|
`).map((line) => line.trim()).filter((line) => line !== "").map((line) => {
|
|
@@ -2716,7 +2692,6 @@ function startPortForwardWatchIfEnabled(args, state, payloadContext) {
|
|
|
2716
2692
|
state.approvedForwardPorts.add(port);
|
|
2717
2693
|
}
|
|
2718
2694
|
state.portForwardWatcher = start({
|
|
2719
|
-
rootCwd: watchOptions.rootCwd ?? args.options.cwd,
|
|
2720
2695
|
...watchOptions,
|
|
2721
2696
|
onCandidate: (candidate) => publishPortForwardPrompt(args, state, payloadContext, candidate),
|
|
2722
2697
|
onCandidateLost: (candidate) => handleLostPortForwardCandidate(args, state, payloadContext, candidate),
|
|
@@ -6016,6 +5991,7 @@ function pathLooksAbsolute(pathValue) {
|
|
|
6016
5991
|
|
|
6017
5992
|
// src/localForwarding.ts
|
|
6018
5993
|
import { gzipSync } from "node:zlib";
|
|
5994
|
+
import NodeWebSocket from "ws";
|
|
6019
5995
|
var maxForwardBodyBytes = 64 * 1024 * 1024;
|
|
6020
5996
|
var gzipForwardThresholdBytes = 32 * 1024;
|
|
6021
5997
|
async function handleForwardHttpRequest(control, allowedPorts) {
|
|
@@ -6059,15 +6035,15 @@ function isForwardHttpRequestControl(control) {
|
|
|
6059
6035
|
function isForwardWebSocketControl(control) {
|
|
6060
6036
|
return control.type === "forward_websocket_open" || control.type === "forward_websocket_send" || control.type === "forward_websocket_close";
|
|
6061
6037
|
}
|
|
6062
|
-
function createForwardWebSocketManager(kandan, topic, allowedPorts) {
|
|
6038
|
+
function createForwardWebSocketManager(kandan, topic, allowedPorts, socketFactory = defaultForwardWebSocketFactory) {
|
|
6063
6039
|
const sockets = new Map;
|
|
6064
6040
|
const pushEvent = (payload) => kandan.push(topic, "forward:websocket_event", payload).catch(() => {
|
|
6065
6041
|
return;
|
|
6066
6042
|
});
|
|
6067
6043
|
const closeSocket = (socketId) => {
|
|
6068
|
-
const
|
|
6044
|
+
const stream = sockets.get(socketId);
|
|
6069
6045
|
sockets.delete(socketId);
|
|
6070
|
-
socket
|
|
6046
|
+
stream?.socket.close();
|
|
6071
6047
|
};
|
|
6072
6048
|
return {
|
|
6073
6049
|
handle: (control) => {
|
|
@@ -6081,12 +6057,12 @@ function createForwardWebSocketManager(kandan, topic, allowedPorts) {
|
|
|
6081
6057
|
});
|
|
6082
6058
|
return;
|
|
6083
6059
|
}
|
|
6084
|
-
openLocalWebSocket(control, sockets, pushEvent, "ws");
|
|
6060
|
+
openLocalWebSocket(control, sockets, pushEvent, socketFactory, "ws");
|
|
6085
6061
|
return;
|
|
6086
6062
|
}
|
|
6087
6063
|
case "forward_websocket_send": {
|
|
6088
|
-
const
|
|
6089
|
-
if (
|
|
6064
|
+
const stream = sockets.get(control.socketId);
|
|
6065
|
+
if (stream === undefined || stream.socket.readyState !== WebSocket.OPEN) {
|
|
6090
6066
|
pushEvent({
|
|
6091
6067
|
socketId: control.socketId,
|
|
6092
6068
|
type: "error",
|
|
@@ -6097,12 +6073,12 @@ function createForwardWebSocketManager(kandan, topic, allowedPorts) {
|
|
|
6097
6073
|
const body = Buffer.from(control.bodyBase64, "base64");
|
|
6098
6074
|
switch (control.opcode) {
|
|
6099
6075
|
case "text":
|
|
6100
|
-
socket.send(body.toString());
|
|
6076
|
+
stream.socket.send(body.toString());
|
|
6101
6077
|
return;
|
|
6102
6078
|
case "binary":
|
|
6103
6079
|
case "ping":
|
|
6104
6080
|
case "pong":
|
|
6105
|
-
socket.send(body);
|
|
6081
|
+
stream.socket.send(body);
|
|
6106
6082
|
return;
|
|
6107
6083
|
}
|
|
6108
6084
|
}
|
|
@@ -6118,18 +6094,27 @@ function createForwardWebSocketManager(kandan, topic, allowedPorts) {
|
|
|
6118
6094
|
}
|
|
6119
6095
|
};
|
|
6120
6096
|
}
|
|
6121
|
-
function openLocalWebSocket(control, sockets, pushEvent, scheme) {
|
|
6097
|
+
function openLocalWebSocket(control, sockets, pushEvent, socketFactory, scheme) {
|
|
6122
6098
|
let opened = false;
|
|
6123
|
-
const url =
|
|
6099
|
+
const url = localForwardWebSocketUrl(scheme, control.port, control.path, control.queryString);
|
|
6124
6100
|
const protocols = webSocketProtocols(control.headers);
|
|
6125
|
-
const
|
|
6101
|
+
const headers = webSocketHeaders(control.headers);
|
|
6102
|
+
const websocket = socketFactory(url, protocols, headers);
|
|
6126
6103
|
websocket.binaryType = "arraybuffer";
|
|
6127
|
-
sockets.
|
|
6104
|
+
const previousStream = sockets.get(control.socketId);
|
|
6105
|
+
previousStream?.socket.close();
|
|
6106
|
+
sockets.set(control.socketId, { socket: websocket });
|
|
6128
6107
|
websocket.addEventListener("open", () => {
|
|
6108
|
+
if (!currentWebSocket(sockets, control.socketId, websocket)) {
|
|
6109
|
+
return;
|
|
6110
|
+
}
|
|
6129
6111
|
opened = true;
|
|
6130
6112
|
pushEvent({ socketId: control.socketId, type: "open" });
|
|
6131
6113
|
});
|
|
6132
6114
|
websocket.addEventListener("message", (event) => {
|
|
6115
|
+
if (!currentWebSocket(sockets, control.socketId, websocket)) {
|
|
6116
|
+
return;
|
|
6117
|
+
}
|
|
6133
6118
|
const body = typeof event.data === "string" ? Buffer.from(event.data) : Buffer.from(event.data);
|
|
6134
6119
|
pushEvent({
|
|
6135
6120
|
socketId: control.socketId,
|
|
@@ -6139,6 +6124,9 @@ function openLocalWebSocket(control, sockets, pushEvent, scheme) {
|
|
|
6139
6124
|
});
|
|
6140
6125
|
});
|
|
6141
6126
|
websocket.addEventListener("close", (event) => {
|
|
6127
|
+
if (!currentWebSocket(sockets, control.socketId, websocket)) {
|
|
6128
|
+
return;
|
|
6129
|
+
}
|
|
6142
6130
|
sockets.delete(control.socketId);
|
|
6143
6131
|
pushEvent({
|
|
6144
6132
|
socketId: control.socketId,
|
|
@@ -6148,18 +6136,32 @@ function openLocalWebSocket(control, sockets, pushEvent, scheme) {
|
|
|
6148
6136
|
});
|
|
6149
6137
|
});
|
|
6150
6138
|
websocket.addEventListener("error", () => {
|
|
6139
|
+
if (!currentWebSocket(sockets, control.socketId, websocket)) {
|
|
6140
|
+
return;
|
|
6141
|
+
}
|
|
6151
6142
|
sockets.delete(control.socketId);
|
|
6152
6143
|
if (!opened && scheme === "ws") {
|
|
6153
|
-
openLocalWebSocket(control, sockets, pushEvent, "wss");
|
|
6144
|
+
openLocalWebSocket(control, sockets, pushEvent, socketFactory, "wss");
|
|
6154
6145
|
return;
|
|
6155
6146
|
}
|
|
6156
6147
|
pushEvent({
|
|
6157
6148
|
socketId: control.socketId,
|
|
6158
6149
|
type: "error",
|
|
6159
|
-
error: "websocket_error"
|
|
6150
|
+
error: "websocket_error",
|
|
6151
|
+
attemptedScheme: scheme
|
|
6160
6152
|
});
|
|
6161
6153
|
});
|
|
6162
6154
|
}
|
|
6155
|
+
function defaultForwardWebSocketFactory(url, protocols, headers) {
|
|
6156
|
+
if (headers === undefined) {
|
|
6157
|
+
return protocols === undefined ? new WebSocket(url) : new WebSocket(url, protocols);
|
|
6158
|
+
}
|
|
6159
|
+
const options = { headers };
|
|
6160
|
+
return protocols === undefined ? new NodeWebSocket(url, options) : new NodeWebSocket(url, protocols, options);
|
|
6161
|
+
}
|
|
6162
|
+
function currentWebSocket(sockets, socketId, socket) {
|
|
6163
|
+
return sockets.get(socketId)?.socket === socket;
|
|
6164
|
+
}
|
|
6163
6165
|
function webSocketProtocols(headers) {
|
|
6164
6166
|
if (!Array.isArray(headers)) {
|
|
6165
6167
|
return;
|
|
@@ -6172,6 +6174,21 @@ function webSocketProtocols(headers) {
|
|
|
6172
6174
|
});
|
|
6173
6175
|
return protocols.length === 0 ? undefined : protocols;
|
|
6174
6176
|
}
|
|
6177
|
+
function webSocketHeaders(headers) {
|
|
6178
|
+
if (!Array.isArray(headers)) {
|
|
6179
|
+
return;
|
|
6180
|
+
}
|
|
6181
|
+
const forwarded = headers.reduce((acc, header) => {
|
|
6182
|
+
if (isOctWebSocketHeader(header)) {
|
|
6183
|
+
acc[header.name] = header.value;
|
|
6184
|
+
}
|
|
6185
|
+
return acc;
|
|
6186
|
+
}, {});
|
|
6187
|
+
return Object.keys(forwarded).length === 0 ? undefined : forwarded;
|
|
6188
|
+
}
|
|
6189
|
+
function isOctWebSocketHeader(value) {
|
|
6190
|
+
return isHeader(value) && value.name.toLowerCase().startsWith("x-oct-");
|
|
6191
|
+
}
|
|
6175
6192
|
function localForwardUrl(scheme, port, path, queryString) {
|
|
6176
6193
|
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
6177
6194
|
const url = new URL(`${scheme}://127.0.0.1:${port}${normalizedPath}`);
|
|
@@ -6180,6 +6197,12 @@ function localForwardUrl(scheme, port, path, queryString) {
|
|
|
6180
6197
|
}
|
|
6181
6198
|
return url.toString();
|
|
6182
6199
|
}
|
|
6200
|
+
function localForwardWebSocketUrl(scheme, port, path, queryString) {
|
|
6201
|
+
const httpScheme = scheme === "ws" ? "http" : "https";
|
|
6202
|
+
const url = new URL(localForwardUrl(httpScheme, port, path, queryString));
|
|
6203
|
+
url.protocol = `${scheme}:`;
|
|
6204
|
+
return url.toString();
|
|
6205
|
+
}
|
|
6183
6206
|
async function fetchWithHttpsFallback(port, path, queryString, request) {
|
|
6184
6207
|
try {
|
|
6185
6208
|
return await fetch(localForwardUrl("http", port, path, queryString), request);
|
|
@@ -6292,8 +6315,10 @@ var blockedForwardHeaderNames = new Set([
|
|
|
6292
6315
|
"connection",
|
|
6293
6316
|
"content-encoding",
|
|
6294
6317
|
"content-length",
|
|
6318
|
+
"cookie",
|
|
6295
6319
|
"host",
|
|
6296
6320
|
"keep-alive",
|
|
6321
|
+
"authorization",
|
|
6297
6322
|
"proxy-authenticate",
|
|
6298
6323
|
"proxy-authorization",
|
|
6299
6324
|
"te",
|
|
@@ -6305,10 +6330,12 @@ var blockedForwardHeaderNames = new Set([
|
|
|
6305
6330
|
// src/localEditor.ts
|
|
6306
6331
|
import { spawn as spawn2 } from "node:child_process";
|
|
6307
6332
|
import {
|
|
6333
|
+
copyFileSync,
|
|
6308
6334
|
cpSync,
|
|
6309
6335
|
existsSync as existsSync2,
|
|
6310
6336
|
mkdirSync as mkdirSync3,
|
|
6311
6337
|
mkdtempSync,
|
|
6338
|
+
readFileSync as readFileSync2,
|
|
6312
6339
|
realpathSync as realpathSync3,
|
|
6313
6340
|
writeFileSync as writeFileSync2
|
|
6314
6341
|
} from "node:fs";
|
|
@@ -6510,6 +6537,7 @@ function prepareCodeServerProfile(collaboration, editorRuntime) {
|
|
|
6510
6537
|
mkdirSync3(collaborationServerDir, { recursive: true });
|
|
6511
6538
|
mkdirSync3(tempDir, { recursive: true });
|
|
6512
6539
|
if (editorRuntime !== undefined) {
|
|
6540
|
+
ensureCodeServerBrowserExtensionAssets(editorRuntime);
|
|
6513
6541
|
installDirectory(editorRuntime.assets.documentStateExtensionDir, join4(extensionsDir, "kandan.document-state-telemetry"));
|
|
6514
6542
|
}
|
|
6515
6543
|
writeFileSync2(join4(userSettingsDir, "settings.json"), JSON.stringify(codeServerSettings(collaboration), null, 2));
|
|
@@ -6518,6 +6546,68 @@ function prepareCodeServerProfile(collaboration, editorRuntime) {
|
|
|
6518
6546
|
return { ok: false, reason: "code_server_spawn_failed" };
|
|
6519
6547
|
}
|
|
6520
6548
|
}
|
|
6549
|
+
function ensureCodeServerBrowserExtensionAssets(runtime) {
|
|
6550
|
+
const vscodeRoot = codeServerVscodeRoot(runtime);
|
|
6551
|
+
const repairs = [
|
|
6552
|
+
{
|
|
6553
|
+
source: join4(vscodeRoot, "extensions", "git-base", "dist", "extension.js"),
|
|
6554
|
+
target: join4(vscodeRoot, "extensions", "git-base", "dist", "browser", "extension.js"),
|
|
6555
|
+
required: true
|
|
6556
|
+
},
|
|
6557
|
+
{
|
|
6558
|
+
source: join4(vscodeRoot, "extensions", "git-base", "dist", "extension.js.map"),
|
|
6559
|
+
target: join4(vscodeRoot, "extensions", "git-base", "dist", "browser", "extension.js.map"),
|
|
6560
|
+
required: false
|
|
6561
|
+
},
|
|
6562
|
+
{
|
|
6563
|
+
source: join4(vscodeRoot, "extensions", "merge-conflict", "dist", "mergeConflictMain.js"),
|
|
6564
|
+
target: join4(vscodeRoot, "extensions", "merge-conflict", "dist", "browser", "mergeConflictMain.js"),
|
|
6565
|
+
required: true
|
|
6566
|
+
},
|
|
6567
|
+
{
|
|
6568
|
+
source: join4(vscodeRoot, "extensions", "merge-conflict", "dist", "mergeConflictMain.js.map"),
|
|
6569
|
+
target: join4(vscodeRoot, "extensions", "merge-conflict", "dist", "browser", "mergeConflictMain.js.map"),
|
|
6570
|
+
required: false
|
|
6571
|
+
}
|
|
6572
|
+
];
|
|
6573
|
+
repairs.forEach(({ source, target, required }) => {
|
|
6574
|
+
switch (true) {
|
|
6575
|
+
case existsSync2(target):
|
|
6576
|
+
return;
|
|
6577
|
+
case (!required && !existsSync2(source)):
|
|
6578
|
+
return;
|
|
6579
|
+
default:
|
|
6580
|
+
mkdirSync3(dirname2(target), { recursive: true });
|
|
6581
|
+
copyFileSync(source, target);
|
|
6582
|
+
return;
|
|
6583
|
+
}
|
|
6584
|
+
});
|
|
6585
|
+
}
|
|
6586
|
+
function codeServerVscodeRoot(runtime) {
|
|
6587
|
+
const roots = uniquePaths([
|
|
6588
|
+
join4(runtime.root, "lib", "vscode"),
|
|
6589
|
+
join4(dirname2(dirname2(runtime.codeServerBin)), "lib", "vscode"),
|
|
6590
|
+
...wrappedCodeServerBin(runtime.codeServerBin).map((codeServerBin) => join4(dirname2(dirname2(codeServerBin)), "lib", "vscode"))
|
|
6591
|
+
]);
|
|
6592
|
+
const rootWithRequiredAssets = roots.find((root) => codeServerBrowserAssetSources(root).every((source) => existsSync2(source)));
|
|
6593
|
+
return rootWithRequiredAssets ?? roots[0];
|
|
6594
|
+
}
|
|
6595
|
+
function wrappedCodeServerBin(codeServerBin) {
|
|
6596
|
+
try {
|
|
6597
|
+
const script = readFileSync2(codeServerBin, "utf8");
|
|
6598
|
+
const match = script.match(/exec\s+(?:"([^"]+)"|'([^']+)'|([^\s]+))\s+"\$@"/u);
|
|
6599
|
+
const target = match?.[1] ?? match?.[2] ?? match?.[3];
|
|
6600
|
+
return target === undefined || target.trim() === "" ? [] : [target];
|
|
6601
|
+
} catch (_error) {
|
|
6602
|
+
return [];
|
|
6603
|
+
}
|
|
6604
|
+
}
|
|
6605
|
+
function codeServerBrowserAssetSources(vscodeRoot) {
|
|
6606
|
+
return [
|
|
6607
|
+
join4(vscodeRoot, "extensions", "git-base", "dist", "extension.js"),
|
|
6608
|
+
join4(vscodeRoot, "extensions", "merge-conflict", "dist", "mergeConflictMain.js")
|
|
6609
|
+
];
|
|
6610
|
+
}
|
|
6521
6611
|
function prepareCodeServerLaunch(options) {
|
|
6522
6612
|
const platform = options.platform ?? process.platform;
|
|
6523
6613
|
if (platform === "linux") {
|
|
@@ -6650,12 +6740,16 @@ function prepareLocalEditorCollaboration(collaboration, runnerId, serverPort, br
|
|
|
6650
6740
|
}
|
|
6651
6741
|
const targetPath = `/local-codex-runners/${encodeURIComponent(runnerId)}/forwards/${serverPort}/preview-target`;
|
|
6652
6742
|
const serverUrl = new URL(targetPath, `${browserBaseUrl}/`).toString();
|
|
6653
|
-
const
|
|
6743
|
+
const collaborationStatePath = `/api/v2/editor/sessions/${collaboration.editorSessionId}/collaboration-state`;
|
|
6744
|
+
const collaborationBootstrapPath = collaboration.bootstrapToken === undefined || collaboration.bootstrapToken === "" ? undefined : `${targetPath}/_kandan-collaboration/${encodeURIComponent(collaboration.bootstrapToken)}`;
|
|
6745
|
+
const collaborationStateUrl = collaborationBootstrapPath === undefined ? collaborationStatePath : `${collaborationBootstrapPath}${collaborationStatePath}`;
|
|
6746
|
+
const bootstrapServerUrl = collaborationBootstrapPath === undefined ? serverUrl : new URL(collaborationBootstrapPath, `${browserBaseUrl}/`).toString();
|
|
6654
6747
|
return {
|
|
6655
6748
|
...collaboration,
|
|
6656
6749
|
serverPort,
|
|
6657
6750
|
serverUrl,
|
|
6658
|
-
bootstrapServerUrl
|
|
6751
|
+
bootstrapServerUrl,
|
|
6752
|
+
collaborationStateUrl
|
|
6659
6753
|
};
|
|
6660
6754
|
}
|
|
6661
6755
|
function codeServerSettings(collaboration) {
|
|
@@ -6668,6 +6762,7 @@ function codeServerSettings(collaboration) {
|
|
|
6668
6762
|
"oct.joinAcceptMode": "auto",
|
|
6669
6763
|
...collaboration === undefined ? {} : {
|
|
6670
6764
|
"oct.kandanEditorSessionId": collaboration.editorSessionId,
|
|
6765
|
+
"oct.kandanCollaborationStateUrl": collaboration.collaborationStateUrl,
|
|
6671
6766
|
"oct.serverUrl": collaboration.bootstrapServerUrl
|
|
6672
6767
|
},
|
|
6673
6768
|
"security.workspace.trust.enabled": false,
|
|
@@ -6746,6 +6841,7 @@ async function startCollaborationSidecar(collaboration, profile, editorRuntime,
|
|
|
6746
6841
|
serverPort: collaboration.serverPort,
|
|
6747
6842
|
serverUrl: collaboration.serverUrl,
|
|
6748
6843
|
bootstrapServerUrl: collaboration.bootstrapServerUrl,
|
|
6844
|
+
collaborationStateUrl: collaboration.collaborationStateUrl,
|
|
6749
6845
|
process: child,
|
|
6750
6846
|
exited
|
|
6751
6847
|
}
|
|
@@ -6769,7 +6865,7 @@ function installDirectory(sourceDir, destinationDir) {
|
|
|
6769
6865
|
mkdirSync3(dirname2(destinationDir), { recursive: true });
|
|
6770
6866
|
cpSync(sourceDir, destinationDir, { recursive: true });
|
|
6771
6867
|
}
|
|
6772
|
-
function codeServerEnv(env, cwd,
|
|
6868
|
+
function codeServerEnv(env, cwd, userDataDir, collaboration) {
|
|
6773
6869
|
const { PORT: _port, ...hostEnv } = env;
|
|
6774
6870
|
const base = {
|
|
6775
6871
|
...hostEnv,
|
|
@@ -6783,7 +6879,8 @@ function codeServerEnv(env, cwd, _userDataDir, collaboration) {
|
|
|
6783
6879
|
KANDAN_EDITOR_COLLABORATION_DEPLOYMENT_SHAPE: "local_runner_sidecar",
|
|
6784
6880
|
KANDAN_EDITOR_COLLABORATION_ENTRY_MODE: "kandan_auto_host_or_join",
|
|
6785
6881
|
KANDAN_EDITOR_COLLABORATION_ROOM_ID: collaboration.roomId,
|
|
6786
|
-
KANDAN_EDITOR_COLLABORATION_SERVER_URL: collaboration.bootstrapServerUrl
|
|
6882
|
+
KANDAN_EDITOR_COLLABORATION_SERVER_URL: collaboration.bootstrapServerUrl,
|
|
6883
|
+
KANDAN_EDITOR_COLLABORATION_AUTO_HOST_CLAIM_PATH: join4(userDataDir, "kandan-oct-auto-host.lock")
|
|
6787
6884
|
};
|
|
6788
6885
|
}
|
|
6789
6886
|
function collaborationEvent(collaboration) {
|
|
@@ -6986,7 +7083,7 @@ import {
|
|
|
6986
7083
|
existsSync as existsSync3,
|
|
6987
7084
|
mkdirSync as mkdirSync4,
|
|
6988
7085
|
mkdtempSync as mkdtempSync2,
|
|
6989
|
-
readFileSync as
|
|
7086
|
+
readFileSync as readFileSync3,
|
|
6990
7087
|
renameSync,
|
|
6991
7088
|
rmSync,
|
|
6992
7089
|
writeFileSync as writeFileSync3
|
|
@@ -7474,7 +7571,7 @@ function installedRuntime(cacheRoot, manifest) {
|
|
|
7474
7571
|
return { ok: false };
|
|
7475
7572
|
}
|
|
7476
7573
|
try {
|
|
7477
|
-
const installed = JSON.parse(
|
|
7574
|
+
const installed = JSON.parse(readFileSync3(manifestPath, "utf8"));
|
|
7478
7575
|
if (isJsonObject(installed) && installed.version === manifest.version && installed.platform === manifest.platform && (installed.archiveSha256 === undefined || installed.archiveSha256 === manifest.archiveSha256)) {
|
|
7479
7576
|
return {
|
|
7480
7577
|
ok: true,
|
|
@@ -7705,7 +7802,7 @@ function manifestAssetChecksums(assets) {
|
|
|
7705
7802
|
return checksums;
|
|
7706
7803
|
}
|
|
7707
7804
|
function fileSha256Sync(path) {
|
|
7708
|
-
return createHash2("sha256").update(
|
|
7805
|
+
return createHash2("sha256").update(readFileSync3(path)).digest("hex");
|
|
7709
7806
|
}
|
|
7710
7807
|
function defaultEditorRuntimeCacheRoot() {
|
|
7711
7808
|
return join5(homedir4(), ".linzumi", "editor-runtimes");
|
|
@@ -7884,6 +7981,7 @@ function firstNonBlank(...values) {
|
|
|
7884
7981
|
}
|
|
7885
7982
|
|
|
7886
7983
|
// src/phoenix.ts
|
|
7984
|
+
var defaultPushTimeoutMs = 30000;
|
|
7887
7985
|
function phoenixWebsocketUrl(baseUrl, token) {
|
|
7888
7986
|
const parsed = new URL(baseUrl);
|
|
7889
7987
|
switch (parsed.protocol) {
|
|
@@ -7899,7 +7997,7 @@ function phoenixWebsocketUrl(baseUrl, token) {
|
|
|
7899
7997
|
parsed.searchParams.set("vsn", "2.0.0");
|
|
7900
7998
|
return parsed.toString();
|
|
7901
7999
|
}
|
|
7902
|
-
async function connectPhoenixClient(baseUrl, token, socketFactory = (url) => new WebSocket(url)) {
|
|
8000
|
+
async function connectPhoenixClient(baseUrl, token, socketFactory = (url) => new WebSocket(url), options = {}) {
|
|
7903
8001
|
const pending = new Map;
|
|
7904
8002
|
const joins = new Map;
|
|
7905
8003
|
const controlCallbacks = new Set;
|
|
@@ -7917,9 +8015,13 @@ async function connectPhoenixClient(baseUrl, token, socketFactory = (url) => new
|
|
|
7917
8015
|
rejectReady: undefined,
|
|
7918
8016
|
reconnectTimer: undefined
|
|
7919
8017
|
};
|
|
8018
|
+
const pushTimeoutMs = options.pushTimeoutMs ?? defaultPushTimeoutMs;
|
|
7920
8019
|
const rejectPending = (message) => {
|
|
7921
8020
|
const error = new Error(message);
|
|
7922
|
-
pending.forEach((pendingPush) =>
|
|
8021
|
+
pending.forEach((pendingPush) => {
|
|
8022
|
+
clearTimeout(pendingPush.timer);
|
|
8023
|
+
pendingPush.reject(error);
|
|
8024
|
+
});
|
|
7923
8025
|
pending.clear();
|
|
7924
8026
|
};
|
|
7925
8027
|
const resetReady = () => {
|
|
@@ -7935,6 +8037,7 @@ async function connectPhoenixClient(baseUrl, token, socketFactory = (url) => new
|
|
|
7935
8037
|
const pendingPush = pending.get(ref);
|
|
7936
8038
|
if (pendingPush !== undefined) {
|
|
7937
8039
|
pending.delete(ref);
|
|
8040
|
+
clearTimeout(pendingPush.timer);
|
|
7938
8041
|
if (name === "phx_error") {
|
|
7939
8042
|
pendingPush.reject(new Error("phoenix push failed"));
|
|
7940
8043
|
} else if (isNonOkPushReply(payload) && pendingPush.event !== "phx_join") {
|
|
@@ -7960,7 +8063,12 @@ async function connectPhoenixClient(baseUrl, token, socketFactory = (url) => new
|
|
|
7960
8063
|
state.nextRef += 1;
|
|
7961
8064
|
const frame = [null, ref, topic, event, payload];
|
|
7962
8065
|
return new Promise((resolve5, reject) => {
|
|
7963
|
-
|
|
8066
|
+
const timer = setTimeout(() => {
|
|
8067
|
+
if (pending.delete(ref)) {
|
|
8068
|
+
reject(new Error(`phoenix push timed out after ${pushTimeoutMs}ms: ${event}`));
|
|
8069
|
+
}
|
|
8070
|
+
}, pushTimeoutMs);
|
|
8071
|
+
pending.set(ref, { event, timer, resolve: resolve5, reject });
|
|
7964
8072
|
websocket.send(JSON.stringify(frame));
|
|
7965
8073
|
});
|
|
7966
8074
|
};
|
|
@@ -8035,10 +8143,10 @@ async function connectPhoenixClient(baseUrl, token, socketFactory = (url) => new
|
|
|
8035
8143
|
return pushOnOpenSocket(topic, event, payload);
|
|
8036
8144
|
};
|
|
8037
8145
|
return {
|
|
8038
|
-
join: async (topic, payload,
|
|
8146
|
+
join: async (topic, payload, options2) => {
|
|
8039
8147
|
const reply = await push(topic, "phx_join", payload);
|
|
8040
8148
|
if (isJoinReply(reply)) {
|
|
8041
|
-
joins.set(topic, { payload:
|
|
8149
|
+
joins.set(topic, { payload: options2?.rejoinPayload ?? (() => payload) });
|
|
8042
8150
|
return reply.response;
|
|
8043
8151
|
}
|
|
8044
8152
|
throw new Error(`phoenix join failed: ${joinErrorMessage(reply)}`);
|
|
@@ -8110,7 +8218,7 @@ import {
|
|
|
8110
8218
|
existsSync as existsSync5,
|
|
8111
8219
|
mkdirSync as mkdirSync6,
|
|
8112
8220
|
openSync as openSync2,
|
|
8113
|
-
readFileSync as
|
|
8221
|
+
readFileSync as readFileSync5,
|
|
8114
8222
|
unlinkSync as unlinkSync2,
|
|
8115
8223
|
writeSync
|
|
8116
8224
|
} from "node:fs";
|
|
@@ -8122,27 +8230,38 @@ import {
|
|
|
8122
8230
|
existsSync as existsSync4,
|
|
8123
8231
|
linkSync,
|
|
8124
8232
|
mkdirSync as mkdirSync5,
|
|
8125
|
-
readFileSync as
|
|
8233
|
+
readFileSync as readFileSync4,
|
|
8126
8234
|
realpathSync as realpathSync4,
|
|
8127
8235
|
unlinkSync,
|
|
8128
8236
|
writeFileSync as writeFileSync4
|
|
8129
8237
|
} from "node:fs";
|
|
8130
8238
|
import { homedir as homedir5 } from "node:os";
|
|
8131
8239
|
import { basename as basename4, dirname as dirname4, join as join6, resolve as resolve5 } from "node:path";
|
|
8240
|
+
|
|
8241
|
+
// src/defaultUrls.ts
|
|
8242
|
+
var defaultLinzumiHttpUrl = "https://serve.linzumi.com";
|
|
8243
|
+
var defaultLinzumiWebSocketUrl = "wss://serve.linzumi.com";
|
|
8244
|
+
|
|
8245
|
+
// src/localConfig.ts
|
|
8246
|
+
var prodConfigScope = "prod";
|
|
8132
8247
|
function localConfigPath(env = process.env) {
|
|
8133
8248
|
const override = env.LINZUMI_CONFIG_FILE;
|
|
8134
8249
|
return override !== undefined && override.trim() !== "" ? resolve5(expandUserPath(override)) : resolve5(homedir5(), ".linzumi", "config.json");
|
|
8135
8250
|
}
|
|
8251
|
+
function localConfigScopeKey(linzumiUrl) {
|
|
8252
|
+
const normalizedUrl = kandanHttpBaseUrl(linzumiUrl);
|
|
8253
|
+
const normalizedProdUrl = kandanHttpBaseUrl(defaultLinzumiWebSocketUrl);
|
|
8254
|
+
return normalizedUrl === normalizedProdUrl ? prodConfigScope : normalizedUrl;
|
|
8255
|
+
}
|
|
8256
|
+
function localConfigScopeFileStem(linzumiUrl) {
|
|
8257
|
+
const scopeKey = localConfigScopeKey(linzumiUrl);
|
|
8258
|
+
return scopeKey === prodConfigScope ? prodConfigScope : Buffer.from(scopeKey).toString("base64url");
|
|
8259
|
+
}
|
|
8136
8260
|
function readLocalConfig(path = localConfigPath()) {
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
if (!isConfigPayload(parsed)) {
|
|
8142
|
-
throw new Error(`invalid Linzumi config: ${path}`);
|
|
8143
|
-
}
|
|
8144
|
-
const allowedCwds = uniqueStrings(parsed.allowedCwds);
|
|
8145
|
-
return parsed.machineId === undefined ? { version: 1, allowedCwds } : { version: 1, machineId: parsed.machineId, allowedCwds };
|
|
8261
|
+
return readLocalConfigSection(path);
|
|
8262
|
+
}
|
|
8263
|
+
function readLocalConfigForLinzumiUrl(linzumiUrl, path = localConfigPath()) {
|
|
8264
|
+
return readLocalConfigSection(path, linzumiUrl);
|
|
8146
8265
|
}
|
|
8147
8266
|
function ensureLocalMachineId(path = localConfigPath(), createMachineId = randomUUID2) {
|
|
8148
8267
|
const config = readLocalConfig(path);
|
|
@@ -8158,13 +8277,36 @@ function ensureLocalMachineId(path = localConfigPath(), createMachineId = random
|
|
|
8158
8277
|
writeLocalConfig({ ...latestConfig, machineId }, path);
|
|
8159
8278
|
return machineId;
|
|
8160
8279
|
}
|
|
8161
|
-
function
|
|
8280
|
+
function ensureLocalMachineIdForLinzumiUrl(linzumiUrl, path = localConfigPath(), createMachineId = randomUUID2) {
|
|
8281
|
+
if (localConfigScopeKey(linzumiUrl) === prodConfigScope) {
|
|
8282
|
+
return ensureLocalMachineId(path, createMachineId);
|
|
8283
|
+
}
|
|
8284
|
+
const config = readLocalConfigForLinzumiUrl(linzumiUrl, path);
|
|
8285
|
+
if (config.machineId !== undefined) {
|
|
8286
|
+
return config.machineId;
|
|
8287
|
+
}
|
|
8288
|
+
const machineId = ensureLocalMachineIdSeed(path, createMachineId, linzumiUrl);
|
|
8289
|
+
const latestConfig = readLocalConfigForLinzumiUrl(linzumiUrl, path);
|
|
8290
|
+
const latestMachineId = latestConfig.machineId;
|
|
8291
|
+
if (latestMachineId !== undefined) {
|
|
8292
|
+
return latestMachineId;
|
|
8293
|
+
}
|
|
8294
|
+
writeLocalConfigSection({ ...latestConfig, machineId }, path, linzumiUrl);
|
|
8295
|
+
return machineId;
|
|
8296
|
+
}
|
|
8297
|
+
function localMachineIdSeedPath(configPath = localConfigPath(), linzumiUrl) {
|
|
8298
|
+
if (linzumiUrl !== undefined && localConfigScopeKey(linzumiUrl) !== prodConfigScope) {
|
|
8299
|
+
return join6(dirname4(configPath), `${basename4(configPath)}.${localConfigScopeFileStem(linzumiUrl)}.machine-id`);
|
|
8300
|
+
}
|
|
8162
8301
|
return join6(dirname4(configPath), `${basename4(configPath)}.machine-id`);
|
|
8163
8302
|
}
|
|
8164
|
-
function
|
|
8303
|
+
function readConfiguredAllowedCwdDetailsForLinzumiUrl(linzumiUrl, path = localConfigPath()) {
|
|
8304
|
+
return readConfiguredAllowedCwdDetailsFromConfig(readLocalConfigForLinzumiUrl(linzumiUrl, path));
|
|
8305
|
+
}
|
|
8306
|
+
function readConfiguredAllowedCwdDetailsFromConfig(config) {
|
|
8165
8307
|
const allowedCwds = [];
|
|
8166
8308
|
const missingAllowedCwds = [];
|
|
8167
|
-
for (const cwd of
|
|
8309
|
+
for (const cwd of config.allowedCwds) {
|
|
8168
8310
|
const absolutePath = resolve5(expandUserPath(cwd));
|
|
8169
8311
|
try {
|
|
8170
8312
|
const realPath = realpathSync4(absolutePath);
|
|
@@ -8183,36 +8325,91 @@ function readConfiguredAllowedCwdDetails(path = localConfigPath()) {
|
|
|
8183
8325
|
};
|
|
8184
8326
|
}
|
|
8185
8327
|
function addAllowedCwd(pathValue, path = localConfigPath()) {
|
|
8328
|
+
return addAllowedCwdToConfig(pathValue, path);
|
|
8329
|
+
}
|
|
8330
|
+
function addAllowedCwdForLinzumiUrl(pathValue, linzumiUrl, path = localConfigPath()) {
|
|
8331
|
+
return addAllowedCwdToConfig(pathValue, path, linzumiUrl);
|
|
8332
|
+
}
|
|
8333
|
+
function addAllowedCwdToConfig(pathValue, path, linzumiUrl) {
|
|
8186
8334
|
const normalizedPath = realpathSync4(resolve5(expandUserPath(pathValue)));
|
|
8187
|
-
const config =
|
|
8335
|
+
const config = readLocalConfigSection(path, linzumiUrl);
|
|
8188
8336
|
const allowedCwds = uniqueStrings([...config.allowedCwds, normalizedPath]);
|
|
8189
|
-
|
|
8337
|
+
writeLocalConfigSection({ ...config, version: 1, allowedCwds }, path, linzumiUrl);
|
|
8190
8338
|
return allowedCwds;
|
|
8191
8339
|
}
|
|
8192
8340
|
function removeAllowedCwd(pathValue, path = localConfigPath()) {
|
|
8341
|
+
return removeAllowedCwdFromConfig(pathValue, path);
|
|
8342
|
+
}
|
|
8343
|
+
function removeAllowedCwdForLinzumiUrl(pathValue, linzumiUrl, path = localConfigPath()) {
|
|
8344
|
+
return removeAllowedCwdFromConfig(pathValue, path, linzumiUrl);
|
|
8345
|
+
}
|
|
8346
|
+
function removeAllowedCwdFromConfig(pathValue, path, linzumiUrl) {
|
|
8193
8347
|
const requestedPath = resolve5(expandUserPath(pathValue));
|
|
8194
8348
|
const normalizedRequest = realpathOrResolved(requestedPath);
|
|
8195
|
-
const config =
|
|
8349
|
+
const config = readLocalConfigSection(path, linzumiUrl);
|
|
8196
8350
|
const allowedCwds = config.allowedCwds.filter((cwd) => {
|
|
8197
8351
|
const normalizedExisting = realpathOrResolved(cwd);
|
|
8198
8352
|
return cwd !== pathValue && normalizedExisting !== normalizedRequest;
|
|
8199
8353
|
});
|
|
8200
|
-
|
|
8354
|
+
writeLocalConfigSection({ ...config, version: 1, allowedCwds }, path, linzumiUrl);
|
|
8201
8355
|
return allowedCwds;
|
|
8202
8356
|
}
|
|
8203
8357
|
function writeLocalConfig(config, path = localConfigPath()) {
|
|
8358
|
+
writeLocalConfigSection(config, path);
|
|
8359
|
+
}
|
|
8360
|
+
function readLocalConfigFile(path) {
|
|
8361
|
+
if (!existsSync4(path)) {
|
|
8362
|
+
return { version: 1, allowedCwds: [] };
|
|
8363
|
+
}
|
|
8364
|
+
const parsed = JSON.parse(readFileSync4(path, "utf8"));
|
|
8365
|
+
if (!isConfigPayload(parsed)) {
|
|
8366
|
+
throw new Error(`invalid Linzumi config: ${path}`);
|
|
8367
|
+
}
|
|
8368
|
+
return parsed;
|
|
8369
|
+
}
|
|
8370
|
+
function readLocalConfigSection(path, linzumiUrl) {
|
|
8371
|
+
const parsed = readLocalConfigFile(path);
|
|
8372
|
+
const scopeKey = linzumiUrl === undefined ? prodConfigScope : localConfigScopeKey(linzumiUrl);
|
|
8373
|
+
const section = scopeKey === prodConfigScope ? parsed : parsed[scopeKey] ?? emptySection();
|
|
8374
|
+
if (!isConfigSection(section)) {
|
|
8375
|
+
throw new Error(`invalid Linzumi config section ${scopeKey}: ${path}`);
|
|
8376
|
+
}
|
|
8377
|
+
const allowedCwds = uniqueStrings(section.allowedCwds);
|
|
8378
|
+
return section.machineId === undefined ? { version: 1, allowedCwds } : { version: 1, machineId: section.machineId, allowedCwds };
|
|
8379
|
+
}
|
|
8380
|
+
function writeLocalConfigSection(config, path, linzumiUrl) {
|
|
8381
|
+
const scopeKey = linzumiUrl === undefined ? prodConfigScope : localConfigScopeKey(linzumiUrl);
|
|
8382
|
+
const nextSection = normalizedConfigSection(config);
|
|
8383
|
+
const next = scopeKey === prodConfigScope ? { ...readLocalConfigFile(path), ...nextSection, version: 1 } : {
|
|
8384
|
+
...readLocalConfigFile(path),
|
|
8385
|
+
version: 1,
|
|
8386
|
+
[scopeKey]: nextSection
|
|
8387
|
+
};
|
|
8204
8388
|
mkdirSync5(dirname4(path), { recursive: true });
|
|
8205
|
-
writeFileSync4(path, `${JSON.stringify(
|
|
8389
|
+
writeFileSync4(path, `${JSON.stringify(next, null, 2)}
|
|
8206
8390
|
`, "utf8");
|
|
8207
8391
|
}
|
|
8208
8392
|
function isConfigPayload(value) {
|
|
8209
|
-
return typeof value === "object" && value !== null && value.version === 1 &&
|
|
8393
|
+
return typeof value === "object" && value !== null && value.version === 1 && isConfigSection(value);
|
|
8394
|
+
}
|
|
8395
|
+
function isConfigSection(value) {
|
|
8396
|
+
return typeof value === "object" && value !== null && Array.isArray(value.allowedCwds) && machineIdValid(value.machineId) && value.allowedCwds.every((cwd) => typeof cwd === "string" && cwd.trim() !== "");
|
|
8397
|
+
}
|
|
8398
|
+
function normalizedConfigSection(config) {
|
|
8399
|
+
if (!isConfigPayload(config)) {
|
|
8400
|
+
throw new Error("invalid Linzumi config");
|
|
8401
|
+
}
|
|
8402
|
+
const allowedCwds = uniqueStrings(config.allowedCwds);
|
|
8403
|
+
return config.machineId === undefined ? { allowedCwds } : { machineId: config.machineId, allowedCwds };
|
|
8404
|
+
}
|
|
8405
|
+
function emptySection() {
|
|
8406
|
+
return { allowedCwds: [] };
|
|
8210
8407
|
}
|
|
8211
8408
|
function machineIdValid(value) {
|
|
8212
8409
|
return value === undefined || typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
|
|
8213
8410
|
}
|
|
8214
|
-
function ensureLocalMachineIdSeed(configPath, createMachineId) {
|
|
8215
|
-
const seedPath = localMachineIdSeedPath(configPath);
|
|
8411
|
+
function ensureLocalMachineIdSeed(configPath, createMachineId, linzumiUrl) {
|
|
8412
|
+
const seedPath = localMachineIdSeedPath(configPath, linzumiUrl);
|
|
8216
8413
|
if (existsSync4(seedPath)) {
|
|
8217
8414
|
return readMachineIdSeed(seedPath);
|
|
8218
8415
|
}
|
|
@@ -8237,7 +8434,7 @@ function ensureLocalMachineIdSeed(configPath, createMachineId) {
|
|
|
8237
8434
|
}
|
|
8238
8435
|
}
|
|
8239
8436
|
function readMachineIdSeed(seedPath) {
|
|
8240
|
-
const machineId =
|
|
8437
|
+
const machineId = readFileSync4(seedPath, "utf8").trim();
|
|
8241
8438
|
if (!machineIdValid(machineId)) {
|
|
8242
8439
|
throw new Error(`invalid Linzumi machine id seed: ${seedPath}`);
|
|
8243
8440
|
}
|
|
@@ -8263,15 +8460,16 @@ function realpathOrResolved(pathValue) {
|
|
|
8263
8460
|
}
|
|
8264
8461
|
|
|
8265
8462
|
// src/version.ts
|
|
8266
|
-
var linzumiCliVersion = "0.0.
|
|
8463
|
+
var linzumiCliVersion = "0.0.46-beta";
|
|
8267
8464
|
var linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
|
|
8268
8465
|
|
|
8269
8466
|
// src/runnerLock.ts
|
|
8270
|
-
function runnerLockPath(machineId, configPath = localConfigPath()) {
|
|
8271
|
-
|
|
8467
|
+
function runnerLockPath(machineId, configPath = localConfigPath(), linzumiUrl) {
|
|
8468
|
+
const lockName = linzumiUrl === undefined ? encodeURIComponent(machineId) : localConfigScopeFileStem(linzumiUrl);
|
|
8469
|
+
return join7(dirname5(configPath), "runners", `${lockName}.lock`);
|
|
8272
8470
|
}
|
|
8273
8471
|
function acquireRunnerLock(options) {
|
|
8274
|
-
const path = runnerLockPath(options.machineId, options.configPath);
|
|
8472
|
+
const path = runnerLockPath(options.machineId, options.configPath, options.linzumiUrl);
|
|
8275
8473
|
const isPidAlive = options.isPidAlive ?? processIsAlive;
|
|
8276
8474
|
const record = {
|
|
8277
8475
|
version: 1,
|
|
@@ -8280,9 +8478,11 @@ function acquireRunnerLock(options) {
|
|
|
8280
8478
|
pid: options.pid ?? process.pid,
|
|
8281
8479
|
cwd: options.cwd,
|
|
8282
8480
|
workspace: options.workspace,
|
|
8481
|
+
...options.linzumiUrl === undefined ? {} : { linzumiUrl: kandanHttpBaseUrl(options.linzumiUrl) },
|
|
8283
8482
|
startedAt: (options.now ?? (() => new Date))().toISOString(),
|
|
8284
8483
|
cliVersion: options.cliVersion ?? linzumiCliVersion
|
|
8285
8484
|
};
|
|
8485
|
+
rejectLiveLegacyProductionRunnerLock(options.machineId, options.configPath, options.linzumiUrl, isPidAlive);
|
|
8286
8486
|
writeLockOrHandleExisting(path, record, isPidAlive, options.beforeReadExistingLock, options.beforeReplaceStaleLock);
|
|
8287
8487
|
return {
|
|
8288
8488
|
path,
|
|
@@ -8290,6 +8490,28 @@ function acquireRunnerLock(options) {
|
|
|
8290
8490
|
release: () => releaseRunnerLock(path, record)
|
|
8291
8491
|
};
|
|
8292
8492
|
}
|
|
8493
|
+
function rejectLiveLegacyProductionRunnerLock(machineId, configPath, linzumiUrl, isPidAlive) {
|
|
8494
|
+
if (linzumiUrl === undefined || localConfigScopeKey(linzumiUrl) !== localConfigScopeKey(defaultLinzumiHttpUrl)) {
|
|
8495
|
+
return;
|
|
8496
|
+
}
|
|
8497
|
+
const legacyPath = runnerLockPath(machineId, configPath);
|
|
8498
|
+
const existing = readRunnerLockIfPresent(legacyPath);
|
|
8499
|
+
if (existing === undefined) {
|
|
8500
|
+
return;
|
|
8501
|
+
}
|
|
8502
|
+
if (isPidAlive(existing.pid)) {
|
|
8503
|
+
throw new Error(activeRunnerLockMessage(legacyPath, existing));
|
|
8504
|
+
}
|
|
8505
|
+
withStaleReplacementLock(legacyPath, isPidAlive, () => {
|
|
8506
|
+
const latest = existsSync5(legacyPath) ? readRunnerLock(legacyPath) : undefined;
|
|
8507
|
+
if (latest !== undefined && isPidAlive(latest.pid)) {
|
|
8508
|
+
throw new Error(activeRunnerLockMessage(legacyPath, latest));
|
|
8509
|
+
}
|
|
8510
|
+
if (latest !== undefined) {
|
|
8511
|
+
unlinkSync2(legacyPath);
|
|
8512
|
+
}
|
|
8513
|
+
});
|
|
8514
|
+
}
|
|
8293
8515
|
function writeLockOrHandleExisting(path, record, isPidAlive, beforeReadExistingLock, beforeReplaceStaleLock) {
|
|
8294
8516
|
if (tryCreateLock(path, record)) {
|
|
8295
8517
|
return;
|
|
@@ -8375,7 +8597,7 @@ function withStaleReplacementLock(path, isPidAlive, callback) {
|
|
|
8375
8597
|
function readReplacementLockPidIfPresent(path) {
|
|
8376
8598
|
let value;
|
|
8377
8599
|
try {
|
|
8378
|
-
value =
|
|
8600
|
+
value = readFileSync5(path, "utf8").trim();
|
|
8379
8601
|
} catch (error) {
|
|
8380
8602
|
if (isNodeErrorCode2(error, "ENOENT")) {
|
|
8381
8603
|
return;
|
|
@@ -8415,14 +8637,17 @@ function readRunnerLockIfPresent(path) {
|
|
|
8415
8637
|
}
|
|
8416
8638
|
}
|
|
8417
8639
|
function readRunnerLock(path) {
|
|
8418
|
-
const parsed = JSON.parse(
|
|
8640
|
+
const parsed = JSON.parse(readFileSync5(path, "utf8"));
|
|
8419
8641
|
if (!isRunnerLockRecord(parsed)) {
|
|
8420
8642
|
throw new Error(`invalid Linzumi runner lock: ${path}`);
|
|
8421
8643
|
}
|
|
8422
8644
|
return parsed;
|
|
8423
8645
|
}
|
|
8424
8646
|
function isRunnerLockRecord(value) {
|
|
8425
|
-
return typeof value === "object" && value !== null && value.version === 1 && typeof value.machineId === "string" && value.machineId.trim() !== "" && typeof value.runnerId === "string" && value.runnerId.trim() !== "" && Number.isInteger(value.pid) && value.pid > 0 && typeof value.cwd === "string" && value.cwd.trim() !== "" && workspaceValid(value.workspace) && typeof value.startedAt === "string" && value.startedAt.trim() !== "" && typeof value.cliVersion === "string" && value.cliVersion.trim() !== "";
|
|
8647
|
+
return typeof value === "object" && value !== null && value.version === 1 && typeof value.machineId === "string" && value.machineId.trim() !== "" && typeof value.runnerId === "string" && value.runnerId.trim() !== "" && Number.isInteger(value.pid) && value.pid > 0 && typeof value.cwd === "string" && value.cwd.trim() !== "" && workspaceValid(value.workspace) && linzumiUrlValid(value.linzumiUrl) && typeof value.startedAt === "string" && value.startedAt.trim() !== "" && typeof value.cliVersion === "string" && value.cliVersion.trim() !== "";
|
|
8648
|
+
}
|
|
8649
|
+
function linzumiUrlValid(value) {
|
|
8650
|
+
return value === undefined || typeof value === "string" && value.trim() !== "";
|
|
8426
8651
|
}
|
|
8427
8652
|
function workspaceValid(value) {
|
|
8428
8653
|
return value === null || typeof value === "string" && value.trim() !== "";
|
|
@@ -8437,8 +8662,10 @@ function processIsAlive(pid) {
|
|
|
8437
8662
|
}
|
|
8438
8663
|
function activeRunnerLockMessage(path, record) {
|
|
8439
8664
|
const workspace = record.workspace === null ? "workspace: unknown" : `workspace: ${record.workspace}`;
|
|
8665
|
+
const linzumiUrl = record.linzumiUrl === undefined ? undefined : `linzumi url: ${displayLinzumiUrl(record.linzumiUrl)}`;
|
|
8440
8666
|
return [
|
|
8441
|
-
"another Linzumi runner is already running for this machine",
|
|
8667
|
+
record.linzumiUrl === undefined ? "another Linzumi runner is already running for this machine" : "another Linzumi runner is already running for this Linzumi URL",
|
|
8668
|
+
...linzumiUrl === undefined ? [] : [linzumiUrl],
|
|
8442
8669
|
`runner id: ${record.runnerId}`,
|
|
8443
8670
|
`pid: ${record.pid}`,
|
|
8444
8671
|
`cwd: ${record.cwd}`,
|
|
@@ -8450,6 +8677,12 @@ function activeRunnerLockMessage(path, record) {
|
|
|
8450
8677
|
].join(`
|
|
8451
8678
|
`);
|
|
8452
8679
|
}
|
|
8680
|
+
function displayLinzumiUrl(linzumiUrl) {
|
|
8681
|
+
if (linzumiUrl === localConfigScopeKey(defaultLinzumiHttpUrl)) {
|
|
8682
|
+
return defaultLinzumiHttpUrl;
|
|
8683
|
+
}
|
|
8684
|
+
return localConfigScopeKey(linzumiUrl) === localConfigScopeKey(defaultLinzumiHttpUrl) ? defaultLinzumiHttpUrl : linzumiUrl;
|
|
8685
|
+
}
|
|
8453
8686
|
function isNodeErrorCode2(error, code) {
|
|
8454
8687
|
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
8455
8688
|
}
|
|
@@ -8611,6 +8844,7 @@ async function runLocalCodexRunner(options) {
|
|
|
8611
8844
|
runnerId: options.runnerId,
|
|
8612
8845
|
cwd: options.cwd,
|
|
8613
8846
|
workspace: runnerWorkspaceSlug(options) ?? null,
|
|
8847
|
+
linzumiUrl: options.kandanUrl,
|
|
8614
8848
|
configPath: options.runnerLockConfigPath
|
|
8615
8849
|
});
|
|
8616
8850
|
cleanup.actions.push(() => runnerLock.release());
|
|
@@ -8717,11 +8951,14 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
8717
8951
|
cleanup.actions.push(() => kandan.close());
|
|
8718
8952
|
const topic = `local_runner:${options.runnerId}`;
|
|
8719
8953
|
const clientId = options.machineId ?? options.runnerId;
|
|
8954
|
+
const runnerHost = hostname2();
|
|
8720
8955
|
const joinPayload = () => ({
|
|
8721
8956
|
clientName: "kandan-local-codex-runner",
|
|
8722
8957
|
clientId,
|
|
8723
8958
|
runnerPid: process.pid,
|
|
8724
8959
|
version: linzumiCliVersion,
|
|
8960
|
+
hostname: runnerHost,
|
|
8961
|
+
cwd: options.cwd,
|
|
8725
8962
|
workspace: runnerWorkspaceSlug(options) ?? null,
|
|
8726
8963
|
channel: options.channelSession?.channelSlug ?? null,
|
|
8727
8964
|
capabilities: capabilitiesPayload()
|
|
@@ -8990,7 +9227,6 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
8990
9227
|
const seq = { value: 0 };
|
|
8991
9228
|
const codexThreads = options.channelSession === undefined ? await discoverCodexThreads(codex, options.cwd) : [];
|
|
8992
9229
|
const discoveredCodexThreads = { value: codexThreads };
|
|
8993
|
-
const runnerHost = hostname2();
|
|
8994
9230
|
const runtimeDefaults = runnerRuntimeDefaults(options);
|
|
8995
9231
|
const instancePayload = {
|
|
8996
9232
|
instanceId,
|
|
@@ -10005,7 +10241,7 @@ function allowedCwdSuggestions(cwd, allowedCwds) {
|
|
|
10005
10241
|
}
|
|
10006
10242
|
|
|
10007
10243
|
// src/authCache.ts
|
|
10008
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync7, readFileSync as
|
|
10244
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
|
|
10009
10245
|
import { homedir as homedir6 } from "node:os";
|
|
10010
10246
|
import { dirname as dirname6, join as join9 } from "node:path";
|
|
10011
10247
|
function defaultAuthFilePath() {
|
|
@@ -10016,7 +10252,7 @@ function readCachedLocalRunnerToken(kandanUrl, authFilePath = defaultAuthFilePat
|
|
|
10016
10252
|
if (!existsSync6(authFilePath)) {
|
|
10017
10253
|
return;
|
|
10018
10254
|
}
|
|
10019
|
-
const authFile = parseAuthFile(
|
|
10255
|
+
const authFile = parseAuthFile(readFileSync6(authFilePath, "utf8"));
|
|
10020
10256
|
const kandanBaseUrl = kandanHttpBaseUrl(kandanUrl);
|
|
10021
10257
|
const entry = authFile.local_codex_runner?.[kandanBaseUrl];
|
|
10022
10258
|
if (entry === undefined || entry.access_token.trim() === "") {
|
|
@@ -10034,7 +10270,7 @@ function readCachedLocalRunnerToken(kandanUrl, authFilePath = defaultAuthFilePat
|
|
|
10034
10270
|
}
|
|
10035
10271
|
function writeCachedLocalRunnerToken(args) {
|
|
10036
10272
|
const authFilePath = args.authFilePath ?? defaultAuthFilePath();
|
|
10037
|
-
const existing = existsSync6(authFilePath) ? parseAuthFile(
|
|
10273
|
+
const existing = existsSync6(authFilePath) ? parseAuthFile(readFileSync6(authFilePath, "utf8")) : { version: 1 };
|
|
10038
10274
|
const kandanBaseUrl = kandanHttpBaseUrl(args.kandanUrl);
|
|
10039
10275
|
const issuedAt = new Date;
|
|
10040
10276
|
const expiresAt = args.expiresInSeconds === undefined ? undefined : new Date(issuedAt.getTime() + args.expiresInSeconds * 1000).toISOString();
|
|
@@ -10143,12 +10379,8 @@ async function acquireAndCacheToken(args) {
|
|
|
10143
10379
|
return token.accessToken;
|
|
10144
10380
|
}
|
|
10145
10381
|
|
|
10146
|
-
// src/defaultUrls.ts
|
|
10147
|
-
var defaultLinzumiHttpUrl = "https://serve.linzumi.com";
|
|
10148
|
-
var defaultLinzumiWebSocketUrl = "wss://serve.linzumi.com";
|
|
10149
|
-
|
|
10150
10382
|
// src/kandanTls.ts
|
|
10151
|
-
import { existsSync as existsSync7, readFileSync as
|
|
10383
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
|
|
10152
10384
|
import { Agent } from "undici";
|
|
10153
10385
|
import { WebSocket as WsWebSocket } from "ws";
|
|
10154
10386
|
function kandanTlsTrustFromEnv() {
|
|
@@ -10162,7 +10394,7 @@ function kandanTlsTrustFromCaFile(caFile) {
|
|
|
10162
10394
|
if (!existsSync7(trimmed)) {
|
|
10163
10395
|
throw new Error(`KANDAN_TLS_CA_FILE does not exist: ${trimmed}`);
|
|
10164
10396
|
}
|
|
10165
|
-
const ca =
|
|
10397
|
+
const ca = readFileSync7(trimmed, "utf8");
|
|
10166
10398
|
return {
|
|
10167
10399
|
caFile: trimmed,
|
|
10168
10400
|
ca,
|
|
@@ -10191,7 +10423,7 @@ function trustedWebSocketFactory(trust, WebSocketImpl = WsWebSocket) {
|
|
|
10191
10423
|
}
|
|
10192
10424
|
|
|
10193
10425
|
// src/agentBootstrap.ts
|
|
10194
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as
|
|
10426
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
|
|
10195
10427
|
import { dirname as dirname7, join as join10 } from "node:path";
|
|
10196
10428
|
import { homedir as homedir7 } from "node:os";
|
|
10197
10429
|
async function runAgentCliCommand(args, deps = {
|
|
@@ -10801,7 +11033,7 @@ function authorizationHeaders(token) {
|
|
|
10801
11033
|
return { authorization: `Bearer ${token}` };
|
|
10802
11034
|
}
|
|
10803
11035
|
function readOptionalTextFile(path) {
|
|
10804
|
-
return existsSync8(path) ?
|
|
11036
|
+
return existsSync8(path) ? readFileSync8(path, "utf8") : undefined;
|
|
10805
11037
|
}
|
|
10806
11038
|
function writeTextFile(path, content) {
|
|
10807
11039
|
mkdirSync8(dirname7(path), { recursive: true });
|
|
@@ -10881,7 +11113,7 @@ Launch target:
|
|
|
10881
11113
|
}
|
|
10882
11114
|
|
|
10883
11115
|
// src/helloLinzumiProject.ts
|
|
10884
|
-
import { existsSync as existsSync9, mkdirSync as mkdirSync9, readFileSync as
|
|
11116
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync9, readFileSync as readFileSync9, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
|
|
10885
11117
|
import { dirname as dirname8, join as join11, resolve as resolve7 } from "node:path";
|
|
10886
11118
|
import { fileURLToPath } from "node:url";
|
|
10887
11119
|
var defaultHelloLinzumiProjectDir = "/tmp/hello_linzumi";
|
|
@@ -10891,7 +11123,7 @@ var defaultHelloLinzumiPort = 8787;
|
|
|
10891
11123
|
var defaultHelloLinzumiHost = "0.0.0.0";
|
|
10892
11124
|
var markerFile = ".linzumi-demo-project";
|
|
10893
11125
|
var moduleDir = dirname8(fileURLToPath(import.meta.url));
|
|
10894
|
-
var linzumiLogoSvg =
|
|
11126
|
+
var linzumiLogoSvg = readFileSync9(join11(moduleDir, "assets", "linzumi-logo.svg"), "utf8");
|
|
10895
11127
|
function createHelloLinzumiProject(input = {}) {
|
|
10896
11128
|
const options = typeof input === "string" ? { rootPath: input } : input;
|
|
10897
11129
|
const root = resolveHelloProjectRoot(options);
|
|
@@ -10946,7 +11178,7 @@ function assertWritableDemoRoot(root, reset) {
|
|
|
10946
11178
|
return;
|
|
10947
11179
|
}
|
|
10948
11180
|
const markerPath = join11(root, markerFile);
|
|
10949
|
-
const isDemoRoot = existsSync9(markerPath) &&
|
|
11181
|
+
const isDemoRoot = existsSync9(markerPath) && readFileSync9(markerPath, "utf8").trim() === "hello-linzumi";
|
|
10950
11182
|
if (isDemoRoot && reset) {
|
|
10951
11183
|
rmSync2(root, { recursive: true, force: true });
|
|
10952
11184
|
return;
|
|
@@ -11449,7 +11681,7 @@ import {
|
|
|
11449
11681
|
closeSync as closeSync2,
|
|
11450
11682
|
mkdirSync as mkdirSync10,
|
|
11451
11683
|
openSync as openSync3,
|
|
11452
|
-
readFileSync as
|
|
11684
|
+
readFileSync as readFileSync10,
|
|
11453
11685
|
watch,
|
|
11454
11686
|
writeFileSync as writeFileSync8
|
|
11455
11687
|
} from "node:fs";
|
|
@@ -11534,12 +11766,12 @@ function commanderDaemonStatus(runnerId, statusDir = commanderStatusDir(), proce
|
|
|
11534
11766
|
if (!existsSync10(statusFile)) {
|
|
11535
11767
|
return { status: "missing", runnerId, statusFile };
|
|
11536
11768
|
}
|
|
11537
|
-
const record = parseRecord(
|
|
11769
|
+
const record = parseRecord(readFileSync10(statusFile, "utf8"));
|
|
11538
11770
|
return processIsRunning(record.pid) && processMatchesRecord(record, processIdentityReader) ? { status: "running", record } : { status: "stopped", record };
|
|
11539
11771
|
}
|
|
11540
11772
|
async function waitForCommanderDaemon(options) {
|
|
11541
11773
|
const now = options.now ?? (() => Date.now());
|
|
11542
|
-
const readTextFile = options.readTextFile ?? ((path) => existsSync10(path) ?
|
|
11774
|
+
const readTextFile = options.readTextFile ?? ((path) => existsSync10(path) ? readFileSync10(path, "utf8") : undefined);
|
|
11543
11775
|
const statusImpl = options.statusImpl ?? commanderDaemonStatus;
|
|
11544
11776
|
const deadline = now() + options.timeoutMs;
|
|
11545
11777
|
while (now() <= deadline) {
|
|
@@ -11794,7 +12026,7 @@ async function main(args) {
|
|
|
11794
12026
|
}
|
|
11795
12027
|
case "start": {
|
|
11796
12028
|
const options = await parseStartRunnerArgs(parsed.args);
|
|
11797
|
-
|
|
12029
|
+
addAllowedCwdForLinzumiUrl(options.cwd, options.kandanUrl);
|
|
11798
12030
|
await runLocalCodexRunner(withLocalMachineId(options));
|
|
11799
12031
|
return;
|
|
11800
12032
|
}
|
|
@@ -11897,19 +12129,16 @@ function runHelloCommand(args) {
|
|
|
11897
12129
|
`);
|
|
11898
12130
|
}
|
|
11899
12131
|
function runPathsCommand(args) {
|
|
11900
|
-
const
|
|
11901
|
-
if (
|
|
12132
|
+
const { subcommand, pathValue, linzumiUrl, help } = parsePathsCommandArgs(args);
|
|
12133
|
+
if (help || subcommand === undefined || subcommand === "help") {
|
|
11902
12134
|
process.stdout.write(pathsHelpText());
|
|
11903
12135
|
return;
|
|
11904
12136
|
}
|
|
11905
|
-
if (rest.length > 0) {
|
|
11906
|
-
throw new Error("linzumi paths accepts one path argument");
|
|
11907
|
-
}
|
|
11908
12137
|
switch (subcommand) {
|
|
11909
12138
|
case "list": {
|
|
11910
|
-
const config = readLocalConfig();
|
|
12139
|
+
const config = linzumiUrl === undefined ? readLocalConfig() : readLocalConfigForLinzumiUrl(linzumiUrl);
|
|
11911
12140
|
if (config.allowedCwds.length === 0) {
|
|
11912
|
-
process.stdout.write(`No trusted paths configured in ${localConfigPath()}
|
|
12141
|
+
process.stdout.write(`No trusted paths configured in ${localConfigPath()}${pathsScopeSuffix(linzumiUrl)}
|
|
11913
12142
|
`);
|
|
11914
12143
|
return;
|
|
11915
12144
|
}
|
|
@@ -11923,7 +12152,11 @@ function runPathsCommand(args) {
|
|
|
11923
12152
|
throw new Error("missing path for linzumi paths add");
|
|
11924
12153
|
}
|
|
11925
12154
|
const trustedPath = realpathSync6(resolve9(expandUserPath(pathValue)));
|
|
11926
|
-
|
|
12155
|
+
if (linzumiUrl === undefined) {
|
|
12156
|
+
addAllowedCwd(pathValue);
|
|
12157
|
+
} else {
|
|
12158
|
+
addAllowedCwdForLinzumiUrl(pathValue, linzumiUrl);
|
|
12159
|
+
}
|
|
11927
12160
|
process.stdout.write(`Trusted ${trustedPath}
|
|
11928
12161
|
`);
|
|
11929
12162
|
return;
|
|
@@ -11932,7 +12165,11 @@ function runPathsCommand(args) {
|
|
|
11932
12165
|
if (pathValue === undefined || pathValue.trim() === "") {
|
|
11933
12166
|
throw new Error("missing path for linzumi paths remove");
|
|
11934
12167
|
}
|
|
11935
|
-
|
|
12168
|
+
if (linzumiUrl === undefined) {
|
|
12169
|
+
removeAllowedCwd(pathValue);
|
|
12170
|
+
} else {
|
|
12171
|
+
removeAllowedCwdForLinzumiUrl(pathValue, linzumiUrl);
|
|
12172
|
+
}
|
|
11936
12173
|
process.stdout.write(`Removed trusted path ${pathValue}
|
|
11937
12174
|
`);
|
|
11938
12175
|
return;
|
|
@@ -11941,6 +12178,46 @@ function runPathsCommand(args) {
|
|
|
11941
12178
|
throw new Error(`invalid paths command: ${subcommand}`);
|
|
11942
12179
|
}
|
|
11943
12180
|
}
|
|
12181
|
+
function parsePathsCommandArgs(args) {
|
|
12182
|
+
const positional = [];
|
|
12183
|
+
let linzumiUrl;
|
|
12184
|
+
let help = false;
|
|
12185
|
+
for (let index = 0;index < args.length; index += 1) {
|
|
12186
|
+
const arg = args[index];
|
|
12187
|
+
switch (arg) {
|
|
12188
|
+
case "--help":
|
|
12189
|
+
help = true;
|
|
12190
|
+
break;
|
|
12191
|
+
case "--linzumi-url":
|
|
12192
|
+
case "--kandan-url": {
|
|
12193
|
+
const value = args[index + 1];
|
|
12194
|
+
if (value === undefined || value.startsWith("--")) {
|
|
12195
|
+
throw new Error(`missing value for ${arg}`);
|
|
12196
|
+
}
|
|
12197
|
+
linzumiUrl = value;
|
|
12198
|
+
index += 1;
|
|
12199
|
+
break;
|
|
12200
|
+
}
|
|
12201
|
+
default:
|
|
12202
|
+
if (arg !== undefined && arg.startsWith("--")) {
|
|
12203
|
+
throw new Error(`invalid flag: ${arg}`);
|
|
12204
|
+
}
|
|
12205
|
+
positional.push(arg ?? "");
|
|
12206
|
+
}
|
|
12207
|
+
}
|
|
12208
|
+
if (positional.length > 2) {
|
|
12209
|
+
throw new Error("linzumi paths accepts one path argument");
|
|
12210
|
+
}
|
|
12211
|
+
return {
|
|
12212
|
+
subcommand: positional[0],
|
|
12213
|
+
pathValue: positional[1],
|
|
12214
|
+
linzumiUrl,
|
|
12215
|
+
help
|
|
12216
|
+
};
|
|
12217
|
+
}
|
|
12218
|
+
function pathsScopeSuffix(linzumiUrl) {
|
|
12219
|
+
return linzumiUrl === undefined ? "" : ` for ${linzumiUrl}`;
|
|
12220
|
+
}
|
|
11944
12221
|
async function runCommanderDaemonCommand(args) {
|
|
11945
12222
|
const [subcommand, ...rest] = args;
|
|
11946
12223
|
switch (subcommand) {
|
|
@@ -12172,7 +12449,7 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
12172
12449
|
const kandanUrl = stringValue3(values, "linzumi-url") ?? agentApiUrlToKandanUrl(tokenFile.apiUrl);
|
|
12173
12450
|
const requestedCwdValue = cwdArg ?? stringValue3(values, "cwd");
|
|
12174
12451
|
const requestedCwd = resolveUserPath(requestedCwdValue ?? process.cwd());
|
|
12175
|
-
const configuredAllowedCwds2 = requestedCwdValue === undefined && !values.has("allowed-cwd") ?
|
|
12452
|
+
const configuredAllowedCwds2 = requestedCwdValue === undefined && !values.has("allowed-cwd") ? readConfiguredAllowedCwdDetailsForLinzumiUrl(kandanUrl) : { allowedCwds: [], missingAllowedCwds: [] };
|
|
12176
12453
|
const allowedCwds = values.has("allowed-cwd") ? assertConfiguredAllowedCwds(parseAllowedCwdList(stringValue3(values, "allowed-cwd"))) : requestedCwdValue === undefined ? configuredAllowedCwds2.allowedCwds.length > 0 ? [...configuredAllowedCwds2.allowedCwds] : assertConfiguredAllowedCwds([requestedCwd]) : assertConfiguredAllowedCwds([requestedCwd]);
|
|
12177
12454
|
const cwd = allowedCwds[0] ?? requestedCwd;
|
|
12178
12455
|
const codexBin = stringValue3(values, "codex-bin") ?? "codex";
|
|
@@ -12219,7 +12496,7 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
12219
12496
|
};
|
|
12220
12497
|
}
|
|
12221
12498
|
function readAgentTokenTextFile(path) {
|
|
12222
|
-
return existsSync11(path) ?
|
|
12499
|
+
return existsSync11(path) ? readFileSync11(path, "utf8") : undefined;
|
|
12223
12500
|
}
|
|
12224
12501
|
function rejectAgentRunnerTargetingFlags(values) {
|
|
12225
12502
|
const unsupportedFlags = [
|
|
@@ -12303,7 +12580,7 @@ async function parseRunnerArgs(args, deps = {
|
|
|
12303
12580
|
const kandanUrl = stringValue3(values, "linzumi-url") ?? defaultLinzumiWebSocketUrl;
|
|
12304
12581
|
const cwd = stringValue3(values, "cwd") ?? process.cwd();
|
|
12305
12582
|
const cwdAllowedCwds = assertConfiguredAllowedCwds([cwd]);
|
|
12306
|
-
const localConfiguredAllowedCwds = values.has("allowed-cwd") ? { allowedCwds: [], missingAllowedCwds: [] } :
|
|
12583
|
+
const localConfiguredAllowedCwds = values.has("allowed-cwd") ? { allowedCwds: [], missingAllowedCwds: [] } : readConfiguredAllowedCwdDetailsForLinzumiUrl(kandanUrl);
|
|
12307
12584
|
const configuredAllowedCwds2 = values.has("allowed-cwd") ? assertConfiguredAllowedCwds(parseAllowedCwdList(stringValue3(values, "allowed-cwd"))) : [...localConfiguredAllowedCwds.allowedCwds];
|
|
12308
12585
|
const codexBin = stringValue3(values, "codex-bin") ?? "codex";
|
|
12309
12586
|
const customCodeServerBin = stringValue3(values, "code-server-bin");
|
|
@@ -12516,7 +12793,7 @@ function parseChannelPath(channel) {
|
|
|
12516
12793
|
function withLocalMachineId(options) {
|
|
12517
12794
|
return {
|
|
12518
12795
|
...options,
|
|
12519
|
-
machineId: ensureLocalMachineId()
|
|
12796
|
+
machineId: localConfigScopeKey(options.kandanUrl) === localConfigScopeKey(defaultLinzumiWebSocketUrl) ? ensureLocalMachineId() : ensureLocalMachineIdForLinzumiUrl(options.kandanUrl)
|
|
12520
12797
|
};
|
|
12521
12798
|
}
|
|
12522
12799
|
function required(values, key) {
|
|
@@ -12698,13 +12975,13 @@ function pathsHelpText() {
|
|
|
12698
12975
|
return `Linzumi trusted paths
|
|
12699
12976
|
|
|
12700
12977
|
Usage:
|
|
12701
|
-
linzumi paths list
|
|
12702
|
-
linzumi paths add <path>
|
|
12703
|
-
linzumi paths remove <path>
|
|
12978
|
+
linzumi paths [--linzumi-url <ws-url>] list
|
|
12979
|
+
linzumi paths [--linzumi-url <ws-url>] add <path>
|
|
12980
|
+
linzumi paths [--linzumi-url <ws-url>] remove <path>
|
|
12704
12981
|
|
|
12705
|
-
Trusted paths are stored in ~/.linzumi/config.json.
|
|
12706
|
-
|
|
12707
|
-
|
|
12982
|
+
Trusted paths are stored in ~/.linzumi/config.json. Production/default paths
|
|
12983
|
+
use the root config fields; explicit --linzumi-url paths use a URL-scoped config
|
|
12984
|
+
section so local, staging, and production runners do not share trust state.
|
|
12708
12985
|
`;
|
|
12709
12986
|
}
|
|
12710
12987
|
function startHelpText() {
|
package/package.json
CHANGED