@cli-remote/local 0.0.2 → 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 +461 -88
- 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,8 +9939,10 @@ var require_lib = __commonJS({
|
|
|
9939
9939
|
});
|
|
9940
9940
|
|
|
9941
9941
|
// src/index.ts
|
|
9942
|
-
var
|
|
9943
|
-
var
|
|
9942
|
+
var import_node_fs3 = require("node:fs");
|
|
9943
|
+
var import_node_child_process2 = require("node:child_process");
|
|
9944
|
+
var import_node_os6 = require("node:os");
|
|
9945
|
+
var import_node_path6 = require("node:path");
|
|
9944
9946
|
var import_node_url = require("node:url");
|
|
9945
9947
|
|
|
9946
9948
|
// ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/wrapper.mjs
|
|
@@ -9956,9 +9958,9 @@ var wrapper_default = import_websocket.default;
|
|
|
9956
9958
|
|
|
9957
9959
|
// src/client.ts
|
|
9958
9960
|
var import_node_readline = require("node:readline");
|
|
9959
|
-
var
|
|
9960
|
-
var
|
|
9961
|
-
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");
|
|
9962
9964
|
|
|
9963
9965
|
// ../shared/src/codec.ts
|
|
9964
9966
|
var import_msgpack = __toESM(require_dist(), 1);
|
|
@@ -9978,6 +9980,10 @@ var ACCESS_TOKEN_TTL_MS = 60 * 6e4;
|
|
|
9978
9980
|
var REFRESH_TOKEN_TTL_MS = 30 * 24 * 60 * 6e4;
|
|
9979
9981
|
var REFRESH_MARGIN_MS = 5 * 6e4;
|
|
9980
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";
|
|
9986
|
+
var RECONNECT_DELAYS_MS = [1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
|
|
9981
9987
|
var DEFAULT_CONFIG_DIR = ".cli-remote";
|
|
9982
9988
|
var CREDENTIALS_FILE = "credentials.json";
|
|
9983
9989
|
var CONFIG_FILE = "config.json";
|
|
@@ -10211,6 +10217,10 @@ var SessionLogger = class {
|
|
|
10211
10217
|
if (this.closed) return;
|
|
10212
10218
|
this.write({ ts: Date.now(), event: "rejected", cmd, reason, dangerous });
|
|
10213
10219
|
}
|
|
10220
|
+
logForced(cmd) {
|
|
10221
|
+
if (this.closed) return;
|
|
10222
|
+
this.write({ ts: Date.now(), event: "forced", cmd });
|
|
10223
|
+
}
|
|
10214
10224
|
logExit(code) {
|
|
10215
10225
|
if (this.closed) return;
|
|
10216
10226
|
this.write({ ts: Date.now(), event: "exit", code });
|
|
@@ -10320,19 +10330,196 @@ function checkCommand(line, whitelist, dangerousPatterns = DANGEROUS_PATTERNS) {
|
|
|
10320
10330
|
return { allowed: true };
|
|
10321
10331
|
}
|
|
10322
10332
|
|
|
10323
|
-
// src/
|
|
10324
|
-
var
|
|
10325
|
-
var import_node_crypto = require("node:crypto");
|
|
10333
|
+
// src/file-transfer.ts
|
|
10334
|
+
var import_node_fs2 = require("node:fs");
|
|
10326
10335
|
var import_promises = require("node:fs/promises");
|
|
10327
10336
|
var import_node_os3 = require("node:os");
|
|
10328
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");
|
|
10329
10516
|
var import_qrcode = __toESM(require_lib(), 1);
|
|
10330
10517
|
function credentialsPath() {
|
|
10331
|
-
return (0,
|
|
10518
|
+
return (0, import_node_path4.join)((0, import_node_os4.homedir)(), DEFAULT_CONFIG_DIR, CREDENTIALS_FILE);
|
|
10332
10519
|
}
|
|
10333
10520
|
async function loadCredentials() {
|
|
10334
10521
|
try {
|
|
10335
|
-
const raw = JSON.parse(await (0,
|
|
10522
|
+
const raw = JSON.parse(await (0, import_promises2.readFile)(credentialsPath(), "utf-8"));
|
|
10336
10523
|
if (!raw.deviceId || !raw.accessToken || !raw.refreshToken) return null;
|
|
10337
10524
|
return raw;
|
|
10338
10525
|
} catch {
|
|
@@ -10341,16 +10528,16 @@ async function loadCredentials() {
|
|
|
10341
10528
|
}
|
|
10342
10529
|
async function saveCredentials(creds) {
|
|
10343
10530
|
const path = credentialsPath();
|
|
10344
|
-
await (0,
|
|
10345
|
-
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 });
|
|
10346
10533
|
try {
|
|
10347
|
-
await (0,
|
|
10534
|
+
await (0, import_promises2.chmod)(path, 384);
|
|
10348
10535
|
} catch {
|
|
10349
10536
|
}
|
|
10350
10537
|
}
|
|
10351
10538
|
async function clearCredentials() {
|
|
10352
10539
|
try {
|
|
10353
|
-
await (0,
|
|
10540
|
+
await (0, import_promises2.writeFile)(credentialsPath(), "");
|
|
10354
10541
|
} catch {
|
|
10355
10542
|
}
|
|
10356
10543
|
}
|
|
@@ -10382,17 +10569,17 @@ function openBrowser(url) {
|
|
|
10382
10569
|
}
|
|
10383
10570
|
}
|
|
10384
10571
|
async function mergeLocalConfig(patch) {
|
|
10385
|
-
const dir = (0,
|
|
10386
|
-
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);
|
|
10387
10574
|
let existing = {};
|
|
10388
10575
|
try {
|
|
10389
|
-
existing = JSON.parse(await (0,
|
|
10576
|
+
existing = JSON.parse(await (0, import_promises2.readFile)(path, "utf-8"));
|
|
10390
10577
|
} catch {
|
|
10391
10578
|
}
|
|
10392
|
-
await (0,
|
|
10393
|
-
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");
|
|
10394
10581
|
}
|
|
10395
|
-
var sleep = (ms) => new Promise((
|
|
10582
|
+
var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
10396
10583
|
var AuthError = class extends Error {
|
|
10397
10584
|
};
|
|
10398
10585
|
async function deviceFlowAuthorize(baseUrl, registrationKey, deviceId) {
|
|
@@ -10404,7 +10591,7 @@ async function deviceFlowAuthorize(baseUrl, registrationKey, deviceId) {
|
|
|
10404
10591
|
const res = await postJson(`${baseUrl}/oauth/device_authorization`, {
|
|
10405
10592
|
registrationKey,
|
|
10406
10593
|
device_id: deviceId,
|
|
10407
|
-
device_name: (0,
|
|
10594
|
+
device_name: (0, import_node_os4.hostname)(),
|
|
10408
10595
|
platform: process.platform
|
|
10409
10596
|
});
|
|
10410
10597
|
if (res.status !== 200) {
|
|
@@ -10507,9 +10694,9 @@ async function ensureCredentials(baseUrl, registrationKey) {
|
|
|
10507
10694
|
|
|
10508
10695
|
// src/client.ts
|
|
10509
10696
|
async function loadConfig() {
|
|
10510
|
-
const path = (0,
|
|
10697
|
+
const path = (0, import_node_path5.join)((0, import_node_os5.homedir)(), DEFAULT_CONFIG_DIR, CONFIG_FILE);
|
|
10511
10698
|
try {
|
|
10512
|
-
return JSON.parse(await (0,
|
|
10699
|
+
return JSON.parse(await (0, import_promises3.readFile)(path, "utf-8"));
|
|
10513
10700
|
} catch {
|
|
10514
10701
|
return {};
|
|
10515
10702
|
}
|
|
@@ -10526,7 +10713,7 @@ function isTTY() {
|
|
|
10526
10713
|
async function readInput(prompt) {
|
|
10527
10714
|
const rl = (0, import_node_readline.createInterface)({ input: process.stdin, output: process.stdout });
|
|
10528
10715
|
try {
|
|
10529
|
-
return await new Promise((
|
|
10716
|
+
return await new Promise((resolve2) => rl.question(prompt, (answer) => resolve2(answer)));
|
|
10530
10717
|
} finally {
|
|
10531
10718
|
rl.close();
|
|
10532
10719
|
}
|
|
@@ -10596,27 +10783,25 @@ async function startLocal(opts = {}) {
|
|
|
10596
10783
|
const pty = new PtyManager();
|
|
10597
10784
|
const loggers = /* @__PURE__ */ new Map();
|
|
10598
10785
|
const lineBuffers = /* @__PURE__ */ new Map();
|
|
10786
|
+
const transfers = new FileTransferManager(
|
|
10787
|
+
(data) => safeSend(data),
|
|
10788
|
+
(msg) => console.log(`[local] ${msg}`)
|
|
10789
|
+
);
|
|
10599
10790
|
let credentials = await ensureCredentials(baseUrl, registrationKey);
|
|
10600
10791
|
console.log(`[local] connecting to ${url}`);
|
|
10601
10792
|
console.log(`[local] deviceId=${credentials.deviceId}`);
|
|
10602
10793
|
console.log(`[local] whitelist: ${whitelist.size} commands`);
|
|
10603
|
-
|
|
10794
|
+
let ws = null;
|
|
10604
10795
|
let heartbeatTimer = null;
|
|
10605
|
-
|
|
10606
|
-
|
|
10607
|
-
|
|
10608
|
-
|
|
10609
|
-
lineBuffers.clear();
|
|
10796
|
+
let reconnectTimer = null;
|
|
10797
|
+
let reconnectAttempts = 0;
|
|
10798
|
+
let userExitCode = null;
|
|
10799
|
+
function stopHeartbeat() {
|
|
10610
10800
|
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
10611
|
-
|
|
10612
|
-
ws.close();
|
|
10613
|
-
} catch {
|
|
10614
|
-
}
|
|
10615
|
-
process.exit(code);
|
|
10801
|
+
heartbeatTimer = null;
|
|
10616
10802
|
}
|
|
10617
|
-
|
|
10618
|
-
|
|
10619
|
-
ws.send(
|
|
10803
|
+
function sendAuth() {
|
|
10804
|
+
ws?.send(
|
|
10620
10805
|
encodeFrame({
|
|
10621
10806
|
t: "auth",
|
|
10622
10807
|
role: "bridge",
|
|
@@ -10624,13 +10809,74 @@ async function startLocal(opts = {}) {
|
|
|
10624
10809
|
token: credentials.accessToken
|
|
10625
10810
|
})
|
|
10626
10811
|
);
|
|
10627
|
-
|
|
10628
|
-
|
|
10629
|
-
|
|
10630
|
-
|
|
10631
|
-
|
|
10632
|
-
|
|
10633
|
-
|
|
10812
|
+
}
|
|
10813
|
+
function connect() {
|
|
10814
|
+
if (userExitCode !== null) return;
|
|
10815
|
+
const sock = new wrapper_default(url);
|
|
10816
|
+
ws = sock;
|
|
10817
|
+
sock.on("open", () => {
|
|
10818
|
+
console.log("[local] connected");
|
|
10819
|
+
sendAuth();
|
|
10820
|
+
stopHeartbeat();
|
|
10821
|
+
heartbeatTimer = setInterval(() => {
|
|
10822
|
+
if (sock.readyState === wrapper_default.OPEN) {
|
|
10823
|
+
sock.send(encodeFrame({ t: "ping" }));
|
|
10824
|
+
}
|
|
10825
|
+
}, HEARTBEAT_INTERVAL_MS);
|
|
10826
|
+
});
|
|
10827
|
+
sock.on("message", (raw) => handleFrame(sock, raw));
|
|
10828
|
+
sock.on("close", () => {
|
|
10829
|
+
stopHeartbeat();
|
|
10830
|
+
if (ws === sock) ws = null;
|
|
10831
|
+
if (userExitCode !== null) {
|
|
10832
|
+
process.exit(userExitCode);
|
|
10833
|
+
}
|
|
10834
|
+
console.log("[local] disconnected; PTY sessions kept alive, reconnecting\u2026");
|
|
10835
|
+
scheduleReconnect();
|
|
10836
|
+
});
|
|
10837
|
+
sock.on("error", (err) => {
|
|
10838
|
+
console.error("[local] ws error:", err.message);
|
|
10839
|
+
});
|
|
10840
|
+
}
|
|
10841
|
+
async function scheduleReconnect() {
|
|
10842
|
+
if (reconnectTimer || userExitCode !== null) return;
|
|
10843
|
+
const idx = Math.min(reconnectAttempts, RECONNECT_DELAYS_MS.length - 1);
|
|
10844
|
+
const delay = RECONNECT_DELAYS_MS[idx];
|
|
10845
|
+
reconnectAttempts++;
|
|
10846
|
+
console.log(`[local] reconnecting in ${Math.round(delay / 1e3)}s (attempt ${reconnectAttempts})`);
|
|
10847
|
+
reconnectTimer = setTimeout(() => {
|
|
10848
|
+
reconnectTimer = null;
|
|
10849
|
+
ensureFreshAccessToken(baseUrl, credentials).then((creds) => {
|
|
10850
|
+
credentials = creds;
|
|
10851
|
+
connect();
|
|
10852
|
+
}).catch(async (e) => {
|
|
10853
|
+
await clearCredentials();
|
|
10854
|
+
console.error(`[local] ${e.message}`);
|
|
10855
|
+
console.error("[local] \u51ED\u8BC1\u5DF2\u5931\u6548\u5E76\u6E05\u9664\uFF1B\u8BF7\u91CD\u65B0\u8FD0\u884C cli-local \u5B8C\u6210\u6388\u6743");
|
|
10856
|
+
exitProcess(1);
|
|
10857
|
+
});
|
|
10858
|
+
}, delay);
|
|
10859
|
+
}
|
|
10860
|
+
function exitProcess(code) {
|
|
10861
|
+
userExitCode = code;
|
|
10862
|
+
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
10863
|
+
reconnectTimer = null;
|
|
10864
|
+
transfers.abortAll();
|
|
10865
|
+
pty.killAll();
|
|
10866
|
+
for (const [, logger] of loggers) logger.logExit(-1);
|
|
10867
|
+
loggers.clear();
|
|
10868
|
+
lineBuffers.clear();
|
|
10869
|
+
stopHeartbeat();
|
|
10870
|
+
try {
|
|
10871
|
+
ws?.close();
|
|
10872
|
+
} catch {
|
|
10873
|
+
}
|
|
10874
|
+
process.exit(code);
|
|
10875
|
+
}
|
|
10876
|
+
function cleanup(code = 0) {
|
|
10877
|
+
exitProcess(code);
|
|
10878
|
+
}
|
|
10879
|
+
function handleFrame(sock, raw) {
|
|
10634
10880
|
let frame;
|
|
10635
10881
|
try {
|
|
10636
10882
|
frame = decodeFrame(toUint8(raw));
|
|
@@ -10639,6 +10885,10 @@ async function startLocal(opts = {}) {
|
|
|
10639
10885
|
}
|
|
10640
10886
|
switch (frame.t) {
|
|
10641
10887
|
case "auth-ok":
|
|
10888
|
+
if (reconnectAttempts > 0) {
|
|
10889
|
+
console.log(`[local] reconnected after ${reconnectAttempts} attempt(s); ${pty.list().length} PTY session(s) alive`);
|
|
10890
|
+
}
|
|
10891
|
+
reconnectAttempts = 0;
|
|
10642
10892
|
console.log(`[local] auth ok, deviceId=${frame.channelId}`);
|
|
10643
10893
|
break;
|
|
10644
10894
|
case "auth-err":
|
|
@@ -10661,23 +10911,31 @@ async function startLocal(opts = {}) {
|
|
|
10661
10911
|
case "replay-req":
|
|
10662
10912
|
handleReplay(frame);
|
|
10663
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;
|
|
10664
10929
|
default:
|
|
10665
10930
|
console.log("[local] unhandled frame:", frame.t);
|
|
10666
10931
|
}
|
|
10667
|
-
}
|
|
10932
|
+
}
|
|
10668
10933
|
async function handleAuthErr(reason) {
|
|
10669
10934
|
if (reason === "access token expired") {
|
|
10670
10935
|
try {
|
|
10671
10936
|
credentials = await ensureFreshAccessToken(baseUrl, credentials);
|
|
10672
10937
|
console.log("[local] token refreshed, retrying auth");
|
|
10673
|
-
|
|
10674
|
-
encodeFrame({
|
|
10675
|
-
t: "auth",
|
|
10676
|
-
role: "bridge",
|
|
10677
|
-
deviceId: credentials.deviceId,
|
|
10678
|
-
token: credentials.accessToken
|
|
10679
|
-
})
|
|
10680
|
-
);
|
|
10938
|
+
sendAuth();
|
|
10681
10939
|
return;
|
|
10682
10940
|
} catch (e) {
|
|
10683
10941
|
console.error(`[local] ${e.message}`);
|
|
@@ -10686,7 +10944,7 @@ async function startLocal(opts = {}) {
|
|
|
10686
10944
|
await clearCredentials();
|
|
10687
10945
|
console.error("[local] auth failed:", reason);
|
|
10688
10946
|
console.error("[local] \u51ED\u8BC1\u5DF2\u6E05\u9664\uFF0C\u8BF7\u91CD\u65B0\u8FD0\u884C cli-local \u5B8C\u6210\u6388\u6743");
|
|
10689
|
-
|
|
10947
|
+
exitProcess(1);
|
|
10690
10948
|
}
|
|
10691
10949
|
function handleSpawn(frame) {
|
|
10692
10950
|
const sessionId = frame.sessionId;
|
|
@@ -10742,6 +11000,15 @@ async function startLocal(opts = {}) {
|
|
|
10742
11000
|
const logger = loggers.get(sessionId);
|
|
10743
11001
|
const session = pty.get(sessionId);
|
|
10744
11002
|
if (!session || !logger) return;
|
|
11003
|
+
if (frame.force) {
|
|
11004
|
+
const line = new TextDecoder().decode(frame.data);
|
|
11005
|
+
ptyWriteChar(sessionId, line + "\r");
|
|
11006
|
+
logger.logInput(new TextEncoder().encode(line + "\r"));
|
|
11007
|
+
logger.logForced(line);
|
|
11008
|
+
lineBuffers.set(sessionId, "");
|
|
11009
|
+
console.log(`[local] forced execution in ${sessionId}: ${line}`);
|
|
11010
|
+
return;
|
|
11011
|
+
}
|
|
10745
11012
|
if (session.cmd === "shell" && !session.inAltScreen) {
|
|
10746
11013
|
handleShellInput(sessionId, frame.data, logger);
|
|
10747
11014
|
} else {
|
|
@@ -10816,23 +11083,13 @@ async function startLocal(opts = {}) {
|
|
|
10816
11083
|
);
|
|
10817
11084
|
}
|
|
10818
11085
|
function safeSend(data) {
|
|
10819
|
-
if (ws.readyState === wrapper_default.OPEN) {
|
|
11086
|
+
if (ws && ws.readyState === wrapper_default.OPEN) {
|
|
10820
11087
|
ws.send(data);
|
|
10821
11088
|
}
|
|
10822
11089
|
}
|
|
10823
|
-
ws.on("close", () => {
|
|
10824
|
-
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
10825
|
-
pty.killAll();
|
|
10826
|
-
for (const [, logger] of loggers) logger.logExit(-1);
|
|
10827
|
-
loggers.clear();
|
|
10828
|
-
lineBuffers.clear();
|
|
10829
|
-
console.log("[local] disconnected");
|
|
10830
|
-
});
|
|
10831
|
-
ws.on("error", (err) => {
|
|
10832
|
-
console.error("[local] error:", err.message);
|
|
10833
|
-
});
|
|
10834
11090
|
process.on("SIGINT", () => cleanup(0));
|
|
10835
11091
|
process.on("SIGTERM", () => cleanup(0));
|
|
11092
|
+
connect();
|
|
10836
11093
|
}
|
|
10837
11094
|
function toUint8(raw) {
|
|
10838
11095
|
if (raw instanceof Buffer) return new Uint8Array(raw.buffer, raw.byteOffset, raw.byteLength);
|
|
@@ -10860,15 +11117,15 @@ function resolveHere() {
|
|
|
10860
11117
|
if (DEBUG) console.error("[debug] cannot resolve script path");
|
|
10861
11118
|
return;
|
|
10862
11119
|
}
|
|
10863
|
-
const hereDir = (0,
|
|
11120
|
+
const hereDir = (0, import_node_path6.dirname)(here);
|
|
10864
11121
|
const candidates = [
|
|
10865
|
-
(0,
|
|
10866
|
-
(0,
|
|
10867
|
-
(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")
|
|
10868
11125
|
];
|
|
10869
11126
|
let prebuildsDir = null;
|
|
10870
11127
|
for (const c of candidates) {
|
|
10871
|
-
if ((0,
|
|
11128
|
+
if ((0, import_node_fs3.existsSync)(c)) {
|
|
10872
11129
|
prebuildsDir = c;
|
|
10873
11130
|
break;
|
|
10874
11131
|
}
|
|
@@ -10878,11 +11135,11 @@ function resolveHere() {
|
|
|
10878
11135
|
return;
|
|
10879
11136
|
}
|
|
10880
11137
|
let n = 0;
|
|
10881
|
-
for (const sub of (0,
|
|
10882
|
-
const helper = (0,
|
|
10883
|
-
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)) {
|
|
10884
11141
|
try {
|
|
10885
|
-
(0,
|
|
11142
|
+
(0, import_node_fs3.chmodSync)(helper, 493);
|
|
10886
11143
|
n++;
|
|
10887
11144
|
} catch {
|
|
10888
11145
|
}
|
|
@@ -10897,6 +11154,8 @@ if (argUrl && !argMatch && (argUrl === "-h" || argUrl === "--help" || argUrl ===
|
|
|
10897
11154
|
|
|
10898
11155
|
usage:
|
|
10899
11156
|
cli-local [HUB_URL]
|
|
11157
|
+
cli-local install [HUB_URL] \u5B89\u88C5 macOS launchd \u5E38\u9A7B\u670D\u52A1\uFF08\u5F00\u673A\u81EA\u542F + \u65AD\u7EBF\u81EA\u52A8\u91CD\u8FDE\uFF09
|
|
11158
|
+
cli-local uninstall \u5378\u8F7D launchd \u5E38\u9A7B\u670D\u52A1
|
|
10900
11159
|
|
|
10901
11160
|
\u9996\u6B21\u8FD0\u884C\uFF08\u65E0\u914D\u7F6E\uFF09\u4F1A\u8FDB\u5165\u5F15\u5BFC\uFF1A
|
|
10902
11161
|
1. \u63D0\u793A hub \u5730\u5740\uFF08\u56DE\u8F66\u7528\u9ED8\u8BA4\uFF09
|
|
@@ -10905,6 +11164,8 @@ usage:
|
|
|
10905
11164
|
4. \u968F\u540E\u8D70 OAuth Device Flow\uFF08RFC 8628\uFF09\uFF1A\u81EA\u52A8\u6253\u5F00\u6388\u6743\u9875 \u2192 \u6279\u51C6\u672C\u8BBE\u5907
|
|
10906
11165
|
5. \u51ED\u8BC1\u5B58\u5165 ~/.cli-remote/credentials.json\uFF080600\uFF09\uFF0C\u4E4B\u540E\u81EA\u52A8\u7EED\u671F
|
|
10907
11166
|
|
|
11167
|
+
\u65AD\u7EBF\u81EA\u52A8\u91CD\u8FDE\uFF1Ahub \u91CD\u542F/\u7F51\u7EDC\u95EA\u65AD\u540E\u8FDB\u7A0B\u4E0D\u9000\u51FA\uFF0CPTY \u4F1A\u8BDD\u4FDD\u6D3B\u5E76\u81EA\u52A8\u91CD\u8FDE\u3002
|
|
11168
|
+
|
|
10908
11169
|
environment:
|
|
10909
11170
|
RELAY_URL hub ws url (overrides argv and config)
|
|
10910
11171
|
REGISTRATION_KEY registration key (fallback of config.json)
|
|
@@ -10919,7 +11180,119 @@ config (~/.cli-remote/config.json):
|
|
|
10919
11180
|
}
|
|
10920
11181
|
|
|
10921
11182
|
example:
|
|
10922
|
-
cli-local wss://cli-remote.mkjs.net/ws
|
|
11183
|
+
cli-local wss://cli-remote.mkjs.net/ws
|
|
11184
|
+
cli-local install # \u914D\u7F6E\u5E76\u6388\u6743\u540E\uFF0C\u5B89\u88C5\u5E38\u9A7B\u670D\u52A1`);
|
|
11185
|
+
process.exit(0);
|
|
11186
|
+
}
|
|
11187
|
+
var LAUNCHD_LABEL = "net.cli-remote.local";
|
|
11188
|
+
function launchdPlistPath() {
|
|
11189
|
+
return (0, import_node_path6.join)((0, import_node_os6.homedir)(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
11190
|
+
}
|
|
11191
|
+
function entryScript() {
|
|
11192
|
+
const a1 = process.argv[1];
|
|
11193
|
+
if (!a1 || a1.endsWith(".ts")) return null;
|
|
11194
|
+
try {
|
|
11195
|
+
return (0, import_node_fs3.realpathSync)(a1);
|
|
11196
|
+
} catch {
|
|
11197
|
+
return a1;
|
|
11198
|
+
}
|
|
11199
|
+
}
|
|
11200
|
+
function run(cmd, args, okToFail = false) {
|
|
11201
|
+
try {
|
|
11202
|
+
return (0, import_node_child_process2.execFileSync)(cmd, args, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
|
|
11203
|
+
} catch (e) {
|
|
11204
|
+
if (okToFail) return null;
|
|
11205
|
+
throw e;
|
|
11206
|
+
}
|
|
11207
|
+
}
|
|
11208
|
+
function launchdInstall(urlArg) {
|
|
11209
|
+
if (process.platform !== "darwin") {
|
|
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`);
|
|
11211
|
+
process.exit(1);
|
|
11212
|
+
}
|
|
11213
|
+
const home = (0, import_node_os6.homedir)();
|
|
11214
|
+
const entry = entryScript();
|
|
11215
|
+
if (!entry) {
|
|
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");
|
|
11217
|
+
console.error("[local] \u8BF7\u5148\u901A\u8FC7 npm \u5B89\u88C5\uFF1Anpm i -g @cli-remote/local\uFF0C\u518D\u7528\u5B89\u88C5\u7248\u6267\u884C install\u3002");
|
|
11218
|
+
process.exit(1);
|
|
11219
|
+
}
|
|
11220
|
+
if (urlArg) {
|
|
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");
|
|
11224
|
+
let cfg = {};
|
|
11225
|
+
try {
|
|
11226
|
+
cfg = JSON.parse((0, import_node_fs3.readFileSync)(cfgPath, "utf-8"));
|
|
11227
|
+
} catch {
|
|
11228
|
+
}
|
|
11229
|
+
cfg.relayUrl = urlArg;
|
|
11230
|
+
(0, import_node_fs3.writeFileSync)(cfgPath, JSON.stringify(cfg, null, 2) + "\n");
|
|
11231
|
+
console.log(`[local] relayUrl \u5DF2\u5199\u5165 ${cfgPath}`);
|
|
11232
|
+
}
|
|
11233
|
+
const credPath = (0, import_node_path6.join)(home, DEFAULT_CONFIG_DIR, CREDENTIALS_FILE);
|
|
11234
|
+
if (!(0, import_node_fs3.existsSync)(credPath)) {
|
|
11235
|
+
console.error("[local] \u5C1A\u672A\u6388\u6743\uFF08\u627E\u4E0D\u5230 credentials.json\uFF09\u3002");
|
|
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");
|
|
11237
|
+
process.exit(1);
|
|
11238
|
+
}
|
|
11239
|
+
const plist = launchdPlistPath();
|
|
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 });
|
|
11243
|
+
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
11244
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
11245
|
+
<plist version="1.0">
|
|
11246
|
+
<dict>
|
|
11247
|
+
<key>Label</key><string>${LAUNCHD_LABEL}</string>
|
|
11248
|
+
<key>ProgramArguments</key>
|
|
11249
|
+
<array>
|
|
11250
|
+
<string>${process.execPath}</string>
|
|
11251
|
+
<string>${entry}</string>
|
|
11252
|
+
</array>
|
|
11253
|
+
<key>RunAtLoad</key><true/>
|
|
11254
|
+
<key>KeepAlive</key><true/>
|
|
11255
|
+
<key>ThrottleInterval</key><integer>30</integer>
|
|
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>
|
|
11258
|
+
</dict>
|
|
11259
|
+
</plist>
|
|
11260
|
+
`;
|
|
11261
|
+
(0, import_node_fs3.writeFileSync)(plist, xml);
|
|
11262
|
+
const uid = process.getuid?.();
|
|
11263
|
+
if (uid === void 0) {
|
|
11264
|
+
console.error("[local] \u65E0\u6CD5\u786E\u5B9A uid\uFF0Claunchd \u5B89\u88C5\u5931\u8D25");
|
|
11265
|
+
process.exit(1);
|
|
11266
|
+
}
|
|
11267
|
+
const guiDomain = `gui/${uid}`;
|
|
11268
|
+
run("launchctl", ["bootout", guiDomain, plist], true);
|
|
11269
|
+
run("launchctl", ["unload", "-w", plist], true);
|
|
11270
|
+
run("launchctl", ["bootstrap", guiDomain, plist]);
|
|
11271
|
+
run("launchctl", ["enable", `${guiDomain}/${LAUNCHD_LABEL}`], true);
|
|
11272
|
+
console.log(`[local] launchd \u670D\u52A1\u5DF2\u5B89\u88C5\u5E76\u542F\u52A8\uFF1A${LAUNCHD_LABEL}`);
|
|
11273
|
+
console.log(`[local] plist: ${plist}`);
|
|
11274
|
+
console.log("[local] \u65E5\u5FD7: ~/.cli-remote/logs/daemon.out.log / daemon.err.log");
|
|
11275
|
+
console.log("[local] \u7BA1\u7406\u670D\u52A1: launchctl kickstart -k, bootout, \u6216 cli-local uninstall");
|
|
11276
|
+
}
|
|
11277
|
+
function launchdUninstall() {
|
|
11278
|
+
const plist = launchdPlistPath();
|
|
11279
|
+
if (!(0, import_node_fs3.existsSync)(plist)) {
|
|
11280
|
+
console.log("[local] \u672A\u627E\u5230\u5DF2\u5B89\u88C5\u7684\u5E38\u9A7B\u670D\u52A1\uFF08nothing to uninstall\uFF09");
|
|
11281
|
+
process.exit(0);
|
|
11282
|
+
}
|
|
11283
|
+
const uid = process.getuid?.();
|
|
11284
|
+
const guiDomain = `gui/${uid ?? 0}`;
|
|
11285
|
+
run("launchctl", ["bootout", guiDomain, plist], true);
|
|
11286
|
+
run("launchctl", ["unload", "-w", plist], true);
|
|
11287
|
+
(0, import_node_fs3.rmSync)(plist);
|
|
11288
|
+
console.log(`[local] launchd \u670D\u52A1\u5DF2\u505C\u6B62\u5E76\u5378\u8F7D\uFF1A${LAUNCHD_LABEL}`);
|
|
11289
|
+
}
|
|
11290
|
+
if (argUrl && !argMatch && argUrl === "install") {
|
|
11291
|
+
launchdInstall(process.argv[3]);
|
|
11292
|
+
process.exit(0);
|
|
11293
|
+
}
|
|
11294
|
+
if (argUrl && !argMatch && argUrl === "uninstall") {
|
|
11295
|
+
launchdUninstall();
|
|
10923
11296
|
process.exit(0);
|
|
10924
11297
|
}
|
|
10925
11298
|
startLocal(argMatch ? { url: argUrl } : {}).catch((err) => {
|
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": {
|