@cli-remote/local 0.0.3 → 0.0.6
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 +543 -74
- 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
|
|
9943
|
-
var
|
|
9944
|
-
var
|
|
9945
|
-
var
|
|
9942
|
+
var import_node_fs4 = require("node:fs");
|
|
9943
|
+
var import_node_child_process3 = require("node:child_process");
|
|
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
|
|
@@ -9957,10 +9957,11 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
|
9957
9957
|
var wrapper_default = import_websocket.default;
|
|
9958
9958
|
|
|
9959
9959
|
// src/client.ts
|
|
9960
|
+
var import_node_child_process2 = require("node:child_process");
|
|
9960
9961
|
var import_node_readline = require("node:readline");
|
|
9961
|
-
var
|
|
9962
|
-
var
|
|
9963
|
-
var
|
|
9962
|
+
var import_node_fs3 = require("node:fs");
|
|
9963
|
+
var import_node_os5 = require("node:os");
|
|
9964
|
+
var import_node_path5 = require("node:path");
|
|
9964
9965
|
|
|
9965
9966
|
// ../shared/src/codec.ts
|
|
9966
9967
|
var import_msgpack = __toESM(require_dist(), 1);
|
|
@@ -9980,6 +9981,9 @@ var ACCESS_TOKEN_TTL_MS = 60 * 6e4;
|
|
|
9980
9981
|
var REFRESH_TOKEN_TTL_MS = 30 * 24 * 60 * 6e4;
|
|
9981
9982
|
var REFRESH_MARGIN_MS = 5 * 6e4;
|
|
9982
9983
|
var OUTPUT_BUFFER_SIZE = 500;
|
|
9984
|
+
var FILE_CHUNK_SIZE = 64 * 1024;
|
|
9985
|
+
var MAX_TRANSFER_BYTES = 500 * 1024 * 1024;
|
|
9986
|
+
var UPLOAD_DIR = "uploads";
|
|
9983
9987
|
var RECONNECT_DELAYS_MS = [1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
|
|
9984
9988
|
var DEFAULT_CONFIG_DIR = ".cli-remote";
|
|
9985
9989
|
var CREDENTIALS_FILE = "credentials.json";
|
|
@@ -10074,6 +10078,8 @@ function resolveCommand(cmd) {
|
|
|
10074
10078
|
return { file: "codex", args: [] };
|
|
10075
10079
|
case "kimi-cli":
|
|
10076
10080
|
return { file: "kimi", args: [] };
|
|
10081
|
+
case "pi":
|
|
10082
|
+
return { file: "pi", args: [] };
|
|
10077
10083
|
default:
|
|
10078
10084
|
return { file: cmd, args: [] };
|
|
10079
10085
|
}
|
|
@@ -10327,19 +10333,196 @@ function checkCommand(line, whitelist, dangerousPatterns = DANGEROUS_PATTERNS) {
|
|
|
10327
10333
|
return { allowed: true };
|
|
10328
10334
|
}
|
|
10329
10335
|
|
|
10330
|
-
// src/
|
|
10331
|
-
var
|
|
10332
|
-
var import_node_crypto = require("node:crypto");
|
|
10336
|
+
// src/file-transfer.ts
|
|
10337
|
+
var import_node_fs2 = require("node:fs");
|
|
10333
10338
|
var import_promises = require("node:fs/promises");
|
|
10334
10339
|
var import_node_os3 = require("node:os");
|
|
10335
10340
|
var import_node_path3 = require("node:path");
|
|
10341
|
+
var FileTransferManager = class _FileTransferManager {
|
|
10342
|
+
constructor(send, log) {
|
|
10343
|
+
this.send = send;
|
|
10344
|
+
this.log = log;
|
|
10345
|
+
}
|
|
10346
|
+
uploads = /* @__PURE__ */ new Map();
|
|
10347
|
+
uploadDir() {
|
|
10348
|
+
return (0, import_node_path3.join)((0, import_node_os3.homedir)(), DEFAULT_CONFIG_DIR, UPLOAD_DIR);
|
|
10349
|
+
}
|
|
10350
|
+
expandPath(p) {
|
|
10351
|
+
const home = process.env.PTY_HOME ?? (0, import_node_os3.homedir)();
|
|
10352
|
+
if (p === "~") return home;
|
|
10353
|
+
if (p.startsWith("~/")) return (0, import_node_path3.join)(home, p.slice(2));
|
|
10354
|
+
return (0, import_node_path3.resolve)(p);
|
|
10355
|
+
}
|
|
10356
|
+
/** Strip any directory components and control chars from a client filename. */
|
|
10357
|
+
static sanitizeFilename(name) {
|
|
10358
|
+
const base = (0, import_node_path3.basename)(name).replace(/[\u0000-\u001f\u007f]/g, "");
|
|
10359
|
+
return base && base !== "." && base !== ".." ? base : "upload.bin";
|
|
10360
|
+
}
|
|
10361
|
+
async handleUploadStart(frame) {
|
|
10362
|
+
const { sessionId, uploadId, filename, size } = frame;
|
|
10363
|
+
if (this.uploads.has(uploadId)) return;
|
|
10364
|
+
if (size > MAX_TRANSFER_BYTES) {
|
|
10365
|
+
this.emit({
|
|
10366
|
+
t: "upload-err",
|
|
10367
|
+
sessionId,
|
|
10368
|
+
uploadId,
|
|
10369
|
+
reason: `\u6587\u4EF6\u8FC7\u5927\uFF08>${Math.floor(MAX_TRANSFER_BYTES / 1024 / 1024)}MB\uFF09`
|
|
10370
|
+
});
|
|
10371
|
+
return;
|
|
10372
|
+
}
|
|
10373
|
+
try {
|
|
10374
|
+
const dir = this.uploadDir();
|
|
10375
|
+
await (0, import_promises.mkdir)(dir, { recursive: true });
|
|
10376
|
+
const target = await this.uniqPath(dir, _FileTransferManager.sanitizeFilename(filename));
|
|
10377
|
+
const stream = (0, import_node_fs2.createWriteStream)(target, { mode: 384 });
|
|
10378
|
+
this.uploads.set(uploadId, {
|
|
10379
|
+
uploadId,
|
|
10380
|
+
sessionId,
|
|
10381
|
+
path: target,
|
|
10382
|
+
size,
|
|
10383
|
+
received: 0,
|
|
10384
|
+
lastSeq: 0,
|
|
10385
|
+
stream
|
|
10386
|
+
});
|
|
10387
|
+
this.emit({ t: "upload-ok", sessionId, uploadId, path: target });
|
|
10388
|
+
this.log(`upload start ${uploadId} \u2192 ${target} (${size}B)`);
|
|
10389
|
+
} catch (e) {
|
|
10390
|
+
this.emit({ t: "upload-err", sessionId, uploadId, reason: e.message });
|
|
10391
|
+
}
|
|
10392
|
+
}
|
|
10393
|
+
async uniqPath(dir, name) {
|
|
10394
|
+
let candidate = (0, import_node_path3.join)(dir, name);
|
|
10395
|
+
let i = 1;
|
|
10396
|
+
while (await exists(candidate)) {
|
|
10397
|
+
const dot = name.lastIndexOf(".");
|
|
10398
|
+
const stem = dot > 0 ? name.slice(0, dot) : name;
|
|
10399
|
+
const ext = dot > 0 ? name.slice(dot) : "";
|
|
10400
|
+
candidate = (0, import_node_path3.join)(dir, `${stem} (${i++})${ext}`);
|
|
10401
|
+
}
|
|
10402
|
+
return candidate;
|
|
10403
|
+
}
|
|
10404
|
+
handleUploadChunk(frame) {
|
|
10405
|
+
const up = this.uploads.get(frame.uploadId);
|
|
10406
|
+
if (!up) return;
|
|
10407
|
+
if (frame.seq <= up.lastSeq) return;
|
|
10408
|
+
up.lastSeq = frame.seq;
|
|
10409
|
+
up.received += frame.data.byteLength;
|
|
10410
|
+
up.stream.write(Buffer.from(frame.data.buffer, frame.data.byteOffset, frame.data.byteLength));
|
|
10411
|
+
}
|
|
10412
|
+
async handleUploadEnd(frame) {
|
|
10413
|
+
const up = this.uploads.get(frame.uploadId);
|
|
10414
|
+
if (!up) return;
|
|
10415
|
+
this.uploads.delete(frame.uploadId);
|
|
10416
|
+
await new Promise((res) => up.stream.end(res));
|
|
10417
|
+
const sizeOk = up.received === up.size;
|
|
10418
|
+
this.log(`upload done ${frame.uploadId}: ${up.received}B \u2192 ${up.path}`);
|
|
10419
|
+
if (!sizeOk) {
|
|
10420
|
+
this.emit({
|
|
10421
|
+
t: "upload-err",
|
|
10422
|
+
sessionId: up.sessionId,
|
|
10423
|
+
uploadId: frame.uploadId,
|
|
10424
|
+
reason: `\u5927\u5C0F\u4E0D\u5339\u914D\uFF08\u58F0\u660E ${up.size}B\uFF0C\u5B9E\u6536 ${up.received}B\uFF09`
|
|
10425
|
+
});
|
|
10426
|
+
}
|
|
10427
|
+
}
|
|
10428
|
+
abortUpload(uploadId) {
|
|
10429
|
+
const up = this.uploads.get(uploadId);
|
|
10430
|
+
if (!up) return;
|
|
10431
|
+
this.uploads.delete(uploadId);
|
|
10432
|
+
up.stream.destroy();
|
|
10433
|
+
this.log(`upload aborted ${uploadId}`);
|
|
10434
|
+
}
|
|
10435
|
+
/** Stream a file back to the web client with mild backpressure via `send`. */
|
|
10436
|
+
async handleDownloadReq(frame, isBusy) {
|
|
10437
|
+
const sessionId = frame.sessionId;
|
|
10438
|
+
const downloadId = "dl_" + Math.random().toString(36).slice(2, 10);
|
|
10439
|
+
let abs;
|
|
10440
|
+
try {
|
|
10441
|
+
abs = this.expandPath(frame.path);
|
|
10442
|
+
const st = await (0, import_promises.stat)(abs);
|
|
10443
|
+
if (!st.isFile()) throw new Error("\u4E0D\u662F\u666E\u901A\u6587\u4EF6");
|
|
10444
|
+
if (st.size > MAX_TRANSFER_BYTES) {
|
|
10445
|
+
throw new Error(`\u6587\u4EF6\u8FC7\u5927\uFF08>${Math.floor(MAX_TRANSFER_BYTES / 1024 / 1024)}MB\uFF09`);
|
|
10446
|
+
}
|
|
10447
|
+
this.emit({
|
|
10448
|
+
t: "download-start",
|
|
10449
|
+
sessionId,
|
|
10450
|
+
downloadId,
|
|
10451
|
+
filename: (0, import_node_path3.basename)(abs),
|
|
10452
|
+
size: st.size
|
|
10453
|
+
});
|
|
10454
|
+
this.log(`download start ${downloadId} \u2190 ${abs} (${st.size}B)`);
|
|
10455
|
+
await this.streamFile(sessionId, downloadId, abs, isBusy);
|
|
10456
|
+
this.emit({ t: "download-end", sessionId, downloadId });
|
|
10457
|
+
this.log(`download done ${downloadId}: ${abs}`);
|
|
10458
|
+
} catch (e) {
|
|
10459
|
+
this.emit({
|
|
10460
|
+
t: "download-err",
|
|
10461
|
+
sessionId,
|
|
10462
|
+
downloadId,
|
|
10463
|
+
reason: e.message
|
|
10464
|
+
});
|
|
10465
|
+
}
|
|
10466
|
+
}
|
|
10467
|
+
async streamFile(sessionId, downloadId, abs, isBusy) {
|
|
10468
|
+
const handle = await (0, import_promises.open)(abs, "r");
|
|
10469
|
+
try {
|
|
10470
|
+
let seq = 0;
|
|
10471
|
+
let pos = 0;
|
|
10472
|
+
for (; ; ) {
|
|
10473
|
+
const buf = Buffer.alloc(FILE_CHUNK_SIZE);
|
|
10474
|
+
const { bytesRead } = await handle.read(buf, 0, FILE_CHUNK_SIZE, pos);
|
|
10475
|
+
if (bytesRead === 0) break;
|
|
10476
|
+
pos += bytesRead;
|
|
10477
|
+
seq++;
|
|
10478
|
+
this.emit({
|
|
10479
|
+
t: "download-chunk",
|
|
10480
|
+
sessionId,
|
|
10481
|
+
downloadId,
|
|
10482
|
+
data: new Uint8Array(buf.buffer, buf.byteOffset, bytesRead),
|
|
10483
|
+
seq
|
|
10484
|
+
});
|
|
10485
|
+
if (isBusy()) {
|
|
10486
|
+
await new Promise((res) => setImmediate(res));
|
|
10487
|
+
let spins = 0;
|
|
10488
|
+
while (isBusy() && spins++ < 2e3) {
|
|
10489
|
+
await new Promise((res) => setTimeout(res, 20));
|
|
10490
|
+
}
|
|
10491
|
+
}
|
|
10492
|
+
}
|
|
10493
|
+
} finally {
|
|
10494
|
+
await handle.close();
|
|
10495
|
+
}
|
|
10496
|
+
}
|
|
10497
|
+
abortAll() {
|
|
10498
|
+
for (const id of [...this.uploads.keys()]) this.abortUpload(id);
|
|
10499
|
+
}
|
|
10500
|
+
emit(frame) {
|
|
10501
|
+
this.send(encodeFrame(frame));
|
|
10502
|
+
}
|
|
10503
|
+
};
|
|
10504
|
+
async function exists(p) {
|
|
10505
|
+
try {
|
|
10506
|
+
await (0, import_promises.stat)(p);
|
|
10507
|
+
return true;
|
|
10508
|
+
} catch {
|
|
10509
|
+
return false;
|
|
10510
|
+
}
|
|
10511
|
+
}
|
|
10512
|
+
|
|
10513
|
+
// src/auth.ts
|
|
10514
|
+
var import_node_child_process = require("node:child_process");
|
|
10515
|
+
var import_node_crypto = require("node:crypto");
|
|
10516
|
+
var import_promises2 = require("node:fs/promises");
|
|
10517
|
+
var import_node_os4 = require("node:os");
|
|
10518
|
+
var import_node_path4 = require("node:path");
|
|
10336
10519
|
var import_qrcode = __toESM(require_lib(), 1);
|
|
10337
10520
|
function credentialsPath() {
|
|
10338
|
-
return (0,
|
|
10521
|
+
return (0, import_node_path4.join)((0, import_node_os4.homedir)(), DEFAULT_CONFIG_DIR, CREDENTIALS_FILE);
|
|
10339
10522
|
}
|
|
10340
10523
|
async function loadCredentials() {
|
|
10341
10524
|
try {
|
|
10342
|
-
const raw = JSON.parse(await (0,
|
|
10525
|
+
const raw = JSON.parse(await (0, import_promises2.readFile)(credentialsPath(), "utf-8"));
|
|
10343
10526
|
if (!raw.deviceId || !raw.accessToken || !raw.refreshToken) return null;
|
|
10344
10527
|
return raw;
|
|
10345
10528
|
} catch {
|
|
@@ -10348,16 +10531,16 @@ async function loadCredentials() {
|
|
|
10348
10531
|
}
|
|
10349
10532
|
async function saveCredentials(creds) {
|
|
10350
10533
|
const path = credentialsPath();
|
|
10351
|
-
await (0,
|
|
10352
|
-
await (0,
|
|
10534
|
+
await (0, import_promises2.mkdir)((0, import_node_path4.join)(path, ".."), { recursive: true });
|
|
10535
|
+
await (0, import_promises2.writeFile)(path, JSON.stringify(creds, null, 2) + "\n", { mode: 384 });
|
|
10353
10536
|
try {
|
|
10354
|
-
await (0,
|
|
10537
|
+
await (0, import_promises2.chmod)(path, 384);
|
|
10355
10538
|
} catch {
|
|
10356
10539
|
}
|
|
10357
10540
|
}
|
|
10358
10541
|
async function clearCredentials() {
|
|
10359
10542
|
try {
|
|
10360
|
-
await (0,
|
|
10543
|
+
await (0, import_promises2.writeFile)(credentialsPath(), "");
|
|
10361
10544
|
} catch {
|
|
10362
10545
|
}
|
|
10363
10546
|
}
|
|
@@ -10388,18 +10571,34 @@ function openBrowser(url) {
|
|
|
10388
10571
|
} catch {
|
|
10389
10572
|
}
|
|
10390
10573
|
}
|
|
10574
|
+
async function loginAndFetchRegistrationKey(baseUrl, email, password) {
|
|
10575
|
+
const login = await postJson(`${baseUrl}/api/login`, { email, password });
|
|
10576
|
+
if (login.status !== 200) {
|
|
10577
|
+
const reason = login.data?.reason;
|
|
10578
|
+
throw new AuthError(`\u767B\u5F55\u5931\u8D25: ${reason ?? login.status}`);
|
|
10579
|
+
}
|
|
10580
|
+
const token = login.data.token;
|
|
10581
|
+
if (!token) throw new AuthError("\u670D\u52A1\u7AEF\u672A\u8FD4\u56DE\u4F1A\u8BDD token");
|
|
10582
|
+
const me = await fetch(`${baseUrl}/api/me`, {
|
|
10583
|
+
headers: { authorization: `Bearer ${token}` }
|
|
10584
|
+
});
|
|
10585
|
+
if (!me.ok) throw new AuthError(`\u83B7\u53D6\u8D26\u53F7\u4FE1\u606F\u5931\u8D25 (${me.status})`);
|
|
10586
|
+
const data = await me.json();
|
|
10587
|
+
if (!data.registrationKey) throw new AuthError("\u8D26\u53F7\u4FE1\u606F\u91CC\u6CA1\u6709 registrationKey");
|
|
10588
|
+
return { registrationKey: data.registrationKey, user: data.user?.email ?? email };
|
|
10589
|
+
}
|
|
10391
10590
|
async function mergeLocalConfig(patch) {
|
|
10392
|
-
const dir = (0,
|
|
10393
|
-
const path = (0,
|
|
10591
|
+
const dir = (0, import_node_path4.join)((0, import_node_os4.homedir)(), DEFAULT_CONFIG_DIR);
|
|
10592
|
+
const path = (0, import_node_path4.join)(dir, CONFIG_FILE);
|
|
10394
10593
|
let existing = {};
|
|
10395
10594
|
try {
|
|
10396
|
-
existing = JSON.parse(await (0,
|
|
10595
|
+
existing = JSON.parse(await (0, import_promises2.readFile)(path, "utf-8"));
|
|
10397
10596
|
} catch {
|
|
10398
10597
|
}
|
|
10399
|
-
await (0,
|
|
10400
|
-
await (0,
|
|
10598
|
+
await (0, import_promises2.mkdir)(dir, { recursive: true });
|
|
10599
|
+
await (0, import_promises2.writeFile)(path, JSON.stringify({ ...existing, ...patch }, null, 2) + "\n");
|
|
10401
10600
|
}
|
|
10402
|
-
var sleep = (ms) => new Promise((
|
|
10601
|
+
var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
10403
10602
|
var AuthError = class extends Error {
|
|
10404
10603
|
};
|
|
10405
10604
|
async function deviceFlowAuthorize(baseUrl, registrationKey, deviceId) {
|
|
@@ -10411,7 +10610,7 @@ async function deviceFlowAuthorize(baseUrl, registrationKey, deviceId) {
|
|
|
10411
10610
|
const res = await postJson(`${baseUrl}/oauth/device_authorization`, {
|
|
10412
10611
|
registrationKey,
|
|
10413
10612
|
device_id: deviceId,
|
|
10414
|
-
device_name: (0,
|
|
10613
|
+
device_name: (0, import_node_os4.hostname)(),
|
|
10415
10614
|
platform: process.platform
|
|
10416
10615
|
});
|
|
10417
10616
|
if (res.status !== 200) {
|
|
@@ -10514,9 +10713,9 @@ async function ensureCredentials(baseUrl, registrationKey) {
|
|
|
10514
10713
|
|
|
10515
10714
|
// src/client.ts
|
|
10516
10715
|
async function loadConfig() {
|
|
10517
|
-
const path = (0,
|
|
10716
|
+
const path = (0, import_node_path5.join)((0, import_node_os5.homedir)(), DEFAULT_CONFIG_DIR, CONFIG_FILE);
|
|
10518
10717
|
try {
|
|
10519
|
-
return JSON.parse(
|
|
10718
|
+
return JSON.parse((0, import_node_fs3.readFileSync)(path, "utf-8"));
|
|
10520
10719
|
} catch {
|
|
10521
10720
|
return {};
|
|
10522
10721
|
}
|
|
@@ -10530,10 +10729,32 @@ function buildWhitelist(cfg) {
|
|
|
10530
10729
|
function isTTY() {
|
|
10531
10730
|
return process.stdin.isTTY === true;
|
|
10532
10731
|
}
|
|
10732
|
+
function detectCommands() {
|
|
10733
|
+
const bins = [
|
|
10734
|
+
["claude", "claude"],
|
|
10735
|
+
["codex", "codex"],
|
|
10736
|
+
["kimi-cli", "kimi"],
|
|
10737
|
+
["pi", "pi"]
|
|
10738
|
+
];
|
|
10739
|
+
const found = ["shell"];
|
|
10740
|
+
for (const [cmd, bin] of bins) {
|
|
10741
|
+
let ok = false;
|
|
10742
|
+
if (process.platform === "win32") {
|
|
10743
|
+
ok = (0, import_node_child_process2.spawnSync)("where", [bin], { timeout: 5e3 }).status === 0;
|
|
10744
|
+
} else {
|
|
10745
|
+
const shell = process.env.SHELL ?? "/bin/bash";
|
|
10746
|
+
ok = (0, import_node_child_process2.spawnSync)(shell, ["-l", "-c", `command -v ${bin}`], {
|
|
10747
|
+
timeout: 5e3
|
|
10748
|
+
}).status === 0;
|
|
10749
|
+
}
|
|
10750
|
+
if (ok) found.push(cmd);
|
|
10751
|
+
}
|
|
10752
|
+
return found;
|
|
10753
|
+
}
|
|
10533
10754
|
async function readInput(prompt) {
|
|
10534
10755
|
const rl = (0, import_node_readline.createInterface)({ input: process.stdin, output: process.stdout });
|
|
10535
10756
|
try {
|
|
10536
|
-
return await new Promise((
|
|
10757
|
+
return await new Promise((resolve2) => rl.question(prompt, (answer) => resolve2(answer)));
|
|
10537
10758
|
} finally {
|
|
10538
10759
|
rl.close();
|
|
10539
10760
|
}
|
|
@@ -10568,18 +10789,42 @@ async function setupWizard(config, opts) {
|
|
|
10568
10789
|
const base = baseUrlFromWsUrl(url);
|
|
10569
10790
|
console.log("");
|
|
10570
10791
|
console.log("[local] \u7F3A\u5C11 registrationKey\u3002");
|
|
10571
|
-
console.log(`[local] \u5DF2\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u8BF7\u767B\u5F55 ${base} \u5E76\u5728\u300C\u6211\u7684\u8BBE\u5907\u300D\u9875\u590D\u5236 registrationKey`);
|
|
10572
|
-
openBrowser(base);
|
|
10573
10792
|
if (!isTTY()) {
|
|
10793
|
+
openBrowser(base);
|
|
10574
10794
|
console.log("[local] \u5F53\u524D\u975E\u4EA4\u4E92\u7EC8\u7AEF\uFF1A\u62FF\u5230 key \u540E\u5199\u5165 ~/.cli-remote/config.json \u518D\u8FD0\u884C\u3002");
|
|
10575
10795
|
return null;
|
|
10576
10796
|
}
|
|
10577
|
-
|
|
10578
|
-
|
|
10579
|
-
|
|
10580
|
-
|
|
10797
|
+
console.log(" 1) \u767B\u5F55\u8D26\u53F7\u81EA\u52A8\u83B7\u53D6\uFF08\u63A8\u8350\uFF09");
|
|
10798
|
+
console.log(" 2) \u4ECE\u7F51\u9875\u300C\u63A7\u5236\u9762\u677F\u300D\u590D\u5236\u7C98\u8D34");
|
|
10799
|
+
const mode = (await readInput("\u9009\u62E9 [1]: ")).trim();
|
|
10800
|
+
if (mode === "2") {
|
|
10801
|
+
openBrowser(base);
|
|
10802
|
+
console.log(`[local] \u5DF2\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u8BF7\u767B\u5F55 ${base} \u5E76\u5728\u300C\u63A7\u5236\u9762\u677F\u300D\u9875\u590D\u5236 registrationKey`);
|
|
10803
|
+
const ans = (await readInput("\u7C98\u8D34 registrationKey: ")).trim();
|
|
10804
|
+
if (!ans) {
|
|
10805
|
+
console.log("[local] \u672A\u63D0\u4F9B registrationKey\uFF0C\u9000\u51FA\u3002");
|
|
10806
|
+
return null;
|
|
10807
|
+
}
|
|
10808
|
+
registrationKey = ans;
|
|
10809
|
+
} else {
|
|
10810
|
+
for (; ; ) {
|
|
10811
|
+
const email = (await readInput("\u90AE\u7BB1: ")).trim();
|
|
10812
|
+
const password = (await readInput("\u5BC6\u7801: ")).trim();
|
|
10813
|
+
if (!email || !password) {
|
|
10814
|
+
console.log("[local] \u90AE\u7BB1\u6216\u5BC6\u7801\u4E3A\u7A7A\uFF0C\u91CD\u8BD5\uFF08\u6216 Ctrl+C \u9000\u51FA\uFF09\u3002");
|
|
10815
|
+
continue;
|
|
10816
|
+
}
|
|
10817
|
+
try {
|
|
10818
|
+
const res = await loginAndFetchRegistrationKey(base, email, password);
|
|
10819
|
+
registrationKey = res.registrationKey;
|
|
10820
|
+
console.log(`[local] \u5DF2\u767B\u5F55 ${res.user}\uFF0C\u83B7\u53D6 registrationKey \u6210\u529F`);
|
|
10821
|
+
break;
|
|
10822
|
+
} catch (e) {
|
|
10823
|
+
console.error(`[local] ${e.message}`);
|
|
10824
|
+
console.log("[local] \u91CD\u8BD5\uFF08\u6216 Ctrl+C \u9000\u51FA\uFF09\u3002");
|
|
10825
|
+
}
|
|
10826
|
+
}
|
|
10581
10827
|
}
|
|
10582
|
-
registrationKey = ans;
|
|
10583
10828
|
changed = true;
|
|
10584
10829
|
}
|
|
10585
10830
|
if (changed) {
|
|
@@ -10603,10 +10848,17 @@ async function startLocal(opts = {}) {
|
|
|
10603
10848
|
const pty = new PtyManager();
|
|
10604
10849
|
const loggers = /* @__PURE__ */ new Map();
|
|
10605
10850
|
const lineBuffers = /* @__PURE__ */ new Map();
|
|
10851
|
+
const transfers = new FileTransferManager(
|
|
10852
|
+
(data) => safeSend(data),
|
|
10853
|
+
(msg) => console.log(`[local] ${msg}`)
|
|
10854
|
+
);
|
|
10606
10855
|
let credentials = await ensureCredentials(baseUrl, registrationKey);
|
|
10856
|
+
const commands = detectCommands();
|
|
10857
|
+
if (opts.daemon) writeGatewayPid();
|
|
10607
10858
|
console.log(`[local] connecting to ${url}`);
|
|
10608
10859
|
console.log(`[local] deviceId=${credentials.deviceId}`);
|
|
10609
10860
|
console.log(`[local] whitelist: ${whitelist.size} commands`);
|
|
10861
|
+
console.log(`[local] available CLIs: ${commands.join(", ")}`);
|
|
10610
10862
|
let ws = null;
|
|
10611
10863
|
let heartbeatTimer = null;
|
|
10612
10864
|
let reconnectTimer = null;
|
|
@@ -10622,7 +10874,8 @@ async function startLocal(opts = {}) {
|
|
|
10622
10874
|
t: "auth",
|
|
10623
10875
|
role: "bridge",
|
|
10624
10876
|
deviceId: credentials.deviceId,
|
|
10625
|
-
token: credentials.accessToken
|
|
10877
|
+
token: credentials.accessToken,
|
|
10878
|
+
commands
|
|
10626
10879
|
})
|
|
10627
10880
|
);
|
|
10628
10881
|
}
|
|
@@ -10677,6 +10930,8 @@ async function startLocal(opts = {}) {
|
|
|
10677
10930
|
userExitCode = code;
|
|
10678
10931
|
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
10679
10932
|
reconnectTimer = null;
|
|
10933
|
+
if (opts.daemon) removeGatewayPid();
|
|
10934
|
+
transfers.abortAll();
|
|
10680
10935
|
pty.killAll();
|
|
10681
10936
|
for (const [, logger] of loggers) logger.logExit(-1);
|
|
10682
10937
|
loggers.clear();
|
|
@@ -10726,6 +10981,21 @@ async function startLocal(opts = {}) {
|
|
|
10726
10981
|
case "replay-req":
|
|
10727
10982
|
handleReplay(frame);
|
|
10728
10983
|
break;
|
|
10984
|
+
case "upload-start":
|
|
10985
|
+
void transfers.handleUploadStart(frame);
|
|
10986
|
+
break;
|
|
10987
|
+
case "upload-chunk":
|
|
10988
|
+
transfers.handleUploadChunk(frame);
|
|
10989
|
+
break;
|
|
10990
|
+
case "upload-end":
|
|
10991
|
+
void transfers.handleUploadEnd(frame);
|
|
10992
|
+
break;
|
|
10993
|
+
case "download-req":
|
|
10994
|
+
void transfers.handleDownloadReq(
|
|
10995
|
+
frame,
|
|
10996
|
+
() => ws ? ws.bufferedAmount > 4 * 1024 * 1024 : false
|
|
10997
|
+
);
|
|
10998
|
+
break;
|
|
10729
10999
|
default:
|
|
10730
11000
|
console.log("[local] unhandled frame:", frame.t);
|
|
10731
11001
|
}
|
|
@@ -10878,7 +11148,8 @@ async function startLocal(opts = {}) {
|
|
|
10878
11148
|
encodeFrame({
|
|
10879
11149
|
t: "replay-res",
|
|
10880
11150
|
sessionId: frame.sessionId,
|
|
10881
|
-
frames
|
|
11151
|
+
frames,
|
|
11152
|
+
exists: pty.has(frame.sessionId)
|
|
10882
11153
|
})
|
|
10883
11154
|
);
|
|
10884
11155
|
}
|
|
@@ -10899,6 +11170,37 @@ function toUint8(raw) {
|
|
|
10899
11170
|
}
|
|
10900
11171
|
throw new Error("unexpected raw type");
|
|
10901
11172
|
}
|
|
11173
|
+
function gatewayPidFile() {
|
|
11174
|
+
return (0, import_node_path5.join)((0, import_node_os5.homedir)(), DEFAULT_CONFIG_DIR, "gateway.pid");
|
|
11175
|
+
}
|
|
11176
|
+
function writeGatewayPid() {
|
|
11177
|
+
(0, import_node_fs3.mkdirSync)((0, import_node_path5.join)((0, import_node_os5.homedir)(), DEFAULT_CONFIG_DIR), { recursive: true });
|
|
11178
|
+
(0, import_node_fs3.writeFileSync)(gatewayPidFile(), String(process.pid));
|
|
11179
|
+
}
|
|
11180
|
+
function removeGatewayPid() {
|
|
11181
|
+
try {
|
|
11182
|
+
(0, import_node_fs3.rmSync)(gatewayPidFile());
|
|
11183
|
+
} catch {
|
|
11184
|
+
}
|
|
11185
|
+
}
|
|
11186
|
+
function gatewayPid() {
|
|
11187
|
+
try {
|
|
11188
|
+
const pid = Number((0, import_node_fs3.readFileSync)(gatewayPidFile(), "utf-8").trim());
|
|
11189
|
+
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
11190
|
+
} catch {
|
|
11191
|
+
return null;
|
|
11192
|
+
}
|
|
11193
|
+
}
|
|
11194
|
+
function gatewayAlive() {
|
|
11195
|
+
const pid = gatewayPid();
|
|
11196
|
+
if (pid === null) return false;
|
|
11197
|
+
try {
|
|
11198
|
+
process.kill(pid, 0);
|
|
11199
|
+
return true;
|
|
11200
|
+
} catch {
|
|
11201
|
+
return false;
|
|
11202
|
+
}
|
|
11203
|
+
}
|
|
10902
11204
|
|
|
10903
11205
|
// src/index.ts
|
|
10904
11206
|
var import_meta = {};
|
|
@@ -10917,15 +11219,15 @@ function resolveHere() {
|
|
|
10917
11219
|
if (DEBUG) console.error("[debug] cannot resolve script path");
|
|
10918
11220
|
return;
|
|
10919
11221
|
}
|
|
10920
|
-
const hereDir = (0,
|
|
11222
|
+
const hereDir = (0, import_node_path6.dirname)(here);
|
|
10921
11223
|
const candidates = [
|
|
10922
|
-
(0,
|
|
10923
|
-
(0,
|
|
10924
|
-
(0,
|
|
11224
|
+
(0, import_node_path6.join)(hereDir, "..", "node_modules", "node-pty", "prebuilds"),
|
|
11225
|
+
(0, import_node_path6.join)(hereDir, "..", "..", "node-pty", "prebuilds"),
|
|
11226
|
+
(0, import_node_path6.join)(hereDir, "..", "..", "..", "node_modules", "node-pty", "prebuilds")
|
|
10925
11227
|
];
|
|
10926
11228
|
let prebuildsDir = null;
|
|
10927
11229
|
for (const c of candidates) {
|
|
10928
|
-
if ((0,
|
|
11230
|
+
if ((0, import_node_fs4.existsSync)(c)) {
|
|
10929
11231
|
prebuildsDir = c;
|
|
10930
11232
|
break;
|
|
10931
11233
|
}
|
|
@@ -10935,11 +11237,11 @@ function resolveHere() {
|
|
|
10935
11237
|
return;
|
|
10936
11238
|
}
|
|
10937
11239
|
let n = 0;
|
|
10938
|
-
for (const sub of (0,
|
|
10939
|
-
const helper = (0,
|
|
10940
|
-
if ((0,
|
|
11240
|
+
for (const sub of (0, import_node_fs4.readdirSync)(prebuildsDir)) {
|
|
11241
|
+
const helper = (0, import_node_path6.join)(prebuildsDir, sub, "spawn-helper");
|
|
11242
|
+
if ((0, import_node_fs4.existsSync)(helper)) {
|
|
10941
11243
|
try {
|
|
10942
|
-
(0,
|
|
11244
|
+
(0, import_node_fs4.chmodSync)(helper, 493);
|
|
10943
11245
|
n++;
|
|
10944
11246
|
} catch {
|
|
10945
11247
|
}
|
|
@@ -10986,20 +11288,20 @@ example:
|
|
|
10986
11288
|
}
|
|
10987
11289
|
var LAUNCHD_LABEL = "net.cli-remote.local";
|
|
10988
11290
|
function launchdPlistPath() {
|
|
10989
|
-
return (0,
|
|
11291
|
+
return (0, import_node_path6.join)((0, import_node_os6.homedir)(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
10990
11292
|
}
|
|
10991
11293
|
function entryScript() {
|
|
10992
11294
|
const a1 = process.argv[1];
|
|
10993
11295
|
if (!a1 || a1.endsWith(".ts")) return null;
|
|
10994
11296
|
try {
|
|
10995
|
-
return (0,
|
|
11297
|
+
return (0, import_node_fs4.realpathSync)(a1);
|
|
10996
11298
|
} catch {
|
|
10997
11299
|
return a1;
|
|
10998
11300
|
}
|
|
10999
11301
|
}
|
|
11000
11302
|
function run(cmd, args, okToFail = false) {
|
|
11001
11303
|
try {
|
|
11002
|
-
return (0,
|
|
11304
|
+
return (0, import_node_child_process3.execFileSync)(cmd, args, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
|
|
11003
11305
|
} catch (e) {
|
|
11004
11306
|
if (okToFail) return null;
|
|
11005
11307
|
throw e;
|
|
@@ -11010,7 +11312,7 @@ function launchdInstall(urlArg) {
|
|
|
11010
11312
|
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
11313
|
process.exit(1);
|
|
11012
11314
|
}
|
|
11013
|
-
const home = (0,
|
|
11315
|
+
const home = (0, import_node_os6.homedir)();
|
|
11014
11316
|
const entry = entryScript();
|
|
11015
11317
|
if (!entry) {
|
|
11016
11318
|
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 +11320,28 @@ function launchdInstall(urlArg) {
|
|
|
11018
11320
|
process.exit(1);
|
|
11019
11321
|
}
|
|
11020
11322
|
if (urlArg) {
|
|
11021
|
-
const cfgDir = (0,
|
|
11022
|
-
(0,
|
|
11023
|
-
const cfgPath = (0,
|
|
11323
|
+
const cfgDir = (0, import_node_path6.join)(home, DEFAULT_CONFIG_DIR);
|
|
11324
|
+
(0, import_node_fs4.mkdirSync)(cfgDir, { recursive: true });
|
|
11325
|
+
const cfgPath = (0, import_node_path6.join)(cfgDir, "config.json");
|
|
11024
11326
|
let cfg = {};
|
|
11025
11327
|
try {
|
|
11026
|
-
cfg = JSON.parse((0,
|
|
11328
|
+
cfg = JSON.parse((0, import_node_fs4.readFileSync)(cfgPath, "utf-8"));
|
|
11027
11329
|
} catch {
|
|
11028
11330
|
}
|
|
11029
11331
|
cfg.relayUrl = urlArg;
|
|
11030
|
-
(0,
|
|
11332
|
+
(0, import_node_fs4.writeFileSync)(cfgPath, JSON.stringify(cfg, null, 2) + "\n");
|
|
11031
11333
|
console.log(`[local] relayUrl \u5DF2\u5199\u5165 ${cfgPath}`);
|
|
11032
11334
|
}
|
|
11033
|
-
const credPath = (0,
|
|
11034
|
-
if (!(0,
|
|
11335
|
+
const credPath = (0, import_node_path6.join)(home, DEFAULT_CONFIG_DIR, CREDENTIALS_FILE);
|
|
11336
|
+
if (!(0, import_node_fs4.existsSync)(credPath)) {
|
|
11035
11337
|
console.error("[local] \u5C1A\u672A\u6388\u6743\uFF08\u627E\u4E0D\u5230 credentials.json\uFF09\u3002");
|
|
11036
11338
|
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
11339
|
process.exit(1);
|
|
11038
11340
|
}
|
|
11039
11341
|
const plist = launchdPlistPath();
|
|
11040
|
-
const logDir = (0,
|
|
11041
|
-
(0,
|
|
11042
|
-
(0,
|
|
11342
|
+
const logDir = (0, import_node_path6.join)(home, DEFAULT_CONFIG_DIR, "logs");
|
|
11343
|
+
(0, import_node_fs4.mkdirSync)((0, import_node_path6.dirname)(plist), { recursive: true });
|
|
11344
|
+
(0, import_node_fs4.mkdirSync)(logDir, { recursive: true });
|
|
11043
11345
|
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
11044
11346
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
11045
11347
|
<plist version="1.0">
|
|
@@ -11053,12 +11355,12 @@ function launchdInstall(urlArg) {
|
|
|
11053
11355
|
<key>RunAtLoad</key><true/>
|
|
11054
11356
|
<key>KeepAlive</key><true/>
|
|
11055
11357
|
<key>ThrottleInterval</key><integer>30</integer>
|
|
11056
|
-
<key>StandardOutPath</key><string>${(0,
|
|
11057
|
-
<key>StandardErrorPath</key><string>${(0,
|
|
11358
|
+
<key>StandardOutPath</key><string>${(0, import_node_path6.join)(logDir, "daemon.out.log")}</string>
|
|
11359
|
+
<key>StandardErrorPath</key><string>${(0, import_node_path6.join)(logDir, "daemon.err.log")}</string>
|
|
11058
11360
|
</dict>
|
|
11059
11361
|
</plist>
|
|
11060
11362
|
`;
|
|
11061
|
-
(0,
|
|
11363
|
+
(0, import_node_fs4.writeFileSync)(plist, xml);
|
|
11062
11364
|
const uid = process.getuid?.();
|
|
11063
11365
|
if (uid === void 0) {
|
|
11064
11366
|
console.error("[local] \u65E0\u6CD5\u786E\u5B9A uid\uFF0Claunchd \u5B89\u88C5\u5931\u8D25");
|
|
@@ -11076,7 +11378,7 @@ function launchdInstall(urlArg) {
|
|
|
11076
11378
|
}
|
|
11077
11379
|
function launchdUninstall() {
|
|
11078
11380
|
const plist = launchdPlistPath();
|
|
11079
|
-
if (!(0,
|
|
11381
|
+
if (!(0, import_node_fs4.existsSync)(plist)) {
|
|
11080
11382
|
console.log("[local] \u672A\u627E\u5230\u5DF2\u5B89\u88C5\u7684\u5E38\u9A7B\u670D\u52A1\uFF08nothing to uninstall\uFF09");
|
|
11081
11383
|
process.exit(0);
|
|
11082
11384
|
}
|
|
@@ -11084,7 +11386,7 @@ function launchdUninstall() {
|
|
|
11084
11386
|
const guiDomain = `gui/${uid ?? 0}`;
|
|
11085
11387
|
run("launchctl", ["bootout", guiDomain, plist], true);
|
|
11086
11388
|
run("launchctl", ["unload", "-w", plist], true);
|
|
11087
|
-
(0,
|
|
11389
|
+
(0, import_node_fs4.rmSync)(plist);
|
|
11088
11390
|
console.log(`[local] launchd \u670D\u52A1\u5DF2\u505C\u6B62\u5E76\u5378\u8F7D\uFF1A${LAUNCHD_LABEL}`);
|
|
11089
11391
|
}
|
|
11090
11392
|
if (argUrl && !argMatch && argUrl === "install") {
|
|
@@ -11095,6 +11397,173 @@ if (argUrl && !argMatch && argUrl === "uninstall") {
|
|
|
11095
11397
|
launchdUninstall();
|
|
11096
11398
|
process.exit(0);
|
|
11097
11399
|
}
|
|
11400
|
+
if (argUrl === "gateway") {
|
|
11401
|
+
let gatewayLogFile = function() {
|
|
11402
|
+
return (0, import_node_path6.join)((0, import_node_os6.homedir)(), DEFAULT_CONFIG_DIR, "logs", "gateway.log");
|
|
11403
|
+
}, stopWorker = function() {
|
|
11404
|
+
const pid = gatewayPid();
|
|
11405
|
+
if (pid === null || !gatewayAlive()) {
|
|
11406
|
+
(0, import_node_fs4.rmSync)((0, import_node_path6.join)((0, import_node_os6.homedir)(), DEFAULT_CONFIG_DIR, "gateway.pid"), { force: true });
|
|
11407
|
+
return;
|
|
11408
|
+
}
|
|
11409
|
+
try {
|
|
11410
|
+
process.kill(pid, "SIGTERM");
|
|
11411
|
+
} catch {
|
|
11412
|
+
}
|
|
11413
|
+
const t0 = Date.now();
|
|
11414
|
+
while (Date.now() - t0 < 5e3 && gatewayAlive()) {
|
|
11415
|
+
const end = Date.now() + 150;
|
|
11416
|
+
while (Date.now() < end) {
|
|
11417
|
+
}
|
|
11418
|
+
}
|
|
11419
|
+
(0, import_node_fs4.rmSync)((0, import_node_path6.join)((0, import_node_os6.homedir)(), DEFAULT_CONFIG_DIR, "gateway.pid"), { force: true });
|
|
11420
|
+
}, gatewayStop = function() {
|
|
11421
|
+
const pid = gatewayPid();
|
|
11422
|
+
const wasRunning = gatewayAlive();
|
|
11423
|
+
stopWorker();
|
|
11424
|
+
console.log(wasRunning ? `[gateway] stopped (pid ${pid ?? "?"})` : "[gateway] not running");
|
|
11425
|
+
process.exit(0);
|
|
11426
|
+
}, gatewayStatus = function() {
|
|
11427
|
+
if (!gatewayAlive()) {
|
|
11428
|
+
console.log("[gateway] stopped");
|
|
11429
|
+
process.exit(1);
|
|
11430
|
+
}
|
|
11431
|
+
const pid = gatewayPid();
|
|
11432
|
+
let hub = "(\u672A\u914D\u7F6E)";
|
|
11433
|
+
try {
|
|
11434
|
+
const cfg = JSON.parse((0, import_node_fs4.readFileSync)((0, import_node_path6.join)((0, import_node_os6.homedir)(), DEFAULT_CONFIG_DIR, "config.json"), "utf-8"));
|
|
11435
|
+
hub = cfg.relayUrl ?? hub;
|
|
11436
|
+
} catch {
|
|
11437
|
+
}
|
|
11438
|
+
console.log(`[gateway] running (pid ${pid})`);
|
|
11439
|
+
console.log(`[gateway] hub: ${hub}`);
|
|
11440
|
+
console.log(`[gateway] \u65E5\u5FD7: ${gatewayLogFile()}`);
|
|
11441
|
+
process.exit(0);
|
|
11442
|
+
}, gatewayLogs = function() {
|
|
11443
|
+
const follow = rest.includes("-f") || rest.includes("--follow");
|
|
11444
|
+
const li = rest.findIndex((a) => a === "-n" || a === "--lines");
|
|
11445
|
+
const lines = li >= 0 ? Number(rest[li + 1]) || 50 : 50;
|
|
11446
|
+
const file = gatewayLogFile();
|
|
11447
|
+
if (!(0, import_node_fs4.existsSync)(file)) {
|
|
11448
|
+
console.log(`[gateway] \u6682\u65E0\u65E5\u5FD7\uFF08${file} \u4E0D\u5B58\u5728\uFF09`);
|
|
11449
|
+
process.exit(0);
|
|
11450
|
+
}
|
|
11451
|
+
const tail = (0, import_node_fs4.readFileSync)(file, "utf-8").trimEnd().split("\n").slice(-lines);
|
|
11452
|
+
console.log(tail.join("\n"));
|
|
11453
|
+
if (!follow) process.exit(0);
|
|
11454
|
+
let size = (0, import_node_fs4.statSync)(file).size;
|
|
11455
|
+
console.log("--- following (Ctrl+C \u9000\u51FA) ---");
|
|
11456
|
+
setInterval(() => {
|
|
11457
|
+
try {
|
|
11458
|
+
const st = (0, import_node_fs4.statSync)(file);
|
|
11459
|
+
if (st.size > size) {
|
|
11460
|
+
const fd = (0, import_node_fs4.openSync)(file, "r");
|
|
11461
|
+
const buf = Buffer.alloc(st.size - size);
|
|
11462
|
+
(0, import_node_fs4.readSync)(fd, buf, 0, buf.length, size);
|
|
11463
|
+
(0, import_node_fs4.closeSync)(fd);
|
|
11464
|
+
size = st.size;
|
|
11465
|
+
process.stdout.write(buf.toString("utf-8"));
|
|
11466
|
+
} else if (st.size < size) {
|
|
11467
|
+
size = 0;
|
|
11468
|
+
}
|
|
11469
|
+
} catch {
|
|
11470
|
+
}
|
|
11471
|
+
}, 1e3);
|
|
11472
|
+
};
|
|
11473
|
+
gatewayLogFile2 = gatewayLogFile, stopWorker2 = stopWorker, gatewayStop2 = gatewayStop, gatewayStatus2 = gatewayStatus, gatewayLogs2 = gatewayLogs;
|
|
11474
|
+
const action = process.argv[3] ?? "";
|
|
11475
|
+
const rest = process.argv.slice(4);
|
|
11476
|
+
const hubArg = (() => {
|
|
11477
|
+
const i = rest.indexOf("--hub");
|
|
11478
|
+
return i >= 0 ? rest[i + 1] : void 0;
|
|
11479
|
+
})();
|
|
11480
|
+
async function gatewayStart() {
|
|
11481
|
+
if (gatewayAlive()) {
|
|
11482
|
+
console.log(`[gateway] already running (pid ${gatewayPid()})`);
|
|
11483
|
+
process.exit(0);
|
|
11484
|
+
}
|
|
11485
|
+
const home = (0, import_node_os6.homedir)();
|
|
11486
|
+
const entry = entryScript();
|
|
11487
|
+
const cfgDir = (0, import_node_path6.join)(home, DEFAULT_CONFIG_DIR);
|
|
11488
|
+
const credPath = (0, import_node_path6.join)(cfgDir, CREDENTIALS_FILE);
|
|
11489
|
+
const cfgPath = (0, import_node_path6.join)(cfgDir, "config.json");
|
|
11490
|
+
const hasCfg = (0, import_node_fs4.existsSync)(cfgPath);
|
|
11491
|
+
if (!entry) {
|
|
11492
|
+
console.error("[gateway] \u6E90\u7801\uFF08tsx\uFF09\u6A21\u5F0F\u4E0D\u652F\u6301\u540E\u53F0\u8FD0\u884C\uFF1B\u8BF7\u7528 npm \u5B89\u88C5\u7248\uFF1Anpm i -g @cli-remote/local");
|
|
11493
|
+
process.exit(1);
|
|
11494
|
+
}
|
|
11495
|
+
if (!hasCfg || !(0, import_node_fs4.existsSync)(credPath)) {
|
|
11496
|
+
console.error("[gateway] \u5C1A\u672A\u914D\u7F6E/\u6388\u6743\u3002\u8BF7\u5148\u4EA4\u4E92\u5F0F\u8FD0\u884C\u4E00\u6B21 cli-local \u5B8C\u6210\u767B\u5F55\u4E0E\u8BBE\u5907\u6388\u6743\u3002");
|
|
11497
|
+
process.exit(1);
|
|
11498
|
+
}
|
|
11499
|
+
(0, import_node_fs4.mkdirSync)((0, import_node_path6.dirname)(gatewayLogFile()), { recursive: true });
|
|
11500
|
+
const out = (0, import_node_fs4.openSync)(gatewayLogFile(), "a");
|
|
11501
|
+
const env = {};
|
|
11502
|
+
for (const [k, v] of Object.entries(process.env)) if (v !== void 0) env[k] = v;
|
|
11503
|
+
const args = [entry, "gateway", "run"];
|
|
11504
|
+
if (hubArg) args.push("--hub", hubArg);
|
|
11505
|
+
const child = (0, import_node_child_process3.spawn)(process.execPath, args, {
|
|
11506
|
+
detached: true,
|
|
11507
|
+
stdio: ["ignore", out, out],
|
|
11508
|
+
env
|
|
11509
|
+
});
|
|
11510
|
+
child.unref();
|
|
11511
|
+
console.log(`[gateway] started (pid ${child.pid})`);
|
|
11512
|
+
console.log(`[gateway] \u65E5\u5FD7: ${gatewayLogFile()}`);
|
|
11513
|
+
console.log("[gateway] \u72B6\u6001: cli-local gateway status");
|
|
11514
|
+
}
|
|
11515
|
+
switch (action) {
|
|
11516
|
+
case "start":
|
|
11517
|
+
gatewayStart().then(() => process.exit(0)).catch((e) => {
|
|
11518
|
+
console.error(`[gateway] ${e.message}`);
|
|
11519
|
+
process.exit(1);
|
|
11520
|
+
});
|
|
11521
|
+
break;
|
|
11522
|
+
case "stop":
|
|
11523
|
+
gatewayStop();
|
|
11524
|
+
break;
|
|
11525
|
+
case "restart":
|
|
11526
|
+
stopWorker();
|
|
11527
|
+
gatewayStart().then(() => process.exit(0)).catch((e) => {
|
|
11528
|
+
console.error(`[gateway] ${e.message}`);
|
|
11529
|
+
process.exit(1);
|
|
11530
|
+
});
|
|
11531
|
+
break;
|
|
11532
|
+
case "status":
|
|
11533
|
+
gatewayStatus();
|
|
11534
|
+
break;
|
|
11535
|
+
case "logs":
|
|
11536
|
+
gatewayLogs();
|
|
11537
|
+
break;
|
|
11538
|
+
case "run":
|
|
11539
|
+
startLocal({ url: hubArg, daemon: true }).catch((err) => {
|
|
11540
|
+
if (err instanceof AuthError) console.error(`[local] ${err.message}`);
|
|
11541
|
+
else console.error("[local] fatal:", err);
|
|
11542
|
+
process.exit(1);
|
|
11543
|
+
});
|
|
11544
|
+
break;
|
|
11545
|
+
default:
|
|
11546
|
+
console.log(`cli-local gateway \u2014 \u540E\u53F0\u8FD0\u884C\u7BA1\u7406
|
|
11547
|
+
|
|
11548
|
+
usage:
|
|
11549
|
+
cli-local gateway start [--hub URL] \u540E\u53F0\u542F\u52A8\uFF08\u81EA\u52A8\u91CD\u8FDE\uFF09
|
|
11550
|
+
cli-local gateway stop \u505C\u6B62
|
|
11551
|
+
cli-local gateway restart \u91CD\u542F
|
|
11552
|
+
cli-local gateway status \u8FD0\u884C\u72B6\u6001
|
|
11553
|
+
cli-local gateway logs [-f] [-n N] \u67E5\u770B\u65E5\u5FD7\uFF08-f \u8DDF\u968F\uFF09
|
|
11554
|
+
cli-local gateway run [--hub URL] \u524D\u53F0\u8FD0\u884C\uFF08\u4F9B start \u62C9\u8D77\uFF09
|
|
11555
|
+
|
|
11556
|
+
\u8BF4\u660E\uFF1A\u540E\u53F0\u8FDB\u7A0B\u7531 pid \u6587\u4EF6\u7BA1\u7406\uFF08~/.cli-remote/gateway.pid\uFF09\uFF0C\u65E5\u5FD7\u5728
|
|
11557
|
+
~/.cli-remote/logs/gateway.log\u3002\u9996\u6B21\u4F7F\u7528\u8BF7\u5148\u4EA4\u4E92\u5F0F\u8FD0\u884C cli-local
|
|
11558
|
+
\u5B8C\u6210\u767B\u5F55\u4E0E\u8BBE\u5907\u6388\u6743\u3002macOS \u60F3\u5F00\u673A\u81EA\u542F\u7528 launchd\uFF1Acli-local install\u3002`);
|
|
11559
|
+
process.exit(action ? 1 : 0);
|
|
11560
|
+
}
|
|
11561
|
+
}
|
|
11562
|
+
var gatewayLogFile2;
|
|
11563
|
+
var stopWorker2;
|
|
11564
|
+
var gatewayStop2;
|
|
11565
|
+
var gatewayStatus2;
|
|
11566
|
+
var gatewayLogs2;
|
|
11098
11567
|
startLocal(argMatch ? { url: argUrl } : {}).catch((err) => {
|
|
11099
11568
|
if (err instanceof AuthError) {
|
|
11100
11569
|
console.error(`[local] ${err.message}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cli-remote/local",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
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": {
|