diff --git a/CONTINUITY.md b/CONTINUITY.md index 471eb4bb1..964359810 100644 --- a/CONTINUITY.md +++ b/CONTINUITY.md @@ -31,12 +31,33 @@ Make exec events (Codex, Claude, etc.) visible in Crabwalk UI as distinct "EXEC" - Build passes ### Now -- [ ] E2E validation with Crabwalk +- [ ] Test & deploy Crabwalk graph layout fixes ### Next - [ ] Push to GitHub (failed earlier due to token permissions) - [ ] Add test coverage for top-level runId +### Crabwalk Graph Layout Fixes (Bead 3) — 2026-01-28 +**Problems Fixed:** +1. Subagents spawned from top "lobster" node → Now connect to parent session +2. Exec nodes appeared unattached → Connect to their session via sessionKey +3. Subagents missing timestamps → Now display relative time ("2m ago") +4. Session identification → Subagent sessions now styled distinctly with cyan glow + +**Changes Made:** + +**Gateway (`/home/clawdbot/dev/clawdbot-exec-events`):** +- `src/gateway/session-utils.types.ts`: Added `spawnedBy?: string` and `createdAt?: number` to `GatewaySessionRow` +- `src/gateway/session-utils.ts`: Include `spawnedBy` in session list response + +**Crabwalk (`/home/clawdbot/apps/crabwalk`):** +- `src/integrations/clawdbot/protocol.ts`: Added `spawnedBy?: string` to `SessionInfo` and `MonitorSession` +- `src/integrations/clawdbot/parser.ts`: Pass through `spawnedBy` in `sessionInfoToMonitor` +- `src/components/monitor/ActionGraph.tsx`: Use `spawnedBy` to connect subagent sessions to parent (not crab origin) +- `src/components/monitor/SessionNode.tsx`: Added timestamp display, subagent visual styling with cyan glow + +**Builds Verified:** Both Gateway and Crabwalk compile successfully + ## Open Questions (RESOLVED) - ✅ CONFIRMED: Exec events ARE being emitted (Line 406-408, server.impl.ts) - ✅ CONFIRMED: Crabwalk HAS distinct ExecNode.tsx component (not reusing AgentNode) diff --git a/src/gateway/session-utils.ts b/src/gateway/session-utils.ts index 164be999e..d766e810c 100644 --- a/src/gateway/session-utils.ts +++ b/src/gateway/session-utils.ts @@ -628,7 +628,12 @@ export function listSessionsFromStore(params: { if (lastMsg) lastMessagePreview = lastMsg; } } - return { ...rest, derivedTitle, lastMessagePreview } satisfies GatewaySessionRow; + return { + ...rest, + derivedTitle, + lastMessagePreview, + spawnedBy: entry?.spawnedBy, + } satisfies GatewaySessionRow; }); return { diff --git a/src/gateway/session-utils.types.ts b/src/gateway/session-utils.types.ts index 074e9eaa8..f55fc773c 100644 --- a/src/gateway/session-utils.types.ts +++ b/src/gateway/session-utils.types.ts @@ -41,6 +41,10 @@ export type GatewaySessionRow = { lastChannel?: SessionEntry["lastChannel"]; lastTo?: string; lastAccountId?: string; + /** Session key of the parent session that spawned this subagent session. */ + spawnedBy?: string; + /** Timestamp when this session was created. */ + createdAt?: number; }; export type GatewayAgentRow = {