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.
- package/README.md +11 -6
- package/dist/cli/src/commands/gateway.d.ts +2 -0
- package/dist/cli/src/commands/gateway.js +29 -0
- package/dist/cli/src/commands/gateway.js.map +1 -0
- package/dist/cli/src/commands/host.d.ts +4 -0
- package/dist/cli/src/commands/host.js +12 -2
- package/dist/cli/src/commands/host.js.map +1 -1
- package/dist/cli/src/commands/screen.d.ts +10 -0
- package/dist/cli/src/commands/screen.js +82 -74
- package/dist/cli/src/commands/screen.js.map +1 -1
- package/dist/cli/src/commands/setup.d.ts +11 -1
- package/dist/cli/src/commands/setup.js +102 -38
- package/dist/cli/src/commands/setup.js.map +1 -1
- package/dist/cli/src/index.js +28 -338
- package/dist/cli/src/index.js.map +1 -1
- package/dist/cli/src/utils/daemon.d.ts +0 -7
- package/dist/cli/src/utils/daemon.js +1 -18
- package/dist/cli/src/utils/daemon.js.map +1 -1
- package/dist/cli/tsconfig.tsbuildinfo +1 -1
- package/dist/gateway/src/accounts.d.ts +6 -0
- package/dist/gateway/src/accounts.js +32 -0
- package/dist/gateway/src/accounts.js.map +1 -0
- package/dist/gateway/src/index.d.ts +4 -0
- package/dist/gateway/src/index.js +5 -0
- package/dist/gateway/src/index.js.map +1 -0
- package/dist/gateway/src/main.d.ts +1 -0
- package/dist/gateway/src/main.js +57 -0
- package/dist/gateway/src/main.js.map +1 -0
- package/dist/gateway/src/rate-limit.d.ts +22 -0
- package/dist/gateway/src/rate-limit.js +66 -0
- package/dist/gateway/src/rate-limit.js.map +1 -0
- package/dist/gateway/src/relay.d.ts +84 -0
- package/dist/gateway/src/relay.js +434 -0
- package/dist/gateway/src/relay.js.map +1 -0
- package/dist/gateway/src/serve.d.ts +34 -0
- package/dist/gateway/src/serve.js +102 -0
- package/dist/gateway/src/serve.js.map +1 -0
- package/dist/gateway/src/store.d.ts +35 -0
- package/dist/gateway/src/store.js +109 -0
- package/dist/gateway/src/store.js.map +1 -0
- package/dist/gateway/src/subscription.d.ts +18 -0
- package/dist/gateway/src/subscription.js +46 -0
- package/dist/gateway/src/subscription.js.map +1 -0
- package/dist/host/src/drivers/claude/transcript.d.ts +23 -23
- package/dist/host/src/fs.d.ts +3 -3
- package/dist/host/src/input.d.ts +112 -27
- package/dist/host/src/input.js +214 -144
- package/dist/host/src/input.js.map +1 -1
- package/dist/host/src/rpc/server.js +1 -1
- package/dist/host/src/rpc/server.js.map +1 -1
- package/dist/host/src/screen-pacer.d.ts +25 -11
- package/dist/host/src/screen-pacer.js +28 -6
- package/dist/host/src/screen-pacer.js.map +1 -1
- package/dist/host/src/screen-viewer.d.ts +5 -0
- package/dist/host/src/screen-viewer.js +1231 -55
- package/dist/host/src/screen-viewer.js.map +1 -1
- package/dist/host/src/screen.d.ts +19 -10
- package/dist/host/src/screen.js +314 -108
- package/dist/host/src/screen.js.map +1 -1
- package/dist/host/src/terminals.d.ts +1 -1
- package/dist/host/src/terminals.js +1 -0
- package/dist/host/src/terminals.js.map +1 -1
- package/dist/wire/src/model.d.ts +6 -6
- package/dist/wire/src/relay.d.ts +8 -8
- package/dist/wire/src/rpc.d.ts +818 -818
- package/dist/wire/src/updates.d.ts +18 -18
- package/package.json +6 -15
- package/src/commands/gateway.ts +31 -0
- package/src/commands/host.ts +15 -2
- package/src/commands/screen.ts +78 -72
- package/src/commands/setup.ts +102 -60
- package/src/index.ts +29 -433
- package/src/utils/daemon.ts +2 -27
- package/dist/cli/src/config.d.ts +0 -14
- package/dist/cli/src/config.js +0 -23
- package/dist/cli/src/config.js.map +0 -1
- package/dist/cli/src/machine-id.d.ts +0 -6
- package/dist/cli/src/machine-id.js +0 -50
- package/dist/cli/src/machine-id.js.map +0 -1
- package/dist/cli/src/providers.d.ts +0 -13
- package/dist/cli/src/providers.js +0 -77
- package/dist/cli/src/providers.js.map +0 -1
- package/dist/cli/src/runtime/acp/acp-client.d.ts +0 -128
- package/dist/cli/src/runtime/acp/acp-client.js +0 -430
- package/dist/cli/src/runtime/acp/acp-client.js.map +0 -1
- package/dist/cli/src/runtime/acp/agent-process-discovery.d.ts +0 -48
- package/dist/cli/src/runtime/acp/agent-process-discovery.js +0 -278
- package/dist/cli/src/runtime/acp/agent-process-discovery.js.map +0 -1
- package/dist/cli/src/runtime/acp/agent-session.d.ts +0 -62
- package/dist/cli/src/runtime/acp/agent-session.js +0 -1081
- package/dist/cli/src/runtime/acp/agent-session.js.map +0 -1
- package/dist/cli/src/runtime/acp/agent-workspace.d.ts +0 -311
- package/dist/cli/src/runtime/acp/agent-workspace.js +0 -6083
- package/dist/cli/src/runtime/acp/agent-workspace.js.map +0 -1
- package/dist/cli/src/runtime/acp/claude-sdk-client.d.ts +0 -121
- package/dist/cli/src/runtime/acp/claude-sdk-client.js +0 -1147
- package/dist/cli/src/runtime/acp/claude-sdk-client.js.map +0 -1
- package/dist/cli/src/runtime/acp/claude-stream-json-client.d.ts +0 -53
- package/dist/cli/src/runtime/acp/claude-stream-json-client.js +0 -552
- package/dist/cli/src/runtime/acp/claude-stream-json-client.js.map +0 -1
- package/dist/cli/src/runtime/acp/json-rpc.d.ts +0 -22
- package/dist/cli/src/runtime/acp/json-rpc.js +0 -160
- package/dist/cli/src/runtime/acp/json-rpc.js.map +0 -1
- package/dist/cli/src/runtime/acp/provider-resolver.d.ts +0 -16
- package/dist/cli/src/runtime/acp/provider-resolver.js +0 -132
- package/dist/cli/src/runtime/acp/provider-resolver.js.map +0 -1
- package/dist/cli/src/runtime/bridge-session.d.ts +0 -97
- package/dist/cli/src/runtime/bridge-session.js +0 -1364
- package/dist/cli/src/runtime/bridge-session.js.map +0 -1
- package/dist/cli/src/runtime/hook-command.d.ts +0 -9
- package/dist/cli/src/runtime/hook-command.js +0 -80
- package/dist/cli/src/runtime/hook-command.js.map +0 -1
- package/dist/cli/src/runtime/screen-fallback.d.ts +0 -22
- package/dist/cli/src/runtime/screen-fallback.js +0 -202
- package/dist/cli/src/runtime/screen-fallback.js.map +0 -1
- package/dist/cli/src/runtime/screen-share.d.ts +0 -34
- package/dist/cli/src/runtime/screen-share.js +0 -376
- package/dist/cli/src/runtime/screen-share.js.map +0 -1
- package/dist/cli/src/runtime/scrollback.d.ts +0 -11
- package/dist/cli/src/runtime/scrollback.js +0 -33
- package/dist/cli/src/runtime/scrollback.js.map +0 -1
- package/dist/cli/src/runtime/usage-report.d.ts +0 -34
- package/dist/cli/src/runtime/usage-report.js +0 -332
- package/dist/cli/src/runtime/usage-report.js.map +0 -1
- package/dist/cli/src/utils/keep-awake.d.ts +0 -6
- package/dist/cli/src/utils/keep-awake.js +0 -48
- package/dist/cli/src/utils/keep-awake.js.map +0 -1
- package/dist/cli/src/utils/lan-ip.d.ts +0 -9
- package/dist/cli/src/utils/lan-ip.js +0 -61
- package/dist/cli/src/utils/lan-ip.js.map +0 -1
- package/dist/host/src/input-helper.d.ts +0 -1
- package/dist/host/src/input-helper.js +0 -564
- package/dist/host/src/input-helper.js.map +0 -1
- package/dist/shared-protocol/src/index.d.ts +0 -17029
- package/dist/shared-protocol/src/index.js +0 -1064
- package/dist/shared-protocol/src/index.js.map +0 -1
- package/scripts/copy-web.mjs +0 -34
- package/src/config.ts +0 -36
- package/src/machine-id.ts +0 -61
- package/src/providers.ts +0 -97
- package/src/runtime/acp/acp-client.ts +0 -521
- package/src/runtime/acp/agent-process-discovery.ts +0 -308
- package/src/runtime/acp/agent-session.ts +0 -1186
- package/src/runtime/acp/agent-workspace.ts +0 -6590
- package/src/runtime/acp/claude-sdk-client.ts +0 -1221
- package/src/runtime/acp/claude-stream-json-client.ts +0 -633
- package/src/runtime/acp/json-rpc.ts +0 -184
- package/src/runtime/acp/provider-resolver.ts +0 -154
- package/src/runtime/bridge-session.ts +0 -1549
- package/src/runtime/hook-command.ts +0 -73
- package/src/runtime/screen-fallback.ts +0 -235
- package/src/runtime/screen-share.ts +0 -426
- package/src/runtime/scrollback.ts +0 -43
- package/src/runtime/usage-report.ts +0 -342
- package/src/utils/keep-awake.ts +0 -61
- package/src/utils/lan-ip.ts +0 -61
- package/web/assets/FileBrowser-wOAfY-xj.js +0 -2
- package/web/assets/PortPreview-Cbvv7yzA.js +0 -2
- package/web/assets/TerminalPanel-CTSklkct.js +0 -1
- package/web/assets/UsageDashboard-CJ1AsNmd.js +0 -1
- package/web/assets/index-BsnDaeCt.css +0 -33
- package/web/assets/index-q85psYZ5.js +0 -36
- package/web/assets/vendor-highlight-NXWAAyIv.js +0 -5
- package/web/assets/vendor-react-M7xG3qiw.js +0 -49
- package/web/assets/vendor-xterm-D15THcI4.js +0 -9
- package/web/index.html +0 -37
- package/web/logos/claude.png +0 -0
- package/web/logos/codex.png +0 -0
- package/web/logos/copilot.png +0 -0
- package/web/logos/gemini.png +0 -0
- package/web/logos/linkshell-1024.png +0 -0
- package/web/logos/linkshell-splash.png +0 -0
- package/web/logos/linkshell.png +0 -0
package/src/commands/setup.ts
CHANGED
|
@@ -1,75 +1,117 @@
|
|
|
1
1
|
import * as readline from "node:readline";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
}
|