mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-18 05:01:55 +00:00
feat(hooks): expose setTitle to HookUIContext (#446)
This commit is contained in:
parent
affa618b43
commit
5cb7af1ddc
9 changed files with 34 additions and 1 deletions
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Hook API: `ctx.ui.setTitle(title)` allows hooks to set the terminal window/tab title ([#446](https://github.com/badlogic/pi-mono/pull/446) by [@aliou](https://github.com/aliou))
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Expanded keybinding documentation to list all 32 supported symbol keys with notes on ctrl+symbol behavior ([#450](https://github.com/badlogic/pi-mono/pull/450) by [@kaofelix](https://github.com/kaofelix))
|
- Expanded keybinding documentation to list all 32 supported symbol keys with notes on ctrl+symbol behavior ([#450](https://github.com/badlogic/pi-mono/pull/450) by [@kaofelix](https://github.com/kaofelix))
|
||||||
|
|
|
||||||
|
|
@ -437,6 +437,9 @@ ctx.ui.setWidget("my-todos", [
|
||||||
]);
|
]);
|
||||||
ctx.ui.setWidget("my-todos", undefined); // Clear widget
|
ctx.ui.setWidget("my-todos", undefined); // Clear widget
|
||||||
|
|
||||||
|
// Set the terminal window/tab title
|
||||||
|
ctx.ui.setTitle("pi - my-project");
|
||||||
|
|
||||||
// Set the core input editor text (pre-fill prompts, generated content)
|
// Set the core input editor text (pre-fill prompts, generated content)
|
||||||
ctx.ui.setEditorText("Generated prompt text here...");
|
ctx.ui.setEditorText("Generated prompt text here...");
|
||||||
|
|
||||||
|
|
@ -457,6 +460,10 @@ const currentText = ctx.ui.getEditorText();
|
||||||
- Supports ANSI styling via `ctx.ui.theme` (including `strikethrough`)
|
- Supports ANSI styling via `ctx.ui.theme` (including `strikethrough`)
|
||||||
- **Caution:** Keep widgets small (a few lines). Large widgets from multiple hooks can cause viewport overflow and TUI flicker. Max 10 lines total across all string widgets.
|
- **Caution:** Keep widgets small (a few lines). Large widgets from multiple hooks can cause viewport overflow and TUI flicker. Max 10 lines total across all string widgets.
|
||||||
|
|
||||||
|
**Terminal title notes:**
|
||||||
|
- Uses OSC escape sequence (works in most modern terminals like iTerm2, Terminal.app, Windows Terminal)
|
||||||
|
- Useful for showing project name, current task, or session status in the terminal tab/window title
|
||||||
|
|
||||||
**Custom widget components:**
|
**Custom widget components:**
|
||||||
|
|
||||||
For more complex widgets, pass a factory function to `setWidget()`:
|
For more complex widgets, pass a factory function to `setWidget()`:
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ function createNoOpUIContext(): HookUIContext {
|
||||||
notify: () => {},
|
notify: () => {},
|
||||||
setStatus: () => {},
|
setStatus: () => {},
|
||||||
setWidget: () => {},
|
setWidget: () => {},
|
||||||
|
setTitle: () => {},
|
||||||
custom: async () => undefined as never,
|
custom: async () => undefined as never,
|
||||||
setEditorText: () => {},
|
setEditorText: () => {},
|
||||||
getEditorText: () => "",
|
getEditorText: () => "",
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ const noOpUIContext: HookUIContext = {
|
||||||
notify: () => {},
|
notify: () => {},
|
||||||
setStatus: () => {},
|
setStatus: () => {},
|
||||||
setWidget: () => {},
|
setWidget: () => {},
|
||||||
|
setTitle: () => {},
|
||||||
custom: async () => undefined as never,
|
custom: async () => undefined as never,
|
||||||
setEditorText: () => {},
|
setEditorText: () => {},
|
||||||
getEditorText: () => "",
|
getEditorText: () => "",
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,13 @@ export interface HookUIContext {
|
||||||
*/
|
*/
|
||||||
setWidget(key: string, content: ((tui: TUI, theme: Theme) => Component & { dispose?(): void }) | undefined): void;
|
setWidget(key: string, content: ((tui: TUI, theme: Theme) => Component & { dispose?(): void }) | undefined): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the terminal window/tab title.
|
||||||
|
* Uses OSC escape sequence (works in most modern terminals).
|
||||||
|
* @param title - Title text to display
|
||||||
|
*/
|
||||||
|
setTitle(title: string): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show a custom component with keyboard focus.
|
* Show a custom component with keyboard focus.
|
||||||
* The factory receives TUI, theme, and a done() callback to close the component.
|
* The factory receives TUI, theme, and a done() callback to close the component.
|
||||||
|
|
|
||||||
|
|
@ -685,6 +685,7 @@ export class InteractiveMode {
|
||||||
notify: (message, type) => this.showHookNotify(message, type),
|
notify: (message, type) => this.showHookNotify(message, type),
|
||||||
setStatus: (key, text) => this.setHookStatus(key, text),
|
setStatus: (key, text) => this.setHookStatus(key, text),
|
||||||
setWidget: (key, content) => this.setHookWidget(key, content),
|
setWidget: (key, content) => this.setHookWidget(key, content),
|
||||||
|
setTitle: (title) => this.ui.terminal.setTitle(title),
|
||||||
custom: (factory) => this.showHookCustom(factory),
|
custom: (factory) => this.showHookCustom(factory),
|
||||||
setEditorText: (text) => this.editor.setText(text),
|
setEditorText: (text) => this.editor.setText(text),
|
||||||
getEditorText: () => this.editor.getText(),
|
getEditorText: () => this.editor.getText(),
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,16 @@ export async function runRpcMode(session: AgentSession): Promise<never> {
|
||||||
// Component factories are not supported in RPC mode - would need TUI access
|
// Component factories are not supported in RPC mode - would need TUI access
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setTitle(title: string): void {
|
||||||
|
// Fire and forget - host can implement terminal title control
|
||||||
|
output({
|
||||||
|
type: "hook_ui_request",
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
method: "setTitle",
|
||||||
|
title,
|
||||||
|
} as RpcHookUIRequest);
|
||||||
|
},
|
||||||
|
|
||||||
async custom() {
|
async custom() {
|
||||||
// Custom UI not supported in RPC mode
|
// Custom UI not supported in RPC mode
|
||||||
return undefined as never;
|
return undefined as never;
|
||||||
|
|
|
||||||
|
|
@ -196,6 +196,7 @@ export type RpcHookUIRequest =
|
||||||
widgetKey: string;
|
widgetKey: string;
|
||||||
widgetLines: string[] | undefined;
|
widgetLines: string[] | undefined;
|
||||||
}
|
}
|
||||||
|
| { type: "hook_ui_request"; id: string; method: "setTitle"; title: string }
|
||||||
| { type: "hook_ui_request"; id: string; method: "set_editor_text"; text: string };
|
| { type: "hook_ui_request"; id: string; method: "set_editor_text"; text: string };
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,7 @@ describe.skipIf(!API_KEY)("Compaction hooks", () => {
|
||||||
notify: () => {},
|
notify: () => {},
|
||||||
setStatus: () => {},
|
setStatus: () => {},
|
||||||
setWidget: () => {},
|
setWidget: () => {},
|
||||||
|
setTitle: () => {},
|
||||||
custom: async () => undefined as never,
|
custom: async () => undefined as never,
|
||||||
setEditorText: () => {},
|
setEditorText: () => {},
|
||||||
getEditorText: () => "",
|
getEditorText: () => "",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue