|
1 | 1 | #!/usr/bin/env node |
2 | | - |
| 2 | +/** |
| 3 | + * Mux CLI entry point. |
| 4 | + * |
| 5 | + * LAZY LOADING REQUIREMENT: |
| 6 | + * We manually route subcommands before calling program.parse() to avoid |
| 7 | + * eagerly importing heavy modules. The desktop app imports Electron, which |
| 8 | + * fails when running CLI commands in non-GUI environments. Subcommands like |
| 9 | + * `run` and `server` import the AI SDK which has significant startup cost. |
| 10 | + * |
| 11 | + * By checking argv[2] first, we only load the code path actually needed. |
| 12 | + * |
| 13 | + * ELECTRON DETECTION: |
| 14 | + * When run via `electron .` or as a packaged app, Electron sets process.versions.electron. |
| 15 | + * In that case, we launch the desktop app automatically. When run via `bun` or `node`, |
| 16 | + * we show CLI help instead. |
| 17 | + */ |
3 | 18 | import { Command } from "commander"; |
4 | 19 | import { VERSION } from "../version"; |
5 | 20 |
|
6 | | -<<<<<<< HEAD |
7 | | -const program = new Command(); |
8 | | - |
9 | | -program |
10 | | - .name("mux") |
11 | | - .description("mux - coder multiplexer") |
12 | | - .version(`mux ${VERSION.git_describe} (${VERSION.git_commit})`, "-v, --version"); |
13 | | - |
14 | | -// Subcommands with their own CLI parsers - disable help interception so --help passes through |
15 | | -program |
16 | | - .command("server") |
17 | | - .description("Start the HTTP/WebSocket oRPC server") |
18 | | - .helpOption(false) |
19 | | - .allowUnknownOption() |
20 | | - .allowExcessArguments() |
21 | | - .action(() => { |
22 | | - process.argv.splice(2, 1); |
23 | | - // eslint-disable-next-line @typescript-eslint/no-require-imports |
24 | | - require("./server"); |
25 | | - }); |
26 | | - |
27 | | -program |
28 | | - .command("api") |
29 | | - .description("Interact with the mux API via a running server") |
30 | | - .helpOption(false) |
31 | | - .allowUnknownOption() |
32 | | - .allowExcessArguments() |
33 | | - .action(() => { |
34 | | - process.argv.splice(2, 1); |
35 | | - // eslint-disable-next-line @typescript-eslint/no-require-imports |
36 | | - require("./api"); |
37 | | - }); |
| 21 | +const subcommand = process.argv[2]; |
| 22 | +const isElectron = "electron" in process.versions; |
38 | 23 |
|
39 | | -program |
40 | | - .command("version") |
41 | | - .description("Show version information") |
42 | | - .action(() => { |
43 | | - console.log(`mux ${VERSION.git_describe} (${VERSION.git_commit})`); |
44 | | - }); |
45 | | - |
46 | | -// Default action: launch desktop app when no subcommand given |
47 | | -program.action(() => { |
48 | | -||||||| parent of 0f258d5fc (🤖 feat: add first-class `mux run` CLI command) |
49 | | -if (subcommand === "server") { |
50 | | - // Remove 'server' from args since main-server doesn't expect it as a positional argument. |
51 | | - process.argv.splice(2, 1); |
| 24 | +function launchDesktop(): void { |
52 | 25 | // eslint-disable-next-line @typescript-eslint/no-require-imports |
53 | | - require("./server"); |
54 | | -} else if (subcommand === "version") { |
| 26 | + require("../desktop/main"); |
| 27 | +} |
| 28 | + |
| 29 | +// Route known subcommands to their dedicated entry points (each has its own Commander instance) |
| 30 | +if (subcommand === "run") { |
| 31 | + process.argv.splice(2, 1); // Remove "run" since run.ts defines .name("mux run") |
55 | 32 | // eslint-disable-next-line @typescript-eslint/no-require-imports |
56 | | - const { VERSION } = require("../version") as { |
57 | | - VERSION: { git_describe: string; git_commit: string }; |
58 | | - }; |
59 | | - console.log(`mux ${VERSION.git_describe} (${VERSION.git_commit})`); |
60 | | -} else { |
61 | | -======= |
62 | | -if (subcommand === "server") { |
63 | | - // Remove 'server' from args since main-server doesn't expect it as a positional argument. |
| 33 | + require("./run"); |
| 34 | +} else if (subcommand === "server") { |
64 | 35 | process.argv.splice(2, 1); |
65 | 36 | // eslint-disable-next-line @typescript-eslint/no-require-imports |
66 | 37 | require("./server"); |
67 | | -} else if (subcommand === "run") { |
68 | | - // Remove 'run' from args since run.ts uses Commander which handles its own parsing |
| 38 | +} else if (subcommand === "api") { |
69 | 39 | process.argv.splice(2, 1); |
70 | 40 | // eslint-disable-next-line @typescript-eslint/no-require-imports |
71 | | - require("./run"); |
72 | | -} else if (subcommand === "version") { |
73 | | - // eslint-disable-next-line @typescript-eslint/no-require-imports |
74 | | - const { VERSION } = require("../version") as { |
75 | | - VERSION: { git_describe: string; git_commit: string }; |
76 | | - }; |
77 | | - console.log(`mux ${VERSION.git_describe} (${VERSION.git_commit})`); |
| 41 | + require("./api"); |
| 42 | +} else if (subcommand === "desktop" || (subcommand === undefined && isElectron)) { |
| 43 | + // Explicit `mux desktop` or no args when running under Electron |
| 44 | + launchDesktop(); |
78 | 45 | } else { |
79 | | ->>>>>>> 0f258d5fc (🤖 feat: add first-class `mux run` CLI command) |
80 | | - // eslint-disable-next-line @typescript-eslint/no-require-imports |
81 | | - require("../desktop/main"); |
82 | | -}); |
83 | | - |
84 | | -program.parse(); |
| 46 | + // No subcommand (non-Electron), flags (--help, --version), or unknown commands |
| 47 | + const program = new Command(); |
| 48 | + program |
| 49 | + .name("mux") |
| 50 | + .description("Mux - AI agent orchestration") |
| 51 | + .version(`${VERSION.git_describe} (${VERSION.git_commit})`, "-v, --version"); |
| 52 | + |
| 53 | + // Register subcommand stubs for help display (actual implementations are above) |
| 54 | + program.command("run").description("Run a one-off agent task"); |
| 55 | + program.command("server").description("Start the HTTP/WebSocket ORPC server"); |
| 56 | + program.command("api").description("Interact with the mux API via a running server"); |
| 57 | + program.command("desktop").description("Launch the desktop app (requires Electron)"); |
| 58 | + |
| 59 | + program.parse(); |
| 60 | +} |
0 commit comments