alink-cli 0.11.6 → 0.11.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/bin/agentlink.js +26 -3
- package/dist/bin.mjs +24 -2
- package/dist/bin.mjs.map +1 -1
- package/dist/ui.js +47 -168
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -17,11 +17,11 @@ AgentLink 让你随时从手机或浏览器继续使用运行在自己电脑上
|
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
19
|
npm install -g alink-cli
|
|
20
|
-
alink
|
|
20
|
+
alink
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
按提示登录,然后在手机或浏览器打开 [AgentLink 控制台](https://link.harmopath.com/login),即可开始任务或继续已有工作。
|
|
24
24
|
|
|
25
|
-
`alink
|
|
25
|
+
`alink login` 会打开浏览器,支持使用 GitHub 或已有 AgentLink 账号登录并添加当前电脑。原命令 `alink-cli` 继续可用。
|
|
26
26
|
|
|
27
27
|
[GitHub](https://github.com/baichen99/agentlink) · [提交问题](https://github.com/baichen99/agentlink/issues)
|
package/bin/agentlink.js
CHANGED
|
@@ -61,6 +61,7 @@ const OFFICIAL_HUB = process.env.AGENTLINK_DEFAULT_HUB || "wss://link.harmopath.
|
|
|
61
61
|
const STATE_DIR = process.env.AGENTLINK_STATE_DIR || join(homedir(), ".agentlink");
|
|
62
62
|
const CREDENTIAL_FILE = join(STATE_DIR, "credential");
|
|
63
63
|
const SESSION_FILE = join(STATE_DIR, "session");
|
|
64
|
+
const STATUS_FILE = join(STATE_DIR, "status.json");
|
|
64
65
|
const args = process.argv.slice(2);
|
|
65
66
|
const legacyCredentialCommands = process.env.AGENTLINK_ENABLE_LEGACY_CREDENTIALS === "1";
|
|
66
67
|
const forceTui = process.env.AGENTLINK_TUI === "1";
|
|
@@ -273,7 +274,7 @@ async function pair(hub) {
|
|
|
273
274
|
|
|
274
275
|
async function showHelp() {
|
|
275
276
|
console.log(
|
|
276
|
-
`用法:\n alink-cli
|
|
277
|
+
`用法:\n alink-cli 打开 AgentLink\n alink-cli login 登录账号\n alink-cli status 查看连接状态\n alink-cli machines 查看账号下的机器\n alink-cli logout 退出账号\n alink-cli help 查看帮助`,
|
|
277
278
|
);
|
|
278
279
|
}
|
|
279
280
|
|
|
@@ -288,9 +289,31 @@ async function showVersion() {
|
|
|
288
289
|
|
|
289
290
|
async function showStatus() {
|
|
290
291
|
const hub = value("hub") || OFFICIAL_HUB;
|
|
292
|
+
let status = {};
|
|
293
|
+
try {
|
|
294
|
+
status = JSON.parse(readFileSync(STATUS_FILE, "utf8"));
|
|
295
|
+
} catch {
|
|
296
|
+
// No daemon status yet.
|
|
297
|
+
}
|
|
298
|
+
let running = false;
|
|
299
|
+
if (Number.isInteger(status.pid) && status.pid > 0) {
|
|
300
|
+
try {
|
|
301
|
+
process.kill(status.pid, 0);
|
|
302
|
+
running = true;
|
|
303
|
+
} catch {
|
|
304
|
+
// Stale status file.
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
const statusMatchesHub =
|
|
308
|
+
typeof status.hub !== "string" || normalizeHub(status.hub) === normalizeHub(hub);
|
|
309
|
+
const hubStatus = !running || !statusMatchesHub
|
|
310
|
+
? "未连接"
|
|
311
|
+
: status.hubConnected
|
|
312
|
+
? "已连接"
|
|
313
|
+
: "连接中";
|
|
291
314
|
console.log(`[agentlink] 登录状态:${savedCredential(hub) ? "已登录" : "未登录"}`);
|
|
292
|
-
console.log(`[agentlink]
|
|
293
|
-
console.log(`[agentlink] Hub
|
|
315
|
+
console.log(`[agentlink] 本机服务:${running ? "运行中" : "已停止"}`);
|
|
316
|
+
console.log(`[agentlink] Hub 连接:${hubStatus}`);
|
|
294
317
|
}
|
|
295
318
|
|
|
296
319
|
async function doLogout() {
|
package/dist/bin.mjs
CHANGED
|
@@ -10,8 +10,9 @@ import * as NodeChildProcess from "node:child_process";
|
|
|
10
10
|
import * as NodeCrypto from "node:crypto";
|
|
11
11
|
import { createCipheriv, createDecipheriv, hkdfSync, randomBytes, randomUUID } from "node:crypto";
|
|
12
12
|
import * as NodeFS from "node:fs";
|
|
13
|
-
import { closeSync, mkdirSync, openSync, readFileSync, rmSync, writeSync } from "node:fs";
|
|
13
|
+
import { closeSync, mkdirSync, openSync, readFileSync, rmSync, writeFileSync, writeSync } from "node:fs";
|
|
14
14
|
import * as NodeOS from "node:os";
|
|
15
|
+
import { homedir } from "node:os";
|
|
15
16
|
import * as NodePath from "node:path";
|
|
16
17
|
import { join } from "node:path";
|
|
17
18
|
import { fileURLToPath } from "node:url";
|
|
@@ -53204,6 +53205,26 @@ function hubHttpUrl(hub) {
|
|
|
53204
53205
|
url.hash = "";
|
|
53205
53206
|
return url.toString().replace(/\/$/, "");
|
|
53206
53207
|
}
|
|
53208
|
+
function writeHubConnectionStatus(config, connected, stateDir = process.env.AGENTLINK_STATE_DIR || join(homedir(), ".agentlink")) {
|
|
53209
|
+
try {
|
|
53210
|
+
mkdirSync(stateDir, { recursive: true });
|
|
53211
|
+
const statusPath = join(stateDir, "status.json");
|
|
53212
|
+
let current = {};
|
|
53213
|
+
try {
|
|
53214
|
+
current = JSON.parse(readFileSync(statusPath, "utf8"));
|
|
53215
|
+
} catch {}
|
|
53216
|
+
writeFileSync(statusPath, JSON.stringify({
|
|
53217
|
+
...current,
|
|
53218
|
+
pid: process.pid,
|
|
53219
|
+
state: connected ? "connected" : "reconnecting",
|
|
53220
|
+
hub: config.hubUrl,
|
|
53221
|
+
hubConnected: connected,
|
|
53222
|
+
machineId: machineIdFromToken(config.machineToken) ?? void 0,
|
|
53223
|
+
startedAt: typeof current.startedAt === "number" ? current.startedAt : Date.now(),
|
|
53224
|
+
ts: Date.now()
|
|
53225
|
+
}));
|
|
53226
|
+
} catch {}
|
|
53227
|
+
}
|
|
53207
53228
|
const uploadHubEnckey = (config) => gen(function* () {
|
|
53208
53229
|
const machineId = machineIdFromToken(config.machineToken);
|
|
53209
53230
|
if (!machineId) return yield* fail(/* @__PURE__ */ new Error("machine id is missing from the machine token"));
|
|
@@ -53334,6 +53355,7 @@ const runHubTunnel = (config) => gen(function* () {
|
|
|
53334
53355
|
yield* wsRpcServices.pipe(asVoid);
|
|
53335
53356
|
yield* ChildProcessSpawner;
|
|
53336
53357
|
yield* retry(gen(function* () {
|
|
53358
|
+
yield* sync(() => writeHubConnectionStatus(config, false));
|
|
53337
53359
|
yield* logInfo("hub tunnel: connection effect entered");
|
|
53338
53360
|
const url = `${config.hubUrl.replace(/\/+$/, "")}/daemon-tunnel?token=${encodeURIComponent(config.machineToken)}&v=1`;
|
|
53339
53361
|
yield* logInfo("hub tunnel: connecting", { hubUrl: config.hubUrl });
|
|
@@ -53582,7 +53604,7 @@ const runHubTunnel = (config) => gen(function* () {
|
|
|
53582
53604
|
else dropTunnel(framed.tunnelId);
|
|
53583
53605
|
return;
|
|
53584
53606
|
}
|
|
53585
|
-
}, { onOpen: logInfo("hub tunnel: connected to hub").pipe(tap(() => sync(() => void runFork(upload)))) }).pipe(tapDefect((cause) => logWarning$1("hub tunnel: hub socket defect", { cause: String(cause) })));
|
|
53607
|
+
}, { onOpen: logInfo("hub tunnel: connected to hub").pipe(tap(() => sync(() => writeHubConnectionStatus(config, true))), tap(() => sync(() => void runFork(upload)))) }).pipe(ensuring(sync(() => writeHubConnectionStatus(config, false))), tapDefect((cause) => logWarning$1("hub tunnel: hub socket defect", { cause: String(cause) })));
|
|
53586
53608
|
yield* logWarning$1("hub tunnel: hub connection closed");
|
|
53587
53609
|
return yield* fail(/* @__PURE__ */ new Error("hub tunnel closed"));
|
|
53588
53610
|
}).pipe(scoped, tapError((error) => logWarning$1("hub tunnel: connection error", { error }))), {
|