@dungle-scrubs/tallow 0.9.4 → 0.9.7

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 (212) hide show
  1. package/dist/cli.js +8 -5
  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 -12
  6. package/dist/interactive-mode-patch.d.ts.map +1 -1
  7. package/dist/interactive-mode-patch.js +229 -146
  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/process-cleanup.js +1 -1
  26. package/dist/process-cleanup.js.map +1 -1
  27. package/dist/reset-diagnostics.d.ts +69 -0
  28. package/dist/reset-diagnostics.d.ts.map +1 -0
  29. package/dist/reset-diagnostics.js +41 -0
  30. package/dist/reset-diagnostics.js.map +1 -0
  31. package/dist/sdk.d.ts +7 -23
  32. package/dist/sdk.d.ts.map +1 -1
  33. package/dist/sdk.js +211 -174
  34. package/dist/sdk.js.map +1 -1
  35. package/dist/workspace-transition-interactive.d.ts +1 -0
  36. package/dist/workspace-transition-interactive.d.ts.map +1 -1
  37. package/dist/workspace-transition-interactive.js +8 -18
  38. package/dist/workspace-transition-interactive.js.map +1 -1
  39. package/extensions/__integration__/audit-findings.test.ts +4 -5
  40. package/extensions/_icons/index.ts +2 -4
  41. package/extensions/_shared/__tests__/image-metadata.test.ts +33 -0
  42. package/extensions/_shared/__tests__/shell-policy.test.ts +19 -0
  43. package/extensions/_shared/__tests__/terminal-links.test.ts +18 -0
  44. package/extensions/_shared/image-metadata.ts +99 -0
  45. package/extensions/_shared/inline-preview.ts +1 -1
  46. package/extensions/_shared/shell-policy.ts +121 -1
  47. package/extensions/_shared/terminal-links.ts +22 -0
  48. package/extensions/ask-user-question-tool/index.ts +0 -3
  49. package/extensions/clear/__tests__/clear.test.ts +269 -2
  50. package/extensions/command-expansion/index.ts +9 -3
  51. package/extensions/context-files/index.ts +5 -1
  52. package/extensions/context-fork/__tests__/context-fork.test.ts +94 -1
  53. package/extensions/context-fork/extension.json +1 -1
  54. package/extensions/context-fork/frontmatter-index.ts +6 -1
  55. package/extensions/context-fork/index.ts +32 -0
  56. package/extensions/edit-tool-enhanced/index.ts +2 -1
  57. package/extensions/git-status/__tests__/git-status.test.ts +65 -2
  58. package/extensions/git-status/index.ts +268 -98
  59. package/extensions/hooks/index.ts +33 -11
  60. package/extensions/loop/index.ts +14 -1
  61. package/extensions/lsp/index.ts +64 -13
  62. package/extensions/lsp/package.json +2 -2
  63. package/extensions/minimal-skill-display/index.ts +7 -1
  64. package/extensions/random-spinner/index.ts +7 -642
  65. package/extensions/read-tool-enhanced/index.ts +13 -10
  66. package/extensions/render-stabilizer/__tests__/render-stabilizer.test.ts +2 -3
  67. package/extensions/render-stabilizer/index.ts +6 -6
  68. package/extensions/rewind/__tests__/session-files.test.ts +115 -0
  69. package/extensions/rewind/__tests__/snapshots.test.ts +23 -0
  70. package/extensions/rewind/index.ts +5 -0
  71. package/extensions/rewind/session-files.ts +138 -0
  72. package/extensions/rewind/snapshots.ts +104 -5
  73. package/extensions/skill-commands/index.ts +6 -1
  74. package/extensions/slash-command-bridge/__tests__/slash-command-bridge.test.ts +26 -0
  75. package/extensions/slash-command-bridge/index.ts +14 -2
  76. package/extensions/subagent-tool/model-resolver.ts +274 -7
  77. package/extensions/subagent-tool/schema.ts +1 -2
  78. package/extensions/tasks/commands/register-tasks-extension.ts +9 -9
  79. package/extensions/teams-tool/tools/register-extension.ts +1 -3
  80. package/extensions/teams-tool/tools/teammate-tools.ts +1 -2
  81. package/extensions/web-search-tool/index.ts +2 -1
  82. package/extensions/wezterm-pane-control/index.ts +1 -2
  83. package/extensions/write-tool-enhanced/index.ts +2 -1
  84. package/node_modules/@mariozechner/pi-tui/README.md +56 -34
  85. package/node_modules/@mariozechner/pi-tui/dist/autocomplete.d.ts +18 -13
  86. package/node_modules/@mariozechner/pi-tui/dist/autocomplete.d.ts.map +1 -1
  87. package/node_modules/@mariozechner/pi-tui/dist/autocomplete.js +182 -113
  88. package/node_modules/@mariozechner/pi-tui/dist/autocomplete.js.map +1 -1
  89. package/node_modules/@mariozechner/pi-tui/dist/components/cancellable-loader.js +3 -3
  90. package/node_modules/@mariozechner/pi-tui/dist/components/cancellable-loader.js.map +1 -1
  91. package/node_modules/@mariozechner/pi-tui/dist/components/editor.d.ts +45 -36
  92. package/node_modules/@mariozechner/pi-tui/dist/components/editor.d.ts.map +1 -1
  93. package/node_modules/@mariozechner/pi-tui/dist/components/editor.js +489 -325
  94. package/node_modules/@mariozechner/pi-tui/dist/components/editor.js.map +1 -1
  95. package/node_modules/@mariozechner/pi-tui/dist/components/image.d.ts +1 -99
  96. package/node_modules/@mariozechner/pi-tui/dist/components/image.d.ts.map +1 -1
  97. package/node_modules/@mariozechner/pi-tui/dist/components/image.js +17 -192
  98. package/node_modules/@mariozechner/pi-tui/dist/components/image.js.map +1 -1
  99. package/node_modules/@mariozechner/pi-tui/dist/components/input.d.ts.map +1 -1
  100. package/node_modules/@mariozechner/pi-tui/dist/components/input.js +57 -60
  101. package/node_modules/@mariozechner/pi-tui/dist/components/input.js.map +1 -1
  102. package/node_modules/@mariozechner/pi-tui/dist/components/loader.d.ts +2 -69
  103. package/node_modules/@mariozechner/pi-tui/dist/components/loader.d.ts.map +1 -1
  104. package/node_modules/@mariozechner/pi-tui/dist/components/loader.js +5 -102
  105. package/node_modules/@mariozechner/pi-tui/dist/components/loader.js.map +1 -1
  106. package/node_modules/@mariozechner/pi-tui/dist/components/markdown.d.ts.map +1 -1
  107. package/node_modules/@mariozechner/pi-tui/dist/components/markdown.js +111 -53
  108. package/node_modules/@mariozechner/pi-tui/dist/components/markdown.js.map +1 -1
  109. package/node_modules/@mariozechner/pi-tui/dist/components/select-list.d.ts +19 -1
  110. package/node_modules/@mariozechner/pi-tui/dist/components/select-list.d.ts.map +1 -1
  111. package/node_modules/@mariozechner/pi-tui/dist/components/select-list.js +78 -67
  112. package/node_modules/@mariozechner/pi-tui/dist/components/select-list.js.map +1 -1
  113. package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.d.ts +1 -25
  114. package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.d.ts.map +1 -1
  115. package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.js +13 -50
  116. package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.js.map +1 -1
  117. package/node_modules/@mariozechner/pi-tui/dist/index.d.ts +8 -10
  118. package/node_modules/@mariozechner/pi-tui/dist/index.d.ts.map +1 -1
  119. package/node_modules/@mariozechner/pi-tui/dist/index.js +6 -9
  120. package/node_modules/@mariozechner/pi-tui/dist/index.js.map +1 -1
  121. package/node_modules/@mariozechner/pi-tui/dist/keybindings.d.ts +108 -238
  122. package/node_modules/@mariozechner/pi-tui/dist/keybindings.d.ts.map +1 -1
  123. package/node_modules/@mariozechner/pi-tui/dist/keybindings.js +108 -365
  124. package/node_modules/@mariozechner/pi-tui/dist/keybindings.js.map +1 -1
  125. package/node_modules/@mariozechner/pi-tui/dist/keys.d.ts +33 -48
  126. package/node_modules/@mariozechner/pi-tui/dist/keys.d.ts.map +1 -1
  127. package/node_modules/@mariozechner/pi-tui/dist/keys.js +239 -155
  128. package/node_modules/@mariozechner/pi-tui/dist/keys.js.map +1 -1
  129. package/node_modules/@mariozechner/pi-tui/dist/terminal-image.d.ts +14 -94
  130. package/node_modules/@mariozechner/pi-tui/dist/terminal-image.d.ts.map +1 -1
  131. package/node_modules/@mariozechner/pi-tui/dist/terminal-image.js +44 -186
  132. package/node_modules/@mariozechner/pi-tui/dist/terminal-image.js.map +1 -1
  133. package/node_modules/@mariozechner/pi-tui/dist/terminal.d.ts +13 -58
  134. package/node_modules/@mariozechner/pi-tui/dist/terminal.d.ts.map +1 -1
  135. package/node_modules/@mariozechner/pi-tui/dist/terminal.js +78 -111
  136. package/node_modules/@mariozechner/pi-tui/dist/terminal.js.map +1 -1
  137. package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts +24 -110
  138. package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts.map +1 -1
  139. package/node_modules/@mariozechner/pi-tui/dist/tui.js +188 -435
  140. package/node_modules/@mariozechner/pi-tui/dist/tui.js.map +1 -1
  141. package/node_modules/@mariozechner/pi-tui/dist/utils.d.ts +0 -18
  142. package/node_modules/@mariozechner/pi-tui/dist/utils.d.ts.map +1 -1
  143. package/node_modules/@mariozechner/pi-tui/dist/utils.js +251 -119
  144. package/node_modules/@mariozechner/pi-tui/dist/utils.js.map +1 -1
  145. package/node_modules/@mariozechner/pi-tui/package.json +6 -6
  146. package/node_modules/@mariozechner/pi-tui/src/__tests__/__snapshots__/render.test.ts.snap +3 -40
  147. package/node_modules/@mariozechner/pi-tui/src/__tests__/image-component.test.ts +71 -81
  148. package/node_modules/@mariozechner/pi-tui/src/__tests__/render.test.ts +0 -33
  149. package/node_modules/@mariozechner/pi-tui/src/__tests__/terminal-image.test.ts +93 -334
  150. package/node_modules/@mariozechner/pi-tui/src/__tests__/tui-render-scheduling.test.ts +1 -1
  151. package/node_modules/@mariozechner/pi-tui/src/__tests__/utils.test.ts +11 -196
  152. package/node_modules/@mariozechner/pi-tui/src/autocomplete.ts +228 -142
  153. package/node_modules/@mariozechner/pi-tui/src/components/cancellable-loader.ts +3 -3
  154. package/node_modules/@mariozechner/pi-tui/src/components/editor.ts +624 -390
  155. package/node_modules/@mariozechner/pi-tui/src/components/image.ts +17 -227
  156. package/node_modules/@mariozechner/pi-tui/src/components/input.ts +71 -63
  157. package/node_modules/@mariozechner/pi-tui/src/components/loader.ts +5 -137
  158. package/node_modules/@mariozechner/pi-tui/src/components/markdown.ts +143 -52
  159. package/node_modules/@mariozechner/pi-tui/src/components/select-list.ts +136 -70
  160. package/node_modules/@mariozechner/pi-tui/src/components/settings-list.ts +12 -51
  161. package/node_modules/@mariozechner/pi-tui/src/index.ts +17 -36
  162. package/node_modules/@mariozechner/pi-tui/src/keybindings.ts +148 -421
  163. package/node_modules/@mariozechner/pi-tui/src/keys.ts +253 -181
  164. package/node_modules/@mariozechner/pi-tui/src/terminal-image.ts +51 -252
  165. package/node_modules/@mariozechner/pi-tui/src/terminal.ts +78 -133
  166. package/node_modules/@mariozechner/pi-tui/src/tui.ts +202 -478
  167. package/node_modules/@mariozechner/pi-tui/src/utils.ts +289 -125
  168. package/node_modules/@mariozechner/pi-tui/tsconfig.build.json +1 -0
  169. package/package.json +13 -13
  170. package/packages/tallow-tui/node_modules/@types/mime-types/README.md +8 -2
  171. package/packages/tallow-tui/node_modules/@types/mime-types/index.d.ts +6 -0
  172. package/packages/tallow-tui/node_modules/@types/mime-types/package.json +9 -3
  173. package/packages/tallow-tui/node_modules/get-east-asian-width/lookup-data.js +18 -0
  174. package/packages/tallow-tui/node_modules/get-east-asian-width/lookup.js +116 -384
  175. package/packages/tallow-tui/node_modules/get-east-asian-width/package.json +5 -4
  176. package/packages/tallow-tui/node_modules/get-east-asian-width/utilities.js +24 -0
  177. package/packages/tallow-tui/node_modules/marked/README.md +5 -4
  178. package/packages/tallow-tui/node_modules/marked/bin/main.js +10 -8
  179. package/packages/tallow-tui/node_modules/marked/bin/marked.js +2 -1
  180. package/packages/tallow-tui/node_modules/marked/lib/marked.d.ts +156 -125
  181. package/packages/tallow-tui/node_modules/marked/lib/marked.esm.js +67 -2179
  182. package/packages/tallow-tui/node_modules/marked/lib/marked.esm.js.map +3 -3
  183. package/packages/tallow-tui/node_modules/marked/lib/marked.umd.js +67 -2201
  184. package/packages/tallow-tui/node_modules/marked/lib/marked.umd.js.map +3 -3
  185. package/packages/tallow-tui/node_modules/marked/man/marked.1 +4 -2
  186. package/packages/tallow-tui/node_modules/marked/man/marked.1.md +2 -1
  187. package/packages/tallow-tui/node_modules/marked/package.json +26 -34
  188. package/skills/tallow-expert/SKILL.md +3 -5
  189. package/node_modules/@mariozechner/pi-tui/dist/border-styles.d.ts +0 -32
  190. package/node_modules/@mariozechner/pi-tui/dist/border-styles.d.ts.map +0 -1
  191. package/node_modules/@mariozechner/pi-tui/dist/border-styles.js +0 -46
  192. package/node_modules/@mariozechner/pi-tui/dist/border-styles.js.map +0 -1
  193. package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.d.ts +0 -52
  194. package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.d.ts.map +0 -1
  195. package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.js +0 -89
  196. package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.js.map +0 -1
  197. package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.d.ts +0 -14
  198. package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.d.ts.map +0 -1
  199. package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.js +0 -55
  200. package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.js.map +0 -1
  201. package/node_modules/@mariozechner/pi-tui/src/__tests__/editor-change-listener.test.ts +0 -121
  202. package/node_modules/@mariozechner/pi-tui/src/__tests__/editor-ghost-text.test.ts +0 -112
  203. package/node_modules/@mariozechner/pi-tui/src/__tests__/mouse-events.test.ts +0 -134
  204. package/node_modules/@mariozechner/pi-tui/src/__tests__/settings-list.test.ts +0 -81
  205. package/node_modules/@mariozechner/pi-tui/src/__tests__/tui-diff-regression.test.ts +0 -555
  206. package/node_modules/@mariozechner/pi-tui/src/border-styles.ts +0 -60
  207. package/node_modules/@mariozechner/pi-tui/src/components/bordered-box.ts +0 -113
  208. package/node_modules/@mariozechner/pi-tui/src/test-utils/capability-env.ts +0 -56
  209. package/packages/tallow-tui/node_modules/marked/lib/marked.cjs +0 -2211
  210. package/packages/tallow-tui/node_modules/marked/lib/marked.cjs.map +0 -7
  211. package/packages/tallow-tui/node_modules/marked/lib/marked.d.cts +0 -728
  212. package/packages/tallow-tui/node_modules/marked/marked.min.js +0 -69
@@ -1,112 +0,0 @@
1
- /**
2
- * Tests for Editor ghost text (inline suggestion) functionality.
3
- *
4
- * Uses a minimal TUI mock since Editor requires a TUI instance.
5
- */
6
- import { describe, expect, test } from "bun:test";
7
- import { Editor, type EditorTheme } from "../components/editor.js";
8
- import type { TUI } from "../tui.js";
9
-
10
- /** Minimal TUI mock providing only what Editor needs. */
11
- function createMockTUI(): TUI {
12
- return {
13
- requestRender: () => {},
14
- terminal: { rows: 40, cols: 80 },
15
- } as unknown as TUI;
16
- }
17
-
18
- const theme: EditorTheme = {
19
- borderColor: (s: string) => s,
20
- selectList: {
21
- selectedBg: (s: string) => s,
22
- selectedFg: (s: string) => s,
23
- normalBg: (s: string) => s,
24
- normalFg: (s: string) => s,
25
- matchHighlight: (s: string) => s,
26
- descriptionFg: (s: string) => s,
27
- },
28
- };
29
-
30
- describe("Editor ghost text", () => {
31
- test("setGhostText stores and getGhostText retrieves", () => {
32
- const editor = new Editor(createMockTUI(), theme);
33
- expect(editor.getGhostText()).toBeNull();
34
- editor.setGhostText("hello world");
35
- expect(editor.getGhostText()).toBe("hello world");
36
- });
37
-
38
- test("setGhostText(null) clears ghost text", () => {
39
- const editor = new Editor(createMockTUI(), theme);
40
- editor.setGhostText("suggestion");
41
- editor.setGhostText(null);
42
- expect(editor.getGhostText()).toBeNull();
43
- });
44
-
45
- test("ghost text renders as dim ANSI after cursor", () => {
46
- const editor = new Editor(createMockTUI(), theme);
47
- editor.setGhostText("complete me");
48
- const lines = editor.render(80);
49
- // Ghost text should appear as muted gray (256-color 242) in the output
50
- const joined = lines.join("\n");
51
- expect(joined).toContain("\x1b[38;5;242m");
52
- expect(joined).toContain("complete me");
53
- });
54
-
55
- test("ghost text cleared when character is typed", () => {
56
- const editor = new Editor(createMockTUI(), theme);
57
- editor.setGhostText("suggestion");
58
- editor.handleInput("a");
59
- expect(editor.getGhostText()).toBeNull();
60
- });
61
-
62
- test("ghost text cleared on backspace", () => {
63
- const editor = new Editor(createMockTUI(), theme);
64
- editor.setText("hello");
65
- editor.setGhostText("world");
66
- // Backspace (DEL character)
67
- editor.handleInput("\x7f");
68
- expect(editor.getGhostText()).toBeNull();
69
- });
70
-
71
- test("Tab accepts ghost text into buffer", () => {
72
- const editor = new Editor(createMockTUI(), theme);
73
- editor.setGhostText("complete me");
74
- // Tab
75
- editor.handleInput("\t");
76
- expect(editor.getGhostText()).toBeNull();
77
- expect(editor.getText()).toBe("complete me");
78
- });
79
-
80
- test("Enter on empty input accepts ghost text and submits", () => {
81
- const editor = new Editor(createMockTUI(), theme);
82
- let submitted = "";
83
- editor.onSubmit = (text: string) => {
84
- submitted = text;
85
- };
86
- editor.setGhostText("suggested prompt");
87
- // Enter (carriage return)
88
- editor.handleInput("\r");
89
- expect(submitted).toBe("suggested prompt");
90
- expect(editor.getGhostText()).toBeNull();
91
- });
92
-
93
- test("Enter on non-empty input submits typed text, not ghost text", () => {
94
- const editor = new Editor(createMockTUI(), theme);
95
- let submitted = "";
96
- editor.onSubmit = (text: string) => {
97
- submitted = text;
98
- };
99
- editor.setText("my input");
100
- editor.setGhostText("ghost suggestion");
101
- editor.handleInput("\r");
102
- expect(submitted).toBe("my input");
103
- });
104
-
105
- test("Escape dismisses ghost text", () => {
106
- const editor = new Editor(createMockTUI(), theme);
107
- editor.setGhostText("suggestion");
108
- // Escape
109
- editor.handleInput("\x1b");
110
- expect(editor.getGhostText()).toBeNull();
111
- });
112
- });
@@ -1,134 +0,0 @@
1
- /**
2
- * Tests for SGR mouse event parsing: parseMouseEvent and isMouseEvent.
3
- */
4
- import { describe, expect, it } from "bun:test";
5
- import { isMouseEvent, parseMouseEvent } from "../keys.js";
6
-
7
- // ── parseMouseEvent ──────────────────────────────────────────────────────────
8
-
9
- describe("parseMouseEvent", () => {
10
- it("parses scroll-up event", () => {
11
- // SGR: \x1b[<64;10;5M — code 64 = scroll up, col 10, row 5, press
12
- expect(parseMouseEvent("\x1b[<64;10;5M")).toEqual({
13
- type: "scroll-up",
14
- button: 0,
15
- x: 10,
16
- y: 5,
17
- });
18
- });
19
-
20
- it("parses scroll-down event", () => {
21
- // SGR: \x1b[<65;20;15M — code 65 = scroll down, col 20, row 15, press
22
- expect(parseMouseEvent("\x1b[<65;20;15M")).toEqual({
23
- type: "scroll-down",
24
- button: 0,
25
- x: 20,
26
- y: 15,
27
- });
28
- });
29
-
30
- it("parses left button press", () => {
31
- // SGR: \x1b[<0;5;3M — code 0 = left button, col 5, row 3, M = press
32
- expect(parseMouseEvent("\x1b[<0;5;3M")).toEqual({
33
- type: "press",
34
- button: 0,
35
- x: 5,
36
- y: 3,
37
- });
38
- });
39
-
40
- it("parses left button release", () => {
41
- // SGR: \x1b[<0;5;3m — code 0, lowercase m = release
42
- expect(parseMouseEvent("\x1b[<0;5;3m")).toEqual({
43
- type: "release",
44
- button: 0,
45
- x: 5,
46
- y: 3,
47
- });
48
- });
49
-
50
- it("parses middle button press", () => {
51
- // SGR: \x1b[<1;12;8M — code 1 = middle button
52
- expect(parseMouseEvent("\x1b[<1;12;8M")).toEqual({
53
- type: "press",
54
- button: 1,
55
- x: 12,
56
- y: 8,
57
- });
58
- });
59
-
60
- it("parses right button press", () => {
61
- // SGR: \x1b[<2;30;20M — code 2 = right button
62
- expect(parseMouseEvent("\x1b[<2;30;20M")).toEqual({
63
- type: "press",
64
- button: 2,
65
- x: 30,
66
- y: 20,
67
- });
68
- });
69
-
70
- it("parses drag event (bit 5 set)", () => {
71
- // SGR: \x1b[<32;15;10M — code 32 = motion + left button
72
- expect(parseMouseEvent("\x1b[<32;15;10M")).toEqual({
73
- type: "drag",
74
- button: 0,
75
- x: 15,
76
- y: 10,
77
- });
78
- });
79
-
80
- it("parses drag with right button", () => {
81
- // SGR: \x1b[<34;15;10M — code 34 = 32 (motion) + 2 (right)
82
- expect(parseMouseEvent("\x1b[<34;15;10M")).toEqual({
83
- type: "drag",
84
- button: 2,
85
- x: 15,
86
- y: 10,
87
- });
88
- });
89
-
90
- it("handles large coordinates (beyond 223-column limit)", () => {
91
- // SGR format supports arbitrary coordinates — this is why we use mode 1006
92
- expect(parseMouseEvent("\x1b[<0;300;150M")).toEqual({
93
- type: "press",
94
- button: 0,
95
- x: 300,
96
- y: 150,
97
- });
98
- });
99
-
100
- it("returns null for non-mouse input", () => {
101
- expect(parseMouseEvent("a")).toBeNull();
102
- expect(parseMouseEvent("\x1b[A")).toBeNull(); // arrow up
103
- expect(parseMouseEvent("\x1b[1;2H")).toBeNull(); // cursor position
104
- expect(parseMouseEvent("")).toBeNull();
105
- });
106
-
107
- it("returns null for malformed SGR sequences", () => {
108
- expect(parseMouseEvent("\x1b[<0;5M")).toBeNull(); // missing y
109
- expect(parseMouseEvent("\x1b[<0;5;3")).toBeNull(); // missing M/m terminator
110
- expect(parseMouseEvent("\x1b[<;5;3M")).toBeNull(); // missing code
111
- });
112
- });
113
-
114
- // ── isMouseEvent ─────────────────────────────────────────────────────────────
115
-
116
- describe("isMouseEvent", () => {
117
- it("returns true for SGR mouse sequences", () => {
118
- expect(isMouseEvent("\x1b[<0;5;3M")).toBe(true);
119
- expect(isMouseEvent("\x1b[<64;10;5M")).toBe(true);
120
- expect(isMouseEvent("\x1b[<0;300;150m")).toBe(true);
121
- });
122
-
123
- it("returns false for non-mouse input", () => {
124
- expect(isMouseEvent("a")).toBe(false);
125
- expect(isMouseEvent("\x1b[A")).toBe(false);
126
- expect(isMouseEvent("\x1b[1")).toBe(false);
127
- expect(isMouseEvent("")).toBe(false);
128
- });
129
-
130
- it("returns false for strings shorter than minimum mouse sequence", () => {
131
- // Minimum: \x1b[<N;N;NM = 9 chars
132
- expect(isMouseEvent("\x1b[<0;5;")).toBe(false);
133
- });
134
- });
@@ -1,81 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
- import { SettingsList, type SettingsListTheme } from "../components/settings-list.js";
3
-
4
- const theme: SettingsListTheme = {
5
- cursor: "> ",
6
- description: (text) => text,
7
- hint: (text) => text,
8
- label: (text) => text,
9
- value: (text) => text,
10
- };
11
-
12
- describe("SettingsList submenu transitions", () => {
13
- it("preserves submenu height for one frame when closing back to the main list", () => {
14
- let changedValue: string | undefined;
15
- const list = new SettingsList(
16
- [
17
- {
18
- id: "thinking",
19
- label: "Thinking level",
20
- currentValue: "medium",
21
- description: "Reasoning depth",
22
- submenu: (_currentValue, done) => ({
23
- handleInput: () => done("high"),
24
- invalidate: () => {},
25
- render: () => ["submenu", "", "one", "two", "three", "four", "five", "six"],
26
- }),
27
- },
28
- ],
29
- 10,
30
- theme,
31
- (_id, newValue) => {
32
- changedValue = newValue;
33
- },
34
- () => {}
35
- );
36
-
37
- const initialLines = list.render(80);
38
- list.handleInput(" ");
39
- const submenuLines = list.render(80);
40
- list.handleInput("x");
41
- const firstFrameAfterClose = list.render(80);
42
- const secondFrameAfterClose = list.render(80);
43
-
44
- expect(changedValue).toBe("high");
45
- expect(submenuLines.length).toBeGreaterThan(initialLines.length);
46
- expect(firstFrameAfterClose.length).toBe(submenuLines.length);
47
- expect(secondFrameAfterClose.length).toBe(initialLines.length);
48
- });
49
-
50
- it("fires the layout transition callback when opening and closing a submenu", () => {
51
- const list = new SettingsList(
52
- [
53
- {
54
- id: "thinking",
55
- label: "Thinking level",
56
- currentValue: "medium",
57
- submenu: (_currentValue, done) => ({
58
- handleInput: () => done("high"),
59
- invalidate: () => {},
60
- render: () => ["submenu", "one", "two"],
61
- }),
62
- },
63
- ],
64
- 10,
65
- theme,
66
- () => {},
67
- () => {}
68
- );
69
- const transitions: string[] = [];
70
- list.setLayoutTransitionCallback(() => {
71
- transitions.push("transition");
72
- });
73
-
74
- list.render(80);
75
- list.handleInput(" ");
76
- list.render(80);
77
- list.handleInput("x");
78
-
79
- expect(transitions).toEqual(["transition", "transition"]);
80
- });
81
- });