Skip to content

Commit 83c940d

Browse files
committed
Improve bash tool colors
and fmt changes
1 parent 4841e93 commit 83c940d

File tree

9 files changed

+1231
-1104
lines changed

9 files changed

+1231
-1104
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ on:
55
branches: ["main"]
66
pull_request:
77
branches: ["**"]
8-
workflow_dispatch: # Allow manual triggering
8+
workflow_dispatch: # Allow manual triggering
99

1010
jobs:
1111
build-macos:

src/components/tools/BashToolCall.tsx

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from "react";
1+
import React, { useState, useEffect, useRef } from "react";
22
import styled from "@emotion/styled";
33
import type { BashToolArgs, BashToolResult } from "../../types/tools";
44
import {
@@ -51,8 +51,16 @@ const ExitCodeBadge = styled.span<{ exitCode: number }>`
5151
margin-left: 8px;
5252
`;
5353

54-
const TimeoutInfo = styled.span`
55-
color: var(--color-text-secondary);
54+
const TimeoutInfo = styled.span<{ status?: ToolStatus }>`
55+
color: ${({ status }) => {
56+
switch (status) {
57+
case "executing":
58+
case "pending":
59+
return "var(--color-pending)";
60+
default:
61+
return "var(--color-text-secondary)";
62+
}
63+
}};
5664
font-size: 10px;
5765
margin-left: 8px;
5866
`;
@@ -76,21 +84,40 @@ function formatDuration(ms: number): string {
7684
if (ms < 1000) {
7785
return `${Math.round(ms)}ms`;
7886
}
79-
return `${(ms / 1000).toFixed(1)}s`;
87+
return `${Math.round(ms / 1000)}s`;
8088
}
8189

8290
export const BashToolCall: React.FC<BashToolCallProps> = ({ args, result, status = "pending" }) => {
8391
const { expanded, toggleExpanded } = useToolExpansion();
92+
const [elapsedTime, setElapsedTime] = useState(0);
93+
const startTimeRef = useRef<number>(Date.now());
94+
95+
// Track elapsed time for pending/executing status
96+
useEffect(() => {
97+
if (status === "executing" || status === "pending") {
98+
startTimeRef.current = Date.now();
99+
setElapsedTime(0);
100+
101+
const timer = setInterval(() => {
102+
setElapsedTime(Date.now() - startTimeRef.current);
103+
}, 1000);
104+
105+
return () => clearInterval(timer);
106+
}
107+
}, [status]);
108+
109+
const isPending = status === "executing" || status === "pending";
84110

85111
return (
86112
<ToolContainer expanded={expanded}>
87113
<ToolHeader onClick={toggleExpanded}>
88114
<ExpandIcon expanded={expanded}></ExpandIcon>
89115
<ToolName>bash</ToolName>
90116
<ScriptPreview>{args.script}</ScriptPreview>
91-
<TimeoutInfo>
117+
<TimeoutInfo status={isPending ? status : undefined}>
92118
timeout: {args.timeout_secs}s
93119
{result && ` • took ${formatDuration(result.wall_duration_ms)}`}
120+
{!result && isPending && elapsedTime > 0 && ` • ${formatDuration(elapsedTime)}`}
94121
</TimeoutInfo>
95122
{result && <ExitCodeBadge exitCode={result.exitCode}>{result.exitCode}</ExitCodeBadge>}
96123
<StatusIndicator status={status}>{getStatusDisplay(status)}</StatusIndicator>

src/components/tools/shared/ToolPrimitives.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,15 @@ export const StatusIndicator = styled.span<{ status: string }>`
4646
color: ${({ status }) => {
4747
switch (status) {
4848
case "executing":
49-
return "#ffa000";
49+
return "var(--color-pending)";
5050
case "completed":
5151
return "#4caf50";
5252
case "failed":
5353
return "#f44336";
5454
case "interrupted":
55-
return "var(--color-warning, #f59e0b)";
55+
return "var(--color-interrupted)";
5656
default:
57-
return "#9e9e9e";
57+
return "var(--color-text-secondary)";
5858
}
5959
}};
6060
`;

src/styles/colors.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ export const GlobalColors = () => (
4747
--color-editing-mode: hsl(30 100% 50%);
4848
--color-editing-mode-alpha: hsl(from var(--color-editing-mode) h s l / 0.1);
4949
50+
/* Pending Colors */
51+
--color-pending: color-mix(in srgb, var(--color-editing-mode), white 40%);
52+
5053
/* Debug Mode Colors */
5154
--color-debug: hsl(214 100% 64%);
5255
--color-debug-light: color-mix(in srgb, var(--color-debug), white 20%);

tests/ipcMain/createWorkspace.test.ts

Lines changed: 73 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -6,75 +6,86 @@ import { createTempGitRepo, cleanupTempGitRepo } from "./helpers";
66
const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip;
77

88
describeIntegration("IpcMain create workspace integration tests", () => {
9-
test.concurrent("should fail to create workspace with invalid name", async () => {
10-
const env = await createTestEnvironment();
11-
const tempGitRepo = await createTempGitRepo();
9+
test.concurrent(
10+
"should fail to create workspace with invalid name",
11+
async () => {
12+
const env = await createTestEnvironment();
13+
const tempGitRepo = await createTempGitRepo();
1214

13-
try {
14-
// Test various invalid names
15-
const invalidNames = [
16-
{ name: "", expectedError: "empty" },
17-
{ name: "My-Branch", expectedError: "lowercase" },
18-
{ name: "branch name", expectedError: "lowercase" },
19-
{ name: "branch@123", expectedError: "lowercase" },
20-
{ name: "branch/test", expectedError: "lowercase" },
21-
{ name: "branch\\test", expectedError: "lowercase" },
22-
{ name: "branch.test", expectedError: "lowercase" },
23-
{ name: "a".repeat(65), expectedError: "64 characters" },
24-
];
15+
try {
16+
// Test various invalid names
17+
const invalidNames = [
18+
{ name: "", expectedError: "empty" },
19+
{ name: "My-Branch", expectedError: "lowercase" },
20+
{ name: "branch name", expectedError: "lowercase" },
21+
{ name: "branch@123", expectedError: "lowercase" },
22+
{ name: "branch/test", expectedError: "lowercase" },
23+
{ name: "branch\\test", expectedError: "lowercase" },
24+
{ name: "branch.test", expectedError: "lowercase" },
25+
{ name: "a".repeat(65), expectedError: "64 characters" },
26+
];
2527

26-
for (const { name, expectedError } of invalidNames) {
27-
const createResult = await env.mockIpcRenderer.invoke(
28-
IPC_CHANNELS.WORKSPACE_CREATE,
29-
tempGitRepo,
30-
name
31-
);
32-
expect(createResult.success).toBe(false);
33-
expect(createResult.error.toLowerCase()).toContain(expectedError.toLowerCase());
28+
for (const { name, expectedError } of invalidNames) {
29+
const createResult = await env.mockIpcRenderer.invoke(
30+
IPC_CHANNELS.WORKSPACE_CREATE,
31+
tempGitRepo,
32+
name
33+
);
34+
expect(createResult.success).toBe(false);
35+
expect(createResult.error.toLowerCase()).toContain(expectedError.toLowerCase());
36+
}
37+
} finally {
38+
await cleanupTestEnvironment(env);
39+
await cleanupTempGitRepo(tempGitRepo);
3440
}
35-
} finally {
36-
await cleanupTestEnvironment(env);
37-
await cleanupTempGitRepo(tempGitRepo);
38-
}
39-
}, 15000);
41+
},
42+
15000
43+
);
4044

41-
test.concurrent("should successfully create workspace with valid name", async () => {
42-
const env = await createTestEnvironment();
43-
const tempGitRepo = await createTempGitRepo();
45+
test.concurrent(
46+
"should successfully create workspace with valid name",
47+
async () => {
48+
const env = await createTestEnvironment();
49+
const tempGitRepo = await createTempGitRepo();
4450

45-
try {
46-
// Test various valid names (avoid "main" as it's already checked out in the repo)
47-
const validNames = [
48-
"feature-branch",
49-
"feature_branch",
50-
"branch123",
51-
"test-branch_123",
52-
"x", // Single character
53-
"b".repeat(64), // Max length
54-
];
51+
try {
52+
// Test various valid names (avoid "main" as it's already checked out in the repo)
53+
const validNames = [
54+
"feature-branch",
55+
"feature_branch",
56+
"branch123",
57+
"test-branch_123",
58+
"x", // Single character
59+
"b".repeat(64), // Max length
60+
];
5561

56-
for (const name of validNames) {
57-
const createResult = await env.mockIpcRenderer.invoke(
58-
IPC_CHANNELS.WORKSPACE_CREATE,
59-
tempGitRepo,
60-
name
61-
);
62-
if (!createResult.success) {
63-
console.error(`Failed to create workspace "${name}":`, createResult.error);
64-
}
65-
expect(createResult.success).toBe(true);
66-
expect(createResult.metadata.id).toBeDefined();
67-
expect(createResult.metadata.workspacePath).toBeDefined();
68-
expect(createResult.metadata.projectName).toBeDefined();
62+
for (const name of validNames) {
63+
const createResult = await env.mockIpcRenderer.invoke(
64+
IPC_CHANNELS.WORKSPACE_CREATE,
65+
tempGitRepo,
66+
name
67+
);
68+
if (!createResult.success) {
69+
console.error(`Failed to create workspace "${name}":`, createResult.error);
70+
}
71+
expect(createResult.success).toBe(true);
72+
expect(createResult.metadata.id).toBeDefined();
73+
expect(createResult.metadata.workspacePath).toBeDefined();
74+
expect(createResult.metadata.projectName).toBeDefined();
6975

70-
// Clean up the workspace
71-
if (createResult.metadata.id) {
72-
await env.mockIpcRenderer.invoke(IPC_CHANNELS.WORKSPACE_REMOVE, createResult.metadata.id);
76+
// Clean up the workspace
77+
if (createResult.metadata.id) {
78+
await env.mockIpcRenderer.invoke(
79+
IPC_CHANNELS.WORKSPACE_REMOVE,
80+
createResult.metadata.id
81+
);
82+
}
7383
}
84+
} finally {
85+
await cleanupTestEnvironment(env);
86+
await cleanupTempGitRepo(tempGitRepo);
7487
}
75-
} finally {
76-
await cleanupTestEnvironment(env);
77-
await cleanupTempGitRepo(tempGitRepo);
78-
}
79-
}, 30000);
88+
},
89+
30000
90+
);
8091
});

tests/ipcMain/helpers.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -276,10 +276,9 @@ export async function createTempGitRepo(): Promise<string> {
276276

277277
// Batch git commands where possible to reduce overhead
278278
await execAsync(`git init`, { cwd: tempDir });
279-
await execAsync(
280-
`git config user.email "test@example.com" && git config user.name "Test User"`,
281-
{ cwd: tempDir }
282-
);
279+
await execAsync(`git config user.email "test@example.com" && git config user.name "Test User"`, {
280+
cwd: tempDir,
281+
});
283282
await execAsync(
284283
`echo "test" > README.md && git add . && git commit -m "Initial commit" && git branch test-branch`,
285284
{ cwd: tempDir }

0 commit comments

Comments
 (0)