diff --git a/client/src/pages/Workspace.tsx b/client/src/pages/Workspace.tsx index d720680e..f8000406 100644 --- a/client/src/pages/Workspace.tsx +++ b/client/src/pages/Workspace.tsx @@ -2,8 +2,8 @@ * @file Workspace.tsx * @description Merged workspace page combining lanes (agent work units) and runs * (CLI spawns: Claude Code or Codex, determined per lane). Displays a horizontal - * lane strip at the top with counters, the selected lane's pipeline map, and run - * configuration/console/history below. Runs are tied to lanes: starting a run + * lane strip at the top (its first tile creates a lane), the selected lane's + * pipeline map, and run configuration/console/history below. Runs are tied to lanes: starting a run * posts to POST /api/lanes/:id/start with tool-appropriate fields. When a cwd * isn't owned by any lane, calls POST /api/lanes/ensure first. Polls GET * /api/sessions?status=active alongside the run list so Claude Code sessions @@ -45,15 +45,7 @@ import { useTranslation } from "react-i18next"; import { Plus, Square, Columns2, Grid2x2 } from "lucide-react"; import { api } from "../lib/api"; import type { CwdSuggestion, RunListResponse } from "../lib/api"; -import type { - Lane, - LaneFeature, - LaneCounts, - ProofFeature, - Session, - WSMessage, - LaneTool, -} from "../lib/types"; +import type { Lane, LaneFeature, ProofFeature, Session, WSMessage, LaneTool } from "../lib/types"; import { eventBus } from "../lib/eventBus"; import { keepIfSame } from "../lib/keepIfSame"; import { LaneConsolePane } from "../components/run/LaneConsolePane"; @@ -203,7 +195,6 @@ export function Workspace() { // Lane state const [lanes, setLanes] = useState([]); - const [counts, setCounts] = useState({ total: 0, running: 0, needs_you: 0, dead: 0 }); const [selectedLaneId, setSelectedLaneId] = useState(null); const [laneActionError, setLaneActionError] = useState(null); const [addLaneOpen, setAddLaneOpen] = useState(false); @@ -263,7 +254,6 @@ export function Workspace() { try { const r = await api.lanes.list(); setLanes(keepIfSame(r.lanes)); - setCounts(keepIfSame(r.counts)); setSelectedLaneId((cur) => cur !== null && r.lanes.some((l) => l.id === cur) ? cur : (r.lanes[0]?.id ?? null) ); @@ -515,60 +505,25 @@ export function Workspace() { : "space-y-5" } > - {/* Page header: what this screen is, and the four numbers that say - whether anything needs a human right now. */} -
-

- {tLanes("title")} -

-
- - {counts.total} {tLanes("countTotal")} - - - {counts.running} {tLanes("countRunning")} - - {counts.needs_you > 0 && ( - - {counts.needs_you} {tLanes("countNeedsYou")} - - )} - {counts.dead > 0 && ( - - {counts.dead} {tLanes("countDead")} - - )} -
-
- {currentLane && } - -
-
- {/* Lane strip + detail stack vertically: the strip is a horizontally scrolling row (holds any number of lanes), the detail/console area below it gets the full width and never competes for it. */}
+ {/* "Add lane" is a tile in the strip rather than a header button: + creating a lane is the same kind of act as picking one, so it + reads as the empty slot at the head of the row. Dashed border and + no liveness dot keep it from being mistaken for a lane. */} + {lanes.map((l) => ( )}
+ {/* Per-lane actions (agents install, mcp sync, sync-base check) + belong beside the lane they act on, not in a page header. */} + -
-
-
-