@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,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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"}