fix: improve file path display and TodoWrite executing state handling
This commit is contained in:
@@ -359,8 +359,13 @@ const DiffFileSection = memo(function DiffFileSection({
|
|||||||
color={theme.colors.foregroundMuted}
|
color={theme.colors.foregroundMuted}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<Text style={styles.filePath} numberOfLines={1} ellipsizeMode="middle">
|
<Text style={styles.filePath} numberOfLines={1} ellipsizeMode="head">
|
||||||
{file.path}
|
<Text style={styles.fileName}>{file.path.split("/").pop()}</Text>
|
||||||
|
<Text style={styles.fileDir}>
|
||||||
|
{file.path.includes("/")
|
||||||
|
? ` ${file.path.slice(0, file.path.lastIndexOf("/"))}`
|
||||||
|
: ""}
|
||||||
|
</Text>
|
||||||
</Text>
|
</Text>
|
||||||
{file.isNew && (
|
{file.isNew && (
|
||||||
<View style={styles.newBadge}>
|
<View style={styles.newBadge}>
|
||||||
@@ -1381,6 +1386,13 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
color: theme.colors.foreground,
|
color: theme.colors.foreground,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
|
fileName: {
|
||||||
|
fontWeight: theme.fontWeight.semibold,
|
||||||
|
},
|
||||||
|
fileDir: {
|
||||||
|
color: theme.colors.foregroundMuted,
|
||||||
|
fontWeight: theme.fontWeight.normal,
|
||||||
|
},
|
||||||
newBadge: {
|
newBadge: {
|
||||||
backgroundColor: "rgba(46, 160, 67, 0.2)",
|
backgroundColor: "rgba(46, 160, 67, 0.2)",
|
||||||
paddingHorizontal: theme.spacing[2],
|
paddingHorizontal: theme.spacing[2],
|
||||||
|
|||||||
@@ -722,6 +722,31 @@ function testTodoWriteToolCallCreatesTodoList() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testTodoWriteToolCallExecutingDoesNotRenderToolCall() {
|
||||||
|
const timestamp = new Date("2025-01-01T12:32:00Z");
|
||||||
|
const event = toolTimelineWithInput({
|
||||||
|
provider: "claude",
|
||||||
|
name: "TodoWrite",
|
||||||
|
status: "executing",
|
||||||
|
input: {
|
||||||
|
todos: [{ content: "Task", status: "pending" }],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const state = reduceStreamUpdate([], event, timestamp);
|
||||||
|
const todoEntries = state.filter(
|
||||||
|
(item): item is TodoListItem => item.kind === "todo_list"
|
||||||
|
);
|
||||||
|
const toolCalls = state.filter((item) => item.kind === "tool_call");
|
||||||
|
|
||||||
|
assert.strictEqual(todoEntries.length, 1);
|
||||||
|
assert.strictEqual(
|
||||||
|
toolCalls.length,
|
||||||
|
0,
|
||||||
|
"TodoWrite (executing) should not render as a tool call"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function testTimelineIdStabilityAfterRemovals() {
|
function testTimelineIdStabilityAfterRemovals() {
|
||||||
const timestamp = new Date('2025-01-01T12:35:00Z');
|
const timestamp = new Date('2025-01-01T12:35:00Z');
|
||||||
|
|
||||||
@@ -1097,6 +1122,10 @@ describe('stream timeline reducers', () => {
|
|||||||
it('retains hydrated user messages across providers', testHydratedUserMessagesPersist);
|
it('retains hydrated user messages across providers', testHydratedUserMessagesPersist);
|
||||||
it('consolidates todo list updates', testTodoListConsolidation);
|
it('consolidates todo list updates', testTodoListConsolidation);
|
||||||
it('renders TodoWrite as a task list', testTodoWriteToolCallCreatesTodoList);
|
it('renders TodoWrite as a task list', testTodoWriteToolCallCreatesTodoList);
|
||||||
|
it(
|
||||||
|
"does not render TodoWrite (executing) as a tool call",
|
||||||
|
testTodoWriteToolCallExecutingDoesNotRenderToolCall
|
||||||
|
);
|
||||||
it('keeps timeline ids stable after list shrinkage', testTimelineIdStabilityAfterRemovals);
|
it('keeps timeline ids stable after list shrinkage', testTimelineIdStabilityAfterRemovals);
|
||||||
it('deduplicates live tool call entries', testToolCallDeduplicationLive);
|
it('deduplicates live tool call entries', testToolCallDeduplicationLive);
|
||||||
it('deduplicates hydrated tool call entries', testToolCallDeduplicationHydrated);
|
it('deduplicates hydrated tool call entries', testToolCallDeduplicationHydrated);
|
||||||
|
|||||||
@@ -764,6 +764,28 @@ export function reduceStreamUpdate(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
event.provider === "claude" &&
|
||||||
|
(normalizedToolName === "todowrite" ||
|
||||||
|
normalizedToolName === "todo_write")
|
||||||
|
) {
|
||||||
|
// For Claude: TodoWrite often appears as a tool call that never resolves. Always render it
|
||||||
|
// as Tasks when possible and otherwise hide it to avoid a stuck loading tool call.
|
||||||
|
const tasks = extractTaskEntriesFromToolCall(item.name, item.input);
|
||||||
|
if (tasks) {
|
||||||
|
nextState = appendTodoList(
|
||||||
|
state,
|
||||||
|
event.provider,
|
||||||
|
tasks.map((entry) => ({
|
||||||
|
text: entry.text,
|
||||||
|
completed: entry.completed,
|
||||||
|
})),
|
||||||
|
timestamp
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const tasks = extractTaskEntriesFromToolCall(
|
const tasks = extractTaskEntriesFromToolCall(
|
||||||
item.name,
|
item.name,
|
||||||
item.input
|
item.input
|
||||||
|
|||||||
Reference in New Issue
Block a user