@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.
- package/LICENSE +21 -0
- package/README.md +324 -0
- package/bin/dsh-tui-pi +5 -0
- package/cordis.patch.yml +9 -0
- package/lib/append-system.d.ts +66 -0
- package/lib/append-system.js +161 -0
- package/lib/append-system.js.map +1 -0
- package/lib/commands.d.ts +53 -0
- package/lib/commands.js +167 -0
- package/lib/commands.js.map +1 -0
- package/lib/dsh-events.d.ts +106 -0
- package/lib/dsh-events.js +30 -0
- package/lib/dsh-events.js.map +1 -0
- package/lib/editor.d.ts +28 -0
- package/lib/editor.js +70 -0
- package/lib/editor.js.map +1 -0
- package/lib/footer.d.ts +36 -0
- package/lib/footer.js +112 -0
- package/lib/footer.js.map +1 -0
- package/lib/frame.d.ts +35 -0
- package/lib/frame.js +75 -0
- package/lib/frame.js.map +1 -0
- package/lib/git.d.ts +17 -0
- package/lib/git.js +51 -0
- package/lib/git.js.map +1 -0
- package/lib/index.d.ts +15 -0
- package/lib/index.js +781 -0
- package/lib/index.js.map +1 -0
- package/lib/instructions.d.ts +29 -0
- package/lib/instructions.js +67 -0
- package/lib/instructions.js.map +1 -0
- package/lib/live-widgets.d.ts +85 -0
- package/lib/live-widgets.js +218 -0
- package/lib/live-widgets.js.map +1 -0
- package/lib/messages.d.ts +277 -0
- package/lib/messages.js +734 -0
- package/lib/messages.js.map +1 -0
- package/lib/permission.d.ts +27 -0
- package/lib/permission.js +48 -0
- package/lib/permission.js.map +1 -0
- package/lib/provider-catalog.d.ts +114 -0
- package/lib/provider-catalog.js +124 -0
- package/lib/provider-catalog.js.map +1 -0
- package/lib/quotes.d.ts +28 -0
- package/lib/quotes.js +144 -0
- package/lib/quotes.js.map +1 -0
- package/lib/reload.d.ts +23 -0
- package/lib/reload.js +171 -0
- package/lib/reload.js.map +1 -0
- package/lib/selectors.d.ts +48 -0
- package/lib/selectors.js +261 -0
- package/lib/selectors.js.map +1 -0
- package/lib/session.d.ts +157 -0
- package/lib/session.js +555 -0
- package/lib/session.js.map +1 -0
- package/lib/sessions.d.ts +73 -0
- package/lib/sessions.js +253 -0
- package/lib/sessions.js.map +1 -0
- package/lib/settings.d.ts +180 -0
- package/lib/settings.js +1328 -0
- package/lib/settings.js.map +1 -0
- package/lib/text.d.ts +22 -0
- package/lib/text.js +45 -0
- package/lib/text.js.map +1 -0
- package/lib/theme/index.d.ts +79 -0
- package/lib/theme/index.js +121 -0
- package/lib/theme/index.js.map +1 -0
- package/lib/theme/palette.d.ts +56 -0
- package/lib/theme/palette.js +154 -0
- package/lib/theme/palette.js.map +1 -0
- package/lib/theme-settings.d.ts +68 -0
- package/lib/theme-settings.js +223 -0
- package/lib/theme-settings.js.map +1 -0
- package/lib/tui.d.ts +70 -0
- package/lib/tui.js +206 -0
- package/lib/tui.js.map +1 -0
- package/lib/welcome.d.ts +91 -0
- package/lib/welcome.js +281 -0
- package/lib/welcome.js.map +1 -0
- package/package.json +50 -0
- package/patches/@earendil-works__pi-tui.patch +72 -0
- package/pnpm-workspace.yaml +2 -0
- package/templates/APPEND_SYSTEM.md +34 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme settings: persists the user's theme preference and the think/tool
|
|
3
|
+
* panel height under the `dsh-tui` settings namespace, surfaced by the
|
|
4
|
+
* /settings browser and the /theme command. The preferences are read once at
|
|
5
|
+
* TUI startup (`readThemePreference` / `readPanelHeightPreference`), and the
|
|
6
|
+
* namespace is marked `applies: 'live'`: a committed change (the /theme
|
|
7
|
+
* picker, the /settings browser, an external edit) is pushed through the
|
|
8
|
+
* watch hook, so the running TUI repaints without a restart.
|
|
9
|
+
*/
|
|
10
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
11
|
+
import { type SettingsNamespace } from '@deepseek-ai/dsh-settings';
|
|
12
|
+
import { type PanelHeight } from './messages.ts';
|
|
13
|
+
import type { ThemePreference } from './theme/index.ts';
|
|
14
|
+
/** Settings namespace carrying the persisted dsh-tui preferences. */
|
|
15
|
+
export declare const THEME_SETTINGS_NAMESPACE: SettingsNamespace;
|
|
16
|
+
/**
|
|
17
|
+
* Register the `dsh-tui` settings namespace with the settings provider.
|
|
18
|
+
*
|
|
19
|
+
* `installSettingsSection` cannot express the `applies` marker (its hooks
|
|
20
|
+
* carry no options, and the registration's applies is fixed at `register`
|
|
21
|
+
* time), so this registers directly through the provider, mirroring that
|
|
22
|
+
* helper's wiring: the registration rides the scoped injection fiber and
|
|
23
|
+
* disappears with the settings service. `onPreferenceChange`, when given,
|
|
24
|
+
* receives every committed change (including this TUI's own writes) through
|
|
25
|
+
* the scope's watch hook; callers guard re-applies by theme-bundle identity
|
|
26
|
+
* and height change, so an echoed self-write is a no-op. No source thunk is
|
|
27
|
+
* needed — the read helpers read the resolved values on demand at TUI
|
|
28
|
+
* startup.
|
|
29
|
+
*
|
|
30
|
+
* @param ctx - plugin context; does nothing while no settings service is mounted.
|
|
31
|
+
* @param onPreferenceChange - hot-reload sink for committed `dsh-tui` theme
|
|
32
|
+
* and panel-height changes; `undefined` when the namespace is already
|
|
33
|
+
* registered (a reloaded plugin instance, a second mount of this bundle) or
|
|
34
|
+
* registration fails.
|
|
35
|
+
*/
|
|
36
|
+
export declare function registerThemeSettings(ctx: Context, onPreferenceChange?: (pref: ThemePreference, panelHeight: PanelHeight) => void): void;
|
|
37
|
+
/**
|
|
38
|
+
* Read the persisted theme preference (the startup snapshot).
|
|
39
|
+
*
|
|
40
|
+
* @param ctx - plugin context.
|
|
41
|
+
* @returns the resolved `dsh-tui` theme value, or `'auto'` when the settings
|
|
42
|
+
* service is absent or the namespace/value cannot be read.
|
|
43
|
+
*/
|
|
44
|
+
export declare function readThemePreference(ctx: Context): Promise<ThemePreference>;
|
|
45
|
+
/**
|
|
46
|
+
* Read the persisted think/tool panel height (the startup snapshot).
|
|
47
|
+
*
|
|
48
|
+
* @param ctx - plugin context.
|
|
49
|
+
* @returns the resolved `dsh-tui` panelHeight value, or DEFAULT_PANEL_HEIGHT
|
|
50
|
+
* when the settings service is absent or the namespace/value cannot be read.
|
|
51
|
+
*/
|
|
52
|
+
export declare function readPanelHeightPreference(ctx: Context): Promise<PanelHeight>;
|
|
53
|
+
/**
|
|
54
|
+
* Read the currently persisted theme preference, synchronously.
|
|
55
|
+
* Unlike `readThemePreference` (the startup snapshot), this does not wait for
|
|
56
|
+
* the namespace registration — it describes whatever the settings service
|
|
57
|
+
* exposes right now, so the `/theme` picker preselects the live value, which
|
|
58
|
+
* may have changed since startup (e.g. through the /settings browser).
|
|
59
|
+
* @returns 'auto' when the service, namespace, or value cannot be read.
|
|
60
|
+
*/
|
|
61
|
+
export declare function currentThemePreference(ctx: Context): ThemePreference;
|
|
62
|
+
/**
|
|
63
|
+
* Persist the theme preference to the `dsh-tui` settings namespace. The
|
|
64
|
+
* namespace is `applies: 'live'`, so the commit (observed through the
|
|
65
|
+
* registration's watch hook) hot-applies the change to the running TUI.
|
|
66
|
+
* @returns undefined on success, the failure message otherwise.
|
|
67
|
+
*/
|
|
68
|
+
export declare function writeThemePreference(ctx: Context, pref: ThemePreference): Promise<string | undefined>;
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme settings: persists the user's theme preference and the think/tool
|
|
3
|
+
* panel height under the `dsh-tui` settings namespace, surfaced by the
|
|
4
|
+
* /settings browser and the /theme command. The preferences are read once at
|
|
5
|
+
* TUI startup (`readThemePreference` / `readPanelHeightPreference`), and the
|
|
6
|
+
* namespace is marked `applies: 'live'`: a committed change (the /theme
|
|
7
|
+
* picker, the /settings browser, an external edit) is pushed through the
|
|
8
|
+
* watch hook, so the running TUI repaints without a restart.
|
|
9
|
+
*/
|
|
10
|
+
import { SettingsConflictError, settingsNamespace, } from '@deepseek-ai/dsh-settings';
|
|
11
|
+
import z from '@deepseek-ai/schemastery';
|
|
12
|
+
import { DEFAULT_PANEL_HEIGHT } from "./messages.js";
|
|
13
|
+
/** Settings namespace carrying the persisted dsh-tui preferences. */
|
|
14
|
+
export const THEME_SETTINGS_NAMESPACE = settingsNamespace('dsh-tui');
|
|
15
|
+
/** Schema of the `dsh-tui` settings section. */
|
|
16
|
+
const THEME_SETTINGS_SCHEMA = z.object({
|
|
17
|
+
theme: z
|
|
18
|
+
.union(['auto', 'light', 'dark'])
|
|
19
|
+
.default('auto')
|
|
20
|
+
.description('Terminal color scheme (applies immediately)'),
|
|
21
|
+
panelHeight: z
|
|
22
|
+
.union(['5', '7', '10', 'all'])
|
|
23
|
+
.default(DEFAULT_PANEL_HEIGHT)
|
|
24
|
+
.description("Think/tool panel height in displayed rows ('5'/'7'/'10' — header + content lines; "
|
|
25
|
+
+ "box borders add 2 more) or 'all' to print the full content — a streaming "
|
|
26
|
+
+ 'reasoning panel shows a 200-line live tail and tool results cap at 2000 lines'),
|
|
27
|
+
});
|
|
28
|
+
/** Composition entry below the user layer: fall back to the defaults. */
|
|
29
|
+
const THEME_SETTINGS_ENTRY = {
|
|
30
|
+
theme: 'auto',
|
|
31
|
+
panelHeight: DEFAULT_PANEL_HEIGHT,
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* In-flight namespace registration. The registration rides the settings
|
|
35
|
+
* injection fiber, so a read issued right after `registerThemeSettings`
|
|
36
|
+
* would not see the namespace yet; `readThemePreference` awaits this promise
|
|
37
|
+
* (bounded) before describing. `undefined` until the first registration.
|
|
38
|
+
*/
|
|
39
|
+
let registrationPromise;
|
|
40
|
+
/**
|
|
41
|
+
* Register the `dsh-tui` settings namespace with the settings provider.
|
|
42
|
+
*
|
|
43
|
+
* `installSettingsSection` cannot express the `applies` marker (its hooks
|
|
44
|
+
* carry no options, and the registration's applies is fixed at `register`
|
|
45
|
+
* time), so this registers directly through the provider, mirroring that
|
|
46
|
+
* helper's wiring: the registration rides the scoped injection fiber and
|
|
47
|
+
* disappears with the settings service. `onPreferenceChange`, when given,
|
|
48
|
+
* receives every committed change (including this TUI's own writes) through
|
|
49
|
+
* the scope's watch hook; callers guard re-applies by theme-bundle identity
|
|
50
|
+
* and height change, so an echoed self-write is a no-op. No source thunk is
|
|
51
|
+
* needed — the read helpers read the resolved values on demand at TUI
|
|
52
|
+
* startup.
|
|
53
|
+
*
|
|
54
|
+
* @param ctx - plugin context; does nothing while no settings service is mounted.
|
|
55
|
+
* @param onPreferenceChange - hot-reload sink for committed `dsh-tui` theme
|
|
56
|
+
* and panel-height changes; `undefined` when the namespace is already
|
|
57
|
+
* registered (a reloaded plugin instance, a second mount of this bundle) or
|
|
58
|
+
* registration fails.
|
|
59
|
+
*/
|
|
60
|
+
export function registerThemeSettings(ctx, onPreferenceChange) {
|
|
61
|
+
registrationPromise = new Promise(resolve => {
|
|
62
|
+
ctx.inject(['settings'], (sctx) => {
|
|
63
|
+
try {
|
|
64
|
+
// The namespace may already be registered (a reloaded plugin instance,
|
|
65
|
+
// a second mount of this bundle): `register` throws on duplicates, and
|
|
66
|
+
// the existing registration already serves the same schema — skip.
|
|
67
|
+
if (sctx.settings.describe().some((descriptor) => descriptor.ns === THEME_SETTINGS_NAMESPACE)) {
|
|
68
|
+
resolve();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const scope = sctx.settings.register(THEME_SETTINGS_NAMESPACE, THEME_SETTINGS_SCHEMA, {
|
|
72
|
+
base: THEME_SETTINGS_ENTRY,
|
|
73
|
+
// 'live': a committed change takes effect immediately — the TUI
|
|
74
|
+
// hot-applies the theme bundle and the panel height via the watch
|
|
75
|
+
// hook below. 'restart' was the old contract, when every component
|
|
76
|
+
// baked its theme at startup.
|
|
77
|
+
applies: 'live',
|
|
78
|
+
});
|
|
79
|
+
if (onPreferenceChange !== undefined) {
|
|
80
|
+
scope.watch((next) => {
|
|
81
|
+
// The resolved section is `{ theme: ..., panelHeight: ... }` —
|
|
82
|
+
// narrow the unknown to the two observed fields.
|
|
83
|
+
const section = next;
|
|
84
|
+
const theme = section.theme;
|
|
85
|
+
const panelHeight = section.panelHeight;
|
|
86
|
+
onPreferenceChange(theme === 'light' || theme === 'dark' ? theme : 'auto', panelHeight === '7' || panelHeight === '10' || panelHeight === 'all' ? panelHeight : DEFAULT_PANEL_HEIGHT);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
// TUI startup awaits `registrationPromise` — it must settle no matter
|
|
92
|
+
// what, so a failed registration degrades to 'auto' instead of
|
|
93
|
+
// hanging. Leave a trace for operators.
|
|
94
|
+
console.warn(`[dsh-tui-pi] settings namespace registration failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
95
|
+
}
|
|
96
|
+
resolve();
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The resolved `dsh-tui` section as read from the settings provider, after
|
|
102
|
+
* waiting for the in-flight registration.
|
|
103
|
+
*
|
|
104
|
+
* The registration is delivered through the settings injection fiber, so the
|
|
105
|
+
* value may not be visible synchronously right after `registerThemeSettings`:
|
|
106
|
+
* the settings service mounts asynchronously (its init sets up the provider,
|
|
107
|
+
* a file watcher, ...), a tick after the registration request in the dsh
|
|
108
|
+
* profile. Wait for the registration to land before describing — bounded, so
|
|
109
|
+
* a settings-less deployment degrades to the defaults instead of hanging TUI
|
|
110
|
+
* startup. Without a registration request there is nothing to wait for.
|
|
111
|
+
*
|
|
112
|
+
* @returns the resolved section, or `undefined` when no registration is in
|
|
113
|
+
* flight, the settings service is absent, or the namespace has not landed.
|
|
114
|
+
*/
|
|
115
|
+
async function readResolvedSection(ctx) {
|
|
116
|
+
if (registrationPromise === undefined)
|
|
117
|
+
return undefined;
|
|
118
|
+
let fallback;
|
|
119
|
+
await Promise.race([
|
|
120
|
+
registrationPromise,
|
|
121
|
+
new Promise(resolve => { fallback = setTimeout(resolve, 2000); }),
|
|
122
|
+
]);
|
|
123
|
+
if (fallback !== undefined)
|
|
124
|
+
clearTimeout(fallback);
|
|
125
|
+
const settings = ctx.get('settings');
|
|
126
|
+
if (settings === undefined)
|
|
127
|
+
return undefined;
|
|
128
|
+
// The descriptor's `value` is the whole resolved section
|
|
129
|
+
// (`{ theme: ..., panelHeight: ... }`), not the field itself — narrow the
|
|
130
|
+
// unknown to the two observed fields.
|
|
131
|
+
return settings
|
|
132
|
+
.describe()
|
|
133
|
+
.find((descriptor) => descriptor.ns === THEME_SETTINGS_NAMESPACE)?.value;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Read the persisted theme preference (the startup snapshot).
|
|
137
|
+
*
|
|
138
|
+
* @param ctx - plugin context.
|
|
139
|
+
* @returns the resolved `dsh-tui` theme value, or `'auto'` when the settings
|
|
140
|
+
* service is absent or the namespace/value cannot be read.
|
|
141
|
+
*/
|
|
142
|
+
export async function readThemePreference(ctx) {
|
|
143
|
+
const pref = (await readResolvedSection(ctx))?.theme;
|
|
144
|
+
if (pref === 'light' || pref === 'dark')
|
|
145
|
+
return pref;
|
|
146
|
+
return 'auto';
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Read the persisted think/tool panel height (the startup snapshot).
|
|
150
|
+
*
|
|
151
|
+
* @param ctx - plugin context.
|
|
152
|
+
* @returns the resolved `dsh-tui` panelHeight value, or DEFAULT_PANEL_HEIGHT
|
|
153
|
+
* when the settings service is absent or the namespace/value cannot be read.
|
|
154
|
+
*/
|
|
155
|
+
export async function readPanelHeightPreference(ctx) {
|
|
156
|
+
const height = (await readResolvedSection(ctx))?.panelHeight;
|
|
157
|
+
if (height === '7' || height === '10' || height === 'all')
|
|
158
|
+
return height;
|
|
159
|
+
return DEFAULT_PANEL_HEIGHT;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Read the currently persisted theme preference, synchronously.
|
|
163
|
+
* Unlike `readThemePreference` (the startup snapshot), this does not wait for
|
|
164
|
+
* the namespace registration — it describes whatever the settings service
|
|
165
|
+
* exposes right now, so the `/theme` picker preselects the live value, which
|
|
166
|
+
* may have changed since startup (e.g. through the /settings browser).
|
|
167
|
+
* @returns 'auto' when the service, namespace, or value cannot be read.
|
|
168
|
+
*/
|
|
169
|
+
export function currentThemePreference(ctx) {
|
|
170
|
+
const settings = ctx.get('settings');
|
|
171
|
+
if (settings === undefined)
|
|
172
|
+
return 'auto';
|
|
173
|
+
const pref = settings
|
|
174
|
+
.describe()
|
|
175
|
+
.find((descriptor) => descriptor.ns === THEME_SETTINGS_NAMESPACE)?.value?.theme;
|
|
176
|
+
if (pref === 'light' || pref === 'dark')
|
|
177
|
+
return pref;
|
|
178
|
+
return 'auto';
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Persist one `dsh-tui` preference (theme or panelHeight) to the settings
|
|
182
|
+
* namespace. The namespace is `applies: 'live'`, so the commit (observed
|
|
183
|
+
* through the registration's watch hook) hot-applies the change to the
|
|
184
|
+
* running TUI. Best-effort: a deployment without a settings provider reports
|
|
185
|
+
* the failure; a failed write returns its error message for the caller to
|
|
186
|
+
* surface. A concurrent writer moving the namespace rejects with
|
|
187
|
+
* `SettingsConflictError` — retried once against a fresh revision; a second
|
|
188
|
+
* conflict surfaces a friendly message instead of the raw error.
|
|
189
|
+
* @returns undefined on success, the failure message otherwise.
|
|
190
|
+
*/
|
|
191
|
+
async function writeDshTuiPreference(ctx, key, value) {
|
|
192
|
+
const settings = ctx.get('settings');
|
|
193
|
+
if (settings === undefined)
|
|
194
|
+
return 'Settings service is not available.';
|
|
195
|
+
// The descriptor carries the namespace's revision (optimistic-concurrency
|
|
196
|
+
// token for mutate) and proves the schema registration that validates the
|
|
197
|
+
// path below; the write rejects when the namespace is unregistered.
|
|
198
|
+
const ops = [{ op: 'set', path: [key], value }];
|
|
199
|
+
for (let attempt = 0;; attempt++) {
|
|
200
|
+
const descriptor = settings.describe().find((d) => d.ns === THEME_SETTINGS_NAMESPACE);
|
|
201
|
+
try {
|
|
202
|
+
await settings.mutate(THEME_SETTINGS_NAMESPACE, ops, descriptor?.revision);
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
if (attempt === 0 && error instanceof SettingsConflictError)
|
|
207
|
+
continue;
|
|
208
|
+
return error instanceof SettingsConflictError
|
|
209
|
+
? 'Settings changed concurrently — please retry.'
|
|
210
|
+
: error instanceof Error ? error.message : String(error);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Persist the theme preference to the `dsh-tui` settings namespace. The
|
|
216
|
+
* namespace is `applies: 'live'`, so the commit (observed through the
|
|
217
|
+
* registration's watch hook) hot-applies the change to the running TUI.
|
|
218
|
+
* @returns undefined on success, the failure message otherwise.
|
|
219
|
+
*/
|
|
220
|
+
export async function writeThemePreference(ctx, pref) {
|
|
221
|
+
return writeDshTuiPreference(ctx, 'theme', pref);
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=theme-settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-settings.js","sourceRoot":"","sources":["../src/theme-settings.ts"],"names":[],"mappings":"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"}
|
package/lib/tui.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TUI bootstrap: owns the terminal and the pi-tui component tree.
|
|
3
|
+
*
|
|
4
|
+
* Layout (alt-screen, mirrors pi interactive mode):
|
|
5
|
+
*
|
|
6
|
+
* ┌──────────────────────────────────────┐
|
|
7
|
+
* │ scrollable transcript (ScrollView) │ basis 0 / grow 1 — fills the rest
|
|
8
|
+
* ├──────────────────────────────────────┤
|
|
9
|
+
* │ statusContainer │ ┐
|
|
10
|
+
* │ widgetsContainer (Todos/Agents) │ │ dock — basis auto / grow 0,
|
|
11
|
+
* │ editor │ │ sized to its content
|
|
12
|
+
* │ footerContainer │ ┘
|
|
13
|
+
* └──────────────────────────────────────┘
|
|
14
|
+
*
|
|
15
|
+
* Design rules inherited from the pi-turbo findings — never re-scan the
|
|
16
|
+
* session log during render; all session-derived state (messages, usage,
|
|
17
|
+
* counts) is maintained incrementally by event listeners and read O(1) here.
|
|
18
|
+
*/
|
|
19
|
+
import { Container, type AutocompleteProvider, type TUI } from '@earendil-works/pi-tui';
|
|
20
|
+
import { CwdBorderEditor } from './editor.ts';
|
|
21
|
+
import { type ThemePreference, type TuiTheme } from './theme/index.ts';
|
|
22
|
+
export interface StartTuiOptions {
|
|
23
|
+
/** Submit handler for the editor. Defaults to a local echo (smoke-test mode). */
|
|
24
|
+
onSubmit?: (text: string) => void;
|
|
25
|
+
/** Ctrl+C handler. Defaults to a plain exit (smoke-test mode). */
|
|
26
|
+
onInterrupt?: () => void;
|
|
27
|
+
/** Persisted theme preference; 'auto' falls back to terminal detection. */
|
|
28
|
+
themePreference?: ThemePreference;
|
|
29
|
+
}
|
|
30
|
+
export interface TuiHandle {
|
|
31
|
+
/** Stop the render loop and leave raw mode. */
|
|
32
|
+
dispose(): void;
|
|
33
|
+
/** The underlying pi-tui instance (for Loader/overlay construction). */
|
|
34
|
+
readonly tui: TUI;
|
|
35
|
+
/** The scrollable transcript document container. */
|
|
36
|
+
readonly transcript: Container;
|
|
37
|
+
/** Fixed slot pinned above the chat window — live Todos/Agents widgets. */
|
|
38
|
+
readonly widgets: Container;
|
|
39
|
+
/** Fixed dock slot rendered between transcript and editor. */
|
|
40
|
+
readonly status: Container;
|
|
41
|
+
/** The input editor. */
|
|
42
|
+
readonly editor: CwdBorderEditor;
|
|
43
|
+
/** Fixed dock slot rendered below the editor. */
|
|
44
|
+
readonly footer: Container;
|
|
45
|
+
/** Request a re-render. */
|
|
46
|
+
requestRender(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Active theme bundle — swaps live under `applyTheme`; every read goes
|
|
49
|
+
* through the getter, so post-switch code always sees the new theme.
|
|
50
|
+
*/
|
|
51
|
+
readonly theme: TuiTheme;
|
|
52
|
+
/**
|
|
53
|
+
* Hot-swap the theme bundle: repaints the editor border, the last-request
|
|
54
|
+
* line and (when empty) the placeholder, and updates every subsequent
|
|
55
|
+
* `theme` read. Transcript repainting is the TranscriptRenderer's job
|
|
56
|
+
* (`setTheme`), owned by the caller; call it before `applyTheme` so the
|
|
57
|
+
* one throttled render frame paints everything at once. No-op when the
|
|
58
|
+
* bundle is unchanged (themes are module singletons).
|
|
59
|
+
*/
|
|
60
|
+
applyTheme(theme: TuiTheme): void;
|
|
61
|
+
/** Autocomplete provider for the editor; re-applied across editor rebuilds. */
|
|
62
|
+
setEditorAutocompleteProvider(provider: AutocompleteProvider): void;
|
|
63
|
+
/** Live git-branch source for the editor; re-applied across editor rebuilds. */
|
|
64
|
+
setEditorBranchProvider(provider: () => string | undefined): void;
|
|
65
|
+
/** Live permission-preset display-name source for the editor; re-applied across editor rebuilds. */
|
|
66
|
+
setEditorPermissionProvider(provider: () => string | undefined): void;
|
|
67
|
+
/** Show/hide the "last request" widget below the editor. */
|
|
68
|
+
setLastRequest(text: string | undefined): void;
|
|
69
|
+
}
|
|
70
|
+
export declare function startTui(options?: StartTuiOptions): TuiHandle;
|
package/lib/tui.js
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TUI bootstrap: owns the terminal and the pi-tui component tree.
|
|
3
|
+
*
|
|
4
|
+
* Layout (alt-screen, mirrors pi interactive mode):
|
|
5
|
+
*
|
|
6
|
+
* ┌──────────────────────────────────────┐
|
|
7
|
+
* │ scrollable transcript (ScrollView) │ basis 0 / grow 1 — fills the rest
|
|
8
|
+
* ├──────────────────────────────────────┤
|
|
9
|
+
* │ statusContainer │ ┐
|
|
10
|
+
* │ widgetsContainer (Todos/Agents) │ │ dock — basis auto / grow 0,
|
|
11
|
+
* │ editor │ │ sized to its content
|
|
12
|
+
* │ footerContainer │ ┘
|
|
13
|
+
* └──────────────────────────────────────┘
|
|
14
|
+
*
|
|
15
|
+
* Design rules inherited from the pi-turbo findings — never re-scan the
|
|
16
|
+
* session log during render; all session-derived state (messages, usage,
|
|
17
|
+
* counts) is maintained incrementally by event listeners and read O(1) here.
|
|
18
|
+
*/
|
|
19
|
+
import { Container, matchesKey, ProcessTerminal, ScrollView, Spacer, Text, TuiAltScreen, VStack, } from '@earendil-works/pi-tui';
|
|
20
|
+
import { CwdBorderEditor } from "./editor.js";
|
|
21
|
+
import { ansiFg, RESET, resolveTheme } from "./theme/index.js";
|
|
22
|
+
import { clipToWidth } from "./text.js";
|
|
23
|
+
export function startTui(options = {}) {
|
|
24
|
+
const terminal = new ProcessTerminal();
|
|
25
|
+
const tui = new TuiAltScreen(terminal, true);
|
|
26
|
+
// Mutable theme ref: `applyTheme` swaps it and every later read (handle
|
|
27
|
+
// getter, baked closures below) observes the new bundle on the next call.
|
|
28
|
+
let themeRef = resolveTheme(process.env, options.themePreference ?? 'auto');
|
|
29
|
+
// ------------------------------------------------------------- component tree --
|
|
30
|
+
// Live Todos/Agents widgets, pinned ABOVE the chat input: a plain Container
|
|
31
|
+
// with auto height — it renders zero rows while empty and grows to its
|
|
32
|
+
// (bordered-panel) content while the model has todos or subagents running.
|
|
33
|
+
const widgets = new Container();
|
|
34
|
+
const transcript = new Container();
|
|
35
|
+
const transcriptView = new ScrollView(transcript, {
|
|
36
|
+
follow: 'end',
|
|
37
|
+
primary: true,
|
|
38
|
+
overscroll: 'chain',
|
|
39
|
+
});
|
|
40
|
+
const status = new Container();
|
|
41
|
+
// The editor is rebuilt under `applyTheme` (its border/info colors are
|
|
42
|
+
// baked at construction), so it must be a mutable binding and the dock
|
|
43
|
+
// must be rebuilt in place below.
|
|
44
|
+
let editor = new CwdBorderEditor(tui, themeRef.editor, process.cwd(), {
|
|
45
|
+
infoColor: text => ansiFg(themeRef.palette.fgMuted) + text + RESET,
|
|
46
|
+
});
|
|
47
|
+
// External wiring that must survive editor rebuilds.
|
|
48
|
+
let autocompleteProvider;
|
|
49
|
+
let branchProvider;
|
|
50
|
+
let permissionProvider;
|
|
51
|
+
const lastRequest = new Container();
|
|
52
|
+
const footer = new Container();
|
|
53
|
+
let lastRequestText;
|
|
54
|
+
let lastRequestDisplay;
|
|
55
|
+
const dock = new VStack([
|
|
56
|
+
{ component: status, shrink: 1, minSize: 0 },
|
|
57
|
+
{ component: widgets, shrink: 1, minSize: 0 },
|
|
58
|
+
{ component: editor, shrink: 1, minSize: 3 },
|
|
59
|
+
{ component: lastRequest, shrink: 1, minSize: 0 },
|
|
60
|
+
{ component: footer, shrink: 1, minSize: 1 },
|
|
61
|
+
]);
|
|
62
|
+
const root = new VStack([
|
|
63
|
+
{ component: transcriptView, basis: 0, grow: 1, shrink: 1, minSize: 1 },
|
|
64
|
+
{ component: dock, basis: 'auto', grow: 0, shrink: 1, minSize: 1 },
|
|
65
|
+
]);
|
|
66
|
+
// -------------------------------------------------------------- placeholder UI --
|
|
67
|
+
const PLACEHOLDER = 'dsh-tui-pi — pi-style TUI for DeepSeek Harness';
|
|
68
|
+
const placeholder = new Text(ansiFg(themeRef.palette.fgDefault) + PLACEHOLDER + RESET, 1, 0);
|
|
69
|
+
transcript.addChild(placeholder);
|
|
70
|
+
transcript.addChild(new Spacer(1));
|
|
71
|
+
editor.onSubmit = (text) => {
|
|
72
|
+
if (text.trim() === '')
|
|
73
|
+
return;
|
|
74
|
+
if (options.onSubmit !== undefined) {
|
|
75
|
+
options.onSubmit(text);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// Smoke-test fallback: local echo only.
|
|
79
|
+
transcript.addChild(new Text(themeRef.chat.userMessageText('▎' + text), 1, 0));
|
|
80
|
+
transcript.addChild(new Spacer(1));
|
|
81
|
+
tui.requestRender();
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Swap the editor for a fresh instance carrying the new theme's baked
|
|
85
|
+
* colors, preserving the input buffer, submit handler and provider wiring.
|
|
86
|
+
* Focus moves to the replacement only when the editor was the focus
|
|
87
|
+
* target: with an overlay open (e.g. the settings browser), the overlay
|
|
88
|
+
* keeps focus and its own close path re-focuses the (new) editor.
|
|
89
|
+
* VStack has no insert-at, so the dock is re-assembled in order with the
|
|
90
|
+
* same sizing options as the initial tree.
|
|
91
|
+
*/
|
|
92
|
+
function rebuildEditor() {
|
|
93
|
+
const text = editor.getText();
|
|
94
|
+
const hadFocus = editor.focused;
|
|
95
|
+
const next = new CwdBorderEditor(tui, themeRef.editor, process.cwd(), {
|
|
96
|
+
infoColor: text => ansiFg(themeRef.palette.fgMuted) + text + RESET,
|
|
97
|
+
});
|
|
98
|
+
next.setText(text);
|
|
99
|
+
next.onSubmit = editor.onSubmit;
|
|
100
|
+
if (autocompleteProvider !== undefined)
|
|
101
|
+
next.setAutocompleteProvider(autocompleteProvider);
|
|
102
|
+
if (branchProvider !== undefined)
|
|
103
|
+
next.setBranchProvider(branchProvider);
|
|
104
|
+
if (permissionProvider !== undefined)
|
|
105
|
+
next.setPermissionProvider(permissionProvider);
|
|
106
|
+
dock.clear();
|
|
107
|
+
dock.addChild(status, { shrink: 1, minSize: 0 });
|
|
108
|
+
dock.addChild(widgets, { shrink: 1, minSize: 0 });
|
|
109
|
+
dock.addChild(next, { shrink: 1, minSize: 3 });
|
|
110
|
+
dock.addChild(lastRequest, { shrink: 1, minSize: 0 });
|
|
111
|
+
dock.addChild(footer, { shrink: 1, minSize: 1 });
|
|
112
|
+
editor = next;
|
|
113
|
+
if (hadFocus)
|
|
114
|
+
tui.setFocus(editor);
|
|
115
|
+
}
|
|
116
|
+
// ---------------------------------------------------------- lifecycle handle --
|
|
117
|
+
const handle = {
|
|
118
|
+
dispose() {
|
|
119
|
+
tui.stop();
|
|
120
|
+
},
|
|
121
|
+
tui,
|
|
122
|
+
transcript,
|
|
123
|
+
widgets,
|
|
124
|
+
status,
|
|
125
|
+
get editor() {
|
|
126
|
+
return editor;
|
|
127
|
+
},
|
|
128
|
+
footer,
|
|
129
|
+
requestRender() {
|
|
130
|
+
tui.requestRender();
|
|
131
|
+
},
|
|
132
|
+
get theme() {
|
|
133
|
+
return themeRef;
|
|
134
|
+
},
|
|
135
|
+
applyTheme(theme) {
|
|
136
|
+
if (theme === themeRef)
|
|
137
|
+
return;
|
|
138
|
+
themeRef = theme;
|
|
139
|
+
rebuildEditor();
|
|
140
|
+
if (lastRequestDisplay !== undefined && lastRequestText !== undefined) {
|
|
141
|
+
lastRequestText.setText(ansiFg(themeRef.palette.fgMuted) + ` ↳ ${lastRequestDisplay}` + RESET);
|
|
142
|
+
}
|
|
143
|
+
tui.requestRender();
|
|
144
|
+
},
|
|
145
|
+
setEditorAutocompleteProvider(provider) {
|
|
146
|
+
autocompleteProvider = provider;
|
|
147
|
+
editor.setAutocompleteProvider(provider);
|
|
148
|
+
},
|
|
149
|
+
setEditorBranchProvider(provider) {
|
|
150
|
+
branchProvider = provider;
|
|
151
|
+
editor.setBranchProvider(provider);
|
|
152
|
+
},
|
|
153
|
+
setEditorPermissionProvider(provider) {
|
|
154
|
+
permissionProvider = provider;
|
|
155
|
+
editor.setPermissionProvider(provider);
|
|
156
|
+
},
|
|
157
|
+
setLastRequest(text) {
|
|
158
|
+
if (text === undefined || text.trim() === '') {
|
|
159
|
+
if (lastRequestText !== undefined) {
|
|
160
|
+
lastRequest.removeChild(lastRequestText);
|
|
161
|
+
lastRequestText = undefined;
|
|
162
|
+
lastRequestDisplay = undefined;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
const display = clipToWidth(text, 200);
|
|
167
|
+
if (lastRequestText === undefined) {
|
|
168
|
+
lastRequestText = new Text('', 1, 0);
|
|
169
|
+
lastRequest.addChild(lastRequestText);
|
|
170
|
+
}
|
|
171
|
+
lastRequestDisplay = display;
|
|
172
|
+
lastRequestText.setText(ansiFg(themeRef.palette.fgMuted) + ` ↳ ${display}` + RESET);
|
|
173
|
+
}
|
|
174
|
+
tui.requestRender();
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
// ------------------------------------------------------------- input & focus --
|
|
178
|
+
tui.setFocus(editor);
|
|
179
|
+
tui.addInputListener((data) => {
|
|
180
|
+
if (matchesKey(data, 'ctrl+c')) {
|
|
181
|
+
if (options.onInterrupt !== undefined) {
|
|
182
|
+
options.onInterrupt();
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
handle.dispose();
|
|
186
|
+
process.exit(130);
|
|
187
|
+
}
|
|
188
|
+
return { consume: true };
|
|
189
|
+
}
|
|
190
|
+
return undefined;
|
|
191
|
+
});
|
|
192
|
+
tui.setLayoutRoot(root);
|
|
193
|
+
try {
|
|
194
|
+
tui.start();
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
// Never leave the terminal stuck in raw mode on a render crash.
|
|
198
|
+
try {
|
|
199
|
+
tui.stop();
|
|
200
|
+
}
|
|
201
|
+
catch { /* best effort */ }
|
|
202
|
+
throw error;
|
|
203
|
+
}
|
|
204
|
+
return handle;
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=tui.js.map
|
package/lib/tui.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tui.js","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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"}
|