feat(tui): bare /details opens a keyboard selector

DetailsDialog is a centered SelectList over the five transcript-detail
states (three tool-card phases, reasoning shown/hidden); it preselects
the current phase, marks both current values, applies on Enter, and
cancels on Esc/Ctrl+C. Width is the new detailsDialogWidth config key.
The argument grammar is unchanged and shares the same setters.
This commit is contained in:
Turtle
2026-07-30 19:52:58 +08:00
parent 3899a26c87
commit 2c98f35a86
13 changed files with 256 additions and 34 deletions

View File

@@ -46,6 +46,8 @@ export interface TuiConfig {
questionDialogMaxHeight?: number
/** Model-selector width in terminal columns. */
modelDialogWidth?: number
/** Transcript-details selector width in terminal columns. */
detailsDialogWidth?: number
/** Model-selector maximum height in terminal rows. */
modelDialogMaxHeight?: number
/** Maximum fuzzy file candidates displayed for one `@` query. */
@@ -70,6 +72,7 @@ const maxResumeOptionsSchema = z.number().step(1).min(1).default(8)
const questionDialogWidthSchema = z.number().step(1).min(20).default(200)
const questionDialogMaxHeightSchema = z.number().step(1).min(6).default(20)
const modelDialogWidthSchema = z.number().step(1).min(20).default(76)
const detailsDialogWidthSchema = z.number().step(1).min(20).default(72)
const modelDialogMaxHeightSchema = z.number().step(1).min(6).default(20)
const fileSearchMaxResultsSchema = z.number().step(1).min(1).default(DEFAULT_FILE_SEARCH_MAX_RESULTS)
const fileSearchMaxEntriesSchema = z.number().step(1).min(1).default(DEFAULT_FILE_SEARCH_MAX_ENTRIES)
@@ -102,6 +105,7 @@ const tuiConfigSchemaFields = {
questionDialogMaxHeight: questionDialogMaxHeightSchema,
modelDialogWidth: modelDialogWidthSchema,
modelDialogMaxHeight: modelDialogMaxHeightSchema,
detailsDialogWidth: detailsDialogWidthSchema,
fileSearchMaxResults: fileSearchMaxResultsSchema,
fileSearchMaxEntries: fileSearchMaxEntriesSchema,
fileSearchExcludedDirectories: fileSearchExcludedDirectoriesSchema,
@@ -142,6 +146,7 @@ export const Config: z<Config> = z.object({
questionDialogMaxHeight: tuiConfigSchemaFields.questionDialogMaxHeight,
modelDialogWidth: tuiConfigSchemaFields.modelDialogWidth,
modelDialogMaxHeight: tuiConfigSchemaFields.modelDialogMaxHeight,
detailsDialogWidth: tuiConfigSchemaFields.detailsDialogWidth,
fileSearchMaxResults: tuiConfigSchemaFields.fileSearchMaxResults,
fileSearchMaxEntries: tuiConfigSchemaFields.fileSearchMaxEntries,
fileSearchExcludedDirectories: tuiConfigSchemaFields.fileSearchExcludedDirectories,
@@ -171,6 +176,7 @@ export interface ResolvedTuiConfig {
questionDialogMaxHeight: number
modelDialogWidth: number
modelDialogMaxHeight: number
detailsDialogWidth: number
fileSearchMaxResults: number
fileSearchMaxEntries: number
fileSearchExcludedDirectories: string[]
@@ -196,6 +202,7 @@ export function resolveTuiConfig(config: TuiConfig | undefined): ResolvedTuiConf
questionDialogMaxHeight: config?.questionDialogMaxHeight ?? 20,
modelDialogWidth: config?.modelDialogWidth ?? 76,
modelDialogMaxHeight: config?.modelDialogMaxHeight ?? 20,
detailsDialogWidth: config?.detailsDialogWidth ?? 72,
fileSearchMaxResults: config?.fileSearchMaxResults ?? DEFAULT_FILE_SEARCH_MAX_RESULTS,
fileSearchMaxEntries: config?.fileSearchMaxEntries ?? DEFAULT_FILE_SEARCH_MAX_ENTRIES,
fileSearchExcludedDirectories: [...(config?.fileSearchExcludedDirectories ?? DEFAULT_FILE_SEARCH_EXCLUDED_DIRECTORIES)],