mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
214 lines
9.3 KiB
TypeScript
214 lines
9.3 KiB
TypeScript
/**
|
|
* Serializable configuration and defaults for the pi-tui terminal mode. Loader
|
|
* schema validation normally fills defaults; {@link resolveTuiConfig} applies
|
|
* the same defaults for direct callers that bypass the Loader.
|
|
* @module @deepseek-ai/dsh-tui/config
|
|
*/
|
|
|
|
import z from 'schemastery'
|
|
import {
|
|
DEFAULT_FILE_SEARCH_EXCLUDED_DIRECTORIES,
|
|
DEFAULT_FILE_SEARCH_MAX_ENTRIES,
|
|
DEFAULT_FILE_SEARCH_MAX_RESULTS,
|
|
} from './chat/file-autocomplete.ts'
|
|
|
|
/** Theme and prompt-template settings for the pi-tui terminal mode. */
|
|
export interface TuiThemeConfig {
|
|
/** Apply the built-in ANSI color palette. */
|
|
color?: boolean
|
|
/** Paint the startup banner with the 24-bit DeepSeek brand gradient. */
|
|
truecolor?: boolean
|
|
/** Left-aligned template on the row above the editor. */
|
|
leftPrompt?: string
|
|
/** Right-aligned template on the row above the editor. */
|
|
rightPrompt?: string
|
|
/** Template used as the editor's first-line prefix. */
|
|
inputPrompt?: string
|
|
/** Static placeholder shown in an empty editor while the agent is running. */
|
|
inputPlaceholder?: string
|
|
}
|
|
|
|
/** Interaction and presentation settings for the pi-tui terminal mode. */
|
|
export interface TuiConfig {
|
|
/** Render model reasoning blocks. */
|
|
showReasoning?: boolean
|
|
/** Maximum tool-card body lines retained in its collapsed head/tail preview. */
|
|
maxToolOutputLines?: number
|
|
/** Maximum options visible at once in a user-question panel. */
|
|
maxQuestionOptions?: number
|
|
/** Maximum models visible at once in the model selector. */
|
|
maxModelOptions?: number
|
|
/** Maximum sessions visible at once in the resume selector. */
|
|
maxResumeOptions?: number
|
|
/** User-question panel width in terminal columns, clamped to the terminal. */
|
|
questionDialogWidth?: number
|
|
/** User-question panel maximum height in terminal rows. */
|
|
questionDialogMaxHeight?: number
|
|
/** Model-selector width in terminal columns. */
|
|
modelDialogWidth?: number
|
|
/** Model-selector maximum height in terminal rows. */
|
|
modelDialogMaxHeight?: number
|
|
/** Maximum fuzzy file candidates displayed for one `@` query. */
|
|
fileSearchMaxResults?: number
|
|
/** Maximum paths retained in one `@` workspace index. */
|
|
fileSearchMaxEntries?: number
|
|
/** Directory basenames excluded from `@` traversal and completion. */
|
|
fileSearchExcludedDirectories?: string[]
|
|
/** Show the terminal's hardware cursor at the pi editor's IME marker. */
|
|
showHardwareCursor?: boolean
|
|
/** Color and prompt-template settings. */
|
|
theme?: TuiThemeConfig
|
|
/** Terminal window title while the UI is mounted; a logged session title prefixes it. */
|
|
title?: string
|
|
}
|
|
|
|
const showReasoningSchema = z.boolean().default(true)
|
|
const maxToolOutputLinesSchema = z.number().step(1).min(1).default(6)
|
|
const maxQuestionOptionsSchema = z.number().step(1).min(1).default(8)
|
|
const maxModelOptionsSchema = z.number().step(1).min(1).default(8)
|
|
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 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)
|
|
const fileSearchExcludedDirectoriesSchema = z.array(z.string()).default([...DEFAULT_FILE_SEARCH_EXCLUDED_DIRECTORIES])
|
|
const showHardwareCursorSchema = z.boolean().default(false)
|
|
const colorSchema = z.boolean().default(true)
|
|
// No default: an unset value auto-detects truecolor from COLORTERM in `apply`.
|
|
const truecolorSchema = z.boolean()
|
|
const DEFAULT_LEFT_PROMPT = '${cwd}${git/worktree}${model}${token_meter/cache_hit_rate}${context}'
|
|
const DEFAULT_RIGHT_PROMPT = '${queued}'
|
|
const DEFAULT_INPUT_PROMPT = '${symbol} ${indicator}'
|
|
const DEFAULT_INPUT_PLACEHOLDER = 'press enter to steer and esc to cancel'
|
|
const TuiThemeConfigSchema: z<TuiThemeConfig> = z.object({
|
|
color: colorSchema,
|
|
truecolor: truecolorSchema,
|
|
leftPrompt: z.string().default(DEFAULT_LEFT_PROMPT),
|
|
rightPrompt: z.string().default(DEFAULT_RIGHT_PROMPT),
|
|
inputPrompt: z.string().default(DEFAULT_INPUT_PROMPT),
|
|
inputPlaceholder: z.string().default(DEFAULT_INPUT_PLACEHOLDER),
|
|
})
|
|
const titleSchema = z.string().default('DeepSeek Harness')
|
|
|
|
const tuiConfigSchemaFields = {
|
|
showReasoning: showReasoningSchema,
|
|
maxToolOutputLines: maxToolOutputLinesSchema,
|
|
maxQuestionOptions: maxQuestionOptionsSchema,
|
|
maxModelOptions: maxModelOptionsSchema,
|
|
maxResumeOptions: maxResumeOptionsSchema,
|
|
questionDialogWidth: questionDialogWidthSchema,
|
|
questionDialogMaxHeight: questionDialogMaxHeightSchema,
|
|
modelDialogWidth: modelDialogWidthSchema,
|
|
modelDialogMaxHeight: modelDialogMaxHeightSchema,
|
|
fileSearchMaxResults: fileSearchMaxResultsSchema,
|
|
fileSearchMaxEntries: fileSearchMaxEntriesSchema,
|
|
fileSearchExcludedDirectories: fileSearchExcludedDirectoriesSchema,
|
|
showHardwareCursor: showHardwareCursorSchema,
|
|
theme: TuiThemeConfigSchema,
|
|
title: titleSchema,
|
|
}
|
|
|
|
/** Schemastery schema for presentation settings embedded by app bundles. */
|
|
export const TuiConfigSchema: z<TuiConfig> = z.object(tuiConfigSchemaFields)
|
|
|
|
/** Serializable plugin configuration. */
|
|
export interface Config extends TuiConfig {
|
|
/** Banner subtitle line. When absent, the banner has no subtitle and sweeps in on start. */
|
|
welcome?: string
|
|
/** Exact shared agent/session identity driven by this terminal. Defaults to `main`. */
|
|
sessionId?: string
|
|
/**
|
|
* Skill name auto-invoked as this session's first user turn, exactly as if
|
|
* the user typed `/skill:<name>`. Set only by a launcher for a fresh
|
|
* skill-guided session (`dsh migrate`/`dsh upgrade`); absent
|
|
* leaves the first turn to the user.
|
|
*/
|
|
initialSkill?: string
|
|
}
|
|
|
|
/** Schemastery schema for the full plugin configuration. */
|
|
export const Config: z<Config> = z.object({
|
|
welcome: z.string(),
|
|
sessionId: z.string().default('main'),
|
|
initialSkill: z.string(),
|
|
showReasoning: tuiConfigSchemaFields.showReasoning,
|
|
maxToolOutputLines: tuiConfigSchemaFields.maxToolOutputLines,
|
|
maxQuestionOptions: tuiConfigSchemaFields.maxQuestionOptions,
|
|
maxModelOptions: tuiConfigSchemaFields.maxModelOptions,
|
|
maxResumeOptions: tuiConfigSchemaFields.maxResumeOptions,
|
|
questionDialogWidth: tuiConfigSchemaFields.questionDialogWidth,
|
|
questionDialogMaxHeight: tuiConfigSchemaFields.questionDialogMaxHeight,
|
|
modelDialogWidth: tuiConfigSchemaFields.modelDialogWidth,
|
|
modelDialogMaxHeight: tuiConfigSchemaFields.modelDialogMaxHeight,
|
|
fileSearchMaxResults: tuiConfigSchemaFields.fileSearchMaxResults,
|
|
fileSearchMaxEntries: tuiConfigSchemaFields.fileSearchMaxEntries,
|
|
fileSearchExcludedDirectories: tuiConfigSchemaFields.fileSearchExcludedDirectories,
|
|
showHardwareCursor: tuiConfigSchemaFields.showHardwareCursor,
|
|
theme: tuiConfigSchemaFields.theme,
|
|
title: tuiConfigSchemaFields.title,
|
|
})
|
|
|
|
/** Fully defaulted TUI theme settings. */
|
|
export interface ResolvedTuiThemeConfig {
|
|
color: boolean
|
|
truecolor: boolean
|
|
leftPrompt: string
|
|
rightPrompt: string
|
|
inputPrompt: string
|
|
inputPlaceholder: string
|
|
}
|
|
|
|
/** Fully defaulted TUI presentation settings. */
|
|
export interface ResolvedTuiConfig {
|
|
showReasoning: boolean
|
|
maxToolOutputLines: number
|
|
maxQuestionOptions: number
|
|
maxModelOptions: number
|
|
maxResumeOptions: number
|
|
questionDialogWidth: number
|
|
questionDialogMaxHeight: number
|
|
modelDialogWidth: number
|
|
modelDialogMaxHeight: number
|
|
fileSearchMaxResults: number
|
|
fileSearchMaxEntries: number
|
|
fileSearchExcludedDirectories: string[]
|
|
showHardwareCursor: boolean
|
|
theme: ResolvedTuiThemeConfig
|
|
title: string
|
|
}
|
|
|
|
/**
|
|
* Apply direct-call defaults after Loader schema validation has normally run.
|
|
*
|
|
* @param config - Deployment-provided terminal presentation settings.
|
|
* @returns Complete settings consumed by the TUI renderer.
|
|
*/
|
|
export function resolveTuiConfig(config: TuiConfig | undefined): ResolvedTuiConfig {
|
|
return {
|
|
showReasoning: config?.showReasoning ?? true,
|
|
maxToolOutputLines: config?.maxToolOutputLines ?? 6,
|
|
maxQuestionOptions: config?.maxQuestionOptions ?? 8,
|
|
maxModelOptions: config?.maxModelOptions ?? 8,
|
|
maxResumeOptions: config?.maxResumeOptions ?? 8,
|
|
questionDialogWidth: config?.questionDialogWidth ?? 200,
|
|
questionDialogMaxHeight: config?.questionDialogMaxHeight ?? 20,
|
|
modelDialogWidth: config?.modelDialogWidth ?? 76,
|
|
modelDialogMaxHeight: config?.modelDialogMaxHeight ?? 20,
|
|
fileSearchMaxResults: config?.fileSearchMaxResults ?? DEFAULT_FILE_SEARCH_MAX_RESULTS,
|
|
fileSearchMaxEntries: config?.fileSearchMaxEntries ?? DEFAULT_FILE_SEARCH_MAX_ENTRIES,
|
|
fileSearchExcludedDirectories: [...(config?.fileSearchExcludedDirectories ?? DEFAULT_FILE_SEARCH_EXCLUDED_DIRECTORIES)],
|
|
showHardwareCursor: config?.showHardwareCursor ?? false,
|
|
theme: {
|
|
color: config?.theme?.color ?? true,
|
|
truecolor: config?.theme?.truecolor ?? false,
|
|
leftPrompt: config?.theme?.leftPrompt ?? DEFAULT_LEFT_PROMPT,
|
|
rightPrompt: config?.theme?.rightPrompt ?? DEFAULT_RIGHT_PROMPT,
|
|
inputPrompt: config?.theme?.inputPrompt ?? DEFAULT_INPUT_PROMPT,
|
|
inputPlaceholder: config?.theme?.inputPlaceholder ?? DEFAULT_INPUT_PLACEHOLDER,
|
|
},
|
|
title: config?.title ?? 'DeepSeek Harness',
|
|
}
|
|
}
|