@linzumi/cli 0.0.44-beta → 0.0.45-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 +392 -93
- 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";
|
|
@@ -6016,6 +6016,7 @@ function pathLooksAbsolute(pathValue) {
|
|
|
6016
6016
|
|
|
6017
6017
|
// src/localForwarding.ts
|
|
6018
6018
|
import { gzipSync } from "node:zlib";
|
|
6019
|
+
import NodeWebSocket from "ws";
|
|
6019
6020
|
var maxForwardBodyBytes = 64 * 1024 * 1024;
|
|
6020
6021
|
var gzipForwardThresholdBytes = 32 * 1024;
|
|
6021
6022
|
async function handleForwardHttpRequest(control, allowedPorts) {
|
|
@@ -6059,15 +6060,15 @@ function isForwardHttpRequestControl(control) {
|
|
|
6059
6060
|
function isForwardWebSocketControl(control) {
|
|
6060
6061
|
return control.type === "forward_websocket_open" || control.type === "forward_websocket_send" || control.type === "forward_websocket_close";
|
|
6061
6062
|
}
|
|
6062
|
-
function createForwardWebSocketManager(kandan, topic, allowedPorts) {
|
|
6063
|
+
function createForwardWebSocketManager(kandan, topic, allowedPorts, socketFactory = defaultForwardWebSocketFactory) {
|
|
6063
6064
|
const sockets = new Map;
|
|
6064
6065
|
const pushEvent = (payload) => kandan.push(topic, "forward:websocket_event", payload).catch(() => {
|
|
6065
6066
|
return;
|
|
6066
6067
|
});
|
|
6067
6068
|
const closeSocket = (socketId) => {
|
|
6068
|
-
const
|
|
6069
|
+
const stream = sockets.get(socketId);
|
|
6069
6070
|
sockets.delete(socketId);
|
|
6070
|
-
socket
|
|
6071
|
+
stream?.socket.close();
|
|
6071
6072
|
};
|
|
6072
6073
|
return {
|
|
6073
6074
|
handle: (control) => {
|
|
@@ -6081,12 +6082,12 @@ function createForwardWebSocketManager(kandan, topic, allowedPorts) {
|
|
|
6081
6082
|
});
|
|
6082
6083
|
return;
|
|
6083
6084
|
}
|
|
6084
|
-
openLocalWebSocket(control, sockets, pushEvent, "ws");
|
|
6085
|
+
openLocalWebSocket(control, sockets, pushEvent, socketFactory, "ws");
|
|
6085
6086
|
return;
|
|
6086
6087
|
}
|
|
6087
6088
|
case "forward_websocket_send": {
|
|
6088
|
-
const
|
|
6089
|
-
if (
|
|
6089
|
+
const stream = sockets.get(control.socketId);
|
|
6090
|
+
if (stream === undefined || stream.socket.readyState !== WebSocket.OPEN) {
|
|
6090
6091
|
pushEvent({
|
|
6091
6092
|
socketId: control.socketId,
|
|
6092
6093
|
type: "error",
|
|
@@ -6097,12 +6098,12 @@ function createForwardWebSocketManager(kandan, topic, allowedPorts) {
|
|
|
6097
6098
|
const body = Buffer.from(control.bodyBase64, "base64");
|
|
6098
6099
|
switch (control.opcode) {
|
|
6099
6100
|
case "text":
|
|
6100
|
-
socket.send(body.toString());
|
|
6101
|
+
stream.socket.send(body.toString());
|
|
6101
6102
|
return;
|
|
6102
6103
|
case "binary":
|
|
6103
6104
|
case "ping":
|
|
6104
6105
|
case "pong":
|
|
6105
|
-
socket.send(body);
|
|
6106
|
+
stream.socket.send(body);
|
|
6106
6107
|
return;
|
|
6107
6108
|
}
|
|
6108
6109
|
}
|
|
@@ -6118,18 +6119,27 @@ function createForwardWebSocketManager(kandan, topic, allowedPorts) {
|
|
|
6118
6119
|
}
|
|
6119
6120
|
};
|
|
6120
6121
|
}
|
|
6121
|
-
function openLocalWebSocket(control, sockets, pushEvent, scheme) {
|
|
6122
|
+
function openLocalWebSocket(control, sockets, pushEvent, socketFactory, scheme) {
|
|
6122
6123
|
let opened = false;
|
|
6123
|
-
const url =
|
|
6124
|
+
const url = localForwardWebSocketUrl(scheme, control.port, control.path, control.queryString);
|
|
6124
6125
|
const protocols = webSocketProtocols(control.headers);
|
|
6125
|
-
const
|
|
6126
|
+
const headers = webSocketHeaders(control.headers);
|
|
6127
|
+
const websocket = socketFactory(url, protocols, headers);
|
|
6126
6128
|
websocket.binaryType = "arraybuffer";
|
|
6127
|
-
sockets.
|
|
6129
|
+
const previousStream = sockets.get(control.socketId);
|
|
6130
|
+
previousStream?.socket.close();
|
|
6131
|
+
sockets.set(control.socketId, { socket: websocket });
|
|
6128
6132
|
websocket.addEventListener("open", () => {
|
|
6133
|
+
if (!currentWebSocket(sockets, control.socketId, websocket)) {
|
|
6134
|
+
return;
|
|
6135
|
+
}
|
|
6129
6136
|
opened = true;
|
|
6130
6137
|
pushEvent({ socketId: control.socketId, type: "open" });
|
|
6131
6138
|
});
|
|
6132
6139
|
websocket.addEventListener("message", (event) => {
|
|
6140
|
+
if (!currentWebSocket(sockets, control.socketId, websocket)) {
|
|
6141
|
+
return;
|
|
6142
|
+
}
|
|
6133
6143
|
const body = typeof event.data === "string" ? Buffer.from(event.data) : Buffer.from(event.data);
|
|
6134
6144
|
pushEvent({
|
|
6135
6145
|
socketId: control.socketId,
|
|
@@ -6139,6 +6149,9 @@ function openLocalWebSocket(control, sockets, pushEvent, scheme) {
|
|
|
6139
6149
|
});
|
|
6140
6150
|
});
|
|
6141
6151
|
websocket.addEventListener("close", (event) => {
|
|
6152
|
+
if (!currentWebSocket(sockets, control.socketId, websocket)) {
|
|
6153
|
+
return;
|
|
6154
|
+
}
|
|
6142
6155
|
sockets.delete(control.socketId);
|
|
6143
6156
|
pushEvent({
|
|
6144
6157
|
socketId: control.socketId,
|
|
@@ -6148,18 +6161,32 @@ function openLocalWebSocket(control, sockets, pushEvent, scheme) {
|
|
|
6148
6161
|
});
|
|
6149
6162
|
});
|
|
6150
6163
|
websocket.addEventListener("error", () => {
|
|
6164
|
+
if (!currentWebSocket(sockets, control.socketId, websocket)) {
|
|
6165
|
+
return;
|
|
6166
|
+
}
|
|
6151
6167
|
sockets.delete(control.socketId);
|
|
6152
6168
|
if (!opened && scheme === "ws") {
|
|
6153
|
-
openLocalWebSocket(control, sockets, pushEvent, "wss");
|
|
6169
|
+
openLocalWebSocket(control, sockets, pushEvent, socketFactory, "wss");
|
|
6154
6170
|
return;
|
|
6155
6171
|
}
|
|
6156
6172
|
pushEvent({
|
|
6157
6173
|
socketId: control.socketId,
|
|
6158
6174
|
type: "error",
|
|
6159
|
-
error: "websocket_error"
|
|
6175
|
+
error: "websocket_error",
|
|
6176
|
+
attemptedScheme: scheme
|
|
6160
6177
|
});
|
|
6161
6178
|
});
|
|
6162
6179
|
}
|
|
6180
|
+
function defaultForwardWebSocketFactory(url, protocols, headers) {
|
|
6181
|
+
if (headers === undefined) {
|
|
6182
|
+
return protocols === undefined ? new WebSocket(url) : new WebSocket(url, protocols);
|
|
6183
|
+
}
|
|
6184
|
+
const options = { headers };
|
|
6185
|
+
return protocols === undefined ? new NodeWebSocket(url, options) : new NodeWebSocket(url, protocols, options);
|
|
6186
|
+
}
|
|
6187
|
+
function currentWebSocket(sockets, socketId, socket) {
|
|
6188
|
+
return sockets.get(socketId)?.socket === socket;
|
|
6189
|
+
}
|
|
6163
6190
|
function webSocketProtocols(headers) {
|
|
6164
6191
|
if (!Array.isArray(headers)) {
|
|
6165
6192
|
return;
|
|
@@ -6172,6 +6199,21 @@ function webSocketProtocols(headers) {
|
|
|
6172
6199
|
});
|
|
6173
6200
|
return protocols.length === 0 ? undefined : protocols;
|
|
6174
6201
|
}
|
|
6202
|
+
function webSocketHeaders(headers) {
|
|
6203
|
+
if (!Array.isArray(headers)) {
|
|
6204
|
+
return;
|
|
6205
|
+
}
|
|
6206
|
+
const forwarded = headers.reduce((acc, header) => {
|
|
6207
|
+
if (isOctWebSocketHeader(header)) {
|
|
6208
|
+
acc[header.name] = header.value;
|
|
6209
|
+
}
|
|
6210
|
+
return acc;
|
|
6211
|
+
}, {});
|
|
6212
|
+
return Object.keys(forwarded).length === 0 ? undefined : forwarded;
|
|
6213
|
+
}
|
|
6214
|
+
function isOctWebSocketHeader(value) {
|
|
6215
|
+
return isHeader(value) && value.name.toLowerCase().startsWith("x-oct-");
|
|
6216
|
+
}
|
|
6175
6217
|
function localForwardUrl(scheme, port, path, queryString) {
|
|
6176
6218
|
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
6177
6219
|
const url = new URL(`${scheme}://127.0.0.1:${port}${normalizedPath}`);
|
|
@@ -6180,6 +6222,12 @@ function localForwardUrl(scheme, port, path, queryString) {
|
|
|
6180
6222
|
}
|
|
6181
6223
|
return url.toString();
|
|
6182
6224
|
}
|
|
6225
|
+
function localForwardWebSocketUrl(scheme, port, path, queryString) {
|
|
6226
|
+
const httpScheme = scheme === "ws" ? "http" : "https";
|
|
6227
|
+
const url = new URL(localForwardUrl(httpScheme, port, path, queryString));
|
|
6228
|
+
url.protocol = `${scheme}:`;
|
|
6229
|
+
return url.toString();
|
|
6230
|
+
}
|
|
6183
6231
|
async function fetchWithHttpsFallback(port, path, queryString, request) {
|
|
6184
6232
|
try {
|
|
6185
6233
|
return await fetch(localForwardUrl("http", port, path, queryString), request);
|
|
@@ -6292,8 +6340,10 @@ var blockedForwardHeaderNames = new Set([
|
|
|
6292
6340
|
"connection",
|
|
6293
6341
|
"content-encoding",
|
|
6294
6342
|
"content-length",
|
|
6343
|
+
"cookie",
|
|
6295
6344
|
"host",
|
|
6296
6345
|
"keep-alive",
|
|
6346
|
+
"authorization",
|
|
6297
6347
|
"proxy-authenticate",
|
|
6298
6348
|
"proxy-authorization",
|
|
6299
6349
|
"te",
|
|
@@ -6305,10 +6355,12 @@ var blockedForwardHeaderNames = new Set([
|
|
|
6305
6355
|
// src/localEditor.ts
|
|
6306
6356
|
import { spawn as spawn2 } from "node:child_process";
|
|
6307
6357
|
import {
|
|
6358
|
+
copyFileSync,
|
|
6308
6359
|
cpSync,
|
|
6309
6360
|
existsSync as existsSync2,
|
|
6310
6361
|
mkdirSync as mkdirSync3,
|
|
6311
6362
|
mkdtempSync,
|
|
6363
|
+
readFileSync as readFileSync2,
|
|
6312
6364
|
realpathSync as realpathSync3,
|
|
6313
6365
|
writeFileSync as writeFileSync2
|
|
6314
6366
|
} from "node:fs";
|
|
@@ -6510,6 +6562,7 @@ function prepareCodeServerProfile(collaboration, editorRuntime) {
|
|
|
6510
6562
|
mkdirSync3(collaborationServerDir, { recursive: true });
|
|
6511
6563
|
mkdirSync3(tempDir, { recursive: true });
|
|
6512
6564
|
if (editorRuntime !== undefined) {
|
|
6565
|
+
ensureCodeServerBrowserExtensionAssets(editorRuntime);
|
|
6513
6566
|
installDirectory(editorRuntime.assets.documentStateExtensionDir, join4(extensionsDir, "kandan.document-state-telemetry"));
|
|
6514
6567
|
}
|
|
6515
6568
|
writeFileSync2(join4(userSettingsDir, "settings.json"), JSON.stringify(codeServerSettings(collaboration), null, 2));
|
|
@@ -6518,6 +6571,68 @@ function prepareCodeServerProfile(collaboration, editorRuntime) {
|
|
|
6518
6571
|
return { ok: false, reason: "code_server_spawn_failed" };
|
|
6519
6572
|
}
|
|
6520
6573
|
}
|
|
6574
|
+
function ensureCodeServerBrowserExtensionAssets(runtime) {
|
|
6575
|
+
const vscodeRoot = codeServerVscodeRoot(runtime);
|
|
6576
|
+
const repairs = [
|
|
6577
|
+
{
|
|
6578
|
+
source: join4(vscodeRoot, "extensions", "git-base", "dist", "extension.js"),
|
|
6579
|
+
target: join4(vscodeRoot, "extensions", "git-base", "dist", "browser", "extension.js"),
|
|
6580
|
+
required: true
|
|
6581
|
+
},
|
|
6582
|
+
{
|
|
6583
|
+
source: join4(vscodeRoot, "extensions", "git-base", "dist", "extension.js.map"),
|
|
6584
|
+
target: join4(vscodeRoot, "extensions", "git-base", "dist", "browser", "extension.js.map"),
|
|
6585
|
+
required: false
|
|
6586
|
+
},
|
|
6587
|
+
{
|
|
6588
|
+
source: join4(vscodeRoot, "extensions", "merge-conflict", "dist", "mergeConflictMain.js"),
|
|
6589
|
+
target: join4(vscodeRoot, "extensions", "merge-conflict", "dist", "browser", "mergeConflictMain.js"),
|
|
6590
|
+
required: true
|
|
6591
|
+
},
|
|
6592
|
+
{
|
|
6593
|
+
source: join4(vscodeRoot, "extensions", "merge-conflict", "dist", "mergeConflictMain.js.map"),
|
|
6594
|
+
target: join4(vscodeRoot, "extensions", "merge-conflict", "dist", "browser", "mergeConflictMain.js.map"),
|
|
6595
|
+
required: false
|
|
6596
|
+
}
|
|
6597
|
+
];
|
|
6598
|
+
repairs.forEach(({ source, target, required }) => {
|
|
6599
|
+
switch (true) {
|
|
6600
|
+
case existsSync2(target):
|
|
6601
|
+
return;
|
|
6602
|
+
case (!required && !existsSync2(source)):
|
|
6603
|
+
return;
|
|
6604
|
+
default:
|
|
6605
|
+
mkdirSync3(dirname2(target), { recursive: true });
|
|
6606
|
+
copyFileSync(source, target);
|
|
6607
|
+
return;
|
|
6608
|
+
}
|
|
6609
|
+
});
|
|
6610
|
+
}
|
|
6611
|
+
function codeServerVscodeRoot(runtime) {
|
|
6612
|
+
const roots = uniquePaths([
|
|
6613
|
+
join4(runtime.root, "lib", "vscode"),
|
|
6614
|
+
join4(dirname2(dirname2(runtime.codeServerBin)), "lib", "vscode"),
|
|
6615
|
+
...wrappedCodeServerBin(runtime.codeServerBin).map((codeServerBin) => join4(dirname2(dirname2(codeServerBin)), "lib", "vscode"))
|
|
6616
|
+
]);
|
|
6617
|
+
const rootWithRequiredAssets = roots.find((root) => codeServerBrowserAssetSources(root).every((source) => existsSync2(source)));
|
|
6618
|
+
return rootWithRequiredAssets ?? roots[0];
|
|
6619
|
+
}
|
|
6620
|
+
function wrappedCodeServerBin(codeServerBin) {
|
|
6621
|
+
try {
|
|
6622
|
+
const script = readFileSync2(codeServerBin, "utf8");
|
|
6623
|
+
const match = script.match(/exec\s+(?:"([^"]+)"|'([^']+)'|([^\s]+))\s+"\$@"/u);
|
|
6624
|
+
const target = match?.[1] ?? match?.[2] ?? match?.[3];
|
|
6625
|
+
return target === undefined || target.trim() === "" ? [] : [target];
|
|
6626
|
+
} catch (_error) {
|
|
6627
|
+
return [];
|
|
6628
|
+
}
|
|
6629
|
+
}
|
|
6630
|
+
function codeServerBrowserAssetSources(vscodeRoot) {
|
|
6631
|
+
return [
|
|
6632
|
+
join4(vscodeRoot, "extensions", "git-base", "dist", "extension.js"),
|
|
6633
|
+
join4(vscodeRoot, "extensions", "merge-conflict", "dist", "mergeConflictMain.js")
|
|
6634
|
+
];
|
|
6635
|
+
}
|
|
6521
6636
|
function prepareCodeServerLaunch(options) {
|
|
6522
6637
|
const platform = options.platform ?? process.platform;
|
|
6523
6638
|
if (platform === "linux") {
|
|
@@ -6650,12 +6765,16 @@ function prepareLocalEditorCollaboration(collaboration, runnerId, serverPort, br
|
|
|
6650
6765
|
}
|
|
6651
6766
|
const targetPath = `/local-codex-runners/${encodeURIComponent(runnerId)}/forwards/${serverPort}/preview-target`;
|
|
6652
6767
|
const serverUrl = new URL(targetPath, `${browserBaseUrl}/`).toString();
|
|
6653
|
-
const
|
|
6768
|
+
const collaborationStatePath = `/api/v2/editor/sessions/${collaboration.editorSessionId}/collaboration-state`;
|
|
6769
|
+
const collaborationBootstrapPath = collaboration.bootstrapToken === undefined || collaboration.bootstrapToken === "" ? undefined : `${targetPath}/_kandan-collaboration/${encodeURIComponent(collaboration.bootstrapToken)}`;
|
|
6770
|
+
const collaborationStateUrl = collaborationBootstrapPath === undefined ? collaborationStatePath : `${collaborationBootstrapPath}${collaborationStatePath}`;
|
|
6771
|
+
const bootstrapServerUrl = collaborationBootstrapPath === undefined ? serverUrl : new URL(collaborationBootstrapPath, `${browserBaseUrl}/`).toString();
|
|
6654
6772
|
return {
|
|
6655
6773
|
...collaboration,
|
|
6656
6774
|
serverPort,
|
|
6657
6775
|
serverUrl,
|
|
6658
|
-
bootstrapServerUrl
|
|
6776
|
+
bootstrapServerUrl,
|
|
6777
|
+
collaborationStateUrl
|
|
6659
6778
|
};
|
|
6660
6779
|
}
|
|
6661
6780
|
function codeServerSettings(collaboration) {
|
|
@@ -6668,6 +6787,7 @@ function codeServerSettings(collaboration) {
|
|
|
6668
6787
|
"oct.joinAcceptMode": "auto",
|
|
6669
6788
|
...collaboration === undefined ? {} : {
|
|
6670
6789
|
"oct.kandanEditorSessionId": collaboration.editorSessionId,
|
|
6790
|
+
"oct.kandanCollaborationStateUrl": collaboration.collaborationStateUrl,
|
|
6671
6791
|
"oct.serverUrl": collaboration.bootstrapServerUrl
|
|
6672
6792
|
},
|
|
6673
6793
|
"security.workspace.trust.enabled": false,
|
|
@@ -6746,6 +6866,7 @@ async function startCollaborationSidecar(collaboration, profile, editorRuntime,
|
|
|
6746
6866
|
serverPort: collaboration.serverPort,
|
|
6747
6867
|
serverUrl: collaboration.serverUrl,
|
|
6748
6868
|
bootstrapServerUrl: collaboration.bootstrapServerUrl,
|
|
6869
|
+
collaborationStateUrl: collaboration.collaborationStateUrl,
|
|
6749
6870
|
process: child,
|
|
6750
6871
|
exited
|
|
6751
6872
|
}
|
|
@@ -6986,7 +7107,7 @@ import {
|
|
|
6986
7107
|
existsSync as existsSync3,
|
|
6987
7108
|
mkdirSync as mkdirSync4,
|
|
6988
7109
|
mkdtempSync as mkdtempSync2,
|
|
6989
|
-
readFileSync as
|
|
7110
|
+
readFileSync as readFileSync3,
|
|
6990
7111
|
renameSync,
|
|
6991
7112
|
rmSync,
|
|
6992
7113
|
writeFileSync as writeFileSync3
|
|
@@ -7474,7 +7595,7 @@ function installedRuntime(cacheRoot, manifest) {
|
|
|
7474
7595
|
return { ok: false };
|
|
7475
7596
|
}
|
|
7476
7597
|
try {
|
|
7477
|
-
const installed = JSON.parse(
|
|
7598
|
+
const installed = JSON.parse(readFileSync3(manifestPath, "utf8"));
|
|
7478
7599
|
if (isJsonObject(installed) && installed.version === manifest.version && installed.platform === manifest.platform && (installed.archiveSha256 === undefined || installed.archiveSha256 === manifest.archiveSha256)) {
|
|
7479
7600
|
return {
|
|
7480
7601
|
ok: true,
|
|
@@ -7705,7 +7826,7 @@ function manifestAssetChecksums(assets) {
|
|
|
7705
7826
|
return checksums;
|
|
7706
7827
|
}
|
|
7707
7828
|
function fileSha256Sync(path) {
|
|
7708
|
-
return createHash2("sha256").update(
|
|
7829
|
+
return createHash2("sha256").update(readFileSync3(path)).digest("hex");
|
|
7709
7830
|
}
|
|
7710
7831
|
function defaultEditorRuntimeCacheRoot() {
|
|
7711
7832
|
return join5(homedir4(), ".linzumi", "editor-runtimes");
|
|
@@ -7884,6 +8005,7 @@ function firstNonBlank(...values) {
|
|
|
7884
8005
|
}
|
|
7885
8006
|
|
|
7886
8007
|
// src/phoenix.ts
|
|
8008
|
+
var defaultPushTimeoutMs = 30000;
|
|
7887
8009
|
function phoenixWebsocketUrl(baseUrl, token) {
|
|
7888
8010
|
const parsed = new URL(baseUrl);
|
|
7889
8011
|
switch (parsed.protocol) {
|
|
@@ -7899,7 +8021,7 @@ function phoenixWebsocketUrl(baseUrl, token) {
|
|
|
7899
8021
|
parsed.searchParams.set("vsn", "2.0.0");
|
|
7900
8022
|
return parsed.toString();
|
|
7901
8023
|
}
|
|
7902
|
-
async function connectPhoenixClient(baseUrl, token, socketFactory = (url) => new WebSocket(url)) {
|
|
8024
|
+
async function connectPhoenixClient(baseUrl, token, socketFactory = (url) => new WebSocket(url), options = {}) {
|
|
7903
8025
|
const pending = new Map;
|
|
7904
8026
|
const joins = new Map;
|
|
7905
8027
|
const controlCallbacks = new Set;
|
|
@@ -7917,9 +8039,13 @@ async function connectPhoenixClient(baseUrl, token, socketFactory = (url) => new
|
|
|
7917
8039
|
rejectReady: undefined,
|
|
7918
8040
|
reconnectTimer: undefined
|
|
7919
8041
|
};
|
|
8042
|
+
const pushTimeoutMs = options.pushTimeoutMs ?? defaultPushTimeoutMs;
|
|
7920
8043
|
const rejectPending = (message) => {
|
|
7921
8044
|
const error = new Error(message);
|
|
7922
|
-
pending.forEach((pendingPush) =>
|
|
8045
|
+
pending.forEach((pendingPush) => {
|
|
8046
|
+
clearTimeout(pendingPush.timer);
|
|
8047
|
+
pendingPush.reject(error);
|
|
8048
|
+
});
|
|
7923
8049
|
pending.clear();
|
|
7924
8050
|
};
|
|
7925
8051
|
const resetReady = () => {
|
|
@@ -7935,6 +8061,7 @@ async function connectPhoenixClient(baseUrl, token, socketFactory = (url) => new
|
|
|
7935
8061
|
const pendingPush = pending.get(ref);
|
|
7936
8062
|
if (pendingPush !== undefined) {
|
|
7937
8063
|
pending.delete(ref);
|
|
8064
|
+
clearTimeout(pendingPush.timer);
|
|
7938
8065
|
if (name === "phx_error") {
|
|
7939
8066
|
pendingPush.reject(new Error("phoenix push failed"));
|
|
7940
8067
|
} else if (isNonOkPushReply(payload) && pendingPush.event !== "phx_join") {
|
|
@@ -7960,7 +8087,12 @@ async function connectPhoenixClient(baseUrl, token, socketFactory = (url) => new
|
|
|
7960
8087
|
state.nextRef += 1;
|
|
7961
8088
|
const frame = [null, ref, topic, event, payload];
|
|
7962
8089
|
return new Promise((resolve5, reject) => {
|
|
7963
|
-
|
|
8090
|
+
const timer = setTimeout(() => {
|
|
8091
|
+
if (pending.delete(ref)) {
|
|
8092
|
+
reject(new Error(`phoenix push timed out after ${pushTimeoutMs}ms: ${event}`));
|
|
8093
|
+
}
|
|
8094
|
+
}, pushTimeoutMs);
|
|
8095
|
+
pending.set(ref, { event, timer, resolve: resolve5, reject });
|
|
7964
8096
|
websocket.send(JSON.stringify(frame));
|
|
7965
8097
|
});
|
|
7966
8098
|
};
|
|
@@ -8035,10 +8167,10 @@ async function connectPhoenixClient(baseUrl, token, socketFactory = (url) => new
|
|
|
8035
8167
|
return pushOnOpenSocket(topic, event, payload);
|
|
8036
8168
|
};
|
|
8037
8169
|
return {
|
|
8038
|
-
join: async (topic, payload,
|
|
8170
|
+
join: async (topic, payload, options2) => {
|
|
8039
8171
|
const reply = await push(topic, "phx_join", payload);
|
|
8040
8172
|
if (isJoinReply(reply)) {
|
|
8041
|
-
joins.set(topic, { payload:
|
|
8173
|
+
joins.set(topic, { payload: options2?.rejoinPayload ?? (() => payload) });
|
|
8042
8174
|
return reply.response;
|
|
8043
8175
|
}
|
|
8044
8176
|
throw new Error(`phoenix join failed: ${joinErrorMessage(reply)}`);
|
|
@@ -8110,7 +8242,7 @@ import {
|
|
|
8110
8242
|
existsSync as existsSync5,
|
|
8111
8243
|
mkdirSync as mkdirSync6,
|
|
8112
8244
|
openSync as openSync2,
|
|
8113
|
-
readFileSync as
|
|
8245
|
+
readFileSync as readFileSync5,
|
|
8114
8246
|
unlinkSync as unlinkSync2,
|
|
8115
8247
|
writeSync
|
|
8116
8248
|
} from "node:fs";
|
|
@@ -8122,27 +8254,38 @@ import {
|
|
|
8122
8254
|
existsSync as existsSync4,
|
|
8123
8255
|
linkSync,
|
|
8124
8256
|
mkdirSync as mkdirSync5,
|
|
8125
|
-
readFileSync as
|
|
8257
|
+
readFileSync as readFileSync4,
|
|
8126
8258
|
realpathSync as realpathSync4,
|
|
8127
8259
|
unlinkSync,
|
|
8128
8260
|
writeFileSync as writeFileSync4
|
|
8129
8261
|
} from "node:fs";
|
|
8130
8262
|
import { homedir as homedir5 } from "node:os";
|
|
8131
8263
|
import { basename as basename4, dirname as dirname4, join as join6, resolve as resolve5 } from "node:path";
|
|
8264
|
+
|
|
8265
|
+
// src/defaultUrls.ts
|
|
8266
|
+
var defaultLinzumiHttpUrl = "https://serve.linzumi.com";
|
|
8267
|
+
var defaultLinzumiWebSocketUrl = "wss://serve.linzumi.com";
|
|
8268
|
+
|
|
8269
|
+
// src/localConfig.ts
|
|
8270
|
+
var prodConfigScope = "prod";
|
|
8132
8271
|
function localConfigPath(env = process.env) {
|
|
8133
8272
|
const override = env.LINZUMI_CONFIG_FILE;
|
|
8134
8273
|
return override !== undefined && override.trim() !== "" ? resolve5(expandUserPath(override)) : resolve5(homedir5(), ".linzumi", "config.json");
|
|
8135
8274
|
}
|
|
8275
|
+
function localConfigScopeKey(linzumiUrl) {
|
|
8276
|
+
const normalizedUrl = kandanHttpBaseUrl(linzumiUrl);
|
|
8277
|
+
const normalizedProdUrl = kandanHttpBaseUrl(defaultLinzumiWebSocketUrl);
|
|
8278
|
+
return normalizedUrl === normalizedProdUrl ? prodConfigScope : normalizedUrl;
|
|
8279
|
+
}
|
|
8280
|
+
function localConfigScopeFileStem(linzumiUrl) {
|
|
8281
|
+
const scopeKey = localConfigScopeKey(linzumiUrl);
|
|
8282
|
+
return scopeKey === prodConfigScope ? prodConfigScope : Buffer.from(scopeKey).toString("base64url");
|
|
8283
|
+
}
|
|
8136
8284
|
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 };
|
|
8285
|
+
return readLocalConfigSection(path);
|
|
8286
|
+
}
|
|
8287
|
+
function readLocalConfigForLinzumiUrl(linzumiUrl, path = localConfigPath()) {
|
|
8288
|
+
return readLocalConfigSection(path, linzumiUrl);
|
|
8146
8289
|
}
|
|
8147
8290
|
function ensureLocalMachineId(path = localConfigPath(), createMachineId = randomUUID2) {
|
|
8148
8291
|
const config = readLocalConfig(path);
|
|
@@ -8158,13 +8301,36 @@ function ensureLocalMachineId(path = localConfigPath(), createMachineId = random
|
|
|
8158
8301
|
writeLocalConfig({ ...latestConfig, machineId }, path);
|
|
8159
8302
|
return machineId;
|
|
8160
8303
|
}
|
|
8161
|
-
function
|
|
8304
|
+
function ensureLocalMachineIdForLinzumiUrl(linzumiUrl, path = localConfigPath(), createMachineId = randomUUID2) {
|
|
8305
|
+
if (localConfigScopeKey(linzumiUrl) === prodConfigScope) {
|
|
8306
|
+
return ensureLocalMachineId(path, createMachineId);
|
|
8307
|
+
}
|
|
8308
|
+
const config = readLocalConfigForLinzumiUrl(linzumiUrl, path);
|
|
8309
|
+
if (config.machineId !== undefined) {
|
|
8310
|
+
return config.machineId;
|
|
8311
|
+
}
|
|
8312
|
+
const machineId = ensureLocalMachineIdSeed(path, createMachineId, linzumiUrl);
|
|
8313
|
+
const latestConfig = readLocalConfigForLinzumiUrl(linzumiUrl, path);
|
|
8314
|
+
const latestMachineId = latestConfig.machineId;
|
|
8315
|
+
if (latestMachineId !== undefined) {
|
|
8316
|
+
return latestMachineId;
|
|
8317
|
+
}
|
|
8318
|
+
writeLocalConfigSection({ ...latestConfig, machineId }, path, linzumiUrl);
|
|
8319
|
+
return machineId;
|
|
8320
|
+
}
|
|
8321
|
+
function localMachineIdSeedPath(configPath = localConfigPath(), linzumiUrl) {
|
|
8322
|
+
if (linzumiUrl !== undefined && localConfigScopeKey(linzumiUrl) !== prodConfigScope) {
|
|
8323
|
+
return join6(dirname4(configPath), `${basename4(configPath)}.${localConfigScopeFileStem(linzumiUrl)}.machine-id`);
|
|
8324
|
+
}
|
|
8162
8325
|
return join6(dirname4(configPath), `${basename4(configPath)}.machine-id`);
|
|
8163
8326
|
}
|
|
8164
|
-
function
|
|
8327
|
+
function readConfiguredAllowedCwdDetailsForLinzumiUrl(linzumiUrl, path = localConfigPath()) {
|
|
8328
|
+
return readConfiguredAllowedCwdDetailsFromConfig(readLocalConfigForLinzumiUrl(linzumiUrl, path));
|
|
8329
|
+
}
|
|
8330
|
+
function readConfiguredAllowedCwdDetailsFromConfig(config) {
|
|
8165
8331
|
const allowedCwds = [];
|
|
8166
8332
|
const missingAllowedCwds = [];
|
|
8167
|
-
for (const cwd of
|
|
8333
|
+
for (const cwd of config.allowedCwds) {
|
|
8168
8334
|
const absolutePath = resolve5(expandUserPath(cwd));
|
|
8169
8335
|
try {
|
|
8170
8336
|
const realPath = realpathSync4(absolutePath);
|
|
@@ -8183,36 +8349,91 @@ function readConfiguredAllowedCwdDetails(path = localConfigPath()) {
|
|
|
8183
8349
|
};
|
|
8184
8350
|
}
|
|
8185
8351
|
function addAllowedCwd(pathValue, path = localConfigPath()) {
|
|
8352
|
+
return addAllowedCwdToConfig(pathValue, path);
|
|
8353
|
+
}
|
|
8354
|
+
function addAllowedCwdForLinzumiUrl(pathValue, linzumiUrl, path = localConfigPath()) {
|
|
8355
|
+
return addAllowedCwdToConfig(pathValue, path, linzumiUrl);
|
|
8356
|
+
}
|
|
8357
|
+
function addAllowedCwdToConfig(pathValue, path, linzumiUrl) {
|
|
8186
8358
|
const normalizedPath = realpathSync4(resolve5(expandUserPath(pathValue)));
|
|
8187
|
-
const config =
|
|
8359
|
+
const config = readLocalConfigSection(path, linzumiUrl);
|
|
8188
8360
|
const allowedCwds = uniqueStrings([...config.allowedCwds, normalizedPath]);
|
|
8189
|
-
|
|
8361
|
+
writeLocalConfigSection({ ...config, version: 1, allowedCwds }, path, linzumiUrl);
|
|
8190
8362
|
return allowedCwds;
|
|
8191
8363
|
}
|
|
8192
8364
|
function removeAllowedCwd(pathValue, path = localConfigPath()) {
|
|
8365
|
+
return removeAllowedCwdFromConfig(pathValue, path);
|
|
8366
|
+
}
|
|
8367
|
+
function removeAllowedCwdForLinzumiUrl(pathValue, linzumiUrl, path = localConfigPath()) {
|
|
8368
|
+
return removeAllowedCwdFromConfig(pathValue, path, linzumiUrl);
|
|
8369
|
+
}
|
|
8370
|
+
function removeAllowedCwdFromConfig(pathValue, path, linzumiUrl) {
|
|
8193
8371
|
const requestedPath = resolve5(expandUserPath(pathValue));
|
|
8194
8372
|
const normalizedRequest = realpathOrResolved(requestedPath);
|
|
8195
|
-
const config =
|
|
8373
|
+
const config = readLocalConfigSection(path, linzumiUrl);
|
|
8196
8374
|
const allowedCwds = config.allowedCwds.filter((cwd) => {
|
|
8197
8375
|
const normalizedExisting = realpathOrResolved(cwd);
|
|
8198
8376
|
return cwd !== pathValue && normalizedExisting !== normalizedRequest;
|
|
8199
8377
|
});
|
|
8200
|
-
|
|
8378
|
+
writeLocalConfigSection({ ...config, version: 1, allowedCwds }, path, linzumiUrl);
|
|
8201
8379
|
return allowedCwds;
|
|
8202
8380
|
}
|
|
8203
8381
|
function writeLocalConfig(config, path = localConfigPath()) {
|
|
8382
|
+
writeLocalConfigSection(config, path);
|
|
8383
|
+
}
|
|
8384
|
+
function readLocalConfigFile(path) {
|
|
8385
|
+
if (!existsSync4(path)) {
|
|
8386
|
+
return { version: 1, allowedCwds: [] };
|
|
8387
|
+
}
|
|
8388
|
+
const parsed = JSON.parse(readFileSync4(path, "utf8"));
|
|
8389
|
+
if (!isConfigPayload(parsed)) {
|
|
8390
|
+
throw new Error(`invalid Linzumi config: ${path}`);
|
|
8391
|
+
}
|
|
8392
|
+
return parsed;
|
|
8393
|
+
}
|
|
8394
|
+
function readLocalConfigSection(path, linzumiUrl) {
|
|
8395
|
+
const parsed = readLocalConfigFile(path);
|
|
8396
|
+
const scopeKey = linzumiUrl === undefined ? prodConfigScope : localConfigScopeKey(linzumiUrl);
|
|
8397
|
+
const section = scopeKey === prodConfigScope ? parsed : parsed[scopeKey] ?? emptySection();
|
|
8398
|
+
if (!isConfigSection(section)) {
|
|
8399
|
+
throw new Error(`invalid Linzumi config section ${scopeKey}: ${path}`);
|
|
8400
|
+
}
|
|
8401
|
+
const allowedCwds = uniqueStrings(section.allowedCwds);
|
|
8402
|
+
return section.machineId === undefined ? { version: 1, allowedCwds } : { version: 1, machineId: section.machineId, allowedCwds };
|
|
8403
|
+
}
|
|
8404
|
+
function writeLocalConfigSection(config, path, linzumiUrl) {
|
|
8405
|
+
const scopeKey = linzumiUrl === undefined ? prodConfigScope : localConfigScopeKey(linzumiUrl);
|
|
8406
|
+
const nextSection = normalizedConfigSection(config);
|
|
8407
|
+
const next = scopeKey === prodConfigScope ? { ...readLocalConfigFile(path), ...nextSection, version: 1 } : {
|
|
8408
|
+
...readLocalConfigFile(path),
|
|
8409
|
+
version: 1,
|
|
8410
|
+
[scopeKey]: nextSection
|
|
8411
|
+
};
|
|
8204
8412
|
mkdirSync5(dirname4(path), { recursive: true });
|
|
8205
|
-
writeFileSync4(path, `${JSON.stringify(
|
|
8413
|
+
writeFileSync4(path, `${JSON.stringify(next, null, 2)}
|
|
8206
8414
|
`, "utf8");
|
|
8207
8415
|
}
|
|
8208
8416
|
function isConfigPayload(value) {
|
|
8209
|
-
return typeof value === "object" && value !== null && value.version === 1 &&
|
|
8417
|
+
return typeof value === "object" && value !== null && value.version === 1 && isConfigSection(value);
|
|
8418
|
+
}
|
|
8419
|
+
function isConfigSection(value) {
|
|
8420
|
+
return typeof value === "object" && value !== null && Array.isArray(value.allowedCwds) && machineIdValid(value.machineId) && value.allowedCwds.every((cwd) => typeof cwd === "string" && cwd.trim() !== "");
|
|
8421
|
+
}
|
|
8422
|
+
function normalizedConfigSection(config) {
|
|
8423
|
+
if (!isConfigPayload(config)) {
|
|
8424
|
+
throw new Error("invalid Linzumi config");
|
|
8425
|
+
}
|
|
8426
|
+
const allowedCwds = uniqueStrings(config.allowedCwds);
|
|
8427
|
+
return config.machineId === undefined ? { allowedCwds } : { machineId: config.machineId, allowedCwds };
|
|
8428
|
+
}
|
|
8429
|
+
function emptySection() {
|
|
8430
|
+
return { allowedCwds: [] };
|
|
8210
8431
|
}
|
|
8211
8432
|
function machineIdValid(value) {
|
|
8212
8433
|
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
8434
|
}
|
|
8214
|
-
function ensureLocalMachineIdSeed(configPath, createMachineId) {
|
|
8215
|
-
const seedPath = localMachineIdSeedPath(configPath);
|
|
8435
|
+
function ensureLocalMachineIdSeed(configPath, createMachineId, linzumiUrl) {
|
|
8436
|
+
const seedPath = localMachineIdSeedPath(configPath, linzumiUrl);
|
|
8216
8437
|
if (existsSync4(seedPath)) {
|
|
8217
8438
|
return readMachineIdSeed(seedPath);
|
|
8218
8439
|
}
|
|
@@ -8237,7 +8458,7 @@ function ensureLocalMachineIdSeed(configPath, createMachineId) {
|
|
|
8237
8458
|
}
|
|
8238
8459
|
}
|
|
8239
8460
|
function readMachineIdSeed(seedPath) {
|
|
8240
|
-
const machineId =
|
|
8461
|
+
const machineId = readFileSync4(seedPath, "utf8").trim();
|
|
8241
8462
|
if (!machineIdValid(machineId)) {
|
|
8242
8463
|
throw new Error(`invalid Linzumi machine id seed: ${seedPath}`);
|
|
8243
8464
|
}
|
|
@@ -8263,15 +8484,16 @@ function realpathOrResolved(pathValue) {
|
|
|
8263
8484
|
}
|
|
8264
8485
|
|
|
8265
8486
|
// src/version.ts
|
|
8266
|
-
var linzumiCliVersion = "0.0.
|
|
8487
|
+
var linzumiCliVersion = "0.0.45-beta";
|
|
8267
8488
|
var linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
|
|
8268
8489
|
|
|
8269
8490
|
// src/runnerLock.ts
|
|
8270
|
-
function runnerLockPath(machineId, configPath = localConfigPath()) {
|
|
8271
|
-
|
|
8491
|
+
function runnerLockPath(machineId, configPath = localConfigPath(), linzumiUrl) {
|
|
8492
|
+
const lockName = linzumiUrl === undefined ? encodeURIComponent(machineId) : localConfigScopeFileStem(linzumiUrl);
|
|
8493
|
+
return join7(dirname5(configPath), "runners", `${lockName}.lock`);
|
|
8272
8494
|
}
|
|
8273
8495
|
function acquireRunnerLock(options) {
|
|
8274
|
-
const path = runnerLockPath(options.machineId, options.configPath);
|
|
8496
|
+
const path = runnerLockPath(options.machineId, options.configPath, options.linzumiUrl);
|
|
8275
8497
|
const isPidAlive = options.isPidAlive ?? processIsAlive;
|
|
8276
8498
|
const record = {
|
|
8277
8499
|
version: 1,
|
|
@@ -8280,9 +8502,11 @@ function acquireRunnerLock(options) {
|
|
|
8280
8502
|
pid: options.pid ?? process.pid,
|
|
8281
8503
|
cwd: options.cwd,
|
|
8282
8504
|
workspace: options.workspace,
|
|
8505
|
+
...options.linzumiUrl === undefined ? {} : { linzumiUrl: kandanHttpBaseUrl(options.linzumiUrl) },
|
|
8283
8506
|
startedAt: (options.now ?? (() => new Date))().toISOString(),
|
|
8284
8507
|
cliVersion: options.cliVersion ?? linzumiCliVersion
|
|
8285
8508
|
};
|
|
8509
|
+
rejectLiveLegacyProductionRunnerLock(options.machineId, options.configPath, options.linzumiUrl, isPidAlive);
|
|
8286
8510
|
writeLockOrHandleExisting(path, record, isPidAlive, options.beforeReadExistingLock, options.beforeReplaceStaleLock);
|
|
8287
8511
|
return {
|
|
8288
8512
|
path,
|
|
@@ -8290,6 +8514,28 @@ function acquireRunnerLock(options) {
|
|
|
8290
8514
|
release: () => releaseRunnerLock(path, record)
|
|
8291
8515
|
};
|
|
8292
8516
|
}
|
|
8517
|
+
function rejectLiveLegacyProductionRunnerLock(machineId, configPath, linzumiUrl, isPidAlive) {
|
|
8518
|
+
if (linzumiUrl === undefined || localConfigScopeKey(linzumiUrl) !== localConfigScopeKey(defaultLinzumiHttpUrl)) {
|
|
8519
|
+
return;
|
|
8520
|
+
}
|
|
8521
|
+
const legacyPath = runnerLockPath(machineId, configPath);
|
|
8522
|
+
const existing = readRunnerLockIfPresent(legacyPath);
|
|
8523
|
+
if (existing === undefined) {
|
|
8524
|
+
return;
|
|
8525
|
+
}
|
|
8526
|
+
if (isPidAlive(existing.pid)) {
|
|
8527
|
+
throw new Error(activeRunnerLockMessage(legacyPath, existing));
|
|
8528
|
+
}
|
|
8529
|
+
withStaleReplacementLock(legacyPath, isPidAlive, () => {
|
|
8530
|
+
const latest = existsSync5(legacyPath) ? readRunnerLock(legacyPath) : undefined;
|
|
8531
|
+
if (latest !== undefined && isPidAlive(latest.pid)) {
|
|
8532
|
+
throw new Error(activeRunnerLockMessage(legacyPath, latest));
|
|
8533
|
+
}
|
|
8534
|
+
if (latest !== undefined) {
|
|
8535
|
+
unlinkSync2(legacyPath);
|
|
8536
|
+
}
|
|
8537
|
+
});
|
|
8538
|
+
}
|
|
8293
8539
|
function writeLockOrHandleExisting(path, record, isPidAlive, beforeReadExistingLock, beforeReplaceStaleLock) {
|
|
8294
8540
|
if (tryCreateLock(path, record)) {
|
|
8295
8541
|
return;
|
|
@@ -8375,7 +8621,7 @@ function withStaleReplacementLock(path, isPidAlive, callback) {
|
|
|
8375
8621
|
function readReplacementLockPidIfPresent(path) {
|
|
8376
8622
|
let value;
|
|
8377
8623
|
try {
|
|
8378
|
-
value =
|
|
8624
|
+
value = readFileSync5(path, "utf8").trim();
|
|
8379
8625
|
} catch (error) {
|
|
8380
8626
|
if (isNodeErrorCode2(error, "ENOENT")) {
|
|
8381
8627
|
return;
|
|
@@ -8415,14 +8661,17 @@ function readRunnerLockIfPresent(path) {
|
|
|
8415
8661
|
}
|
|
8416
8662
|
}
|
|
8417
8663
|
function readRunnerLock(path) {
|
|
8418
|
-
const parsed = JSON.parse(
|
|
8664
|
+
const parsed = JSON.parse(readFileSync5(path, "utf8"));
|
|
8419
8665
|
if (!isRunnerLockRecord(parsed)) {
|
|
8420
8666
|
throw new Error(`invalid Linzumi runner lock: ${path}`);
|
|
8421
8667
|
}
|
|
8422
8668
|
return parsed;
|
|
8423
8669
|
}
|
|
8424
8670
|
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() !== "";
|
|
8671
|
+
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() !== "";
|
|
8672
|
+
}
|
|
8673
|
+
function linzumiUrlValid(value) {
|
|
8674
|
+
return value === undefined || typeof value === "string" && value.trim() !== "";
|
|
8426
8675
|
}
|
|
8427
8676
|
function workspaceValid(value) {
|
|
8428
8677
|
return value === null || typeof value === "string" && value.trim() !== "";
|
|
@@ -8437,8 +8686,10 @@ function processIsAlive(pid) {
|
|
|
8437
8686
|
}
|
|
8438
8687
|
function activeRunnerLockMessage(path, record) {
|
|
8439
8688
|
const workspace = record.workspace === null ? "workspace: unknown" : `workspace: ${record.workspace}`;
|
|
8689
|
+
const linzumiUrl = record.linzumiUrl === undefined ? undefined : `linzumi url: ${displayLinzumiUrl(record.linzumiUrl)}`;
|
|
8440
8690
|
return [
|
|
8441
|
-
"another Linzumi runner is already running for this machine",
|
|
8691
|
+
record.linzumiUrl === undefined ? "another Linzumi runner is already running for this machine" : "another Linzumi runner is already running for this Linzumi URL",
|
|
8692
|
+
...linzumiUrl === undefined ? [] : [linzumiUrl],
|
|
8442
8693
|
`runner id: ${record.runnerId}`,
|
|
8443
8694
|
`pid: ${record.pid}`,
|
|
8444
8695
|
`cwd: ${record.cwd}`,
|
|
@@ -8450,6 +8701,12 @@ function activeRunnerLockMessage(path, record) {
|
|
|
8450
8701
|
].join(`
|
|
8451
8702
|
`);
|
|
8452
8703
|
}
|
|
8704
|
+
function displayLinzumiUrl(linzumiUrl) {
|
|
8705
|
+
if (linzumiUrl === localConfigScopeKey(defaultLinzumiHttpUrl)) {
|
|
8706
|
+
return defaultLinzumiHttpUrl;
|
|
8707
|
+
}
|
|
8708
|
+
return localConfigScopeKey(linzumiUrl) === localConfigScopeKey(defaultLinzumiHttpUrl) ? defaultLinzumiHttpUrl : linzumiUrl;
|
|
8709
|
+
}
|
|
8453
8710
|
function isNodeErrorCode2(error, code) {
|
|
8454
8711
|
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
8455
8712
|
}
|
|
@@ -8611,6 +8868,7 @@ async function runLocalCodexRunner(options) {
|
|
|
8611
8868
|
runnerId: options.runnerId,
|
|
8612
8869
|
cwd: options.cwd,
|
|
8613
8870
|
workspace: runnerWorkspaceSlug(options) ?? null,
|
|
8871
|
+
linzumiUrl: options.kandanUrl,
|
|
8614
8872
|
configPath: options.runnerLockConfigPath
|
|
8615
8873
|
});
|
|
8616
8874
|
cleanup.actions.push(() => runnerLock.release());
|
|
@@ -10005,7 +10263,7 @@ function allowedCwdSuggestions(cwd, allowedCwds) {
|
|
|
10005
10263
|
}
|
|
10006
10264
|
|
|
10007
10265
|
// src/authCache.ts
|
|
10008
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync7, readFileSync as
|
|
10266
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
|
|
10009
10267
|
import { homedir as homedir6 } from "node:os";
|
|
10010
10268
|
import { dirname as dirname6, join as join9 } from "node:path";
|
|
10011
10269
|
function defaultAuthFilePath() {
|
|
@@ -10016,7 +10274,7 @@ function readCachedLocalRunnerToken(kandanUrl, authFilePath = defaultAuthFilePat
|
|
|
10016
10274
|
if (!existsSync6(authFilePath)) {
|
|
10017
10275
|
return;
|
|
10018
10276
|
}
|
|
10019
|
-
const authFile = parseAuthFile(
|
|
10277
|
+
const authFile = parseAuthFile(readFileSync6(authFilePath, "utf8"));
|
|
10020
10278
|
const kandanBaseUrl = kandanHttpBaseUrl(kandanUrl);
|
|
10021
10279
|
const entry = authFile.local_codex_runner?.[kandanBaseUrl];
|
|
10022
10280
|
if (entry === undefined || entry.access_token.trim() === "") {
|
|
@@ -10034,7 +10292,7 @@ function readCachedLocalRunnerToken(kandanUrl, authFilePath = defaultAuthFilePat
|
|
|
10034
10292
|
}
|
|
10035
10293
|
function writeCachedLocalRunnerToken(args) {
|
|
10036
10294
|
const authFilePath = args.authFilePath ?? defaultAuthFilePath();
|
|
10037
|
-
const existing = existsSync6(authFilePath) ? parseAuthFile(
|
|
10295
|
+
const existing = existsSync6(authFilePath) ? parseAuthFile(readFileSync6(authFilePath, "utf8")) : { version: 1 };
|
|
10038
10296
|
const kandanBaseUrl = kandanHttpBaseUrl(args.kandanUrl);
|
|
10039
10297
|
const issuedAt = new Date;
|
|
10040
10298
|
const expiresAt = args.expiresInSeconds === undefined ? undefined : new Date(issuedAt.getTime() + args.expiresInSeconds * 1000).toISOString();
|
|
@@ -10143,12 +10401,8 @@ async function acquireAndCacheToken(args) {
|
|
|
10143
10401
|
return token.accessToken;
|
|
10144
10402
|
}
|
|
10145
10403
|
|
|
10146
|
-
// src/defaultUrls.ts
|
|
10147
|
-
var defaultLinzumiHttpUrl = "https://serve.linzumi.com";
|
|
10148
|
-
var defaultLinzumiWebSocketUrl = "wss://serve.linzumi.com";
|
|
10149
|
-
|
|
10150
10404
|
// src/kandanTls.ts
|
|
10151
|
-
import { existsSync as existsSync7, readFileSync as
|
|
10405
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
|
|
10152
10406
|
import { Agent } from "undici";
|
|
10153
10407
|
import { WebSocket as WsWebSocket } from "ws";
|
|
10154
10408
|
function kandanTlsTrustFromEnv() {
|
|
@@ -10162,7 +10416,7 @@ function kandanTlsTrustFromCaFile(caFile) {
|
|
|
10162
10416
|
if (!existsSync7(trimmed)) {
|
|
10163
10417
|
throw new Error(`KANDAN_TLS_CA_FILE does not exist: ${trimmed}`);
|
|
10164
10418
|
}
|
|
10165
|
-
const ca =
|
|
10419
|
+
const ca = readFileSync7(trimmed, "utf8");
|
|
10166
10420
|
return {
|
|
10167
10421
|
caFile: trimmed,
|
|
10168
10422
|
ca,
|
|
@@ -10191,7 +10445,7 @@ function trustedWebSocketFactory(trust, WebSocketImpl = WsWebSocket) {
|
|
|
10191
10445
|
}
|
|
10192
10446
|
|
|
10193
10447
|
// src/agentBootstrap.ts
|
|
10194
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as
|
|
10448
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
|
|
10195
10449
|
import { dirname as dirname7, join as join10 } from "node:path";
|
|
10196
10450
|
import { homedir as homedir7 } from "node:os";
|
|
10197
10451
|
async function runAgentCliCommand(args, deps = {
|
|
@@ -10801,7 +11055,7 @@ function authorizationHeaders(token) {
|
|
|
10801
11055
|
return { authorization: `Bearer ${token}` };
|
|
10802
11056
|
}
|
|
10803
11057
|
function readOptionalTextFile(path) {
|
|
10804
|
-
return existsSync8(path) ?
|
|
11058
|
+
return existsSync8(path) ? readFileSync8(path, "utf8") : undefined;
|
|
10805
11059
|
}
|
|
10806
11060
|
function writeTextFile(path, content) {
|
|
10807
11061
|
mkdirSync8(dirname7(path), { recursive: true });
|
|
@@ -10881,7 +11135,7 @@ Launch target:
|
|
|
10881
11135
|
}
|
|
10882
11136
|
|
|
10883
11137
|
// src/helloLinzumiProject.ts
|
|
10884
|
-
import { existsSync as existsSync9, mkdirSync as mkdirSync9, readFileSync as
|
|
11138
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync9, readFileSync as readFileSync9, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
|
|
10885
11139
|
import { dirname as dirname8, join as join11, resolve as resolve7 } from "node:path";
|
|
10886
11140
|
import { fileURLToPath } from "node:url";
|
|
10887
11141
|
var defaultHelloLinzumiProjectDir = "/tmp/hello_linzumi";
|
|
@@ -10891,7 +11145,7 @@ var defaultHelloLinzumiPort = 8787;
|
|
|
10891
11145
|
var defaultHelloLinzumiHost = "0.0.0.0";
|
|
10892
11146
|
var markerFile = ".linzumi-demo-project";
|
|
10893
11147
|
var moduleDir = dirname8(fileURLToPath(import.meta.url));
|
|
10894
|
-
var linzumiLogoSvg =
|
|
11148
|
+
var linzumiLogoSvg = readFileSync9(join11(moduleDir, "assets", "linzumi-logo.svg"), "utf8");
|
|
10895
11149
|
function createHelloLinzumiProject(input = {}) {
|
|
10896
11150
|
const options = typeof input === "string" ? { rootPath: input } : input;
|
|
10897
11151
|
const root = resolveHelloProjectRoot(options);
|
|
@@ -10946,7 +11200,7 @@ function assertWritableDemoRoot(root, reset) {
|
|
|
10946
11200
|
return;
|
|
10947
11201
|
}
|
|
10948
11202
|
const markerPath = join11(root, markerFile);
|
|
10949
|
-
const isDemoRoot = existsSync9(markerPath) &&
|
|
11203
|
+
const isDemoRoot = existsSync9(markerPath) && readFileSync9(markerPath, "utf8").trim() === "hello-linzumi";
|
|
10950
11204
|
if (isDemoRoot && reset) {
|
|
10951
11205
|
rmSync2(root, { recursive: true, force: true });
|
|
10952
11206
|
return;
|
|
@@ -11449,7 +11703,7 @@ import {
|
|
|
11449
11703
|
closeSync as closeSync2,
|
|
11450
11704
|
mkdirSync as mkdirSync10,
|
|
11451
11705
|
openSync as openSync3,
|
|
11452
|
-
readFileSync as
|
|
11706
|
+
readFileSync as readFileSync10,
|
|
11453
11707
|
watch,
|
|
11454
11708
|
writeFileSync as writeFileSync8
|
|
11455
11709
|
} from "node:fs";
|
|
@@ -11534,12 +11788,12 @@ function commanderDaemonStatus(runnerId, statusDir = commanderStatusDir(), proce
|
|
|
11534
11788
|
if (!existsSync10(statusFile)) {
|
|
11535
11789
|
return { status: "missing", runnerId, statusFile };
|
|
11536
11790
|
}
|
|
11537
|
-
const record = parseRecord(
|
|
11791
|
+
const record = parseRecord(readFileSync10(statusFile, "utf8"));
|
|
11538
11792
|
return processIsRunning(record.pid) && processMatchesRecord(record, processIdentityReader) ? { status: "running", record } : { status: "stopped", record };
|
|
11539
11793
|
}
|
|
11540
11794
|
async function waitForCommanderDaemon(options) {
|
|
11541
11795
|
const now = options.now ?? (() => Date.now());
|
|
11542
|
-
const readTextFile = options.readTextFile ?? ((path) => existsSync10(path) ?
|
|
11796
|
+
const readTextFile = options.readTextFile ?? ((path) => existsSync10(path) ? readFileSync10(path, "utf8") : undefined);
|
|
11543
11797
|
const statusImpl = options.statusImpl ?? commanderDaemonStatus;
|
|
11544
11798
|
const deadline = now() + options.timeoutMs;
|
|
11545
11799
|
while (now() <= deadline) {
|
|
@@ -11794,7 +12048,7 @@ async function main(args) {
|
|
|
11794
12048
|
}
|
|
11795
12049
|
case "start": {
|
|
11796
12050
|
const options = await parseStartRunnerArgs(parsed.args);
|
|
11797
|
-
|
|
12051
|
+
addAllowedCwdForLinzumiUrl(options.cwd, options.kandanUrl);
|
|
11798
12052
|
await runLocalCodexRunner(withLocalMachineId(options));
|
|
11799
12053
|
return;
|
|
11800
12054
|
}
|
|
@@ -11897,19 +12151,16 @@ function runHelloCommand(args) {
|
|
|
11897
12151
|
`);
|
|
11898
12152
|
}
|
|
11899
12153
|
function runPathsCommand(args) {
|
|
11900
|
-
const
|
|
11901
|
-
if (
|
|
12154
|
+
const { subcommand, pathValue, linzumiUrl, help } = parsePathsCommandArgs(args);
|
|
12155
|
+
if (help || subcommand === undefined || subcommand === "help") {
|
|
11902
12156
|
process.stdout.write(pathsHelpText());
|
|
11903
12157
|
return;
|
|
11904
12158
|
}
|
|
11905
|
-
if (rest.length > 0) {
|
|
11906
|
-
throw new Error("linzumi paths accepts one path argument");
|
|
11907
|
-
}
|
|
11908
12159
|
switch (subcommand) {
|
|
11909
12160
|
case "list": {
|
|
11910
|
-
const config = readLocalConfig();
|
|
12161
|
+
const config = linzumiUrl === undefined ? readLocalConfig() : readLocalConfigForLinzumiUrl(linzumiUrl);
|
|
11911
12162
|
if (config.allowedCwds.length === 0) {
|
|
11912
|
-
process.stdout.write(`No trusted paths configured in ${localConfigPath()}
|
|
12163
|
+
process.stdout.write(`No trusted paths configured in ${localConfigPath()}${pathsScopeSuffix(linzumiUrl)}
|
|
11913
12164
|
`);
|
|
11914
12165
|
return;
|
|
11915
12166
|
}
|
|
@@ -11923,7 +12174,11 @@ function runPathsCommand(args) {
|
|
|
11923
12174
|
throw new Error("missing path for linzumi paths add");
|
|
11924
12175
|
}
|
|
11925
12176
|
const trustedPath = realpathSync6(resolve9(expandUserPath(pathValue)));
|
|
11926
|
-
|
|
12177
|
+
if (linzumiUrl === undefined) {
|
|
12178
|
+
addAllowedCwd(pathValue);
|
|
12179
|
+
} else {
|
|
12180
|
+
addAllowedCwdForLinzumiUrl(pathValue, linzumiUrl);
|
|
12181
|
+
}
|
|
11927
12182
|
process.stdout.write(`Trusted ${trustedPath}
|
|
11928
12183
|
`);
|
|
11929
12184
|
return;
|
|
@@ -11932,7 +12187,11 @@ function runPathsCommand(args) {
|
|
|
11932
12187
|
if (pathValue === undefined || pathValue.trim() === "") {
|
|
11933
12188
|
throw new Error("missing path for linzumi paths remove");
|
|
11934
12189
|
}
|
|
11935
|
-
|
|
12190
|
+
if (linzumiUrl === undefined) {
|
|
12191
|
+
removeAllowedCwd(pathValue);
|
|
12192
|
+
} else {
|
|
12193
|
+
removeAllowedCwdForLinzumiUrl(pathValue, linzumiUrl);
|
|
12194
|
+
}
|
|
11936
12195
|
process.stdout.write(`Removed trusted path ${pathValue}
|
|
11937
12196
|
`);
|
|
11938
12197
|
return;
|
|
@@ -11941,6 +12200,46 @@ function runPathsCommand(args) {
|
|
|
11941
12200
|
throw new Error(`invalid paths command: ${subcommand}`);
|
|
11942
12201
|
}
|
|
11943
12202
|
}
|
|
12203
|
+
function parsePathsCommandArgs(args) {
|
|
12204
|
+
const positional = [];
|
|
12205
|
+
let linzumiUrl;
|
|
12206
|
+
let help = false;
|
|
12207
|
+
for (let index = 0;index < args.length; index += 1) {
|
|
12208
|
+
const arg = args[index];
|
|
12209
|
+
switch (arg) {
|
|
12210
|
+
case "--help":
|
|
12211
|
+
help = true;
|
|
12212
|
+
break;
|
|
12213
|
+
case "--linzumi-url":
|
|
12214
|
+
case "--kandan-url": {
|
|
12215
|
+
const value = args[index + 1];
|
|
12216
|
+
if (value === undefined || value.startsWith("--")) {
|
|
12217
|
+
throw new Error(`missing value for ${arg}`);
|
|
12218
|
+
}
|
|
12219
|
+
linzumiUrl = value;
|
|
12220
|
+
index += 1;
|
|
12221
|
+
break;
|
|
12222
|
+
}
|
|
12223
|
+
default:
|
|
12224
|
+
if (arg !== undefined && arg.startsWith("--")) {
|
|
12225
|
+
throw new Error(`invalid flag: ${arg}`);
|
|
12226
|
+
}
|
|
12227
|
+
positional.push(arg ?? "");
|
|
12228
|
+
}
|
|
12229
|
+
}
|
|
12230
|
+
if (positional.length > 2) {
|
|
12231
|
+
throw new Error("linzumi paths accepts one path argument");
|
|
12232
|
+
}
|
|
12233
|
+
return {
|
|
12234
|
+
subcommand: positional[0],
|
|
12235
|
+
pathValue: positional[1],
|
|
12236
|
+
linzumiUrl,
|
|
12237
|
+
help
|
|
12238
|
+
};
|
|
12239
|
+
}
|
|
12240
|
+
function pathsScopeSuffix(linzumiUrl) {
|
|
12241
|
+
return linzumiUrl === undefined ? "" : ` for ${linzumiUrl}`;
|
|
12242
|
+
}
|
|
11944
12243
|
async function runCommanderDaemonCommand(args) {
|
|
11945
12244
|
const [subcommand, ...rest] = args;
|
|
11946
12245
|
switch (subcommand) {
|
|
@@ -12172,7 +12471,7 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
12172
12471
|
const kandanUrl = stringValue3(values, "linzumi-url") ?? agentApiUrlToKandanUrl(tokenFile.apiUrl);
|
|
12173
12472
|
const requestedCwdValue = cwdArg ?? stringValue3(values, "cwd");
|
|
12174
12473
|
const requestedCwd = resolveUserPath(requestedCwdValue ?? process.cwd());
|
|
12175
|
-
const configuredAllowedCwds2 = requestedCwdValue === undefined && !values.has("allowed-cwd") ?
|
|
12474
|
+
const configuredAllowedCwds2 = requestedCwdValue === undefined && !values.has("allowed-cwd") ? readConfiguredAllowedCwdDetailsForLinzumiUrl(kandanUrl) : { allowedCwds: [], missingAllowedCwds: [] };
|
|
12176
12475
|
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
12476
|
const cwd = allowedCwds[0] ?? requestedCwd;
|
|
12178
12477
|
const codexBin = stringValue3(values, "codex-bin") ?? "codex";
|
|
@@ -12219,7 +12518,7 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
12219
12518
|
};
|
|
12220
12519
|
}
|
|
12221
12520
|
function readAgentTokenTextFile(path) {
|
|
12222
|
-
return existsSync11(path) ?
|
|
12521
|
+
return existsSync11(path) ? readFileSync11(path, "utf8") : undefined;
|
|
12223
12522
|
}
|
|
12224
12523
|
function rejectAgentRunnerTargetingFlags(values) {
|
|
12225
12524
|
const unsupportedFlags = [
|
|
@@ -12303,7 +12602,7 @@ async function parseRunnerArgs(args, deps = {
|
|
|
12303
12602
|
const kandanUrl = stringValue3(values, "linzumi-url") ?? defaultLinzumiWebSocketUrl;
|
|
12304
12603
|
const cwd = stringValue3(values, "cwd") ?? process.cwd();
|
|
12305
12604
|
const cwdAllowedCwds = assertConfiguredAllowedCwds([cwd]);
|
|
12306
|
-
const localConfiguredAllowedCwds = values.has("allowed-cwd") ? { allowedCwds: [], missingAllowedCwds: [] } :
|
|
12605
|
+
const localConfiguredAllowedCwds = values.has("allowed-cwd") ? { allowedCwds: [], missingAllowedCwds: [] } : readConfiguredAllowedCwdDetailsForLinzumiUrl(kandanUrl);
|
|
12307
12606
|
const configuredAllowedCwds2 = values.has("allowed-cwd") ? assertConfiguredAllowedCwds(parseAllowedCwdList(stringValue3(values, "allowed-cwd"))) : [...localConfiguredAllowedCwds.allowedCwds];
|
|
12308
12607
|
const codexBin = stringValue3(values, "codex-bin") ?? "codex";
|
|
12309
12608
|
const customCodeServerBin = stringValue3(values, "code-server-bin");
|
|
@@ -12516,7 +12815,7 @@ function parseChannelPath(channel) {
|
|
|
12516
12815
|
function withLocalMachineId(options) {
|
|
12517
12816
|
return {
|
|
12518
12817
|
...options,
|
|
12519
|
-
machineId: ensureLocalMachineId()
|
|
12818
|
+
machineId: localConfigScopeKey(options.kandanUrl) === localConfigScopeKey(defaultLinzumiWebSocketUrl) ? ensureLocalMachineId() : ensureLocalMachineIdForLinzumiUrl(options.kandanUrl)
|
|
12520
12819
|
};
|
|
12521
12820
|
}
|
|
12522
12821
|
function required(values, key) {
|
|
@@ -12698,13 +12997,13 @@ function pathsHelpText() {
|
|
|
12698
12997
|
return `Linzumi trusted paths
|
|
12699
12998
|
|
|
12700
12999
|
Usage:
|
|
12701
|
-
linzumi paths list
|
|
12702
|
-
linzumi paths add <path>
|
|
12703
|
-
linzumi paths remove <path>
|
|
13000
|
+
linzumi paths [--linzumi-url <ws-url>] list
|
|
13001
|
+
linzumi paths [--linzumi-url <ws-url>] add <path>
|
|
13002
|
+
linzumi paths [--linzumi-url <ws-url>] remove <path>
|
|
12704
13003
|
|
|
12705
|
-
Trusted paths are stored in ~/.linzumi/config.json.
|
|
12706
|
-
|
|
12707
|
-
|
|
13004
|
+
Trusted paths are stored in ~/.linzumi/config.json. Production/default paths
|
|
13005
|
+
use the root config fields; explicit --linzumi-url paths use a URL-scoped config
|
|
13006
|
+
section so local, staging, and production runners do not share trust state.
|
|
12708
13007
|
`;
|
|
12709
13008
|
}
|
|
12710
13009
|
function startHelpText() {
|
package/package.json
CHANGED