fix(run): plumb the recorded prompt back into live runs, fix lane routing when the cwd doesn't match the selected lane
- pty-run.js's publicRun() now reads promptPreview back from the dashboard_runs row it already wrote at spawn time (was persisted, never read back) — RunHandle carries it through to the client. - Workspace.tsx's onStartFromSetup no longer trusts RunSetup's always-populated laneId prop to decide whether a new lane needs ensuring — it re-resolves the target lane from the cwd the user actually typed, so starting a run with a different cwd than the currently-selected lane correctly ensures/creates the right lane instead of silently starting in the wrong one. Fixes findings from the Task 8+9+10 review that a prior fix attempt left unresolved (2f39f4e's --no-verify commit, and an incomplete diagnosis of the lane-routing bug as a test-harness artifact).
This commit is contained in:
@@ -125,7 +125,7 @@ export function ActiveRunsSwitcher({
|
|||||||
cwd: r.cwd || "",
|
cwd: r.cwd || "",
|
||||||
model: r.model,
|
model: r.model,
|
||||||
status: r.status,
|
status: r.status,
|
||||||
promptPreview: "",
|
promptPreview: r.promptPreview || "",
|
||||||
startedAt: r.startedAt ? new Date(r.startedAt).getTime() : 0,
|
startedAt: r.startedAt ? new Date(r.startedAt).getTime() : 0,
|
||||||
endedAt: null,
|
endedAt: null,
|
||||||
isLive: r.status === "running",
|
isLive: r.status === "running",
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ const activeRuns = {
|
|||||||
model: "claude-opus-5",
|
model: "claude-opus-5",
|
||||||
status: "running",
|
status: "running",
|
||||||
startedAt: "2000-01-01T00:50:00Z",
|
startedAt: "2000-01-01T00:50:00Z",
|
||||||
|
promptPreview: "the live prompt",
|
||||||
endedAt: null,
|
endedAt: null,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -2466,6 +2466,8 @@ export interface RunHandle {
|
|||||||
sessionId: string | null;
|
sessionId: string | null;
|
||||||
/** ISO timestamp the tmux session was created. */
|
/** ISO timestamp the tmux session was created. */
|
||||||
startedAt: string | null;
|
startedAt: string | null;
|
||||||
|
/** Initial prompt preview (first 500 chars), null when not provided. */
|
||||||
|
promptPreview: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Response shape of GET /api/run. */
|
/** Response shape of GET /api/run. */
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ import type {
|
|||||||
RunHandle,
|
RunHandle,
|
||||||
RunListResponse,
|
RunListResponse,
|
||||||
RunMode,
|
RunMode,
|
||||||
|
RunStartArgs,
|
||||||
} from "../lib/api";
|
} from "../lib/api";
|
||||||
import type {
|
import type {
|
||||||
Session,
|
Session,
|
||||||
@@ -606,7 +607,7 @@ export function Workspace() {
|
|||||||
}, [binaryStatus, prompt, cwd, busy, handle, start]);
|
}, [binaryStatus, prompt, cwd, busy, handle, start]);
|
||||||
|
|
||||||
const onStartFromSetup = useCallback(
|
const onStartFromSetup = useCallback(
|
||||||
async (args: any) => {
|
async (args: RunStartArgs) => {
|
||||||
if (busy) return;
|
if (busy) return;
|
||||||
setBusy("start");
|
setBusy("start");
|
||||||
setError(null);
|
setError(null);
|
||||||
@@ -621,29 +622,30 @@ export function Workspace() {
|
|||||||
throw new Error(t("errors.cwdRequired"));
|
throw new Error(t("errors.cwdRequired"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let targetLaneId = args.laneId;
|
// Resolve the lane from the cwd the user actually typed, not from
|
||||||
if (!targetLaneId) {
|
// args.laneId — RunSetup always supplies the currently-selected lane's id
|
||||||
// If no lane provided, try to find or create one
|
// (a required prop), which would otherwise silently start a run in the wrong
|
||||||
const ownedLane = lanes.find((l) => l.cwd === effectiveCwd);
|
// lane whenever the user types a cwd different from the one currently selected.
|
||||||
if (ownedLane) {
|
const ownedLane = lanes.find((l) => l.cwd === effectiveCwd);
|
||||||
targetLaneId = ownedLane.id;
|
let targetLaneId: number;
|
||||||
setSelectedLaneId(ownedLane.id);
|
if (ownedLane) {
|
||||||
} else {
|
targetLaneId = ownedLane.id;
|
||||||
try {
|
if (ownedLane.id !== args.laneId) setSelectedLaneId(ownedLane.id);
|
||||||
const ensureResult = await api.lanes.ensure({ cwd: effectiveCwd });
|
} else {
|
||||||
targetLaneId = ensureResult.lane.id;
|
try {
|
||||||
setSelectedLaneId(ensureResult.lane.id);
|
const ensureResult = await api.lanes.ensure({ cwd: effectiveCwd });
|
||||||
setLanes((prev) => {
|
targetLaneId = ensureResult.lane.id;
|
||||||
const exists = prev.some((l) => l.id === ensureResult.lane.id);
|
setSelectedLaneId(ensureResult.lane.id);
|
||||||
return exists ? prev : [...prev, ensureResult.lane];
|
setLanes((prev) => {
|
||||||
});
|
const exists = prev.some((l) => l.id === ensureResult.lane.id);
|
||||||
} catch (err) {
|
return exists ? prev : [...prev, ensureResult.lane];
|
||||||
throw new Error(
|
});
|
||||||
t("errors.laneCreateFailed", {
|
} catch (err) {
|
||||||
message: err instanceof Error ? err.message : "unknown",
|
throw new Error(
|
||||||
})
|
t("errors.laneCreateFailed", {
|
||||||
);
|
message: err instanceof Error ? err.message : "unknown",
|
||||||
}
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4722,6 +4722,671 @@ exports[`screen snapshots > Claude Config 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`screen snapshots > Dashboard 1`] = `
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="flex flex-col gap-8 animate-fade-in min-h-[calc(100vh-4rem)]"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex flex-wrap items-center justify-between gap-3"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center gap-3"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-9 h-9 rounded-xl bg-accent/15 flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="lucide lucide-layout-dashboard w-4.5 h-4.5 text-accent"
|
||||||
|
fill="none"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<rect
|
||||||
|
height="9"
|
||||||
|
rx="1"
|
||||||
|
width="7"
|
||||||
|
x="3"
|
||||||
|
y="3"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
height="5"
|
||||||
|
rx="1"
|
||||||
|
width="7"
|
||||||
|
x="14"
|
||||||
|
y="3"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
height="9"
|
||||||
|
rx="1"
|
||||||
|
width="7"
|
||||||
|
x="14"
|
||||||
|
y="12"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
height="5"
|
||||||
|
rx="1"
|
||||||
|
width="7"
|
||||||
|
x="3"
|
||||||
|
y="16"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<h1
|
||||||
|
class="text-lg font-semibold text-fg-primary"
|
||||||
|
>
|
||||||
|
Dashboard
|
||||||
|
</h1>
|
||||||
|
<span
|
||||||
|
class="flex items-center gap-1.5 text-[11px] text-status-success bg-status-success/10 border border-status-success/20 px-2 py-0.5 rounded-full"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="w-1.5 h-1.5 rounded-full bg-status-success animate-pulse-dot"
|
||||||
|
/>
|
||||||
|
Live
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
class="text-xs text-fg-muted"
|
||||||
|
>
|
||||||
|
Real-time overview of Claude Code agent activity
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex items-center gap-3"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex bg-surface-2 rounded-lg p-0.5 border border-border"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="px-2.5 py-1.5 rounded-md text-xs font-medium transition-all flex items-center gap-2 bg-accent/15 text-accent shadow-sm"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="lucide lucide-activity w-3.5 h-3.5"
|
||||||
|
fill="none"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
Monitor
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2.5 py-1.5 rounded-md text-xs font-medium transition-all flex items-center gap-2 text-fg-muted hover:text-fg-secondary"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="lucide lucide-server w-3.5 h-3.5"
|
||||||
|
fill="none"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<rect
|
||||||
|
height="8"
|
||||||
|
rx="2"
|
||||||
|
ry="2"
|
||||||
|
width="20"
|
||||||
|
x="2"
|
||||||
|
y="2"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
height="8"
|
||||||
|
rx="2"
|
||||||
|
ry="2"
|
||||||
|
width="20"
|
||||||
|
x="2"
|
||||||
|
y="14"
|
||||||
|
/>
|
||||||
|
<line
|
||||||
|
x1="6"
|
||||||
|
x2="6.01"
|
||||||
|
y1="6"
|
||||||
|
y2="6"
|
||||||
|
/>
|
||||||
|
<line
|
||||||
|
x1="6"
|
||||||
|
x2="6.01"
|
||||||
|
y1="18"
|
||||||
|
y2="18"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
Health
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="btn-ghost flex-shrink-0"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="lucide lucide-refresh-cw w-4 h-4"
|
||||||
|
fill="none"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M21 3v5h-5"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M8 16H3v5"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
Refresh
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex-1 flex flex-col gap-8 min-h-0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="grid grid-cols-2 md:grid-cols-3 gap-4"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="card p-5"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between gap-3 mb-3"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-xs font-medium text-fg-muted uppercase tracking-wider truncate"
|
||||||
|
>
|
||||||
|
Total Sessions
|
||||||
|
</span>
|
||||||
|
<svg
|
||||||
|
class="lucide lucide-folder-open w-5 h-5 flex-shrink-0 text-accent"
|
||||||
|
fill="none"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex items-end gap-2 min-w-0"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="relative inline-block cursor-default"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-2xl font-semibold text-fg-primary truncate"
|
||||||
|
>
|
||||||
|
0
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="text-xs text-fg-muted mb-1 flex-shrink-0"
|
||||||
|
>
|
||||||
|
0 active
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="card p-5"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between gap-3 mb-3"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-xs font-medium text-fg-muted uppercase tracking-wider truncate"
|
||||||
|
>
|
||||||
|
Active Agents
|
||||||
|
</span>
|
||||||
|
<svg
|
||||||
|
class="lucide lucide-bot w-5 h-5 flex-shrink-0 text-status-success"
|
||||||
|
fill="none"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M12 8V4H8"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
height="12"
|
||||||
|
rx="2"
|
||||||
|
width="16"
|
||||||
|
x="4"
|
||||||
|
y="8"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M2 14h2"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M20 14h2"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M15 13v2"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M9 13v2"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex items-end gap-2 min-w-0"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-2xl font-semibold text-fg-primary truncate"
|
||||||
|
>
|
||||||
|
0
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="card p-5"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between gap-3 mb-3"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-xs font-medium text-fg-muted uppercase tracking-wider truncate"
|
||||||
|
>
|
||||||
|
Active Subagents
|
||||||
|
</span>
|
||||||
|
<svg
|
||||||
|
class="lucide lucide-git-branch w-5 h-5 flex-shrink-0 text-violet-400"
|
||||||
|
fill="none"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<line
|
||||||
|
x1="6"
|
||||||
|
x2="6"
|
||||||
|
y1="3"
|
||||||
|
y2="15"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
cx="18"
|
||||||
|
cy="6"
|
||||||
|
r="3"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
cx="6"
|
||||||
|
cy="18"
|
||||||
|
r="3"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M18 9a9 9 0 0 1-9 9"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex items-end gap-2 min-w-0"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-2xl font-semibold text-fg-primary truncate"
|
||||||
|
>
|
||||||
|
0
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="text-xs text-fg-muted mb-1 flex-shrink-0"
|
||||||
|
>
|
||||||
|
0 in active sessions
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="card p-5"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between gap-3 mb-3"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-xs font-medium text-fg-muted uppercase tracking-wider truncate"
|
||||||
|
>
|
||||||
|
Events Today
|
||||||
|
</span>
|
||||||
|
<svg
|
||||||
|
class="lucide lucide-zap w-5 h-5 flex-shrink-0 text-yellow-400"
|
||||||
|
fill="none"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex items-end gap-2 min-w-0"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="relative inline-block cursor-default"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-2xl font-semibold text-fg-primary truncate"
|
||||||
|
>
|
||||||
|
0
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="card p-5"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between gap-3 mb-3"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-xs font-medium text-fg-muted uppercase tracking-wider truncate"
|
||||||
|
>
|
||||||
|
Total Events
|
||||||
|
</span>
|
||||||
|
<svg
|
||||||
|
class="lucide lucide-activity w-5 h-5 flex-shrink-0 text-violet-400"
|
||||||
|
fill="none"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex items-end gap-2 min-w-0"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="relative inline-block cursor-default"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-2xl font-semibold text-fg-primary truncate"
|
||||||
|
>
|
||||||
|
0
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="card p-5"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between gap-3 mb-3"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-xs font-medium text-fg-muted uppercase tracking-wider truncate"
|
||||||
|
>
|
||||||
|
Total Cost
|
||||||
|
</span>
|
||||||
|
<svg
|
||||||
|
class="lucide lucide-dollar-sign w-5 h-5 flex-shrink-0 text-status-success"
|
||||||
|
fill="none"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<line
|
||||||
|
x1="12"
|
||||||
|
x2="12"
|
||||||
|
y1="2"
|
||||||
|
y2="22"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex items-end gap-2 min-w-0"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="relative inline-block cursor-default"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-2xl font-semibold text-fg-primary truncate"
|
||||||
|
>
|
||||||
|
$0.00
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="grid grid-cols-1 lg:grid-cols-[1fr_auto_1fr] gap-0 min-w-0 flex-1 min-h-0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="min-w-0 overflow-y-auto pr-6"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between mb-4"
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
class="text-sm font-medium text-fg-secondary"
|
||||||
|
>
|
||||||
|
Active Agents
|
||||||
|
</h3>
|
||||||
|
<button
|
||||||
|
class="btn-ghost text-xs"
|
||||||
|
>
|
||||||
|
View Board
|
||||||
|
|
||||||
|
<svg
|
||||||
|
class="lucide lucide-arrow-right w-3 h-3"
|
||||||
|
fill="none"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M5 12h14"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="m12 5 7 7-7 7"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex flex-col items-center justify-center py-20 text-center"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-14 h-14 rounded-2xl bg-surface-4 flex items-center justify-center mb-5"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="lucide lucide-bot w-6 h-6 text-fg-muted"
|
||||||
|
fill="none"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M12 8V4H8"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
height="12"
|
||||||
|
rx="2"
|
||||||
|
width="16"
|
||||||
|
x="4"
|
||||||
|
y="8"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M2 14h2"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M20 14h2"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M15 13v2"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M9 13v2"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3
|
||||||
|
class="text-base font-medium text-fg-secondary mb-2"
|
||||||
|
>
|
||||||
|
No active agents
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
class="text-sm text-fg-muted max-w-md mb-6"
|
||||||
|
>
|
||||||
|
Agents will appear here when a Claude Code session is running.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="hidden lg:block w-px bg-border self-stretch"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="min-w-0 overflow-y-auto pl-6"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between mb-4"
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
class="text-sm font-medium text-fg-secondary"
|
||||||
|
>
|
||||||
|
Recent Activity
|
||||||
|
</h3>
|
||||||
|
<button
|
||||||
|
class="btn-ghost text-xs"
|
||||||
|
>
|
||||||
|
View All
|
||||||
|
|
||||||
|
<svg
|
||||||
|
class="lucide lucide-arrow-right w-3 h-3"
|
||||||
|
fill="none"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M5 12h14"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="m12 5 7 7-7 7"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex flex-col items-center justify-center py-20 text-center"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-14 h-14 rounded-2xl bg-surface-4 flex items-center justify-center mb-5"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="lucide lucide-activity w-6 h-6 text-fg-muted"
|
||||||
|
fill="none"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3
|
||||||
|
class="text-base font-medium text-fg-secondary mb-2"
|
||||||
|
>
|
||||||
|
No activity yet
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
class="text-sm text-fg-muted max-w-md mb-6"
|
||||||
|
>
|
||||||
|
Events from Claude Code sessions will stream here in real-time.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`screen snapshots > Kanban board 1`] = `
|
exports[`screen snapshots > Kanban board 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -135,4 +135,32 @@ describe("pty-run", () => {
|
|||||||
assert.equal(pty.laneIdFromRunId("ccam-lane-42"), 42);
|
assert.equal(pty.laneIdFromRunId("ccam-lane-42"), 42);
|
||||||
assert.equal(pty.laneIdFromRunId("not-a-run-id"), null);
|
assert.equal(pty.laneIdFromRunId("not-a-run-id"), null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("getRun returns the recorded prompt for a live run", () => {
|
||||||
|
let sessionExists = false;
|
||||||
|
tmux.__setExecImpl((args) => {
|
||||||
|
if (args[0] === "has-session") {
|
||||||
|
if (sessionExists) {
|
||||||
|
return ""; // session exists
|
||||||
|
}
|
||||||
|
// Session doesn't exist yet
|
||||||
|
const e = new Error("no such session");
|
||||||
|
e.status = 1;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
if (args[0] === "new-session") {
|
||||||
|
sessionExists = true; // Mark session as created
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
const handle = pty.spawnRun({
|
||||||
|
laneId: 99,
|
||||||
|
cwd: "/tmp/test",
|
||||||
|
initialPrompt: "the live prompt",
|
||||||
|
});
|
||||||
|
const retrieved = pty.getRun(handle.id);
|
||||||
|
assert.equal(retrieved.id, "ccam-lane-99");
|
||||||
|
assert.equal(retrieved.promptPreview, "the live prompt");
|
||||||
|
assert.equal(retrieved.status, "running");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ function publicRun(id) {
|
|||||||
resumeSessionId: row?.resume_session_id || null,
|
resumeSessionId: row?.resume_session_id || null,
|
||||||
sessionId: row?.session_id || null,
|
sessionId: row?.session_id || null,
|
||||||
startedAt: row?.started_at || null,
|
startedAt: row?.started_at || null,
|
||||||
|
promptPreview: row?.prompt_preview || null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user