diff --git a/web/src/ChatStream.test.tsx b/web/src/ChatStream.test.tsx
index 0578c6a..00178a7 100644
--- a/web/src/ChatStream.test.tsx
+++ b/web/src/ChatStream.test.tsx
@@ -63,10 +63,7 @@ function stream(p: {
describe("Bubble", () => {
it("renders plain text per role class", () => {
const { container } = render(
- ,
+ ,
);
expect(container.querySelector(".bubble-row.user")).not.toBeNull();
expect(container.textContent).toContain("hi there");
@@ -94,10 +91,7 @@ describe("Bubble", () => {
it("toolResult collapses to a one-line preview, expands to full text", async () => {
const long = `${"x".repeat(200)}`;
render(
- ,
+ ,
);
const details = screen
.getByText("result")
@@ -160,9 +154,7 @@ describe("Bubble", () => {
expect(screen.getByText("🛠bash")).toBeInTheDocument();
expect(screen.getByText("finished")).toBeInTheDocument();
- const summary = screen
- .getByText("🛠bash")
- .closest("summary") as HTMLElement;
+ const summary = screen.getByText("🛠bash").closest("summary") as HTMLElement;
const card = summary.closest("details") as HTMLDetailsElement;
expect(card.open).toBe(false);
await userEvent.click(summary);
@@ -256,9 +248,7 @@ describe("ChatStream", () => {
}),
);
expect(container.querySelector(".typing")).toBeNull();
- rerender(
- stream({ messages: [msg({ key: "a", text: "one" })], busy: false }),
- );
+ rerender(stream({ messages: [msg({ key: "a", text: "one" })], busy: false }));
expect(container.querySelector(".typing")).toBeNull();
});
@@ -767,15 +757,34 @@ describe("copy button", () => {
describe("pretty tool args", () => {
const tool = (args: string): ToolState => ({
- id: "t1", name: "bash", args, running: false, isError: false, preview: "out",
+ id: "t1",
+ name: "bash",
+ args,
+ running: false,
+ isError: false,
+ preview: "out",
});
it("bash command renders as the bare command, no JSON braces", () => {
- render();
+ render(
+ ,
+ );
expect(document.querySelector(".tool-summary")?.textContent).toBe("ls -la");
- expect(document.querySelector(".tool-args")?.textContent).not.toContain('"command"');
+ expect(document.querySelector(".tool-args")?.textContent).not.toContain(
+ '"command"',
+ );
});
it("priority ordering puts command first even when not first in JSON", () => {
@@ -785,10 +794,24 @@ describe("pretty tool args", () => {
});
it("single string arg renders label-less; multi-field keeps labels", () => {
- render();
- expect(document.querySelector(".tool-summary")?.textContent).toBe("src/main.ts");
+ render(
+ ,
+ );
+ expect(document.querySelector(".tool-summary")?.textContent).toBe(
+ "src/main.ts",
+ );
expect(document.querySelector(".tool-args .arg-k")).toBeNull();
});
@@ -839,7 +862,9 @@ describe("tool summary + diff", () => {
tools={new Map([["t1", tool('{"path":"src/main.ts"}', "read")]])}
/>,
);
- expect(document.querySelector(".tool-summary")?.textContent).toBe("src/main.ts");
+ expect(document.querySelector(".tool-summary")?.textContent).toBe(
+ "src/main.ts",
+ );
});
it("long summary is truncated with ellipsis", () => {
@@ -863,20 +888,28 @@ describe("tool summary + diff", () => {
msg={msg({
toolCalls: [{ id: "t1", name: "edit", argsJson: "{}" }],
})}
- tools={new Map([
- [
- "t1",
- tool(
- '{"path":"a.ts","edits":[{"oldText":"const a = 1;\\nconst b = 2;","newText":"const a = 3;\\nconst b = 2;"}]}',
- "edit",
- ),
- ],
- ])}
+ tools={
+ new Map([
+ [
+ "t1",
+ tool(
+ '{"path":"a.ts","edits":[{"oldText":"const a = 1;\\nconst b = 2;","newText":"const a = 3;\\nconst b = 2;"}]}',
+ "edit",
+ ),
+ ],
+ ])
+ }
/>,
);
- expect(document.querySelector(".diff-del")?.textContent).toContain("-const a = 1;");
- expect(document.querySelector(".diff-add")?.textContent).toContain("+const a = 3;");
- expect(document.querySelector(".diff-ctx")?.textContent).toContain(" const b = 2;");
+ expect(document.querySelector(".diff-del")?.textContent).toContain(
+ "-const a = 1;",
+ );
+ expect(document.querySelector(".diff-add")?.textContent).toContain(
+ "+const a = 3;",
+ );
+ expect(document.querySelector(".diff-ctx")?.textContent).toContain(
+ " const b = 2;",
+ );
expect(document.querySelector(".tool-args")).toBeNull();
});
@@ -886,9 +919,11 @@ describe("tool summary + diff", () => {
msg={msg({
toolCalls: [{ id: "t1", name: "write", argsJson: "{}" }],
})}
- tools={new Map([
- ["t1", tool('{"path":"new.ts","content":"hello\\nworld"}', "write")],
- ])}
+ tools={
+ new Map([
+ ["t1", tool('{"path":"new.ts","content":"hello\\nworld"}', "write")],
+ ])
+ }
/>,
);
const adds = document.querySelectorAll(".diff-add");
diff --git a/web/src/index.css b/web/src/index.css
index c0420fa..38905ec 100644
--- a/web/src/index.css
+++ b/web/src/index.css
@@ -25,8 +25,7 @@
--shadow-1: 0 1px 2px rgba(0, 0, 0, 0.35);
--shadow-2: 0 8px 28px rgba(0, 0, 0, 0.45);
font-family:
- ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Inter,
- sans-serif;
+ ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Inter, sans-serif;
}
* {
@@ -1445,24 +1444,37 @@ mark.hit {
/* ---------- busy activity pip ---------- */
.busy-pip {
- display: inline-block;
- width: 8px;
- height: 8px;
- margin-left: 7px;
- border-radius: 50%;
- background: var(--accent);
- animation: busy-pulse 1.1s ease-in-out infinite;
- vertical-align: middle;
+ display: inline-block;
+ width: 8px;
+ height: 8px;
+ margin-left: 7px;
+ border-radius: 50%;
+ background: var(--accent);
+ animation: busy-pulse 1.1s ease-in-out infinite;
+ vertical-align: middle;
}
@keyframes busy-pulse {
- 0%, 100% { transform: scale(0.55); opacity: 0.45; box-shadow: 0 0 0 0 rgba(108, 140, 255, 0.5); }
- 50% { transform: scale(1); opacity: 1; box-shadow: 0 0 0 5px rgba(108, 140, 255, 0); }
+ 0%,
+ 100% {
+ transform: scale(0.55);
+ opacity: 0.45;
+ box-shadow: 0 0 0 0 rgba(108, 140, 255, 0.5);
+ }
+ 50% {
+ transform: scale(1);
+ opacity: 1;
+ box-shadow: 0 0 0 5px rgba(108, 140, 255, 0);
+ }
}
/* ---------- pretty tool args ---------- */
-.tool-args { margin-bottom: 10px; }
-.tool-arg { margin-bottom: 6px; }
+.tool-args {
+ margin-bottom: 10px;
+}
+.tool-arg {
+ margin-bottom: 6px;
+}
.arg-k {
display: block;
font-size: 10.5px;