fix: event-loop freezes, plugin-install boot crash, tmux attach/scrollbar, Codex transcripts
- GET /api/workflows: one LEAD() window pass in a read worker (read-pool.js, workflow-stats.js); idx_events_session restored, idx_events_tool added - compat-sqlite gains function/pluck/readonly so a plugin install without a better-sqlite3 build boots again; antigravity-usage uses db.js's Database - install-hooks adds no checkout hooks while the agenthub plugin is enabled (events were doubled) - terminal attach runs the live tmux server's own binary; the pane scrollbar gets a visible 2-column style, and claude panes start with CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1 so tmux keeps history to scroll - Codex sessions' conversation in GET /api/sessions/:id/transcript - Codex/Antigravity sessions claimed by their workspace without hooks - UI-audit follow-ups, docs and OpenAPI
This commit is contained in:
@@ -113,6 +113,18 @@ const PAGE_SIZE = 50;
|
||||
// stream still refreshes, which a trailing debounce never did.
|
||||
const REFRESH_THROTTLE_MS = 1000;
|
||||
|
||||
/** The agents on screen not asked about yet, and the sessions to ask for them. */
|
||||
export function agentsToFetch(
|
||||
events: { session_id: string; agent_id?: string | null }[],
|
||||
asked: ReadonlySet<string>
|
||||
): { agentIds: string[]; sessionIds: string[] } {
|
||||
const fresh = events.filter((e) => e.agent_id && !asked.has(e.agent_id));
|
||||
return {
|
||||
agentIds: [...new Set(fresh.map((e) => e.agent_id as string))],
|
||||
sessionIds: [...new Set(fresh.map((e) => e.session_id))],
|
||||
};
|
||||
}
|
||||
|
||||
export function ActivityFeed({ embedded = false }: { embedded?: boolean } = {}) {
|
||||
const eventCtx = useContextMenu<DashboardEvent>();
|
||||
const { t } = useTranslation("activity");
|
||||
@@ -158,7 +170,7 @@ export function ActivityFeed({ embedded = false }: { embedded?: boolean } = {})
|
||||
// agent_id → subagent-facing info for the agents of the sessions on screen,
|
||||
// fetched in one call per new set of sessions (never every agent).
|
||||
const [agentInfoById, setAgentInfoById] = useState<Map<string, AgentInfo>>(() => new Map());
|
||||
const knownAgentSessions = useRef(new Set<string>());
|
||||
const askedAgents = useRef(new Set<string>());
|
||||
|
||||
const pausedRef = useRef(paused);
|
||||
pausedRef.current = paused;
|
||||
@@ -223,13 +235,12 @@ export function ActivityFeed({ embedded = false }: { embedded?: boolean } = {})
|
||||
load();
|
||||
}, [load]);
|
||||
|
||||
// Agent labels for the sessions on screen that we have not seen yet.
|
||||
// Agent labels for agents on screen not asked about yet — keyed by agent, so
|
||||
// a subagent spawned later in a live session gets its label too.
|
||||
useEffect(() => {
|
||||
const missing = [...new Set(events.map((e) => e.session_id))].filter(
|
||||
(sid) => !knownAgentSessions.current.has(sid)
|
||||
);
|
||||
const { agentIds, sessionIds: missing } = agentsToFetch(events, askedAgents.current);
|
||||
if (missing.length === 0) return;
|
||||
for (const sid of missing) knownAgentSessions.current.add(sid);
|
||||
for (const id of agentIds) askedAgents.current.add(id);
|
||||
api.agents
|
||||
.list({ session_ids: missing, limit: 5000 })
|
||||
.then(({ agents }) =>
|
||||
@@ -247,7 +258,7 @@ export function ActivityFeed({ embedded = false }: { embedded?: boolean } = {})
|
||||
)
|
||||
.catch(() => {
|
||||
// Non-fatal: subagent pills fall back to the short-id label.
|
||||
for (const sid of missing) knownAgentSessions.current.delete(sid);
|
||||
for (const id of agentIds) askedAgents.current.delete(id);
|
||||
});
|
||||
}, [events]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user