feat: Claude Code Monitor — lanes, pipelines and a merged workspace

Internal SmartGift build of a Claude Code monitoring dashboard.

Lanes: a durable unit of parallel agent work, one per working directory,
tracked across session restarts. Managed lanes are git worktrees the
dashboard provisions and can reset or remove behind a three-check destroy
guard and a counted preflight; adopted lanes are directories you already
own and are never destroyable.

Pipelines: a lane moves through pipeline stages. A stage the agent declares
with evidence renders green; a stage inferred from the tool-event stream
renders dashed amber and never counts as done. Detection is forward-only
within a 30-minute window, and never writes the declared stage.

Workspace: one page at /run with a lane grid, the selected lane's pipeline,
and a full Claude console behind a disclosure.
This commit is contained in:
2026-07-29 17:07:45 +07:00
commit 57dc91585d
783 changed files with 221743 additions and 0 deletions
@@ -0,0 +1,75 @@
/**
* @file MarkdownContent.test.tsx
* @description Tests for the lightweight markdown renderer used by the conversation viewer.
* Focuses on the block parser since the inline parser is well-exercised by snapshot-style
* DOM assertions.
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
*/
import { describe, it, expect } from "vitest";
import { render, screen } from "@testing-library/react";
import { MarkdownContent } from "../MarkdownContent";
describe("<MarkdownContent />", () => {
it("renders fenced code blocks with the language label", () => {
render(<MarkdownContent text={"Here is some code:\n```js\nconst x = 1;\n```"} />);
// The CodeBlock header shows the language
expect(screen.getByText(/javascript/i)).toBeInTheDocument();
// The code text is present (split across syntax-highlighted spans, so use a substring)
expect(screen.getByText(/const/)).toBeInTheDocument();
});
it("renders headings as semantic-looking elements", () => {
render(<MarkdownContent text={"# Title\n\nbody"} />);
expect(screen.getByText("Title")).toBeInTheDocument();
expect(screen.getByText("body")).toBeInTheDocument();
});
it("renders unordered and ordered lists", () => {
const { container } = render(<MarkdownContent text={"- one\n- two\n\n1. first\n2. second"} />);
expect(container.querySelectorAll("ul li")).toHaveLength(2);
expect(container.querySelectorAll("ol li")).toHaveLength(2);
});
it("renders blockquotes", () => {
const { container } = render(<MarkdownContent text={"> a quote"} />);
expect(container.querySelector("blockquote")).not.toBeNull();
expect(screen.getByText("a quote")).toBeInTheDocument();
});
it("renders inline code, bold, and italic", () => {
const { container } = render(
<MarkdownContent text={"This has `code`, **bold**, and *italic*."} />
);
expect(container.querySelector("code")).not.toBeNull();
expect(container.querySelector("strong")).not.toBeNull();
expect(container.querySelector("em")).not.toBeNull();
});
it("auto-links bare URLs and renders explicit markdown links", () => {
const { container } = render(
<MarkdownContent text={"See https://example.com or [docs](https://example.com/docs)."} />
);
const links = container.querySelectorAll("a");
expect(links.length).toBe(2);
expect(links[0]!.getAttribute("href")).toBe("https://example.com");
expect(links[1]!.getAttribute("href")).toBe("https://example.com/docs");
// Both should open in a new tab safely
for (const a of links) {
expect(a.getAttribute("target")).toBe("_blank");
expect(a.getAttribute("rel")).toContain("noopener");
}
});
it("renders plain text without any markdown features", () => {
render(<MarkdownContent text={"just a normal sentence."} />);
expect(screen.getByText("just a normal sentence.")).toBeInTheDocument();
});
it("handles empty input safely", () => {
const { container } = render(<MarkdownContent text="" />);
// Wrapper exists but no block elements
expect(container.firstChild).not.toBeNull();
expect(container.querySelectorAll("p, ul, ol, blockquote, pre, hr").length).toBe(0);
});
});
@@ -0,0 +1,54 @@
/**
* @file MessageList.sender.test.tsx
* @description Verifies the transcript renders each message under its TRUE
* sender label — User / Assistant / Main agent / System — instead of labeling
* every `type:"user"` line "User" (reported transcript mis-attribution).
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
*/
import { describe, it, expect } from "vitest";
import { render, screen } from "@testing-library/react";
import { MessageList } from "../MessageList";
import type { TranscriptMessage } from "../../../lib/types";
function msg(partial: Partial<TranscriptMessage>): TranscriptMessage {
return {
type: "user",
timestamp: "2026-06-26T08:14:00.000Z",
content: [{ type: "text", text: "hello" }],
...partial,
} as TranscriptMessage;
}
describe("MessageList — sender attribution", () => {
it("labels each row by its sender, not blanket 'User'", () => {
const messages: TranscriptMessage[] = [
msg({ sender: "user", content: [{ type: "text", text: "spin up a team" }] }),
msg({
type: "assistant",
sender: "assistant",
content: [{ type: "text", text: "on it" }],
}),
msg({
sender: "system",
content: [{ type: "text", text: "<task-notification>\n<task-id>x</task-id>\n" }],
}),
msg({ sender: "orchestrator", content: [{ type: "text", text: "Light research task…" }] }),
];
render(<MessageList messages={messages} loading={false} />);
expect(screen.getByText("User")).toBeInTheDocument();
expect(screen.getByText("Assistant")).toBeInTheDocument();
expect(screen.getByText("System")).toBeInTheDocument();
expect(screen.getByText("Main agent")).toBeInTheDocument();
});
it("falls back to type-based labels when sender is absent (legacy payloads)", () => {
const messages: TranscriptMessage[] = [
msg({ content: [{ type: "text", text: "hi there" }] }), // no sender → "User"
msg({ type: "assistant", content: [{ type: "text", text: "hello" }] }), // → "Assistant"
];
render(<MessageList messages={messages} loading={false} />);
expect(screen.getByText("User")).toBeInTheDocument();
expect(screen.getByText("Assistant")).toBeInTheDocument();
});
});