fix(FN-834): fix branch prefix drift, add merger branch guard, and fix test OOM
- Fix resolveBaseBranch to use stored branch name and consistent fusion/ prefix for both explicit deps and blockedBy paths (was using kb/ for blockedBy) - Add main branch checkout verification in merger before squash merge to prevent feature code from landing on wrong branch lineage - Align all branch prefix references from stale kb/ to fusion/ across executor, merger, store, and routes - Fix executor test OOM by mocking merger fully, adding fake timers to retry tests, and switching vitest pool to vmThreads - Update all test assertions to use fusion/ branch prefix Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
60
packages/dashboard/app/hooks/useAgents.ts
Normal file
60
packages/dashboard/app/hooks/useAgents.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import type { Agent, AgentState, AgentCapability, AgentStats } from "../api";
|
||||
import { fetchAgents, fetchAgentStats } from "../api";
|
||||
|
||||
export function useAgents(projectId?: string) {
|
||||
const [agents, setAgents] = useState<Agent[]>([]);
|
||||
const [stats, setStats] = useState<AgentStats | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const loadAgents = useCallback(async (filter?: { state?: AgentState; role?: AgentCapability }) => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const data = await fetchAgents(filter, projectId);
|
||||
setAgents(data);
|
||||
} catch (err) {
|
||||
console.error("Failed to load agents:", err);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [projectId]);
|
||||
|
||||
const loadStats = useCallback(async () => {
|
||||
try {
|
||||
const data = await fetchAgentStats(projectId);
|
||||
setStats(data);
|
||||
} catch (err) {
|
||||
console.error("Failed to load agent stats:", err);
|
||||
}
|
||||
}, [projectId]);
|
||||
|
||||
useEffect(() => {
|
||||
void loadAgents();
|
||||
void loadStats();
|
||||
}, [loadAgents, loadStats]);
|
||||
|
||||
// SSE subscription for agent events
|
||||
useEffect(() => {
|
||||
if (!projectId) return;
|
||||
const query = `?projectId=${encodeURIComponent(projectId)}`;
|
||||
const es = new EventSource(`/api/events${query}`);
|
||||
|
||||
const refresh = () => {
|
||||
void loadAgents();
|
||||
void loadStats();
|
||||
};
|
||||
|
||||
es.addEventListener("agent:created", refresh);
|
||||
es.addEventListener("agent:updated", refresh);
|
||||
es.addEventListener("agent:deleted", refresh);
|
||||
es.addEventListener("agent:stateChanged", refresh);
|
||||
|
||||
return () => {
|
||||
es.close();
|
||||
};
|
||||
}, [projectId, loadAgents, loadStats]);
|
||||
|
||||
const activeAgents = agents.filter(a => a.state === "active" || a.state === "running");
|
||||
|
||||
return { agents, activeAgents, stats, isLoading, loadAgents, loadStats };
|
||||
}
|
||||
43
packages/dashboard/app/hooks/useLiveTranscript.ts
Normal file
43
packages/dashboard/app/hooks/useLiveTranscript.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
|
||||
/** Log entry from an agent's execution stream */
|
||||
export interface TranscriptEntry {
|
||||
type: string;
|
||||
content: string;
|
||||
timestamp?: string;
|
||||
}
|
||||
|
||||
export function useLiveTranscript(taskId: string | undefined) {
|
||||
const [entries, setEntries] = useState<TranscriptEntry[]>([]);
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
const esRef = useRef<EventSource | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!taskId) {
|
||||
setEntries([]);
|
||||
setIsConnected(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const es = new EventSource(`/api/tasks/${encodeURIComponent(taskId)}/logs/stream`);
|
||||
esRef.current = es;
|
||||
|
||||
es.addEventListener("agent:log", (event) => {
|
||||
try {
|
||||
const entry = JSON.parse(event.data) as TranscriptEntry;
|
||||
setEntries(prev => [entry, ...prev]);
|
||||
} catch { /* skip */ }
|
||||
});
|
||||
|
||||
es.addEventListener("open", () => setIsConnected(true));
|
||||
es.addEventListener("error", () => setIsConnected(false));
|
||||
|
||||
return () => {
|
||||
es.close();
|
||||
esRef.current = null;
|
||||
setIsConnected(false);
|
||||
};
|
||||
}, [taskId]);
|
||||
|
||||
return { entries, isConnected };
|
||||
}
|
||||
Reference in New Issue
Block a user