feat(tui): /model and /setup slash commands with in-place CLI handoff

- hermes-ink: export `withInkSuspended()` + `useExternalProcess()` that
  pause/resume Ink around an arbitrary external process (built on the
  existing enterAlternateScreen/exitAlternateScreen plumbing)
- tui: `launchHermesCommand(args)` spawns the `hermes` binary with
  inherited stdio, with `HERMES_BIN` override for non-standard launches
- tui: `/model` and `/setup` slash commands invoke the CLI wizards
  in-place, then re-preflight `setup.status` and auto-start a session on
  success — no more exit-and-relaunch to finish first-run setup
- setup panel now advertises those slashes instead of only pointing
  users back at the shell
This commit is contained in:
Brooklyn Nicholson 2026-04-17 10:58:18 -05:00
parent 0dd5055d59
commit a82097e7a2
8 changed files with 141 additions and 7 deletions

View file

@ -0,0 +1,33 @@
import { withInkSuspended } from '@hermes/ink'
import { launchHermesCommand } from '../../../lib/externalCli.js'
import { runExternalSetup } from '../../setupHandoff.js'
import type { SlashCommand } from '../types.js'
export const setupCommands: SlashCommand[] = [
{
aliases: ['provider'],
help: 'configure LLM provider and model (launches `hermes model`)',
name: 'model',
run: (_arg, ctx) =>
void runExternalSetup({
args: ['model'],
ctx,
done: 'provider updated — starting session…',
launcher: launchHermesCommand,
suspend: withInkSuspended
})
},
{
help: 'run full setup wizard (launches `hermes setup`)',
name: 'setup',
run: (arg, ctx) =>
void runExternalSetup({
args: ['setup', ...arg.split(/\s+/).filter(Boolean)],
ctx,
done: 'setup complete — starting session…',
launcher: launchHermesCommand,
suspend: withInkSuspended
})
}
]

View file

@ -1,9 +1,10 @@
import { coreCommands } from './commands/core.js'
import { opsCommands } from './commands/ops.js'
import { sessionCommands } from './commands/session.js'
import { setupCommands } from './commands/setup.js'
import type { SlashCommand } from './types.js'
export const SLASH_COMMANDS: SlashCommand[] = [...coreCommands, ...sessionCommands, ...opsCommands]
export const SLASH_COMMANDS: SlashCommand[] = [...coreCommands, ...sessionCommands, ...opsCommands, ...setupCommands]
const byName = new Map<string, SlashCommand>(
SLASH_COMMANDS.flatMap(cmd => [cmd.name, ...(cmd.aliases ?? [])].map(name => [name, cmd] as const))