@dungle-scrubs/tallow 0.8.26 → 0.8.28
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 +42 -1
- package/dist/cli.js +7 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/interactive-mode-patch.d.ts +1 -0
- package/dist/interactive-mode-patch.d.ts.map +1 -1
- package/dist/interactive-mode-patch.js +40 -1
- package/dist/interactive-mode-patch.js.map +1 -1
- package/dist/model-metadata-overrides.d.ts +2 -5
- package/dist/model-metadata-overrides.d.ts.map +1 -1
- package/dist/model-metadata-overrides.js +23 -12
- package/dist/model-metadata-overrides.js.map +1 -1
- package/dist/pid-manager.d.ts +2 -9
- package/dist/pid-manager.d.ts.map +1 -1
- package/dist/pid-manager.js +1 -58
- package/dist/pid-manager.js.map +1 -1
- package/dist/pid-schema.d.ts +51 -0
- package/dist/pid-schema.d.ts.map +1 -0
- package/dist/pid-schema.js +70 -0
- package/dist/pid-schema.js.map +1 -0
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +24 -17
- package/dist/sdk.js.map +1 -1
- package/dist/workspace-transition-interactive.d.ts.map +1 -1
- package/dist/workspace-transition-interactive.js +53 -3
- package/dist/workspace-transition-interactive.js.map +1 -1
- package/dist/workspace-transition.d.ts +2 -1
- package/dist/workspace-transition.d.ts.map +1 -1
- package/dist/workspace-transition.js +16 -4
- package/dist/workspace-transition.js.map +1 -1
- package/extensions/__integration__/audit-findings.test.ts +309 -0
- package/extensions/__integration__/cd-tool-guidelines.test.ts +46 -0
- package/extensions/__integration__/tasks-runtime.test.ts +63 -12
- package/extensions/__integration__/welcome-screen.test.ts +240 -0
- package/extensions/_shared/lazy-init.ts +88 -3
- package/extensions/_shared/pid-registry.ts +8 -82
- package/extensions/background-task-tool/index.ts +1 -1
- package/extensions/cd-tool/index.ts +4 -1
- package/extensions/cheatsheet/__tests__/cheatsheet.test.ts +47 -0
- package/extensions/clear/__tests__/clear.test.ts +38 -0
- package/extensions/edit-tool-enhanced/index.ts +3 -1
- package/extensions/git-status/__tests__/git-status.test.ts +32 -0
- package/extensions/health/__tests__/diagnostics.test.ts +25 -0
- package/extensions/health/index.ts +61 -0
- package/extensions/loop/__tests__/loop.test.ts +365 -1
- package/extensions/loop/index.ts +213 -3
- package/extensions/mcp-adapter-tool/index.ts +1 -1
- package/extensions/minimal-skill-display/__tests__/minimal-skill-display.test.ts +20 -0
- package/extensions/permissions/__tests__/permissions.test.ts +213 -0
- package/extensions/progress-indicator/__tests__/progress-indicator.test.ts +104 -0
- package/extensions/prompt-suggestions/__tests__/autocomplete.test.ts +111 -3
- package/extensions/prompt-suggestions/autocomplete.ts +23 -5
- package/extensions/prompt-suggestions/index.ts +62 -3
- package/extensions/random-spinner/__tests__/random-spinner.test.ts +35 -0
- package/extensions/read-tool-enhanced/index.ts +5 -1
- package/extensions/session-memory/index.ts +1 -1
- package/extensions/session-namer/index.ts +1 -1
- package/extensions/show-system-prompt/__tests__/show-system-prompt.test.ts +51 -0
- package/extensions/subagent-tool/__tests__/presentation-rendering.test.ts +9 -8
- package/extensions/subagent-tool/__tests__/process-liveness.test.ts +51 -0
- package/extensions/subagent-tool/__tests__/subprocess-args.test.ts +120 -0
- package/extensions/subagent-tool/formatting.ts +2 -0
- package/extensions/subagent-tool/index.ts +160 -97
- package/extensions/subagent-tool/process.ts +152 -40
- package/extensions/tasks/commands/register-tasks-extension.ts +64 -20
- package/extensions/tasks/extension.json +1 -0
- package/extensions/tasks/index.ts +2 -12
- package/extensions/tasks/state/index.ts +26 -0
- package/extensions/teams-tool/dashboard.ts +13 -1
- package/extensions/teams-tool/sessions/spawn.ts +2 -2
- package/extensions/teams-tool/tools/register-extension.ts +10 -2
- package/extensions/upstream-check/__tests__/upstream-check.test.ts +49 -0
- package/extensions/welcome-screen/__tests__/welcome-screen.test.ts +35 -0
- package/extensions/welcome-screen/extension.json +20 -0
- package/extensions/welcome-screen/index.ts +189 -0
- package/extensions/wezterm-notify/__tests__/index.test.ts +49 -11
- package/extensions/wezterm-notify/index.ts +5 -3
- package/extensions/write-tool-enhanced/__tests__/write-tool-enhanced.test.ts +296 -0
- package/node_modules/@mariozechner/pi-tui/dist/index.d.ts +2 -2
- package/node_modules/@mariozechner/pi-tui/dist/index.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/index.js +2 -2
- package/node_modules/@mariozechner/pi-tui/dist/index.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/keybindings.d.ts +309 -25
- package/node_modules/@mariozechner/pi-tui/dist/keybindings.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/keybindings.js +392 -72
- package/node_modules/@mariozechner/pi-tui/dist/keybindings.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/keys.d.ts +30 -0
- package/node_modules/@mariozechner/pi-tui/dist/keys.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/keys.js +50 -6
- package/node_modules/@mariozechner/pi-tui/dist/keys.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/terminal.d.ts +27 -0
- package/node_modules/@mariozechner/pi-tui/dist/terminal.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/terminal.js +59 -4
- package/node_modules/@mariozechner/pi-tui/dist/terminal.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts +9 -0
- package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/tui.js +50 -1
- package/node_modules/@mariozechner/pi-tui/dist/tui.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/package.json +1 -1
- package/node_modules/@mariozechner/pi-tui/src/__tests__/mouse-events.test.ts +134 -0
- package/node_modules/@mariozechner/pi-tui/src/__tests__/tmux-compat.test.ts +204 -0
- package/node_modules/@mariozechner/pi-tui/src/__tests__/tui-diff-regression.test.ts +49 -0
- package/node_modules/@mariozechner/pi-tui/src/__tests__/tui-render-scheduling.test.ts +2 -0
- package/node_modules/@mariozechner/pi-tui/src/index.ts +11 -0
- package/node_modules/@mariozechner/pi-tui/src/keybindings.ts +478 -140
- package/node_modules/@mariozechner/pi-tui/src/keys.ts +84 -6
- package/node_modules/@mariozechner/pi-tui/src/terminal.ts +69 -4
- package/node_modules/@mariozechner/pi-tui/src/tui.ts +64 -1
- package/package.json +11 -10
- package/runtime/config.ts +7 -0
- package/runtime/model-metadata-overrides.ts +7 -0
- package/runtime/pid-schema.ts +13 -0
- package/skills/tallow-expert/SKILL.md +7 -5
|
@@ -1,183 +1,521 @@
|
|
|
1
1
|
import { type KeyId, matchesKey } from "./keys.js";
|
|
2
2
|
|
|
3
|
+
/** Modern TUI keybinding identifiers. */
|
|
4
|
+
export interface Keybindings {
|
|
5
|
+
"tui.editor.cursorDown": true;
|
|
6
|
+
"tui.editor.cursorLeft": true;
|
|
7
|
+
"tui.editor.cursorLineEnd": true;
|
|
8
|
+
"tui.editor.cursorLineStart": true;
|
|
9
|
+
"tui.editor.cursorRight": true;
|
|
10
|
+
"tui.editor.cursorUp": true;
|
|
11
|
+
"tui.editor.cursorWordLeft": true;
|
|
12
|
+
"tui.editor.cursorWordRight": true;
|
|
13
|
+
"tui.editor.deleteCharBackward": true;
|
|
14
|
+
"tui.editor.deleteCharForward": true;
|
|
15
|
+
"tui.editor.deleteToLineEnd": true;
|
|
16
|
+
"tui.editor.deleteToLineStart": true;
|
|
17
|
+
"tui.editor.deleteWordBackward": true;
|
|
18
|
+
"tui.editor.deleteWordForward": true;
|
|
19
|
+
"tui.editor.jumpBackward": true;
|
|
20
|
+
"tui.editor.jumpForward": true;
|
|
21
|
+
"tui.editor.pageDown": true;
|
|
22
|
+
"tui.editor.pageUp": true;
|
|
23
|
+
"tui.editor.undo": true;
|
|
24
|
+
"tui.editor.yank": true;
|
|
25
|
+
"tui.editor.yankPop": true;
|
|
26
|
+
"tui.input.copy": true;
|
|
27
|
+
"tui.input.newLine": true;
|
|
28
|
+
"tui.input.submit": true;
|
|
29
|
+
"tui.input.tab": true;
|
|
30
|
+
"tui.select.cancel": true;
|
|
31
|
+
"tui.select.confirm": true;
|
|
32
|
+
"tui.select.down": true;
|
|
33
|
+
"tui.select.pageDown": true;
|
|
34
|
+
"tui.select.pageUp": true;
|
|
35
|
+
"tui.select.up": true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const LEGACY_TO_MODERN_KEYBINDINGS = {
|
|
39
|
+
copy: "tui.input.copy",
|
|
40
|
+
cursorDown: "tui.editor.cursorDown",
|
|
41
|
+
cursorLeft: "tui.editor.cursorLeft",
|
|
42
|
+
cursorLineEnd: "tui.editor.cursorLineEnd",
|
|
43
|
+
cursorLineStart: "tui.editor.cursorLineStart",
|
|
44
|
+
cursorRight: "tui.editor.cursorRight",
|
|
45
|
+
cursorUp: "tui.editor.cursorUp",
|
|
46
|
+
cursorWordLeft: "tui.editor.cursorWordLeft",
|
|
47
|
+
cursorWordRight: "tui.editor.cursorWordRight",
|
|
48
|
+
deleteCharBackward: "tui.editor.deleteCharBackward",
|
|
49
|
+
deleteCharForward: "tui.editor.deleteCharForward",
|
|
50
|
+
deleteSession: "app.session.delete",
|
|
51
|
+
deleteSessionNoninvasive: "app.session.deleteNoninvasive",
|
|
52
|
+
deleteToLineEnd: "tui.editor.deleteToLineEnd",
|
|
53
|
+
deleteToLineStart: "tui.editor.deleteToLineStart",
|
|
54
|
+
deleteWordBackward: "tui.editor.deleteWordBackward",
|
|
55
|
+
deleteWordForward: "tui.editor.deleteWordForward",
|
|
56
|
+
expandTools: "app.tools.expand",
|
|
57
|
+
jumpBackward: "tui.editor.jumpBackward",
|
|
58
|
+
jumpForward: "tui.editor.jumpForward",
|
|
59
|
+
newLine: "tui.input.newLine",
|
|
60
|
+
pageDown: "tui.editor.pageDown",
|
|
61
|
+
pageUp: "tui.editor.pageUp",
|
|
62
|
+
renameSession: "app.session.rename",
|
|
63
|
+
selectCancel: "tui.select.cancel",
|
|
64
|
+
selectConfirm: "tui.select.confirm",
|
|
65
|
+
selectDown: "tui.select.down",
|
|
66
|
+
selectPageDown: "tui.select.pageDown",
|
|
67
|
+
selectPageUp: "tui.select.pageUp",
|
|
68
|
+
selectUp: "tui.select.up",
|
|
69
|
+
submit: "tui.input.submit",
|
|
70
|
+
tab: "tui.input.tab",
|
|
71
|
+
toggleSessionPath: "app.session.togglePath",
|
|
72
|
+
toggleSessionSort: "app.session.toggleSort",
|
|
73
|
+
undo: "tui.editor.undo",
|
|
74
|
+
yank: "tui.editor.yank",
|
|
75
|
+
yankPop: "tui.editor.yankPop",
|
|
76
|
+
} as const;
|
|
77
|
+
|
|
78
|
+
/** Backward-compatible legacy editor actions. */
|
|
79
|
+
export type EditorAction = keyof typeof LEGACY_TO_MODERN_KEYBINDINGS;
|
|
80
|
+
|
|
81
|
+
/** Modern keybinding identifier. */
|
|
82
|
+
export type Keybinding = keyof Keybindings | EditorAction;
|
|
83
|
+
|
|
84
|
+
/** Single keybinding definition with defaults and UI help text. */
|
|
85
|
+
export interface KeybindingDefinition {
|
|
86
|
+
readonly defaultKeys: KeyId | readonly KeyId[];
|
|
87
|
+
readonly description: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** User-provided keybinding overrides. */
|
|
91
|
+
export type KeybindingsConfig = Partial<Record<Keybinding, KeyId | readonly KeyId[]>>;
|
|
92
|
+
|
|
93
|
+
/** Backward-compatible legacy editor config. */
|
|
94
|
+
export type EditorKeybindingsConfig = Partial<Record<EditorAction, KeyId | readonly KeyId[]>>;
|
|
95
|
+
|
|
96
|
+
/** Default legacy editor keybindings preserved for compatibility. */
|
|
97
|
+
export const DEFAULT_EDITOR_KEYBINDINGS: Required<Record<EditorAction, KeyId | readonly KeyId[]>> =
|
|
98
|
+
{
|
|
99
|
+
copy: "ctrl+shift+c",
|
|
100
|
+
cursorDown: "down",
|
|
101
|
+
cursorLeft: ["left", "ctrl+b"],
|
|
102
|
+
cursorLineEnd: ["end", "ctrl+e"],
|
|
103
|
+
cursorLineStart: ["home", "ctrl+a"],
|
|
104
|
+
cursorRight: ["right", "ctrl+f"],
|
|
105
|
+
cursorUp: "up",
|
|
106
|
+
cursorWordLeft: ["alt+left", "ctrl+left", "alt+b"],
|
|
107
|
+
cursorWordRight: ["alt+right", "ctrl+right", "alt+f"],
|
|
108
|
+
deleteCharBackward: "backspace",
|
|
109
|
+
deleteCharForward: ["delete", "ctrl+d"],
|
|
110
|
+
deleteSession: "ctrl+d",
|
|
111
|
+
deleteSessionNoninvasive: "ctrl+backspace",
|
|
112
|
+
deleteToLineEnd: "ctrl+k",
|
|
113
|
+
deleteToLineStart: "ctrl+u",
|
|
114
|
+
deleteWordBackward: ["ctrl+w", "alt+backspace"],
|
|
115
|
+
deleteWordForward: ["alt+d", "alt+delete"],
|
|
116
|
+
expandTools: "ctrl+o",
|
|
117
|
+
jumpBackward: "ctrl+alt+]",
|
|
118
|
+
jumpForward: "ctrl+]",
|
|
119
|
+
newLine: "shift+enter",
|
|
120
|
+
pageDown: "pageDown",
|
|
121
|
+
pageUp: "pageUp",
|
|
122
|
+
renameSession: "ctrl+r",
|
|
123
|
+
selectCancel: ["escape", "ctrl+c"],
|
|
124
|
+
selectConfirm: "enter",
|
|
125
|
+
selectDown: "down",
|
|
126
|
+
selectPageDown: "pageDown",
|
|
127
|
+
selectPageUp: "pageUp",
|
|
128
|
+
selectUp: "up",
|
|
129
|
+
submit: "enter",
|
|
130
|
+
tab: "tab",
|
|
131
|
+
toggleSessionPath: "ctrl+p",
|
|
132
|
+
toggleSessionSort: "ctrl+s",
|
|
133
|
+
undo: "ctrl+-",
|
|
134
|
+
yank: "ctrl+y",
|
|
135
|
+
yankPop: "alt+y",
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
/** Modern TUI keybinding definitions consumed by pi-coding-agent 0.61+. */
|
|
139
|
+
export const TUI_KEYBINDINGS = {
|
|
140
|
+
"tui.editor.cursorDown": {
|
|
141
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.cursorDown,
|
|
142
|
+
description: "Move cursor down",
|
|
143
|
+
},
|
|
144
|
+
"tui.editor.cursorLeft": {
|
|
145
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.cursorLeft,
|
|
146
|
+
description: "Move cursor left",
|
|
147
|
+
},
|
|
148
|
+
"tui.editor.cursorLineEnd": {
|
|
149
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.cursorLineEnd,
|
|
150
|
+
description: "Move to line end",
|
|
151
|
+
},
|
|
152
|
+
"tui.editor.cursorLineStart": {
|
|
153
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.cursorLineStart,
|
|
154
|
+
description: "Move to line start",
|
|
155
|
+
},
|
|
156
|
+
"tui.editor.cursorRight": {
|
|
157
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.cursorRight,
|
|
158
|
+
description: "Move cursor right",
|
|
159
|
+
},
|
|
160
|
+
"tui.editor.cursorUp": {
|
|
161
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.cursorUp,
|
|
162
|
+
description: "Move cursor up",
|
|
163
|
+
},
|
|
164
|
+
"tui.editor.cursorWordLeft": {
|
|
165
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.cursorWordLeft,
|
|
166
|
+
description: "Move cursor word left",
|
|
167
|
+
},
|
|
168
|
+
"tui.editor.cursorWordRight": {
|
|
169
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.cursorWordRight,
|
|
170
|
+
description: "Move cursor word right",
|
|
171
|
+
},
|
|
172
|
+
"tui.editor.deleteCharBackward": {
|
|
173
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.deleteCharBackward,
|
|
174
|
+
description: "Delete character backward",
|
|
175
|
+
},
|
|
176
|
+
"tui.editor.deleteCharForward": {
|
|
177
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.deleteCharForward,
|
|
178
|
+
description: "Delete character forward",
|
|
179
|
+
},
|
|
180
|
+
"tui.editor.deleteToLineEnd": {
|
|
181
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.deleteToLineEnd,
|
|
182
|
+
description: "Delete to line end",
|
|
183
|
+
},
|
|
184
|
+
"tui.editor.deleteToLineStart": {
|
|
185
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.deleteToLineStart,
|
|
186
|
+
description: "Delete to line start",
|
|
187
|
+
},
|
|
188
|
+
"tui.editor.deleteWordBackward": {
|
|
189
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.deleteWordBackward,
|
|
190
|
+
description: "Delete word backward",
|
|
191
|
+
},
|
|
192
|
+
"tui.editor.deleteWordForward": {
|
|
193
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.deleteWordForward,
|
|
194
|
+
description: "Delete word forward",
|
|
195
|
+
},
|
|
196
|
+
"tui.editor.jumpBackward": {
|
|
197
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.jumpBackward,
|
|
198
|
+
description: "Jump backward to character",
|
|
199
|
+
},
|
|
200
|
+
"tui.editor.jumpForward": {
|
|
201
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.jumpForward,
|
|
202
|
+
description: "Jump forward to character",
|
|
203
|
+
},
|
|
204
|
+
"tui.editor.pageDown": {
|
|
205
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.pageDown,
|
|
206
|
+
description: "Page down",
|
|
207
|
+
},
|
|
208
|
+
"tui.editor.pageUp": {
|
|
209
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.pageUp,
|
|
210
|
+
description: "Page up",
|
|
211
|
+
},
|
|
212
|
+
"tui.editor.undo": {
|
|
213
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.undo,
|
|
214
|
+
description: "Undo",
|
|
215
|
+
},
|
|
216
|
+
"tui.editor.yank": {
|
|
217
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.yank,
|
|
218
|
+
description: "Yank",
|
|
219
|
+
},
|
|
220
|
+
"tui.editor.yankPop": {
|
|
221
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.yankPop,
|
|
222
|
+
description: "Yank pop",
|
|
223
|
+
},
|
|
224
|
+
"tui.input.copy": {
|
|
225
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.copy,
|
|
226
|
+
description: "Copy selection",
|
|
227
|
+
},
|
|
228
|
+
"tui.input.newLine": {
|
|
229
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.newLine,
|
|
230
|
+
description: "Insert newline",
|
|
231
|
+
},
|
|
232
|
+
"tui.input.submit": {
|
|
233
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.submit,
|
|
234
|
+
description: "Submit input",
|
|
235
|
+
},
|
|
236
|
+
"tui.input.tab": {
|
|
237
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.tab,
|
|
238
|
+
description: "Tab / autocomplete",
|
|
239
|
+
},
|
|
240
|
+
"tui.select.cancel": {
|
|
241
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.selectCancel,
|
|
242
|
+
description: "Cancel selection",
|
|
243
|
+
},
|
|
244
|
+
"tui.select.confirm": {
|
|
245
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.selectConfirm,
|
|
246
|
+
description: "Confirm selection",
|
|
247
|
+
},
|
|
248
|
+
"tui.select.down": {
|
|
249
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.selectDown,
|
|
250
|
+
description: "Move selection down",
|
|
251
|
+
},
|
|
252
|
+
"tui.select.pageDown": {
|
|
253
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.selectPageDown,
|
|
254
|
+
description: "Selection page down",
|
|
255
|
+
},
|
|
256
|
+
"tui.select.pageUp": {
|
|
257
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.selectPageUp,
|
|
258
|
+
description: "Selection page up",
|
|
259
|
+
},
|
|
260
|
+
"tui.select.up": {
|
|
261
|
+
defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.selectUp,
|
|
262
|
+
description: "Move selection up",
|
|
263
|
+
},
|
|
264
|
+
} as const satisfies Record<keyof Keybindings, KeybindingDefinition>;
|
|
265
|
+
|
|
266
|
+
type ModernKeybinding = keyof Keybindings;
|
|
267
|
+
|
|
268
|
+
type NormalizedKeybindingsConfig = Partial<Record<ModernKeybinding, readonly KeyId[]>>;
|
|
269
|
+
|
|
3
270
|
/**
|
|
4
|
-
*
|
|
271
|
+
* Check whether a keybinding name is a supported modern identifier.
|
|
272
|
+
*
|
|
273
|
+
* @param {string} keybinding - Candidate keybinding name.
|
|
274
|
+
* @returns {keybinding is ModernKeybinding} True when the keybinding exists.
|
|
5
275
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
| "deleteToLineEnd"
|
|
27
|
-
// Text input
|
|
28
|
-
| "newLine"
|
|
29
|
-
| "submit"
|
|
30
|
-
| "tab"
|
|
31
|
-
// Selection/autocomplete
|
|
32
|
-
| "selectUp"
|
|
33
|
-
| "selectDown"
|
|
34
|
-
| "selectPageUp"
|
|
35
|
-
| "selectPageDown"
|
|
36
|
-
| "selectConfirm"
|
|
37
|
-
| "selectCancel"
|
|
38
|
-
// Clipboard
|
|
39
|
-
| "copy"
|
|
40
|
-
// Kill ring
|
|
41
|
-
| "yank"
|
|
42
|
-
| "yankPop"
|
|
43
|
-
// Undo
|
|
44
|
-
| "undo"
|
|
45
|
-
// Tool output
|
|
46
|
-
| "expandTools"
|
|
47
|
-
// Session
|
|
48
|
-
| "toggleSessionPath"
|
|
49
|
-
| "toggleSessionSort"
|
|
50
|
-
| "renameSession"
|
|
51
|
-
| "deleteSession"
|
|
52
|
-
| "deleteSessionNoninvasive";
|
|
53
|
-
|
|
54
|
-
// Re-export KeyId from keys.ts
|
|
55
|
-
export type { KeyId };
|
|
276
|
+
function isModernKeybinding(keybinding: string): keybinding is ModernKeybinding {
|
|
277
|
+
return keybinding in TUI_KEYBINDINGS;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Normalize a legacy or modern keybinding identifier to the modern name.
|
|
282
|
+
* Only checks TUI_KEYBINDINGS and legacy mappings. For consumer-defined
|
|
283
|
+
* keybindings (e.g. app.*), use {@link KeybindingsManager.resolveKeybinding}.
|
|
284
|
+
*
|
|
285
|
+
* @param {Keybinding} keybinding - Keybinding identifier to normalize.
|
|
286
|
+
* @returns {ModernKeybinding | null} Modern keybinding or null when unsupported.
|
|
287
|
+
*/
|
|
288
|
+
function normalizeKeybinding(keybinding: Keybinding): ModernKeybinding | null {
|
|
289
|
+
if (isModernKeybinding(keybinding)) {
|
|
290
|
+
return keybinding;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const normalized = LEGACY_TO_MODERN_KEYBINDINGS[keybinding as EditorAction];
|
|
294
|
+
return normalized && isModernKeybinding(normalized) ? normalized : null;
|
|
295
|
+
}
|
|
56
296
|
|
|
57
297
|
/**
|
|
58
|
-
*
|
|
298
|
+
* Convert a raw keybinding value into an array form.
|
|
299
|
+
*
|
|
300
|
+
* @param {KeyId | readonly KeyId[]} value - Raw keybinding value.
|
|
301
|
+
* @returns {readonly KeyId[]} Normalized key array.
|
|
59
302
|
*/
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
303
|
+
function normalizeKeyArray(value: KeyId | readonly KeyId[]): readonly KeyId[] {
|
|
304
|
+
return Array.isArray(value) ? [...value] : [value as KeyId];
|
|
305
|
+
}
|
|
63
306
|
|
|
64
307
|
/**
|
|
65
|
-
*
|
|
308
|
+
* Normalize user bindings to modern identifiers and array values.
|
|
309
|
+
*
|
|
310
|
+
* @param {KeybindingsConfig} userBindings - Raw user bindings.
|
|
311
|
+
* @returns {NormalizedKeybindingsConfig} Normalized modern binding map.
|
|
66
312
|
*/
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
deleteCharForward: ["delete", "ctrl+d"],
|
|
84
|
-
deleteWordBackward: ["ctrl+w", "alt+backspace"],
|
|
85
|
-
deleteWordForward: ["alt+d", "alt+delete"],
|
|
86
|
-
deleteToLineStart: "ctrl+u",
|
|
87
|
-
deleteToLineEnd: "ctrl+k",
|
|
88
|
-
// Text input
|
|
89
|
-
newLine: "shift+enter",
|
|
90
|
-
submit: "enter",
|
|
91
|
-
tab: "tab",
|
|
92
|
-
// Selection/autocomplete
|
|
93
|
-
selectUp: "up",
|
|
94
|
-
selectDown: "down",
|
|
95
|
-
selectPageUp: "pageUp",
|
|
96
|
-
selectPageDown: "pageDown",
|
|
97
|
-
selectConfirm: "enter",
|
|
98
|
-
selectCancel: ["escape", "ctrl+c"],
|
|
99
|
-
// Clipboard (ctrl+c in editor is handled as selectCancel/interrupt, not copy)
|
|
100
|
-
copy: "ctrl+shift+c",
|
|
101
|
-
// Kill ring
|
|
102
|
-
yank: "ctrl+y",
|
|
103
|
-
yankPop: "alt+y",
|
|
104
|
-
// Undo
|
|
105
|
-
undo: "ctrl+-",
|
|
106
|
-
// Tool output
|
|
107
|
-
expandTools: "ctrl+o",
|
|
108
|
-
// Session
|
|
109
|
-
toggleSessionPath: "ctrl+p",
|
|
110
|
-
toggleSessionSort: "ctrl+s",
|
|
111
|
-
renameSession: "ctrl+r",
|
|
112
|
-
deleteSession: "ctrl+d",
|
|
113
|
-
deleteSessionNoninvasive: "ctrl+backspace",
|
|
114
|
-
};
|
|
313
|
+
function normalizeUserBindings(userBindings: KeybindingsConfig): NormalizedKeybindingsConfig {
|
|
314
|
+
const normalized: NormalizedKeybindingsConfig = {};
|
|
315
|
+
|
|
316
|
+
for (const [rawKey, rawValue] of Object.entries(userBindings)) {
|
|
317
|
+
if (rawValue === undefined) continue;
|
|
318
|
+
|
|
319
|
+
const key = rawKey as Keybinding;
|
|
320
|
+
const modernKey = normalizeKeybinding(key);
|
|
321
|
+
if (!modernKey) continue;
|
|
322
|
+
if (key !== modernKey && userBindings[modernKey] !== undefined) continue;
|
|
323
|
+
|
|
324
|
+
normalized[modernKey] = [...normalizeKeyArray(rawValue)];
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return normalized;
|
|
328
|
+
}
|
|
115
329
|
|
|
116
330
|
/**
|
|
117
|
-
*
|
|
331
|
+
* Keybinding manager compatible with pi-tui 0.61+ while preserving legacy names.
|
|
118
332
|
*/
|
|
119
|
-
export class
|
|
120
|
-
private
|
|
333
|
+
export class KeybindingsManager {
|
|
334
|
+
private readonly definitions: Readonly<Record<ModernKeybinding, KeybindingDefinition>>;
|
|
335
|
+
private readonly resolvedKeys = new Map<ModernKeybinding, KeyId[]>();
|
|
336
|
+
private userBindings: NormalizedKeybindingsConfig;
|
|
121
337
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
338
|
+
/**
|
|
339
|
+
* Create a keybindings manager.
|
|
340
|
+
*
|
|
341
|
+
* @param {Readonly<Record<ModernKeybinding, KeybindingDefinition>>} definitions - Keybinding definitions.
|
|
342
|
+
* @param {KeybindingsConfig} userBindings - Optional user overrides.
|
|
343
|
+
*/
|
|
344
|
+
constructor(
|
|
345
|
+
definitions: Readonly<Record<ModernKeybinding, KeybindingDefinition>> = TUI_KEYBINDINGS,
|
|
346
|
+
userBindings: KeybindingsConfig = {}
|
|
347
|
+
) {
|
|
348
|
+
this.definitions = definitions;
|
|
349
|
+
this.userBindings = this.normalizeUserBindingsWithDefinitions(userBindings);
|
|
350
|
+
this.rebuild();
|
|
125
351
|
}
|
|
126
352
|
|
|
127
|
-
|
|
128
|
-
|
|
353
|
+
/**
|
|
354
|
+
* Rebuild resolved bindings from defaults plus user overrides.
|
|
355
|
+
*
|
|
356
|
+
* @returns {void} Nothing.
|
|
357
|
+
*/
|
|
358
|
+
private rebuild(): void {
|
|
359
|
+
this.resolvedKeys.clear();
|
|
129
360
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
|
|
361
|
+
for (const [keybinding, definition] of Object.entries(this.definitions)) {
|
|
362
|
+
const modernKey = keybinding as ModernKeybinding;
|
|
363
|
+
const override = this.userBindings[modernKey];
|
|
364
|
+
const keys = override ?? normalizeKeyArray(definition.defaultKeys);
|
|
365
|
+
this.resolvedKeys.set(modernKey, [...keys]);
|
|
134
366
|
}
|
|
367
|
+
}
|
|
135
368
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
369
|
+
/**
|
|
370
|
+
* Resolve a keybinding name to its lookup key in resolvedKeys.
|
|
371
|
+
* Checks the TUI namespace and legacy names first, then falls back to
|
|
372
|
+
* a direct lookup in definitions/resolvedKeys for consumer-defined
|
|
373
|
+
* keybindings (e.g. app.* keybindings registered by pi-coding-agent).
|
|
374
|
+
*
|
|
375
|
+
* @param {string} keybinding - Keybinding identifier.
|
|
376
|
+
* @returns {ModernKeybinding | null} Resolved key or null when unknown.
|
|
377
|
+
*/
|
|
378
|
+
private resolveKeybinding(keybinding: string): ModernKeybinding | null {
|
|
379
|
+
const normalized = normalizeKeybinding(keybinding as Keybinding);
|
|
380
|
+
if (normalized) return normalized;
|
|
381
|
+
|
|
382
|
+
// Fall back to direct lookup for keybindings registered via definitions
|
|
383
|
+
// but outside the tui.* namespace (e.g. app.interrupt, app.clear).
|
|
384
|
+
// Check definitions first (available at construction) then resolvedKeys.
|
|
385
|
+
const asKey = keybinding as ModernKeybinding;
|
|
386
|
+
return asKey in this.definitions || this.resolvedKeys.has(asKey) ? asKey : null;
|
|
142
387
|
}
|
|
143
388
|
|
|
144
389
|
/**
|
|
145
|
-
* Check
|
|
390
|
+
* Check whether input matches a keybinding.
|
|
391
|
+
*
|
|
392
|
+
* @param {string} data - Raw terminal input.
|
|
393
|
+
* @param {Keybinding | string} keybinding - Keybinding identifier.
|
|
394
|
+
* @returns {boolean} True when the input matches.
|
|
146
395
|
*/
|
|
147
|
-
matches(data: string,
|
|
148
|
-
const
|
|
149
|
-
if (!
|
|
150
|
-
|
|
396
|
+
matches(data: string, keybinding: Keybinding | string): boolean {
|
|
397
|
+
const resolved = this.resolveKeybinding(keybinding as string);
|
|
398
|
+
if (!resolved) return false;
|
|
399
|
+
|
|
400
|
+
for (const key of this.resolvedKeys.get(resolved) ?? []) {
|
|
151
401
|
if (matchesKey(data, key)) return true;
|
|
152
402
|
}
|
|
153
403
|
return false;
|
|
154
404
|
}
|
|
155
405
|
|
|
156
406
|
/**
|
|
157
|
-
* Get keys bound to
|
|
407
|
+
* Get the keys currently bound to a keybinding.
|
|
408
|
+
*
|
|
409
|
+
* @param {Keybinding | string} keybinding - Keybinding identifier.
|
|
410
|
+
* @returns {KeyId[]} Resolved key list.
|
|
411
|
+
*/
|
|
412
|
+
getKeys(keybinding: Keybinding | string): KeyId[] {
|
|
413
|
+
const resolved = this.resolveKeybinding(keybinding as string);
|
|
414
|
+
return resolved ? [...(this.resolvedKeys.get(resolved) ?? [])] : [];
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Replace user bindings and rebuild the resolved map.
|
|
419
|
+
*
|
|
420
|
+
* @param {KeybindingsConfig} userBindings - New user bindings.
|
|
421
|
+
* @returns {void} Nothing.
|
|
422
|
+
*/
|
|
423
|
+
setUserBindings(userBindings: KeybindingsConfig): void {
|
|
424
|
+
this.userBindings = this.normalizeUserBindingsWithDefinitions(userBindings);
|
|
425
|
+
this.rebuild();
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Normalize user bindings using both TUI namespace and consumer definitions.
|
|
430
|
+
* This extends the module-level normalizeUserBindings to also accept
|
|
431
|
+
* keybinding names that exist in this.definitions (e.g. app.*).
|
|
432
|
+
*
|
|
433
|
+
* @param {KeybindingsConfig} userBindings - Raw user bindings.
|
|
434
|
+
* @returns {NormalizedKeybindingsConfig} Normalized modern binding map.
|
|
435
|
+
*/
|
|
436
|
+
private normalizeUserBindingsWithDefinitions(
|
|
437
|
+
userBindings: KeybindingsConfig
|
|
438
|
+
): NormalizedKeybindingsConfig {
|
|
439
|
+
const normalized: NormalizedKeybindingsConfig = {};
|
|
440
|
+
|
|
441
|
+
for (const [rawKey, rawValue] of Object.entries(userBindings)) {
|
|
442
|
+
if (rawValue === undefined) continue;
|
|
443
|
+
|
|
444
|
+
const resolved = this.resolveKeybinding(rawKey);
|
|
445
|
+
if (!resolved) continue;
|
|
446
|
+
if (rawKey !== resolved && userBindings[resolved] !== undefined) continue;
|
|
447
|
+
|
|
448
|
+
normalized[resolved] = [...normalizeKeyArray(rawValue)];
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
return normalized;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Get the fully resolved modern keybinding config.
|
|
456
|
+
*
|
|
457
|
+
* @returns {NormalizedKeybindingsConfig} Resolved keybinding config.
|
|
158
458
|
*/
|
|
159
|
-
|
|
160
|
-
|
|
459
|
+
getResolvedBindings(): NormalizedKeybindingsConfig {
|
|
460
|
+
const resolved: NormalizedKeybindingsConfig = {};
|
|
461
|
+
for (const [keybinding, keys] of this.resolvedKeys.entries()) {
|
|
462
|
+
resolved[keybinding] = [...keys];
|
|
463
|
+
}
|
|
464
|
+
return resolved;
|
|
161
465
|
}
|
|
466
|
+
}
|
|
162
467
|
|
|
468
|
+
/** Backward-compatible alias for legacy callers. */
|
|
469
|
+
export class EditorKeybindingsManager extends KeybindingsManager {
|
|
163
470
|
/**
|
|
164
|
-
*
|
|
471
|
+
* Create a legacy editor keybindings manager.
|
|
472
|
+
*
|
|
473
|
+
* @param {EditorKeybindingsConfig} config - Legacy editor keybinding overrides.
|
|
165
474
|
*/
|
|
166
|
-
|
|
167
|
-
|
|
475
|
+
constructor(config: EditorKeybindingsConfig = {}) {
|
|
476
|
+
super(TUI_KEYBINDINGS, config);
|
|
168
477
|
}
|
|
169
478
|
}
|
|
170
479
|
|
|
171
|
-
|
|
172
|
-
let globalEditorKeybindings: EditorKeybindingsManager | null = null;
|
|
480
|
+
let globalKeybindings: KeybindingsManager | null = null;
|
|
173
481
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
482
|
+
/**
|
|
483
|
+
* Get the shared keybindings manager.
|
|
484
|
+
*
|
|
485
|
+
* @returns {KeybindingsManager} Shared keybindings manager.
|
|
486
|
+
*/
|
|
487
|
+
export function getKeybindings(): KeybindingsManager {
|
|
488
|
+
if (!globalKeybindings) {
|
|
489
|
+
globalKeybindings = new EditorKeybindingsManager();
|
|
177
490
|
}
|
|
178
|
-
return
|
|
491
|
+
return globalKeybindings;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Replace the shared keybindings manager.
|
|
496
|
+
*
|
|
497
|
+
* @param {KeybindingsManager} manager - Keybindings manager to install.
|
|
498
|
+
* @returns {void} Nothing.
|
|
499
|
+
*/
|
|
500
|
+
export function setKeybindings(manager: KeybindingsManager): void {
|
|
501
|
+
globalKeybindings = manager;
|
|
179
502
|
}
|
|
180
503
|
|
|
504
|
+
/**
|
|
505
|
+
* Get the shared legacy editor keybindings manager.
|
|
506
|
+
*
|
|
507
|
+
* @returns {EditorKeybindingsManager} Shared legacy-compatible manager.
|
|
508
|
+
*/
|
|
509
|
+
export function getEditorKeybindings(): EditorKeybindingsManager {
|
|
510
|
+
return getKeybindings() as EditorKeybindingsManager;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Replace the shared legacy editor keybindings manager.
|
|
515
|
+
*
|
|
516
|
+
* @param {EditorKeybindingsManager} manager - Legacy keybindings manager.
|
|
517
|
+
* @returns {void} Nothing.
|
|
518
|
+
*/
|
|
181
519
|
export function setEditorKeybindings(manager: EditorKeybindingsManager): void {
|
|
182
|
-
|
|
520
|
+
setKeybindings(manager);
|
|
183
521
|
}
|