@aiwayds/dsh-tui-pi 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +324 -0
  3. package/bin/dsh-tui-pi +5 -0
  4. package/cordis.patch.yml +9 -0
  5. package/lib/append-system.d.ts +66 -0
  6. package/lib/append-system.js +161 -0
  7. package/lib/append-system.js.map +1 -0
  8. package/lib/commands.d.ts +53 -0
  9. package/lib/commands.js +167 -0
  10. package/lib/commands.js.map +1 -0
  11. package/lib/dsh-events.d.ts +106 -0
  12. package/lib/dsh-events.js +30 -0
  13. package/lib/dsh-events.js.map +1 -0
  14. package/lib/editor.d.ts +28 -0
  15. package/lib/editor.js +70 -0
  16. package/lib/editor.js.map +1 -0
  17. package/lib/footer.d.ts +36 -0
  18. package/lib/footer.js +112 -0
  19. package/lib/footer.js.map +1 -0
  20. package/lib/frame.d.ts +35 -0
  21. package/lib/frame.js +75 -0
  22. package/lib/frame.js.map +1 -0
  23. package/lib/git.d.ts +17 -0
  24. package/lib/git.js +51 -0
  25. package/lib/git.js.map +1 -0
  26. package/lib/index.d.ts +15 -0
  27. package/lib/index.js +781 -0
  28. package/lib/index.js.map +1 -0
  29. package/lib/instructions.d.ts +29 -0
  30. package/lib/instructions.js +67 -0
  31. package/lib/instructions.js.map +1 -0
  32. package/lib/live-widgets.d.ts +85 -0
  33. package/lib/live-widgets.js +218 -0
  34. package/lib/live-widgets.js.map +1 -0
  35. package/lib/messages.d.ts +277 -0
  36. package/lib/messages.js +734 -0
  37. package/lib/messages.js.map +1 -0
  38. package/lib/permission.d.ts +27 -0
  39. package/lib/permission.js +48 -0
  40. package/lib/permission.js.map +1 -0
  41. package/lib/provider-catalog.d.ts +114 -0
  42. package/lib/provider-catalog.js +124 -0
  43. package/lib/provider-catalog.js.map +1 -0
  44. package/lib/quotes.d.ts +28 -0
  45. package/lib/quotes.js +144 -0
  46. package/lib/quotes.js.map +1 -0
  47. package/lib/reload.d.ts +23 -0
  48. package/lib/reload.js +171 -0
  49. package/lib/reload.js.map +1 -0
  50. package/lib/selectors.d.ts +48 -0
  51. package/lib/selectors.js +261 -0
  52. package/lib/selectors.js.map +1 -0
  53. package/lib/session.d.ts +157 -0
  54. package/lib/session.js +555 -0
  55. package/lib/session.js.map +1 -0
  56. package/lib/sessions.d.ts +73 -0
  57. package/lib/sessions.js +253 -0
  58. package/lib/sessions.js.map +1 -0
  59. package/lib/settings.d.ts +180 -0
  60. package/lib/settings.js +1328 -0
  61. package/lib/settings.js.map +1 -0
  62. package/lib/text.d.ts +22 -0
  63. package/lib/text.js +45 -0
  64. package/lib/text.js.map +1 -0
  65. package/lib/theme/index.d.ts +79 -0
  66. package/lib/theme/index.js +121 -0
  67. package/lib/theme/index.js.map +1 -0
  68. package/lib/theme/palette.d.ts +56 -0
  69. package/lib/theme/palette.js +154 -0
  70. package/lib/theme/palette.js.map +1 -0
  71. package/lib/theme-settings.d.ts +68 -0
  72. package/lib/theme-settings.js +223 -0
  73. package/lib/theme-settings.js.map +1 -0
  74. package/lib/tui.d.ts +70 -0
  75. package/lib/tui.js +206 -0
  76. package/lib/tui.js.map +1 -0
  77. package/lib/welcome.d.ts +91 -0
  78. package/lib/welcome.js +281 -0
  79. package/lib/welcome.js.map +1 -0
  80. package/package.json +50 -0
  81. package/patches/@earendil-works__pi-tui.patch +72 -0
  82. package/pnpm-workspace.yaml +2 -0
  83. package/templates/APPEND_SYSTEM.md +34 -0
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Slash-command integration with dsh's own command registry.
3
+ *
4
+ * dsh-tui-pi never re-implements a command: autocomplete lists
5
+ * `ctx.commands.list(agent)` and submission routes through
6
+ * `ctx.commands.execute(agent, line, signal)`. Anything that is not a
7
+ * resolvable command falls through to the model as an ordinary prompt, so
8
+ * every command registered by dsh packages (plan, compact, feedback, export,
9
+ * permission, goal, …) works here unchanged and future registrations appear
10
+ * automatically.
11
+ *
12
+ * One exemption: TUI-owned commands that never touch the receiving agent
13
+ * (model pickers, settings browser, session info/resume) are dispatched
14
+ * locally when no live agent exists — dsh's execute path addresses an agent
15
+ * and would mint a throwaway session just to run them.
16
+ */
17
+ import { parseCommand } from '@deepseek-ai/dsh-commands';
18
+ /**
19
+ * Token ending at the cursor on one editor line, for command detection.
20
+ * Returns the leading slash token when the caret sits inside one.
21
+ */
22
+ function tokenAtCursor(line, cursorCol) {
23
+ const upto = line.slice(0, cursorCol);
24
+ const match = /(^|\s)\/([a-z][a-z0-9_-]*)?$/u.exec(upto);
25
+ if (match === null)
26
+ return undefined;
27
+ const start = match.index + (match[1] ?? '').length;
28
+ return { token: upto.slice(start), start };
29
+ }
30
+ export class CommandService {
31
+ ctx;
32
+ bridge;
33
+ /** TUI-owned command bodies, dispatchable without a live agent. */
34
+ local = new Map();
35
+ constructor(ctx, bridge) {
36
+ this.ctx = ctx;
37
+ this.bridge = bridge;
38
+ }
39
+ /**
40
+ * Register a local command body (the same handler the ctx.commands
41
+ * registration wraps). It is dispatched directly when no live agent
42
+ * exists, avoiding a throwaway session for agentless commands.
43
+ */
44
+ registerLocal(name, handler) {
45
+ this.local.set(name, handler);
46
+ }
47
+ /**
48
+ * Try to run `line` as a dsh slash command.
49
+ * @returns `handled: true` when the line was admitted as a command (the
50
+ * caller must not forward it to the model), with an optional `error` or
51
+ * success `text` to surface; `handled: false` when it is not a command.
52
+ */
53
+ async tryExecute(line, signal) {
54
+ const parsed = parseCommand(line);
55
+ if (parsed === undefined)
56
+ return { handled: false };
57
+ const commands = this.ctx.get('commands');
58
+ if (commands === undefined)
59
+ return { handled: false };
60
+ // Agentless local commands never warm the session — /resume or /session
61
+ // on a fresh TUI must not mint a session just to run.
62
+ const localHandler = this.local.get(parsed.name);
63
+ if (localHandler !== undefined && this.bridge.getAgent() === undefined) {
64
+ try {
65
+ const result = await localHandler(parsed.rawInput, signal);
66
+ if (result.kind === 'error')
67
+ return { handled: true, error: result.text };
68
+ return { handled: true, ...result.text === undefined ? {} : { text: result.text } };
69
+ }
70
+ catch (error) {
71
+ const message = error instanceof Error ? error.message : String(error);
72
+ return { handled: true, error: message };
73
+ }
74
+ }
75
+ // Commands address a live agent; warm the session when it does not exist.
76
+ let agent;
77
+ try {
78
+ agent = await this.bridge.ensureAgent();
79
+ }
80
+ catch (error) {
81
+ // Warm-up failed (e.g. provider not configured) — surface instead of
82
+ // rejecting into an unhandled promise rejection.
83
+ const message = error instanceof Error ? error.message : String(error);
84
+ return { handled: true, error: message };
85
+ }
86
+ if (commands.find(agent, parsed.name) === undefined) {
87
+ // Syntactically a command but unregistered → treat as ordinary text so
88
+ // the model still sees it (matches "unknown command" falling through).
89
+ return { handled: false };
90
+ }
91
+ try {
92
+ const execution = await commands.execute(agent, line, signal);
93
+ if (execution === undefined)
94
+ return { handled: false };
95
+ if (execution.result.kind === 'error')
96
+ return { handled: true, error: execution.result.text };
97
+ return { handled: true, ...execution.result.text === undefined ? {} : { text: execution.result.text } };
98
+ }
99
+ catch (error) {
100
+ const message = error instanceof Error ? error.message : String(error);
101
+ return { handled: true, error: message };
102
+ }
103
+ }
104
+ /**
105
+ * Effective command descriptors for the current agent. Warms the session on
106
+ * first use so `/` autocompletes before any prompt was sent.
107
+ */
108
+ async list() {
109
+ const commands = this.ctx.get('commands');
110
+ if (commands === undefined)
111
+ return [];
112
+ try {
113
+ const agent = await this.bridge.ensureAgent();
114
+ return commands.list(agent);
115
+ }
116
+ catch {
117
+ // Session warm-up failed (e.g. provider not configured) — no completions.
118
+ return [];
119
+ }
120
+ }
121
+ /** pi-tui autocomplete provider over the live command registry. */
122
+ autocompleteProvider() {
123
+ return {
124
+ triggerCharacters: ['/'],
125
+ getSuggestions: async (lines, cursorLine, cursorCol, options) => {
126
+ const line = lines[cursorLine] ?? '';
127
+ const at = tokenAtCursor(line, cursorCol);
128
+ if (at === undefined)
129
+ return null;
130
+ // Only complete the command name itself (leading token, no arguments yet).
131
+ if (at.start !== 0 && line.slice(0, at.start).trim() !== '')
132
+ return null;
133
+ const descriptors = await this.list();
134
+ if (descriptors.length === 0)
135
+ return null;
136
+ const query = at.token.slice(1).toLowerCase();
137
+ const items = descriptors
138
+ .filter(d => query === '' || d.name.toLowerCase().startsWith(query))
139
+ .map(d => ({
140
+ value: `/${d.name}`,
141
+ label: `/${d.name}`,
142
+ description: d.description,
143
+ }));
144
+ if (items.length === 0)
145
+ return null;
146
+ return { items, prefix: at.token };
147
+ },
148
+ applyCompletion: (lines, cursorLine, cursorCol, item, prefix) => {
149
+ const line = lines[cursorLine] ?? '';
150
+ const at = tokenAtCursor(line, cursorCol);
151
+ if (at === undefined)
152
+ return { lines, cursorLine, cursorCol };
153
+ const before = line.slice(0, at.start);
154
+ const after = line.slice(cursorCol);
155
+ const completed = `${before}${item.value} ${after}`;
156
+ const nextLines = lines.slice();
157
+ nextLines[cursorLine] = completed;
158
+ return {
159
+ lines: nextLines,
160
+ cursorLine,
161
+ cursorCol: before.length + item.value.length + 1,
162
+ };
163
+ },
164
+ };
165
+ }
166
+ }
167
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Local structural types for session events whose declaring packages
3
+ * (`@deepseek-ai/dsh-tool-workflow`, `@deepseek-ai/dsh-subagent`,
4
+ * `@deepseek-ai/dsh-llm-retry`) are not installed in this plugin. The TUI
5
+ * receives these events on the `session/event` firehose regardless (the
6
+ * firehose is not scope-filtered — see dsh-scope's generated subject
7
+ * resolvers), so the bridge folds them through these minimal, dependency-free
8
+ * shapes instead of importing the augmenting packages.
9
+ *
10
+ * `SessionEvent` is a closed discriminated union over the core event map, so
11
+ * `switch (event.type)` falls through these types; the guards narrow them
12
+ * explicitly.
13
+ */
14
+ import type { SessionEvent } from '@deepseek-ai/dsh-session';
15
+ declare module '@deepseek-ai/dsh-session' {
16
+ interface SessionEventMap {
17
+ 'tool-workflow/agent-start': ToolWorkflowAgentStartData;
18
+ 'tool-workflow/agent-end': ToolWorkflowAgentEndData;
19
+ 'subagent/descriptor': SubagentDescriptorData;
20
+ 'llm/retry': LlmRetryData;
21
+ }
22
+ }
23
+ /** `tool-workflow/agent-start`: one workflow member, after its child Session is published. */
24
+ export interface ToolWorkflowAgentStartData {
25
+ readonly runId: string;
26
+ readonly seq: number;
27
+ readonly label: string;
28
+ readonly phase?: string;
29
+ readonly childId: string;
30
+ }
31
+ /** `tool-workflow/agent-end`: one workflow member settlement. */
32
+ export interface ToolWorkflowAgentEndData {
33
+ readonly runId: string;
34
+ readonly seq: number;
35
+ readonly outcome: 'completed' | 'failed' | 'cancelled';
36
+ }
37
+ /** `subagent/descriptor`: durable identity of a session-backed subagent child. */
38
+ export interface SubagentDescriptorData {
39
+ readonly version: number;
40
+ readonly mode: 'one-shot' | 'continuable';
41
+ readonly provider: string;
42
+ readonly label?: string;
43
+ }
44
+ /** `llm/retry`: one provider-routed retry scheduled after a failed request attempt. */
45
+ export interface LlmRetryData {
46
+ readonly retry: number;
47
+ /** Absent for the `mode: 'always'` arm of the real event. */
48
+ readonly maxRetries?: number;
49
+ }
50
+ /** Type guard for `tool-workflow/agent-start` events. */
51
+ export declare function isAgentStart(event: SessionEvent): event is SessionEvent & {
52
+ type: 'tool-workflow/agent-start';
53
+ data: ToolWorkflowAgentStartData;
54
+ };
55
+ /** Type guard for `tool-workflow/agent-end` events. */
56
+ export declare function isAgentEnd(event: SessionEvent): event is SessionEvent & {
57
+ type: 'tool-workflow/agent-end';
58
+ data: ToolWorkflowAgentEndData;
59
+ };
60
+ /** Type guard for `subagent/descriptor` events (written to the CHILD session's log). */
61
+ export declare function isSubagentDescriptor(event: SessionEvent): event is SessionEvent & {
62
+ type: 'subagent/descriptor';
63
+ data: SubagentDescriptorData;
64
+ };
65
+ /** Type guard for `llm/retry` events. */
66
+ export declare function isLlmRetry(event: SessionEvent): event is SessionEvent & {
67
+ type: 'llm/retry';
68
+ data: LlmRetryData;
69
+ };
70
+ /**
71
+ * One live subagent row the TUI renders: the bridge's per-child fold of
72
+ * workflow events (parent log) and the child's own session events. Children
73
+ * are keyed by their session id — discovered either from
74
+ * `tool-workflow/agent-start` or, when the deployment never emits workflow
75
+ * events, from the child session's header (`origin: 'subagent'` +
76
+ * `parentSession`). All fields are O(1)-maintained — never a session-log
77
+ * scan on the render path.
78
+ */
79
+ export interface AgentView {
80
+ /** The child session id (raw string) — the stable identity key. */
81
+ readonly childId: string;
82
+ /** Subagent type name from the child's `subagent/descriptor.provider`, when known. */
83
+ readonly provider?: string;
84
+ /** Delegation label from `tool-workflow/agent-start` or the child's descriptor. */
85
+ readonly label: string;
86
+ /** Unix epoch ms when the child was first observed — the elapsed baseline. */
87
+ readonly startedAt: number;
88
+ /**
89
+ * Settled marker: set by `tool-workflow/agent-end` (real outcome) or,
90
+ * for header-discovered children, best-effort on the child's `turn/end`.
91
+ * A settled child drops off the live board (clear-when-done).
92
+ */
93
+ readonly outcome?: 'completed' | 'failed' | 'cancelled';
94
+ /** Unix epoch ms of the settle event, when settled. */
95
+ readonly endedAt?: number;
96
+ /** Cumulative tokens: input + output + cacheRead + cacheWrite. */
97
+ readonly tokens: number;
98
+ /** Latest `llm/retry` attempt number (0 = none retried). */
99
+ readonly retries: number;
100
+ /** Latest `llm/retry` maxRetries, when the policy reported one. */
101
+ readonly maxRetries?: number;
102
+ /** Last tool name the child invoked (the activity line), when any. */
103
+ readonly lastTool?: string;
104
+ /** Context window from the child's `request/context`, for the % column. */
105
+ readonly contextWindow?: number;
106
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Local structural types for session events whose declaring packages
3
+ * (`@deepseek-ai/dsh-tool-workflow`, `@deepseek-ai/dsh-subagent`,
4
+ * `@deepseek-ai/dsh-llm-retry`) are not installed in this plugin. The TUI
5
+ * receives these events on the `session/event` firehose regardless (the
6
+ * firehose is not scope-filtered — see dsh-scope's generated subject
7
+ * resolvers), so the bridge folds them through these minimal, dependency-free
8
+ * shapes instead of importing the augmenting packages.
9
+ *
10
+ * `SessionEvent` is a closed discriminated union over the core event map, so
11
+ * `switch (event.type)` falls through these types; the guards narrow them
12
+ * explicitly.
13
+ */
14
+ /** Type guard for `tool-workflow/agent-start` events. */
15
+ export function isAgentStart(event) {
16
+ return event.type === 'tool-workflow/agent-start';
17
+ }
18
+ /** Type guard for `tool-workflow/agent-end` events. */
19
+ export function isAgentEnd(event) {
20
+ return event.type === 'tool-workflow/agent-end';
21
+ }
22
+ /** Type guard for `subagent/descriptor` events (written to the CHILD session's log). */
23
+ export function isSubagentDescriptor(event) {
24
+ return event.type === 'subagent/descriptor';
25
+ }
26
+ /** Type guard for `llm/retry` events. */
27
+ export function isLlmRetry(event) {
28
+ return event.type === 'llm/retry';
29
+ }
30
+ //# sourceMappingURL=dsh-events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dsh-events.js","sourceRoot":"","sources":["../src/dsh-events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAqDH,yDAAyD;AACzD,MAAM,UAAU,YAAY,CAAC,KAAmB;IAC9C,OAAO,KAAK,CAAC,IAAI,KAAK,2BAA2B,CAAA;AACnD,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,UAAU,CAAC,KAAmB;IAC5C,OAAO,KAAK,CAAC,IAAI,KAAK,yBAAyB,CAAA;AACjD,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,oBAAoB,CAAC,KAAmB;IACtD,OAAO,KAAK,CAAC,IAAI,KAAK,qBAAqB,CAAA;AAC7C,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,UAAU,CAAC,KAAmB;IAC5C,OAAO,KAAK,CAAC,IAAI,KAAK,WAAW,CAAA;AACnC,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Custom editor that replaces the input's TOP BORDER row with a plain-text
3
+ * info line: cwd + permission badge + git branch (separator "│"), in border
4
+ * color only (no powerline background segments). Ported from
5
+ * pi-powerline-footer's CwdBorderEditor; every other editor row is left
6
+ * untouched.
7
+ */
8
+ import { Editor, type EditorTheme, type TUI } from '@earendil-works/pi-tui';
9
+ /** Shorten the cwd by replacing the HOME prefix with `~`. */
10
+ export declare function formatCwd(cwd: string): string;
11
+ export declare class CwdBorderEditor extends Editor {
12
+ private readonly sessionCwd;
13
+ private readonly infoColor;
14
+ private branchProvider;
15
+ private permissionProvider;
16
+ constructor(tui: TUI, theme: EditorTheme, sessionCwd: string, options?: {
17
+ paddingX?: number;
18
+ infoColor?: (str: string) => string;
19
+ });
20
+ /** Live git-branch source (polled outside; the editor only reads it). */
21
+ setBranchProvider(provider: () => string | undefined): void;
22
+ /**
23
+ * Live permission-preset display-name source (e.g. "Full access") — the
24
+ * badge shown right after the cwd; polled outside, the editor only reads it.
25
+ */
26
+ setPermissionProvider(provider: () => string | undefined): void;
27
+ render(width: number): string[];
28
+ }
package/lib/editor.js ADDED
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Custom editor that replaces the input's TOP BORDER row with a plain-text
3
+ * info line: cwd + permission badge + git branch (separator "│"), in border
4
+ * color only (no powerline background segments). Ported from
5
+ * pi-powerline-footer's CwdBorderEditor; every other editor row is left
6
+ * untouched.
7
+ */
8
+ import { Editor, truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';
9
+ /** Shorten the cwd by replacing the HOME prefix with `~`. */
10
+ export function formatCwd(cwd) {
11
+ const home = process.env.HOME;
12
+ if (home !== undefined && cwd.startsWith(home)) {
13
+ return `~${cwd.slice(home.length)}`;
14
+ }
15
+ return cwd;
16
+ }
17
+ export class CwdBorderEditor extends Editor {
18
+ sessionCwd;
19
+ infoColor;
20
+ branchProvider = () => undefined;
21
+ permissionProvider = () => undefined;
22
+ constructor(tui, theme, sessionCwd, options) {
23
+ super(tui, theme, { paddingX: options?.paddingX ?? 0 });
24
+ this.sessionCwd = sessionCwd;
25
+ // The border dashes stay border-colored, but the cwd/branch info needs a
26
+ // readable foreground (border color is near-invisible on light themes).
27
+ this.infoColor = options?.infoColor ?? theme.borderColor;
28
+ }
29
+ /** Live git-branch source (polled outside; the editor only reads it). */
30
+ setBranchProvider(provider) {
31
+ this.branchProvider = provider;
32
+ }
33
+ /**
34
+ * Live permission-preset display-name source (e.g. "Full access") — the
35
+ * badge shown right after the cwd; polled outside, the editor only reads it.
36
+ */
37
+ setPermissionProvider(provider) {
38
+ this.permissionProvider = provider;
39
+ }
40
+ render(width) {
41
+ const lines = super.render(width);
42
+ if (lines.length < 2 || width < 3)
43
+ return lines;
44
+ // When scrolled, the built-in top border row is a scroll indicator
45
+ // ("─── ↑ N more ─…"); preserve that feedback by appending ↑ N.
46
+ const firstLine = lines[0] ?? '';
47
+ const scrollMatch = /↑\s*(\d+)/u.exec(firstLine);
48
+ const scrollInfo = scrollMatch === null ? '' : ` ↑ ${scrollMatch[1]}`;
49
+ const permission = this.permissionProvider();
50
+ const parts = [
51
+ `📁 ${formatCwd(this.sessionCwd)}` +
52
+ (permission !== undefined && permission !== '' ? ` (${permission})` : ''),
53
+ ];
54
+ const branch = this.branchProvider();
55
+ if (branch !== undefined && branch !== '')
56
+ parts.push(`⎇ ${branch}`);
57
+ const content = parts.join(' │ ') + scrollInfo;
58
+ // Reserve 3 fixed columns: "─ " prefix (2) + " " suffix (1).
59
+ const maxContent = Math.max(0, width - 3);
60
+ const contentText = truncateToWidth(content, maxContent, '…');
61
+ const fill = Math.max(0, width - 3 - visibleWidth(contentText));
62
+ lines[0] =
63
+ this.borderColor('─ ') +
64
+ this.infoColor(contentText) +
65
+ this.borderColor(' ') +
66
+ this.borderColor('─'.repeat(fill));
67
+ return lines;
68
+ }
69
+ }
70
+ //# sourceMappingURL=editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor.js","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Powerline-style status footer, ported from pi-powerline-footer.
3
+ *
4
+ * Segments (left → right): fixed brand "dsh" · provider · model+thinking ·
5
+ * context usage · cache-hit rate · message count · tool count, then a
6
+ * right-aligned 24h clock. Segment backgrounds are the pi-powerline-footer
7
+ * palette; separators are U+E0B0 powerline arrows tinted by the neighbouring
8
+ * segment colours.
9
+ *
10
+ * Render cost is O(segments): every statistic is read from the bridge's
11
+ * incrementally maintained counters (never a session-log scan). The 1s clock
12
+ * tick only re-renders this component's single line.
13
+ */
14
+ import { type Component } from '@earendil-works/pi-tui';
15
+ import type { BridgeStats } from './session.ts';
16
+ export interface FooterDataSource {
17
+ /** O(1) incremental counters. */
18
+ getStats(): BridgeStats;
19
+ /** Current model selection (provider, model, reasoning effort). */
20
+ getSelection(): {
21
+ provider: string;
22
+ model: string;
23
+ reasoningEffort?: string;
24
+ } | undefined;
25
+ /** Model context window in tokens, when known. */
26
+ getContextWindow(): number | undefined;
27
+ /** Git branch of the session cwd, when known. */
28
+ getBranch(): string | undefined;
29
+ }
30
+ export declare function fmtNum(n: number): string;
31
+ export declare class PowerlineFooter implements Component {
32
+ private readonly source;
33
+ constructor(source: FooterDataSource);
34
+ invalidate(): void;
35
+ render(width: number): string[];
36
+ }
package/lib/footer.js ADDED
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Powerline-style status footer, ported from pi-powerline-footer.
3
+ *
4
+ * Segments (left → right): fixed brand "dsh" · provider · model+thinking ·
5
+ * context usage · cache-hit rate · message count · tool count, then a
6
+ * right-aligned 24h clock. Segment backgrounds are the pi-powerline-footer
7
+ * palette; separators are U+E0B0 powerline arrows tinted by the neighbouring
8
+ * segment colours.
9
+ *
10
+ * Render cost is O(segments): every statistic is read from the bridge's
11
+ * incrementally maintained counters (never a session-log scan). The 1s clock
12
+ * tick only re-renders this component's single line.
13
+ */
14
+ import { truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';
15
+ import { ansiBg, ansiFg, BOLD, POWERLINE, RESET } from "./theme/index.js";
16
+ import { clipToWidth } from "./text.js";
17
+ const ARROW_RIGHT = '\uE0B0';
18
+ const WHITE = ansiFg('#FFFFFF');
19
+ export function fmtNum(n) {
20
+ if (n >= 1_000_000)
21
+ return `${(n / 1_000_000).toFixed(1)}M`;
22
+ if (n >= 1000)
23
+ return `${(n / 1000).toFixed(1)}k`;
24
+ return `${n}`;
25
+ }
26
+ function buildSegments(segs) {
27
+ if (segs.length === 0)
28
+ return '';
29
+ let out = '';
30
+ for (let i = 0; i < segs.length; i++) {
31
+ const s = segs[i];
32
+ out += `${ansiBg(s.bgHex)}${BOLD}${WHITE} ${s.label} `;
33
+ if (i + 1 < segs.length) {
34
+ out += `${ansiBg(segs[i + 1].bgHex)}${ansiFg(s.bgHex)}${ARROW_RIGHT}`;
35
+ }
36
+ else {
37
+ out += RESET + ansiFg(s.bgHex) + ARROW_RIGHT + RESET;
38
+ }
39
+ }
40
+ return out;
41
+ }
42
+ /** Thinking-level → segment background (pi-powerline-footer mapping). */
43
+ function thinkingBg(level) {
44
+ const key = (level ?? 'off');
45
+ return POWERLINE.thinking[key] ?? POWERLINE.thinking.off;
46
+ }
47
+ function thinkingIcon(level) {
48
+ switch (level ?? 'off') {
49
+ case 'minimal': return '◔';
50
+ case 'low': return '◑';
51
+ case 'medium': return '◕';
52
+ case 'high': return '●';
53
+ case 'xhigh': return '◉';
54
+ case 'max': return '★';
55
+ default: return '○';
56
+ }
57
+ }
58
+ function contextBg(percent) {
59
+ if (percent >= 90)
60
+ return POWERLINE.contextDanger;
61
+ if (percent >= 70)
62
+ return POWERLINE.contextOrange;
63
+ if (percent >= 50)
64
+ return POWERLINE.contextWarn;
65
+ return POWERLINE.contextOk;
66
+ }
67
+ export class PowerlineFooter {
68
+ source;
69
+ constructor(source) {
70
+ this.source = source;
71
+ }
72
+ invalidate() { }
73
+ render(width) {
74
+ const stats = this.source.getStats();
75
+ const selection = this.source.getSelection();
76
+ const segs = [{ label: 'dsh', bgHex: POWERLINE.brand }];
77
+ if (selection !== undefined) {
78
+ segs.push({ label: `☁️ ${selection.provider}`, bgHex: POWERLINE.provider });
79
+ const model = clipToWidth(selection.model.split('/').pop(), 24);
80
+ const effort = selection.reasoningEffort ?? 'off';
81
+ segs.push({
82
+ label: `🤖 ${model} ${thinkingIcon(effort)} ${effort}`,
83
+ bgHex: thinkingBg(effort),
84
+ });
85
+ }
86
+ // Context usage: latest request's input tokens vs. the model's window.
87
+ const window = this.source.getContextWindow();
88
+ const used = stats.inputTokens;
89
+ if (window !== undefined && window > 0) {
90
+ const percent = (used / window) * 100;
91
+ segs.push({
92
+ label: `🧠 ${fmtNum(used)}/${fmtNum(window)}(${percent.toFixed(1)}%)`,
93
+ bgHex: contextBg(percent),
94
+ });
95
+ }
96
+ else {
97
+ segs.push({ label: `🧠 ${fmtNum(used)}`, bgHex: POWERLINE.contextOk });
98
+ }
99
+ if ((stats.cacheReadTokens > 0 || stats.cacheWriteTokens > 0) && stats.cacheHitRate !== undefined) {
100
+ segs.push({ label: `⚡ CH${stats.cacheHitRate.toFixed(1)}%`, bgHex: POWERLINE.cache });
101
+ }
102
+ segs.push({ label: `💬 ${stats.msgCount} msgs`, bgHex: POWERLINE.messages });
103
+ segs.push({ label: `🔧 ${stats.toolCallCount} tools`, bgHex: POWERLINE.tools });
104
+ const left = buildSegments(segs);
105
+ const leftWidth = visibleWidth(left);
106
+ const clock = new Date().toLocaleTimeString('en-GB', { hour12: false });
107
+ const clockWidth = visibleWidth(clock);
108
+ const pad = Math.max(1, width - leftWidth - clockWidth);
109
+ return [truncateToWidth(left + ' '.repeat(pad) + clock, width)];
110
+ }
111
+ }
112
+ //# sourceMappingURL=footer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"footer.js","sourceRoot":"","sources":["../src/footer.ts"],"names":[],"mappings":"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"}
package/lib/frame.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Framed overlay chrome — the shared full box (`┌─┐`) every pi SelectList /
3
+ * SettingsList overlay gets, so a popup reads as one bounded surface instead
4
+ * of panel rows floating directly on the chat canvas.
5
+ *
6
+ * Replaces pi agent's DynamicBorder (bare `─` lines) with a complete box:
7
+ * `┌───┐` top, `│ │` side-bordered content rows, `└───┘` bottom. Width
8
+ * passed to `showOverlay` is unchanged — the box is self-contained within it
9
+ * (child renders at width − 2).
10
+ *
11
+ * The frame also paints the panel backdrop: every row (borders, spacers, and
12
+ * each child line — including the raw separator/search rows pi's SettingsList
13
+ * pushes without any theme call) is laid on a full-width canvasSubtle
14
+ * background, so the popup reads as one solid rectangle instead of stripes
15
+ * of text-width highlight.
16
+ */
17
+ import type { Component } from '@earendil-works/pi-tui';
18
+ import { type TuiTheme } from './theme/index.ts';
19
+ /**
20
+ * Full-box wrapper for one overlay component: `┌─┐` top border, `│`-bordered
21
+ * content rows, `└─┘` bottom border — each with a blank spacer row inside
22
+ * the box for breathing room, colored `palette.borderDefault` on the panel's
23
+ * canvasSubtle backdrop. Every row spans the full overlay width on that
24
+ * backdrop (see fillLine); the child renders at width − 2.
25
+ */
26
+ export declare class FramedOverlay implements Component {
27
+ private readonly theme;
28
+ private readonly child;
29
+ constructor(theme: TuiTheme, child: Component);
30
+ invalidate(): void;
31
+ render(width: number): string[];
32
+ handleInput(data: string): void;
33
+ }
34
+ /** Build the framed wrapper for `child` (see FramedOverlay). */
35
+ export declare function wrapFramedOverlay(theme: TuiTheme, child: Component): Component;