feat(lanes): Antigravity lanes, release exited panes, fresh Codex starts
- antigravity: a third lane tool running Antigravity's `agy` CLI. `-i`
carries the first prompt, `--continue` resumes; `agy` has no model,
effort or permission flag, and `--dangerously-skip-permissions` is never
emitted. No pipeline, no agents install, and no AI Router (native only,
else EUNSUPPORTED). Add lane gains an Antigravity choice and the binary
probe maps it to `agy`.
- UI: the lane card no longer renders a frame holding only a "Codex" chip,
and the prompt box names the lane's CLI ("Ask Codex anything…"), via
LANE_TOOL_LABEL.
- runs: a pane that exits is released on a 10 s server beat
(healAllRunIds, DASHBOARD_RUN_HEAL_MS). Codex and Antigravity fire no
hook, so their lanes stayed "running" until something re-read them.
- codex: Start no longer sends resumeLast — only "Resume last session"
continues the previous thread.
This commit is contained in:
@@ -395,8 +395,8 @@ export function Workspace() {
|
||||
}, [lanes, searchParams, setSearchParams]);
|
||||
|
||||
useEffect(() => {
|
||||
Promise.all([api.run.binary("claude"), api.run.binary("codex")])
|
||||
.then(([claude, codex]) => setBinaryStatus({ claude, codex }))
|
||||
Promise.all([api.run.binary("claude"), api.run.binary("codex"), api.run.binary("antigravity")])
|
||||
.then(([claude, codex, antigravity]) => setBinaryStatus({ claude, codex, antigravity }))
|
||||
// Fetch failure (server unreachable, proxy misrouted, etc.) isn't proof
|
||||
// `claude` or `codex` is missing from PATH — leave the probe unresolved rather than
|
||||
// showing a misleading "binary missing" banner for an unrelated fault.
|
||||
@@ -523,7 +523,8 @@ export function Workspace() {
|
||||
}, [refreshList]);
|
||||
|
||||
const currentLane = selectedLaneId !== null ? lanes.find((l) => l.id === selectedLaneId) : null;
|
||||
const isCodexLane = currentLane?.tool === "codex";
|
||||
// Only claude lanes carry a pipeline (codex and antigravity emit no hooks).
|
||||
const noPipeline = !!currentLane && currentLane.tool !== "claude";
|
||||
|
||||
// Feature list follows the selected lane, resets the viewer on lane switch.
|
||||
useEffect(() => {
|
||||
@@ -816,16 +817,16 @@ export function Workspace() {
|
||||
<Pencil className="h-3 w-3 shrink-0 text-fg-muted opacity-0 transition-opacity group-hover:opacity-100" />
|
||||
</button>
|
||||
)}
|
||||
{/* Codex lanes carry no pipeline: no time-at-stage, no pipeline
|
||||
or feature picker, no map. */}
|
||||
{!isCodexLane && (
|
||||
{/* Non-claude lanes carry no pipeline: no time-at-stage, no
|
||||
pipeline or feature picker, no map. */}
|
||||
{!noPipeline && (
|
||||
<span className="shrink-0 tabular-nums text-xs text-fg-muted">
|
||||
{since(currentLane.stage_seconds)}
|
||||
</span>
|
||||
)}
|
||||
{showInfo && (
|
||||
<>
|
||||
{!isCodexLane && (
|
||||
{!noPipeline && (
|
||||
<select
|
||||
data-testid="pipeline-picker"
|
||||
aria-label={tLanes("pipelinePicker.label")}
|
||||
@@ -855,13 +856,14 @@ export function Workspace() {
|
||||
))}
|
||||
</select>
|
||||
)}
|
||||
<LaneRouterRow lane={currentLane} />
|
||||
{/* `agy` has no endpoint to point at a router. */}
|
||||
{currentLane.tool !== "antigravity" && <LaneRouterRow lane={currentLane} />}
|
||||
{/* No stage chip and no "auto: <stage>" chip here: the
|
||||
PipelineMap right below this header already draws both
|
||||
— the declared node as the current ring, the detected
|
||||
one as its amber badge — so the chips were a second,
|
||||
smaller copy of the same two facts. */}
|
||||
{!isCodexLane && features.length > 0 && (
|
||||
{!noPipeline && features.length > 0 && (
|
||||
<select
|
||||
data-testid="feature-picker"
|
||||
className="rounded border border-border bg-surface-1 px-2 py-0.5 text-xs"
|
||||
@@ -921,7 +923,7 @@ export function Workspace() {
|
||||
onSelectLane={setSelectedLaneId}
|
||||
/>
|
||||
</div>
|
||||
{!isCodexLane && (
|
||||
{!noPipeline && (
|
||||
<div className="mb-3">
|
||||
<PipelineMap
|
||||
nodes={
|
||||
|
||||
Reference in New Issue
Block a user