import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent"; import { getSettingsListTheme } from "@earendil-works/pi-coding-agent"; import { type AutocompleteItem, Key, matchesKey, type SettingItem, SettingsList, type SettingsListTheme, truncateToWidth, } from "@earendil-works/pi-tui"; import { type ColorSource, type ColorSourcesConfig, type ContextStyle, type ExtensionStatusColorMode, type ExtensionStatusPlacement, type FooterRowsConfig, type FooterSegmentsConfig, type GitBranchConfig, type GitBranchMaxLength, getExtensionStatusColorMode, getExtensionStatusPlacement, type IconMode, isExtensionStatusColorMode, isExtensionStatusPlacement, isSeparatorStyle, type PathDisplayConfig, type PathDisplayMode, type PolishedTuiConfig, type SeparatorStyle, type UiFeaturesConfig, } from "../config/config.js"; import { sanitizeExtensionStatusText } from "../segments/extension-status.js"; import { isIconMode } from "../ui/icons.js"; import { safeThemeFg } from "../ui/style.js"; const colorSourceValues: ColorSource[] = ["theme", "terminal"]; const extensionStatusPlacementValues: ExtensionStatusPlacement[] = [ "off", "left", "middle", "right", ]; const extensionStatusColorModeValues: ExtensionStatusColorMode[] = ["zentui", "original"]; const contextStyleValues: ContextStyle[] = ["text", "gauge", "text+gauge"]; const separatorStyleValues: SeparatorStyle[] = ["pipe", "dot", "chevron", "none"]; const pathDisplayModeValues: PathDisplayMode[] = ["basename", "full"]; const pathDepthValues = ["0", "1", "2", "3", "4", "5"] as const; const branchLengthPresetValues = ["full", "10", "20", "30", "40", "50"] as const; const iconModeValues: IconMode[] = ["auto", "nerd", "ascii"]; type FeatureState = "enabled" | "disabled"; const featureStateValues: FeatureState[] = ["enabled", "disabled"]; const settingsSections = [ "coloring", "features", "layout", "builtinSegments", "extensionSegments", ] as const; type ColorSettingId = "starship"; type FeatureSettingId = keyof UiFeaturesConfig; type FooterSegmentSettingId = keyof FooterSegmentsConfig; type SettingsSection = (typeof settingsSections)[number]; type LayoutSettingId = "contextStyle" | "separator" | "pathDisplay" | "pathDepth" | "branchLength" | "iconMode"; type SettingsCommandDeps = { getConfig: () => PolishedTuiConfig; setColorSources: (patch: Partial) => void; setUiFeatures: (patch: Partial, ctx: ExtensionContext) => void; setFooterRows: (patch: Partial) => void; setFooterSegments: (patch: Partial) => void; setFooterFormat: (value: string) => void; setIconMode: (mode: IconMode) => void; setContextStyle: (style: ContextStyle) => void; setSeparator: (separator: SeparatorStyle) => void; setPathDisplay: (patch: Partial) => void; setGitBranch: (patch: Partial) => void; getActiveExtensionStatuses: () => ReadonlyMap; setExtensionStatusPlacement: (key: string, placement: ExtensionStatusPlacement) => void; setExtensionStatusColorMode: (key: string, colorMode: ExtensionStatusColorMode) => void; requestRender: () => void; settingsListTheme?: SettingsListTheme; }; const colorSettingLabels: Record = { starship: "Footer colors", }; const colorSettingDescriptions: Record = { starship: "Choose whether footer runtime/git/context colors use Pi theme tokens or terminal palette styles.", }; const featureSettingLabels: Record = { statusLine: "Status line", }; const featureSettingDescriptions: Record = { statusLine: "Enable or disable Zentui's custom footer/status line.", }; const footerRowLabels: Record = { project: "Project row", session: "Session row", activity: "Activity row", usage: "Usage row", }; const footerSegmentSettingLabels: Record = { cwd: "Current directory", gitBranch: "Git branch", gitStatus: "Git status", gitState: "Git operation state", gitCounts: "Git counts", gitCommit: "Git commit", gitMetrics: "Git line metrics", runtime: "Runtime", packageVersion: "Package version", configCounts: "Config counts", os: "OS icon", username: "Username@host", sessionName: "Session name", model: "Model", thinking: "Thinking level", turnCount: "Turn count", sessionDuration: "Session duration", runningTools: "Running tools", toolCounts: "Completed tool counts", activeAgents: "Active agents", agentIdle: "Agent idle status", skills: "Skill activity", mcp: "MCP connections", context: "Context usage", inputTokens: "Input tokens", outputTokens: "Output tokens", cacheDetails: "Cache details", cost: "Session cost", codexUsage: "Codex subscription", time: "Current time", }; const footerSegmentSettingDescriptions: Record = { cwd: "Show or hide the current working directory on the project row.", gitBranch: "Show or hide the git branch name on the project row.", gitStatus: "Show or hide git status icons and ahead/behind markers on the project row.", gitState: "Show or hide Git operation states such as MERGING and REBASING.", gitCounts: "Show numeric ahead/behind and stash counts (requires the Git status segment to be enabled).", sessionDuration: "Show session running time on the session row.", username: "Show user@hostname on the project row.", time: "Show the current time (HH:MM) on the usage row.", os: "Show an operating-system icon on the project row.", runtime: "Show or hide the detected runtime/language on the project row.", context: "Show or hide context usage on the usage row.", inputTokens: "Show or hide cumulative input tokens on the usage row.", outputTokens: "Show or hide cumulative output tokens on the usage row.", cost: "Show or hide session cost on the usage row.", packageVersion: "Show the project’s own manifest version (package.json, Cargo.toml, pyproject.toml, …) on the project row. Distinct from the installed toolchain version.", gitCommit: "Show the current commit hash and optional exact-match tag on the project row. Starship `git_commit`-style; default off.", gitMetrics: "Show aggregate added/deleted line counts (e.g. `+ 12 − 3`) on the project row via `git diff HEAD --numstat`; default off.", sessionName: "Show the current Pi session name on the session row.", model: "Show provider/model information on the session row.", thinking: "Show the selected thinking level on the session row for reasoning-capable models.", turnCount: "Show the current turn index on the session row.", cacheDetails: "Show cumulative cache read/write token totals on the usage row.", codexUsage: "Show OpenAI Codex subscription rate limits on the usage row when available.", configCounts: "Show instruction-file and installed Pi package counts on the project row.", skills: "Show active/available Pi skill counts on the activity row.", mcp: "Show parsed MCP connected/total server counts on the activity row.", runningTools: "Show currently running native tools and their elapsed time.", toolCounts: "Show cumulative completed native-tool counts.", activeAgents: "Show active main agent runs on the activity row (not subagent count).", agentIdle: "Show Agent idle when no main agent run is active.", }; const directCommandSuggestions = [ "statusline enable", "statusline disable", "statusline toggle", ...Object.keys(footerRowLabels).flatMap((row) => [ `row ${row} enable`, `row ${row} disable`, `row ${row} toggle`, ]), "format clear", "format $cwd on $git_branch $fill $context", "format $cwd( on $git_branch)($git_status)$fill($context)( | $cost)", ]; const sectionLabels: Record = { coloring: "Coloring", features: "Features", layout: "Layout", builtinSegments: "Built-in segments", extensionSegments: "Extension segments", }; const thirdPartyStatusSettingPrefix = "thirdPartyStatus:"; const footerSegmentSettingPrefix = "footerSegment:"; type ThirdPartyStatusSettingKind = "placement" | "colorMode"; function isColorSource(value: string): value is ColorSource { return value === "theme" || value === "terminal"; } function isColorSettingId(value: string): value is ColorSettingId { return value === "starship"; } function isFeatureSettingId(value: string): value is FeatureSettingId { return value === "statusLine"; } function isFooterSegmentSettingId(value: string): value is FooterSegmentSettingId { return ( value === "cwd" || value === "gitBranch" || value === "gitStatus" || value === "gitState" || value === "gitCounts" || value === "sessionDuration" || value === "runtime" || value === "context" || value === "inputTokens" || value === "outputTokens" || value === "cost" || value === "username" || value === "time" || value === "os" || value === "packageVersion" || value === "gitCommit" || value === "gitMetrics" || value === "sessionName" || value === "model" || value === "thinking" || value === "turnCount" || value === "cacheDetails" || value === "codexUsage" || value === "configCounts" || value === "skills" || value === "mcp" || value === "runningTools" || value === "toolCounts" || value === "activeAgents" || value === "agentIdle" ); } function isFeatureState(value: string): value is FeatureState { return value === "enabled" || value === "disabled"; } function isContextStyle(value: string): value is ContextStyle { return value === "text" || value === "gauge" || value === "text+gauge"; } function isPathDisplayMode(value: string): value is PathDisplayMode { return value === "basename" || value === "full"; } function isPathDepthValue(value: string): boolean { return (pathDepthValues as readonly string[]).includes(value); } function parseGitBranchLengthValue(value: string): GitBranchMaxLength | undefined { if (value === "full") return value; const parsed = Number(value); return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined; } function branchLengthValues(maxLength: GitBranchMaxLength): string[] { const current = String(maxLength); return (branchLengthPresetValues as readonly string[]).includes(current) ? [...branchLengthPresetValues] : [current, ...branchLengthPresetValues]; } function isLayoutSettingId(value: string): value is LayoutSettingId { return ( value === "contextStyle" || value === "separator" || value === "pathDisplay" || value === "pathDepth" || value === "branchLength" || value === "iconMode" ); } function patchForSetting(_id: ColorSettingId, value: ColorSource): Partial { return { starship: value }; } function featureValue(enabled: boolean): FeatureState { return enabled ? "enabled" : "disabled"; } function featurePatch(id: FeatureSettingId, value: FeatureState): Partial { return { [id]: value === "enabled" } as Partial; } function footerSegmentSettingId(key: FooterSegmentSettingId): string { return `${footerSegmentSettingPrefix}${key}`; } function footerSegmentSettingFromId(id: string): FooterSegmentSettingId | undefined { if (!id.startsWith(footerSegmentSettingPrefix)) return undefined; const key = id.slice(footerSegmentSettingPrefix.length); return isFooterSegmentSettingId(key) ? key : undefined; } function footerSegmentPatch( id: FooterSegmentSettingId, value: FeatureState, ): Partial { return { [id]: value === "enabled" } as Partial; } function usageText(): string { return 'Usage: /zentui statusline [enable|disable|toggle], /zentui row [project|session|activity|usage] [enable|disable|toggle], or /zentui format "