mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 07:04:45 +00:00
feat(coding-agent): add treeFilterMode setting for /tree default filter (#1852)
Add configurable initial filter mode for the session tree navigator. Users who always switch to a specific filter (e.g. no-tools via Ctrl+T) can now set it as default in settings. Same pattern as doubleEscapeAction (#404). Filter infra from #747.
This commit is contained in:
parent
a0d839ce84
commit
1f39cc776a
5 changed files with 39 additions and 2 deletions
|
|
@ -42,6 +42,7 @@ Edit directly or use `/settings` for common options.
|
||||||
| `quietStartup` | boolean | `false` | Hide startup header |
|
| `quietStartup` | boolean | `false` | Hide startup header |
|
||||||
| `collapseChangelog` | boolean | `false` | Show condensed changelog after updates |
|
| `collapseChangelog` | boolean | `false` | Show condensed changelog after updates |
|
||||||
| `doubleEscapeAction` | string | `"tree"` | Action for double-escape: `"tree"`, `"fork"`, or `"none"` |
|
| `doubleEscapeAction` | string | `"tree"` | Action for double-escape: `"tree"`, `"fork"`, or `"none"` |
|
||||||
|
| `treeFilterMode` | string | `"default"` | Default filter for `/tree`: `"default"`, `"no-tools"`, `"user-only"`, `"labeled-only"`, `"all"` |
|
||||||
| `editorPaddingX` | number | `0` | Horizontal padding for input editor (0-3) |
|
| `editorPaddingX` | number | `0` | Horizontal padding for input editor (0-3) |
|
||||||
| `autocompleteMaxVisible` | number | `5` | Max visible items in autocomplete dropdown (3-20) |
|
| `autocompleteMaxVisible` | number | `5` | Max visible items in autocomplete dropdown (3-20) |
|
||||||
| `showHardwareCursor` | boolean | `false` | Show terminal cursor |
|
| `showHardwareCursor` | boolean | `false` | Show terminal cursor |
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,7 @@ export interface Settings {
|
||||||
images?: ImageSettings;
|
images?: ImageSettings;
|
||||||
enabledModels?: string[]; // Model patterns for cycling (same format as --models CLI flag)
|
enabledModels?: string[]; // Model patterns for cycling (same format as --models CLI flag)
|
||||||
doubleEscapeAction?: "fork" | "tree" | "none"; // Action for double-escape with empty editor (default: "tree")
|
doubleEscapeAction?: "fork" | "tree" | "none"; // Action for double-escape with empty editor (default: "tree")
|
||||||
|
treeFilterMode?: "default" | "no-tools" | "user-only" | "labeled-only" | "all"; // Default filter when opening /tree
|
||||||
thinkingBudgets?: ThinkingBudgetsSettings; // Custom token budgets for thinking levels
|
thinkingBudgets?: ThinkingBudgetsSettings; // Custom token budgets for thinking levels
|
||||||
editorPaddingX?: number; // Horizontal padding for input editor (default: 0)
|
editorPaddingX?: number; // Horizontal padding for input editor (default: 0)
|
||||||
autocompleteMaxVisible?: number; // Max visible items in autocomplete dropdown (default: 5)
|
autocompleteMaxVisible?: number; // Max visible items in autocomplete dropdown (default: 5)
|
||||||
|
|
@ -866,6 +867,18 @@ export class SettingsManager {
|
||||||
this.save();
|
this.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTreeFilterMode(): "default" | "no-tools" | "user-only" | "labeled-only" | "all" {
|
||||||
|
const mode = this.settings.treeFilterMode;
|
||||||
|
const valid = ["default", "no-tools", "user-only", "labeled-only", "all"];
|
||||||
|
return mode && valid.includes(mode) ? mode : "default";
|
||||||
|
}
|
||||||
|
|
||||||
|
setTreeFilterMode(mode: "default" | "no-tools" | "user-only" | "labeled-only" | "all"): void {
|
||||||
|
this.globalSettings.treeFilterMode = mode;
|
||||||
|
this.markModified("treeFilterMode");
|
||||||
|
this.save();
|
||||||
|
}
|
||||||
|
|
||||||
getShowHardwareCursor(): boolean {
|
getShowHardwareCursor(): boolean {
|
||||||
return this.settings.showHardwareCursor ?? process.env.PI_HARDWARE_CURSOR === "1";
|
return this.settings.showHardwareCursor ?? process.env.PI_HARDWARE_CURSOR === "1";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ export interface SettingsConfig {
|
||||||
hideThinkingBlock: boolean;
|
hideThinkingBlock: boolean;
|
||||||
collapseChangelog: boolean;
|
collapseChangelog: boolean;
|
||||||
doubleEscapeAction: "fork" | "tree" | "none";
|
doubleEscapeAction: "fork" | "tree" | "none";
|
||||||
|
treeFilterMode: "default" | "no-tools" | "user-only" | "labeled-only" | "all";
|
||||||
showHardwareCursor: boolean;
|
showHardwareCursor: boolean;
|
||||||
editorPaddingX: number;
|
editorPaddingX: number;
|
||||||
autocompleteMaxVisible: number;
|
autocompleteMaxVisible: number;
|
||||||
|
|
@ -60,6 +61,7 @@ export interface SettingsCallbacks {
|
||||||
onHideThinkingBlockChange: (hidden: boolean) => void;
|
onHideThinkingBlockChange: (hidden: boolean) => void;
|
||||||
onCollapseChangelogChange: (collapsed: boolean) => void;
|
onCollapseChangelogChange: (collapsed: boolean) => void;
|
||||||
onDoubleEscapeActionChange: (action: "fork" | "tree" | "none") => void;
|
onDoubleEscapeActionChange: (action: "fork" | "tree" | "none") => void;
|
||||||
|
onTreeFilterModeChange: (mode: "default" | "no-tools" | "user-only" | "labeled-only" | "all") => void;
|
||||||
onShowHardwareCursorChange: (enabled: boolean) => void;
|
onShowHardwareCursorChange: (enabled: boolean) => void;
|
||||||
onEditorPaddingXChange: (padding: number) => void;
|
onEditorPaddingXChange: (padding: number) => void;
|
||||||
onAutocompleteMaxVisibleChange: (maxVisible: number) => void;
|
onAutocompleteMaxVisibleChange: (maxVisible: number) => void;
|
||||||
|
|
@ -200,6 +202,13 @@ export class SettingsSelectorComponent extends Container {
|
||||||
currentValue: config.doubleEscapeAction,
|
currentValue: config.doubleEscapeAction,
|
||||||
values: ["tree", "fork", "none"],
|
values: ["tree", "fork", "none"],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "tree-filter-mode",
|
||||||
|
label: "Tree filter mode",
|
||||||
|
description: "Default filter when opening /tree",
|
||||||
|
currentValue: config.treeFilterMode,
|
||||||
|
values: ["default", "no-tools", "user-only", "labeled-only", "all"],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "thinking",
|
id: "thinking",
|
||||||
label: "Thinking level",
|
label: "Thinking level",
|
||||||
|
|
@ -379,6 +388,11 @@ export class SettingsSelectorComponent extends Container {
|
||||||
case "double-escape-action":
|
case "double-escape-action":
|
||||||
callbacks.onDoubleEscapeActionChange(newValue as "fork" | "tree");
|
callbacks.onDoubleEscapeActionChange(newValue as "fork" | "tree");
|
||||||
break;
|
break;
|
||||||
|
case "tree-filter-mode":
|
||||||
|
callbacks.onTreeFilterModeChange(
|
||||||
|
newValue as "default" | "no-tools" | "user-only" | "labeled-only" | "all",
|
||||||
|
);
|
||||||
|
break;
|
||||||
case "show-hardware-cursor":
|
case "show-hardware-cursor":
|
||||||
callbacks.onShowHardwareCursorChange(newValue === "true");
|
callbacks.onShowHardwareCursorChange(newValue === "true");
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ interface FlatNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Filter mode for tree display */
|
/** Filter mode for tree display */
|
||||||
type FilterMode = "default" | "no-tools" | "user-only" | "labeled-only" | "all";
|
export type FilterMode = "default" | "no-tools" | "user-only" | "labeled-only" | "all";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tree list component with selection and ASCII art visualization
|
* Tree list component with selection and ASCII art visualization
|
||||||
|
|
@ -70,9 +70,11 @@ class TreeList implements Component {
|
||||||
currentLeafId: string | null,
|
currentLeafId: string | null,
|
||||||
maxVisibleLines: number,
|
maxVisibleLines: number,
|
||||||
initialSelectedId?: string,
|
initialSelectedId?: string,
|
||||||
|
initialFilterMode?: FilterMode,
|
||||||
) {
|
) {
|
||||||
this.currentLeafId = currentLeafId;
|
this.currentLeafId = currentLeafId;
|
||||||
this.maxVisibleLines = maxVisibleLines;
|
this.maxVisibleLines = maxVisibleLines;
|
||||||
|
this.filterMode = initialFilterMode ?? "default";
|
||||||
this.multipleRoots = tree.length > 1;
|
this.multipleRoots = tree.length > 1;
|
||||||
this.flatNodes = this.flattenTree(tree);
|
this.flatNodes = this.flattenTree(tree);
|
||||||
this.buildActivePath();
|
this.buildActivePath();
|
||||||
|
|
@ -1001,13 +1003,14 @@ export class TreeSelectorComponent extends Container implements Focusable {
|
||||||
onCancel: () => void,
|
onCancel: () => void,
|
||||||
onLabelChange?: (entryId: string, label: string | undefined) => void,
|
onLabelChange?: (entryId: string, label: string | undefined) => void,
|
||||||
initialSelectedId?: string,
|
initialSelectedId?: string,
|
||||||
|
initialFilterMode?: FilterMode,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.onLabelChangeCallback = onLabelChange;
|
this.onLabelChangeCallback = onLabelChange;
|
||||||
const maxVisibleLines = Math.max(5, Math.floor(terminalHeight / 2));
|
const maxVisibleLines = Math.max(5, Math.floor(terminalHeight / 2));
|
||||||
|
|
||||||
this.treeList = new TreeList(tree, currentLeafId, maxVisibleLines, initialSelectedId);
|
this.treeList = new TreeList(tree, currentLeafId, maxVisibleLines, initialSelectedId, initialFilterMode);
|
||||||
this.treeList.onSelect = onSelect;
|
this.treeList.onSelect = onSelect;
|
||||||
this.treeList.onCancel = onCancel;
|
this.treeList.onCancel = onCancel;
|
||||||
this.treeList.onLabelEdit = (entryId, currentLabel) => this.showLabelInput(entryId, currentLabel);
|
this.treeList.onLabelEdit = (entryId, currentLabel) => this.showLabelInput(entryId, currentLabel);
|
||||||
|
|
|
||||||
|
|
@ -3045,6 +3045,7 @@ export class InteractiveMode {
|
||||||
hideThinkingBlock: this.hideThinkingBlock,
|
hideThinkingBlock: this.hideThinkingBlock,
|
||||||
collapseChangelog: this.settingsManager.getCollapseChangelog(),
|
collapseChangelog: this.settingsManager.getCollapseChangelog(),
|
||||||
doubleEscapeAction: this.settingsManager.getDoubleEscapeAction(),
|
doubleEscapeAction: this.settingsManager.getDoubleEscapeAction(),
|
||||||
|
treeFilterMode: this.settingsManager.getTreeFilterMode(),
|
||||||
showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
|
showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
|
||||||
editorPaddingX: this.settingsManager.getEditorPaddingX(),
|
editorPaddingX: this.settingsManager.getEditorPaddingX(),
|
||||||
autocompleteMaxVisible: this.settingsManager.getAutocompleteMaxVisible(),
|
autocompleteMaxVisible: this.settingsManager.getAutocompleteMaxVisible(),
|
||||||
|
|
@ -3124,6 +3125,9 @@ export class InteractiveMode {
|
||||||
onDoubleEscapeActionChange: (action) => {
|
onDoubleEscapeActionChange: (action) => {
|
||||||
this.settingsManager.setDoubleEscapeAction(action);
|
this.settingsManager.setDoubleEscapeAction(action);
|
||||||
},
|
},
|
||||||
|
onTreeFilterModeChange: (mode) => {
|
||||||
|
this.settingsManager.setTreeFilterMode(mode);
|
||||||
|
},
|
||||||
onShowHardwareCursorChange: (enabled) => {
|
onShowHardwareCursorChange: (enabled) => {
|
||||||
this.settingsManager.setShowHardwareCursor(enabled);
|
this.settingsManager.setShowHardwareCursor(enabled);
|
||||||
this.ui.setShowHardwareCursor(enabled);
|
this.ui.setShowHardwareCursor(enabled);
|
||||||
|
|
@ -3413,6 +3417,7 @@ export class InteractiveMode {
|
||||||
private showTreeSelector(initialSelectedId?: string): void {
|
private showTreeSelector(initialSelectedId?: string): void {
|
||||||
const tree = this.sessionManager.getTree();
|
const tree = this.sessionManager.getTree();
|
||||||
const realLeafId = this.sessionManager.getLeafId();
|
const realLeafId = this.sessionManager.getLeafId();
|
||||||
|
const initialFilterMode = this.settingsManager.getTreeFilterMode();
|
||||||
|
|
||||||
if (tree.length === 0) {
|
if (tree.length === 0) {
|
||||||
this.showStatus("No entries in session");
|
this.showStatus("No entries in session");
|
||||||
|
|
@ -3531,6 +3536,7 @@ export class InteractiveMode {
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
},
|
},
|
||||||
initialSelectedId,
|
initialSelectedId,
|
||||||
|
initialFilterMode,
|
||||||
);
|
);
|
||||||
return { component: selector, focus: selector };
|
return { component: selector, focus: selector };
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue