linkshell-cli 0.9.0 → 0.10.0

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 (153) hide show
  1. package/README.md +11 -6
  2. package/dist/cli/src/commands/gateway.d.ts +2 -0
  3. package/dist/cli/src/commands/gateway.js +29 -0
  4. package/dist/cli/src/commands/gateway.js.map +1 -0
  5. package/dist/cli/src/commands/host.d.ts +2 -0
  6. package/dist/cli/src/commands/host.js +12 -2
  7. package/dist/cli/src/commands/host.js.map +1 -1
  8. package/dist/cli/src/commands/setup.js +4 -2
  9. package/dist/cli/src/commands/setup.js.map +1 -1
  10. package/dist/cli/src/index.js +12 -334
  11. package/dist/cli/src/index.js.map +1 -1
  12. package/dist/cli/src/utils/daemon.d.ts +0 -7
  13. package/dist/cli/src/utils/daemon.js +1 -18
  14. package/dist/cli/src/utils/daemon.js.map +1 -1
  15. package/dist/cli/tsconfig.tsbuildinfo +1 -1
  16. package/dist/gateway/src/accounts.d.ts +6 -0
  17. package/dist/gateway/src/accounts.js +32 -0
  18. package/dist/gateway/src/accounts.js.map +1 -0
  19. package/dist/gateway/src/index.d.ts +4 -0
  20. package/dist/gateway/src/index.js +5 -0
  21. package/dist/gateway/src/index.js.map +1 -0
  22. package/dist/gateway/src/main.d.ts +1 -0
  23. package/dist/gateway/src/main.js +57 -0
  24. package/dist/gateway/src/main.js.map +1 -0
  25. package/dist/gateway/src/rate-limit.d.ts +22 -0
  26. package/dist/gateway/src/rate-limit.js +66 -0
  27. package/dist/gateway/src/rate-limit.js.map +1 -0
  28. package/dist/gateway/src/relay.d.ts +84 -0
  29. package/dist/gateway/src/relay.js +434 -0
  30. package/dist/gateway/src/relay.js.map +1 -0
  31. package/dist/gateway/src/serve.d.ts +34 -0
  32. package/dist/gateway/src/serve.js +102 -0
  33. package/dist/gateway/src/serve.js.map +1 -0
  34. package/dist/gateway/src/store.d.ts +35 -0
  35. package/dist/gateway/src/store.js +109 -0
  36. package/dist/gateway/src/store.js.map +1 -0
  37. package/dist/gateway/src/subscription.d.ts +18 -0
  38. package/dist/gateway/src/subscription.js +46 -0
  39. package/dist/gateway/src/subscription.js.map +1 -0
  40. package/dist/host/src/drivers/claude/transcript.d.ts +23 -23
  41. package/dist/host/src/fs.d.ts +3 -3
  42. package/dist/host/src/input.d.ts +4 -4
  43. package/dist/host/src/terminals.d.ts +1 -1
  44. package/dist/wire/src/model.d.ts +6 -6
  45. package/dist/wire/src/relay.d.ts +8 -8
  46. package/dist/wire/src/rpc.d.ts +818 -818
  47. package/dist/wire/src/updates.d.ts +18 -18
  48. package/package.json +4 -13
  49. package/src/commands/gateway.ts +31 -0
  50. package/src/commands/host.ts +13 -2
  51. package/src/commands/setup.ts +4 -2
  52. package/src/index.ts +14 -429
  53. package/src/utils/daemon.ts +2 -27
  54. package/dist/cli/src/config.d.ts +0 -14
  55. package/dist/cli/src/config.js +0 -23
  56. package/dist/cli/src/config.js.map +0 -1
  57. package/dist/cli/src/machine-id.d.ts +0 -6
  58. package/dist/cli/src/machine-id.js +0 -50
  59. package/dist/cli/src/machine-id.js.map +0 -1
  60. package/dist/cli/src/providers.d.ts +0 -13
  61. package/dist/cli/src/providers.js +0 -77
  62. package/dist/cli/src/providers.js.map +0 -1
  63. package/dist/cli/src/runtime/acp/acp-client.d.ts +0 -128
  64. package/dist/cli/src/runtime/acp/acp-client.js +0 -430
  65. package/dist/cli/src/runtime/acp/acp-client.js.map +0 -1
  66. package/dist/cli/src/runtime/acp/agent-process-discovery.d.ts +0 -48
  67. package/dist/cli/src/runtime/acp/agent-process-discovery.js +0 -278
  68. package/dist/cli/src/runtime/acp/agent-process-discovery.js.map +0 -1
  69. package/dist/cli/src/runtime/acp/agent-session.d.ts +0 -62
  70. package/dist/cli/src/runtime/acp/agent-session.js +0 -1081
  71. package/dist/cli/src/runtime/acp/agent-session.js.map +0 -1
  72. package/dist/cli/src/runtime/acp/agent-workspace.d.ts +0 -311
  73. package/dist/cli/src/runtime/acp/agent-workspace.js +0 -6083
  74. package/dist/cli/src/runtime/acp/agent-workspace.js.map +0 -1
  75. package/dist/cli/src/runtime/acp/claude-sdk-client.d.ts +0 -121
  76. package/dist/cli/src/runtime/acp/claude-sdk-client.js +0 -1147
  77. package/dist/cli/src/runtime/acp/claude-sdk-client.js.map +0 -1
  78. package/dist/cli/src/runtime/acp/claude-stream-json-client.d.ts +0 -53
  79. package/dist/cli/src/runtime/acp/claude-stream-json-client.js +0 -552
  80. package/dist/cli/src/runtime/acp/claude-stream-json-client.js.map +0 -1
  81. package/dist/cli/src/runtime/acp/json-rpc.d.ts +0 -22
  82. package/dist/cli/src/runtime/acp/json-rpc.js +0 -160
  83. package/dist/cli/src/runtime/acp/json-rpc.js.map +0 -1
  84. package/dist/cli/src/runtime/acp/provider-resolver.d.ts +0 -16
  85. package/dist/cli/src/runtime/acp/provider-resolver.js +0 -132
  86. package/dist/cli/src/runtime/acp/provider-resolver.js.map +0 -1
  87. package/dist/cli/src/runtime/bridge-session.d.ts +0 -97
  88. package/dist/cli/src/runtime/bridge-session.js +0 -1364
  89. package/dist/cli/src/runtime/bridge-session.js.map +0 -1
  90. package/dist/cli/src/runtime/hook-command.d.ts +0 -9
  91. package/dist/cli/src/runtime/hook-command.js +0 -80
  92. package/dist/cli/src/runtime/hook-command.js.map +0 -1
  93. package/dist/cli/src/runtime/screen-fallback.d.ts +0 -22
  94. package/dist/cli/src/runtime/screen-fallback.js +0 -202
  95. package/dist/cli/src/runtime/screen-fallback.js.map +0 -1
  96. package/dist/cli/src/runtime/screen-share.d.ts +0 -34
  97. package/dist/cli/src/runtime/screen-share.js +0 -376
  98. package/dist/cli/src/runtime/screen-share.js.map +0 -1
  99. package/dist/cli/src/runtime/scrollback.d.ts +0 -11
  100. package/dist/cli/src/runtime/scrollback.js +0 -33
  101. package/dist/cli/src/runtime/scrollback.js.map +0 -1
  102. package/dist/cli/src/runtime/usage-report.d.ts +0 -34
  103. package/dist/cli/src/runtime/usage-report.js +0 -332
  104. package/dist/cli/src/runtime/usage-report.js.map +0 -1
  105. package/dist/cli/src/utils/keep-awake.d.ts +0 -6
  106. package/dist/cli/src/utils/keep-awake.js +0 -48
  107. package/dist/cli/src/utils/keep-awake.js.map +0 -1
  108. package/dist/cli/src/utils/lan-ip.d.ts +0 -9
  109. package/dist/cli/src/utils/lan-ip.js +0 -61
  110. package/dist/cli/src/utils/lan-ip.js.map +0 -1
  111. package/dist/host/src/input-helper.d.ts +0 -1
  112. package/dist/host/src/input-helper.js +0 -564
  113. package/dist/host/src/input-helper.js.map +0 -1
  114. package/dist/shared-protocol/src/index.d.ts +0 -17029
  115. package/dist/shared-protocol/src/index.js +0 -1064
  116. package/dist/shared-protocol/src/index.js.map +0 -1
  117. package/scripts/copy-web.mjs +0 -34
  118. package/src/config.ts +0 -36
  119. package/src/machine-id.ts +0 -61
  120. package/src/providers.ts +0 -97
  121. package/src/runtime/acp/acp-client.ts +0 -521
  122. package/src/runtime/acp/agent-process-discovery.ts +0 -308
  123. package/src/runtime/acp/agent-session.ts +0 -1186
  124. package/src/runtime/acp/agent-workspace.ts +0 -6590
  125. package/src/runtime/acp/claude-sdk-client.ts +0 -1221
  126. package/src/runtime/acp/claude-stream-json-client.ts +0 -633
  127. package/src/runtime/acp/json-rpc.ts +0 -184
  128. package/src/runtime/acp/provider-resolver.ts +0 -154
  129. package/src/runtime/bridge-session.ts +0 -1549
  130. package/src/runtime/hook-command.ts +0 -73
  131. package/src/runtime/screen-fallback.ts +0 -235
  132. package/src/runtime/screen-share.ts +0 -426
  133. package/src/runtime/scrollback.ts +0 -43
  134. package/src/runtime/usage-report.ts +0 -342
  135. package/src/utils/keep-awake.ts +0 -61
  136. package/src/utils/lan-ip.ts +0 -61
  137. package/web/assets/FileBrowser-wOAfY-xj.js +0 -2
  138. package/web/assets/PortPreview-Cbvv7yzA.js +0 -2
  139. package/web/assets/TerminalPanel-CTSklkct.js +0 -1
  140. package/web/assets/UsageDashboard-CJ1AsNmd.js +0 -1
  141. package/web/assets/index-BsnDaeCt.css +0 -33
  142. package/web/assets/index-q85psYZ5.js +0 -36
  143. package/web/assets/vendor-highlight-NXWAAyIv.js +0 -5
  144. package/web/assets/vendor-react-M7xG3qiw.js +0 -49
  145. package/web/assets/vendor-xterm-D15THcI4.js +0 -9
  146. package/web/index.html +0 -37
  147. package/web/logos/claude.png +0 -0
  148. package/web/logos/codex.png +0 -0
  149. package/web/logos/copilot.png +0 -0
  150. package/web/logos/gemini.png +0 -0
  151. package/web/logos/linkshell-1024.png +0 -0
  152. package/web/logos/linkshell-splash.png +0 -0
  153. package/web/logos/linkshell.png +0 -0
@@ -312,7 +312,7 @@ export declare const sessionConfigOptionSchema: z.ZodObject<{
312
312
  }[];
313
313
  id: string;
314
314
  name: string;
315
- category: "other" | "model" | "mode" | "effort";
315
+ category: "mode" | "other" | "model" | "effort";
316
316
  current: string;
317
317
  }, {
318
318
  values: {
@@ -323,7 +323,7 @@ export declare const sessionConfigOptionSchema: z.ZodObject<{
323
323
  id: string;
324
324
  name: string;
325
325
  current: string;
326
- category?: "other" | "model" | "mode" | "effort" | undefined;
326
+ category?: "mode" | "other" | "model" | "effort" | undefined;
327
327
  }>;
328
328
  export type SessionConfigOption = z.infer<typeof sessionConfigOptionSchema>;
329
329
  export declare const sessionUpdateSchema: z.ZodDiscriminatedUnion<"sessionUpdate", [z.ZodObject<{
@@ -795,7 +795,7 @@ export declare const sessionUpdateSchema: z.ZodDiscriminatedUnion<"sessionUpdate
795
795
  }>]>>;
796
796
  }, "strip", z.ZodTypeAny, {
797
797
  status: "failed" | "pending" | "in_progress" | "completed";
798
- kind: "read" | "edit" | "delete" | "move" | "search" | "execute" | "think" | "fetch" | "other";
798
+ kind: "search" | "read" | "edit" | "delete" | "move" | "execute" | "think" | "fetch" | "other";
799
799
  title: string;
800
800
  toolCallId: string;
801
801
  sessionUpdate: "tool_call";
@@ -868,7 +868,7 @@ export declare const sessionUpdateSchema: z.ZodDiscriminatedUnion<"sessionUpdate
868
868
  }[] | undefined;
869
869
  }, {
870
870
  status: "failed" | "pending" | "in_progress" | "completed";
871
- kind: "read" | "edit" | "delete" | "move" | "search" | "execute" | "think" | "fetch" | "other";
871
+ kind: "search" | "read" | "edit" | "delete" | "move" | "execute" | "think" | "fetch" | "other";
872
872
  title: string;
873
873
  toolCallId: string;
874
874
  sessionUpdate: "tool_call";
@@ -1430,7 +1430,7 @@ export declare const sessionUpdateSchema: z.ZodDiscriminatedUnion<"sessionUpdate
1430
1430
  }[];
1431
1431
  id: string;
1432
1432
  name: string;
1433
- category: "other" | "model" | "mode" | "effort";
1433
+ category: "mode" | "other" | "model" | "effort";
1434
1434
  current: string;
1435
1435
  }, {
1436
1436
  values: {
@@ -1441,7 +1441,7 @@ export declare const sessionUpdateSchema: z.ZodDiscriminatedUnion<"sessionUpdate
1441
1441
  id: string;
1442
1442
  name: string;
1443
1443
  current: string;
1444
- category?: "other" | "model" | "mode" | "effort" | undefined;
1444
+ category?: "mode" | "other" | "model" | "effort" | undefined;
1445
1445
  }>, "many">;
1446
1446
  }, "strip", z.ZodTypeAny, {
1447
1447
  options: {
@@ -1452,7 +1452,7 @@ export declare const sessionUpdateSchema: z.ZodDiscriminatedUnion<"sessionUpdate
1452
1452
  }[];
1453
1453
  id: string;
1454
1454
  name: string;
1455
- category: "other" | "model" | "mode" | "effort";
1455
+ category: "mode" | "other" | "model" | "effort";
1456
1456
  current: string;
1457
1457
  }[];
1458
1458
  sessionUpdate: "ls_config";
@@ -1466,7 +1466,7 @@ export declare const sessionUpdateSchema: z.ZodDiscriminatedUnion<"sessionUpdate
1466
1466
  id: string;
1467
1467
  name: string;
1468
1468
  current: string;
1469
- category?: "other" | "model" | "mode" | "effort" | undefined;
1469
+ category?: "mode" | "other" | "model" | "effort" | undefined;
1470
1470
  }[];
1471
1471
  sessionUpdate: "ls_config";
1472
1472
  }>, z.ZodObject<{
@@ -2174,7 +2174,7 @@ export declare const sessionEventSchema: z.ZodObject<{
2174
2174
  }>]>>;
2175
2175
  }, "strip", z.ZodTypeAny, {
2176
2176
  status: "failed" | "pending" | "in_progress" | "completed";
2177
- kind: "read" | "edit" | "delete" | "move" | "search" | "execute" | "think" | "fetch" | "other";
2177
+ kind: "search" | "read" | "edit" | "delete" | "move" | "execute" | "think" | "fetch" | "other";
2178
2178
  title: string;
2179
2179
  toolCallId: string;
2180
2180
  sessionUpdate: "tool_call";
@@ -2247,7 +2247,7 @@ export declare const sessionEventSchema: z.ZodObject<{
2247
2247
  }[] | undefined;
2248
2248
  }, {
2249
2249
  status: "failed" | "pending" | "in_progress" | "completed";
2250
- kind: "read" | "edit" | "delete" | "move" | "search" | "execute" | "think" | "fetch" | "other";
2250
+ kind: "search" | "read" | "edit" | "delete" | "move" | "execute" | "think" | "fetch" | "other";
2251
2251
  title: string;
2252
2252
  toolCallId: string;
2253
2253
  sessionUpdate: "tool_call";
@@ -2809,7 +2809,7 @@ export declare const sessionEventSchema: z.ZodObject<{
2809
2809
  }[];
2810
2810
  id: string;
2811
2811
  name: string;
2812
- category: "other" | "model" | "mode" | "effort";
2812
+ category: "mode" | "other" | "model" | "effort";
2813
2813
  current: string;
2814
2814
  }, {
2815
2815
  values: {
@@ -2820,7 +2820,7 @@ export declare const sessionEventSchema: z.ZodObject<{
2820
2820
  id: string;
2821
2821
  name: string;
2822
2822
  current: string;
2823
- category?: "other" | "model" | "mode" | "effort" | undefined;
2823
+ category?: "mode" | "other" | "model" | "effort" | undefined;
2824
2824
  }>, "many">;
2825
2825
  }, "strip", z.ZodTypeAny, {
2826
2826
  options: {
@@ -2831,7 +2831,7 @@ export declare const sessionEventSchema: z.ZodObject<{
2831
2831
  }[];
2832
2832
  id: string;
2833
2833
  name: string;
2834
- category: "other" | "model" | "mode" | "effort";
2834
+ category: "mode" | "other" | "model" | "effort";
2835
2835
  current: string;
2836
2836
  }[];
2837
2837
  sessionUpdate: "ls_config";
@@ -2845,7 +2845,7 @@ export declare const sessionEventSchema: z.ZodObject<{
2845
2845
  id: string;
2846
2846
  name: string;
2847
2847
  current: string;
2848
- category?: "other" | "model" | "mode" | "effort" | undefined;
2848
+ category?: "mode" | "other" | "model" | "effort" | undefined;
2849
2849
  }[];
2850
2850
  sessionUpdate: "ls_config";
2851
2851
  }>, z.ZodObject<{
@@ -3133,7 +3133,7 @@ export declare const sessionEventSchema: z.ZodObject<{
3133
3133
  parentToolCallId?: string | undefined;
3134
3134
  } | {
3135
3135
  status: "failed" | "pending" | "in_progress" | "completed";
3136
- kind: "read" | "edit" | "delete" | "move" | "search" | "execute" | "think" | "fetch" | "other";
3136
+ kind: "search" | "read" | "edit" | "delete" | "move" | "execute" | "think" | "fetch" | "other";
3137
3137
  title: string;
3138
3138
  toolCallId: string;
3139
3139
  sessionUpdate: "tool_call";
@@ -3312,7 +3312,7 @@ export declare const sessionEventSchema: z.ZodObject<{
3312
3312
  }[];
3313
3313
  id: string;
3314
3314
  name: string;
3315
- category: "other" | "model" | "mode" | "effort";
3315
+ category: "mode" | "other" | "model" | "effort";
3316
3316
  current: string;
3317
3317
  }[];
3318
3318
  sessionUpdate: "ls_config";
@@ -3433,7 +3433,7 @@ export declare const sessionEventSchema: z.ZodObject<{
3433
3433
  parentToolCallId?: string | undefined;
3434
3434
  } | {
3435
3435
  status: "failed" | "pending" | "in_progress" | "completed";
3436
- kind: "read" | "edit" | "delete" | "move" | "search" | "execute" | "think" | "fetch" | "other";
3436
+ kind: "search" | "read" | "edit" | "delete" | "move" | "execute" | "think" | "fetch" | "other";
3437
3437
  title: string;
3438
3438
  toolCallId: string;
3439
3439
  sessionUpdate: "tool_call";
@@ -3613,7 +3613,7 @@ export declare const sessionEventSchema: z.ZodObject<{
3613
3613
  id: string;
3614
3614
  name: string;
3615
3615
  current: string;
3616
- category?: "other" | "model" | "mode" | "effort" | undefined;
3616
+ category?: "mode" | "other" | "model" | "effort" | undefined;
3617
3617
  }[];
3618
3618
  sessionUpdate: "ls_config";
3619
3619
  } | {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linkshell-cli",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Follow, steer and approve the coding agents on your computer (Claude Code, Codex, Gemini, Copilot and more) from your phone",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -11,7 +11,6 @@
11
11
  "dist",
12
12
  "src",
13
13
  "scripts",
14
- "web",
15
14
  "README.md",
16
15
  "LICENSE"
17
16
  ],
@@ -32,21 +31,13 @@
32
31
  },
33
32
  "dependencies": {
34
33
  "commander": "^13.1.0",
35
- "node-pty": "^1.0.0",
34
+ "node-pty": "^1.1.0",
36
35
  "qrcode-terminal": "^0.12.0",
37
- "ws": "^8.18.1",
38
- "zod": "^3.24.3",
39
- "@linkshell/gateway": "0.5.3",
40
- "@linkshell/protocol": "0.4.10",
36
+ "@linkshell/gateway": "0.6.0",
41
37
  "@linkshell/host": "0.4.0",
42
38
  "@linkshell/wire": "0.2.1"
43
39
  },
44
- "optionalDependencies": {
45
- "@anthropic-ai/claude-agent-sdk": "^0.2.128",
46
- "werift": "^0.22.9"
47
- },
48
40
  "devDependencies": {
49
- "@types/ws": "^8.5.14",
50
41
  "tsx": "^4.19.3",
51
42
  "vitest": "^3.2.1"
52
43
  },
@@ -54,7 +45,7 @@
54
45
  "node": ">=22.13"
55
46
  },
56
47
  "scripts": {
57
- "build": "tsc -p tsconfig.json && node scripts/copy-web.mjs",
48
+ "build": "rm -rf dist *.tsbuildinfo && tsc -p tsconfig.json",
58
49
  "postinstall": "node scripts/postinstall.mjs",
59
50
  "typecheck": "tsc -p tsconfig.json --noEmit",
60
51
  "dev": "tsx src/index.ts",
@@ -0,0 +1,31 @@
1
+ import { join } from "node:path";
2
+ import * as daemon from "../utils/daemon.js";
3
+ import { assertHostRuntime, silenceSqliteWarning } from "./host.js";
4
+
5
+ /** Runs a gateway in this process until SIGINT/SIGTERM. */
6
+ export async function runGatewayForeground(version: string, port: number): Promise<void> {
7
+ // The relay keeps its pairings in node:sqlite, like the host.
8
+ assertHostRuntime();
9
+ silenceSqliteWarning();
10
+ const { startGateway } = await import("@linkshell/gateway");
11
+ // Pairings live here; keeping this file keeps phones paired.
12
+ const databasePath = join(daemon.linkshellDir(), "relay.db");
13
+ const gateway = await startGateway({ port, databasePath });
14
+ daemon.savePid("gateway", process.pid);
15
+
16
+ process.stderr.write(`\n LinkShell Gateway ${version}\n`);
17
+ process.stderr.write(` Listening on http://0.0.0.0:${gateway.port}\n`);
18
+ process.stderr.write(` PID: ${process.pid}\n`);
19
+ process.stderr.write(` Pairings: ${databasePath}\n\n`);
20
+ process.stderr.write(` Computers: linkshell host --gateway ws://this-server:${gateway.port}\n`);
21
+ process.stderr.write(` Health check: curl http://this-server:${gateway.port}/healthz\n\n`);
22
+
23
+ const shutdown = async () => {
24
+ process.stderr.write("[gateway] shutting down...\n");
25
+ daemon.removePid("gateway");
26
+ await gateway.close();
27
+ process.exit(0);
28
+ };
29
+ process.on("SIGINT", shutdown);
30
+ process.on("SIGTERM", shutdown);
31
+ }
@@ -26,6 +26,12 @@ interface HostConfig {
26
26
  /** LinkShell's own gateway: a Pro account's computers are reachable there. */
27
27
  export const OFFICIAL_GATEWAY = "wss://gateway.itool.tech";
28
28
 
29
+ /** Whether two gateway addresses name the same one, however they were typed (scheme, trailing slash). */
30
+ export function sameGateway(a: string | undefined, b: string): boolean {
31
+ const key = (url: string) => url.trim().replace(/^http/i, "ws").replace(/\/+$/, "").toLowerCase();
32
+ return a !== undefined && key(a) === key(b);
33
+ }
34
+
29
35
  /**
30
36
  * Where devices reach this computer from outside the LAN: LINKSHELL_GATEWAY,
31
37
  * else the saved choice, else the official gateway when logged in.
@@ -33,7 +39,7 @@ export const OFFICIAL_GATEWAY = "wss://gateway.itool.tech";
33
39
  export function resolveGateway(home: string): string | undefined {
34
40
  const chosen = process.env.LINKSHELL_GATEWAY || readHostConfig(home).gateway;
35
41
  if (chosen === "off") return undefined;
36
- // config.json is shared with the v1 bridge, whose gateway URLs end in /ws.
42
+ // A config.json written by 1.x holds a gateway URL ending in /ws.
37
43
  if (chosen) return chosen.replace(/\/ws\/?$/, "");
38
44
  return isLoggedIn() ? OFFICIAL_GATEWAY : undefined;
39
45
  }
@@ -97,7 +103,12 @@ export async function runHostForeground(version: string): Promise<void> {
97
103
  version,
98
104
  env,
99
105
  log,
100
- gateway: { url: () => resolveGateway(home), token: async () => (await getValidToken()) ?? undefined },
106
+ gateway: {
107
+ url: () => resolveGateway(home),
108
+ // The account is LinkShell's, so its token goes to LinkShell's gateway and to no other: a
109
+ // gateway of one's own has no accounts, and would refuse a computer that offered one.
110
+ token: async () => (sameGateway(resolveGateway(home), OFFICIAL_GATEWAY) ? ((await getValidToken()) ?? undefined) : undefined),
111
+ },
101
112
  tcpPort: devPort,
102
113
  claudeCommand: process.env.LINKSHELL_CLAUDE_COMMAND || undefined,
103
114
  claudeAdapter: adapter ? { command: adapter, args: [] } : undefined,
@@ -1,6 +1,6 @@
1
1
  import * as readline from "node:readline";
2
2
  import { isLoggedIn, loadAuth } from "../auth.js";
3
- import { assertHostRuntime, ensureHostRunning, joinGatewayAfterLogin, readHostConfig, withRunningHost, writeHostConfig } from "./host.js";
3
+ import { assertHostRuntime, ensureHostRunning, joinGatewayAfterLogin, OFFICIAL_GATEWAY, readHostConfig, sameGateway, withRunningHost, writeHostConfig } from "./host.js";
4
4
  import { setUpScreen } from "./screen.js";
5
5
 
6
6
  // `linkshell setup`: everything a new installation needs, once, in order —
@@ -41,7 +41,9 @@ async function remember(outcome: "done"): Promise<void> {
41
41
  /** The phone's way to this computer: an account both are signed in to, or a pairing through a gateway. */
42
42
  async function setUpPhone(out: (line?: string) => void, interactive: boolean): Promise<boolean> {
43
43
  const gateway = await withRunningHost((client) => client.call("gateway.status", {}));
44
- if (isLoggedIn()) {
44
+ // The account counts on LinkShell's own gateway only; with a gateway of one's own, phones are paired.
45
+ const official = !gateway || gateway.status === "off" || !gateway.url || sameGateway(gateway.url, OFFICIAL_GATEWAY);
46
+ if (isLoggedIn() && official) {
45
47
  const email = loadAuth()?.email;
46
48
  if (gateway?.status === "online") {
47
49
  out(` ${green("✓")} Signed in${email ? ` as ${email}` : ""}: this computer is online.`);