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 <n>` 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 <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-08-22 14:13:58 +02:00
parent e5ae2826c6
commit 3f88226d50
+32
View File
@@ -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. */