alink-cli 0.8.6 → 0.8.8

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/daemon.js CHANGED
@@ -24357,6 +24357,30 @@ function webLink(hub, token) {
24357
24357
  u.search = `?token=${encodeURIComponent(token)}`;
24358
24358
  return u.toString();
24359
24359
  }
24360
+ function hubHttpUrl(hub) {
24361
+ if (PUBLIC_BASE) return PUBLIC_BASE.replace(/\/$/, "");
24362
+ const u = new URL(hub);
24363
+ u.protocol = u.protocol === "wss:" ? "https:" : "http:";
24364
+ u.pathname = "";
24365
+ u.search = "";
24366
+ return u.toString().replace(/\/$/, "");
24367
+ }
24368
+ async function uploadEnckey(hub, machineToken, machineId, enckey) {
24369
+ const url3 = `${hubHttpUrl(hub)}/api/machines/${encodeURIComponent(machineId)}/enckey`;
24370
+ const response = await fetch(url3, {
24371
+ method: "POST",
24372
+ headers: {
24373
+ "Content-Type": "application/json",
24374
+ "X-Requested-With": "agentlink",
24375
+ Authorization: `Bearer ${machineToken}`
24376
+ },
24377
+ body: JSON.stringify({ enckey })
24378
+ });
24379
+ if (!response.ok) {
24380
+ const body = await response.text().catch(() => "");
24381
+ throw new Error(`enckey upload failed: ${response.status} ${body.slice(0, 200)}`);
24382
+ }
24383
+ }
24360
24384
  async function probeVersion(bin) {
24361
24385
  const out = await captureCommand(bin, ["--version"], 3e3);
24362
24386
  const first = out?.trim().split("\n")[0]?.trim();
@@ -24760,6 +24784,15 @@ function connect2() {
24760
24784
  send(ws, { type: "register", hostname: hostname3(), daemonVersion: ownVersion(), dirs: DIRS, home: homedir6(), agents, e2e: CRED.enckey !== void 0 });
24761
24785
  console.log(`[daemon] registered. Waiting for work pushed from the hub...`);
24762
24786
  writeStatus("connected");
24787
+ if (CRED.multi && CRED.machineId && ENCKEY) {
24788
+ console.log(`[daemon] uploading enckey for machine ${CRED.machineId}...`);
24789
+ uploadEnckey(HUB, TOKEN, CRED.machineId, ENCKEY).then(
24790
+ () => console.log(`[daemon] enckey uploaded to hub for cross-device recovery`),
24791
+ (err) => console.error(`[daemon] enckey upload failed: ${err instanceof Error ? err.message : err}`)
24792
+ );
24793
+ } else {
24794
+ console.log(`[daemon] enckey upload skipped: multi=${CRED.multi}, hasMachineId=${Boolean(CRED.machineId)}, hasEnckey=${Boolean(ENCKEY)}`);
24795
+ }
24763
24796
  if (printedLink) return;
24764
24797
  printedLink = true;
24765
24798
  if (CRED.multi) {
package/dist/ui.js CHANGED
@@ -48340,6 +48340,10 @@ function loadConfig() {
48340
48340
  function saveConfig(config) {
48341
48341
  writeFileSync2(CONFIG_FILE, JSON.stringify(config, null, 2));
48342
48342
  }
48343
+ function quit(exit) {
48344
+ exit();
48345
+ process.exit(0);
48346
+ }
48343
48347
  function StatusBar({ running, status }) {
48344
48348
  const hub = status?.hub || loadConfig().hub;
48345
48349
  const loggedIn = isLoggedIn(hub);
@@ -48422,7 +48426,7 @@ function StatusDetail({ status, running, onBack }) {
48422
48426
  const { exit } = use_app_default();
48423
48427
  use_input_default((input, key) => {
48424
48428
  if (key.return || key.escape) onBack();
48425
- if (key.ctrl && input === "c") exit();
48429
+ if (key.ctrl && input === "c") quit(exit);
48426
48430
  });
48427
48431
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
48428
48432
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { bold: true, color: "cyanBright", children: "\u25C6 Daemon \u72B6\u6001\u8BE6\u60C5" }),
@@ -48484,7 +48488,7 @@ function HelpView({ onBack }) {
48484
48488
  const { exit } = use_app_default();
48485
48489
  use_input_default((input, key) => {
48486
48490
  if (key.return || key.escape) onBack();
48487
- if (key.ctrl && input === "c") exit();
48491
+ if (key.ctrl && input === "c") quit(exit);
48488
48492
  });
48489
48493
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
48490
48494
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { bold: true, color: "cyanBright", children: "\u25C6 \u5FEB\u6377\u5E2E\u52A9" }),
@@ -48542,7 +48546,8 @@ function App2() {
48542
48546
  }
48543
48547
  items.push({ label: "\u67E5\u770B\u72B6\u6001\u8BE6\u60C5", value: "status" });
48544
48548
  items.push({ label: loggedIn ? "\u9000\u51FA\u8D26\u53F7" : "\u767B\u5F55\u8D26\u53F7", value: loggedIn ? "logout" : "login" });
48545
- if (!loggedIn) items.push({ label: "\u514D\u767B\u5F55\u914D\u5BF9\uFF08\u65E0\u9700\u8D26\u53F7\uFF0C\u7AEF\u5230\u7AEF\u52A0\u5BC6\uFF09", value: "pair" });
48549
+ const isOfficialHub = normalizeHub(config.hub) === normalizeHub(OFFICIAL_HUB);
48550
+ if (!loggedIn && !isOfficialHub) items.push({ label: "\u514D\u767B\u5F55\u914D\u5BF9\uFF08\u65E0\u9700\u8D26\u53F7\uFF0C\u7AEF\u5230\u7AEF\u52A0\u5BC6\uFF09", value: "pair" });
48546
48551
  items.push({ label: "\u67E5\u770B\u673A\u5668", value: "machines", disabled: !loggedIn });
48547
48552
  items.push({ label: "\u8BBE\u7F6E", value: "settings" });
48548
48553
  items.push({ label: "\u5E2E\u52A9", value: "help" });
@@ -48570,7 +48575,7 @@ function App2() {
48570
48575
  const item = menuItems[selectedIndex];
48571
48576
  if (item && !item.disabled) handleMenu(item.value);
48572
48577
  } else if (key.escape || input === "q" || key.ctrl && input === "c") {
48573
- exit();
48578
+ quit(exit);
48574
48579
  }
48575
48580
  });
48576
48581
  function setNotice(text) {
@@ -48650,7 +48655,7 @@ function App2() {
48650
48655
  return;
48651
48656
  }
48652
48657
  case "exit": {
48653
- exit();
48658
+ quit(exit);
48654
48659
  return;
48655
48660
  }
48656
48661
  }
@@ -49036,7 +49041,7 @@ function MachinesView({ onDone }) {
49036
49041
  const [error, setError] = (0, import_react22.useState)("");
49037
49042
  use_input_default((input, key) => {
49038
49043
  if (key.escape) onDone();
49039
- if (key.ctrl && input === "c") exit();
49044
+ if (key.ctrl && input === "c") quit(exit);
49040
49045
  });
49041
49046
  (0, import_react22.useEffect)(() => {
49042
49047
  let cancelled = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alink-cli",
3
- "version": "0.8.6",
3
+ "version": "0.8.8",
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",