feat: right-click menus everywhere, workspace/session cost, long-term DB safety

Right-click menus: one portal shell (components/ContextMenu.tsx) for every
item with actions - sidebar/Recents/archived session rows (SessionMenu),
console tabs, pane headers, the Changes panel's files/tree/commits, the
workspace home, sessions outside a workspace (SessionRowMenu: Sessions
table, Dashboard, Activity, Workflow runs), prompt images, every Settings
list and every Claude Code/Codex config list (FileItemMenu). Buttons stay;
a delete keeps its button's confirm; the shell stops portal clicks from
reaching the card that opened it.

Status bar: Workspace $ and Session $ on the Workspace page, from
?lane= on GET /api/pricing/cost and the focused/replayed session's cost.

Database, no data dropped: synchronous=NORMAL, journal_size_limit 64 MB,
hourly PASSIVE checkpoint + PRAGMA optimize, idx_events_session_created
(replacing the redundant idx_events_session), watchdog reads
sessions.transcript_path, transcript parsed before the hook's write
transaction, GET /api/sessions/:id?events=0 for the web page (reloads only
on its own session, debounced), streamed export, transactional clear-data
and chunked cleanup, subagent import reads tool_use_ids once, runtime logs
rotated past 5 MB.
This commit is contained in:
2026-10-05 09:37:48 +07:00
parent 65fe680d38
commit ad6e80192d
80 changed files with 2914 additions and 489 deletions
+13 -1
View File
@@ -1,6 +1,6 @@
/**
* @file AgentCard.tsx
* @description Defines the AgentCard component that displays a summary of an agent's information, including its name, status, task, current tool, and timestamps. The card is clickable and navigates to the agent's session details when clicked. It also visually distinguishes active agents with a border highlight.
* @description Defines the AgentCard component that displays a summary of an agent's information, including its name, status, task, current tool, and timestamps. The card is clickable and navigates to the agent's session details when clicked; a right-click opens `SessionRowMenu`. It also visually distinguishes active agents with a border highlight.
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
*/
/* =============================================================================
@@ -51,6 +51,8 @@ import { useTranslation } from "react-i18next";
import { Bot, GitBranch, Clock, Wrench, Cpu, Coins } from "lucide-react";
import { useNavigate } from "react-router-dom";
import { AgentStatusBadge } from "./StatusBadge";
import { useContextMenu } from "./ContextMenu";
import { SessionRowMenu } from "./SessionRowMenu";
import { effectiveAgentStatus, isAgentAwaitingInput, agentAwaitingReason } from "../lib/types";
import type { Agent, Session } from "../lib/types";
import { formatDuration, timeAgo, formatModelName, pathBasename, fmtCost } from "../lib/format";
@@ -83,6 +85,7 @@ interface AgentCardProps {
export function AgentCard({ agent, session, label, onClick }: AgentCardProps) {
const navigate = useNavigate();
const { t } = useTranslation("kanban");
const ctx = useContextMenu<true>();
const isWaiting = agent.status === "waiting" || isAgentAwaitingInput(agent);
const status = effectiveAgentStatus(agent);
const isActive = agent.status === "working";
@@ -170,6 +173,7 @@ export function AgentCard({ agent, session, label, onClick }: AgentCardProps) {
return (
<div
onClick={handleClick}
onContextMenu={(e) => ctx.open(e, true)}
className={`card-hover p-4 cursor-pointer overflow-hidden ${
isWaiting
? "border-l-2 border-l-yellow-500/60"
@@ -252,6 +256,14 @@ export function AgentCard({ agent, session, label, onClick }: AgentCardProps) {
<span className="font-mono flex-shrink-0">{agent.session_id.slice(0, 8)}</span>
</span>
</div>
{ctx.menu && (
<SessionRowMenu
session={{ id: agent.session_id, lane_id: session?.lane_id, cwd: session?.cwd }}
x={ctx.menu.x}
y={ctx.menu.y}
onClose={ctx.close}
/>
)}
</div>
);
}