From 3f88226d5042021100f966655c63f19d04457aa6 Mon Sep 17 00:00:00 2001 From: Codeman maintainer Date: Sun, 16 Aug 2026 20:01:17 +0200 Subject: [PATCH] feat: register the tui command with its two fast paths `codeman tui` opens the dashboard, `codeman tui --list` prints the numbered list and exits (the `sc -l` replacement, plain when piped) and `codeman tui ` attaches straight to a row (the `sc 2` replacement). Both fast paths short-circuit before any screen setup, and both refuse the numbers path without a terminal instead of half-opening a UI. Bare `codeman` still prints help: the web UI stays the primary surface. The TUI module is imported lazily so the other commands do not pay for it at startup. Co-Authored-By: Claude Fable 5 --- src/cli.ts | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/cli.ts b/src/cli.ts index a1f18270..7408f131 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -800,6 +800,38 @@ program .description('List active sessions (shorthand; `codeman session list` also shows stopped ones)') .action(() => printSessionList({ includeStored: false })); +// ============ TUI ============ + +program + .command('tui') + .argument('[n]', 'attach straight to the nth session of `codeman tui --list`') + .description('Terminal dashboard for your sessions (the web UI remains the primary surface)') + .option('-l, --list', 'Print the numbered session list and exit, instead of opening the dashboard') + .action(async (position: string | undefined, options: { list?: boolean }) => { + // Imported here, not at the top: the dashboard pulls in the whole TUI core, + // and every other command would pay for it at startup. + const { runTui, runTuiAttach, runTuiList } = await import('./tui/tui-app.js'); + + if (options.list) { + process.exitCode = await runTuiList(); + return; + } + if (position !== undefined) { + const n = Number.parseInt(position, 10); + if (!Number.isSafeInteger(n) || n < 1) { + console.error(palette.err(`"${position}" is not a session number.`)); + console.error(`Run ${palette.info('codeman tui --list')} to see them.`); + process.exitCode = 1; + return; + } + process.exitCode = await runTuiAttach(n); + return; + } + // The dashboard owns the terminal until it quits; exiting explicitly keeps a + // stray handle (a socket mid-close) from stranding the user's shell. + process.exit(await runTui()); + }); + // ============ Web / daemon / service Commands ============ /** Shared option set for the commands that can launch a web server. */