@cli-remote/local 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +263 -63
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3214,7 +3214,7 @@ var require_stream = __commonJS({
|
|
|
3214
3214
|
};
|
|
3215
3215
|
duplex._final = function(callback) {
|
|
3216
3216
|
if (ws.readyState === ws.CONNECTING) {
|
|
3217
|
-
ws.once("open", function
|
|
3217
|
+
ws.once("open", function open2() {
|
|
3218
3218
|
duplex._final(callback);
|
|
3219
3219
|
});
|
|
3220
3220
|
return;
|
|
@@ -3235,7 +3235,7 @@ var require_stream = __commonJS({
|
|
|
3235
3235
|
};
|
|
3236
3236
|
duplex._write = function(chunk, encoding, callback) {
|
|
3237
3237
|
if (ws.readyState === ws.CONNECTING) {
|
|
3238
|
-
ws.once("open", function
|
|
3238
|
+
ws.once("open", function open2() {
|
|
3239
3239
|
duplex._write(chunk, encoding, callback);
|
|
3240
3240
|
});
|
|
3241
3241
|
return;
|
|
@@ -6683,11 +6683,11 @@ var require_dijkstra = __commonJS({
|
|
|
6683
6683
|
var predecessors = {};
|
|
6684
6684
|
var costs = {};
|
|
6685
6685
|
costs[s] = 0;
|
|
6686
|
-
var
|
|
6687
|
-
|
|
6686
|
+
var open2 = dijkstra.PriorityQueue.make();
|
|
6687
|
+
open2.push(s, 0);
|
|
6688
6688
|
var closest, u, v, cost_of_s_to_u, adjacent_nodes, cost_of_e, cost_of_s_to_u_plus_cost_of_e, cost_of_s_to_v, first_visit;
|
|
6689
|
-
while (!
|
|
6690
|
-
closest =
|
|
6689
|
+
while (!open2.empty()) {
|
|
6690
|
+
closest = open2.pop();
|
|
6691
6691
|
u = closest.value;
|
|
6692
6692
|
cost_of_s_to_u = closest.cost;
|
|
6693
6693
|
adjacent_nodes = graph[u] || {};
|
|
@@ -6699,7 +6699,7 @@ var require_dijkstra = __commonJS({
|
|
|
6699
6699
|
first_visit = typeof costs[v] === "undefined";
|
|
6700
6700
|
if (first_visit || cost_of_s_to_v > cost_of_s_to_u_plus_cost_of_e) {
|
|
6701
6701
|
costs[v] = cost_of_s_to_u_plus_cost_of_e;
|
|
6702
|
-
|
|
6702
|
+
open2.push(v, cost_of_s_to_u_plus_cost_of_e);
|
|
6703
6703
|
predecessors[v] = u;
|
|
6704
6704
|
}
|
|
6705
6705
|
}
|
|
@@ -9786,10 +9786,10 @@ var require_browser = __commonJS({
|
|
|
9786
9786
|
text = canvas;
|
|
9787
9787
|
canvas = void 0;
|
|
9788
9788
|
}
|
|
9789
|
-
return new Promise(function(
|
|
9789
|
+
return new Promise(function(resolve2, reject) {
|
|
9790
9790
|
try {
|
|
9791
9791
|
const data = QRCode2.create(text, opts);
|
|
9792
|
-
|
|
9792
|
+
resolve2(renderFunc(data, canvas, opts));
|
|
9793
9793
|
} catch (e) {
|
|
9794
9794
|
reject(e);
|
|
9795
9795
|
}
|
|
@@ -9870,11 +9870,11 @@ var require_server = __commonJS({
|
|
|
9870
9870
|
}
|
|
9871
9871
|
function render(renderFunc, text, params) {
|
|
9872
9872
|
if (!params.cb) {
|
|
9873
|
-
return new Promise(function(
|
|
9873
|
+
return new Promise(function(resolve2, reject) {
|
|
9874
9874
|
try {
|
|
9875
9875
|
const data = QRCode2.create(text, params.opts);
|
|
9876
9876
|
return renderFunc(data, params.opts, function(err, data2) {
|
|
9877
|
-
return err ? reject(err) :
|
|
9877
|
+
return err ? reject(err) : resolve2(data2);
|
|
9878
9878
|
});
|
|
9879
9879
|
} catch (e) {
|
|
9880
9880
|
reject(e);
|
|
@@ -9939,10 +9939,10 @@ var require_lib = __commonJS({
|
|
|
9939
9939
|
});
|
|
9940
9940
|
|
|
9941
9941
|
// src/index.ts
|
|
9942
|
-
var
|
|
9942
|
+
var import_node_fs3 = require("node:fs");
|
|
9943
9943
|
var import_node_child_process2 = require("node:child_process");
|
|
9944
|
-
var
|
|
9945
|
-
var
|
|
9944
|
+
var import_node_os6 = require("node:os");
|
|
9945
|
+
var import_node_path6 = require("node:path");
|
|
9946
9946
|
var import_node_url = require("node:url");
|
|
9947
9947
|
|
|
9948
9948
|
// ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/wrapper.mjs
|
|
@@ -9958,9 +9958,9 @@ var wrapper_default = import_websocket.default;
|
|
|
9958
9958
|
|
|
9959
9959
|
// src/client.ts
|
|
9960
9960
|
var import_node_readline = require("node:readline");
|
|
9961
|
-
var
|
|
9962
|
-
var
|
|
9963
|
-
var
|
|
9961
|
+
var import_promises3 = require("node:fs/promises");
|
|
9962
|
+
var import_node_os5 = require("node:os");
|
|
9963
|
+
var import_node_path5 = require("node:path");
|
|
9964
9964
|
|
|
9965
9965
|
// ../shared/src/codec.ts
|
|
9966
9966
|
var import_msgpack = __toESM(require_dist(), 1);
|
|
@@ -9980,6 +9980,9 @@ var ACCESS_TOKEN_TTL_MS = 60 * 6e4;
|
|
|
9980
9980
|
var REFRESH_TOKEN_TTL_MS = 30 * 24 * 60 * 6e4;
|
|
9981
9981
|
var REFRESH_MARGIN_MS = 5 * 6e4;
|
|
9982
9982
|
var OUTPUT_BUFFER_SIZE = 500;
|
|
9983
|
+
var FILE_CHUNK_SIZE = 64 * 1024;
|
|
9984
|
+
var MAX_TRANSFER_BYTES = 500 * 1024 * 1024;
|
|
9985
|
+
var UPLOAD_DIR = "uploads";
|
|
9983
9986
|
var RECONNECT_DELAYS_MS = [1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
|
|
9984
9987
|
var DEFAULT_CONFIG_DIR = ".cli-remote";
|
|
9985
9988
|
var CREDENTIALS_FILE = "credentials.json";
|
|
@@ -10327,19 +10330,196 @@ function checkCommand(line, whitelist, dangerousPatterns = DANGEROUS_PATTERNS) {
|
|
|
10327
10330
|
return { allowed: true };
|
|
10328
10331
|
}
|
|
10329
10332
|
|
|
10330
|
-
// src/
|
|
10331
|
-
var
|
|
10332
|
-
var import_node_crypto = require("node:crypto");
|
|
10333
|
+
// src/file-transfer.ts
|
|
10334
|
+
var import_node_fs2 = require("node:fs");
|
|
10333
10335
|
var import_promises = require("node:fs/promises");
|
|
10334
10336
|
var import_node_os3 = require("node:os");
|
|
10335
10337
|
var import_node_path3 = require("node:path");
|
|
10338
|
+
var FileTransferManager = class _FileTransferManager {
|
|
10339
|
+
constructor(send, log) {
|
|
10340
|
+
this.send = send;
|
|
10341
|
+
this.log = log;
|
|
10342
|
+
}
|
|
10343
|
+
uploads = /* @__PURE__ */ new Map();
|
|
10344
|
+
uploadDir() {
|
|
10345
|
+
return (0, import_node_path3.join)((0, import_node_os3.homedir)(), DEFAULT_CONFIG_DIR, UPLOAD_DIR);
|
|
10346
|
+
}
|
|
10347
|
+
expandPath(p) {
|
|
10348
|
+
const home = process.env.PTY_HOME ?? (0, import_node_os3.homedir)();
|
|
10349
|
+
if (p === "~") return home;
|
|
10350
|
+
if (p.startsWith("~/")) return (0, import_node_path3.join)(home, p.slice(2));
|
|
10351
|
+
return (0, import_node_path3.resolve)(p);
|
|
10352
|
+
}
|
|
10353
|
+
/** Strip any directory components and control chars from a client filename. */
|
|
10354
|
+
static sanitizeFilename(name) {
|
|
10355
|
+
const base = (0, import_node_path3.basename)(name).replace(/[\u0000-\u001f\u007f]/g, "");
|
|
10356
|
+
return base && base !== "." && base !== ".." ? base : "upload.bin";
|
|
10357
|
+
}
|
|
10358
|
+
async handleUploadStart(frame) {
|
|
10359
|
+
const { sessionId, uploadId, filename, size } = frame;
|
|
10360
|
+
if (this.uploads.has(uploadId)) return;
|
|
10361
|
+
if (size > MAX_TRANSFER_BYTES) {
|
|
10362
|
+
this.emit({
|
|
10363
|
+
t: "upload-err",
|
|
10364
|
+
sessionId,
|
|
10365
|
+
uploadId,
|
|
10366
|
+
reason: `\u6587\u4EF6\u8FC7\u5927\uFF08>${Math.floor(MAX_TRANSFER_BYTES / 1024 / 1024)}MB\uFF09`
|
|
10367
|
+
});
|
|
10368
|
+
return;
|
|
10369
|
+
}
|
|
10370
|
+
try {
|
|
10371
|
+
const dir = this.uploadDir();
|
|
10372
|
+
await (0, import_promises.mkdir)(dir, { recursive: true });
|
|
10373
|
+
const target = await this.uniqPath(dir, _FileTransferManager.sanitizeFilename(filename));
|
|
10374
|
+
const stream = (0, import_node_fs2.createWriteStream)(target, { mode: 384 });
|
|
10375
|
+
this.uploads.set(uploadId, {
|
|
10376
|
+
uploadId,
|
|
10377
|
+
sessionId,
|
|
10378
|
+
path: target,
|
|
10379
|
+
size,
|
|
10380
|
+
received: 0,
|
|
10381
|
+
lastSeq: 0,
|
|
10382
|
+
stream
|
|
10383
|
+
});
|
|
10384
|
+
this.emit({ t: "upload-ok", sessionId, uploadId, path: target });
|
|
10385
|
+
this.log(`upload start ${uploadId} \u2192 ${target} (${size}B)`);
|
|
10386
|
+
} catch (e) {
|
|
10387
|
+
this.emit({ t: "upload-err", sessionId, uploadId, reason: e.message });
|
|
10388
|
+
}
|
|
10389
|
+
}
|
|
10390
|
+
async uniqPath(dir, name) {
|
|
10391
|
+
let candidate = (0, import_node_path3.join)(dir, name);
|
|
10392
|
+
let i = 1;
|
|
10393
|
+
while (await exists(candidate)) {
|
|
10394
|
+
const dot = name.lastIndexOf(".");
|
|
10395
|
+
const stem = dot > 0 ? name.slice(0, dot) : name;
|
|
10396
|
+
const ext = dot > 0 ? name.slice(dot) : "";
|
|
10397
|
+
candidate = (0, import_node_path3.join)(dir, `${stem} (${i++})${ext}`);
|
|
10398
|
+
}
|
|
10399
|
+
return candidate;
|
|
10400
|
+
}
|
|
10401
|
+
handleUploadChunk(frame) {
|
|
10402
|
+
const up = this.uploads.get(frame.uploadId);
|
|
10403
|
+
if (!up) return;
|
|
10404
|
+
if (frame.seq <= up.lastSeq) return;
|
|
10405
|
+
up.lastSeq = frame.seq;
|
|
10406
|
+
up.received += frame.data.byteLength;
|
|
10407
|
+
up.stream.write(Buffer.from(frame.data.buffer, frame.data.byteOffset, frame.data.byteLength));
|
|
10408
|
+
}
|
|
10409
|
+
async handleUploadEnd(frame) {
|
|
10410
|
+
const up = this.uploads.get(frame.uploadId);
|
|
10411
|
+
if (!up) return;
|
|
10412
|
+
this.uploads.delete(frame.uploadId);
|
|
10413
|
+
await new Promise((res) => up.stream.end(res));
|
|
10414
|
+
const sizeOk = up.received === up.size;
|
|
10415
|
+
this.log(`upload done ${frame.uploadId}: ${up.received}B \u2192 ${up.path}`);
|
|
10416
|
+
if (!sizeOk) {
|
|
10417
|
+
this.emit({
|
|
10418
|
+
t: "upload-err",
|
|
10419
|
+
sessionId: up.sessionId,
|
|
10420
|
+
uploadId: frame.uploadId,
|
|
10421
|
+
reason: `\u5927\u5C0F\u4E0D\u5339\u914D\uFF08\u58F0\u660E ${up.size}B\uFF0C\u5B9E\u6536 ${up.received}B\uFF09`
|
|
10422
|
+
});
|
|
10423
|
+
}
|
|
10424
|
+
}
|
|
10425
|
+
abortUpload(uploadId) {
|
|
10426
|
+
const up = this.uploads.get(uploadId);
|
|
10427
|
+
if (!up) return;
|
|
10428
|
+
this.uploads.delete(uploadId);
|
|
10429
|
+
up.stream.destroy();
|
|
10430
|
+
this.log(`upload aborted ${uploadId}`);
|
|
10431
|
+
}
|
|
10432
|
+
/** Stream a file back to the web client with mild backpressure via `send`. */
|
|
10433
|
+
async handleDownloadReq(frame, isBusy) {
|
|
10434
|
+
const sessionId = frame.sessionId;
|
|
10435
|
+
const downloadId = "dl_" + Math.random().toString(36).slice(2, 10);
|
|
10436
|
+
let abs;
|
|
10437
|
+
try {
|
|
10438
|
+
abs = this.expandPath(frame.path);
|
|
10439
|
+
const st = await (0, import_promises.stat)(abs);
|
|
10440
|
+
if (!st.isFile()) throw new Error("\u4E0D\u662F\u666E\u901A\u6587\u4EF6");
|
|
10441
|
+
if (st.size > MAX_TRANSFER_BYTES) {
|
|
10442
|
+
throw new Error(`\u6587\u4EF6\u8FC7\u5927\uFF08>${Math.floor(MAX_TRANSFER_BYTES / 1024 / 1024)}MB\uFF09`);
|
|
10443
|
+
}
|
|
10444
|
+
this.emit({
|
|
10445
|
+
t: "download-start",
|
|
10446
|
+
sessionId,
|
|
10447
|
+
downloadId,
|
|
10448
|
+
filename: (0, import_node_path3.basename)(abs),
|
|
10449
|
+
size: st.size
|
|
10450
|
+
});
|
|
10451
|
+
this.log(`download start ${downloadId} \u2190 ${abs} (${st.size}B)`);
|
|
10452
|
+
await this.streamFile(sessionId, downloadId, abs, isBusy);
|
|
10453
|
+
this.emit({ t: "download-end", sessionId, downloadId });
|
|
10454
|
+
this.log(`download done ${downloadId}: ${abs}`);
|
|
10455
|
+
} catch (e) {
|
|
10456
|
+
this.emit({
|
|
10457
|
+
t: "download-err",
|
|
10458
|
+
sessionId,
|
|
10459
|
+
downloadId,
|
|
10460
|
+
reason: e.message
|
|
10461
|
+
});
|
|
10462
|
+
}
|
|
10463
|
+
}
|
|
10464
|
+
async streamFile(sessionId, downloadId, abs, isBusy) {
|
|
10465
|
+
const handle = await (0, import_promises.open)(abs, "r");
|
|
10466
|
+
try {
|
|
10467
|
+
let seq = 0;
|
|
10468
|
+
let pos = 0;
|
|
10469
|
+
for (; ; ) {
|
|
10470
|
+
const buf = Buffer.alloc(FILE_CHUNK_SIZE);
|
|
10471
|
+
const { bytesRead } = await handle.read(buf, 0, FILE_CHUNK_SIZE, pos);
|
|
10472
|
+
if (bytesRead === 0) break;
|
|
10473
|
+
pos += bytesRead;
|
|
10474
|
+
seq++;
|
|
10475
|
+
this.emit({
|
|
10476
|
+
t: "download-chunk",
|
|
10477
|
+
sessionId,
|
|
10478
|
+
downloadId,
|
|
10479
|
+
data: new Uint8Array(buf.buffer, buf.byteOffset, bytesRead),
|
|
10480
|
+
seq
|
|
10481
|
+
});
|
|
10482
|
+
if (isBusy()) {
|
|
10483
|
+
await new Promise((res) => setImmediate(res));
|
|
10484
|
+
let spins = 0;
|
|
10485
|
+
while (isBusy() && spins++ < 2e3) {
|
|
10486
|
+
await new Promise((res) => setTimeout(res, 20));
|
|
10487
|
+
}
|
|
10488
|
+
}
|
|
10489
|
+
}
|
|
10490
|
+
} finally {
|
|
10491
|
+
await handle.close();
|
|
10492
|
+
}
|
|
10493
|
+
}
|
|
10494
|
+
abortAll() {
|
|
10495
|
+
for (const id of [...this.uploads.keys()]) this.abortUpload(id);
|
|
10496
|
+
}
|
|
10497
|
+
emit(frame) {
|
|
10498
|
+
this.send(encodeFrame(frame));
|
|
10499
|
+
}
|
|
10500
|
+
};
|
|
10501
|
+
async function exists(p) {
|
|
10502
|
+
try {
|
|
10503
|
+
await (0, import_promises.stat)(p);
|
|
10504
|
+
return true;
|
|
10505
|
+
} catch {
|
|
10506
|
+
return false;
|
|
10507
|
+
}
|
|
10508
|
+
}
|
|
10509
|
+
|
|
10510
|
+
// src/auth.ts
|
|
10511
|
+
var import_node_child_process = require("node:child_process");
|
|
10512
|
+
var import_node_crypto = require("node:crypto");
|
|
10513
|
+
var import_promises2 = require("node:fs/promises");
|
|
10514
|
+
var import_node_os4 = require("node:os");
|
|
10515
|
+
var import_node_path4 = require("node:path");
|
|
10336
10516
|
var import_qrcode = __toESM(require_lib(), 1);
|
|
10337
10517
|
function credentialsPath() {
|
|
10338
|
-
return (0,
|
|
10518
|
+
return (0, import_node_path4.join)((0, import_node_os4.homedir)(), DEFAULT_CONFIG_DIR, CREDENTIALS_FILE);
|
|
10339
10519
|
}
|
|
10340
10520
|
async function loadCredentials() {
|
|
10341
10521
|
try {
|
|
10342
|
-
const raw = JSON.parse(await (0,
|
|
10522
|
+
const raw = JSON.parse(await (0, import_promises2.readFile)(credentialsPath(), "utf-8"));
|
|
10343
10523
|
if (!raw.deviceId || !raw.accessToken || !raw.refreshToken) return null;
|
|
10344
10524
|
return raw;
|
|
10345
10525
|
} catch {
|
|
@@ -10348,16 +10528,16 @@ async function loadCredentials() {
|
|
|
10348
10528
|
}
|
|
10349
10529
|
async function saveCredentials(creds) {
|
|
10350
10530
|
const path = credentialsPath();
|
|
10351
|
-
await (0,
|
|
10352
|
-
await (0,
|
|
10531
|
+
await (0, import_promises2.mkdir)((0, import_node_path4.join)(path, ".."), { recursive: true });
|
|
10532
|
+
await (0, import_promises2.writeFile)(path, JSON.stringify(creds, null, 2) + "\n", { mode: 384 });
|
|
10353
10533
|
try {
|
|
10354
|
-
await (0,
|
|
10534
|
+
await (0, import_promises2.chmod)(path, 384);
|
|
10355
10535
|
} catch {
|
|
10356
10536
|
}
|
|
10357
10537
|
}
|
|
10358
10538
|
async function clearCredentials() {
|
|
10359
10539
|
try {
|
|
10360
|
-
await (0,
|
|
10540
|
+
await (0, import_promises2.writeFile)(credentialsPath(), "");
|
|
10361
10541
|
} catch {
|
|
10362
10542
|
}
|
|
10363
10543
|
}
|
|
@@ -10389,17 +10569,17 @@ function openBrowser(url) {
|
|
|
10389
10569
|
}
|
|
10390
10570
|
}
|
|
10391
10571
|
async function mergeLocalConfig(patch) {
|
|
10392
|
-
const dir = (0,
|
|
10393
|
-
const path = (0,
|
|
10572
|
+
const dir = (0, import_node_path4.join)((0, import_node_os4.homedir)(), DEFAULT_CONFIG_DIR);
|
|
10573
|
+
const path = (0, import_node_path4.join)(dir, CONFIG_FILE);
|
|
10394
10574
|
let existing = {};
|
|
10395
10575
|
try {
|
|
10396
|
-
existing = JSON.parse(await (0,
|
|
10576
|
+
existing = JSON.parse(await (0, import_promises2.readFile)(path, "utf-8"));
|
|
10397
10577
|
} catch {
|
|
10398
10578
|
}
|
|
10399
|
-
await (0,
|
|
10400
|
-
await (0,
|
|
10579
|
+
await (0, import_promises2.mkdir)(dir, { recursive: true });
|
|
10580
|
+
await (0, import_promises2.writeFile)(path, JSON.stringify({ ...existing, ...patch }, null, 2) + "\n");
|
|
10401
10581
|
}
|
|
10402
|
-
var sleep = (ms) => new Promise((
|
|
10582
|
+
var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
10403
10583
|
var AuthError = class extends Error {
|
|
10404
10584
|
};
|
|
10405
10585
|
async function deviceFlowAuthorize(baseUrl, registrationKey, deviceId) {
|
|
@@ -10411,7 +10591,7 @@ async function deviceFlowAuthorize(baseUrl, registrationKey, deviceId) {
|
|
|
10411
10591
|
const res = await postJson(`${baseUrl}/oauth/device_authorization`, {
|
|
10412
10592
|
registrationKey,
|
|
10413
10593
|
device_id: deviceId,
|
|
10414
|
-
device_name: (0,
|
|
10594
|
+
device_name: (0, import_node_os4.hostname)(),
|
|
10415
10595
|
platform: process.platform
|
|
10416
10596
|
});
|
|
10417
10597
|
if (res.status !== 200) {
|
|
@@ -10514,9 +10694,9 @@ async function ensureCredentials(baseUrl, registrationKey) {
|
|
|
10514
10694
|
|
|
10515
10695
|
// src/client.ts
|
|
10516
10696
|
async function loadConfig() {
|
|
10517
|
-
const path = (0,
|
|
10697
|
+
const path = (0, import_node_path5.join)((0, import_node_os5.homedir)(), DEFAULT_CONFIG_DIR, CONFIG_FILE);
|
|
10518
10698
|
try {
|
|
10519
|
-
return JSON.parse(await (0,
|
|
10699
|
+
return JSON.parse(await (0, import_promises3.readFile)(path, "utf-8"));
|
|
10520
10700
|
} catch {
|
|
10521
10701
|
return {};
|
|
10522
10702
|
}
|
|
@@ -10533,7 +10713,7 @@ function isTTY() {
|
|
|
10533
10713
|
async function readInput(prompt) {
|
|
10534
10714
|
const rl = (0, import_node_readline.createInterface)({ input: process.stdin, output: process.stdout });
|
|
10535
10715
|
try {
|
|
10536
|
-
return await new Promise((
|
|
10716
|
+
return await new Promise((resolve2) => rl.question(prompt, (answer) => resolve2(answer)));
|
|
10537
10717
|
} finally {
|
|
10538
10718
|
rl.close();
|
|
10539
10719
|
}
|
|
@@ -10603,6 +10783,10 @@ async function startLocal(opts = {}) {
|
|
|
10603
10783
|
const pty = new PtyManager();
|
|
10604
10784
|
const loggers = /* @__PURE__ */ new Map();
|
|
10605
10785
|
const lineBuffers = /* @__PURE__ */ new Map();
|
|
10786
|
+
const transfers = new FileTransferManager(
|
|
10787
|
+
(data) => safeSend(data),
|
|
10788
|
+
(msg) => console.log(`[local] ${msg}`)
|
|
10789
|
+
);
|
|
10606
10790
|
let credentials = await ensureCredentials(baseUrl, registrationKey);
|
|
10607
10791
|
console.log(`[local] connecting to ${url}`);
|
|
10608
10792
|
console.log(`[local] deviceId=${credentials.deviceId}`);
|
|
@@ -10677,6 +10861,7 @@ async function startLocal(opts = {}) {
|
|
|
10677
10861
|
userExitCode = code;
|
|
10678
10862
|
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
10679
10863
|
reconnectTimer = null;
|
|
10864
|
+
transfers.abortAll();
|
|
10680
10865
|
pty.killAll();
|
|
10681
10866
|
for (const [, logger] of loggers) logger.logExit(-1);
|
|
10682
10867
|
loggers.clear();
|
|
@@ -10726,6 +10911,21 @@ async function startLocal(opts = {}) {
|
|
|
10726
10911
|
case "replay-req":
|
|
10727
10912
|
handleReplay(frame);
|
|
10728
10913
|
break;
|
|
10914
|
+
case "upload-start":
|
|
10915
|
+
void transfers.handleUploadStart(frame);
|
|
10916
|
+
break;
|
|
10917
|
+
case "upload-chunk":
|
|
10918
|
+
transfers.handleUploadChunk(frame);
|
|
10919
|
+
break;
|
|
10920
|
+
case "upload-end":
|
|
10921
|
+
void transfers.handleUploadEnd(frame);
|
|
10922
|
+
break;
|
|
10923
|
+
case "download-req":
|
|
10924
|
+
void transfers.handleDownloadReq(
|
|
10925
|
+
frame,
|
|
10926
|
+
() => ws ? ws.bufferedAmount > 4 * 1024 * 1024 : false
|
|
10927
|
+
);
|
|
10928
|
+
break;
|
|
10729
10929
|
default:
|
|
10730
10930
|
console.log("[local] unhandled frame:", frame.t);
|
|
10731
10931
|
}
|
|
@@ -10917,15 +11117,15 @@ function resolveHere() {
|
|
|
10917
11117
|
if (DEBUG) console.error("[debug] cannot resolve script path");
|
|
10918
11118
|
return;
|
|
10919
11119
|
}
|
|
10920
|
-
const hereDir = (0,
|
|
11120
|
+
const hereDir = (0, import_node_path6.dirname)(here);
|
|
10921
11121
|
const candidates = [
|
|
10922
|
-
(0,
|
|
10923
|
-
(0,
|
|
10924
|
-
(0,
|
|
11122
|
+
(0, import_node_path6.join)(hereDir, "..", "node_modules", "node-pty", "prebuilds"),
|
|
11123
|
+
(0, import_node_path6.join)(hereDir, "..", "..", "node-pty", "prebuilds"),
|
|
11124
|
+
(0, import_node_path6.join)(hereDir, "..", "..", "..", "node_modules", "node-pty", "prebuilds")
|
|
10925
11125
|
];
|
|
10926
11126
|
let prebuildsDir = null;
|
|
10927
11127
|
for (const c of candidates) {
|
|
10928
|
-
if ((0,
|
|
11128
|
+
if ((0, import_node_fs3.existsSync)(c)) {
|
|
10929
11129
|
prebuildsDir = c;
|
|
10930
11130
|
break;
|
|
10931
11131
|
}
|
|
@@ -10935,11 +11135,11 @@ function resolveHere() {
|
|
|
10935
11135
|
return;
|
|
10936
11136
|
}
|
|
10937
11137
|
let n = 0;
|
|
10938
|
-
for (const sub of (0,
|
|
10939
|
-
const helper = (0,
|
|
10940
|
-
if ((0,
|
|
11138
|
+
for (const sub of (0, import_node_fs3.readdirSync)(prebuildsDir)) {
|
|
11139
|
+
const helper = (0, import_node_path6.join)(prebuildsDir, sub, "spawn-helper");
|
|
11140
|
+
if ((0, import_node_fs3.existsSync)(helper)) {
|
|
10941
11141
|
try {
|
|
10942
|
-
(0,
|
|
11142
|
+
(0, import_node_fs3.chmodSync)(helper, 493);
|
|
10943
11143
|
n++;
|
|
10944
11144
|
} catch {
|
|
10945
11145
|
}
|
|
@@ -10986,13 +11186,13 @@ example:
|
|
|
10986
11186
|
}
|
|
10987
11187
|
var LAUNCHD_LABEL = "net.cli-remote.local";
|
|
10988
11188
|
function launchdPlistPath() {
|
|
10989
|
-
return (0,
|
|
11189
|
+
return (0, import_node_path6.join)((0, import_node_os6.homedir)(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
10990
11190
|
}
|
|
10991
11191
|
function entryScript() {
|
|
10992
11192
|
const a1 = process.argv[1];
|
|
10993
11193
|
if (!a1 || a1.endsWith(".ts")) return null;
|
|
10994
11194
|
try {
|
|
10995
|
-
return (0,
|
|
11195
|
+
return (0, import_node_fs3.realpathSync)(a1);
|
|
10996
11196
|
} catch {
|
|
10997
11197
|
return a1;
|
|
10998
11198
|
}
|
|
@@ -11010,7 +11210,7 @@ function launchdInstall(urlArg) {
|
|
|
11010
11210
|
console.error(`[local] launchd \u5E38\u9A7B\u4EC5\u652F\u6301 macOS\uFF08\u5F53\u524D ${process.platform}\uFF09\uFF1BLinux \u8BF7\u7528 systemd --user \u81EA\u884C\u6258\u7BA1`);
|
|
11011
11211
|
process.exit(1);
|
|
11012
11212
|
}
|
|
11013
|
-
const home = (0,
|
|
11213
|
+
const home = (0, import_node_os6.homedir)();
|
|
11014
11214
|
const entry = entryScript();
|
|
11015
11215
|
if (!entry) {
|
|
11016
11216
|
console.error("[local] \u5F53\u524D\u4EE5\u6E90\u7801\uFF08tsx\uFF09\u6A21\u5F0F\u8FD0\u884C\uFF0C\u65E0\u6CD5\u5B89\u88C5\u5E38\u9A7B\u670D\u52A1\u3002");
|
|
@@ -11018,28 +11218,28 @@ function launchdInstall(urlArg) {
|
|
|
11018
11218
|
process.exit(1);
|
|
11019
11219
|
}
|
|
11020
11220
|
if (urlArg) {
|
|
11021
|
-
const cfgDir = (0,
|
|
11022
|
-
(0,
|
|
11023
|
-
const cfgPath = (0,
|
|
11221
|
+
const cfgDir = (0, import_node_path6.join)(home, DEFAULT_CONFIG_DIR);
|
|
11222
|
+
(0, import_node_fs3.mkdirSync)(cfgDir, { recursive: true });
|
|
11223
|
+
const cfgPath = (0, import_node_path6.join)(cfgDir, "config.json");
|
|
11024
11224
|
let cfg = {};
|
|
11025
11225
|
try {
|
|
11026
|
-
cfg = JSON.parse((0,
|
|
11226
|
+
cfg = JSON.parse((0, import_node_fs3.readFileSync)(cfgPath, "utf-8"));
|
|
11027
11227
|
} catch {
|
|
11028
11228
|
}
|
|
11029
11229
|
cfg.relayUrl = urlArg;
|
|
11030
|
-
(0,
|
|
11230
|
+
(0, import_node_fs3.writeFileSync)(cfgPath, JSON.stringify(cfg, null, 2) + "\n");
|
|
11031
11231
|
console.log(`[local] relayUrl \u5DF2\u5199\u5165 ${cfgPath}`);
|
|
11032
11232
|
}
|
|
11033
|
-
const credPath = (0,
|
|
11034
|
-
if (!(0,
|
|
11233
|
+
const credPath = (0, import_node_path6.join)(home, DEFAULT_CONFIG_DIR, CREDENTIALS_FILE);
|
|
11234
|
+
if (!(0, import_node_fs3.existsSync)(credPath)) {
|
|
11035
11235
|
console.error("[local] \u5C1A\u672A\u6388\u6743\uFF08\u627E\u4E0D\u5230 credentials.json\uFF09\u3002");
|
|
11036
11236
|
console.error("[local] \u8BF7\u5148\u4EA4\u4E92\u5F0F\u8FD0\u884C\u4E00\u6B21 cli-local \u5B8C\u6210\u914D\u7F6E\u4E0E\u6388\u6743\uFF0C\u518D\u5B89\u88C5\u5E38\u9A7B\u670D\u52A1\u3002");
|
|
11037
11237
|
process.exit(1);
|
|
11038
11238
|
}
|
|
11039
11239
|
const plist = launchdPlistPath();
|
|
11040
|
-
const logDir = (0,
|
|
11041
|
-
(0,
|
|
11042
|
-
(0,
|
|
11240
|
+
const logDir = (0, import_node_path6.join)(home, DEFAULT_CONFIG_DIR, "logs");
|
|
11241
|
+
(0, import_node_fs3.mkdirSync)((0, import_node_path6.dirname)(plist), { recursive: true });
|
|
11242
|
+
(0, import_node_fs3.mkdirSync)(logDir, { recursive: true });
|
|
11043
11243
|
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
11044
11244
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
11045
11245
|
<plist version="1.0">
|
|
@@ -11053,12 +11253,12 @@ function launchdInstall(urlArg) {
|
|
|
11053
11253
|
<key>RunAtLoad</key><true/>
|
|
11054
11254
|
<key>KeepAlive</key><true/>
|
|
11055
11255
|
<key>ThrottleInterval</key><integer>30</integer>
|
|
11056
|
-
<key>StandardOutPath</key><string>${(0,
|
|
11057
|
-
<key>StandardErrorPath</key><string>${(0,
|
|
11256
|
+
<key>StandardOutPath</key><string>${(0, import_node_path6.join)(logDir, "daemon.out.log")}</string>
|
|
11257
|
+
<key>StandardErrorPath</key><string>${(0, import_node_path6.join)(logDir, "daemon.err.log")}</string>
|
|
11058
11258
|
</dict>
|
|
11059
11259
|
</plist>
|
|
11060
11260
|
`;
|
|
11061
|
-
(0,
|
|
11261
|
+
(0, import_node_fs3.writeFileSync)(plist, xml);
|
|
11062
11262
|
const uid = process.getuid?.();
|
|
11063
11263
|
if (uid === void 0) {
|
|
11064
11264
|
console.error("[local] \u65E0\u6CD5\u786E\u5B9A uid\uFF0Claunchd \u5B89\u88C5\u5931\u8D25");
|
|
@@ -11076,7 +11276,7 @@ function launchdInstall(urlArg) {
|
|
|
11076
11276
|
}
|
|
11077
11277
|
function launchdUninstall() {
|
|
11078
11278
|
const plist = launchdPlistPath();
|
|
11079
|
-
if (!(0,
|
|
11279
|
+
if (!(0, import_node_fs3.existsSync)(plist)) {
|
|
11080
11280
|
console.log("[local] \u672A\u627E\u5230\u5DF2\u5B89\u88C5\u7684\u5E38\u9A7B\u670D\u52A1\uFF08nothing to uninstall\uFF09");
|
|
11081
11281
|
process.exit(0);
|
|
11082
11282
|
}
|
|
@@ -11084,7 +11284,7 @@ function launchdUninstall() {
|
|
|
11084
11284
|
const guiDomain = `gui/${uid ?? 0}`;
|
|
11085
11285
|
run("launchctl", ["bootout", guiDomain, plist], true);
|
|
11086
11286
|
run("launchctl", ["unload", "-w", plist], true);
|
|
11087
|
-
(0,
|
|
11287
|
+
(0, import_node_fs3.rmSync)(plist);
|
|
11088
11288
|
console.log(`[local] launchd \u670D\u52A1\u5DF2\u505C\u6B62\u5E76\u5378\u8F7D\uFF1A${LAUNCHD_LABEL}`);
|
|
11089
11289
|
}
|
|
11090
11290
|
if (argUrl && !argMatch && argUrl === "install") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cli-remote/local",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Local PTY agent for cli-remote — exposes your local CLI tools (claude/codex/kimi-cli/shell) to the mobile web client via a self-hosted hub.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|