@aiwayds/dsh-tui-pi 0.1.1 → 0.4.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/README.md +175 -41
- package/lib/agent-manager.d.ts +125 -0
- package/lib/agent-manager.js +298 -0
- package/lib/agent-manager.js.map +1 -0
- package/lib/agents.d.ts +30 -0
- package/lib/agents.js +489 -0
- package/lib/agents.js.map +1 -0
- package/lib/append-system.d.ts +2 -0
- package/lib/append-system.js +1 -1
- package/lib/append-system.js.map +1 -1
- package/lib/dsh-events.d.ts +12 -0
- package/lib/editor.d.ts +58 -0
- package/lib/editor.js +92 -0
- package/lib/editor.js.map +1 -1
- package/lib/footer.d.ts +46 -0
- package/lib/footer.js +65 -0
- package/lib/footer.js.map +1 -1
- package/lib/hotkeys.d.ts +93 -0
- package/lib/hotkeys.js +305 -0
- package/lib/hotkeys.js.map +1 -0
- package/lib/index.js +342 -61
- package/lib/index.js.map +1 -1
- package/lib/keymap.d.ts +243 -0
- package/lib/keymap.js +245 -0
- package/lib/keymap.js.map +1 -0
- package/lib/live-widgets.d.ts +59 -49
- package/lib/live-widgets.js +174 -117
- package/lib/live-widgets.js.map +1 -1
- package/lib/panels.d.ts +177 -0
- package/lib/panels.js +331 -0
- package/lib/panels.js.map +1 -0
- package/lib/selectors.d.ts +12 -1
- package/lib/selectors.js +1 -1
- package/lib/selectors.js.map +1 -1
- package/lib/session.d.ts +25 -0
- package/lib/session.js +173 -12
- package/lib/session.js.map +1 -1
- package/lib/settings.d.ts +1 -2
- package/lib/subagent-policy.d.ts +88 -0
- package/lib/subagent-policy.js +189 -0
- package/lib/subagent-policy.js.map +1 -0
- package/lib/subagent-viewer.d.ts +49 -0
- package/lib/subagent-viewer.js +523 -0
- package/lib/subagent-viewer.js.map +1 -0
- package/lib/theme/index.js +4 -0
- package/lib/theme/index.js.map +1 -1
- package/lib/theme/palette.d.ts +21 -3
- package/lib/theme/palette.js +27 -6
- package/lib/theme/palette.js.map +1 -1
- package/lib/theme-settings.d.ts +71 -9
- package/lib/theme-settings.js +145 -21
- package/lib/theme-settings.js.map +1 -1
- package/lib/tui.d.ts +23 -9
- package/lib/tui.js +110 -7
- package/lib/tui.js.map +1 -1
- package/package.json +3 -4
- package/patches/@earendil-works__pi-tui.patch +206 -2
- package/scripts/dev-install.mjs +87 -0
- package/scripts/link-dsh-closure.mjs +85 -0
- package/templates/agents/ArtyDuck.md +11 -0
- package/templates/agents/oldfox.md +33 -0
- package/templates/agents/workhorse.md +34 -0
package/lib/editor.js
CHANGED
|
@@ -14,6 +14,8 @@ export function formatCwd(cwd) {
|
|
|
14
14
|
}
|
|
15
15
|
return cwd;
|
|
16
16
|
}
|
|
17
|
+
/** History cap for the submitted-message browse (shell-style Up/Down recall). */
|
|
18
|
+
export const HISTORY_LIMIT = 500;
|
|
17
19
|
export class CwdBorderEditor extends Editor {
|
|
18
20
|
sessionCwd;
|
|
19
21
|
infoColor;
|
|
@@ -37,6 +39,96 @@ export class CwdBorderEditor extends Editor {
|
|
|
37
39
|
setPermissionProvider(provider) {
|
|
38
40
|
this.permissionProvider = provider;
|
|
39
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Record a submitted message for Up/Down browsing. Same semantics as the
|
|
44
|
+
* pi-tui base `addToHistory` (trim, skip empty, skip consecutive duplicates,
|
|
45
|
+
* index 0 = most recent) but caps the list at `HISTORY_LIMIT` instead of the
|
|
46
|
+
* base's 100 — the chat editor wants a 500-entry recall, dropping the oldest.
|
|
47
|
+
* Note: the base (0.84.2) declares `history` private in its .d.ts but keeps
|
|
48
|
+
* it as a plain runtime field; we reach it via a type cast. The `override`
|
|
49
|
+
* keyword is fine under this tsconfig.
|
|
50
|
+
*/
|
|
51
|
+
addToHistory(text) {
|
|
52
|
+
const trimmed = text.trim();
|
|
53
|
+
if (trimmed === '')
|
|
54
|
+
return;
|
|
55
|
+
const history = this.history;
|
|
56
|
+
// A bad pi-tui bump must degrade, not throw on every Enter: if the base
|
|
57
|
+
// ever stops exposing `history` as a plain array, fall back to the base
|
|
58
|
+
// implementation (its own 100-cap path) and return.
|
|
59
|
+
if (!Array.isArray(history)) {
|
|
60
|
+
super.addToHistory(text);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Don't add consecutive duplicates.
|
|
64
|
+
if (history.length > 0 && history[0] === trimmed)
|
|
65
|
+
return;
|
|
66
|
+
history.unshift(trimmed);
|
|
67
|
+
// Drop the oldest beyond the cap (base caps at 100).
|
|
68
|
+
if (history.length > HISTORY_LIMIT)
|
|
69
|
+
history.length = HISTORY_LIMIT;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Snapshot of the browse history, newest first (index 0). Returns a copy so
|
|
73
|
+
* callers can reseed another instance (theme-swap rebuild) without mutating
|
|
74
|
+
* this editor's internal list. Returns `[]` when the base no longer exposes
|
|
75
|
+
* the runtime list (a bad pi-tui bump) rather than throwing.
|
|
76
|
+
*/
|
|
77
|
+
getHistory() {
|
|
78
|
+
const history = this.history;
|
|
79
|
+
if (!Array.isArray(history))
|
|
80
|
+
return [];
|
|
81
|
+
return [...history];
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Reseed this editor's browse history from `entries` (newest first, index 0
|
|
85
|
+
* = most recent, matching the base's addToHistory ordering). Adds oldest →
|
|
86
|
+
* newest so the list lands in the same order on a fresh instance. Pinned to
|
|
87
|
+
* HISTORY_LIMIT like any other add.
|
|
88
|
+
*/
|
|
89
|
+
reseedHistory(entries) {
|
|
90
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
91
|
+
this.addToHistory(entries[i]);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Snapshot the base's mid-browse state for a rebuild restore. `draft` is
|
|
96
|
+
* `null` when not browsing (historyIndex -1) — `structuredClone`d so the
|
|
97
|
+
* caller can reseed another instance without aliasing this editor's object.
|
|
98
|
+
* Treats a missing/invalid base field as not browsing (a bad pi-tui bump
|
|
99
|
+
* must degrade, not throw).
|
|
100
|
+
*/
|
|
101
|
+
getBrowseState() {
|
|
102
|
+
const base = this;
|
|
103
|
+
const index = typeof base.historyIndex === 'number' ? base.historyIndex : -1;
|
|
104
|
+
const rawDraft = base.historyDraft;
|
|
105
|
+
const draft = rawDraft !== null && rawDraft !== undefined && Array.isArray(rawDraft.lines)
|
|
106
|
+
? {
|
|
107
|
+
lines: structuredClone(rawDraft.lines),
|
|
108
|
+
cursorLine: rawDraft.cursorLine ?? 0,
|
|
109
|
+
cursorCol: rawDraft.cursorCol ?? 0,
|
|
110
|
+
}
|
|
111
|
+
: null;
|
|
112
|
+
return { index, draft };
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Restore a previously-captured browse state (see getBrowseState) onto a
|
|
116
|
+
* fresh editor after a rebuild. `index` is clamped to the reseeded list so a
|
|
117
|
+
* stale snapshot can never read out of bounds; a snapshot whose history was
|
|
118
|
+
* truncated to nothing degrades to not browsing. `draft` is `null` → null,
|
|
119
|
+
* else `structuredClone`d. Skips writes entirely when the base no longer
|
|
120
|
+
* exposes the runtime fields (a bad pi-tui bump degrades silently).
|
|
121
|
+
*/
|
|
122
|
+
restoreBrowseState(state) {
|
|
123
|
+
const base = this;
|
|
124
|
+
if (!Array.isArray(base.history))
|
|
125
|
+
return;
|
|
126
|
+
const maxIndex = base.history.length - 1;
|
|
127
|
+
const index = maxIndex < 0 ? -1 : Math.max(-1, Math.min(state.index, maxIndex));
|
|
128
|
+
base.historyIndex = index;
|
|
129
|
+
base.historyDraft =
|
|
130
|
+
state.draft === null ? null : structuredClone(state.draft);
|
|
131
|
+
}
|
|
40
132
|
render(width) {
|
|
41
133
|
const lines = super.render(width);
|
|
42
134
|
if (lines.length < 2 || width < 3)
|
package/lib/editor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor.js","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"editor.js","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"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"}
|
package/lib/footer.d.ts
CHANGED
|
@@ -13,6 +13,52 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { type Component } from '@earendil-works/pi-tui';
|
|
15
15
|
import type { BridgeStats } from './session.ts';
|
|
16
|
+
import { type TuiTheme } from './theme/index.ts';
|
|
17
|
+
/**
|
|
18
|
+
* The footer keybinding hint, assembled from the user's `dsh-tui.footerHints`
|
|
19
|
+
* selection (see buildFooterHint) - the pre-feature full string is what the
|
|
20
|
+
* all-true default produces, and stays exactly 103 visible columns. The
|
|
21
|
+
* no-wrap rendering lives in `FooterHint` (a width-clipping component, not a
|
|
22
|
+
* word-wrapping Text). The unit test in test/history.test.mjs guards the
|
|
23
|
+
* default against future length regressions (a longer hint word-wraps on
|
|
24
|
+
* 105-118-column terminals and hides its suffix on <=104).
|
|
25
|
+
*/
|
|
26
|
+
export declare const FOOTER_HINT = "\u2328 Enter: send \u00B7 Esc \u00D72: stop \u00B7 Ctrl+C \u00D72: quit \u00B7 Ctrl+D: quit (empty) \u00B7 Ctrl+G: subagents \u00B7 \u2191\u2193: history";
|
|
27
|
+
/** The toggleable footer hint segments, keyed as in the `dsh-tui` settings. */
|
|
28
|
+
export interface FooterHints {
|
|
29
|
+
send: boolean;
|
|
30
|
+
stop: boolean;
|
|
31
|
+
quit: boolean;
|
|
32
|
+
quitEmpty: boolean;
|
|
33
|
+
subagents: boolean;
|
|
34
|
+
history: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** Every hint off - the footer hint bar renders nothing. */
|
|
37
|
+
export declare const DEFAULT_FOOTER_HINTS: FooterHints;
|
|
38
|
+
/** The hint segments in display order, each without the `⌨ ` lead. */
|
|
39
|
+
export declare const FOOTER_HINT_ITEMS: ReadonlyArray<{
|
|
40
|
+
id: keyof FooterHints;
|
|
41
|
+
label: string;
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* Assemble the footer hint from the user's per-segment on/off selection, in
|
|
45
|
+
* the fixed display order. `''` when every segment is off.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildFooterHint(shown: FooterHints): string;
|
|
48
|
+
/**
|
|
49
|
+
* The footer hint bar - a single width-clipped row, never word-wrapped. The
|
|
50
|
+
* old `Text` wrapped the 103-column hint on narrow terminals; this component
|
|
51
|
+
* clips it to the current width every frame (and re-reads the live hints
|
|
52
|
+
* selection through the getter, so a /settings change applies on the next
|
|
53
|
+
* repaint). Renders zero rows when the user turned every hint off.
|
|
54
|
+
*/
|
|
55
|
+
export declare class FooterHint implements Component {
|
|
56
|
+
private readonly getTheme;
|
|
57
|
+
private readonly getHints;
|
|
58
|
+
constructor(getTheme: () => TuiTheme, getHints: () => FooterHints);
|
|
59
|
+
invalidate(): void;
|
|
60
|
+
render(width: number): string[];
|
|
61
|
+
}
|
|
16
62
|
export interface FooterDataSource {
|
|
17
63
|
/** O(1) incremental counters. */
|
|
18
64
|
getStats(): BridgeStats;
|
package/lib/footer.js
CHANGED
|
@@ -14,6 +14,71 @@
|
|
|
14
14
|
import { truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';
|
|
15
15
|
import { ansiBg, ansiFg, BOLD, POWERLINE, RESET } from "./theme/index.js";
|
|
16
16
|
import { clipToWidth } from "./text.js";
|
|
17
|
+
/**
|
|
18
|
+
* The footer keybinding hint, assembled from the user's `dsh-tui.footerHints`
|
|
19
|
+
* selection (see buildFooterHint) - the pre-feature full string is what the
|
|
20
|
+
* all-true default produces, and stays exactly 103 visible columns. The
|
|
21
|
+
* no-wrap rendering lives in `FooterHint` (a width-clipping component, not a
|
|
22
|
+
* word-wrapping Text). The unit test in test/history.test.mjs guards the
|
|
23
|
+
* default against future length regressions (a longer hint word-wraps on
|
|
24
|
+
* 105-118-column terminals and hides its suffix on <=104).
|
|
25
|
+
*/
|
|
26
|
+
export const FOOTER_HINT = '⌨ Enter: send · Esc ×2: stop · Ctrl+C ×2: quit · Ctrl+D: quit (empty) · Ctrl+G: subagents · ↑↓: history';
|
|
27
|
+
/** Every hint off - the footer hint bar renders nothing. */
|
|
28
|
+
export const DEFAULT_FOOTER_HINTS = Object.freeze({
|
|
29
|
+
send: true,
|
|
30
|
+
stop: true,
|
|
31
|
+
quit: true,
|
|
32
|
+
quitEmpty: true,
|
|
33
|
+
subagents: true,
|
|
34
|
+
history: true,
|
|
35
|
+
});
|
|
36
|
+
/** The hint segments in display order, each without the `⌨ ` lead. */
|
|
37
|
+
export const FOOTER_HINT_ITEMS = [
|
|
38
|
+
{ id: 'send', label: 'Enter: send' },
|
|
39
|
+
{ id: 'stop', label: 'Esc ×2: stop' },
|
|
40
|
+
{ id: 'quit', label: 'Ctrl+C ×2: quit' },
|
|
41
|
+
{ id: 'quitEmpty', label: 'Ctrl+D: quit (empty)' },
|
|
42
|
+
{ id: 'subagents', label: 'Ctrl+G: subagents' },
|
|
43
|
+
{ id: 'history', label: '↑↓: history' },
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* Assemble the footer hint from the user's per-segment on/off selection, in
|
|
47
|
+
* the fixed display order. `''` when every segment is off.
|
|
48
|
+
*/
|
|
49
|
+
export function buildFooterHint(shown) {
|
|
50
|
+
const parts = FOOTER_HINT_ITEMS.filter(item => shown[item.id]).map(item => item.label);
|
|
51
|
+
if (parts.length === 0)
|
|
52
|
+
return '';
|
|
53
|
+
return `⌨ ${parts.join(' · ')}`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The footer hint bar - a single width-clipped row, never word-wrapped. The
|
|
57
|
+
* old `Text` wrapped the 103-column hint on narrow terminals; this component
|
|
58
|
+
* clips it to the current width every frame (and re-reads the live hints
|
|
59
|
+
* selection through the getter, so a /settings change applies on the next
|
|
60
|
+
* repaint). Renders zero rows when the user turned every hint off.
|
|
61
|
+
*/
|
|
62
|
+
export class FooterHint {
|
|
63
|
+
getTheme;
|
|
64
|
+
getHints;
|
|
65
|
+
constructor(getTheme, getHints) {
|
|
66
|
+
this.getTheme = getTheme;
|
|
67
|
+
this.getHints = getHints;
|
|
68
|
+
}
|
|
69
|
+
invalidate() { }
|
|
70
|
+
render(width) {
|
|
71
|
+
const hint = buildFooterHint(this.getHints());
|
|
72
|
+
if (hint === '')
|
|
73
|
+
return [];
|
|
74
|
+
// paddingX 1 on each side, matching the powerline segments' leading space.
|
|
75
|
+
const inner = Math.max(1, width - 2);
|
|
76
|
+
const clipped = clipToWidth(hint, inner);
|
|
77
|
+
const styled = ansiFg(this.getTheme().palette.fgSubtle) + clipped + RESET;
|
|
78
|
+
const pad = ' '.repeat(Math.max(0, width - visibleWidth(clipped) - 2));
|
|
79
|
+
return [` ${styled}${pad} `];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
17
82
|
const ARROW_RIGHT = '\uE0B0';
|
|
18
83
|
const WHITE = ansiFg('#FFFFFF');
|
|
19
84
|
export function fmtNum(n) {
|
package/lib/footer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"footer.js","sourceRoot":"","sources":["../src/footer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,eAAe,EAAE,YAAY,EAAkB,MAAM,wBAAwB,CAAA;AAEtF,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"footer.js","sourceRoot":"","sources":["../src/footer.ts"],"names":[],"mappings":"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"}
|
package/lib/hotkeys.d.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/hotkeys` — view and customize the app-level keybindings, in the /agents
|
|
3
|
+
* select-panel style (src/panels.ts).
|
|
4
|
+
*
|
|
5
|
+
* pi's convention is a `/hotkeys` command plus a user-editable
|
|
6
|
+
* `~/.pi/agent/keybindings.json`. dsh side: `$DSH_HOME/keybindings.json`
|
|
7
|
+
* (default `~/.dsh/keybindings.json`). The file is a PARTIAL map of the four
|
|
8
|
+
* app keys ({@link APP_KEY_FIELDS}) to pi-tui key ids; anything missing falls
|
|
9
|
+
* back to the defaults (`src/keymap.ts`).
|
|
10
|
+
*
|
|
11
|
+
* UI (mirrors `/agents`): a FieldPanel lists the app keys — binding, custom
|
|
12
|
+
* star, action, file path + warnings; Enter opens an EditField to type a new
|
|
13
|
+
* key id (empty input resets the key to its default). A commit writes the
|
|
14
|
+
* file AND live-applies the new bindings to the running TUI (no /reload
|
|
15
|
+
* needed). Invalid entries never block: they warn and keep the default.
|
|
16
|
+
*
|
|
17
|
+
* The decision logic stays in `keymap.ts` (pure); this module owns the file
|
|
18
|
+
* contract, the validation, the display table and the interactive flow.
|
|
19
|
+
*/
|
|
20
|
+
import type { KeyId, TUI } from '@earendil-works/pi-tui';
|
|
21
|
+
import { type KeyBindings } from './keymap.ts';
|
|
22
|
+
import { type ParseOutcome } from './settings.ts';
|
|
23
|
+
import { type TuiTheme } from './theme/index.ts';
|
|
24
|
+
/** The user-editable keybindings file name inside the dsh home. */
|
|
25
|
+
export declare const KEYBINDINGS_FILE = "keybindings.json";
|
|
26
|
+
/** Absolute path of the keybindings file under a dsh home directory. */
|
|
27
|
+
export declare function keybindingsPath(home: string): string;
|
|
28
|
+
/** The five app-level bindings the file may remap (order = display order). */
|
|
29
|
+
export declare const APP_KEY_FIELDS: readonly (keyof KeyBindings)[];
|
|
30
|
+
/**
|
|
31
|
+
* Conservative check of one pi-tui key id as a user might type it:
|
|
32
|
+
* `modifier+key` where every modifier is ctrl/shift/alt/super and the key is
|
|
33
|
+
* a named key (`escape`, `pageUp`, `f5`, …) or a single printable character.
|
|
34
|
+
* pi-tui's own `parseKeyId` is lenient (unknown ids just never match), so we
|
|
35
|
+
* reject obvious typos up front and let a warning surface them.
|
|
36
|
+
*/
|
|
37
|
+
export declare function isValidKeyId(value: unknown): value is KeyId;
|
|
38
|
+
/** Human display of a key id: `escape`→`Esc`, `ctrl+shift+p`→`Ctrl+Shift+P`. */
|
|
39
|
+
export declare function displayKey(id: KeyId): string;
|
|
40
|
+
/** Result of reading the user keybindings file. */
|
|
41
|
+
export interface LoadedKeyBindings {
|
|
42
|
+
/** Valid entries only; may be empty when the file is absent or broken. */
|
|
43
|
+
bindings: Partial<KeyBindings>;
|
|
44
|
+
/** Human-readable problems (invalid entries, bad JSON) — shown as notices. */
|
|
45
|
+
warnings: string[];
|
|
46
|
+
/** Whether the file existed and parsed (a JSON object). */
|
|
47
|
+
exists: boolean;
|
|
48
|
+
}
|
|
49
|
+
/** Read + validate `$DSH_HOME/keybindings.json`. Never throws. */
|
|
50
|
+
export declare function loadKeyBindings(path: string): LoadedKeyBindings;
|
|
51
|
+
/**
|
|
52
|
+
* Merge-write the keybindings file: each `[field, value]` sets a binding,
|
|
53
|
+
* `null` removes it (reset to default). Unknown fields already in the file
|
|
54
|
+
* are preserved (the user's other keys survive). Missing file → fresh object;
|
|
55
|
+
* an unreadable/broken EXISTING file is an error — never clobbered silently.
|
|
56
|
+
* Returns an error message, or `undefined` on success.
|
|
57
|
+
*/
|
|
58
|
+
export declare function updateKeyBindingsFile(path: string, updates: ReadonlyArray<readonly [keyof KeyBindings, KeyId | null]>): string | undefined;
|
|
59
|
+
/** The `/hotkeys` EditField parse: empty = reset, else a validated key id. */
|
|
60
|
+
export declare function parseKeyInput(text: string): ParseOutcome;
|
|
61
|
+
/** One row of the `/hotkeys` table. */
|
|
62
|
+
export interface HotkeyRow {
|
|
63
|
+
/** The app-key field this row edits. */
|
|
64
|
+
field: keyof KeyBindings;
|
|
65
|
+
/** Display key text (custom override reflected). */
|
|
66
|
+
key: string;
|
|
67
|
+
/** What the key does. */
|
|
68
|
+
action: string;
|
|
69
|
+
/** True when the key comes from the user's keybindings file. */
|
|
70
|
+
custom: boolean;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Build the app-key rows from the effective bindings — defaults, with any
|
|
74
|
+
* file override replacing the key display and flagging the row as custom.
|
|
75
|
+
* Pure, so the table content is unit-testable without a terminal.
|
|
76
|
+
*/
|
|
77
|
+
export declare function appHotkeyRows(custom: Partial<KeyBindings>): HotkeyRow[];
|
|
78
|
+
/** Options for the `/hotkeys` interactive flow. */
|
|
79
|
+
export interface HotkeysManagerOptions {
|
|
80
|
+
/** Absolute path of the user keybindings file. */
|
|
81
|
+
filePath: string;
|
|
82
|
+
/** Live-apply new bindings to the running TUI (called after every write). */
|
|
83
|
+
apply: (bindings: Partial<KeyBindings>) => void;
|
|
84
|
+
/** Re-focus the CURRENT editor instance on close. */
|
|
85
|
+
restoreFocus: () => void;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Open the `/hotkeys` manager: a FieldPanel of the five app keys (binding,
|
|
89
|
+
* custom star, action, file status + warnings), Enter opens an EditField that
|
|
90
|
+
* writes the file and live-applies the change. Resolves with a summary when
|
|
91
|
+
* the user changed something and closed, or `undefined` when nothing changed.
|
|
92
|
+
*/
|
|
93
|
+
export declare function openHotkeysManager(tui: TUI, theme: TuiTheme, options: HotkeysManagerOptions): Promise<string | undefined>;
|