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

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 (197) hide show
  1. package/dist/index.mjs +450 -422
  2. package/package.json +4 -1
  3. package/.oxlintrc.json +0 -8
  4. package/resources/abacus.ico +0 -0
  5. package/resources/entitlements.plist +0 -9
  6. package/src/__e2e__/README.md +0 -196
  7. package/src/__e2e__/agent-interactions.e2e.test.tsx +0 -61
  8. package/src/__e2e__/cli-commands.e2e.test.tsx +0 -77
  9. package/src/__e2e__/conversation-throttle.e2e.test.ts +0 -453
  10. package/src/__e2e__/conversation.e2e.test.tsx +0 -56
  11. package/src/__e2e__/diff-preview.e2e.test.tsx +0 -3399
  12. package/src/__e2e__/file-creation.e2e.test.tsx +0 -149
  13. package/src/__e2e__/helpers/test-helpers.ts +0 -449
  14. package/src/__e2e__/keyboard-navigation.e2e.test.tsx +0 -34
  15. package/src/__e2e__/llm-models.e2e.test.ts +0 -402
  16. package/src/__e2e__/mcp/mcp-callback-flow.e2e.test.tsx +0 -71
  17. package/src/__e2e__/mcp/mcp-full-app-ui.e2e.test.tsx +0 -167
  18. package/src/__e2e__/mcp/mcp-ui-rendering.e2e.test.tsx +0 -185
  19. package/src/__e2e__/repl.e2e.test.tsx +0 -78
  20. package/src/__e2e__/shell-compatibility.e2e.test.tsx +0 -76
  21. package/src/__e2e__/theme-mcp.e2e.test.tsx +0 -98
  22. package/src/__e2e__/tool-permissions.e2e.test.tsx +0 -66
  23. package/src/args.ts +0 -22
  24. package/src/components/__tests__/react-compiler.test.tsx +0 -78
  25. package/src/components/__tests__/status-indicator.test.tsx +0 -403
  26. package/src/components/composer/__tests__/bash-runner.test.tsx +0 -263
  27. package/src/components/composer/agent-mode-indicator.tsx +0 -63
  28. package/src/components/composer/bash-runner.tsx +0 -54
  29. package/src/components/composer/commands/default-commands.tsx +0 -615
  30. package/src/components/composer/commands/handler.tsx +0 -59
  31. package/src/components/composer/commands/picker.tsx +0 -273
  32. package/src/components/composer/commands/registry.ts +0 -233
  33. package/src/components/composer/commands/types.ts +0 -33
  34. package/src/components/composer/context.tsx +0 -88
  35. package/src/components/composer/file-mention-picker.tsx +0 -83
  36. package/src/components/composer/help.tsx +0 -44
  37. package/src/components/composer/index.tsx +0 -1007
  38. package/src/components/composer/mentions.ts +0 -57
  39. package/src/components/composer/message-queue.tsx +0 -70
  40. package/src/components/composer/mode-panel.tsx +0 -35
  41. package/src/components/composer/modes/__tests__/bash-handler.test.tsx +0 -755
  42. package/src/components/composer/modes/__tests__/bash-renderer.test.tsx +0 -1108
  43. package/src/components/composer/modes/bash-handler.tsx +0 -132
  44. package/src/components/composer/modes/bash-renderer.tsx +0 -175
  45. package/src/components/composer/modes/default-handlers.tsx +0 -33
  46. package/src/components/composer/modes/index.ts +0 -41
  47. package/src/components/composer/modes/types.ts +0 -21
  48. package/src/components/composer/persistent-shell.ts +0 -283
  49. package/src/components/composer/process.ts +0 -65
  50. package/src/components/composer/types.ts +0 -9
  51. package/src/components/composer/use-mention-search.ts +0 -68
  52. package/src/components/error-boundry.tsx +0 -60
  53. package/src/components/exit-message.tsx +0 -29
  54. package/src/components/expanded-view.tsx +0 -74
  55. package/src/components/file-completion.tsx +0 -127
  56. package/src/components/header.tsx +0 -47
  57. package/src/components/logo.tsx +0 -37
  58. package/src/components/segments.tsx +0 -356
  59. package/src/components/status-indicator.tsx +0 -306
  60. package/src/components/tool-group-summary.tsx +0 -263
  61. package/src/components/tool-permissions/ask-user-question-permission-ui.tsx +0 -319
  62. package/src/components/tool-permissions/diff-preview.tsx +0 -359
  63. package/src/components/tool-permissions/index.ts +0 -5
  64. package/src/components/tool-permissions/permission-options.tsx +0 -401
  65. package/src/components/tool-permissions/permission-preview-header.tsx +0 -57
  66. package/src/components/tool-permissions/tool-permission-ui.tsx +0 -420
  67. package/src/components/tools/agent/ask-user-question.tsx +0 -107
  68. package/src/components/tools/agent/enter-plan-mode.tsx +0 -55
  69. package/src/components/tools/agent/exit-plan-mode.tsx +0 -83
  70. package/src/components/tools/agent/handoff-to-main.tsx +0 -27
  71. package/src/components/tools/agent/subagent.tsx +0 -37
  72. package/src/components/tools/agent/todo-write.tsx +0 -104
  73. package/src/components/tools/browser/close-tab.tsx +0 -58
  74. package/src/components/tools/browser/computer.tsx +0 -70
  75. package/src/components/tools/browser/get-interactive-elements.tsx +0 -54
  76. package/src/components/tools/browser/get-tab-content.tsx +0 -51
  77. package/src/components/tools/browser/navigate-to.tsx +0 -59
  78. package/src/components/tools/browser/new-tab.tsx +0 -60
  79. package/src/components/tools/browser/perform-action.tsx +0 -63
  80. package/src/components/tools/browser/refresh-tab.tsx +0 -43
  81. package/src/components/tools/browser/switch-tab.tsx +0 -58
  82. package/src/components/tools/filesystem/delete-file.tsx +0 -104
  83. package/src/components/tools/filesystem/edit.tsx +0 -220
  84. package/src/components/tools/filesystem/list-dir.tsx +0 -78
  85. package/src/components/tools/filesystem/read-file.tsx +0 -180
  86. package/src/components/tools/filesystem/upload-image.tsx +0 -76
  87. package/src/components/tools/ide/ide-diagnostics.tsx +0 -62
  88. package/src/components/tools/index.ts +0 -91
  89. package/src/components/tools/mcp/mcp-tool.tsx +0 -158
  90. package/src/components/tools/search/fetch-url.tsx +0 -73
  91. package/src/components/tools/search/file-search.tsx +0 -78
  92. package/src/components/tools/search/grep.tsx +0 -90
  93. package/src/components/tools/search/semantic-search.tsx +0 -66
  94. package/src/components/tools/search/web-search.tsx +0 -71
  95. package/src/components/tools/shared/index.tsx +0 -48
  96. package/src/components/tools/shared/zod-coercion.ts +0 -35
  97. package/src/components/tools/terminal/bash-tool-output.tsx +0 -188
  98. package/src/components/tools/terminal/get-terminal-output.tsx +0 -91
  99. package/src/components/tools/terminal/run-in-terminal.tsx +0 -131
  100. package/src/components/tools/types.ts +0 -16
  101. package/src/components/tools.tsx +0 -68
  102. package/src/components/ui/__tests__/divider.test.tsx +0 -61
  103. package/src/components/ui/__tests__/gradient.test.tsx +0 -125
  104. package/src/components/ui/__tests__/input.test.tsx +0 -166
  105. package/src/components/ui/__tests__/select.test.tsx +0 -273
  106. package/src/components/ui/__tests__/shimmer.test.tsx +0 -99
  107. package/src/components/ui/blinking-indicator.tsx +0 -27
  108. package/src/components/ui/divider.tsx +0 -162
  109. package/src/components/ui/gradient.tsx +0 -56
  110. package/src/components/ui/input.tsx +0 -228
  111. package/src/components/ui/select.tsx +0 -151
  112. package/src/components/ui/shimmer.tsx +0 -76
  113. package/src/context/agent-mode.tsx +0 -95
  114. package/src/context/extension-file.tsx +0 -136
  115. package/src/context/network-activity.tsx +0 -45
  116. package/src/context/notification.tsx +0 -62
  117. package/src/context/shell-size.tsx +0 -49
  118. package/src/context/shell-title.tsx +0 -38
  119. package/src/entrypoints/print-mode.ts +0 -312
  120. package/src/entrypoints/repl.tsx +0 -389
  121. package/src/hooks/use-agent.ts +0 -15
  122. package/src/hooks/use-api-client.ts +0 -1
  123. package/src/hooks/use-available-height.ts +0 -8
  124. package/src/hooks/use-cleanup.ts +0 -29
  125. package/src/hooks/use-interrupt-manager.ts +0 -242
  126. package/src/hooks/use-models.ts +0 -22
  127. package/src/index.ts +0 -217
  128. package/src/lib/__tests__/ansi.test.ts +0 -255
  129. package/src/lib/__tests__/cli.test.ts +0 -122
  130. package/src/lib/__tests__/commands.test.ts +0 -325
  131. package/src/lib/__tests__/constants.test.ts +0 -15
  132. package/src/lib/__tests__/focusables.test.ts +0 -25
  133. package/src/lib/__tests__/fs.test.ts +0 -231
  134. package/src/lib/__tests__/markdown.test.tsx +0 -348
  135. package/src/lib/__tests__/mcpCommandHandler.test.ts +0 -173
  136. package/src/lib/__tests__/mcpManagement.test.ts +0 -38
  137. package/src/lib/__tests__/path-paste.test.ts +0 -144
  138. package/src/lib/__tests__/path.test.ts +0 -300
  139. package/src/lib/__tests__/queries.test.ts +0 -39
  140. package/src/lib/__tests__/standaloneMcpService.test.ts +0 -71
  141. package/src/lib/__tests__/text-buffer.test.ts +0 -328
  142. package/src/lib/__tests__/text-utils.test.ts +0 -32
  143. package/src/lib/__tests__/timing.test.ts +0 -78
  144. package/src/lib/__tests__/utils.test.ts +0 -238
  145. package/src/lib/__tests__/vim-buffer-actions.test.ts +0 -154
  146. package/src/lib/ansi.ts +0 -150
  147. package/src/lib/cli-push-server.ts +0 -112
  148. package/src/lib/cli.ts +0 -44
  149. package/src/lib/clipboard.ts +0 -226
  150. package/src/lib/command-utils.ts +0 -93
  151. package/src/lib/commands.ts +0 -270
  152. package/src/lib/constants.ts +0 -3
  153. package/src/lib/extension-connection.ts +0 -181
  154. package/src/lib/focusables.ts +0 -7
  155. package/src/lib/fs.ts +0 -533
  156. package/src/lib/markdown/code-block.tsx +0 -63
  157. package/src/lib/markdown/index.ts +0 -4
  158. package/src/lib/markdown/link.tsx +0 -19
  159. package/src/lib/markdown/markdown.tsx +0 -372
  160. package/src/lib/markdown/types.ts +0 -15
  161. package/src/lib/mcpCommandHandler.ts +0 -121
  162. package/src/lib/mcpManagement.ts +0 -44
  163. package/src/lib/path-paste.ts +0 -185
  164. package/src/lib/path.ts +0 -179
  165. package/src/lib/queries.ts +0 -15
  166. package/src/lib/standaloneMcpService.ts +0 -688
  167. package/src/lib/status-utils.ts +0 -237
  168. package/src/lib/test-utils.tsx +0 -72
  169. package/src/lib/text-buffer.ts +0 -2415
  170. package/src/lib/text-utils.ts +0 -272
  171. package/src/lib/timing.ts +0 -63
  172. package/src/lib/types.ts +0 -295
  173. package/src/lib/utils.ts +0 -182
  174. package/src/lib/vim-buffer-actions.ts +0 -732
  175. package/src/providers/agent.tsx +0 -1063
  176. package/src/providers/api-client.tsx +0 -43
  177. package/src/services/logger.ts +0 -85
  178. package/src/terminal/detection.ts +0 -187
  179. package/src/terminal/exit.ts +0 -279
  180. package/src/terminal/notification.ts +0 -83
  181. package/src/terminal/progress.ts +0 -201
  182. package/src/terminal/setup.ts +0 -797
  183. package/src/terminal/types.ts +0 -51
  184. package/src/theme/context.tsx +0 -57
  185. package/src/theme/index.ts +0 -4
  186. package/src/theme/themed.tsx +0 -35
  187. package/src/theme/themes.json +0 -546
  188. package/src/theme/types.ts +0 -110
  189. package/src/tools/types.ts +0 -59
  190. package/src/tools/utils/__tests__/zod-coercion.test.ts +0 -33
  191. package/src/tools/utils/tool-ui-components.tsx +0 -649
  192. package/src/tools/utils/zod-coercion.ts +0 -35
  193. package/tsconfig.json +0 -16
  194. package/tsconfig.node.json +0 -29
  195. package/tsconfig.test.json +0 -27
  196. package/tsdown.config.ts +0 -17
  197. package/vitest.config.ts +0 -76
@@ -1,48 +0,0 @@
1
- // components/tools/shared/index.tsx
2
- // Re-exports all shared UI components and utilities for tools
3
-
4
- export {
5
- formatBytes,
6
- formatDuration,
7
- truncatePath,
8
- getStatusColor,
9
- BlinkingDot,
10
- ToolHeader,
11
- ToolResult,
12
- PreviewContent,
13
- parseToolResult,
14
- computeExpectedFinalContentForDiff,
15
- wrapLine,
16
- CodePreview,
17
- CondensedDiffPreview,
18
- PendingToolCallIdContext,
19
- } from "../../../tools/utils/tool-ui-components.js";
20
-
21
- export type {
22
- ToolHeaderProps,
23
- ToolResultProps,
24
- PreviewContentProps,
25
- CodePreviewProps,
26
- CondensedDiffLine,
27
- CondensedDiffPreviewProps,
28
- } from "../../../tools/utils/tool-ui-components.js";
29
-
30
- /**
31
- * Convert snake_case keys to camelCase recursively
32
- */
33
- export function snakeToCamel(obj: unknown): unknown {
34
- if (obj === null || obj === undefined || typeof obj !== "object") {
35
- return obj;
36
- }
37
-
38
- if (Array.isArray(obj)) {
39
- return obj.map((item) => snakeToCamel(item));
40
- }
41
-
42
- const result: Record<string, unknown> = {};
43
- for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {
44
- const camelKey = key.replace(/_([a-z])/g, (_, letter: string) => letter.toUpperCase());
45
- result[camelKey] = snakeToCamel(value);
46
- }
47
- return result;
48
- }
@@ -1,35 +0,0 @@
1
- import { z } from "zod";
2
-
3
- function normalizeNumberInput(value: unknown): unknown {
4
- if (typeof value !== "string") {
5
- return value;
6
- }
7
-
8
- const trimmed = value.trim();
9
- if (!trimmed) {
10
- return Number.NaN;
11
- }
12
-
13
- return Number(trimmed);
14
- }
15
-
16
- function normalizeBooleanInput(value: unknown): unknown {
17
- if (typeof value !== "string") {
18
- return value;
19
- }
20
-
21
- const normalized = value.trim().toLowerCase();
22
- if (["true", "1", "yes", "y"].includes(normalized)) {
23
- return true;
24
- }
25
- if (["false", "0", "no", "n"].includes(normalized)) {
26
- return false;
27
- }
28
-
29
- return value;
30
- }
31
-
32
- export const coerceNumber = z.preprocess(normalizeNumberInput, z.number());
33
- export const coerceOptionalNumber = z.preprocess(normalizeNumberInput, z.number().optional());
34
- export const coerceBoolean = z.preprocess(normalizeBooleanInput, z.boolean());
35
- export const coerceOptionalBoolean = z.preprocess(normalizeBooleanInput, z.boolean().optional());
@@ -1,188 +0,0 @@
1
- import type { RunInTerminalParsedData } from "@codellm/agent";
2
-
3
- import { View, Text, useFocus, useInput } from "@codellm/jar";
4
- import { useState, useEffect, useMemo, useDeferredValue } from "react";
5
-
6
- import { useAgent } from "../../../hooks/use-agent.js";
7
- import { AgentStatus } from "../../../providers/agent.js";
8
- import { ToolHeader, ToolResult, PreviewContent, formatDuration } from "../shared/index.js";
9
-
10
- const MAX_LINES_PREVIEW = 7;
11
- const MAX_LINES_EXPANDED = 100;
12
-
13
- interface BashToolOutputProps {
14
- command: string;
15
- toolCallId: string;
16
- executionResult?: RunInTerminalParsedData;
17
- }
18
-
19
- interface TruncatedOutput {
20
- lines: string[];
21
- isTruncated: boolean;
22
- hiddenCount: number;
23
- }
24
-
25
- function getTruncatedOutput(
26
- output: string,
27
- maxLines: number,
28
- isExpanded: boolean,
29
- ): TruncatedOutput {
30
- const limit = isExpanded ? MAX_LINES_EXPANDED : maxLines;
31
- const lines = output.split("\n").filter(Boolean);
32
- if (lines.length <= limit) {
33
- return { lines, isTruncated: false, hiddenCount: 0 };
34
- }
35
-
36
- return {
37
- lines: lines.slice(0, limit),
38
- isTruncated: true,
39
- hiddenCount: lines.length - limit,
40
- };
41
- }
42
-
43
- function formatElapsedTime(ms: number): string {
44
- const seconds = ms / 1000;
45
- return `${seconds.toFixed(1)}s`;
46
- }
47
-
48
- export function BashToolOutput({ command, toolCallId, executionResult }: BashToolOutputProps) {
49
- const { agentStatus, activeToolOutputs } = useAgent();
50
- const [startTime] = useState(Date.now());
51
- const [elapsedMs, setElapsedMs] = useState(0);
52
- const [isExpanded, setIsExpanded] = useState(false);
53
-
54
- const isExecuting =
55
- !executionResult &&
56
- (agentStatus === AgentStatus.Streaming || agentStatus === AgentStatus.ExecutingTool);
57
-
58
- const streamingOutput = activeToolOutputs[toolCallId] || "";
59
- const finalOutput = executionResult?.output || "";
60
- const currentOutput = isExecuting ? streamingOutput : finalOutput;
61
-
62
- const deferredOutput = useDeferredValue(currentOutput);
63
- const isProcessing = currentOutput !== deferredOutput;
64
-
65
- useEffect(() => {
66
- if (isExecuting) {
67
- const interval = setInterval(() => {
68
- setElapsedMs(Date.now() - startTime);
69
- }, 1000);
70
- return () => clearInterval(interval);
71
- } else if (executionResult) {
72
- setElapsedMs(executionResult.duration ?? 0);
73
- }
74
- return () => {};
75
- }, [isExecuting, startTime, executionResult]);
76
-
77
- const { lines, isTruncated, hiddenCount } = useMemo(
78
- () => getTruncatedOutput(deferredOutput, MAX_LINES_PREVIEW, isExpanded),
79
- [deferredOutput, isExpanded],
80
- );
81
-
82
- const canExpand = !isExecuting && executionResult !== undefined && (isTruncated || isExpanded);
83
- const { isFocused } = useFocus({
84
- id: `bash-tool-${toolCallId}`,
85
- isActive: canExpand,
86
- });
87
-
88
- useInput(
89
- (input, key) => {
90
- if (isFocused && key.ctrl && input === "o") {
91
- setIsExpanded((prev) => !prev);
92
- }
93
- },
94
- { isActive: isFocused && canExpand },
95
- );
96
-
97
- const displayCommand = command;
98
- const exitCode = executionResult?.exitCode ?? 0;
99
- const isError = executionResult?.status === "error" || exitCode !== 0;
100
- const headerStatus = isExecuting ? "pending" : isError ? "error" : "success";
101
-
102
- if (isExecuting && lines.length === 0) {
103
- return (
104
- <View flexDirection="column" gap={0}>
105
- <ToolHeader
106
- name="Bash"
107
- params={displayCommand}
108
- paramsLanguage="bash"
109
- status={headerStatus}
110
- showSpinner
111
- />
112
- <ToolResult color="gray">Running…</ToolResult>
113
- </View>
114
- );
115
- }
116
-
117
- if (isExecuting && lines.length > 0) {
118
- const elapsedText = elapsedMs > 0 ? ` (${formatElapsedTime(elapsedMs)})` : "";
119
- return (
120
- <View flexDirection="column" gap={0}>
121
- <ToolHeader
122
- name="Bash"
123
- params={displayCommand}
124
- paramsLanguage="bash"
125
- status={headerStatus}
126
- showSpinner
127
- />
128
- <PreviewContent>
129
- {lines.map((line, idx) => (
130
- <Text key={idx}>{line}</Text>
131
- ))}
132
- {isTruncated && (
133
- <Text dimColor>
134
- … +{hiddenCount} more line{hiddenCount !== 1 ? "s" : ""}
135
- {elapsedText}
136
- </Text>
137
- )}
138
- {isProcessing && <Text dimColor>Processing output...</Text>}
139
- </PreviewContent>
140
- </View>
141
- );
142
- }
143
-
144
- if (executionResult) {
145
- const isStaleResult = !finalOutput && (executionResult.duration ?? 0) === 0;
146
- const duration = formatDuration(executionResult.duration ?? 0);
147
- const resultText = isStaleResult ? `exit ${exitCode}` : `exit ${exitCode} (${duration})`;
148
- const hasOutput = lines.length > 0;
149
-
150
- return (
151
- <View flexDirection="column" gap={0}>
152
- <ToolHeader
153
- name="Bash"
154
- params={displayCommand}
155
- paramsLanguage="bash"
156
- status={headerStatus}
157
- />
158
- {hasOutput && (
159
- <PreviewContent>
160
- {isError && (
161
- <Text color="red" dimColor>
162
- Error:
163
- </Text>
164
- )}
165
- {lines.map((line, idx) => (
166
- <Text key={idx} color={isError ? "red" : undefined} dimColor>
167
- {line}
168
- </Text>
169
- ))}
170
- {isTruncated && (
171
- <Text dimColor>
172
- … +{hiddenCount} {isExpanded ? "more " : ""}line{hiddenCount !== 1 ? "s" : ""}
173
- {!isExpanded ? " (ctrl+o to expand)" : ""}
174
- </Text>
175
- )}
176
- </PreviewContent>
177
- )}
178
- <ToolResult color={isError ? "red" : "gray"}>{resultText}</ToolResult>
179
- </View>
180
- );
181
- }
182
-
183
- return (
184
- <View flexDirection="column">
185
- <ToolHeader name="Bash" params={displayCommand} paramsLanguage="bash" status="pending" />
186
- </View>
187
- );
188
- }
@@ -1,91 +0,0 @@
1
- import type { ParsedToolResult } from "@codellm/agent";
2
-
3
- import { View, Text } from "@codellm/jar";
4
- import React from "react";
5
- import { z } from "zod";
6
-
7
- import type { ToolDef, ToolStatus } from "../types.js";
8
-
9
- import { ToolHeader, ToolResult } from "../shared/index.js";
10
- import { snakeToCamel } from "../shared/index.js";
11
-
12
- const GetTerminalOutputParams = z.object({
13
- id: z.string(),
14
- });
15
-
16
- export const getTerminalOutputTool: ToolDef = {
17
- displayName: "TerminalOutput",
18
-
19
- getHeaderParams(input: Record<string, unknown>): string {
20
- try {
21
- return `id: ${input?.id || ""}`;
22
- } catch {
23
- return "[unknown]";
24
- }
25
- },
26
-
27
- renderUI(
28
- rawInput: Record<string, unknown>,
29
- status: ToolStatus,
30
- parsedResult?: ParsedToolResult,
31
- ): React.ReactElement {
32
- const parseResult = GetTerminalOutputParams.safeParse(snakeToCamel(rawInput));
33
- if (!parseResult.success) {
34
- return (
35
- <View flexDirection="column">
36
- <ToolHeader name="TerminalOutput" params="" status="error" />
37
- <ToolResult color="red">Invalid params</ToolResult>
38
- </View>
39
- );
40
- }
41
- const params = parseResult.data;
42
- const terminalIdParam = `id: ${params.id}`;
43
-
44
- if (status === "interrupted") {
45
- return (
46
- <View flexDirection="column">
47
- <ToolHeader name="TerminalOutput" params={terminalIdParam} status="interrupted" />
48
- <ToolResult color="yellow">Interrupted · What should I do instead?</ToolResult>
49
- </View>
50
- );
51
- }
52
-
53
- if (status === "rejected") {
54
- return (
55
- <View flexDirection="column">
56
- <ToolHeader name="TerminalOutput" params={terminalIdParam} status="rejected" />
57
- {parsedResult?.userNote ? (
58
- <ToolResult color="yellow">
59
- Rejected · <Text italic>"{parsedResult.userNote}"</Text>
60
- </ToolResult>
61
- ) : (
62
- <ToolResult color="yellow">Rejected</ToolResult>
63
- )}
64
- </View>
65
- );
66
- }
67
-
68
- const isExecuting = !parsedResult && (status === "executing" || status === "pending");
69
-
70
- if (isExecuting) {
71
- return (
72
- <ToolHeader name="TerminalOutput" params={terminalIdParam} status="pending" showSpinner />
73
- );
74
- }
75
-
76
- if (!parsedResult) {
77
- return (
78
- <View flexDirection="column">
79
- <ToolHeader name="TerminalOutput" params={terminalIdParam} status="pending" />
80
- </View>
81
- );
82
- }
83
-
84
- return (
85
- <View flexDirection="column">
86
- <ToolHeader name="TerminalOutput" params={terminalIdParam} status="success" />
87
- <ToolResult>{parsedResult.summary}</ToolResult>
88
- </View>
89
- );
90
- },
91
- };
@@ -1,131 +0,0 @@
1
- import type { ParsedToolResult, RunInTerminalParsedData } from "@codellm/agent";
2
-
3
- import { View, Text } from "@codellm/jar";
4
- import React from "react";
5
- import { z } from "zod";
6
-
7
- import type { ToolDef, ToolStatus } from "../types.js";
8
-
9
- import { ToolHeader, ToolResult, snakeToCamel } from "../shared/index.js";
10
- import { coerceOptionalBoolean } from "../shared/zod-coercion.js";
11
- import { BashToolOutput } from "./bash-tool-output.js";
12
-
13
- const RunInTerminalParams = z.object({
14
- command: z.string(),
15
- explanation: z.string().optional(),
16
- isBackground: coerceOptionalBoolean,
17
- id: z.string().optional(),
18
- interactiveMode: coerceOptionalBoolean,
19
- timeout: z.coerce.number().optional(),
20
- });
21
-
22
- function RunInTerminalUI({
23
- rawInput,
24
- status,
25
- parsedResult,
26
- }: {
27
- rawInput: Record<string, unknown>;
28
- status: ToolStatus;
29
- parsedResult?: ParsedToolResult<RunInTerminalParsedData>;
30
- }) {
31
- const parseResult = RunInTerminalParams.safeParse(snakeToCamel(rawInput));
32
- if (!parseResult.success) {
33
- return (
34
- <View flexDirection="column">
35
- <ToolHeader name="Bash" params="" paramsLanguage="bash" status="error" />
36
- <ToolResult color="red">Invalid params</ToolResult>
37
- </View>
38
- );
39
- }
40
- const params = parseResult.data;
41
- const command = params.command || "";
42
- const timeoutLabel = params.timeout ? ` (timeout: ${(params.timeout / 1000).toFixed(0)}s)` : "";
43
-
44
- if (status === "interrupted") {
45
- return (
46
- <View flexDirection="column">
47
- <ToolHeader name="Bash" params={command} paramsLanguage="bash" status="interrupted" />
48
- <ToolResult color="yellow">Interrupted · What should I do instead?</ToolResult>
49
- </View>
50
- );
51
- }
52
-
53
- if (status === "rejected") {
54
- if (parsedResult?.userNote) {
55
- return (
56
- <View flexDirection="column">
57
- <ToolHeader name="Bash" params={command} paramsLanguage="bash" status="rejected" />
58
- <ToolResult color="yellow">
59
- Rejected · <Text italic>"{parsedResult.userNote}"</Text>
60
- </ToolResult>
61
- </View>
62
- );
63
- }
64
- return (
65
- <View flexDirection="column">
66
- <ToolHeader name="Bash" params={command} paramsLanguage="bash" status="rejected" />
67
- <ToolResult color="yellow">Rejected</ToolResult>
68
- </View>
69
- );
70
- }
71
-
72
- if (parsedResult?.data?.timedOut) {
73
- return (
74
- <View flexDirection="column">
75
- <ToolHeader
76
- name="Bash"
77
- params={`${command}${timeoutLabel}`}
78
- paramsLanguage="bash"
79
- status="success"
80
- />
81
- <ToolResult>Running in the background</ToolResult>
82
- </View>
83
- );
84
- }
85
-
86
- if (parsedResult?.isBackground) {
87
- return (
88
- <View flexDirection="column">
89
- <ToolHeader
90
- name="Bash"
91
- params={`${command}${timeoutLabel}`}
92
- paramsLanguage="bash"
93
- status="success"
94
- />
95
- <ToolResult>{parsedResult.summary}</ToolResult>
96
- </View>
97
- );
98
- }
99
-
100
- // We need toolCallId here; use a best-effort id from rawInput
101
- const toolCallId = (rawInput?.id as string) || "unknown";
102
- const executionResult = parsedResult?.data;
103
-
104
- return (
105
- <BashToolOutput
106
- command={`${command}${timeoutLabel}`}
107
- toolCallId={toolCallId}
108
- executionResult={executionResult}
109
- />
110
- );
111
- }
112
-
113
- export const runInTerminalTool: ToolDef<RunInTerminalParsedData> = {
114
- displayName: "Bash",
115
-
116
- getHeaderParams(input: Record<string, unknown>): string {
117
- try {
118
- return (input?.command || "[no command]") as string;
119
- } catch {
120
- return "[unknown]";
121
- }
122
- },
123
-
124
- renderUI(
125
- rawInput: Record<string, unknown>,
126
- status: ToolStatus,
127
- parsedResult,
128
- ): React.ReactElement {
129
- return <RunInTerminalUI rawInput={rawInput} status={status} parsedResult={parsedResult} />;
130
- },
131
- };
@@ -1,16 +0,0 @@
1
- // components/tools/types.ts
2
- import type { ParsedToolResult, ToolDisplayData } from "@codellm/agent";
3
- import type { ReactElement } from "react";
4
-
5
- export type ToolStatus = "pending" | "executing" | "success" | "error" | "rejected" | "interrupted";
6
-
7
- export interface ToolDef<TData = Record<string, unknown>> {
8
- displayName: string;
9
- getHeaderParams(input: Record<string, unknown>): string;
10
- renderUI(
11
- input: Record<string, unknown>,
12
- status: ToolStatus,
13
- parsedResult?: ParsedToolResult<TData>,
14
- displayData?: ToolDisplayData,
15
- ): ReactElement;
16
- }
@@ -1,68 +0,0 @@
1
- import type { ParsedToolResult, ToolDisplayData } from "@codellm/agent";
2
- import type { ToolUseRequest, ToolUseResult } from "@codellm/api";
3
-
4
- import { View, Text } from "@codellm/jar";
5
-
6
- import { toolMap } from "./tools/index.js";
7
- import { ToolHeader, ToolResult } from "./tools/shared/index.js";
8
-
9
- type ToolProps<T extends ToolUseRequest> = T & {
10
- result?: ToolUseResult;
11
- displayData?: ToolDisplayData;
12
- parsedResult?: ParsedToolResult;
13
- };
14
-
15
- /**
16
- * Generic Tool component that uses the new toolMap.
17
- * Prefers parsedResult.data (from SDK parse()) over re-parsing toolUseResult.content.
18
- */
19
- export function Tool(tool: ToolProps<ToolUseRequest>) {
20
- const def = toolMap[tool.name];
21
-
22
- if (!def) {
23
- return (
24
- <View flexDirection="column">
25
- <Text color="red">Unknown tool: {tool.name}</Text>
26
- </View>
27
- );
28
- }
29
-
30
- let status: import("./tools/types.js").ToolStatus;
31
- if (tool.result?.rejected) {
32
- const parsed = (() => {
33
- try {
34
- return JSON.parse(tool.result.content) as { reason?: string };
35
- } catch {
36
- return {};
37
- }
38
- })();
39
- status = parsed.reason === "interrupted" ? "interrupted" : "rejected";
40
- } else if (tool.result) {
41
- status = "success";
42
- } else if (tool.parsedResult?.phase === "error") {
43
- status = "error";
44
- } else {
45
- status = "executing";
46
- }
47
- const input = (tool.input ?? {}) as Record<string, unknown>;
48
-
49
- let headerParams = "";
50
- try {
51
- headerParams = def.getHeaderParams(input);
52
- } catch {
53
- // ignore
54
- }
55
-
56
- try {
57
- return def.renderUI(input, status, tool.parsedResult, tool.displayData);
58
- } catch (error) {
59
- const errorMessage = error instanceof Error ? error.message : String(error);
60
- console.error(`Error rendering tool ${tool.name}:`, errorMessage);
61
- return (
62
- <View flexDirection="column">
63
- <ToolHeader name={def.displayName} params={headerParams} status="error" />
64
- <ToolResult color="red">Error rendering tool</ToolResult>
65
- </View>
66
- );
67
- }
68
- }
@@ -1,61 +0,0 @@
1
- import { Text } from "@codellm/jar";
2
- import { describe, expect, it } from "vitest";
3
-
4
- import { stripAnsi } from "../../../lib/ansi.js";
5
- import { render, logInk } from "../../../lib/test-utils.js";
6
- import { Divider } from "../divider.js";
7
-
8
- describe.concurrent("Divider", () => {
9
- it("should render a basic divider", () => {
10
- const instance = render(<Divider />);
11
-
12
- logInk(instance);
13
-
14
- const output = stripAnsi(instance.frames.join(""));
15
-
16
- expect(output).toBeDefined();
17
- expect(typeof output).toBe("string");
18
- // The divider should contain the default divider character
19
- expect(output).toContain("─");
20
- });
21
-
22
- it("should render divider with custom character", () => {
23
- const instance = render(<Divider dividerChar="=" />);
24
-
25
- logInk(instance);
26
-
27
- const output = stripAnsi(instance.frames.join(""));
28
-
29
- expect(output).toBeDefined();
30
- expect(output).toContain("=");
31
- });
32
-
33
- it("should render divider with children", () => {
34
- const instance = render(
35
- <Divider>
36
- <Text>Title</Text>
37
- </Divider>,
38
- );
39
-
40
- logInk(instance);
41
-
42
- const output = stripAnsi(instance.frames.join(""));
43
-
44
- expect(output).toBeDefined();
45
- expect(output).toContain("Title");
46
- // Should still have divider characters
47
- expect(output).toContain("─");
48
- });
49
-
50
- it("should render divider with padding", () => {
51
- const instance = render(<Divider padding={2} />);
52
-
53
- logInk(instance);
54
-
55
- const output = stripAnsi(instance.frames.join(""));
56
-
57
- expect(output).toBeDefined();
58
- // Padding should add spaces
59
- expect(output).toContain("─");
60
- });
61
- });