linkshell-cli 0.9.0 → 0.10.1

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 (168) 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/drivers/codex/app-server.d.ts +31 -6
  42. package/dist/host/src/drivers/codex/app-server.js +99 -24
  43. package/dist/host/src/drivers/codex/app-server.js.map +1 -1
  44. package/dist/host/src/drivers/codex/desktop-ipc.d.ts +8 -0
  45. package/dist/host/src/drivers/codex/desktop-ipc.js +124 -0
  46. package/dist/host/src/drivers/codex/desktop-ipc.js.map +1 -0
  47. package/dist/host/src/drivers/codex/driver.d.ts +111 -2
  48. package/dist/host/src/drivers/codex/driver.js +629 -63
  49. package/dist/host/src/drivers/codex/driver.js.map +1 -1
  50. package/dist/host/src/drivers/codex/mapper.d.ts +21 -0
  51. package/dist/host/src/drivers/codex/mapper.js +45 -6
  52. package/dist/host/src/drivers/codex/mapper.js.map +1 -1
  53. package/dist/host/src/drivers/types.d.ts +6 -0
  54. package/dist/host/src/fs.d.ts +3 -3
  55. package/dist/host/src/hub.js +8 -1
  56. package/dist/host/src/hub.js.map +1 -1
  57. package/dist/host/src/input.d.ts +4 -4
  58. package/dist/host/src/terminals.d.ts +1 -1
  59. package/dist/wire/src/model.d.ts +6 -6
  60. package/dist/wire/src/relay.d.ts +8 -8
  61. package/dist/wire/src/rpc.d.ts +818 -818
  62. package/dist/wire/src/updates.d.ts +18 -18
  63. package/package.json +5 -14
  64. package/src/commands/gateway.ts +31 -0
  65. package/src/commands/host.ts +13 -2
  66. package/src/commands/setup.ts +4 -2
  67. package/src/index.ts +14 -429
  68. package/src/utils/daemon.ts +2 -27
  69. package/dist/cli/src/config.d.ts +0 -14
  70. package/dist/cli/src/config.js +0 -23
  71. package/dist/cli/src/config.js.map +0 -1
  72. package/dist/cli/src/machine-id.d.ts +0 -6
  73. package/dist/cli/src/machine-id.js +0 -50
  74. package/dist/cli/src/machine-id.js.map +0 -1
  75. package/dist/cli/src/providers.d.ts +0 -13
  76. package/dist/cli/src/providers.js +0 -77
  77. package/dist/cli/src/providers.js.map +0 -1
  78. package/dist/cli/src/runtime/acp/acp-client.d.ts +0 -128
  79. package/dist/cli/src/runtime/acp/acp-client.js +0 -430
  80. package/dist/cli/src/runtime/acp/acp-client.js.map +0 -1
  81. package/dist/cli/src/runtime/acp/agent-process-discovery.d.ts +0 -48
  82. package/dist/cli/src/runtime/acp/agent-process-discovery.js +0 -278
  83. package/dist/cli/src/runtime/acp/agent-process-discovery.js.map +0 -1
  84. package/dist/cli/src/runtime/acp/agent-session.d.ts +0 -62
  85. package/dist/cli/src/runtime/acp/agent-session.js +0 -1081
  86. package/dist/cli/src/runtime/acp/agent-session.js.map +0 -1
  87. package/dist/cli/src/runtime/acp/agent-workspace.d.ts +0 -311
  88. package/dist/cli/src/runtime/acp/agent-workspace.js +0 -6083
  89. package/dist/cli/src/runtime/acp/agent-workspace.js.map +0 -1
  90. package/dist/cli/src/runtime/acp/claude-sdk-client.d.ts +0 -121
  91. package/dist/cli/src/runtime/acp/claude-sdk-client.js +0 -1147
  92. package/dist/cli/src/runtime/acp/claude-sdk-client.js.map +0 -1
  93. package/dist/cli/src/runtime/acp/claude-stream-json-client.d.ts +0 -53
  94. package/dist/cli/src/runtime/acp/claude-stream-json-client.js +0 -552
  95. package/dist/cli/src/runtime/acp/claude-stream-json-client.js.map +0 -1
  96. package/dist/cli/src/runtime/acp/json-rpc.d.ts +0 -22
  97. package/dist/cli/src/runtime/acp/json-rpc.js +0 -160
  98. package/dist/cli/src/runtime/acp/json-rpc.js.map +0 -1
  99. package/dist/cli/src/runtime/acp/provider-resolver.d.ts +0 -16
  100. package/dist/cli/src/runtime/acp/provider-resolver.js +0 -132
  101. package/dist/cli/src/runtime/acp/provider-resolver.js.map +0 -1
  102. package/dist/cli/src/runtime/bridge-session.d.ts +0 -97
  103. package/dist/cli/src/runtime/bridge-session.js +0 -1364
  104. package/dist/cli/src/runtime/bridge-session.js.map +0 -1
  105. package/dist/cli/src/runtime/hook-command.d.ts +0 -9
  106. package/dist/cli/src/runtime/hook-command.js +0 -80
  107. package/dist/cli/src/runtime/hook-command.js.map +0 -1
  108. package/dist/cli/src/runtime/screen-fallback.d.ts +0 -22
  109. package/dist/cli/src/runtime/screen-fallback.js +0 -202
  110. package/dist/cli/src/runtime/screen-fallback.js.map +0 -1
  111. package/dist/cli/src/runtime/screen-share.d.ts +0 -34
  112. package/dist/cli/src/runtime/screen-share.js +0 -376
  113. package/dist/cli/src/runtime/screen-share.js.map +0 -1
  114. package/dist/cli/src/runtime/scrollback.d.ts +0 -11
  115. package/dist/cli/src/runtime/scrollback.js +0 -33
  116. package/dist/cli/src/runtime/scrollback.js.map +0 -1
  117. package/dist/cli/src/runtime/usage-report.d.ts +0 -34
  118. package/dist/cli/src/runtime/usage-report.js +0 -332
  119. package/dist/cli/src/runtime/usage-report.js.map +0 -1
  120. package/dist/cli/src/utils/keep-awake.d.ts +0 -6
  121. package/dist/cli/src/utils/keep-awake.js +0 -48
  122. package/dist/cli/src/utils/keep-awake.js.map +0 -1
  123. package/dist/cli/src/utils/lan-ip.d.ts +0 -9
  124. package/dist/cli/src/utils/lan-ip.js +0 -61
  125. package/dist/cli/src/utils/lan-ip.js.map +0 -1
  126. package/dist/host/src/input-helper.d.ts +0 -1
  127. package/dist/host/src/input-helper.js +0 -564
  128. package/dist/host/src/input-helper.js.map +0 -1
  129. package/dist/shared-protocol/src/index.d.ts +0 -17029
  130. package/dist/shared-protocol/src/index.js +0 -1064
  131. package/dist/shared-protocol/src/index.js.map +0 -1
  132. package/scripts/copy-web.mjs +0 -34
  133. package/src/config.ts +0 -36
  134. package/src/machine-id.ts +0 -61
  135. package/src/providers.ts +0 -97
  136. package/src/runtime/acp/acp-client.ts +0 -521
  137. package/src/runtime/acp/agent-process-discovery.ts +0 -308
  138. package/src/runtime/acp/agent-session.ts +0 -1186
  139. package/src/runtime/acp/agent-workspace.ts +0 -6590
  140. package/src/runtime/acp/claude-sdk-client.ts +0 -1221
  141. package/src/runtime/acp/claude-stream-json-client.ts +0 -633
  142. package/src/runtime/acp/json-rpc.ts +0 -184
  143. package/src/runtime/acp/provider-resolver.ts +0 -154
  144. package/src/runtime/bridge-session.ts +0 -1549
  145. package/src/runtime/hook-command.ts +0 -73
  146. package/src/runtime/screen-fallback.ts +0 -235
  147. package/src/runtime/screen-share.ts +0 -426
  148. package/src/runtime/scrollback.ts +0 -43
  149. package/src/runtime/usage-report.ts +0 -342
  150. package/src/utils/keep-awake.ts +0 -61
  151. package/src/utils/lan-ip.ts +0 -61
  152. package/web/assets/FileBrowser-wOAfY-xj.js +0 -2
  153. package/web/assets/PortPreview-Cbvv7yzA.js +0 -2
  154. package/web/assets/TerminalPanel-CTSklkct.js +0 -1
  155. package/web/assets/UsageDashboard-CJ1AsNmd.js +0 -1
  156. package/web/assets/index-BsnDaeCt.css +0 -33
  157. package/web/assets/index-q85psYZ5.js +0 -36
  158. package/web/assets/vendor-highlight-NXWAAyIv.js +0 -5
  159. package/web/assets/vendor-react-M7xG3qiw.js +0 -49
  160. package/web/assets/vendor-xterm-D15THcI4.js +0 -9
  161. package/web/index.html +0 -37
  162. package/web/logos/claude.png +0 -0
  163. package/web/logos/codex.png +0 -0
  164. package/web/logos/copilot.png +0 -0
  165. package/web/logos/gemini.png +0 -0
  166. package/web/logos/linkshell-1024.png +0 -0
  167. package/web/logos/linkshell-splash.png +0 -0
  168. 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
- }