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,73 +0,0 @@
1
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
- import { join } from "node:path";
3
-
4
- /** Pre-marker CLI: `curl -X POST http://127.0.0.1:<port>/hook --data-binary @-`. */
5
- const LEGACY_LOCAL_HOOK =
6
- /https?:\/\/127\.0\.0\.1:\d+\/hook(?:\?|"|'|\s|$|\\)/;
7
-
8
- function hookEntryText(entry: unknown): string {
9
- try {
10
- return JSON.stringify(entry);
11
- } catch {
12
- return String(entry);
13
- }
14
- }
15
-
16
- /** True for current (`/hook?m=lsh-…`) and legacy localhost `/hook` curl entries. */
17
- export function isLinkShellHookEntry(entry: unknown, marker?: string): boolean {
18
- const raw = hookEntryText(entry);
19
- if (marker && raw.includes(`/hook?m=${marker}`)) return true;
20
- if (raw.includes("/hook?m=lsh-")) return true;
21
- if (raw.includes("/hook?m=") && raw.includes("LINKSHELL_ID")) return true;
22
- return LEGACY_LOCAL_HOOK.test(raw) && raw.includes("--data-binary @-");
23
- }
24
-
25
- function sweepHooksObject(hooks: Record<string, unknown>): boolean {
26
- let changed = false;
27
- for (const [eventName, entries] of Object.entries(hooks)) {
28
- if (!Array.isArray(entries)) continue;
29
- const filtered = entries.filter((entry) => !isLinkShellHookEntry(entry));
30
- if (filtered.length !== entries.length) {
31
- changed = true;
32
- if (filtered.length === 0) delete hooks[eventName];
33
- else hooks[eventName] = filtered;
34
- }
35
- }
36
- return changed;
37
- }
38
-
39
- /** Remove leftover LinkShell hook entries from one JSON settings/hooks file. */
40
- export function sweepLinkShellHookEntries(configPath: string): boolean {
41
- if (!existsSync(configPath)) return false;
42
- try {
43
- const raw = JSON.parse(readFileSync(configPath, "utf8")) as Record<string, unknown>;
44
- const hooks = raw.hooks;
45
- if (!hooks || typeof hooks !== "object" || Array.isArray(hooks)) return false;
46
- const changed = sweepHooksObject(hooks as Record<string, unknown>);
47
- if (!changed) return false;
48
- if (Object.keys(hooks as object).length === 0) delete raw.hooks;
49
- writeFileSync(configPath, `${JSON.stringify(raw, null, 2)}\n`);
50
- return true;
51
- } catch {
52
- return false;
53
- }
54
- }
55
-
56
- /**
57
- * One-shot leftover sweep. LinkShell no longer writes hook configs; this only
58
- * deletes historical curl-hook entries so they cannot fire after upgrade.
59
- */
60
- export function sweepLinkShellHookConfigs(home: string, extraPaths: string[] = []): string[] {
61
- const candidates = [
62
- join(home, ".claude", "settings.json"),
63
- join(home, ".claude", "settings.local.json"),
64
- join(home, ".codex", "hooks.json"),
65
- join(home, ".gemini", "settings.json"),
66
- ...extraPaths,
67
- ];
68
- const swept: string[] = [];
69
- for (const path of candidates) {
70
- if (sweepLinkShellHookEntries(path)) swept.push(path);
71
- }
72
- return swept;
73
- }
@@ -1,235 +0,0 @@
1
- import { execSync, spawn } from "node:child_process";
2
- import { readFileSync, unlinkSync, existsSync } from "node:fs";
3
- import { tmpdir } from "node:os";
4
- import { join } from "node:path";
5
- import { platform } from "node:os";
6
- import { createEnvelope, serializeEnvelope } from "@linkshell/protocol";
7
- import type { Envelope } from "@linkshell/protocol";
8
-
9
- export interface ScreenFallbackOptions {
10
- fps: number;
11
- quality: number;
12
- scale: number;
13
- sessionId: string;
14
- onFrame: (envelope: Envelope) => void;
15
- onStatus: (envelope: Envelope) => void;
16
- }
17
-
18
- const CHUNK_SIZE = 48 * 1024; // 48KB per chunk, leave room for envelope overhead
19
- const TMP_FILE = join(tmpdir(), `linkshell-screen-${process.pid}.jpg`);
20
-
21
- export class ScreenFallback {
22
- private timer: ReturnType<typeof setInterval> | undefined;
23
- private frameId = 0;
24
- private active = false;
25
- private readonly options: ScreenFallbackOptions;
26
-
27
- constructor(options: ScreenFallbackOptions) {
28
- this.options = options;
29
- }
30
-
31
- start(): void {
32
- if (this.active) return;
33
- this.active = true;
34
- this.frameId = 0;
35
-
36
- const interval = Math.max(50, Math.floor(1000 / this.options.fps));
37
-
38
- this.options.onStatus(
39
- createEnvelope({
40
- type: "screen.status",
41
- sessionId: this.options.sessionId,
42
- payload: { active: true, mode: "fallback" as const },
43
- }),
44
- );
45
-
46
- // Capture first frame immediately
47
- this.captureAndSend();
48
-
49
- this.timer = setInterval(() => {
50
- this.captureAndSend();
51
- }, interval);
52
- }
53
-
54
- stop(): void {
55
- if (!this.active) return;
56
- this.active = false;
57
- if (this.timer) {
58
- clearInterval(this.timer);
59
- this.timer = undefined;
60
- }
61
- // Clean up temp file
62
- try { if (existsSync(TMP_FILE)) unlinkSync(TMP_FILE); } catch {}
63
-
64
- this.options.onStatus(
65
- createEnvelope({
66
- type: "screen.status",
67
- sessionId: this.options.sessionId,
68
- payload: { active: false, mode: "off" as const },
69
- }),
70
- );
71
- }
72
-
73
- private captureAndSend(): void {
74
- if (!this.active) return;
75
-
76
- try {
77
- const imgBuffer = this.captureScreen();
78
- if (!imgBuffer || imgBuffer.length === 0) return;
79
-
80
- const base64 = imgBuffer.toString("base64");
81
- const frameId = this.frameId++;
82
-
83
- // Get dimensions (approximate from JPEG header or use defaults)
84
- const dims = this.getJpegDimensions(imgBuffer);
85
-
86
- if (base64.length <= CHUNK_SIZE) {
87
- // Single chunk
88
- this.options.onFrame(
89
- createEnvelope({
90
- type: "screen.frame",
91
- sessionId: this.options.sessionId,
92
- payload: {
93
- data: base64,
94
- width: dims.width,
95
- height: dims.height,
96
- frameId,
97
- chunkIndex: 0,
98
- chunkTotal: 1,
99
- },
100
- }),
101
- );
102
- } else {
103
- // Split into chunks
104
- const chunkTotal = Math.ceil(base64.length / CHUNK_SIZE);
105
- for (let i = 0; i < chunkTotal; i++) {
106
- if (!this.active) return;
107
- const chunk = base64.slice(i * CHUNK_SIZE, (i + 1) * CHUNK_SIZE);
108
- this.options.onFrame(
109
- createEnvelope({
110
- type: "screen.frame",
111
- sessionId: this.options.sessionId,
112
- payload: {
113
- data: chunk,
114
- width: dims.width,
115
- height: dims.height,
116
- frameId,
117
- chunkIndex: i,
118
- chunkTotal,
119
- },
120
- }),
121
- );
122
- }
123
- }
124
- } catch {
125
- // Silently skip failed frames
126
- }
127
- }
128
-
129
- private captureScreen(): Buffer | null {
130
- const os = platform();
131
- const q = this.options.quality;
132
- const s = this.options.scale;
133
-
134
- try {
135
- if (os === "darwin") {
136
- // macOS: screencapture
137
- execSync(
138
- `screencapture -x -t jpg -C "${TMP_FILE}"`,
139
- { timeout: 3000, stdio: "pipe" },
140
- );
141
- if (!existsSync(TMP_FILE)) return null;
142
- let buf = readFileSync(TMP_FILE);
143
-
144
- // Resize if scale < 1 and sips is available
145
- if (s < 1) {
146
- try {
147
- const w = Math.floor(this.getJpegDimensions(buf).width * s);
148
- execSync(
149
- `sips --resampleWidth ${w} -s formatOptions ${q} "${TMP_FILE}" --out "${TMP_FILE}"`,
150
- { timeout: 3000, stdio: "pipe" },
151
- );
152
- buf = readFileSync(TMP_FILE);
153
- } catch {
154
- // Use original size if resize fails
155
- }
156
- }
157
- return buf;
158
- }
159
-
160
- if (os === "linux") {
161
- // Linux: try import (ImageMagick) or scrot
162
- try {
163
- const resizeArg = s < 1 ? `-resize ${Math.floor(s * 100)}%` : "";
164
- execSync(
165
- `import -window root -quality ${q} ${resizeArg} jpeg:"${TMP_FILE}"`,
166
- { timeout: 3000, stdio: "pipe" },
167
- );
168
- } catch {
169
- // Fallback to scrot
170
- execSync(
171
- `scrot -q ${q} "${TMP_FILE}"`,
172
- { timeout: 3000, stdio: "pipe" },
173
- );
174
- }
175
- if (!existsSync(TMP_FILE)) return null;
176
- return readFileSync(TMP_FILE);
177
- }
178
-
179
- // Windows: use PowerShell
180
- if (os === "win32") {
181
- execSync(
182
- `powershell -Command "Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.Screen]::PrimaryScreen | ForEach-Object { $bmp = New-Object System.Drawing.Bitmap($_.Bounds.Width, $_.Bounds.Height); $g = [System.Drawing.Graphics]::FromImage($bmp); $g.CopyFromScreen($_.Bounds.Location, [System.Drawing.Point]::Empty, $_.Bounds.Size); $bmp.Save('${TMP_FILE.replace(/\\/g, "\\\\")}', [System.Drawing.Imaging.ImageFormat]::Jpeg) }"`,
183
- { timeout: 5000, stdio: "pipe" },
184
- );
185
- if (!existsSync(TMP_FILE)) return null;
186
- return readFileSync(TMP_FILE);
187
- }
188
-
189
- return null;
190
- } catch {
191
- return null;
192
- }
193
- }
194
-
195
- private getJpegDimensions(buf: Buffer): { width: number; height: number } {
196
- // Parse JPEG SOF marker for dimensions
197
- try {
198
- let i = 2; // Skip SOI
199
- while (i < buf.length - 8) {
200
- if (buf[i] !== 0xff) break;
201
- const marker = buf[i + 1]!;
202
- // SOF0, SOF1, SOF2
203
- if (marker >= 0xc0 && marker <= 0xc2) {
204
- const height = buf.readUInt16BE(i + 5);
205
- const width = buf.readUInt16BE(i + 7);
206
- return { width, height };
207
- }
208
- const len = buf.readUInt16BE(i + 2);
209
- i += 2 + len;
210
- }
211
- } catch {}
212
- return { width: 1920, height: 1080 }; // Default fallback
213
- }
214
-
215
- static isAvailable(): boolean {
216
- const os = platform();
217
- try {
218
- if (os === "darwin") {
219
- execSync("which screencapture", { stdio: "pipe" });
220
- return true;
221
- }
222
- if (os === "linux") {
223
- try {
224
- execSync("which import", { stdio: "pipe" });
225
- return true;
226
- } catch {
227
- execSync("which scrot", { stdio: "pipe" });
228
- return true;
229
- }
230
- }
231
- if (os === "win32") return true; // PowerShell always available
232
- } catch {}
233
- return false;
234
- }
235
- }