linkshell-cli 0.5.8 → 0.5.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linkshell-cli",
3
- "version": "0.5.8",
3
+ "version": "0.5.9",
4
4
  "description": "Remote terminal bridge for Claude Code / Codex / Gemini / Copilot — control from your phone",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -11,6 +11,7 @@
11
11
  "dist",
12
12
  "src",
13
13
  "scripts",
14
+ "web",
14
15
  "README.md",
15
16
  "LICENSE"
16
17
  ],
@@ -35,8 +36,8 @@
35
36
  "qrcode-terminal": "^0.12.0",
36
37
  "ws": "^8.18.1",
37
38
  "zod": "^3.24.3",
38
- "@linkshell/protocol": "0.4.4",
39
- "@linkshell/gateway": "0.4.15"
39
+ "@linkshell/gateway": "0.4.27",
40
+ "@linkshell/protocol": "0.4.4"
40
41
  },
41
42
  "optionalDependencies": {
42
43
  "@anthropic-ai/claude-agent-sdk": "^0.2.128",
@@ -48,7 +49,7 @@
48
49
  "vitest": "^3.2.1"
49
50
  },
50
51
  "scripts": {
51
- "build": "tsc -p tsconfig.json",
52
+ "build": "tsc -p tsconfig.json && node scripts/copy-web.mjs",
52
53
  "postinstall": "node scripts/postinstall.mjs",
53
54
  "typecheck": "tsc -p tsconfig.json --noEmit",
54
55
  "dev": "tsx src/index.ts",
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ // Copy the built web-dashboard SPA into the CLI package (packages/cli/web) so
3
+ // it ships in the npm tarball. The CLI's embedded gateway then serves it via
4
+ // WEB_DIST, giving LAN / self-hosted users the same in-app web console that the
5
+ // cloud gateway Docker image bundles separately.
6
+ //
7
+ // Non-fatal when the web build is absent: a CLI-only `tsc` build still
8
+ // succeeds; the embedded gateway just logs "web UI not bundled". Release builds
9
+ // must build apps/web-dashboard FIRST so this copy has something to pick up.
10
+ import { cpSync, existsSync, rmSync } from "node:fs";
11
+ import { dirname, resolve } from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+
14
+ const here = dirname(fileURLToPath(import.meta.url)); // packages/cli/scripts
15
+ const src = resolve(here, "../../../apps/web-dashboard/dist");
16
+ const dest = resolve(here, "../web"); // packages/cli/web
17
+
18
+ if (!existsSync(resolve(src, "index.html"))) {
19
+ console.warn(
20
+ `[copy-web] web-dashboard build not found at ${src} — skipping. ` +
21
+ `The in-app agent console will be blank for embedded-gateway users. ` +
22
+ `Run \`pnpm --filter @linkshell/web-dashboard build\` first.`,
23
+ );
24
+ process.exit(0);
25
+ }
26
+
27
+ try {
28
+ rmSync(dest, { recursive: true, force: true });
29
+ cpSync(src, dest, { recursive: true });
30
+ console.log(`[copy-web] copied ${src} -> ${dest}`);
31
+ } catch (err) {
32
+ console.error(`[copy-web] failed to copy web dist: ${err}`);
33
+ process.exit(1);
34
+ }
package/src/index.ts CHANGED
@@ -12,10 +12,39 @@ import { getLanIp } from "./utils/lan-ip.js";
12
12
  import { shouldKeepAwake } from "./utils/keep-awake.js";
13
13
 
14
14
  import { createRequire } from "node:module";
15
+ import { fileURLToPath } from "node:url";
16
+ import { dirname, resolve } from "node:path";
17
+ import { existsSync, statSync } from "node:fs";
15
18
 
16
19
  const require = createRequire(import.meta.url);
17
20
  const pkg = require("../../../package.json") as { version: string };
18
21
 
22
+ // Locate the bundled web-dashboard SPA and point the (embedded) gateway's
23
+ // static server at it via WEB_DIST — BEFORE any gateway module is imported,
24
+ // because static-web.ts freezes WEB_DIST at module-load time. This is what lets
25
+ // the in-app WebView render for LAN / self-hosted users whose CLI runs its own
26
+ // embedded gateway (the cloud image bundles web separately). A user-set
27
+ // WEB_DIST always wins. Probed across published-package, monorepo-compiled, and
28
+ // dev (tsx) layouts; the first candidate containing index.html is used.
29
+ if (!process.env.WEB_DIST) {
30
+ const here = dirname(fileURLToPath(import.meta.url));
31
+ const candidates = [
32
+ resolve(here, "../../../web"), // published npm package root, and packages/cli/web (compiled)
33
+ resolve(here, "../../../apps/web-dashboard/dist"), // dev: tsx src/index.ts in the monorepo
34
+ ];
35
+ for (const dir of candidates) {
36
+ try {
37
+ if (existsSync(resolve(dir, "index.html")) && statSync(dir).isDirectory()) {
38
+ process.env.WEB_DIST = dir;
39
+ break;
40
+ }
41
+ } catch {
42
+ // ignore and try the next candidate
43
+ }
44
+ }
45
+ }
46
+
47
+
19
48
  const config = loadConfig();
20
49
  const program = new Command();
21
50