webtty 1.1.0 → 1.2.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 CHANGED
@@ -1,3 +1,22 @@
1
+ <img src="assets/social-preview.png" width="600">
2
+
1
3
  # webtty
2
4
 
3
- A web TTY for running CLI/TUI applications in a browser tab, across platforms.
5
+ Terminal UI in the browser. Run CLI/TUI applications in a browser tab, across platforms.
6
+
7
+ ```sh
8
+ npx webtty run # start server + open a terminal in the browser
9
+ npx webtty ls # list sessions
10
+ npx webtty help # show all commands
11
+ ```
12
+
13
+ ## Debugging
14
+
15
+ Build emits source maps (`dist/**/*.js.map`), so you can debug against the built output directly — no minification, original TypeScript line numbers preserved.
16
+
17
+ ```
18
+ bun run build
19
+ bun --inspect run dist/server/index.js
20
+ # or
21
+ node --inspect dist/server/index.js
22
+ ```
package/dist/cli/index.js CHANGED
@@ -2157,7 +2157,7 @@ var {
2157
2157
  } = import__.default;
2158
2158
 
2159
2159
  // src/cli/http.ts
2160
- import { spawn } from "node:child_process";
2160
+ import * as childProcess from "node:child_process";
2161
2161
  import fs from "node:fs";
2162
2162
  import path from "node:path";
2163
2163
  import { fileURLToPath } from "node:url";
@@ -2173,20 +2173,21 @@ async function isServerRunning() {
2173
2173
  return false;
2174
2174
  }
2175
2175
  }
2176
- async function startServer() {
2177
- const isTs = __filename2.endsWith(".ts");
2176
+ async function startServer(timeoutMs = 1e4, _spawn = childProcess.spawn) {
2177
+ const isBun = typeof globalThis.Bun !== "undefined";
2178
+ const isTs = isBun && __filename2.endsWith(".ts");
2178
2179
  const serverEntry = path.resolve(__dirname2, isTs ? "../server/index.ts" : "../server/index.js");
2179
2180
  if (!fs.existsSync(serverEntry)) {
2180
2181
  console.error(`webtty: server entry not found at ${serverEntry}`);
2181
2182
  process.exit(1);
2182
2183
  }
2183
- const child = spawn(process.execPath, [serverEntry], {
2184
+ const child = _spawn(process.execPath, [serverEntry], {
2184
2185
  detached: true,
2185
2186
  stdio: "ignore",
2186
2187
  env: { ...process.env, PORT: String(PORT) }
2187
2188
  });
2188
2189
  child.unref();
2189
- const deadline = Date.now() + 1e4;
2190
+ const deadline = Date.now() + timeoutMs;
2190
2191
  while (Date.now() < deadline) {
2191
2192
  if (await isServerRunning())
2192
2193
  return;
@@ -2195,14 +2196,32 @@ async function startServer() {
2195
2196
  console.error("webtty: server did not start in time");
2196
2197
  process.exit(1);
2197
2198
  }
2198
- function openBrowser(url) {
2199
+ async function stopServer(baseUrl = BASE_URL, timeoutMs = 5000) {
2200
+ try {
2201
+ const res = await fetch(`${baseUrl}/api/server/stop`, { method: "POST" });
2202
+ if (!res.ok)
2203
+ return false;
2204
+ const deadline = Date.now() + timeoutMs;
2205
+ while (Date.now() < deadline) {
2206
+ if (!await isServerRunning())
2207
+ return true;
2208
+ await new Promise((r) => setTimeout(r, 100));
2209
+ }
2210
+ return false;
2211
+ } catch {
2212
+ return false;
2213
+ }
2214
+ }
2215
+ function openBrowser(url, _spawn = childProcess.spawn) {
2199
2216
  if (process.env.WEBTTY_NO_OPEN === "1")
2200
2217
  return;
2218
+ if (false)
2219
+ ;
2201
2220
  if (process.platform === "win32") {
2202
- spawn("cmd.exe", ["/c", "start", "", url], { detached: true, stdio: "ignore" }).unref();
2221
+ _spawn("cmd.exe", ["/c", "start", "", url], { detached: true, stdio: "ignore" }).unref();
2203
2222
  } else {
2204
2223
  const cmd = process.platform === "darwin" ? "open" : "xdg-open";
2205
- spawn(cmd, [url], { detached: true, stdio: "ignore" }).unref();
2224
+ _spawn(cmd, [url], { detached: true, stdio: "ignore" }).unref();
2206
2225
  }
2207
2226
  }
2208
2227
 
@@ -2217,16 +2236,16 @@ function registerCommands(program2) {
2217
2236
  console.log("webtty started");
2218
2237
  });
2219
2238
  program2.command("stop").description("Stop the webtty server").action(async () => {
2220
- try {
2221
- const res = await fetch(`${BASE_URL}/api/server/stop`, { method: "POST" });
2222
- if (res.ok) {
2223
- console.log("webtty stopped");
2224
- } else {
2225
- console.error(`webtty stop failed (status: ${res.status})`);
2226
- process.exit(1);
2227
- }
2228
- } catch {
2239
+ if (!await isServerRunning()) {
2229
2240
  console.log("webtty is not running");
2241
+ return;
2242
+ }
2243
+ const ok = await stopServer();
2244
+ if (ok) {
2245
+ console.log("webtty stopped");
2246
+ } else {
2247
+ console.error("webtty stop failed");
2248
+ process.exit(1);
2230
2249
  }
2231
2250
  });
2232
2251
  program2.command("ls").description("List all sessions").action(async () => {
@@ -2332,6 +2351,17 @@ function registerCommands(program2) {
2332
2351
  process.exit(1);
2333
2352
  }
2334
2353
  });
2354
+ program2.command("restart").description("Restart the webtty server").action(async () => {
2355
+ if (await isServerRunning()) {
2356
+ const ok = await stopServer();
2357
+ if (!ok) {
2358
+ console.error("webtty: failed to stop server");
2359
+ process.exit(1);
2360
+ }
2361
+ }
2362
+ await startServer();
2363
+ console.log("webtty restarted");
2364
+ });
2335
2365
  }
2336
2366
 
2337
2367
  // src/cli/index.ts
@@ -2340,4 +2370,4 @@ program2.name("webtty").description("Web TTY — run terminal sessions in a brow
2340
2370
  registerCommands(program2);
2341
2371
  program2.parse(process.argv);
2342
2372
 
2343
- //# debugId=C181BFB3597D22B864756E2164756E21
2373
+ //# debugId=1DEC1C353196B21C64756E2164756E21