@dungle-scrubs/tallow 0.9.3 → 0.9.6

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 (207) hide show
  1. package/dist/cli.js +7 -4
  2. package/dist/cli.js.map +1 -1
  3. package/dist/config.d.ts +1 -1
  4. package/dist/config.js +1 -1
  5. package/dist/interactive-mode-patch.d.ts +24 -10
  6. package/dist/interactive-mode-patch.d.ts.map +1 -1
  7. package/dist/interactive-mode-patch.js +285 -148
  8. package/dist/interactive-mode-patch.js.map +1 -1
  9. package/dist/interactive-reset.d.ts +49 -0
  10. package/dist/interactive-reset.d.ts.map +1 -0
  11. package/dist/interactive-reset.js +40 -0
  12. package/dist/interactive-reset.js.map +1 -0
  13. package/dist/pi-tui-editor-patch.d.ts +10 -0
  14. package/dist/pi-tui-editor-patch.d.ts.map +1 -0
  15. package/dist/pi-tui-editor-patch.js +159 -0
  16. package/dist/pi-tui-editor-patch.js.map +1 -0
  17. package/dist/pi-tui-patch.d.ts +2 -0
  18. package/dist/pi-tui-patch.d.ts.map +1 -0
  19. package/dist/pi-tui-patch.js +563 -0
  20. package/dist/pi-tui-patch.js.map +1 -0
  21. package/dist/pi-tui-settings-list-patch.d.ts +11 -0
  22. package/dist/pi-tui-settings-list-patch.d.ts.map +1 -0
  23. package/dist/pi-tui-settings-list-patch.js +38 -0
  24. package/dist/pi-tui-settings-list-patch.js.map +1 -0
  25. package/dist/reset-diagnostics.d.ts +69 -0
  26. package/dist/reset-diagnostics.d.ts.map +1 -0
  27. package/dist/reset-diagnostics.js +41 -0
  28. package/dist/reset-diagnostics.js.map +1 -0
  29. package/dist/sdk.d.ts +5 -21
  30. package/dist/sdk.d.ts.map +1 -1
  31. package/dist/sdk.js +180 -149
  32. package/dist/sdk.js.map +1 -1
  33. package/dist/workspace-transition-interactive.d.ts +1 -0
  34. package/dist/workspace-transition-interactive.d.ts.map +1 -1
  35. package/dist/workspace-transition-interactive.js +7 -17
  36. package/dist/workspace-transition-interactive.js.map +1 -1
  37. package/extensions/__integration__/audit-findings.test.ts +6 -16
  38. package/extensions/__integration__/teams-runtime.test.ts +4 -1
  39. package/extensions/_icons/index.ts +2 -4
  40. package/extensions/_shared/__tests__/image-metadata.test.ts +33 -0
  41. package/extensions/_shared/__tests__/terminal-links.test.ts +18 -0
  42. package/extensions/_shared/image-metadata.ts +99 -0
  43. package/extensions/_shared/inline-preview.ts +1 -1
  44. package/extensions/_shared/pid-registry.ts +0 -1
  45. package/extensions/_shared/terminal-links.ts +22 -0
  46. package/extensions/ask-user-question-tool/index.ts +0 -3
  47. package/extensions/clear/__tests__/clear.test.ts +270 -3
  48. package/extensions/command-expansion/index.ts +1 -1
  49. package/extensions/context-files/index.ts +5 -1
  50. package/extensions/context-fork/__tests__/context-fork.test.ts +94 -1
  51. package/extensions/context-fork/extension.json +1 -1
  52. package/extensions/context-fork/index.ts +32 -0
  53. package/extensions/edit-tool-enhanced/index.ts +2 -1
  54. package/extensions/hooks/index.ts +33 -11
  55. package/extensions/loop/index.ts +14 -1
  56. package/extensions/lsp/index.ts +64 -13
  57. package/extensions/lsp/package.json +2 -2
  58. package/extensions/permissions/__tests__/permissions.test.ts +4 -4
  59. package/extensions/random-spinner/index.ts +7 -642
  60. package/extensions/read-tool-enhanced/index.ts +6 -8
  61. package/extensions/render-stabilizer/__tests__/render-stabilizer.test.ts +4 -5
  62. package/extensions/render-stabilizer/index.ts +6 -6
  63. package/extensions/show-system-prompt/__tests__/show-system-prompt.test.ts +1 -1
  64. package/extensions/slash-command-bridge/__tests__/slash-command-bridge.test.ts +26 -0
  65. package/extensions/slash-command-bridge/index.ts +14 -2
  66. package/extensions/subagent-tool/index.ts +1 -1
  67. package/extensions/subagent-tool/model-resolver.ts +274 -7
  68. package/extensions/tasks/__tests__/state-ui.test.ts +3 -3
  69. package/extensions/tasks/__tests__/widget-subagents.test.ts +2 -2
  70. package/extensions/tasks/commands/register-tasks-extension.ts +10 -10
  71. package/extensions/tasks/state/index.ts +1 -1
  72. package/extensions/tasks/ui/index.ts +2 -7
  73. package/extensions/teams-tool/tools/register-extension.ts +1 -3
  74. package/extensions/web-search-tool/index.ts +2 -1
  75. package/extensions/write-tool-enhanced/__tests__/write-tool-enhanced.test.ts +21 -6
  76. package/extensions/write-tool-enhanced/index.ts +2 -1
  77. package/node_modules/@mariozechner/pi-tui/README.md +56 -34
  78. package/node_modules/@mariozechner/pi-tui/dist/autocomplete.d.ts +18 -13
  79. package/node_modules/@mariozechner/pi-tui/dist/autocomplete.d.ts.map +1 -1
  80. package/node_modules/@mariozechner/pi-tui/dist/autocomplete.js +182 -113
  81. package/node_modules/@mariozechner/pi-tui/dist/autocomplete.js.map +1 -1
  82. package/node_modules/@mariozechner/pi-tui/dist/components/cancellable-loader.js +3 -3
  83. package/node_modules/@mariozechner/pi-tui/dist/components/cancellable-loader.js.map +1 -1
  84. package/node_modules/@mariozechner/pi-tui/dist/components/editor.d.ts +45 -36
  85. package/node_modules/@mariozechner/pi-tui/dist/components/editor.d.ts.map +1 -1
  86. package/node_modules/@mariozechner/pi-tui/dist/components/editor.js +489 -325
  87. package/node_modules/@mariozechner/pi-tui/dist/components/editor.js.map +1 -1
  88. package/node_modules/@mariozechner/pi-tui/dist/components/image.d.ts +1 -99
  89. package/node_modules/@mariozechner/pi-tui/dist/components/image.d.ts.map +1 -1
  90. package/node_modules/@mariozechner/pi-tui/dist/components/image.js +17 -192
  91. package/node_modules/@mariozechner/pi-tui/dist/components/image.js.map +1 -1
  92. package/node_modules/@mariozechner/pi-tui/dist/components/input.d.ts.map +1 -1
  93. package/node_modules/@mariozechner/pi-tui/dist/components/input.js +57 -60
  94. package/node_modules/@mariozechner/pi-tui/dist/components/input.js.map +1 -1
  95. package/node_modules/@mariozechner/pi-tui/dist/components/loader.d.ts +2 -69
  96. package/node_modules/@mariozechner/pi-tui/dist/components/loader.d.ts.map +1 -1
  97. package/node_modules/@mariozechner/pi-tui/dist/components/loader.js +5 -102
  98. package/node_modules/@mariozechner/pi-tui/dist/components/loader.js.map +1 -1
  99. package/node_modules/@mariozechner/pi-tui/dist/components/markdown.d.ts.map +1 -1
  100. package/node_modules/@mariozechner/pi-tui/dist/components/markdown.js +111 -53
  101. package/node_modules/@mariozechner/pi-tui/dist/components/markdown.js.map +1 -1
  102. package/node_modules/@mariozechner/pi-tui/dist/components/select-list.d.ts +19 -1
  103. package/node_modules/@mariozechner/pi-tui/dist/components/select-list.d.ts.map +1 -1
  104. package/node_modules/@mariozechner/pi-tui/dist/components/select-list.js +78 -67
  105. package/node_modules/@mariozechner/pi-tui/dist/components/select-list.js.map +1 -1
  106. package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.d.ts +0 -2
  107. package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.d.ts.map +1 -1
  108. package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.js +12 -23
  109. package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.js.map +1 -1
  110. package/node_modules/@mariozechner/pi-tui/dist/index.d.ts +8 -10
  111. package/node_modules/@mariozechner/pi-tui/dist/index.d.ts.map +1 -1
  112. package/node_modules/@mariozechner/pi-tui/dist/index.js +6 -9
  113. package/node_modules/@mariozechner/pi-tui/dist/index.js.map +1 -1
  114. package/node_modules/@mariozechner/pi-tui/dist/keybindings.d.ts +108 -238
  115. package/node_modules/@mariozechner/pi-tui/dist/keybindings.d.ts.map +1 -1
  116. package/node_modules/@mariozechner/pi-tui/dist/keybindings.js +108 -365
  117. package/node_modules/@mariozechner/pi-tui/dist/keybindings.js.map +1 -1
  118. package/node_modules/@mariozechner/pi-tui/dist/keys.d.ts +33 -48
  119. package/node_modules/@mariozechner/pi-tui/dist/keys.d.ts.map +1 -1
  120. package/node_modules/@mariozechner/pi-tui/dist/keys.js +239 -155
  121. package/node_modules/@mariozechner/pi-tui/dist/keys.js.map +1 -1
  122. package/node_modules/@mariozechner/pi-tui/dist/terminal-image.d.ts +14 -94
  123. package/node_modules/@mariozechner/pi-tui/dist/terminal-image.d.ts.map +1 -1
  124. package/node_modules/@mariozechner/pi-tui/dist/terminal-image.js +44 -186
  125. package/node_modules/@mariozechner/pi-tui/dist/terminal-image.js.map +1 -1
  126. package/node_modules/@mariozechner/pi-tui/dist/terminal.d.ts +13 -58
  127. package/node_modules/@mariozechner/pi-tui/dist/terminal.d.ts.map +1 -1
  128. package/node_modules/@mariozechner/pi-tui/dist/terminal.js +78 -111
  129. package/node_modules/@mariozechner/pi-tui/dist/terminal.js.map +1 -1
  130. package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts +24 -110
  131. package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts.map +1 -1
  132. package/node_modules/@mariozechner/pi-tui/dist/tui.js +188 -435
  133. package/node_modules/@mariozechner/pi-tui/dist/tui.js.map +1 -1
  134. package/node_modules/@mariozechner/pi-tui/dist/utils.d.ts +0 -18
  135. package/node_modules/@mariozechner/pi-tui/dist/utils.d.ts.map +1 -1
  136. package/node_modules/@mariozechner/pi-tui/dist/utils.js +251 -119
  137. package/node_modules/@mariozechner/pi-tui/dist/utils.js.map +1 -1
  138. package/node_modules/@mariozechner/pi-tui/package.json +6 -6
  139. package/node_modules/@mariozechner/pi-tui/src/__tests__/__snapshots__/render.test.ts.snap +3 -40
  140. package/node_modules/@mariozechner/pi-tui/src/__tests__/image-component.test.ts +71 -81
  141. package/node_modules/@mariozechner/pi-tui/src/__tests__/render.test.ts +0 -33
  142. package/node_modules/@mariozechner/pi-tui/src/__tests__/terminal-image.test.ts +93 -334
  143. package/node_modules/@mariozechner/pi-tui/src/__tests__/tui-render-scheduling.test.ts +1 -1
  144. package/node_modules/@mariozechner/pi-tui/src/__tests__/utils.test.ts +11 -196
  145. package/node_modules/@mariozechner/pi-tui/src/autocomplete.ts +228 -142
  146. package/node_modules/@mariozechner/pi-tui/src/components/cancellable-loader.ts +3 -3
  147. package/node_modules/@mariozechner/pi-tui/src/components/editor.ts +624 -390
  148. package/node_modules/@mariozechner/pi-tui/src/components/image.ts +17 -227
  149. package/node_modules/@mariozechner/pi-tui/src/components/input.ts +71 -63
  150. package/node_modules/@mariozechner/pi-tui/src/components/loader.ts +5 -137
  151. package/node_modules/@mariozechner/pi-tui/src/components/markdown.ts +143 -52
  152. package/node_modules/@mariozechner/pi-tui/src/components/select-list.ts +136 -70
  153. package/node_modules/@mariozechner/pi-tui/src/components/settings-list.ts +11 -23
  154. package/node_modules/@mariozechner/pi-tui/src/index.ts +17 -36
  155. package/node_modules/@mariozechner/pi-tui/src/keybindings.ts +148 -421
  156. package/node_modules/@mariozechner/pi-tui/src/keys.ts +253 -181
  157. package/node_modules/@mariozechner/pi-tui/src/terminal-image.ts +51 -252
  158. package/node_modules/@mariozechner/pi-tui/src/terminal.ts +78 -133
  159. package/node_modules/@mariozechner/pi-tui/src/tui.ts +202 -478
  160. package/node_modules/@mariozechner/pi-tui/src/utils.ts +289 -125
  161. package/node_modules/@mariozechner/pi-tui/tsconfig.build.json +1 -0
  162. package/package.json +13 -13
  163. package/packages/tallow-tui/node_modules/@types/mime-types/README.md +8 -2
  164. package/packages/tallow-tui/node_modules/@types/mime-types/index.d.ts +6 -0
  165. package/packages/tallow-tui/node_modules/@types/mime-types/package.json +9 -3
  166. package/packages/tallow-tui/node_modules/get-east-asian-width/lookup-data.js +18 -0
  167. package/packages/tallow-tui/node_modules/get-east-asian-width/lookup.js +116 -384
  168. package/packages/tallow-tui/node_modules/get-east-asian-width/package.json +5 -4
  169. package/packages/tallow-tui/node_modules/get-east-asian-width/utilities.js +24 -0
  170. package/packages/tallow-tui/node_modules/marked/README.md +5 -4
  171. package/packages/tallow-tui/node_modules/marked/bin/main.js +10 -8
  172. package/packages/tallow-tui/node_modules/marked/bin/marked.js +2 -1
  173. package/packages/tallow-tui/node_modules/marked/lib/marked.d.ts +156 -125
  174. package/packages/tallow-tui/node_modules/marked/lib/marked.esm.js +67 -2179
  175. package/packages/tallow-tui/node_modules/marked/lib/marked.esm.js.map +3 -3
  176. package/packages/tallow-tui/node_modules/marked/lib/marked.umd.js +67 -2201
  177. package/packages/tallow-tui/node_modules/marked/lib/marked.umd.js.map +3 -3
  178. package/packages/tallow-tui/node_modules/marked/man/marked.1 +4 -2
  179. package/packages/tallow-tui/node_modules/marked/man/marked.1.md +2 -1
  180. package/packages/tallow-tui/node_modules/marked/package.json +26 -34
  181. package/runtime/model-metadata-overrides.ts +10 -1
  182. package/runtime/pid-schema.ts +26 -6
  183. package/skills/tallow-expert/SKILL.md +1 -3
  184. package/node_modules/@mariozechner/pi-tui/dist/border-styles.d.ts +0 -32
  185. package/node_modules/@mariozechner/pi-tui/dist/border-styles.d.ts.map +0 -1
  186. package/node_modules/@mariozechner/pi-tui/dist/border-styles.js +0 -46
  187. package/node_modules/@mariozechner/pi-tui/dist/border-styles.js.map +0 -1
  188. package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.d.ts +0 -52
  189. package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.d.ts.map +0 -1
  190. package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.js +0 -89
  191. package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.js.map +0 -1
  192. package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.d.ts +0 -14
  193. package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.d.ts.map +0 -1
  194. package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.js +0 -55
  195. package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.js.map +0 -1
  196. package/node_modules/@mariozechner/pi-tui/src/__tests__/editor-change-listener.test.ts +0 -121
  197. package/node_modules/@mariozechner/pi-tui/src/__tests__/editor-ghost-text.test.ts +0 -112
  198. package/node_modules/@mariozechner/pi-tui/src/__tests__/mouse-events.test.ts +0 -134
  199. package/node_modules/@mariozechner/pi-tui/src/__tests__/settings-list.test.ts +0 -49
  200. package/node_modules/@mariozechner/pi-tui/src/__tests__/tui-diff-regression.test.ts +0 -555
  201. package/node_modules/@mariozechner/pi-tui/src/border-styles.ts +0 -60
  202. package/node_modules/@mariozechner/pi-tui/src/components/bordered-box.ts +0 -113
  203. package/node_modules/@mariozechner/pi-tui/src/test-utils/capability-env.ts +0 -56
  204. package/packages/tallow-tui/node_modules/marked/lib/marked.cjs +0 -2211
  205. package/packages/tallow-tui/node_modules/marked/lib/marked.cjs.map +0 -7
  206. package/packages/tallow-tui/node_modules/marked/lib/marked.d.cts +0 -728
  207. package/packages/tallow-tui/node_modules/marked/marked.min.js +0 -69
@@ -1,521 +1,248 @@
1
1
  import { type KeyId, matchesKey } from "./keys.js";
2
2
 
3
- /** Modern TUI keybinding identifiers. */
3
+ /**
4
+ * Global keybinding registry.
5
+ * Downstream packages can add keybindings via declaration merging.
6
+ */
4
7
  export interface Keybindings {
8
+ // Editor navigation and editing
9
+ "tui.editor.cursorUp": true;
5
10
  "tui.editor.cursorDown": true;
6
11
  "tui.editor.cursorLeft": true;
7
- "tui.editor.cursorLineEnd": true;
8
- "tui.editor.cursorLineStart": true;
9
12
  "tui.editor.cursorRight": true;
10
- "tui.editor.cursorUp": true;
11
13
  "tui.editor.cursorWordLeft": true;
12
14
  "tui.editor.cursorWordRight": true;
15
+ "tui.editor.cursorLineStart": true;
16
+ "tui.editor.cursorLineEnd": true;
17
+ "tui.editor.jumpForward": true;
18
+ "tui.editor.jumpBackward": true;
19
+ "tui.editor.pageUp": true;
20
+ "tui.editor.pageDown": true;
13
21
  "tui.editor.deleteCharBackward": true;
14
22
  "tui.editor.deleteCharForward": true;
15
- "tui.editor.deleteToLineEnd": true;
16
- "tui.editor.deleteToLineStart": true;
17
23
  "tui.editor.deleteWordBackward": true;
18
24
  "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;
25
+ "tui.editor.deleteToLineStart": true;
26
+ "tui.editor.deleteToLineEnd": true;
24
27
  "tui.editor.yank": true;
25
28
  "tui.editor.yankPop": true;
26
- "tui.input.copy": true;
29
+ "tui.editor.undo": true;
30
+ // Generic input actions
27
31
  "tui.input.newLine": true;
28
32
  "tui.input.submit": true;
29
33
  "tui.input.tab": true;
30
- "tui.select.cancel": true;
31
- "tui.select.confirm": true;
34
+ "tui.input.copy": true;
35
+ // Generic selection actions
36
+ "tui.select.up": true;
32
37
  "tui.select.down": true;
33
- "tui.select.pageDown": true;
34
38
  "tui.select.pageUp": true;
35
- "tui.select.up": true;
39
+ "tui.select.pageDown": true;
40
+ "tui.select.confirm": true;
41
+ "tui.select.cancel": true;
36
42
  }
37
43
 
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;
44
+ export type Keybinding = keyof Keybindings;
77
45
 
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
46
  export interface KeybindingDefinition {
86
- readonly defaultKeys: KeyId | readonly KeyId[];
87
- readonly description: string;
47
+ defaultKeys: KeyId | KeyId[];
48
+ description?: string;
88
49
  }
89
50
 
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
- };
51
+ export type KeybindingDefinitions = Record<string, KeybindingDefinition>;
52
+ export type KeybindingsConfig = Record<string, KeyId | KeyId[] | undefined>;
137
53
 
138
- /** Modern TUI keybinding definitions consumed by pi-coding-agent 0.61+. */
139
54
  export const TUI_KEYBINDINGS = {
140
- "tui.editor.cursorDown": {
141
- defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.cursorDown,
142
- description: "Move cursor down",
143
- },
55
+ "tui.editor.cursorUp": { defaultKeys: "up", description: "Move cursor up" },
56
+ "tui.editor.cursorDown": { defaultKeys: "down", description: "Move cursor down" },
144
57
  "tui.editor.cursorLeft": {
145
- defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.cursorLeft,
58
+ defaultKeys: ["left", "ctrl+b"],
146
59
  description: "Move cursor left",
147
60
  },
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
61
  "tui.editor.cursorRight": {
157
- defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.cursorRight,
62
+ defaultKeys: ["right", "ctrl+f"],
158
63
  description: "Move cursor right",
159
64
  },
160
- "tui.editor.cursorUp": {
161
- defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.cursorUp,
162
- description: "Move cursor up",
163
- },
164
65
  "tui.editor.cursorWordLeft": {
165
- defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.cursorWordLeft,
66
+ defaultKeys: ["alt+left", "ctrl+left", "alt+b"],
166
67
  description: "Move cursor word left",
167
68
  },
168
69
  "tui.editor.cursorWordRight": {
169
- defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.cursorWordRight,
70
+ defaultKeys: ["alt+right", "ctrl+right", "alt+f"],
170
71
  description: "Move cursor word right",
171
72
  },
73
+ "tui.editor.cursorLineStart": {
74
+ defaultKeys: ["home", "ctrl+a"],
75
+ description: "Move to line start",
76
+ },
77
+ "tui.editor.cursorLineEnd": {
78
+ defaultKeys: ["end", "ctrl+e"],
79
+ description: "Move to line end",
80
+ },
81
+ "tui.editor.jumpForward": {
82
+ defaultKeys: "ctrl+]",
83
+ description: "Jump forward to character",
84
+ },
85
+ "tui.editor.jumpBackward": {
86
+ defaultKeys: "ctrl+alt+]",
87
+ description: "Jump backward to character",
88
+ },
89
+ "tui.editor.pageUp": { defaultKeys: "pageUp", description: "Page up" },
90
+ "tui.editor.pageDown": { defaultKeys: "pageDown", description: "Page down" },
172
91
  "tui.editor.deleteCharBackward": {
173
- defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.deleteCharBackward,
92
+ defaultKeys: "backspace",
174
93
  description: "Delete character backward",
175
94
  },
176
95
  "tui.editor.deleteCharForward": {
177
- defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.deleteCharForward,
96
+ defaultKeys: ["delete", "ctrl+d"],
178
97
  description: "Delete character forward",
179
98
  },
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
99
  "tui.editor.deleteWordBackward": {
189
- defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.deleteWordBackward,
100
+ defaultKeys: ["ctrl+w", "alt+backspace"],
190
101
  description: "Delete word backward",
191
102
  },
192
103
  "tui.editor.deleteWordForward": {
193
- defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.deleteWordForward,
104
+ defaultKeys: ["alt+d", "alt+delete"],
194
105
  description: "Delete word forward",
195
106
  },
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",
107
+ "tui.editor.deleteToLineStart": {
108
+ defaultKeys: "ctrl+u",
109
+ description: "Delete to line start",
247
110
  },
248
- "tui.select.down": {
249
- defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.selectDown,
250
- description: "Move selection down",
111
+ "tui.editor.deleteToLineEnd": {
112
+ defaultKeys: "ctrl+k",
113
+ description: "Delete to line end",
251
114
  },
115
+ "tui.editor.yank": { defaultKeys: "ctrl+y", description: "Yank" },
116
+ "tui.editor.yankPop": { defaultKeys: "alt+y", description: "Yank pop" },
117
+ "tui.editor.undo": { defaultKeys: "ctrl+-", description: "Undo" },
118
+ "tui.input.newLine": { defaultKeys: "shift+enter", description: "Insert newline" },
119
+ "tui.input.submit": { defaultKeys: "enter", description: "Submit input" },
120
+ "tui.input.tab": { defaultKeys: "tab", description: "Tab / autocomplete" },
121
+ "tui.input.copy": { defaultKeys: "ctrl+c", description: "Copy selection" },
122
+ "tui.select.up": { defaultKeys: "up", description: "Move selection up" },
123
+ "tui.select.down": { defaultKeys: "down", description: "Move selection down" },
124
+ "tui.select.pageUp": { defaultKeys: "pageUp", description: "Selection page up" },
252
125
  "tui.select.pageDown": {
253
- defaultKeys: DEFAULT_EDITOR_KEYBINDINGS.selectPageDown,
126
+ defaultKeys: "pageDown",
254
127
  description: "Selection page down",
255
128
  },
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",
129
+ "tui.select.confirm": { defaultKeys: "enter", description: "Confirm selection" },
130
+ "tui.select.cancel": {
131
+ defaultKeys: ["escape", "ctrl+c"],
132
+ description: "Cancel selection",
263
133
  },
264
- } as const satisfies Record<keyof Keybindings, KeybindingDefinition>;
265
-
266
- type ModernKeybinding = keyof Keybindings;
267
-
268
- type NormalizedKeybindingsConfig = Partial<Record<ModernKeybinding, readonly KeyId[]>>;
269
-
270
- /**
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.
275
- */
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
- }
134
+ } as const satisfies KeybindingDefinitions;
296
135
 
297
- /**
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.
302
- */
303
- function normalizeKeyArray(value: KeyId | readonly KeyId[]): readonly KeyId[] {
304
- return Array.isArray(value) ? [...value] : [value as KeyId];
136
+ export interface KeybindingConflict {
137
+ key: KeyId;
138
+ keybindings: string[];
305
139
  }
306
140
 
307
- /**
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.
312
- */
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)];
141
+ function normalizeKeys(keys: KeyId | KeyId[] | undefined): KeyId[] {
142
+ if (keys === undefined) return [];
143
+ const keyList = Array.isArray(keys) ? keys : [keys];
144
+ const seen = new Set<KeyId>();
145
+ const result: KeyId[] = [];
146
+ for (const key of keyList) {
147
+ if (!seen.has(key)) {
148
+ seen.add(key);
149
+ result.push(key);
150
+ }
325
151
  }
326
-
327
- return normalized;
152
+ return result;
328
153
  }
329
154
 
330
- /**
331
- * Keybinding manager compatible with pi-tui 0.61+ while preserving legacy names.
332
- */
333
155
  export class KeybindingsManager {
334
- private readonly definitions: Readonly<Record<ModernKeybinding, KeybindingDefinition>>;
335
- private readonly resolvedKeys = new Map<ModernKeybinding, KeyId[]>();
336
- private userBindings: NormalizedKeybindingsConfig;
156
+ private definitions: KeybindingDefinitions;
157
+ private userBindings: KeybindingsConfig;
158
+ private keysById = new Map<Keybinding, KeyId[]>();
159
+ private conflicts: KeybindingConflict[] = [];
337
160
 
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
- ) {
161
+ constructor(definitions: KeybindingDefinitions, userBindings: KeybindingsConfig = {}) {
348
162
  this.definitions = definitions;
349
- this.userBindings = this.normalizeUserBindingsWithDefinitions(userBindings);
163
+ this.userBindings = userBindings;
350
164
  this.rebuild();
351
165
  }
352
166
 
353
- /**
354
- * Rebuild resolved bindings from defaults plus user overrides.
355
- *
356
- * @returns {void} Nothing.
357
- */
358
167
  private rebuild(): void {
359
- this.resolvedKeys.clear();
360
-
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]);
168
+ this.keysById.clear();
169
+ this.conflicts = [];
170
+
171
+ const userClaims = new Map<KeyId, Set<Keybinding>>();
172
+ for (const [keybinding, keys] of Object.entries(this.userBindings)) {
173
+ if (!(keybinding in this.definitions)) continue;
174
+ for (const key of normalizeKeys(keys)) {
175
+ const claimants = userClaims.get(key) ?? new Set<Keybinding>();
176
+ claimants.add(keybinding as Keybinding);
177
+ userClaims.set(key, claimants);
178
+ }
366
179
  }
367
- }
368
180
 
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;
181
+ for (const [key, keybindings] of userClaims) {
182
+ if (keybindings.size > 1) {
183
+ this.conflicts.push({ key, keybindings: [...keybindings] });
184
+ }
185
+ }
381
186
 
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;
187
+ for (const [id, definition] of Object.entries(this.definitions)) {
188
+ const userKeys = this.userBindings[id];
189
+ const keys =
190
+ userKeys === undefined ? normalizeKeys(definition.defaultKeys) : normalizeKeys(userKeys);
191
+ this.keysById.set(id as Keybinding, keys);
192
+ }
387
193
  }
388
194
 
389
- /**
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.
395
- */
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) ?? []) {
195
+ matches(data: string, keybinding: Keybinding): boolean {
196
+ const keys = this.keysById.get(keybinding) ?? [];
197
+ for (const key of keys) {
401
198
  if (matchesKey(data, key)) return true;
402
199
  }
403
200
  return false;
404
201
  }
405
202
 
406
- /**
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) ?? [])] : [];
203
+ getKeys(keybinding: Keybinding): KeyId[] {
204
+ return [...(this.keysById.get(keybinding) ?? [])];
415
205
  }
416
206
 
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();
207
+ getDefinition(keybinding: Keybinding): KeybindingDefinition {
208
+ return this.definitions[keybinding];
426
209
  }
427
210
 
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;
211
+ getConflicts(): KeybindingConflict[] {
212
+ return this.conflicts.map((conflict) => ({
213
+ ...conflict,
214
+ keybindings: [...conflict.keybindings],
215
+ }));
216
+ }
447
217
 
448
- normalized[resolved] = [...normalizeKeyArray(rawValue)];
449
- }
218
+ setUserBindings(userBindings: KeybindingsConfig): void {
219
+ this.userBindings = userBindings;
220
+ this.rebuild();
221
+ }
450
222
 
451
- return normalized;
223
+ getUserBindings(): KeybindingsConfig {
224
+ return { ...this.userBindings };
452
225
  }
453
226
 
454
- /**
455
- * Get the fully resolved modern keybinding config.
456
- *
457
- * @returns {NormalizedKeybindingsConfig} Resolved keybinding config.
458
- */
459
- getResolvedBindings(): NormalizedKeybindingsConfig {
460
- const resolved: NormalizedKeybindingsConfig = {};
461
- for (const [keybinding, keys] of this.resolvedKeys.entries()) {
462
- resolved[keybinding] = [...keys];
227
+ getResolvedBindings(): KeybindingsConfig {
228
+ const resolved: KeybindingsConfig = {};
229
+ for (const id of Object.keys(this.definitions)) {
230
+ const keys = this.keysById.get(id as Keybinding) ?? [];
231
+ resolved[id] = keys.length === 1 ? keys[0]! : [...keys];
463
232
  }
464
233
  return resolved;
465
234
  }
466
235
  }
467
236
 
468
- /** Backward-compatible alias for legacy callers. */
469
- export class EditorKeybindingsManager extends KeybindingsManager {
470
- /**
471
- * Create a legacy editor keybindings manager.
472
- *
473
- * @param {EditorKeybindingsConfig} config - Legacy editor keybinding overrides.
474
- */
475
- constructor(config: EditorKeybindingsConfig = {}) {
476
- super(TUI_KEYBINDINGS, config);
477
- }
478
- }
479
-
480
237
  let globalKeybindings: KeybindingsManager | null = null;
481
238
 
482
- /**
483
- * Get the shared keybindings manager.
484
- *
485
- * @returns {KeybindingsManager} Shared keybindings manager.
486
- */
239
+ export function setKeybindings(keybindings: KeybindingsManager): void {
240
+ globalKeybindings = keybindings;
241
+ }
242
+
487
243
  export function getKeybindings(): KeybindingsManager {
488
244
  if (!globalKeybindings) {
489
- globalKeybindings = new EditorKeybindingsManager();
245
+ globalKeybindings = new KeybindingsManager(TUI_KEYBINDINGS);
490
246
  }
491
247
  return globalKeybindings;
492
248
  }
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;
502
- }
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
- */
519
- export function setEditorKeybindings(manager: EditorKeybindingsManager): void {
520
- setKeybindings(manager);
521
- }