lg-dev-manager-bridge 1.0.1 → 1.0.2
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
CHANGED
|
@@ -24,20 +24,52 @@ A web rebuild of [webosbrew/dev-manager-desktop](https://github.com/webosbrew/de
|
|
|
24
24
|
|
|
25
25
|
## 🚀 Get started
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
The app needs a small helper on your computer, **the bridge** (why: [How it works](#how-it-works)). There are three
|
|
28
|
+
ways to run it. It's the same bridge every time, so pick whichever suits you:
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
| | Needs | How |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| 🖥️ **The app** | nothing | Download it from the [latest release](https://github.com/Scoty/lg-dev-manager/releases/latest) and open it |
|
|
33
|
+
| 📦 **npx** | Node.js 22.12+ | `npx lg-dev-manager-bridge@latest` in a terminal |
|
|
34
|
+
| 🛠️ **From the source code** | Node.js 22.12+ | [Clone, build and run](#run-from-source) |
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
npx lg-dev-manager-bridge@latest
|
|
35
|
-
```
|
|
36
|
+
### 🖥️ Option 1: the app — no Node.js needed
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
One file with everything inside. Download the one for your computer from the
|
|
39
|
+
[latest release](https://github.com/Scoty/lg-dev-manager/releases/latest):
|
|
40
|
+
|
|
41
|
+
| Computer | File |
|
|
42
|
+
|---|---|
|
|
43
|
+
| 🪟 Windows | `lg-dev-manager-bridge-<version>-windows-x64.exe` — just run it (also works on Windows on ARM) |
|
|
44
|
+
| 🍎 Mac with Apple Silicon (M1 and newer) | `…-macos-arm64.dmg` — open it, then double-click `lg-dev-manager-bridge` |
|
|
45
|
+
| 🍎 Mac with Intel | `…-macos-x64.dmg` |
|
|
46
|
+
| 🐧 Linux (x64 / ARM64) | `…-linux-x64.tar.gz` / `…-linux-arm64.tar.gz` — `tar -xzf …`, then `./lg-dev-manager-bridge` |
|
|
47
|
+
|
|
48
|
+
A window opens with the **pairing token**, and https://lg.scoty.uk opens in your browser. Keep the window open while you
|
|
49
|
+
use the app; closing it stops the bridge.
|
|
50
|
+
|
|
51
|
+
> 🔐 **The first time:** the app isn't signed by Apple or Microsoft (that costs a yearly fee), so your computer asks
|
|
52
|
+
> before running it. **Windows**: "Windows protected your PC" → **More info** → **Run anyway**. **macOS**: "Apple
|
|
53
|
+
> could not verify…" → **Done**, then **System Settings → Privacy & Security** → **Open Anyway**. You only do this
|
|
54
|
+
> once. It's the same code as the npm package, built and tested by GitHub Actions in public. Each release lists
|
|
55
|
+
> SHA-256 checksums.
|
|
56
|
+
|
|
57
|
+
### 📦 Option 2: npx
|
|
58
|
+
|
|
59
|
+
**You need [Node.js](https://nodejs.org) 22.12 or newer** (any current LTS — 22 or 24). `node --version` shows
|
|
60
|
+
yours. In a terminal:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npx lg-dev-manager-bridge@latest
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
It prints a **pairing token**. Keep the terminal open while you use the app (Ctrl+C stops it).
|
|
67
|
+
|
|
68
|
+
### 🔗 Then, whichever way you chose
|
|
69
|
+
|
|
70
|
+
1. Open **https://lg.scoty.uk**, or the local page the bridge serves at **http://localhost:5199** — they are the
|
|
39
71
|
same app. On the **Bridge** page, paste the token.
|
|
40
|
-
|
|
72
|
+
2. On **Devices → Add a TV**, pick your TV from the scan. Rooted TVs log in as root (Homebrew Channel's SSH server);
|
|
41
73
|
other TVs use the Developer Mode app and its passphrase.
|
|
42
74
|
|
|
43
75
|
🍎 On macOS, the first time the bridge looks for your TV, the system asks whether your terminal may find devices on the
|
|
@@ -49,6 +81,8 @@ bridge. 🏠 **http://localhost:5199** is served from your computer by the bridg
|
|
|
49
81
|
website can't be reached. Each keeps its own list of TVs (browsers store them per site); use **Export backup** / **Import backup** on
|
|
50
82
|
the Devices page to move them.
|
|
51
83
|
|
|
84
|
+
<a id="how-it-works"></a>
|
|
85
|
+
|
|
52
86
|
## 🔧 How it works
|
|
53
87
|
|
|
54
88
|
Browsers can't open SSH connections, so the app comes in two parts:
|
|
@@ -57,7 +91,7 @@ Browsers can't open SSH connections, so the app comes in two parts:
|
|
|
57
91
|
Browser (lg.scoty.uk or localhost:5199) Your computer Your TV
|
|
58
92
|
┌──────────────────────────────────┐ WebSocket ┌────────────────────┐ SSH / SFTP ┌──────────────┐
|
|
59
93
|
│ Web app — your TVs, keys and │ ────────────▶ │ Bridge │ ─────────────▶ │ webOS │
|
|
60
|
-
│ passwords are stored only here │ 127.0.0.1 │ (
|
|
94
|
+
│ passwords are stored only here │ 127.0.0.1 │ (app or npx) │ │ (port 22 or │
|
|
61
95
|
└──────────────────────────────────┘ + token └────────────────────┘ │ 9922) │
|
|
62
96
|
└──────────────┘
|
|
63
97
|
```
|
|
@@ -71,8 +105,9 @@ Browsers can't open SSH connections, so the app comes in two parts:
|
|
|
71
105
|
- 📦 **Homebrew repository and Litefin releases** are fetched by the bridge, so the site itself talks to no one but your
|
|
72
106
|
bridge. Downloads are checked against their published SHA-256 whenever one is published.
|
|
73
107
|
|
|
74
|
-
🔄 The bridge tells the site its version; when a newer one is out, the app says so
|
|
75
|
-
|
|
108
|
+
🔄 The bridge tells the site its version; when a newer one is out, the app says so and how to update: download the
|
|
109
|
+
new app from the [releases](https://github.com/Scoty/lg-dev-manager/releases/latest), or run
|
|
110
|
+
`npx lg-dev-manager-bridge@latest` again. Your pairing and TVs stay as they are.
|
|
76
111
|
|
|
77
112
|
## ✨ What it does
|
|
78
113
|
|
|
@@ -109,9 +144,11 @@ downloading the right IPK by hand and installing it through the desktop webOS De
|
|
|
109
144
|
— through Homebrew Channel on a rooted TV, or the Developer Mode installer otherwise. All builds are the same app,
|
|
110
145
|
so switching builds or versions simply replaces it.
|
|
111
146
|
|
|
147
|
+
<a id="run-from-source"></a>
|
|
148
|
+
|
|
112
149
|
## 🛠️ Run the bridge from the source code
|
|
113
150
|
|
|
114
|
-
|
|
151
|
+
The third way: run it from a clone. It's the same bridge, and it serves the local page too:
|
|
115
152
|
|
|
116
153
|
```bash
|
|
117
154
|
git clone https://github.com/Scoty/lg-dev-manager.git
|
|
@@ -125,7 +162,7 @@ pnpm bridge # same as: node apps/bridge/dist/cli.js
|
|
|
125
162
|
This needs Node.js 22.12 or newer, the same as npx (the project itself is developed on Node 24, see `.nvmrc`).
|
|
126
163
|
To update: `git pull`, `pnpm install`, `pnpm build`, then `pnpm bridge`.
|
|
127
164
|
|
|
128
|
-
Bridge options (`
|
|
165
|
+
Bridge options (`--help`; with the app, run it from a terminal: `lg-dev-manager-bridge --help`):
|
|
129
166
|
|
|
130
167
|
| Option | |
|
|
131
168
|
|---|---|
|
|
@@ -133,6 +170,8 @@ Bridge options (`npx lg-dev-manager-bridge --help`):
|
|
|
133
170
|
| `--no-ui` | Don't serve the local page |
|
|
134
171
|
| `--allow-origin <url>` | Also accept another origin, e.g. a self-hosted copy of the web app |
|
|
135
172
|
| `--reset-token` | Make a new pairing token (un-pairs every browser) |
|
|
173
|
+
| `--no-open` | The app only: don't open lg.scoty.uk in the browser when it starts |
|
|
174
|
+
| `--license` | Show the licenses of the bridge and everything it includes |
|
|
136
175
|
|
|
137
176
|
## 🧪 Development
|
|
138
177
|
|
|
@@ -143,6 +182,7 @@ pnpm test # unit and integration tests (against a mock TV)
|
|
|
143
182
|
pnpm e2e # Playwright: built app + real bridge + mock TVs + fake Homebrew repo
|
|
144
183
|
pnpm dev:rig # the same rig to try by hand: http://127.0.0.1:5299, token e2e-token
|
|
145
184
|
pnpm lint && pnpm typecheck
|
|
185
|
+
pnpm app # the standalone app for this computer → apps/bridge/release (after pnpm build)
|
|
146
186
|
```
|
|
147
187
|
|
|
148
188
|
`tools/mock-tv` fakes webOS TVs (SSH, luna-send, key server, logs) so everything can be tested without a TV.
|
package/dist/cli.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
// src/config.ts
|
|
4
4
|
import { randomBytes } from "crypto";
|
|
5
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
|
|
6
|
-
import { fileURLToPath } from "url";
|
|
5
|
+
import { chmodSync, existsSync as existsSync2, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
|
|
6
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7
7
|
import { homedir } from "os";
|
|
8
8
|
import { join } from "path";
|
|
9
9
|
|
|
@@ -346,7 +346,9 @@ var Methods = {
|
|
|
346
346
|
result: z9.object({
|
|
347
347
|
protocolVersion: z9.number().int(),
|
|
348
348
|
bridgeVersion: z9.string(),
|
|
349
|
-
platform: z9.string()
|
|
349
|
+
platform: z9.string(),
|
|
350
|
+
/** How the bridge was installed, so the site can say how to update it (bridges before 1.0.2 don't say). */
|
|
351
|
+
distribution: z9.enum(["app", "npm", "source"]).optional()
|
|
350
352
|
})
|
|
351
353
|
},
|
|
352
354
|
"system.ping": {
|
|
@@ -737,6 +739,54 @@ var UNAUTHENTICATED_METHODS = ["system.hello"];
|
|
|
737
739
|
var PUBLIC_WEB_ORIGIN = "https://lg.scoty.uk";
|
|
738
740
|
var DEFAULT_ALLOWED_ORIGINS = [PUBLIC_WEB_ORIGIN];
|
|
739
741
|
var DEV_ALLOWED_ORIGINS = ["http://localhost:5173", "http://127.0.0.1:5173"];
|
|
742
|
+
var REPO_URL = "https://github.com/Scoty/lg-dev-manager";
|
|
743
|
+
var RELEASES_URL = `${REPO_URL}/releases/latest`;
|
|
744
|
+
|
|
745
|
+
// src/standalone.ts
|
|
746
|
+
import { existsSync } from "fs";
|
|
747
|
+
import { fileURLToPath } from "url";
|
|
748
|
+
import * as sea from "sea";
|
|
749
|
+
function isStandalone() {
|
|
750
|
+
try {
|
|
751
|
+
return sea.isSea();
|
|
752
|
+
} catch {
|
|
753
|
+
return false;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
function distribution() {
|
|
757
|
+
if (isStandalone()) return "app";
|
|
758
|
+
try {
|
|
759
|
+
return existsSync(fileURLToPath(new URL("../src/", import.meta.url))) ? "source" : "npm";
|
|
760
|
+
} catch {
|
|
761
|
+
return "npm";
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
var WEB_MANIFEST_ASSET = "web-manifest.json";
|
|
765
|
+
function standaloneUi() {
|
|
766
|
+
if (!isStandalone()) return void 0;
|
|
767
|
+
try {
|
|
768
|
+
const names = JSON.parse(sea.getAsset(WEB_MANIFEST_ASSET, "utf8"));
|
|
769
|
+
if (!Array.isArray(names)) return void 0;
|
|
770
|
+
const files = /* @__PURE__ */ new Map();
|
|
771
|
+
for (const name of names) {
|
|
772
|
+
if (typeof name === "string") files.set(name, new Uint8Array(sea.getAsset(`web/${name}`)));
|
|
773
|
+
}
|
|
774
|
+
return files.has("index.html") ? files : void 0;
|
|
775
|
+
} catch {
|
|
776
|
+
return void 0;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
function licenseText() {
|
|
780
|
+
if (!isStandalone()) {
|
|
781
|
+
return `Apache-2.0. See the LICENSE and NOTICE files next to this program, or https://github.com/Scoty/lg-dev-manager/blob/main/LICENSE
|
|
782
|
+
`;
|
|
783
|
+
}
|
|
784
|
+
const rule = `
|
|
785
|
+
${"=".repeat(78)}
|
|
786
|
+
|
|
787
|
+
`;
|
|
788
|
+
return ["LICENSE", "NOTICE", "THIRD-PARTY-LICENSES.txt"].map((f) => sea.getAsset(f, "utf8").trim()).join(rule) + "\n";
|
|
789
|
+
}
|
|
740
790
|
|
|
741
791
|
// src/config.ts
|
|
742
792
|
var stateDir = () => process.env.LGDM_STATE_DIR ?? join(homedir(), ".lg-dev-manager");
|
|
@@ -769,9 +819,14 @@ function loadOrCreateToken(reset = false) {
|
|
|
769
819
|
return token;
|
|
770
820
|
}
|
|
771
821
|
function bundledUi() {
|
|
822
|
+
const packed = standaloneUi();
|
|
823
|
+
if (packed) return packed;
|
|
772
824
|
for (const rel of ["../web/", "../../web/dist/"]) {
|
|
773
|
-
|
|
774
|
-
|
|
825
|
+
try {
|
|
826
|
+
const dir = fileURLToPath2(new URL(rel, import.meta.url));
|
|
827
|
+
if (existsSync2(join(dir, "index.html"))) return dir;
|
|
828
|
+
} catch {
|
|
829
|
+
}
|
|
775
830
|
}
|
|
776
831
|
return void 0;
|
|
777
832
|
}
|
|
@@ -837,7 +892,7 @@ import { platform } from "os";
|
|
|
837
892
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
838
893
|
|
|
839
894
|
// src/version.ts
|
|
840
|
-
var BRIDGE_VERSION = "1.0.
|
|
895
|
+
var BRIDGE_VERSION = "1.0.2";
|
|
841
896
|
|
|
842
897
|
// src/ssh/logged.ts
|
|
843
898
|
import { randomUUID } from "crypto";
|
|
@@ -2603,7 +2658,7 @@ var handlers = {
|
|
|
2603
2658
|
);
|
|
2604
2659
|
}
|
|
2605
2660
|
session.authed = true;
|
|
2606
|
-
return { protocolVersion: PROTOCOL_VERSION, bridgeVersion: BRIDGE_VERSION, platform: platform() };
|
|
2661
|
+
return { protocolVersion: PROTOCOL_VERSION, bridgeVersion: BRIDGE_VERSION, platform: platform(), distribution: distribution() };
|
|
2607
2662
|
},
|
|
2608
2663
|
"system.ping": () => ({ now: Date.now() }),
|
|
2609
2664
|
"device.checkConnection": ({ host }) => checkConnection(host),
|
|
@@ -2870,7 +2925,7 @@ async function dispatch(raw, session, ctx) {
|
|
|
2870
2925
|
|
|
2871
2926
|
// src/http/static.ts
|
|
2872
2927
|
import { createReadStream, statSync } from "fs";
|
|
2873
|
-
import { extname, join as join2, normalize, resolve, sep } from "path";
|
|
2928
|
+
import { extname, join as join2, normalize, posix as posix4, resolve, sep } from "path";
|
|
2874
2929
|
var MIME = {
|
|
2875
2930
|
".html": "text/html; charset=utf-8",
|
|
2876
2931
|
".js": "text/javascript; charset=utf-8",
|
|
@@ -2898,13 +2953,29 @@ var statOf = (file) => {
|
|
|
2898
2953
|
return null;
|
|
2899
2954
|
}
|
|
2900
2955
|
};
|
|
2956
|
+
var headersFor = (name, size) => ({
|
|
2957
|
+
"content-type": MIME[extname(name)] ?? "application/octet-stream",
|
|
2958
|
+
"content-length": size,
|
|
2959
|
+
"cache-control": name.endsWith("index.html") ? "no-cache" : "public, max-age=31536000, immutable",
|
|
2960
|
+
...SECURITY_HEADERS
|
|
2961
|
+
});
|
|
2962
|
+
function serveFiles(files, urlPath, req, res) {
|
|
2963
|
+
let name = posix4.normalize(urlPath).replace(/^\/+/, "");
|
|
2964
|
+
if (!files.has(name)) name = "index.html";
|
|
2965
|
+
const body = files.get(name);
|
|
2966
|
+
if (!body) {
|
|
2967
|
+
res.writeHead(404, { "content-type": "text/plain", ...SECURITY_HEADERS }).end("Web UI missing from this build.");
|
|
2968
|
+
return;
|
|
2969
|
+
}
|
|
2970
|
+
res.writeHead(200, headersFor(name, body.byteLength));
|
|
2971
|
+
res.end(req.method === "HEAD" ? void 0 : body);
|
|
2972
|
+
}
|
|
2901
2973
|
function serveStatic(root, req, res) {
|
|
2902
2974
|
try {
|
|
2903
2975
|
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
2904
2976
|
res.writeHead(405, { allow: "GET, HEAD", ...SECURITY_HEADERS }).end();
|
|
2905
2977
|
return;
|
|
2906
2978
|
}
|
|
2907
|
-
const base = resolve(root);
|
|
2908
2979
|
let urlPath;
|
|
2909
2980
|
try {
|
|
2910
2981
|
urlPath = decodeURIComponent((req.url ?? "/").split("?")[0] ?? "/");
|
|
@@ -2916,6 +2987,11 @@ function serveStatic(root, req, res) {
|
|
|
2916
2987
|
res.writeHead(400, SECURITY_HEADERS).end();
|
|
2917
2988
|
return;
|
|
2918
2989
|
}
|
|
2990
|
+
if (typeof root !== "string") {
|
|
2991
|
+
serveFiles(root, urlPath, req, res);
|
|
2992
|
+
return;
|
|
2993
|
+
}
|
|
2994
|
+
const base = resolve(root);
|
|
2919
2995
|
let file = normalize(join2(base, urlPath));
|
|
2920
2996
|
if (!file.startsWith(base + sep) && file !== base) {
|
|
2921
2997
|
res.writeHead(403, SECURITY_HEADERS).end();
|
|
@@ -2930,12 +3006,7 @@ function serveStatic(root, req, res) {
|
|
|
2930
3006
|
res.writeHead(404, { "content-type": "text/plain", ...SECURITY_HEADERS }).end("Web UI not built. Run `pnpm build`.");
|
|
2931
3007
|
return;
|
|
2932
3008
|
}
|
|
2933
|
-
res.writeHead(200,
|
|
2934
|
-
"content-type": MIME[extname(file)] ?? "application/octet-stream",
|
|
2935
|
-
"content-length": st.size,
|
|
2936
|
-
"cache-control": file.endsWith("index.html") ? "no-cache" : "public, max-age=31536000, immutable",
|
|
2937
|
-
...SECURITY_HEADERS
|
|
2938
|
-
});
|
|
3009
|
+
res.writeHead(200, headersFor(file, st.size));
|
|
2939
3010
|
if (req.method === "HEAD") {
|
|
2940
3011
|
res.end();
|
|
2941
3012
|
return;
|
|
@@ -4224,6 +4295,20 @@ function startServer(config, pool = new SshPool(), repo = new RepoClient(config.
|
|
|
4224
4295
|
});
|
|
4225
4296
|
}
|
|
4226
4297
|
|
|
4298
|
+
// src/open.ts
|
|
4299
|
+
import { spawn } from "child_process";
|
|
4300
|
+
function openInBrowser(url2) {
|
|
4301
|
+
if (!/^https:\/\/[a-z0-9.-]+\/?$/i.test(url2)) return;
|
|
4302
|
+
const [cmd, args] = process.platform === "darwin" ? ["open", [url2]] : process.platform === "win32" ? ["rundll32", ["url.dll,FileProtocolHandler", url2]] : ["xdg-open", [url2]];
|
|
4303
|
+
try {
|
|
4304
|
+
const child = spawn(cmd, args, { detached: true, stdio: "ignore", windowsHide: true });
|
|
4305
|
+
child.on("error", () => {
|
|
4306
|
+
});
|
|
4307
|
+
child.unref();
|
|
4308
|
+
} catch {
|
|
4309
|
+
}
|
|
4310
|
+
}
|
|
4311
|
+
|
|
4227
4312
|
// src/cli.ts
|
|
4228
4313
|
var HELP = `lg-dev-manager-bridge ${BRIDGE_VERSION}
|
|
4229
4314
|
|
|
@@ -4234,7 +4319,9 @@ Usage: lg-dev-manager-bridge [options]
|
|
|
4234
4319
|
--web-root <dir> Serve the web UI from this folder instead of the bundled one (env LGDM_WEB_ROOT)
|
|
4235
4320
|
--no-ui Don't serve the local page; use https://lg.scoty.uk only
|
|
4236
4321
|
--reset-token Generate a new pairing token (un-pairs existing browsers)
|
|
4322
|
+
--no-open The app only: don't open ${PUBLIC_WEB_ORIGIN} in the browser on start
|
|
4237
4323
|
--version Print the version
|
|
4324
|
+
--license Print the licenses of this program and what it includes
|
|
4238
4325
|
--help Show this help
|
|
4239
4326
|
`;
|
|
4240
4327
|
process.on("uncaughtException", (e) => console.error(`[bridge] unexpected error: ${e instanceof Error ? e.message : String(e)}`));
|
|
@@ -4250,6 +4337,10 @@ async function main() {
|
|
|
4250
4337
|
`);
|
|
4251
4338
|
return;
|
|
4252
4339
|
}
|
|
4340
|
+
if (argv.includes("--license")) {
|
|
4341
|
+
process.stdout.write(licenseText());
|
|
4342
|
+
return;
|
|
4343
|
+
}
|
|
4253
4344
|
const config = parseArgs(argv);
|
|
4254
4345
|
await startServer(config);
|
|
4255
4346
|
const shown = config.host;
|
|
@@ -4260,8 +4351,19 @@ async function main() {
|
|
|
4260
4351
|
console.log(` Pairing token ${config.token}`);
|
|
4261
4352
|
console.log(` Allowed origins ${config.allowedOrigins.join(", ")}
|
|
4262
4353
|
`);
|
|
4354
|
+
if (isStandalone()) {
|
|
4355
|
+
console.log(" Keep this window open while you use the app. Close it (or press Ctrl+C) to stop the bridge.\n");
|
|
4356
|
+
if (!argv.includes("--no-open")) openInBrowser(PUBLIC_WEB_ORIGIN);
|
|
4357
|
+
}
|
|
4263
4358
|
}
|
|
4264
4359
|
main().catch((e) => {
|
|
4265
|
-
console.error(
|
|
4360
|
+
console.error(
|
|
4361
|
+
e.code === "EADDRINUSE" ? `[bridge] failed to start: port ${/:(\d+)$/.exec(e.message)?.[1] ?? ""} is already in use. Is the bridge already running in another window? Close that one, or start this one with --port <another port>.` : `[bridge] failed to start: ${e.message}`
|
|
4362
|
+
);
|
|
4363
|
+
if (isStandalone() && process.stdin.isTTY) {
|
|
4364
|
+
console.error("\nPress Enter to close this window.");
|
|
4365
|
+
process.stdin.once("data", () => process.exit(1));
|
|
4366
|
+
return;
|
|
4367
|
+
}
|
|
4266
4368
|
process.exit(1);
|
|
4267
4369
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lg-dev-manager-bridge",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Local bridge for LG Dev Manager: lets the web app at lg.scoty.uk (or its local copy) manage LG webOS TVs over SSH",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Scoty (https://github.com/Scoty)",
|
|
@@ -45,12 +45,14 @@
|
|
|
45
45
|
"@types/node": "^22.10.0",
|
|
46
46
|
"@types/ssh2": "^1.15.6",
|
|
47
47
|
"@types/ws": "^8.5.0",
|
|
48
|
+
"esbuild": "^0.27.7",
|
|
49
|
+
"postject": "1.0.0-alpha.6",
|
|
48
50
|
"tsup": "^8.5.0",
|
|
49
51
|
"tsx": "^4.20.0",
|
|
50
52
|
"typescript": "^5.9.0",
|
|
51
53
|
"vitest": "^4.1.11",
|
|
52
|
-
"@lgdm/mock-tv": "1.0.
|
|
53
|
-
"@lgdm/protocol": "1.0.
|
|
54
|
+
"@lgdm/mock-tv": "1.0.2",
|
|
55
|
+
"@lgdm/protocol": "1.0.2"
|
|
54
56
|
},
|
|
55
57
|
"scripts": {
|
|
56
58
|
"dev": "tsx watch src/cli.ts --dev",
|