alink-cli 0.11.2 → 0.11.3

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.
@@ -35,7 +35,7 @@ function normalizeMachineRow(row) {
35
35
  };
36
36
  }
37
37
 
38
- function machineIdFromToken(authToken) {
38
+ export function machineIdFromToken(authToken) {
39
39
  try {
40
40
  const payload = JSON.parse(
41
41
  Buffer.from(authToken.split(".")[1] || "", "base64url").toString("utf8"),
@@ -60,6 +60,7 @@ export async function registerAgentLinkAccountMachine({
60
60
  identifier,
61
61
  password,
62
62
  machineName,
63
+ preferredMachineId,
63
64
  fetchFn = fetch,
64
65
  cloudbaseSdk,
65
66
  randomBytesFn = randomBytes,
@@ -89,7 +90,7 @@ export async function registerAgentLinkAccountMachine({
89
90
  "Content-Type": "application/json",
90
91
  "X-Requested-With": "agentlink",
91
92
  },
92
- body: JSON.stringify({ name: machineName }),
93
+ body: JSON.stringify({ name: machineName, ...(preferredMachineId ? { machineId: preferredMachineId } : {}) }),
93
94
  });
94
95
  const minted = await json(mintResponse);
95
96
  const authToken = typeof minted.authToken === "string" ? minted.authToken : "";
@@ -144,6 +145,7 @@ export async function registerAgentLinkSessionMachine({
144
145
  hub,
145
146
  jwt,
146
147
  machineName,
148
+ preferredMachineId,
147
149
  fetchFn = fetch,
148
150
  randomBytesFn = randomBytes,
149
151
  }) {
@@ -156,10 +158,20 @@ export async function registerAgentLinkSessionMachine({
156
158
  "Content-Type": "application/json",
157
159
  "X-Requested-With": "agentlink",
158
160
  },
159
- body: JSON.stringify({ name: machineName, enckey }),
161
+ body: JSON.stringify({
162
+ name: machineName,
163
+ enckey,
164
+ ...(preferredMachineId ? { machineId: preferredMachineId } : {}),
165
+ }),
160
166
  });
161
167
  const minted = await json(response);
162
- if (!response.ok || typeof minted.authToken !== "string" || !minted.authToken.startsWith("al1.")) {
168
+ if (
169
+ !response.ok ||
170
+ typeof minted.authToken !== "string" ||
171
+ !minted.authToken.startsWith("al1.") ||
172
+ typeof minted.machineId !== "string" ||
173
+ !minted.machineId
174
+ ) {
163
175
  throw new Error(minted.error || "机器注册失败。");
164
176
  }
165
177
  return { credential: `${minted.authToken}.${enckey}`, machineId: minted.machineId, jwt };
package/bin/agentlink.js CHANGED
@@ -14,6 +14,7 @@ import {
14
14
  listAgentLinkAccountMachines,
15
15
  listAgentLinkAccountMachinesFromHub,
16
16
  loadAgentLinkAccountConfig,
17
+ machineIdFromToken,
17
18
  registerAgentLinkAccountMachine,
18
19
  registerAgentLinkSessionMachine,
19
20
  } from "./agentlink-account.js";
@@ -60,6 +61,7 @@ function clearSessionJwt(hub = OFFICIAL_HUB) {
60
61
  const OFFICIAL_HUB = process.env.AGENTLINK_DEFAULT_HUB || "wss://link.harmopath.com";
61
62
  const STATE_DIR = process.env.AGENTLINK_STATE_DIR || join(homedir(), ".agentlink");
62
63
  const CREDENTIAL_FILE = join(STATE_DIR, "credential");
64
+ const MACHINE_ID_FILE = join(STATE_DIR, "machine-id");
63
65
  const SESSION_FILE = join(STATE_DIR, "session");
64
66
  const args = process.argv.slice(2);
65
67
  const legacyCredentialCommands = process.env.AGENTLINK_ENABLE_LEGACY_CREDENTIALS === "1";
@@ -118,6 +120,26 @@ function saveCredential(credential, hub = OFFICIAL_HUB) {
118
120
  chmodSync(CREDENTIAL_FILE, 0o600);
119
121
  }
120
122
 
123
+ function savedMachineId(hub = OFFICIAL_HUB) {
124
+ try {
125
+ const saved = JSON.parse(readFileSync(MACHINE_ID_FILE, "utf8"));
126
+ return saved.hub === normalizeHub(hub) && typeof saved.machineId === "string"
127
+ ? saved.machineId
128
+ : undefined;
129
+ } catch {
130
+ return undefined;
131
+ }
132
+ }
133
+
134
+ function saveMachineId(machineId, hub = OFFICIAL_HUB) {
135
+ if (!machineId) return;
136
+ mkdirSync(STATE_DIR, { recursive: true });
137
+ writeFileSync(MACHINE_ID_FILE, JSON.stringify({ hub: normalizeHub(hub), machineId }), {
138
+ mode: 0o600,
139
+ });
140
+ chmodSync(MACHINE_ID_FILE, 0o600);
141
+ }
142
+
121
143
  function parseCredential(credential) {
122
144
  const parts = credential.split(".");
123
145
  if (parts.length === 3 && parts[0] === "als1" && parts.slice(1).every(Boolean)) {
@@ -149,17 +171,25 @@ async function createSingleCredential(hub) {
149
171
 
150
172
  async function loginAndCreateCredential(hub, config) {
151
173
  const envLogin = process.env.AGENTLINK_ACCOUNT && process.env.AGENTLINK_PASSWORD;
174
+ const preferredMachineId = savedMachineId(hub);
152
175
  const result = envLogin
153
176
  ? await registerAgentLinkAccountMachine({
154
177
  hub,
155
178
  config,
156
179
  ...(await accountCredentials()),
157
180
  machineName: hostname(),
181
+ preferredMachineId,
158
182
  })
159
183
  : await browserLogin(hub).then((jwt) =>
160
- registerAgentLinkSessionMachine({ hub, jwt, machineName: hostname() }),
184
+ registerAgentLinkSessionMachine({
185
+ hub,
186
+ jwt,
187
+ machineName: hostname(),
188
+ preferredMachineId,
189
+ }),
161
190
  );
162
191
  saveCredential(result.credential, hub);
192
+ saveMachineId(result.machineId, hub);
163
193
  if (result.jwt) saveSessionJwt(result.jwt, hub);
164
194
  console.log("[agentlink] 登录成功,这台电脑已加入账号。");
165
195
  return result.credential;
@@ -296,7 +326,11 @@ async function showStatus() {
296
326
  async function doLogout() {
297
327
  const hub = value("hub") || OFFICIAL_HUB;
298
328
  const loggedIn = savedCredential(hub);
299
- if (loggedIn) rmSync(CREDENTIAL_FILE, { force: true });
329
+ if (loggedIn) {
330
+ const { machineToken } = parseCredential(loggedIn);
331
+ saveMachineId(machineIdFromToken(machineToken), hub);
332
+ rmSync(CREDENTIAL_FILE, { force: true });
333
+ }
300
334
  clearSessionJwt(hub);
301
335
  console.log(
302
336
  loggedIn ? "[agentlink] 已退出账号;下次启动时需要重新登录。" : "[agentlink] 当前未登录。",
package/dist/ui.js CHANGED
@@ -48721,11 +48721,16 @@ function App2() {
48721
48721
  setReconnecting(false);
48722
48722
  }
48723
48723
  } else if (confirmAction.type === "logout") {
48724
- stopDaemon().catch(() => void 0);
48725
- clearCredential();
48726
- setRunning(false);
48727
- setAuthTick((t) => t + 1);
48728
- setNotice("\u5DF2\u9000\u51FA\u8D26\u53F7\u5E76\u505C\u6B62 daemon");
48724
+ try {
48725
+ await stopDaemon();
48726
+ const code = await runDetachedScript(["logout", "--hub", cfg.hub]);
48727
+ if (code !== 0) throw new Error(`\u9000\u51FA\u547D\u4EE4\u5F02\u5E38\u7ED3\u675F\uFF08\u9000\u51FA\u7801 ${code}\uFF09`);
48728
+ setRunning(false);
48729
+ setAuthTick((t) => t + 1);
48730
+ setNotice("\u5DF2\u9000\u51FA\u8D26\u53F7\u5E76\u505C\u6B62 daemon");
48731
+ } catch (err) {
48732
+ setNotice(`\u9000\u51FA\u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`);
48733
+ }
48729
48734
  }
48730
48735
  setView("menu");
48731
48736
  setConfirmAction(null);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alink-cli",
3
- "version": "0.11.2",
3
+ "version": "0.11.3",
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",