@abacus-ai/cli 2.0.0-canary.1 → 2.0.0-canary.11

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 (198) hide show
  1. package/README.md +25 -0
  2. package/dist/index.mjs +466 -438
  3. package/package.json +4 -1
  4. package/.oxlintrc.json +0 -8
  5. package/resources/abacus.ico +0 -0
  6. package/resources/entitlements.plist +0 -9
  7. package/src/__e2e__/README.md +0 -196
  8. package/src/__e2e__/agent-interactions.e2e.test.tsx +0 -61
  9. package/src/__e2e__/cli-commands.e2e.test.tsx +0 -77
  10. package/src/__e2e__/conversation-throttle.e2e.test.ts +0 -453
  11. package/src/__e2e__/conversation.e2e.test.tsx +0 -56
  12. package/src/__e2e__/diff-preview.e2e.test.tsx +0 -3399
  13. package/src/__e2e__/file-creation.e2e.test.tsx +0 -149
  14. package/src/__e2e__/helpers/test-helpers.ts +0 -449
  15. package/src/__e2e__/keyboard-navigation.e2e.test.tsx +0 -34
  16. package/src/__e2e__/llm-models.e2e.test.ts +0 -402
  17. package/src/__e2e__/mcp/mcp-callback-flow.e2e.test.tsx +0 -71
  18. package/src/__e2e__/mcp/mcp-full-app-ui.e2e.test.tsx +0 -167
  19. package/src/__e2e__/mcp/mcp-ui-rendering.e2e.test.tsx +0 -185
  20. package/src/__e2e__/repl.e2e.test.tsx +0 -78
  21. package/src/__e2e__/shell-compatibility.e2e.test.tsx +0 -76
  22. package/src/__e2e__/theme-mcp.e2e.test.tsx +0 -98
  23. package/src/__e2e__/tool-permissions.e2e.test.tsx +0 -66
  24. package/src/args.ts +0 -22
  25. package/src/components/__tests__/react-compiler.test.tsx +0 -78
  26. package/src/components/__tests__/status-indicator.test.tsx +0 -403
  27. package/src/components/composer/__tests__/bash-runner.test.tsx +0 -263
  28. package/src/components/composer/agent-mode-indicator.tsx +0 -63
  29. package/src/components/composer/bash-runner.tsx +0 -54
  30. package/src/components/composer/commands/default-commands.tsx +0 -615
  31. package/src/components/composer/commands/handler.tsx +0 -59
  32. package/src/components/composer/commands/picker.tsx +0 -273
  33. package/src/components/composer/commands/registry.ts +0 -233
  34. package/src/components/composer/commands/types.ts +0 -33
  35. package/src/components/composer/context.tsx +0 -88
  36. package/src/components/composer/file-mention-picker.tsx +0 -83
  37. package/src/components/composer/help.tsx +0 -44
  38. package/src/components/composer/index.tsx +0 -1007
  39. package/src/components/composer/mentions.ts +0 -57
  40. package/src/components/composer/message-queue.tsx +0 -70
  41. package/src/components/composer/mode-panel.tsx +0 -35
  42. package/src/components/composer/modes/__tests__/bash-handler.test.tsx +0 -755
  43. package/src/components/composer/modes/__tests__/bash-renderer.test.tsx +0 -1108
  44. package/src/components/composer/modes/bash-handler.tsx +0 -132
  45. package/src/components/composer/modes/bash-renderer.tsx +0 -175
  46. package/src/components/composer/modes/default-handlers.tsx +0 -33
  47. package/src/components/composer/modes/index.ts +0 -41
  48. package/src/components/composer/modes/types.ts +0 -21
  49. package/src/components/composer/persistent-shell.ts +0 -283
  50. package/src/components/composer/process.ts +0 -65
  51. package/src/components/composer/types.ts +0 -9
  52. package/src/components/composer/use-mention-search.ts +0 -68
  53. package/src/components/error-boundry.tsx +0 -60
  54. package/src/components/exit-message.tsx +0 -29
  55. package/src/components/expanded-view.tsx +0 -74
  56. package/src/components/file-completion.tsx +0 -127
  57. package/src/components/header.tsx +0 -47
  58. package/src/components/logo.tsx +0 -37
  59. package/src/components/segments.tsx +0 -356
  60. package/src/components/status-indicator.tsx +0 -306
  61. package/src/components/tool-group-summary.tsx +0 -263
  62. package/src/components/tool-permissions/ask-user-question-permission-ui.tsx +0 -319
  63. package/src/components/tool-permissions/diff-preview.tsx +0 -359
  64. package/src/components/tool-permissions/index.ts +0 -5
  65. package/src/components/tool-permissions/permission-options.tsx +0 -401
  66. package/src/components/tool-permissions/permission-preview-header.tsx +0 -57
  67. package/src/components/tool-permissions/tool-permission-ui.tsx +0 -420
  68. package/src/components/tools/agent/ask-user-question.tsx +0 -107
  69. package/src/components/tools/agent/enter-plan-mode.tsx +0 -55
  70. package/src/components/tools/agent/exit-plan-mode.tsx +0 -83
  71. package/src/components/tools/agent/handoff-to-main.tsx +0 -27
  72. package/src/components/tools/agent/subagent.tsx +0 -37
  73. package/src/components/tools/agent/todo-write.tsx +0 -104
  74. package/src/components/tools/browser/close-tab.tsx +0 -58
  75. package/src/components/tools/browser/computer.tsx +0 -70
  76. package/src/components/tools/browser/get-interactive-elements.tsx +0 -54
  77. package/src/components/tools/browser/get-tab-content.tsx +0 -51
  78. package/src/components/tools/browser/navigate-to.tsx +0 -59
  79. package/src/components/tools/browser/new-tab.tsx +0 -60
  80. package/src/components/tools/browser/perform-action.tsx +0 -63
  81. package/src/components/tools/browser/refresh-tab.tsx +0 -43
  82. package/src/components/tools/browser/switch-tab.tsx +0 -58
  83. package/src/components/tools/filesystem/delete-file.tsx +0 -104
  84. package/src/components/tools/filesystem/edit.tsx +0 -220
  85. package/src/components/tools/filesystem/list-dir.tsx +0 -78
  86. package/src/components/tools/filesystem/read-file.tsx +0 -180
  87. package/src/components/tools/filesystem/upload-image.tsx +0 -76
  88. package/src/components/tools/ide/ide-diagnostics.tsx +0 -62
  89. package/src/components/tools/index.ts +0 -91
  90. package/src/components/tools/mcp/mcp-tool.tsx +0 -158
  91. package/src/components/tools/search/fetch-url.tsx +0 -73
  92. package/src/components/tools/search/file-search.tsx +0 -78
  93. package/src/components/tools/search/grep.tsx +0 -90
  94. package/src/components/tools/search/semantic-search.tsx +0 -66
  95. package/src/components/tools/search/web-search.tsx +0 -71
  96. package/src/components/tools/shared/index.tsx +0 -48
  97. package/src/components/tools/shared/zod-coercion.ts +0 -35
  98. package/src/components/tools/terminal/bash-tool-output.tsx +0 -188
  99. package/src/components/tools/terminal/get-terminal-output.tsx +0 -91
  100. package/src/components/tools/terminal/run-in-terminal.tsx +0 -131
  101. package/src/components/tools/types.ts +0 -16
  102. package/src/components/tools.tsx +0 -68
  103. package/src/components/ui/__tests__/divider.test.tsx +0 -61
  104. package/src/components/ui/__tests__/gradient.test.tsx +0 -125
  105. package/src/components/ui/__tests__/input.test.tsx +0 -166
  106. package/src/components/ui/__tests__/select.test.tsx +0 -273
  107. package/src/components/ui/__tests__/shimmer.test.tsx +0 -99
  108. package/src/components/ui/blinking-indicator.tsx +0 -27
  109. package/src/components/ui/divider.tsx +0 -162
  110. package/src/components/ui/gradient.tsx +0 -56
  111. package/src/components/ui/input.tsx +0 -228
  112. package/src/components/ui/select.tsx +0 -151
  113. package/src/components/ui/shimmer.tsx +0 -76
  114. package/src/context/agent-mode.tsx +0 -95
  115. package/src/context/extension-file.tsx +0 -136
  116. package/src/context/network-activity.tsx +0 -45
  117. package/src/context/notification.tsx +0 -62
  118. package/src/context/shell-size.tsx +0 -49
  119. package/src/context/shell-title.tsx +0 -38
  120. package/src/entrypoints/print-mode.ts +0 -312
  121. package/src/entrypoints/repl.tsx +0 -389
  122. package/src/hooks/use-agent.ts +0 -15
  123. package/src/hooks/use-api-client.ts +0 -1
  124. package/src/hooks/use-available-height.ts +0 -8
  125. package/src/hooks/use-cleanup.ts +0 -29
  126. package/src/hooks/use-interrupt-manager.ts +0 -242
  127. package/src/hooks/use-models.ts +0 -22
  128. package/src/index.ts +0 -217
  129. package/src/lib/__tests__/ansi.test.ts +0 -255
  130. package/src/lib/__tests__/cli.test.ts +0 -122
  131. package/src/lib/__tests__/commands.test.ts +0 -325
  132. package/src/lib/__tests__/constants.test.ts +0 -15
  133. package/src/lib/__tests__/focusables.test.ts +0 -25
  134. package/src/lib/__tests__/fs.test.ts +0 -231
  135. package/src/lib/__tests__/markdown.test.tsx +0 -348
  136. package/src/lib/__tests__/mcpCommandHandler.test.ts +0 -173
  137. package/src/lib/__tests__/mcpManagement.test.ts +0 -38
  138. package/src/lib/__tests__/path-paste.test.ts +0 -144
  139. package/src/lib/__tests__/path.test.ts +0 -300
  140. package/src/lib/__tests__/queries.test.ts +0 -39
  141. package/src/lib/__tests__/standaloneMcpService.test.ts +0 -71
  142. package/src/lib/__tests__/text-buffer.test.ts +0 -328
  143. package/src/lib/__tests__/text-utils.test.ts +0 -32
  144. package/src/lib/__tests__/timing.test.ts +0 -78
  145. package/src/lib/__tests__/utils.test.ts +0 -238
  146. package/src/lib/__tests__/vim-buffer-actions.test.ts +0 -154
  147. package/src/lib/ansi.ts +0 -150
  148. package/src/lib/cli-push-server.ts +0 -112
  149. package/src/lib/cli.ts +0 -44
  150. package/src/lib/clipboard.ts +0 -226
  151. package/src/lib/command-utils.ts +0 -93
  152. package/src/lib/commands.ts +0 -270
  153. package/src/lib/constants.ts +0 -3
  154. package/src/lib/extension-connection.ts +0 -181
  155. package/src/lib/focusables.ts +0 -7
  156. package/src/lib/fs.ts +0 -533
  157. package/src/lib/markdown/code-block.tsx +0 -63
  158. package/src/lib/markdown/index.ts +0 -4
  159. package/src/lib/markdown/link.tsx +0 -19
  160. package/src/lib/markdown/markdown.tsx +0 -372
  161. package/src/lib/markdown/types.ts +0 -15
  162. package/src/lib/mcpCommandHandler.ts +0 -121
  163. package/src/lib/mcpManagement.ts +0 -44
  164. package/src/lib/path-paste.ts +0 -185
  165. package/src/lib/path.ts +0 -179
  166. package/src/lib/queries.ts +0 -15
  167. package/src/lib/standaloneMcpService.ts +0 -688
  168. package/src/lib/status-utils.ts +0 -237
  169. package/src/lib/test-utils.tsx +0 -72
  170. package/src/lib/text-buffer.ts +0 -2415
  171. package/src/lib/text-utils.ts +0 -272
  172. package/src/lib/timing.ts +0 -63
  173. package/src/lib/types.ts +0 -295
  174. package/src/lib/utils.ts +0 -182
  175. package/src/lib/vim-buffer-actions.ts +0 -732
  176. package/src/providers/agent.tsx +0 -1063
  177. package/src/providers/api-client.tsx +0 -43
  178. package/src/services/logger.ts +0 -85
  179. package/src/terminal/detection.ts +0 -187
  180. package/src/terminal/exit.ts +0 -279
  181. package/src/terminal/notification.ts +0 -83
  182. package/src/terminal/progress.ts +0 -201
  183. package/src/terminal/setup.ts +0 -797
  184. package/src/terminal/types.ts +0 -51
  185. package/src/theme/context.tsx +0 -57
  186. package/src/theme/index.ts +0 -4
  187. package/src/theme/themed.tsx +0 -35
  188. package/src/theme/themes.json +0 -546
  189. package/src/theme/types.ts +0 -110
  190. package/src/tools/types.ts +0 -59
  191. package/src/tools/utils/__tests__/zod-coercion.test.ts +0 -33
  192. package/src/tools/utils/tool-ui-components.tsx +0 -649
  193. package/src/tools/utils/zod-coercion.ts +0 -35
  194. package/tsconfig.json +0 -16
  195. package/tsconfig.node.json +0 -29
  196. package/tsconfig.test.json +0 -27
  197. package/tsdown.config.ts +0 -17
  198. package/vitest.config.ts +0 -76
@@ -1,125 +0,0 @@
1
- import { Text } from "@codellm/jar";
2
- import stripAnsi from "strip-ansi";
3
- import { describe, expect } from "vitest";
4
-
5
- // TODO: re-enable when jar testing utilities are available
6
- import { render, logInk, cleanup } from "../../../lib/test-utils.js";
7
- import { Gradient } from "../gradient.js";
8
-
9
- describe.concurrent("Gradient", () => {
10
- afterEach(() => {
11
- cleanup();
12
- });
13
-
14
- it("should render text with a named gradient", () => {
15
- const instance = render(
16
- <Gradient name="rainbow">
17
- <Text>Hello World</Text>
18
- </Gradient>,
19
- );
20
-
21
- logInk(instance);
22
-
23
- const output = instance.frames.join("");
24
- const plainText = "Hello World";
25
-
26
- expect(output).toBeDefined();
27
- expect(typeof output).toBe("string");
28
- // The gradient should apply ANSI color codes to the text
29
- expect(stripAnsi(output)).toContain(plainText);
30
- // Verify that ANSI codes are present (output should be longer than plain text)
31
- expect(output.length).toBeGreaterThan(plainText.length);
32
- // Verify ANSI escape sequences are present (should contain escape character)
33
- expect(output).toMatch(new RegExp(String.fromCharCode(27) + "\\["));
34
- });
35
-
36
- it("should render text with custom colors", () => {
37
- const instance = render(
38
- <Gradient colors={["#ff0000", "#0000ff"]}>
39
- <Text>Test Text</Text>
40
- </Gradient>,
41
- );
42
-
43
- logInk(instance);
44
-
45
- const output = instance.frames.join("");
46
- const plainText = "Test Text";
47
-
48
- expect(output).toBeDefined();
49
- expect(stripAnsi(output)).toContain(plainText);
50
- // Verify that ANSI codes are present (output should be longer than plain text)
51
- expect(output.length).toBeGreaterThan(plainText.length);
52
- // Verify ANSI escape sequences are present
53
- expect(output).toMatch(new RegExp(String.fromCharCode(27) + "\\["));
54
- });
55
-
56
- const gradientNames = [
57
- "atlas",
58
- "cristal",
59
- "teen",
60
- "mind",
61
- "morning",
62
- "vice",
63
- "passion",
64
- "fruit",
65
- "instagram",
66
- "retro",
67
- "summer",
68
- "pastel",
69
- "rainbow",
70
- ] as const;
71
- for (const name of gradientNames) {
72
- it(`should handle gradient name: ${name}`, () => {
73
- const instance = render(
74
- <Gradient name={name}>
75
- <Text>Test Text</Text>
76
- </Gradient>,
77
- );
78
-
79
- logInk(instance);
80
-
81
- const output = instance.frames.join("");
82
- const plainText = "Test Text";
83
-
84
- expect(output).toBeDefined();
85
- expect(stripAnsi(output)).toContain(plainText);
86
- // Verify that ANSI codes are present
87
- expect(output.length).toBeGreaterThan(plainText.length);
88
- expect(output).toMatch(new RegExp(String.fromCharCode(27) + "\\["));
89
- });
90
- }
91
-
92
- it("should handle multiline text", () => {
93
- const instance = render(
94
- <Gradient name="rainbow">
95
- <Text>Line 1{"\n"}Line 2</Text>
96
- </Gradient>,
97
- );
98
-
99
- logInk(instance);
100
-
101
- const output = instance.frames.join("");
102
-
103
- expect(output).toBeDefined();
104
- expect(stripAnsi(output)).toContain("Line 1");
105
- expect(stripAnsi(output)).toContain("Line 2");
106
- // Verify that ANSI codes are present
107
- expect(output).toMatch(new RegExp(String.fromCharCode(27) + "\\["));
108
- });
109
-
110
- it("should handle empty text", () => {
111
- const instance = render(
112
- <Gradient name="rainbow">
113
- <Text></Text>
114
- </Gradient>,
115
- );
116
-
117
- logInk(instance);
118
-
119
- const output = instance.frames.join("");
120
-
121
- expect(output).toBeDefined();
122
- // Empty text should still be valid (may or may not have ANSI codes)
123
- expect(typeof output).toBe("string");
124
- });
125
- });
@@ -1,166 +0,0 @@
1
- import { createRef } from "react";
2
- import { describe, expect, it, vi } from "vitest";
3
-
4
- import { stripAnsi } from "../../../lib/ansi.js";
5
- import { render, logInk, cleanup } from "../../../lib/test-utils.js";
6
- import { Input } from "../input.js";
7
-
8
- describe.concurrent("Input", () => {
9
- const TestWrapper = ({ children }: React.PropsWithChildren) => <>{children}</>;
10
-
11
- afterEach(() => {
12
- cleanup();
13
- });
14
-
15
- it("should render with placeholder", () => {
16
- const instance = render(
17
- <TestWrapper>
18
- <Input placeholder="Enter text..." />
19
- </TestWrapper>,
20
- );
21
-
22
- logInk(instance);
23
-
24
- const output = stripAnsi(instance.frames.join(""));
25
-
26
- expect(output).toBeDefined();
27
- expect(typeof output).toBe("string");
28
- expect(output).toContain("Enter text...");
29
- });
30
-
31
- it("should render with initial value", () => {
32
- const instance = render(
33
- <TestWrapper>
34
- <Input initialValue="Hello" />
35
- </TestWrapper>,
36
- );
37
-
38
- logInk(instance);
39
-
40
- const output = stripAnsi(instance.frames.join(""));
41
-
42
- expect(output).toBeDefined();
43
- expect(output).toContain("Hello");
44
- });
45
-
46
- it("should call onChange when value changes", () => {
47
- const onChange = vi.fn();
48
- render(
49
- <TestWrapper>
50
- <Input onChange={onChange} />
51
- </TestWrapper>,
52
- );
53
-
54
- // Note: Testing actual keypress events would require more complex setup
55
- // This test verifies the component renders correctly with the onChange prop
56
- expect(onChange).toBeDefined();
57
- });
58
-
59
- it("should call onSubmit when enter is pressed", () => {
60
- const onSubmit = vi.fn();
61
- render(
62
- <TestWrapper>
63
- <Input initialValue="test" onSubmit={onSubmit} />
64
- </TestWrapper>,
65
- );
66
-
67
- // Note: Testing actual keypress events would require more complex setup
68
- // This test verifies the component renders correctly with the onSubmit prop
69
- expect(onSubmit).toBeDefined();
70
- });
71
-
72
- it("should handle ref", () => {
73
- const ref = createRef<any>();
74
- render(
75
- <TestWrapper>
76
- <Input ref={ref} />
77
- </TestWrapper>,
78
- );
79
-
80
- // The ref should be set after render
81
- expect(ref.current).toBeDefined();
82
- });
83
-
84
- it("should render with custom placeholder props", () => {
85
- const instance = render(
86
- <TestWrapper>
87
- <Input placeholder="Custom" placeholderProps={{ color: "blue" }} />
88
- </TestWrapper>,
89
- );
90
-
91
- logInk(instance);
92
-
93
- const output = stripAnsi(instance.frames.join(""));
94
-
95
- expect(output).toBeDefined();
96
- expect(output).toContain("Custom");
97
- });
98
-
99
- it("should handle disabled state", () => {
100
- const instance = render(
101
- <TestWrapper>
102
- <Input disabled placeholder="Disabled input" />
103
- </TestWrapper>,
104
- );
105
-
106
- logInk(instance);
107
-
108
- const output = stripAnsi(instance.frames.join(""));
109
-
110
- expect(output).toBeDefined();
111
- expect(output).toContain("Disabled input");
112
- });
113
-
114
- it("should handle grammar highlighting", () => {
115
- const grammar = [
116
- { regex: /\d+/g, color: "red" },
117
- { regex: /[a-z]+/g, color: "blue" },
118
- ];
119
-
120
- const instance = render(
121
- <TestWrapper>
122
- <Input initialValue="test123" grammar={grammar} />
123
- </TestWrapper>,
124
- );
125
-
126
- logInk(instance);
127
-
128
- const output = stripAnsi(instance.frames.join(""));
129
-
130
- expect(output).toBeDefined();
131
- expect(output).toContain("test");
132
- expect(output).toContain("123");
133
- });
134
-
135
- it("should handle onKeyDown callback", () => {
136
- const onKeyDown = vi.fn();
137
- render(
138
- <TestWrapper>
139
- <Input onKeyDown={onKeyDown} />
140
- </TestWrapper>,
141
- );
142
-
143
- // Note: Testing actual keypress events would require more complex setup
144
- // This test verifies the component renders correctly with the onKeyDown prop
145
- expect(onKeyDown).toBeDefined();
146
- });
147
-
148
- it("should handle width and height constraints", () => {
149
- const instance = render(
150
- <TestWrapper>
151
- <Input
152
- initialValue="This is a long text that should be constrained"
153
- width={20}
154
- height={5}
155
- />
156
- </TestWrapper>,
157
- );
158
-
159
- logInk(instance);
160
-
161
- const output = stripAnsi(instance.frames.join(""));
162
-
163
- expect(output).toBeDefined();
164
- expect(output).toContain("This is a long");
165
- });
166
- });
@@ -1,273 +0,0 @@
1
- import { describe, expect, it, vi } from "vitest";
2
-
3
- import { cleanup, render, logInk } from "../../../lib/test-utils.js";
4
- import { Select } from "../select.js";
5
-
6
- describe.concurrent("Select", () => {
7
- const TestWrapper = ({ children }: React.PropsWithChildren) => <>{children}</>;
8
-
9
- afterEach(() => {
10
- cleanup();
11
- });
12
-
13
- it("should render items", () => {
14
- const items = ["Item 1", "Item 2", "Item 3"];
15
- const instance = render(
16
- <TestWrapper>
17
- <Select items={items} />
18
- </TestWrapper>,
19
- );
20
-
21
- logInk(instance);
22
-
23
- const output = instance.frames.join("");
24
-
25
- expect(output).toBeDefined();
26
- expect(typeof output).toBe("string");
27
- expect(output).toContain("Item 1");
28
- expect(output).toContain("Item 2");
29
- expect(output).toContain("Item 3");
30
- });
31
-
32
- it("should highlight the first item by default", () => {
33
- const items = ["First", "Second", "Third"];
34
- const instance = render(
35
- <TestWrapper>
36
- <Select items={items} />
37
- </TestWrapper>,
38
- );
39
-
40
- logInk(instance);
41
-
42
- const output = instance.frames.join("");
43
-
44
- expect(output).toBeDefined();
45
- // The selected item should have a '>' prefix
46
- expect(output).toContain("> First");
47
- });
48
-
49
- it("should use initialIndex to set initial selection", () => {
50
- const items = ["First", "Second", "Third"];
51
- const instance = render(
52
- <TestWrapper>
53
- <Select items={items} initialIndex={1} />
54
- </TestWrapper>,
55
- );
56
-
57
- logInk(instance);
58
-
59
- const output = instance.frames.join("");
60
-
61
- expect(output).toBeDefined();
62
- expect(output).toContain("> Second");
63
- });
64
-
65
- it('should show "No matches" when items array is empty', () => {
66
- const instance = render(
67
- <TestWrapper>
68
- <Select items={[]} />
69
- </TestWrapper>,
70
- );
71
-
72
- logInk(instance);
73
-
74
- const output = instance.frames.join("");
75
-
76
- expect(output).toBeDefined();
77
- expect(output).toContain("No matches");
78
- });
79
-
80
- it("should respect limit prop", () => {
81
- const items = Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`);
82
- const instance = render(
83
- <TestWrapper>
84
- <Select items={items} limit={5} />
85
- </TestWrapper>,
86
- );
87
-
88
- logInk(instance);
89
-
90
- const output = instance.frames.join("");
91
-
92
- expect(output).toBeDefined();
93
- // Should only show up to limit items
94
- expect(output).toContain("Item 1");
95
- expect(output).toContain("Item 5");
96
- // Should not show items beyond limit
97
- expect(output).not.toContain("Item 6");
98
- });
99
-
100
- it("should show index when showIndex is true", () => {
101
- const items = ["Item 1", "Item 2", "Item 3"];
102
- const instance = render(
103
- <TestWrapper>
104
- <Select items={items} showIndex={true} />
105
- </TestWrapper>,
106
- );
107
-
108
- logInk(instance);
109
-
110
- const output = instance.frames.join("");
111
-
112
- expect(output).toBeDefined();
113
- // Should show index like (1/3)
114
- expect(output).toContain("(1/3)");
115
- });
116
-
117
- it("should not show index when showIndex is false", () => {
118
- const items = ["Item 1", "Item 2", "Item 3"];
119
- const instance = render(
120
- <TestWrapper>
121
- <Select items={items} showIndex={false} />
122
- </TestWrapper>,
123
- );
124
-
125
- logInk(instance);
126
-
127
- const output = instance.frames.join("");
128
-
129
- expect(output).toBeDefined();
130
- // Should not show index
131
- expect(output).not.toContain("(1/3)");
132
- });
133
-
134
- it("should show indicators when showIndicators is true and there are more items", () => {
135
- const items = Array.from({ length: 15 }, (_, i) => `Item ${i + 1}`);
136
- const instance = render(
137
- <TestWrapper>
138
- <Select items={items} limit={5} showIndicators={true} />
139
- </TestWrapper>,
140
- );
141
-
142
- logInk(instance);
143
-
144
- const output = instance.frames.join("");
145
-
146
- expect(output).toBeDefined();
147
- // Should show scroll indicators when there are more items
148
- expect(output).toContain("▼");
149
- });
150
-
151
- it("should call onHighlight when selection changes", () => {
152
- const onHighlight = vi.fn();
153
- const items = ["Item 1", "Item 2", "Item 3"];
154
- render(
155
- <TestWrapper>
156
- <Select items={items} onHighlight={onHighlight} />
157
- </TestWrapper>,
158
- );
159
-
160
- // onHighlight should be called with the initial selection
161
- // Note: Testing actual keypress events would require more complex setup
162
- expect(onHighlight).toBeDefined();
163
- });
164
-
165
- it("should call onSubmit when enter is pressed", () => {
166
- const onSubmit = vi.fn();
167
- const items = ["Item 1", "Item 2", "Item 3"];
168
- render(
169
- <TestWrapper>
170
- <Select items={items} onSubmit={onSubmit} />
171
- </TestWrapper>,
172
- );
173
-
174
- // Note: Testing actual keypress events would require more complex setup
175
- // This test verifies the component renders correctly with the onSubmit prop
176
- expect(onSubmit).toBeDefined();
177
- });
178
-
179
- it("should call onCancel when escape is pressed", () => {
180
- const onCancel = vi.fn();
181
- const items = ["Item 1", "Item 2", "Item 3"];
182
- render(
183
- <TestWrapper>
184
- <Select items={items} onCancel={onCancel} />
185
- </TestWrapper>,
186
- );
187
-
188
- // Note: Testing actual keypress events would require more complex setup
189
- // This test verifies the component renders correctly with the onCancel prop
190
- expect(onCancel).toBeDefined();
191
- });
192
-
193
- it("should call onTab when tab is pressed", () => {
194
- const onTab = vi.fn();
195
- const items = ["Item 1", "Item 2", "Item 3"];
196
- render(
197
- <TestWrapper>
198
- <Select items={items} onTab={onTab} />
199
- </TestWrapper>,
200
- );
201
-
202
- // Note: Testing actual keypress events would require more complex setup
203
- // This test verifies the component renders correctly with the onTab prop
204
- expect(onTab).toBeDefined();
205
- });
206
-
207
- it("should respect isActive prop", () => {
208
- const items = ["Item 1", "Item 2", "Item 3"];
209
- const instance = render(
210
- <TestWrapper>
211
- <Select items={items} isActive={false} />
212
- </TestWrapper>,
213
- );
214
-
215
- logInk(instance);
216
-
217
- const output = instance.frames.join("");
218
-
219
- expect(output).toBeDefined();
220
- expect(output).toContain("Item 1");
221
- });
222
-
223
- it("should handle maxHeight constraint", () => {
224
- const items = Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`);
225
- const instance = render(
226
- <TestWrapper>
227
- <Select items={items} limit={10} maxHeight={5} />
228
- </TestWrapper>,
229
- );
230
-
231
- logInk(instance);
232
-
233
- const output = instance.frames.join("");
234
-
235
- expect(output).toBeDefined();
236
- // Should respect maxHeight constraint
237
- expect(output).toContain("Item 1");
238
- });
239
-
240
- it("should clamp initialIndex to valid range", () => {
241
- const items = ["Item 1", "Item 2", "Item 3"];
242
- const instance = render(
243
- <TestWrapper>
244
- <Select items={items} initialIndex={10} />
245
- </TestWrapper>,
246
- );
247
-
248
- logInk(instance);
249
-
250
- const output = instance.frames.join("");
251
-
252
- expect(output).toBeDefined();
253
- // Should clamp to last item (index 2)
254
- expect(output).toContain("> Item 3");
255
- });
256
-
257
- it("should handle negative initialIndex", () => {
258
- const items = ["Item 1", "Item 2", "Item 3"];
259
- const instance = render(
260
- <TestWrapper>
261
- <Select items={items} initialIndex={-1} />
262
- </TestWrapper>,
263
- );
264
-
265
- logInk(instance);
266
-
267
- const output = instance.frames.join("");
268
-
269
- expect(output).toBeDefined();
270
- // Should clamp to first item (index 0)
271
- expect(output).toContain("> Item 1");
272
- });
273
- });
@@ -1,99 +0,0 @@
1
- import stripAnsi from "strip-ansi";
2
- import { describe, expect } from "vitest";
3
-
4
- import { render, logInk, cleanup } from "../../../lib/test-utils.js";
5
- import { Shimmer } from "../shimmer.js";
6
-
7
- describe.concurrent("Shimmer", () => {
8
- afterEach(() => {
9
- cleanup();
10
- });
11
-
12
- it("should render text with shimmer effect", () => {
13
- const instance = render(<Shimmer text="Hello World Shimmer" />);
14
-
15
- logInk(instance);
16
-
17
- const output = instance.frames.join("");
18
- const plainText = "Hello World Shimmer";
19
-
20
- expect(output).toBeDefined();
21
- expect(typeof output).toBe("string");
22
- expect(stripAnsi(output)).toContain(plainText);
23
- // Verify that ANSI codes are present (output should be longer than plain text)
24
- expect(output.length).toBeGreaterThan(plainText.length);
25
- // Verify ANSI escape sequences are present
26
- expect(output).toMatch(new RegExp(String.fromCharCode(27) + "\\["));
27
- });
28
-
29
- it("should render with custom color", () => {
30
- const instance = render(<Shimmer text="Test" color="#ff0000" />);
31
-
32
- logInk(instance);
33
-
34
- const output = instance.frames.join("");
35
- const plainText = "Test";
36
-
37
- expect(output).toBeDefined();
38
- expect(stripAnsi(output)).toContain(plainText);
39
- // Verify that ANSI codes are present
40
- expect(output.length).toBeGreaterThan(plainText.length);
41
- expect(output).toMatch(new RegExp(String.fromCharCode(27) + "\\["));
42
- });
43
-
44
- it("should handle empty text", () => {
45
- const instance = render(<Shimmer text="" />);
46
-
47
- logInk(instance);
48
-
49
- const output = instance.frames.join("");
50
-
51
- expect(output).toBeDefined();
52
- });
53
-
54
- it("should handle single character", () => {
55
- const instance = render(<Shimmer text="A" />);
56
-
57
- logInk(instance);
58
-
59
- const output = instance.frames.join("");
60
- const plainText = "A";
61
-
62
- expect(output).toBeDefined();
63
- expect(stripAnsi(output)).toContain(plainText);
64
- // Verify that ANSI codes are present
65
- expect(output.length).toBeGreaterThan(plainText.length);
66
- expect(output).toMatch(new RegExp(String.fromCharCode(27) + "\\["));
67
- });
68
-
69
- it("should handle long text", () => {
70
- const longText =
71
- "This is a very long text that should still render properly with the shimmer effect";
72
- const instance = render(<Shimmer text={longText} />);
73
-
74
- logInk(instance);
75
-
76
- const output = instance.frames.join("");
77
-
78
- expect(output).toBeDefined();
79
- expect(stripAnsi(output)).toContain(longText);
80
- // Verify that ANSI codes are present
81
- expect(output.length).toBeGreaterThan(longText.length);
82
- expect(output).toMatch(new RegExp(String.fromCharCode(27) + "\\["));
83
- });
84
-
85
- it("should use default color when not provided", () => {
86
- const instance = render(<Shimmer text="Default Shimmer" />);
87
-
88
- logInk(instance);
89
-
90
- const output = instance.frames.join("");
91
- const plainText = "Default Shimmer";
92
-
93
- expect(output).toBeDefined();
94
- expect(stripAnsi(output)).toContain(plainText);
95
- // Verify that ANSI codes are present
96
- expect(output.length).toBeGreaterThan(plainText.length);
97
- expect(output).toMatch(new RegExp(String.fromCharCode(27) + "\\["));
98
- });
99
- });
@@ -1,27 +0,0 @@
1
- import { Text } from "@codellm/jar";
2
- import { memo, startTransition, useEffect, useState } from "react";
3
-
4
- interface BlinkingIndicatorProps {
5
- char: string;
6
- color?: string;
7
- }
8
-
9
- const BLINK_INTERVAL = 500; // ms
10
-
11
- export const BlinkingIndicator = memo(({ char, color }: BlinkingIndicatorProps) => {
12
- const [visible, setVisible] = useState(true);
13
-
14
- useEffect(() => {
15
- const interval = setInterval(() => {
16
- startTransition(() => {
17
- setVisible((prev) => !prev);
18
- });
19
- }, BLINK_INTERVAL);
20
-
21
- return () => clearInterval(interval);
22
- }, []);
23
-
24
- return <Text color={color}>{visible ? char : " "}</Text>;
25
- });
26
-
27
- BlinkingIndicator.displayName = "BlinkingIndicator";