alink-cli 0.7.4 → 0.7.5
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 +12 -2
- package/bin/agentlink-account.js +23 -0
- package/bin/agentlink.js +60 -12
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -9,14 +9,24 @@ npx alink-cli
|
|
|
9
9
|
首次运行输入 AgentLink 账号和密码,这台电脑会自动加入账号并上线。之后直接重复 `npx alink-cli` 即可上线;密码不会保存到本机。
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
+
npm install -g alink-cli
|
|
13
|
+
alink-cli help
|
|
14
|
+
alink-cli login
|
|
15
|
+
alink-cli status
|
|
16
|
+
alink-cli machines
|
|
17
|
+
alink-cli logout
|
|
18
|
+
|
|
12
19
|
npx alink-cli --hub wss://your-hub.example.com
|
|
13
20
|
npx alink-cli --dir /path/to/project
|
|
14
|
-
npx alink-cli logout
|
|
15
21
|
```
|
|
16
22
|
|
|
23
|
+
- 全局安装后可直接使用 `alink-cli`(兼容旧命令 `agentlink`)。
|
|
24
|
+
- `login`:登录账号并注册这台电脑,但不启动服务。
|
|
25
|
+
- `status`:查看当前登录状态和 Hub。
|
|
26
|
+
- `machines`:验证账号密码后查看账号下的所有机器,不展示内部凭证。
|
|
27
|
+
- `logout`:退出当前账号并清除本机登录记录,下次运行重新输入账号密码。
|
|
17
28
|
- `--hub`:Hub 地址,默认 `wss://link.harmopath.com`。
|
|
18
29
|
- `--dir`:默认工作目录,缺省为当前目录。
|
|
19
|
-
- `logout`:退出当前账号并清除本机登录记录,下次运行重新输入账号密码。
|
|
20
30
|
- `--legacy`:临时运行旧 daemon;默认始终是 daemon-t3。
|
|
21
31
|
|
|
22
32
|
Node.js 22.16+。连接为出站 WebSocket,无需端口转发;Hub 只转发 E2EE 密文。
|
package/bin/agentlink-account.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
|
|
4
|
+
// CloudBase's Node adapter resolves optional dependencies through a runtime
|
|
5
|
+
// `require`; expose this package's resolver so its bundled `ws` dependency is found.
|
|
6
|
+
globalThis.require ??= createRequire(import.meta.url);
|
|
2
7
|
|
|
3
8
|
const MACHINE_BUCKET = "agentlink-machines";
|
|
4
9
|
const REQUEST_TIMEOUT_MS = 10_000;
|
|
@@ -131,3 +136,21 @@ export async function registerAgentLinkAccountMachine({
|
|
|
131
136
|
await auth.signOut().catch(() => undefined);
|
|
132
137
|
}
|
|
133
138
|
}
|
|
139
|
+
|
|
140
|
+
export async function listAgentLinkAccountMachines({ config, identifier, password, cloudbaseSdk }) {
|
|
141
|
+
if (!config?.cloudbaseEnvId) throw new Error("当前 Hub 尚未配置账号机器目录。");
|
|
142
|
+
const sdk = cloudbaseSdk ?? (await import("@cloudbase/js-sdk")).default;
|
|
143
|
+
const app = sdk.init({ env: config.cloudbaseEnvId, region: "ap-shanghai" });
|
|
144
|
+
const auth = app.auth();
|
|
145
|
+
const signedIn = await auth.signInWithPassword(
|
|
146
|
+
identifier.includes("@") ? { email: identifier, password } : { username: identifier, password },
|
|
147
|
+
);
|
|
148
|
+
if (signedIn?.error) throw new Error(signedIn.error.message || "账号或密码错误。");
|
|
149
|
+
try {
|
|
150
|
+
const user = await auth.getCurrentUser();
|
|
151
|
+
if (!user?.uid) throw new Error("CloudBase 账号登录状态无效。");
|
|
152
|
+
return readMachines(app.storage.from(MACHINE_BUCKET), `${user.uid}/machines.json`);
|
|
153
|
+
} finally {
|
|
154
|
+
await auth.signOut().catch(() => undefined);
|
|
155
|
+
}
|
|
156
|
+
}
|
package/bin/agentlink.js
CHANGED
|
@@ -9,6 +9,7 @@ import { fileURLToPath } from "node:url";
|
|
|
9
9
|
import WebSocket from "ws";
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
|
+
listAgentLinkAccountMachines,
|
|
12
13
|
loadAgentLinkAccountConfig,
|
|
13
14
|
registerAgentLinkAccountMachine,
|
|
14
15
|
} from "./agentlink-account.js";
|
|
@@ -17,6 +18,7 @@ const OFFICIAL_HUB = process.env.AGENTLINK_DEFAULT_HUB || "wss://link.harmopath.
|
|
|
17
18
|
const STATE_DIR = process.env.AGENTLINK_STATE_DIR || join(homedir(), ".agentlink");
|
|
18
19
|
const CREDENTIAL_FILE = join(STATE_DIR, "credential");
|
|
19
20
|
const args = process.argv.slice(2);
|
|
21
|
+
const legacyCredentialCommands = process.env.AGENTLINK_ENABLE_LEGACY_CREDENTIALS === "1";
|
|
20
22
|
|
|
21
23
|
function value(name) {
|
|
22
24
|
const index = args.findIndex((arg) => arg === `--${name}` || arg.startsWith(`--${name}=`));
|
|
@@ -206,20 +208,61 @@ async function pair(hub) {
|
|
|
206
208
|
});
|
|
207
209
|
}
|
|
208
210
|
|
|
209
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
211
|
+
if (args[0] === "help" || args.includes("--help") || args.includes("-h")) {
|
|
210
212
|
console.log(
|
|
211
|
-
|
|
213
|
+
`用法:\n alink-cli 登录(首次)并让这台电脑上线\n alink-cli login 登录账号,不启动服务\n alink-cli status 查看登录状态\n alink-cli machines 查看账号下的所有机器\n alink-cli logout 退出账号\n alink-cli help 查看帮助\n\n选项:\n --hub <wss://…> Hub 地址\n --dir <目录> 默认工作目录\n --legacy 临时运行旧 daemon`,
|
|
212
214
|
);
|
|
213
215
|
process.exit(0);
|
|
214
216
|
}
|
|
215
217
|
|
|
218
|
+
if (args[0] === "status") {
|
|
219
|
+
const hub = value("hub") || OFFICIAL_HUB;
|
|
220
|
+
console.log(`[agentlink] 登录状态:${savedCredential(hub) ? "已登录" : "未登录"}`);
|
|
221
|
+
console.log(`[agentlink] Hub:${normalizeHub(hub)}`);
|
|
222
|
+
process.exit(0);
|
|
223
|
+
}
|
|
224
|
+
|
|
216
225
|
if (args[0] === "logout") {
|
|
217
|
-
|
|
218
|
-
|
|
226
|
+
const loggedIn = savedCredential(value("hub") || OFFICIAL_HUB);
|
|
227
|
+
if (loggedIn) rmSync(CREDENTIAL_FILE, { force: true });
|
|
228
|
+
console.log(
|
|
229
|
+
loggedIn ? "[agentlink] 已退出账号;下次启动时需要重新登录。" : "[agentlink] 当前未登录。",
|
|
230
|
+
);
|
|
231
|
+
process.exit(0);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (args[0] === "login") {
|
|
235
|
+
const hub = value("hub") || OFFICIAL_HUB;
|
|
236
|
+
if (savedCredential(hub)) {
|
|
237
|
+
console.log("[agentlink] 已登录。需要切换或修复机器时,请先运行 alink-cli logout。");
|
|
238
|
+
process.exit(0);
|
|
239
|
+
}
|
|
240
|
+
const config = await loadAgentLinkAccountConfig(hub);
|
|
241
|
+
if (config?.mode !== "multi") throw new Error("当前 Hub 不使用账号登录。");
|
|
242
|
+
await loginAndCreateCredential(hub, config);
|
|
219
243
|
process.exit(0);
|
|
220
244
|
}
|
|
221
245
|
|
|
222
|
-
if (args[0] === "
|
|
246
|
+
if (args[0] === "machines") {
|
|
247
|
+
const hub = value("hub") || OFFICIAL_HUB;
|
|
248
|
+
const config = await loadAgentLinkAccountConfig(hub);
|
|
249
|
+
if (config?.mode !== "multi") throw new Error("当前 Hub 不使用账号机器目录。");
|
|
250
|
+
console.log("[agentlink] 查看账号机器,请验证 AgentLink 账号。");
|
|
251
|
+
const { identifier, password } = await accountCredentials();
|
|
252
|
+
const machines = await listAgentLinkAccountMachines({ config, identifier, password });
|
|
253
|
+
if (machines.length === 0) console.log("[agentlink] 账号下还没有机器。");
|
|
254
|
+
else {
|
|
255
|
+
console.log(`[agentlink] 账号下共 ${machines.length} 台机器:`);
|
|
256
|
+
for (const machine of machines) {
|
|
257
|
+
console.log(
|
|
258
|
+
`- ${machine.name || machine.hostname || machine.machineId} (${machine.machineId})`,
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
process.exit(0);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (args[0] === "credential" && legacyCredentialCommands) {
|
|
223
266
|
const hub = value("hub") || OFFICIAL_HUB;
|
|
224
267
|
const command = args[1] || "status";
|
|
225
268
|
if (command === "path") console.log(CREDENTIAL_FILE);
|
|
@@ -231,7 +274,7 @@ if (args[0] === "credential") {
|
|
|
231
274
|
process.exit(0);
|
|
232
275
|
}
|
|
233
276
|
|
|
234
|
-
if (args[0] === "qr") {
|
|
277
|
+
if (args[0] === "qr" && legacyCredentialCommands) {
|
|
235
278
|
const credential =
|
|
236
279
|
value("token") || process.env.AGENTLINK_TOKEN || savedCredential(value("hub") || OFFICIAL_HUB);
|
|
237
280
|
if (!credential) throw new Error("这台电脑还没有凭证,请先运行 npx alink-cli 完成配对。");
|
|
@@ -239,6 +282,11 @@ if (args[0] === "qr") {
|
|
|
239
282
|
process.exit(0);
|
|
240
283
|
}
|
|
241
284
|
|
|
285
|
+
if (args[0] && !args[0].startsWith("-")) {
|
|
286
|
+
console.error(`[agentlink] 未知命令:${args[0]}。运行 alink-cli help 查看帮助。`);
|
|
287
|
+
process.exit(1);
|
|
288
|
+
}
|
|
289
|
+
|
|
242
290
|
if (args.includes("--legacy")) {
|
|
243
291
|
process.argv = process.argv.filter((arg) => arg !== "--legacy");
|
|
244
292
|
await import(new URL("../dist/daemon.js", import.meta.url));
|
|
@@ -252,13 +300,13 @@ if (args.includes("--legacy")) {
|
|
|
252
300
|
const credential =
|
|
253
301
|
explicit ||
|
|
254
302
|
(!args.includes("--pair") && savedCredential(hub)) ||
|
|
255
|
-
(
|
|
256
|
-
? await
|
|
257
|
-
:
|
|
303
|
+
(args.includes("--pair")
|
|
304
|
+
? await pair(hub)
|
|
305
|
+
: config?.mode === "multi"
|
|
306
|
+
? await loginAndCreateCredential(hub, config)
|
|
307
|
+
: await createSingleCredential(hub));
|
|
258
308
|
if (explicit && explicit !== savedCredential(hub)) saveCredential(explicit, hub);
|
|
259
|
-
if (!explicit &&
|
|
260
|
-
console.log("[agentlink] 已登录,正在让这台电脑上线。");
|
|
261
|
-
}
|
|
309
|
+
if (!explicit && !args.includes("--pair")) console.log("[agentlink] 正在让这台电脑上线。");
|
|
262
310
|
const { machineToken, enckey } = parseCredential(credential);
|
|
263
311
|
const daemon = fileURLToPath(new URL("../dist/bin.mjs", import.meta.url));
|
|
264
312
|
const cwd = value("dir") || process.cwd();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alink-cli",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.5",
|
|
4
4
|
"description": "一条命令把工作机接入 AgentLink,随时随地遥控本机的编码 agent。One command to link your machine to AgentLink and control your coding agents from anywhere.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"acp",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"directory": "packages/cli"
|
|
22
22
|
},
|
|
23
23
|
"bin": {
|
|
24
|
-
"agentlink": "bin/agentlink.js"
|
|
24
|
+
"agentlink": "bin/agentlink.js",
|
|
25
|
+
"alink-cli": "bin/agentlink.js"
|
|
25
26
|
},
|
|
26
27
|
"files": [
|
|
27
28
|
"bin",
|