@linkshell/host 0.4.60 → 0.4.62

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.
Files changed (37) hide show
  1. package/dist/host/src/access.d.ts +28 -0
  2. package/dist/host/src/access.js +106 -0
  3. package/dist/host/src/access.js.map +1 -0
  4. package/dist/host/src/drivers/acp/antigravity.js +8 -4
  5. package/dist/host/src/drivers/acp/antigravity.js.map +1 -1
  6. package/dist/host/src/drivers/claude/transcript.d.ts +5 -5
  7. package/dist/host/src/gateway.d.ts +2 -0
  8. package/dist/host/src/gateway.js +2 -0
  9. package/dist/host/src/gateway.js.map +1 -1
  10. package/dist/host/src/host.js +7 -1
  11. package/dist/host/src/host.js.map +1 -1
  12. package/dist/host/src/hub.d.ts +4 -4
  13. package/dist/host/src/index.d.ts +1 -0
  14. package/dist/host/src/index.js +1 -0
  15. package/dist/host/src/index.js.map +1 -1
  16. package/dist/host/src/rpc/server.d.ts +10 -0
  17. package/dist/host/src/rpc/server.js +74 -17
  18. package/dist/host/src/rpc/server.js.map +1 -1
  19. package/dist/host/src/screen-session.d.ts +2 -2
  20. package/dist/host/tsconfig.tsbuildinfo +1 -1
  21. package/dist/wire/src/editor.d.ts +12 -12
  22. package/dist/wire/src/live-activity.d.ts +2 -2
  23. package/dist/wire/src/model.d.ts +32 -28
  24. package/dist/wire/src/model.js +2 -0
  25. package/dist/wire/src/model.js.map +1 -1
  26. package/dist/wire/src/relay-client.d.ts +2 -0
  27. package/dist/wire/src/relay-client.js +1 -0
  28. package/dist/wire/src/relay-client.js.map +1 -1
  29. package/dist/wire/src/relay.d.ts +14 -6
  30. package/dist/wire/src/relay.js +4 -0
  31. package/dist/wire/src/relay.js.map +1 -1
  32. package/dist/wire/src/rpc.d.ts +371 -313
  33. package/dist/wire/src/rpc.js +19 -0
  34. package/dist/wire/src/rpc.js.map +1 -1
  35. package/dist/wire/src/updates.d.ts +44 -44
  36. package/dist/wire/src/watch.d.ts +18 -18
  37. package/package.json +3 -3
@@ -0,0 +1,28 @@
1
+ export declare function accessPath(home: string): string;
2
+ /** Writes or removes the password file directly (the CLI, when no host is running). */
3
+ export declare function writeAccessPassword(home: string, password: string | undefined): void;
4
+ export type UnlockResult = {
5
+ ok: true;
6
+ token: string;
7
+ expiresAt: number;
8
+ } | {
9
+ ok: false;
10
+ reason: "wrong" | "throttled" | "invalid_token";
11
+ };
12
+ /** The computer's optional access password. Remote connections must unlock before anything else. */
13
+ export declare class AccessControl {
14
+ private readonly home;
15
+ private file;
16
+ private readonly failures;
17
+ constructor(home: string);
18
+ get enabled(): boolean;
19
+ set(password: string | undefined): void;
20
+ unlock(deviceId: string, input: {
21
+ password?: string;
22
+ token?: string;
23
+ }, now?: number): UnlockResult;
24
+ private matches;
25
+ private issue;
26
+ private verifyToken;
27
+ private sign;
28
+ }
@@ -0,0 +1,106 @@
1
+ import { createHmac, randomBytes, scryptSync, timingSafeEqual } from "node:crypto";
2
+ import { chmodSync, existsSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ /** scrypt cost: ~50 ms per guess here, on top of the per-device throttle. */
5
+ const SCRYPT = { N: 16384, r: 8, p: 1, keylen: 32 };
6
+ const TOKEN_TTL_MS = 7 * 24 * 60 * 60_000;
7
+ const FAILURE_WINDOW_MS = 5 * 60_000;
8
+ const MAX_FAILURES = 5;
9
+ export function accessPath(home) {
10
+ return join(home, "access.json");
11
+ }
12
+ /** Writes or removes the password file directly (the CLI, when no host is running). */
13
+ export function writeAccessPassword(home, password) {
14
+ const path = accessPath(home);
15
+ if (!password) {
16
+ rmSync(path, { force: true });
17
+ return;
18
+ }
19
+ const salt = randomBytes(16);
20
+ const file = {
21
+ salt: salt.toString("base64"),
22
+ hash: scryptSync(password, salt, SCRYPT.keylen, SCRYPT).toString("base64"),
23
+ secret: randomBytes(32).toString("base64"),
24
+ };
25
+ const temp = `${path}.${process.pid}.tmp`;
26
+ writeFileSync(temp, `${JSON.stringify(file)}\n`, { mode: 0o600 });
27
+ chmodSync(temp, 0o600);
28
+ renameSync(temp, path);
29
+ }
30
+ function readAccessFile(home) {
31
+ const path = accessPath(home);
32
+ if (!existsSync(path))
33
+ return undefined;
34
+ try {
35
+ const file = JSON.parse(readFileSync(path, "utf8"));
36
+ if (typeof file.salt === "string" && typeof file.hash === "string" && typeof file.secret === "string")
37
+ return file;
38
+ }
39
+ catch { /* handled below */ }
40
+ // A damaged file must not silently open the computer: keep it locked with no password that matches.
41
+ return { salt: "", hash: "", secret: randomBytes(32).toString("base64") };
42
+ }
43
+ /** The computer's optional access password. Remote connections must unlock before anything else. */
44
+ export class AccessControl {
45
+ home;
46
+ file;
47
+ failures = new Map();
48
+ constructor(home) {
49
+ this.home = home;
50
+ this.file = readAccessFile(home);
51
+ }
52
+ get enabled() {
53
+ return this.file !== undefined;
54
+ }
55
+ set(password) {
56
+ writeAccessPassword(this.home, password);
57
+ this.file = readAccessFile(this.home);
58
+ this.failures.clear();
59
+ }
60
+ unlock(deviceId, input, now = Date.now()) {
61
+ const file = this.file;
62
+ if (!file)
63
+ return { ok: true, ...this.issue(deviceId, now) };
64
+ if (input.token !== undefined && input.password === undefined) {
65
+ return this.verifyToken(file, deviceId, input.token, now) ? { ok: true, ...this.issue(deviceId, now) } : { ok: false, reason: "invalid_token" };
66
+ }
67
+ const failure = this.failures.get(deviceId);
68
+ if (failure && now - failure.since < FAILURE_WINDOW_MS && failure.count >= MAX_FAILURES)
69
+ return { ok: false, reason: "throttled" };
70
+ if (this.matches(file, input.password ?? "")) {
71
+ this.failures.delete(deviceId);
72
+ return { ok: true, ...this.issue(deviceId, now) };
73
+ }
74
+ if (!failure || now - failure.since >= FAILURE_WINDOW_MS)
75
+ this.failures.set(deviceId, { since: now, count: 1 });
76
+ else
77
+ failure.count++;
78
+ return { ok: false, reason: "wrong" };
79
+ }
80
+ matches(file, password) {
81
+ if (!file.hash)
82
+ return false;
83
+ const expected = Buffer.from(file.hash, "base64");
84
+ const actual = scryptSync(password, Buffer.from(file.salt, "base64"), expected.length, SCRYPT);
85
+ return timingSafeEqual(actual, expected);
86
+ }
87
+ issue(deviceId, now) {
88
+ const expiresAt = now + TOKEN_TTL_MS;
89
+ if (!this.file)
90
+ return { token: "", expiresAt };
91
+ return { token: `${expiresAt}.${this.sign(this.file, deviceId, expiresAt)}`, expiresAt };
92
+ }
93
+ verifyToken(file, deviceId, token, now) {
94
+ const [expires, signature] = token.split(".");
95
+ const expiresAt = Number(expires);
96
+ if (!signature || !Number.isFinite(expiresAt) || expiresAt <= now)
97
+ return false;
98
+ const expected = Buffer.from(this.sign(file, deviceId, expiresAt));
99
+ const actual = Buffer.from(signature);
100
+ return actual.length === expected.length && timingSafeEqual(actual, expected);
101
+ }
102
+ sign(file, deviceId, expiresAt) {
103
+ return createHmac("sha256", Buffer.from(file.secret, "base64")).update(`linkshell-access:${deviceId}:${expiresAt}`).digest("base64url");
104
+ }
105
+ }
106
+ //# sourceMappingURL=access.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access.js","sourceRoot":"","sources":["../../../src/access.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACjG,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,6EAA6E;AAC7E,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAW,CAAC;AAC7D,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC;AAC1C,MAAM,iBAAiB,GAAG,CAAC,GAAG,MAAM,CAAC;AACrC,MAAM,YAAY,GAAG,CAAC,CAAC;AASvB,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;AACnC,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,QAA4B;IAC5E,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9B,OAAO;IACT,CAAC;IACD,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAe;QACvB,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC7B,IAAI,EAAE,UAAU,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC1E,MAAM,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;KAC3C,CAAC;IACF,MAAM,IAAI,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;IAC1C,aAAa,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAClE,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACvB,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAwB,CAAC;QAC3E,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ;YAAE,OAAO,IAAkB,CAAC;IACnI,CAAC;IAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,CAAC;IAC/B,oGAAoG;IACpG,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC5E,CAAC;AAID,oGAAoG;AACpG,MAAM,OAAO,aAAa;IAIK;IAHrB,IAAI,CAAyB;IACpB,QAAQ,GAAG,IAAI,GAAG,EAA4C,CAAC;IAEhF,YAA6B,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;QACvC,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC;IACjC,CAAC;IAED,GAAG,CAAC,QAA4B;QAC9B,mBAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IAED,MAAM,CAAC,QAAgB,EAAE,KAA4C,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;QACrF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC;QAC7D,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC9D,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;QAClJ,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC5C,IAAI,OAAO,IAAI,GAAG,GAAG,OAAO,CAAC,KAAK,GAAG,iBAAiB,IAAI,OAAO,CAAC,KAAK,IAAI,YAAY;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QACnI,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,CAAC;YAC7C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC/B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC;QACpD,CAAC;QACD,IAAI,CAAC,OAAO,IAAI,GAAG,GAAG,OAAO,CAAC,KAAK,IAAI,iBAAiB;YAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;;YAC3G,OAAO,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IACxC,CAAC;IAEO,OAAO,CAAC,IAAgB,EAAE,QAAgB;QAChD,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QAC7B,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/F,OAAO,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAEO,KAAK,CAAC,QAAgB,EAAE,GAAW;QACzC,MAAM,SAAS,GAAG,GAAG,GAAG,YAAY,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC;QAChD,OAAO,EAAE,KAAK,EAAE,GAAG,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC;IAC3F,CAAC;IAEO,WAAW,CAAC,IAAgB,EAAE,QAAgB,EAAE,KAAa,EAAE,GAAW;QAChF,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,GAAG;YAAE,OAAO,KAAK,CAAC;QAChF,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;QACnE,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtC,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAChF,CAAC;IAEO,IAAI,CAAC,IAAgB,EAAE,QAAgB,EAAE,SAAiB;QAChE,OAAO,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,oBAAoB,QAAQ,IAAI,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAC1I,CAAC;CACF"}
@@ -348,7 +348,10 @@ export function cleanAntigravityAgentContent(content) {
348
348
  function extractModelSelectionFromContent(content) {
349
349
  if (!content)
350
350
  return undefined;
351
- const regex = /changed setting `?Model Selection`? from .*? to ([^\r\n.<]+?)(?:\.(?:\s|$)|<\/USER_SETTINGS_CHANGE>|\r|\n|$)/gi;
351
+ // Names carry dots ("Claude Opus 5.5 (High)", "Gemini 3.8 Flash (Low)"): one ends at the sentence's
352
+ // full stop, a dot followed by a space or the line's end. Stopping at the first dot made the match
353
+ // skip ahead to "No need to comment…" and read that as the model.
354
+ const regex = /changed setting `?Model Selection`? from .+? to (.+?)(?:\.(?=\s|$)|<\/USER_SETTINGS_CHANGE>|$)/gim;
352
355
  let last;
353
356
  let match;
354
357
  while ((match = regex.exec(content)) !== null) {
@@ -1664,9 +1667,7 @@ export class AntigravityDriver extends AcpDriver {
1664
1667
  if (found)
1665
1668
  return found;
1666
1669
  }
1667
- const fromDefault = matchByValueOrName(this.desktopDefaultModel);
1668
- if (fromDefault)
1669
- return fromDefault;
1670
+ // The model the user last picked in the app comes before the server's default.
1670
1671
  const desktop = this.desktop();
1671
1672
  if (desktop && existsSync(join(desktop.dataDir, "antigravity_state.pbtxt"))) {
1672
1673
  try {
@@ -1680,6 +1681,9 @@ export class AntigravityDriver extends AcpDriver {
1680
1681
  // ignore
1681
1682
  }
1682
1683
  }
1684
+ const fromDefault = matchByValueOrName(this.desktopDefaultModel);
1685
+ if (fromDefault)
1686
+ return fromDefault;
1683
1687
  return models[0];
1684
1688
  }
1685
1689
  async resolvePlanModelEnum(conn, nativeId, explicitModel) {