webtty 1.1.1 → 1.3.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 +9 -1
- package/dist/cli/index.js +265 -60
- package/dist/cli/index.js.map +7 -6
- package/dist/client-browser.js +3 -0
- package/dist/client.css +18 -0
- package/dist/client.html +14 -0
- package/dist/server/index.js +345 -294
- package/dist/server/index.js.map +12 -13
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
<img src="assets/social-preview.png" width="600">
|
|
2
|
+
|
|
1
3
|
# webtty
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
Terminal UI in the browser. Run CLI/TUI applications in a browser tab, across platforms.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npx webtty # start server + open a terminal in the browser
|
|
9
|
+
npx webtty ls # list sessions
|
|
10
|
+
npx webtty help # show all commands
|
|
11
|
+
```
|
|
4
12
|
|
|
5
13
|
## Debugging
|
|
6
14
|
|
package/dist/cli/index.js
CHANGED
|
@@ -2156,38 +2156,161 @@ var {
|
|
|
2156
2156
|
Help
|
|
2157
2157
|
} = import__.default;
|
|
2158
2158
|
|
|
2159
|
-
// src/cli/
|
|
2160
|
-
import
|
|
2159
|
+
// src/cli/commands.ts
|
|
2160
|
+
import * as childProcess2 from "node:child_process";
|
|
2161
|
+
import fs3 from "node:fs";
|
|
2162
|
+
import path3 from "node:path";
|
|
2163
|
+
|
|
2164
|
+
// src/config.ts
|
|
2161
2165
|
import fs from "node:fs";
|
|
2166
|
+
import os from "node:os";
|
|
2162
2167
|
import path from "node:path";
|
|
2168
|
+
function configDir() {
|
|
2169
|
+
return path.join(process.env.HOME ?? os.homedir(), ".config", "webtty");
|
|
2170
|
+
}
|
|
2171
|
+
function getConfigPath() {
|
|
2172
|
+
return path.join(configDir(), "config.json");
|
|
2173
|
+
}
|
|
2174
|
+
var DEFAULT_THEME = {
|
|
2175
|
+
background: "#000000",
|
|
2176
|
+
foreground: "#CCCCCC",
|
|
2177
|
+
cursor: "#FFFFFF",
|
|
2178
|
+
selection: "#FFFFFF",
|
|
2179
|
+
black: "#0C0C0C",
|
|
2180
|
+
red: "#C50F1F",
|
|
2181
|
+
green: "#13A10E",
|
|
2182
|
+
yellow: "#C19C00",
|
|
2183
|
+
blue: "#0037DA",
|
|
2184
|
+
purple: "#881798",
|
|
2185
|
+
cyan: "#3A96DD",
|
|
2186
|
+
white: "#CCCCCC",
|
|
2187
|
+
brightBlack: "#767676",
|
|
2188
|
+
brightRed: "#E74856",
|
|
2189
|
+
brightGreen: "#16C60C",
|
|
2190
|
+
brightYellow: "#F9F1A5",
|
|
2191
|
+
brightBlue: "#3B78FF",
|
|
2192
|
+
brightPurple: "#B4009E",
|
|
2193
|
+
brightCyan: "#61D6D6",
|
|
2194
|
+
brightWhite: "#F2F2F2"
|
|
2195
|
+
};
|
|
2196
|
+
var DEFAULT_CONFIG = {
|
|
2197
|
+
port: 2346,
|
|
2198
|
+
host: "127.0.0.1",
|
|
2199
|
+
shell: process.platform === "win32" ? process.env.COMSPEC ?? "cmd.exe" : process.env.SHELL ?? "/bin/bash",
|
|
2200
|
+
term: process.env.TERM ?? "xterm-256color",
|
|
2201
|
+
colorTerm: "truecolor",
|
|
2202
|
+
scrollback: 256 * 1024,
|
|
2203
|
+
cols: 80,
|
|
2204
|
+
rows: 24,
|
|
2205
|
+
fontSize: 13,
|
|
2206
|
+
fontFamily: "Menlo, Consolas, 'DejaVu Sans Mono', monospace",
|
|
2207
|
+
cursorBlink: true,
|
|
2208
|
+
copyOnSelect: true,
|
|
2209
|
+
rightClickBehavior: "default",
|
|
2210
|
+
logs: false,
|
|
2211
|
+
theme: DEFAULT_THEME
|
|
2212
|
+
};
|
|
2213
|
+
function loadConfig() {
|
|
2214
|
+
if (!fs.existsSync(getConfigPath())) {
|
|
2215
|
+
try {
|
|
2216
|
+
saveConfig(DEFAULT_CONFIG);
|
|
2217
|
+
} catch (err) {
|
|
2218
|
+
console.warn(`webtty: failed to write default config to ${getConfigPath()}: ${err.message}`);
|
|
2219
|
+
return { ...DEFAULT_CONFIG };
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
let raw;
|
|
2223
|
+
try {
|
|
2224
|
+
raw = fs.readFileSync(getConfigPath(), "utf8");
|
|
2225
|
+
} catch (err) {
|
|
2226
|
+
throw new Error(`webtty: failed to read config at ${getConfigPath()}: ${err.message}`);
|
|
2227
|
+
}
|
|
2228
|
+
let parsed;
|
|
2229
|
+
try {
|
|
2230
|
+
parsed = JSON.parse(raw);
|
|
2231
|
+
} catch {
|
|
2232
|
+
throw new Error(`webtty: invalid JSON in config file ${getConfigPath()}`);
|
|
2233
|
+
}
|
|
2234
|
+
const p = parsed;
|
|
2235
|
+
return {
|
|
2236
|
+
...DEFAULT_CONFIG,
|
|
2237
|
+
...typeof p.port === "number" && { port: p.port },
|
|
2238
|
+
...typeof p.host === "string" && { host: p.host },
|
|
2239
|
+
...typeof p.shell === "string" && { shell: p.shell },
|
|
2240
|
+
...typeof p.term === "string" && { term: p.term },
|
|
2241
|
+
...typeof p.colorTerm === "string" && { colorTerm: p.colorTerm },
|
|
2242
|
+
...typeof p.scrollback === "number" && { scrollback: p.scrollback },
|
|
2243
|
+
...typeof p.cols === "number" && { cols: p.cols },
|
|
2244
|
+
...typeof p.rows === "number" && { rows: p.rows },
|
|
2245
|
+
...typeof p.fontSize === "number" && { fontSize: p.fontSize },
|
|
2246
|
+
...typeof p.fontFamily === "string" && { fontFamily: p.fontFamily },
|
|
2247
|
+
...typeof p.cursorBlink === "boolean" && { cursorBlink: p.cursorBlink },
|
|
2248
|
+
...typeof p.copyOnSelect === "boolean" && { copyOnSelect: p.copyOnSelect },
|
|
2249
|
+
...typeof p.rightClickBehavior === "string" && {
|
|
2250
|
+
rightClickBehavior: p.rightClickBehavior === "copyPaste" ? "copyPaste" : "default"
|
|
2251
|
+
},
|
|
2252
|
+
...typeof p.logs === "boolean" && { logs: p.logs },
|
|
2253
|
+
...p.theme && typeof p.theme === "object" && { theme: { ...DEFAULT_THEME, ...p.theme } }
|
|
2254
|
+
};
|
|
2255
|
+
}
|
|
2256
|
+
function saveConfig(_config) {
|
|
2257
|
+
fs.mkdirSync(path.dirname(getConfigPath()), { recursive: true });
|
|
2258
|
+
const content = JSON.stringify({
|
|
2259
|
+
port: DEFAULT_CONFIG.port,
|
|
2260
|
+
host: DEFAULT_CONFIG.host
|
|
2261
|
+
}, null, 2);
|
|
2262
|
+
fs.writeFileSync(getConfigPath(), content, "utf8");
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
// src/cli/http.ts
|
|
2266
|
+
import * as childProcess from "node:child_process";
|
|
2267
|
+
import fs2 from "node:fs";
|
|
2268
|
+
import path2 from "node:path";
|
|
2163
2269
|
import { fileURLToPath } from "node:url";
|
|
2164
2270
|
var __filename2 = fileURLToPath(import.meta.url);
|
|
2165
|
-
var __dirname2 =
|
|
2271
|
+
var __dirname2 = path2.dirname(__filename2);
|
|
2166
2272
|
var PORT = Number(process.env.PORT) || 2346;
|
|
2167
2273
|
var BASE_URL = `http://127.0.0.1:${PORT}`;
|
|
2274
|
+
function logPath() {
|
|
2275
|
+
return path2.join(configDir(), "server.log");
|
|
2276
|
+
}
|
|
2168
2277
|
async function isServerRunning() {
|
|
2169
2278
|
try {
|
|
2170
|
-
await fetch(`${BASE_URL}/api/sessions`);
|
|
2171
|
-
|
|
2279
|
+
const res = await fetch(`${BASE_URL}/api/sessions`);
|
|
2280
|
+
if (!res.ok)
|
|
2281
|
+
return false;
|
|
2282
|
+
const body = await res.json();
|
|
2283
|
+
return Array.isArray(body);
|
|
2172
2284
|
} catch {
|
|
2173
2285
|
return false;
|
|
2174
2286
|
}
|
|
2175
2287
|
}
|
|
2176
|
-
async function startServer() {
|
|
2288
|
+
async function startServer(timeoutMs = 1e4, _spawn = childProcess.spawn) {
|
|
2177
2289
|
const isBun = typeof globalThis.Bun !== "undefined";
|
|
2178
2290
|
const isTs = isBun && __filename2.endsWith(".ts");
|
|
2179
|
-
const serverEntry =
|
|
2180
|
-
if (!
|
|
2291
|
+
const serverEntry = path2.resolve(__dirname2, isTs ? "../server/index.ts" : "../server/index.js");
|
|
2292
|
+
if (!fs2.existsSync(serverEntry)) {
|
|
2181
2293
|
console.error(`webtty: server entry not found at ${serverEntry}`);
|
|
2182
2294
|
process.exit(1);
|
|
2183
2295
|
}
|
|
2184
|
-
const
|
|
2296
|
+
const config = loadConfig();
|
|
2297
|
+
let stdio = "ignore";
|
|
2298
|
+
let logFd;
|
|
2299
|
+
if (config.logs) {
|
|
2300
|
+
const log = logPath();
|
|
2301
|
+
fs2.mkdirSync(path2.dirname(log), { recursive: true });
|
|
2302
|
+
logFd = fs2.openSync(log, "a");
|
|
2303
|
+
stdio = ["ignore", logFd, logFd];
|
|
2304
|
+
}
|
|
2305
|
+
const child = _spawn(process.execPath, [serverEntry], {
|
|
2185
2306
|
detached: true,
|
|
2186
|
-
stdio
|
|
2307
|
+
stdio,
|
|
2187
2308
|
env: { ...process.env, PORT: String(PORT) }
|
|
2188
2309
|
});
|
|
2189
2310
|
child.unref();
|
|
2190
|
-
|
|
2311
|
+
if (logFd !== undefined)
|
|
2312
|
+
fs2.closeSync(logFd);
|
|
2313
|
+
const deadline = Date.now() + timeoutMs;
|
|
2191
2314
|
while (Date.now() < deadline) {
|
|
2192
2315
|
if (await isServerRunning())
|
|
2193
2316
|
return;
|
|
@@ -2196,60 +2319,38 @@ async function startServer() {
|
|
|
2196
2319
|
console.error("webtty: server did not start in time");
|
|
2197
2320
|
process.exit(1);
|
|
2198
2321
|
}
|
|
2199
|
-
function
|
|
2322
|
+
async function stopServer(baseUrl = BASE_URL, timeoutMs = 5000) {
|
|
2323
|
+
try {
|
|
2324
|
+
const res = await fetch(`${baseUrl}/api/server/stop`, { method: "POST" });
|
|
2325
|
+
if (!res.ok)
|
|
2326
|
+
return false;
|
|
2327
|
+
const deadline = Date.now() + timeoutMs;
|
|
2328
|
+
while (Date.now() < deadline) {
|
|
2329
|
+
if (!await isServerRunning())
|
|
2330
|
+
return true;
|
|
2331
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
2332
|
+
}
|
|
2333
|
+
return false;
|
|
2334
|
+
} catch {
|
|
2335
|
+
return false;
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
function openBrowser(url, _spawn = childProcess.spawn) {
|
|
2200
2339
|
if (process.env.WEBTTY_NO_OPEN === "1")
|
|
2201
2340
|
return;
|
|
2341
|
+
if (false)
|
|
2342
|
+
;
|
|
2202
2343
|
if (process.platform === "win32") {
|
|
2203
|
-
|
|
2344
|
+
_spawn("cmd.exe", ["/c", "start", "", url], { detached: true, stdio: "ignore" }).unref();
|
|
2204
2345
|
} else {
|
|
2205
2346
|
const cmd = process.platform === "darwin" ? "open" : "xdg-open";
|
|
2206
|
-
|
|
2347
|
+
_spawn(cmd, [url], { detached: true, stdio: "ignore" }).unref();
|
|
2207
2348
|
}
|
|
2208
2349
|
}
|
|
2209
2350
|
|
|
2210
2351
|
// src/cli/commands.ts
|
|
2211
2352
|
function registerCommands(program2) {
|
|
2212
|
-
program2.command("
|
|
2213
|
-
if (await isServerRunning()) {
|
|
2214
|
-
console.log("webtty is already running");
|
|
2215
|
-
return;
|
|
2216
|
-
}
|
|
2217
|
-
await startServer();
|
|
2218
|
-
console.log("webtty started");
|
|
2219
|
-
});
|
|
2220
|
-
program2.command("stop").description("Stop the webtty server").action(async () => {
|
|
2221
|
-
try {
|
|
2222
|
-
const res = await fetch(`${BASE_URL}/api/server/stop`, { method: "POST" });
|
|
2223
|
-
if (res.ok) {
|
|
2224
|
-
console.log("webtty stopped");
|
|
2225
|
-
} else {
|
|
2226
|
-
console.error(`webtty stop failed (status: ${res.status})`);
|
|
2227
|
-
process.exit(1);
|
|
2228
|
-
}
|
|
2229
|
-
} catch {
|
|
2230
|
-
console.log("webtty is not running");
|
|
2231
|
-
}
|
|
2232
|
-
});
|
|
2233
|
-
program2.command("ls").description("List all sessions").action(async () => {
|
|
2234
|
-
let res;
|
|
2235
|
-
try {
|
|
2236
|
-
res = await fetch(`${BASE_URL}/api/sessions`);
|
|
2237
|
-
} catch {
|
|
2238
|
-
console.log("webtty is not running");
|
|
2239
|
-
process.exit(1);
|
|
2240
|
-
}
|
|
2241
|
-
const sessions = await res.json();
|
|
2242
|
-
if (sessions.length === 0) {
|
|
2243
|
-
console.log("no sessions");
|
|
2244
|
-
return;
|
|
2245
|
-
}
|
|
2246
|
-
console.log("id\t\t\tconnected\tcreated");
|
|
2247
|
-
for (const s of sessions) {
|
|
2248
|
-
const created = new Date(s.createdAt).toLocaleString();
|
|
2249
|
-
console.log(`${s.id} ${s.connected} ${created}`);
|
|
2250
|
-
}
|
|
2251
|
-
});
|
|
2252
|
-
program2.command("run [id]").description("Create or reuse a session and open it in the browser").action(async (id) => {
|
|
2353
|
+
program2.command("at [id]").alias("a").alias("attach").description("Attach to a new or existing session and open it").action(async (id) => {
|
|
2253
2354
|
if (!await isServerRunning()) {
|
|
2254
2355
|
await startServer();
|
|
2255
2356
|
}
|
|
@@ -2290,7 +2391,31 @@ function registerCommands(program2) {
|
|
|
2290
2391
|
console.log(url);
|
|
2291
2392
|
openBrowser(url);
|
|
2292
2393
|
});
|
|
2293
|
-
program2.command("
|
|
2394
|
+
program2.command("ls [id]").alias("list").description("List all sessions, or filter by id substring").action(async (filter) => {
|
|
2395
|
+
let res;
|
|
2396
|
+
try {
|
|
2397
|
+
res = await fetch(`${BASE_URL}/api/sessions`);
|
|
2398
|
+
} catch {
|
|
2399
|
+
console.log("webtty is not running");
|
|
2400
|
+
process.exit(1);
|
|
2401
|
+
}
|
|
2402
|
+
const all = await res.json();
|
|
2403
|
+
const sessions = filter ? all.filter((s) => s.id.includes(filter)) : all;
|
|
2404
|
+
if (sessions.length === 0) {
|
|
2405
|
+
console.log("no sessions");
|
|
2406
|
+
return;
|
|
2407
|
+
}
|
|
2408
|
+
console.log("id\t\t\tconnected\tcreated");
|
|
2409
|
+
for (const s of sessions) {
|
|
2410
|
+
const created = new Date(s.createdAt).toLocaleString();
|
|
2411
|
+
console.log(`${s.id} ${s.connected} ${created}`);
|
|
2412
|
+
}
|
|
2413
|
+
});
|
|
2414
|
+
program2.command("rm [id]").alias("remove").description("Destroy a session").action(async (id) => {
|
|
2415
|
+
if (!id) {
|
|
2416
|
+
console.error("webtty: rm requires a session id");
|
|
2417
|
+
process.exit(1);
|
|
2418
|
+
}
|
|
2294
2419
|
let res;
|
|
2295
2420
|
try {
|
|
2296
2421
|
res = await fetch(`${BASE_URL}/api/sessions/${encodeURIComponent(id)}`, {
|
|
@@ -2302,6 +2427,10 @@ function registerCommands(program2) {
|
|
|
2302
2427
|
}
|
|
2303
2428
|
if (res.status === 204) {
|
|
2304
2429
|
console.log(`removed ${id}`);
|
|
2430
|
+
if (res.headers.get("x-sessions-remaining") === "0") {
|
|
2431
|
+
await stopServer();
|
|
2432
|
+
console.log("no sessions remaining — webtty stopped");
|
|
2433
|
+
}
|
|
2305
2434
|
} else if (res.status === 404) {
|
|
2306
2435
|
console.error(`session ${id} not found`);
|
|
2307
2436
|
process.exit(1);
|
|
@@ -2310,7 +2439,11 @@ function registerCommands(program2) {
|
|
|
2310
2439
|
process.exit(1);
|
|
2311
2440
|
}
|
|
2312
2441
|
});
|
|
2313
|
-
program2.command("
|
|
2442
|
+
program2.command("mv [id] [new-id]").alias("move").alias("rename").description("Rename a session").action(async (id, newId) => {
|
|
2443
|
+
if (!id || !newId) {
|
|
2444
|
+
console.error("webtty: rename requires two arguments: [id] [new-id]");
|
|
2445
|
+
process.exit(1);
|
|
2446
|
+
}
|
|
2314
2447
|
let res;
|
|
2315
2448
|
try {
|
|
2316
2449
|
res = await fetch(`${BASE_URL}/api/sessions/${encodeURIComponent(id)}`, {
|
|
@@ -2333,12 +2466,84 @@ function registerCommands(program2) {
|
|
|
2333
2466
|
process.exit(1);
|
|
2334
2467
|
}
|
|
2335
2468
|
});
|
|
2469
|
+
program2.command("stop").description("Stop the webtty server").action(async () => {
|
|
2470
|
+
if (!await isServerRunning()) {
|
|
2471
|
+
console.log("webtty is not running");
|
|
2472
|
+
return;
|
|
2473
|
+
}
|
|
2474
|
+
const ok = await stopServer();
|
|
2475
|
+
if (ok) {
|
|
2476
|
+
console.log("webtty stopped");
|
|
2477
|
+
} else {
|
|
2478
|
+
console.error("webtty stop failed");
|
|
2479
|
+
process.exit(1);
|
|
2480
|
+
}
|
|
2481
|
+
});
|
|
2482
|
+
program2.command("start").description("Start the webtty server").action(async () => {
|
|
2483
|
+
if (await isServerRunning()) {
|
|
2484
|
+
console.log("webtty is already running");
|
|
2485
|
+
return;
|
|
2486
|
+
}
|
|
2487
|
+
await startServer();
|
|
2488
|
+
console.log("webtty started");
|
|
2489
|
+
});
|
|
2490
|
+
program2.command("config").description("Open the config file in $EDITOR").action(() => {
|
|
2491
|
+
const dir = configDir();
|
|
2492
|
+
const configPath = path3.join(dir, "config.json");
|
|
2493
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
2494
|
+
if (!fs3.existsSync(configPath)) {
|
|
2495
|
+
fs3.writeFileSync(configPath, `{}
|
|
2496
|
+
`, "utf8");
|
|
2497
|
+
}
|
|
2498
|
+
const editor = process.env.VISUAL ?? process.env.EDITOR ?? (process.platform === "win32" ? "notepad" : "vi");
|
|
2499
|
+
childProcess2.spawnSync(editor, [configPath], { stdio: "inherit" });
|
|
2500
|
+
});
|
|
2501
|
+
program2.command("help").description("Show help — all commands and options").action(() => {
|
|
2502
|
+
program2.outputHelp();
|
|
2503
|
+
});
|
|
2336
2504
|
}
|
|
2337
2505
|
|
|
2338
2506
|
// src/cli/index.ts
|
|
2507
|
+
var CMDS_WITH_ARGS = new Set(["at", "rm", "ls", "mv"]);
|
|
2508
|
+
var CMD_NAME_WIDTH = "mv".length;
|
|
2339
2509
|
var program2 = new Command;
|
|
2340
|
-
program2.name("webtty").description("
|
|
2510
|
+
program2.name("webtty").description("Launch Terminal UI in the browser.").configureHelp({
|
|
2511
|
+
styleTitle(str) {
|
|
2512
|
+
return str.replace(/:$/, "").toUpperCase();
|
|
2513
|
+
},
|
|
2514
|
+
subcommandTerm(cmd) {
|
|
2515
|
+
const args = cmd.registeredArguments.map((arg) => arg.required ? `<${arg.name()}>` : `[${arg.name()}]`).join(" ");
|
|
2516
|
+
const name = CMDS_WITH_ARGS.has(cmd.name()) ? cmd.name().padEnd(CMD_NAME_WIDTH) : cmd.name();
|
|
2517
|
+
return args ? `${name} ${args}` : name;
|
|
2518
|
+
},
|
|
2519
|
+
formatHelp(cmd, helper) {
|
|
2520
|
+
const helpWidth = helper.helpWidth ?? 80;
|
|
2521
|
+
const termWidth = helper.padWidth(cmd, helper);
|
|
2522
|
+
const callFormatItem = (term, description2) => helper.formatItem(term, termWidth, description2, helper);
|
|
2523
|
+
const description = helper.commandDescription(cmd);
|
|
2524
|
+
const descriptionBlock = description.length > 0 ? ["", helper.boxWrap(helper.styleCommandDescription(description), helpWidth), ""] : [];
|
|
2525
|
+
const indent = " ";
|
|
2526
|
+
const usageWidth = "webtty [command]".length;
|
|
2527
|
+
const usageBlock = [
|
|
2528
|
+
helper.styleTitle("Usage:"),
|
|
2529
|
+
`${indent}${helper.styleUsage("webtty".padEnd(usageWidth))} ${helper.styleCommandDescription("Attach to main session and open it")}`,
|
|
2530
|
+
`${indent}${helper.styleUsage("webtty [command]".padEnd(usageWidth))} ${helper.styleCommandDescription("Execute a specific command")}`,
|
|
2531
|
+
""
|
|
2532
|
+
];
|
|
2533
|
+
const commandGroups = helper.groupItems(cmd.commands, helper.visibleCommands(cmd), (sub) => sub.helpGroup?.() || "Commands:");
|
|
2534
|
+
const commandsBlock = [];
|
|
2535
|
+
commandGroups.forEach((commands, group) => {
|
|
2536
|
+
const commandList = commands.map((sub) => callFormatItem(helper.styleSubcommandTerm(helper.subcommandTerm(sub)), helper.styleSubcommandDescription(helper.subcommandDescription(sub))));
|
|
2537
|
+
commandsBlock.push(...helper.formatItemList(group, commandList, helper));
|
|
2538
|
+
});
|
|
2539
|
+
return [...descriptionBlock, ...usageBlock, ...commandsBlock].join(`
|
|
2540
|
+
`);
|
|
2541
|
+
}
|
|
2542
|
+
});
|
|
2341
2543
|
registerCommands(program2);
|
|
2342
|
-
program2.
|
|
2544
|
+
program2.action(async () => {
|
|
2545
|
+
await program2.parseAsync(["at", "main"], { from: "user" });
|
|
2546
|
+
});
|
|
2547
|
+
program2.parseAsync(process.argv);
|
|
2343
2548
|
|
|
2344
|
-
//# debugId=
|
|
2549
|
+
//# debugId=1ED78924E352A12364756E2164756E21
|