Unified tool call display schema, compaction timeline, and auth fixes

- Replace extractPrincipalParam, parseToolCallDisplay, getToolKindFromName
  with a single unified parseToolCallDisplay on the server, consumed by
  both server (activity-curator) and app
- Parse tool calls exactly once and pass ToolCallDisplayInfo down to all
  consumers (message, sheet, details, stream view)
- Add compaction timeline item: detect SDKStatusMessage (compacting) and
  SDKCompactBoundaryMessage, show loading/completed marker in timeline
- Suppress compact summary user message in live stream (flag) and JSONL
  resume (isCompactSummary check)
- Add CompactionMarker component with scissors icon and token count
- Hide sub-agent tool calls from timeline, collapse into Task metadata
- Add Bot icon for Task tool calls
- Fix stripShellWrapperPrefix to strip /bin/zsh -lc wrappers without cd
- Replace CLAUDE_SESSION_TOKEN with CLAUDE_CODE_OAUTH_TOKEN
This commit is contained in:
Mohamed Boudra
2026-02-07 21:13:24 +07:00
parent 598a1823ae
commit e3fad77d5b
18 changed files with 1470 additions and 867 deletions
@@ -1,9 +1,9 @@
import { describe, expect, test } from "vitest";
import {
stripShellWrapperPrefix,
extractPrincipalParam,
normalizeToolDisplayName,
stripCwdPrefix,
parseToolCallDisplay,
} from "./tool-call-parsers.js";
describe("stripShellWrapperPrefix", () => {
@@ -37,57 +37,22 @@ describe("stripShellWrapperPrefix", () => {
expect(stripShellWrapperPrefix(command)).toBe("npm run build");
});
test("returns command unchanged for partial match", () => {
test("strips shell prefix even without cd", () => {
const command = "/bin/zsh -lc npm run build";
expect(stripShellWrapperPrefix(command)).toBe("/bin/zsh -lc npm run build");
expect(stripShellWrapperPrefix(command)).toBe("npm run build");
});
test("strips when cd path includes spaces in quotes", () => {
const command = '/bin/zsh -lc cd "/path with spaces" && npm test';
expect(stripShellWrapperPrefix(command)).toBe("npm test");
});
});
describe("extractPrincipalParam", () => {
test("extracts and strips shell wrapper from command string", () => {
const args = { command: "/bin/zsh -lc cd /Users/dev/project && npm run format" };
expect(extractPrincipalParam(args)).toBe("npm run format");
});
test("extracts and strips shell wrapper from command array", () => {
const args = { command: ["/bin/bash", "-lc", "cd /path && git status"] };
// Array is joined with spaces first: "/bin/bash -lc cd /path && git status"
// Then shell wrapper is stripped
expect(extractPrincipalParam(args)).toBe("git status");
});
test("extracts plain command without shell wrapper", () => {
const args = { command: "npm run build" };
expect(extractPrincipalParam(args)).toBe("npm run build");
});
test("extracts file_path and strips cwd", () => {
const args = { file_path: "/Users/dev/project/src/file.ts" };
expect(extractPrincipalParam(args, "/Users/dev/project")).toBe("src/file.ts");
});
test("extracts pattern without modification", () => {
const args = { pattern: "*.ts" };
expect(extractPrincipalParam(args)).toBe("*.ts");
});
test("extracts query without modification", () => {
const args = { query: "search term" };
expect(extractPrincipalParam(args)).toBe("search term");
});
test("extracts url without modification", () => {
const args = { url: "https://example.com" };
expect(extractPrincipalParam(args)).toBe("https://example.com");
});
test("returns undefined for empty object", () => {
expect(extractPrincipalParam({})).toBeUndefined();
test("strips /bin/zsh -lc with quoted complex command", () => {
const command =
'/bin/zsh -lc "adb shell pm list packages | rg \'sh\\.paseo(\\.dev)?\' && adb shell cmd package resolve-activity --brief sh.paseo.dev | tail -n 1"';
expect(stripShellWrapperPrefix(command)).toBe(
"adb shell pm list packages | rg 'sh\\.paseo(\\.dev)?' && adb shell cmd package resolve-activity --brief sh.paseo.dev | tail -n 1"
);
});
});
@@ -128,3 +93,193 @@ describe("stripCwdPrefix", () => {
expect(stripCwdPrefix("/Users/dev/project/file.ts")).toBe("/Users/dev/project/file.ts");
});
});
describe("parseToolCallDisplay", () => {
describe("summary (was extractPrincipalParam)", () => {
test("extracts and strips shell wrapper from command string", () => {
const result = parseToolCallDisplay({
name: "Bash",
input: { command: "/bin/zsh -lc cd /Users/dev/project && npm run format" },
});
expect(result.summary).toBe("npm run format");
});
test("extracts and strips shell wrapper from command array", () => {
const result = parseToolCallDisplay({
name: "shell",
input: { command: ["/bin/bash", "-lc", "cd /path && git status"] },
});
expect(result.summary).toBe("git status");
});
test("extracts plain command without shell wrapper", () => {
const result = parseToolCallDisplay({
name: "Bash",
input: { command: "npm run build" },
});
expect(result.summary).toBe("npm run build");
});
test("extracts file_path and strips cwd", () => {
const result = parseToolCallDisplay({
name: "Read",
input: { file_path: "/Users/dev/project/src/file.ts" },
cwd: "/Users/dev/project",
});
expect(result.summary).toBe("src/file.ts");
});
test("extracts pattern without modification", () => {
const result = parseToolCallDisplay({
name: "Grep",
input: { pattern: "*.ts" },
});
expect(result.summary).toBe("*.ts");
});
test("extracts query without modification", () => {
const result = parseToolCallDisplay({
name: "WebSearch",
input: { query: "search term" },
});
expect(result.summary).toBe("search term");
});
test("extracts url without modification", () => {
const result = parseToolCallDisplay({
name: "WebFetch",
input: { url: "https://example.com" },
});
expect(result.summary).toBe("https://example.com");
});
test("returns undefined summary for empty input", () => {
const result = parseToolCallDisplay({ name: "Unknown", input: {} });
expect(result.summary).toBeUndefined();
});
test("extracts description from Task tool", () => {
const result = parseToolCallDisplay({
name: "Task",
input: { description: "Explore the codebase" },
});
expect(result.summary).toBe("Explore the codebase");
});
});
describe("summary from metadata", () => {
test("subAgentActivity in metadata takes priority over input", () => {
const result = parseToolCallDisplay({
name: "Task",
input: { description: "Explore codebase" },
metadata: { subAgentActivity: "Read" },
});
expect(result.summary).toBe("Read");
});
test("metadata merges with input for summary parsing", () => {
const result = parseToolCallDisplay({
name: "Task",
input: {},
metadata: { subAgentActivity: "Bash" },
});
expect(result.summary).toBe("Bash");
});
});
describe("kind", () => {
test("Read -> read", () => {
expect(parseToolCallDisplay({ name: "Read" }).kind).toBe("read");
});
test("read_file -> read", () => {
expect(parseToolCallDisplay({ name: "read_file" }).kind).toBe("read");
});
test("Edit -> edit", () => {
expect(parseToolCallDisplay({ name: "Edit" }).kind).toBe("edit");
});
test("Write -> edit", () => {
expect(parseToolCallDisplay({ name: "Write" }).kind).toBe("edit");
});
test("apply_patch -> edit", () => {
expect(parseToolCallDisplay({ name: "apply_patch" }).kind).toBe("edit");
});
test("Bash -> execute", () => {
expect(parseToolCallDisplay({ name: "Bash" }).kind).toBe("execute");
});
test("shell -> execute", () => {
expect(parseToolCallDisplay({ name: "shell" }).kind).toBe("execute");
});
test("Grep -> search", () => {
expect(parseToolCallDisplay({ name: "Grep" }).kind).toBe("search");
});
test("Glob -> search", () => {
expect(parseToolCallDisplay({ name: "Glob" }).kind).toBe("search");
});
test("thinking -> thinking", () => {
expect(parseToolCallDisplay({ name: "thinking" }).kind).toBe("thinking");
});
test("unknown tool -> tool", () => {
expect(parseToolCallDisplay({ name: "MyCustomTool" }).kind).toBe("tool");
});
});
describe("displayName", () => {
test("shell -> Shell", () => {
expect(parseToolCallDisplay({ name: "shell" }).displayName).toBe("Shell");
});
test("Bash -> Shell", () => {
expect(parseToolCallDisplay({ name: "Bash" }).displayName).toBe("Shell");
});
test("read_file -> Read", () => {
expect(parseToolCallDisplay({ name: "read_file" }).displayName).toBe("Read");
});
test("apply_patch -> Edit", () => {
expect(parseToolCallDisplay({ name: "apply_patch" }).displayName).toBe("Edit");
});
test("preserves unknown tool names", () => {
expect(parseToolCallDisplay({ name: "MyCustomTool" }).displayName).toBe("MyCustomTool");
});
test("normalizes speak variants", () => {
expect(parseToolCallDisplay({ name: "paseo_voice.speak" }).displayName).toBe("Speak");
expect(parseToolCallDisplay({ name: "mcp__paseo_voice__speak" }).displayName).toBe("Speak");
});
});
describe("errorText", () => {
test("formats string error", () => {
const result = parseToolCallDisplay({
name: "Bash",
error: "something broke",
});
expect(result.errorText).toBe("something broke");
});
test("extracts content from tool_result error", () => {
const result = parseToolCallDisplay({
name: "Bash",
error: { type: "tool_result", content: "Exit code 1", is_error: true },
});
expect(result.errorText).toBe("Exit code 1");
});
test("returns undefined for no error", () => {
const result = parseToolCallDisplay({ name: "Read" });
expect(result.errorText).toBeUndefined();
});
});
});