linkshell-cli 0.8.2 → 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 (173) 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 +4 -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/screen.d.ts +10 -0
  9. package/dist/cli/src/commands/screen.js +82 -74
  10. package/dist/cli/src/commands/screen.js.map +1 -1
  11. package/dist/cli/src/commands/setup.d.ts +11 -1
  12. package/dist/cli/src/commands/setup.js +102 -38
  13. package/dist/cli/src/commands/setup.js.map +1 -1
  14. package/dist/cli/src/index.js +28 -338
  15. package/dist/cli/src/index.js.map +1 -1
  16. package/dist/cli/src/utils/daemon.d.ts +0 -7
  17. package/dist/cli/src/utils/daemon.js +1 -18
  18. package/dist/cli/src/utils/daemon.js.map +1 -1
  19. package/dist/cli/tsconfig.tsbuildinfo +1 -1
  20. package/dist/gateway/src/accounts.d.ts +6 -0
  21. package/dist/gateway/src/accounts.js +32 -0
  22. package/dist/gateway/src/accounts.js.map +1 -0
  23. package/dist/gateway/src/index.d.ts +4 -0
  24. package/dist/gateway/src/index.js +5 -0
  25. package/dist/gateway/src/index.js.map +1 -0
  26. package/dist/gateway/src/main.d.ts +1 -0
  27. package/dist/gateway/src/main.js +57 -0
  28. package/dist/gateway/src/main.js.map +1 -0
  29. package/dist/gateway/src/rate-limit.d.ts +22 -0
  30. package/dist/gateway/src/rate-limit.js +66 -0
  31. package/dist/gateway/src/rate-limit.js.map +1 -0
  32. package/dist/gateway/src/relay.d.ts +84 -0
  33. package/dist/gateway/src/relay.js +434 -0
  34. package/dist/gateway/src/relay.js.map +1 -0
  35. package/dist/gateway/src/serve.d.ts +34 -0
  36. package/dist/gateway/src/serve.js +102 -0
  37. package/dist/gateway/src/serve.js.map +1 -0
  38. package/dist/gateway/src/store.d.ts +35 -0
  39. package/dist/gateway/src/store.js +109 -0
  40. package/dist/gateway/src/store.js.map +1 -0
  41. package/dist/gateway/src/subscription.d.ts +18 -0
  42. package/dist/gateway/src/subscription.js +46 -0
  43. package/dist/gateway/src/subscription.js.map +1 -0
  44. package/dist/host/src/drivers/claude/transcript.d.ts +23 -23
  45. package/dist/host/src/fs.d.ts +3 -3
  46. package/dist/host/src/input.d.ts +112 -27
  47. package/dist/host/src/input.js +214 -144
  48. package/dist/host/src/input.js.map +1 -1
  49. package/dist/host/src/rpc/server.js +1 -1
  50. package/dist/host/src/rpc/server.js.map +1 -1
  51. package/dist/host/src/screen-pacer.d.ts +25 -11
  52. package/dist/host/src/screen-pacer.js +28 -6
  53. package/dist/host/src/screen-pacer.js.map +1 -1
  54. package/dist/host/src/screen-viewer.d.ts +5 -0
  55. package/dist/host/src/screen-viewer.js +1231 -55
  56. package/dist/host/src/screen-viewer.js.map +1 -1
  57. package/dist/host/src/screen.d.ts +19 -10
  58. package/dist/host/src/screen.js +314 -108
  59. package/dist/host/src/screen.js.map +1 -1
  60. package/dist/host/src/terminals.d.ts +1 -1
  61. package/dist/host/src/terminals.js +1 -0
  62. package/dist/host/src/terminals.js.map +1 -1
  63. package/dist/wire/src/model.d.ts +6 -6
  64. package/dist/wire/src/relay.d.ts +8 -8
  65. package/dist/wire/src/rpc.d.ts +818 -818
  66. package/dist/wire/src/updates.d.ts +18 -18
  67. package/package.json +6 -15
  68. package/src/commands/gateway.ts +31 -0
  69. package/src/commands/host.ts +15 -2
  70. package/src/commands/screen.ts +78 -72
  71. package/src/commands/setup.ts +102 -60
  72. package/src/index.ts +29 -433
  73. package/src/utils/daemon.ts +2 -27
  74. package/dist/cli/src/config.d.ts +0 -14
  75. package/dist/cli/src/config.js +0 -23
  76. package/dist/cli/src/config.js.map +0 -1
  77. package/dist/cli/src/machine-id.d.ts +0 -6
  78. package/dist/cli/src/machine-id.js +0 -50
  79. package/dist/cli/src/machine-id.js.map +0 -1
  80. package/dist/cli/src/providers.d.ts +0 -13
  81. package/dist/cli/src/providers.js +0 -77
  82. package/dist/cli/src/providers.js.map +0 -1
  83. package/dist/cli/src/runtime/acp/acp-client.d.ts +0 -128
  84. package/dist/cli/src/runtime/acp/acp-client.js +0 -430
  85. package/dist/cli/src/runtime/acp/acp-client.js.map +0 -1
  86. package/dist/cli/src/runtime/acp/agent-process-discovery.d.ts +0 -48
  87. package/dist/cli/src/runtime/acp/agent-process-discovery.js +0 -278
  88. package/dist/cli/src/runtime/acp/agent-process-discovery.js.map +0 -1
  89. package/dist/cli/src/runtime/acp/agent-session.d.ts +0 -62
  90. package/dist/cli/src/runtime/acp/agent-session.js +0 -1081
  91. package/dist/cli/src/runtime/acp/agent-session.js.map +0 -1
  92. package/dist/cli/src/runtime/acp/agent-workspace.d.ts +0 -311
  93. package/dist/cli/src/runtime/acp/agent-workspace.js +0 -6083
  94. package/dist/cli/src/runtime/acp/agent-workspace.js.map +0 -1
  95. package/dist/cli/src/runtime/acp/claude-sdk-client.d.ts +0 -121
  96. package/dist/cli/src/runtime/acp/claude-sdk-client.js +0 -1147
  97. package/dist/cli/src/runtime/acp/claude-sdk-client.js.map +0 -1
  98. package/dist/cli/src/runtime/acp/claude-stream-json-client.d.ts +0 -53
  99. package/dist/cli/src/runtime/acp/claude-stream-json-client.js +0 -552
  100. package/dist/cli/src/runtime/acp/claude-stream-json-client.js.map +0 -1
  101. package/dist/cli/src/runtime/acp/json-rpc.d.ts +0 -22
  102. package/dist/cli/src/runtime/acp/json-rpc.js +0 -160
  103. package/dist/cli/src/runtime/acp/json-rpc.js.map +0 -1
  104. package/dist/cli/src/runtime/acp/provider-resolver.d.ts +0 -16
  105. package/dist/cli/src/runtime/acp/provider-resolver.js +0 -132
  106. package/dist/cli/src/runtime/acp/provider-resolver.js.map +0 -1
  107. package/dist/cli/src/runtime/bridge-session.d.ts +0 -97
  108. package/dist/cli/src/runtime/bridge-session.js +0 -1364
  109. package/dist/cli/src/runtime/bridge-session.js.map +0 -1
  110. package/dist/cli/src/runtime/hook-command.d.ts +0 -9
  111. package/dist/cli/src/runtime/hook-command.js +0 -80
  112. package/dist/cli/src/runtime/hook-command.js.map +0 -1
  113. package/dist/cli/src/runtime/screen-fallback.d.ts +0 -22
  114. package/dist/cli/src/runtime/screen-fallback.js +0 -202
  115. package/dist/cli/src/runtime/screen-fallback.js.map +0 -1
  116. package/dist/cli/src/runtime/screen-share.d.ts +0 -34
  117. package/dist/cli/src/runtime/screen-share.js +0 -376
  118. package/dist/cli/src/runtime/screen-share.js.map +0 -1
  119. package/dist/cli/src/runtime/scrollback.d.ts +0 -11
  120. package/dist/cli/src/runtime/scrollback.js +0 -33
  121. package/dist/cli/src/runtime/scrollback.js.map +0 -1
  122. package/dist/cli/src/runtime/usage-report.d.ts +0 -34
  123. package/dist/cli/src/runtime/usage-report.js +0 -332
  124. package/dist/cli/src/runtime/usage-report.js.map +0 -1
  125. package/dist/cli/src/utils/keep-awake.d.ts +0 -6
  126. package/dist/cli/src/utils/keep-awake.js +0 -48
  127. package/dist/cli/src/utils/keep-awake.js.map +0 -1
  128. package/dist/cli/src/utils/lan-ip.d.ts +0 -9
  129. package/dist/cli/src/utils/lan-ip.js +0 -61
  130. package/dist/cli/src/utils/lan-ip.js.map +0 -1
  131. package/dist/host/src/input-helper.d.ts +0 -1
  132. package/dist/host/src/input-helper.js +0 -564
  133. package/dist/host/src/input-helper.js.map +0 -1
  134. package/dist/shared-protocol/src/index.d.ts +0 -17029
  135. package/dist/shared-protocol/src/index.js +0 -1064
  136. package/dist/shared-protocol/src/index.js.map +0 -1
  137. package/scripts/copy-web.mjs +0 -34
  138. package/src/config.ts +0 -36
  139. package/src/machine-id.ts +0 -61
  140. package/src/providers.ts +0 -97
  141. package/src/runtime/acp/acp-client.ts +0 -521
  142. package/src/runtime/acp/agent-process-discovery.ts +0 -308
  143. package/src/runtime/acp/agent-session.ts +0 -1186
  144. package/src/runtime/acp/agent-workspace.ts +0 -6590
  145. package/src/runtime/acp/claude-sdk-client.ts +0 -1221
  146. package/src/runtime/acp/claude-stream-json-client.ts +0 -633
  147. package/src/runtime/acp/json-rpc.ts +0 -184
  148. package/src/runtime/acp/provider-resolver.ts +0 -154
  149. package/src/runtime/bridge-session.ts +0 -1549
  150. package/src/runtime/hook-command.ts +0 -73
  151. package/src/runtime/screen-fallback.ts +0 -235
  152. package/src/runtime/screen-share.ts +0 -426
  153. package/src/runtime/scrollback.ts +0 -43
  154. package/src/runtime/usage-report.ts +0 -342
  155. package/src/utils/keep-awake.ts +0 -61
  156. package/src/utils/lan-ip.ts +0 -61
  157. package/web/assets/FileBrowser-wOAfY-xj.js +0 -2
  158. package/web/assets/PortPreview-Cbvv7yzA.js +0 -2
  159. package/web/assets/TerminalPanel-CTSklkct.js +0 -1
  160. package/web/assets/UsageDashboard-CJ1AsNmd.js +0 -1
  161. package/web/assets/index-BsnDaeCt.css +0 -33
  162. package/web/assets/index-q85psYZ5.js +0 -36
  163. package/web/assets/vendor-highlight-NXWAAyIv.js +0 -5
  164. package/web/assets/vendor-react-M7xG3qiw.js +0 -49
  165. package/web/assets/vendor-xterm-D15THcI4.js +0 -9
  166. package/web/index.html +0 -37
  167. package/web/logos/claude.png +0 -0
  168. package/web/logos/codex.png +0 -0
  169. package/web/logos/copilot.png +0 -0
  170. package/web/logos/gemini.png +0 -0
  171. package/web/logos/linkshell-1024.png +0 -0
  172. package/web/logos/linkshell-splash.png +0 -0
  173. package/web/logos/linkshell.png +0 -0
@@ -1,75 +1,117 @@
1
1
  import * as readline from "node:readline";
2
- import { hostname } from "node:os";
3
- import { loadConfig, saveConfig, getConfigPath } from "../config.js";
4
- import type { LinkShellConfig } from "../config.js";
2
+ import { isLoggedIn, loadAuth } from "../auth.js";
3
+ import { assertHostRuntime, ensureHostRunning, joinGatewayAfterLogin, OFFICIAL_GATEWAY, readHostConfig, sameGateway, withRunningHost, writeHostConfig } from "./host.js";
4
+ import { setUpScreen } from "./screen.js";
5
5
 
6
- function ask(
7
- rl: readline.Interface,
8
- question: string,
9
- defaultValue?: string,
10
- ): Promise<string> {
11
- const suffix = defaultValue ? ` (${defaultValue})` : "";
12
- return new Promise((resolve) => {
13
- rl.question(` ${question}${suffix}: `, (answer) => {
14
- resolve(answer.trim() || defaultValue || "");
15
- });
16
- });
6
+ // `linkshell setup`: everything a new installation needs, once, in order —
7
+ // the host running, the screen's permissions, a phone that can reach this
8
+ // computer. Someone who installs and never comes back to the terminal should
9
+ // leave with all of it done: the first `linkshell host --daemon` runs this by
10
+ // itself (see `offerSetup`).
11
+
12
+ const green = (text: string) => `\x1b[32m${text}\x1b[0m`;
13
+ const dim = (text: string) => `\x1b[2m${text}\x1b[0m`;
14
+ const bold = (text: string) => `\x1b[1m${text}\x1b[0m`;
15
+
16
+ function ask(question: string): Promise<string> {
17
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
18
+ return new Promise((resolve) =>
19
+ rl.question(question, (answer) => {
20
+ rl.close();
21
+ resolve(answer.trim().toLowerCase());
22
+ }),
23
+ );
17
24
  }
18
25
 
19
- function defaultShell(): string {
20
- if (process.platform === "win32") {
21
- return process.env.COMSPEC ?? "cmd.exe";
22
- }
23
- return process.env.SHELL ?? "/bin/bash";
26
+ async function home(): Promise<string> {
27
+ const { defaultHome } = await import("@linkshell/host");
28
+ return defaultHome();
24
29
  }
25
30
 
26
- export async function runSetup(): Promise<void> {
27
- const existing = loadConfig();
28
- const rl = readline.createInterface({
29
- input: process.stdin,
30
- output: process.stdout,
31
- });
31
+ /** Whether this installation has been through setup (or said no to it). */
32
+ export async function setupDone(): Promise<boolean> {
33
+ return readHostConfig(await home()).setup !== undefined;
34
+ }
32
35
 
33
- process.stdout.write("\n LinkShell Setup\n\n");
34
- process.stdout.write(
35
- " Tip: leave Gateway URL empty to use the built-in gateway (recommended for LAN use).\n\n",
36
- );
36
+ async function remember(outcome: "done"): Promise<void> {
37
+ const at = await home();
38
+ writeHostConfig(at, { ...readHostConfig(at), setup: outcome });
39
+ }
37
40
 
38
- const gateway = await ask(rl, "Gateway URL (leave empty for built-in)", "");
41
+ /** The phone's way to this computer: an account both are signed in to, or a pairing through a gateway. */
42
+ async function setUpPhone(out: (line?: string) => void, interactive: boolean): Promise<boolean> {
43
+ const gateway = await withRunningHost((client) => client.call("gateway.status", {}));
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) {
47
+ const email = loadAuth()?.email;
48
+ if (gateway?.status === "online") {
49
+ out(` ${green("✓")} Signed in${email ? ` as ${email}` : ""}: this computer is online.`);
50
+ out(dim(" Open LinkShell on your phone and sign in with the same account — it shows up there, no pairing needed."));
51
+ return true;
52
+ }
53
+ // Signed in, not online yet (a host started before the login, or no subscription): say which.
54
+ await joinGatewayAfterLogin("pro");
55
+ return (await withRunningHost((client) => client.call("gateway.status", {})))?.status === "online";
56
+ }
57
+ if (gateway && gateway.status !== "off" && gateway.devices.length > 0) {
58
+ out(` ${green("✓")} Paired with ${gateway.devices.map((device) => device.name).join(", ")}.`);
59
+ return true;
60
+ }
61
+ if (gateway && gateway.status !== "off") {
62
+ out(" This computer uses your own gateway. Pair your phone with: linkshell pair");
63
+ return false;
64
+ }
65
+ if (!interactive) {
66
+ out(" Not connected to a phone yet: linkshell login (LinkShell account), or your own gateway and linkshell pair.");
67
+ return false;
68
+ }
69
+ out(" Your phone reaches this computer through your LinkShell account (Pro), from anywhere.");
70
+ const answer = await ask(" Sign in now? It opens your browser. [Y/n] ");
71
+ if (answer === "n" || answer === "no") {
72
+ out(dim(" Later: linkshell login — or with your own gateway: linkshell host --gateway <url>, then linkshell pair"));
73
+ return false;
74
+ }
75
+ const { runLogin } = await import("./login.js");
76
+ const result = await runLogin();
77
+ if (!result) return false;
78
+ await joinGatewayAfterLogin(result.plan);
79
+ return (await withRunningHost((client) => client.call("gateway.status", {})))?.status === "online";
80
+ }
39
81
 
40
- const command = await ask(
41
- rl,
42
- "Terminal command (the shell or CLI you want to bridge)",
43
- existing.command ?? defaultShell(),
44
- );
82
+ /** The whole of it. `from`: who is running it — said aloud only when it wasn't asked for. */
83
+ export async function runSetup(version: string, from: "command" | "first-start" = "command"): Promise<void> {
84
+ const out = (line = "") => process.stdout.write(`${line}\n`);
85
+ const interactive = process.stdin.isTTY === true && process.stdout.isTTY === true;
86
+ assertHostRuntime();
87
+ out(`\n ${bold("LinkShell setup")}${from === "first-start" ? dim(" (first start on this computer; again any time with: linkshell setup)") : ""}\n`);
45
88
 
46
- const clientName = await ask(
47
- rl,
48
- "Client name",
49
- existing.clientName ?? hostname(),
50
- );
51
- const hostnameName = await ask(
52
- rl,
53
- "Hostname (display name for your machine)",
54
- existing.hostname ?? hostname(),
55
- );
89
+ out(` ${bold("1")} The host`);
90
+ await ensureHostRunning();
91
+ out(` ${green("✓")} Running (${version}); it keeps running in the background.\n`);
56
92
 
57
- rl.close();
93
+ out(` ${bold("2")} The screen ${dim("— watch and control this computer from the phone")}`);
94
+ const screen = await setUpScreen(out, interactive);
95
+ out();
58
96
 
59
- const config: LinkShellConfig = {
60
- gateway: gateway || undefined,
61
- provider: "custom",
62
- command: command || undefined,
63
- clientName,
64
- hostname: hostnameName || undefined,
65
- };
97
+ out(` ${bold("3")} Your phone`);
98
+ const phone = await setUpPhone(out, interactive);
99
+ out();
66
100
 
67
- saveConfig(config);
101
+ // Run where nobody could answer, it has set nothing up: the first start at a terminal still offers it.
102
+ if (interactive) await remember("done");
103
+ if (screen && phone) out(` ${green("All set.")} Open LinkShell on your phone.\n`);
104
+ else out(` Done for now. ${[!screen && "The screen: linkshell screen", !phone && "The phone: linkshell login, or linkshell pair"].filter(Boolean).join(" · ")}\n`);
105
+ }
68
106
 
69
- process.stdout.write(
70
- `\n \x1b[32mConfig saved to ${getConfigPath()}\x1b[0m\n\n`,
71
- );
72
- process.stdout.write(" Next steps:\n");
73
- process.stdout.write(" linkshell doctor — verify your setup\n");
74
- process.stdout.write(" linkshell start — start a bridge session\n\n");
107
+ /**
108
+ * The first start on a computer: the host has just been started by someone at
109
+ * a terminal, and nothing has ever been set up here. Rather than leave the
110
+ * rest for the day it is needed (by then nobody is at the computer), it is
111
+ * done now. Once: a second start says nothing.
112
+ */
113
+ export async function offerSetup(version: string): Promise<boolean> {
114
+ if (process.stdin.isTTY !== true || process.stdout.isTTY !== true || (await setupDone())) return false;
115
+ await runSetup(version, "first-start");
116
+ return true;
75
117
  }