mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-16 23:01:56 +00:00
Custom tools with session lifecycle, examples for hooks and tools
- Custom tools: TypeScript modules that extend pi with new tools - Custom TUI rendering via renderCall/renderResult - User interaction via pi.ui (select, confirm, input, notify) - Session lifecycle via onSession callback for state reconstruction - Examples: todo.ts, question.ts, hello.ts - Hook examples: permission-gate, git-checkpoint, protected-paths - Session lifecycle centralized in AgentSession - Works across all modes (interactive, print, RPC) - Unified session event for hooks (replaces session_start/session_switch) - Box component added to pi-tui - Examples bundled in npm and binary releases Fixes #190
This commit is contained in:
parent
295f51b53f
commit
e7097d911a
33 changed files with 1926 additions and 117 deletions
96
packages/tui/src/components/box.ts
Normal file
96
packages/tui/src/components/box.ts
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
import type { Component } from "../tui.js";
|
||||
import { applyBackgroundToLine, visibleWidth } from "../utils.js";
|
||||
|
||||
/**
|
||||
* Box component - a container that applies padding and background to all children
|
||||
*/
|
||||
export class Box implements Component {
|
||||
children: Component[] = [];
|
||||
private paddingX: number;
|
||||
private paddingY: number;
|
||||
private bgFn?: (text: string) => string;
|
||||
|
||||
constructor(paddingX = 1, paddingY = 1, bgFn?: (text: string) => string) {
|
||||
this.paddingX = paddingX;
|
||||
this.paddingY = paddingY;
|
||||
this.bgFn = bgFn;
|
||||
}
|
||||
|
||||
addChild(component: Component): void {
|
||||
this.children.push(component);
|
||||
}
|
||||
|
||||
removeChild(component: Component): void {
|
||||
const index = this.children.indexOf(component);
|
||||
if (index !== -1) {
|
||||
this.children.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.children = [];
|
||||
}
|
||||
|
||||
setBgFn(bgFn?: (text: string) => string): void {
|
||||
this.bgFn = bgFn;
|
||||
}
|
||||
|
||||
invalidate(): void {
|
||||
for (const child of this.children) {
|
||||
child.invalidate?.();
|
||||
}
|
||||
}
|
||||
|
||||
render(width: number): string[] {
|
||||
if (this.children.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const contentWidth = Math.max(1, width - this.paddingX * 2);
|
||||
const leftPad = " ".repeat(this.paddingX);
|
||||
|
||||
// Render all children
|
||||
const childLines: string[] = [];
|
||||
for (const child of this.children) {
|
||||
const lines = child.render(contentWidth);
|
||||
for (const line of lines) {
|
||||
childLines.push(leftPad + line);
|
||||
}
|
||||
}
|
||||
|
||||
if (childLines.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Apply background and padding
|
||||
const result: string[] = [];
|
||||
|
||||
// Top padding
|
||||
for (let i = 0; i < this.paddingY; i++) {
|
||||
result.push(this.applyBg("", width));
|
||||
}
|
||||
|
||||
// Content
|
||||
for (const line of childLines) {
|
||||
result.push(this.applyBg(line, width));
|
||||
}
|
||||
|
||||
// Bottom padding
|
||||
for (let i = 0; i < this.paddingY; i++) {
|
||||
result.push(this.applyBg("", width));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private applyBg(line: string, width: number): string {
|
||||
const visLen = visibleWidth(line);
|
||||
const padNeeded = Math.max(0, width - visLen);
|
||||
const padded = line + " ".repeat(padNeeded);
|
||||
|
||||
if (this.bgFn) {
|
||||
return applyBackgroundToLine(padded, width, this.bgFn);
|
||||
}
|
||||
return padded;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue