mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-14 02:42:04 +08:00
feat: Implement phases 6 to 9 of the review cycle fix process, including discovery, batching, parallel planning, execution, and completion
- Added Phase 6: Fix Discovery & Batching with intelligent grouping and batching of findings. - Added Phase 7: Fix Parallel Planning to launch planning agents for concurrent analysis and aggregation of partial plans. - Added Phase 8: Fix Execution for stage-based execution of fixes with conservative test verification. - Added Phase 9: Fix Completion to aggregate results, generate summary reports, and handle session completion. - Introduced new frontend components: ResizeHandle for draggable resizing of sidebar panels and useResizablePanel hook for managing panel sizes with localStorage persistence. - Added PowerShell script for checking TypeScript errors in source code, excluding test files.
This commit is contained in:
@@ -11,7 +11,10 @@ import type {
|
||||
ExecutionStatus,
|
||||
NodeExecutionState,
|
||||
ExecutionLog,
|
||||
NodeExecutionOutput,
|
||||
} from '../types/execution';
|
||||
import type { ToolCallExecution } from '../types/toolCall';
|
||||
import type { CliOutputLine } from './cliStreamStore';
|
||||
|
||||
// Constants
|
||||
const MAX_LOGS = 500;
|
||||
@@ -28,6 +31,15 @@ const initialState = {
|
||||
logs: [] as ExecutionLog[],
|
||||
maxLogs: MAX_LOGS,
|
||||
|
||||
// Node output tracking
|
||||
nodeOutputs: {} as Record<string, NodeExecutionOutput>,
|
||||
|
||||
// Tool call tracking
|
||||
nodeToolCalls: {} as Record<string, ToolCallExecution[]>,
|
||||
|
||||
// Selected node for detail view
|
||||
selectedNodeId: null as string | null,
|
||||
|
||||
// UI state
|
||||
isMonitorPanelOpen: false,
|
||||
autoScrollLogs: true,
|
||||
@@ -35,7 +47,7 @@ const initialState = {
|
||||
|
||||
export const useExecutionStore = create<ExecutionStore>()(
|
||||
devtools(
|
||||
(set) => ({
|
||||
(set, get) => ({
|
||||
...initialState,
|
||||
|
||||
// ========== Execution Lifecycle ==========
|
||||
@@ -204,6 +216,248 @@ export const useExecutionStore = create<ExecutionStore>()(
|
||||
setAutoScrollLogs: (autoScroll: boolean) => {
|
||||
set({ autoScrollLogs: autoScroll }, false, 'setAutoScrollLogs');
|
||||
},
|
||||
|
||||
// ========== Node Output Management ==========
|
||||
|
||||
addNodeOutput: (nodeId: string, output: CliOutputLine) => {
|
||||
set(
|
||||
(state) => {
|
||||
const current = state.nodeOutputs[nodeId];
|
||||
if (!current) {
|
||||
// Create new node output
|
||||
return {
|
||||
nodeOutputs: {
|
||||
...state.nodeOutputs,
|
||||
[nodeId]: {
|
||||
nodeId,
|
||||
outputs: [output],
|
||||
toolCalls: [],
|
||||
logs: [],
|
||||
variables: {},
|
||||
startTime: Date.now(),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
// Append to existing output
|
||||
return {
|
||||
nodeOutputs: {
|
||||
...state.nodeOutputs,
|
||||
[nodeId]: {
|
||||
...current,
|
||||
outputs: [...current.outputs, output],
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
false,
|
||||
'addNodeOutput'
|
||||
);
|
||||
},
|
||||
|
||||
clearNodeOutputs: (nodeId: string) => {
|
||||
set(
|
||||
(state) => {
|
||||
const newOutputs = { ...state.nodeOutputs };
|
||||
delete newOutputs[nodeId];
|
||||
return { nodeOutputs: newOutputs };
|
||||
},
|
||||
false,
|
||||
'clearNodeOutputs'
|
||||
);
|
||||
},
|
||||
|
||||
// ========== Tool Call Management ==========
|
||||
|
||||
startToolCall: (
|
||||
nodeId: string,
|
||||
callId: string,
|
||||
data: { kind: ToolCallExecution['kind']; subtype?: string; description: string }
|
||||
) => {
|
||||
const newToolCall: ToolCallExecution = {
|
||||
callId,
|
||||
nodeId,
|
||||
status: 'executing',
|
||||
kind: data.kind,
|
||||
subtype: data.subtype,
|
||||
description: data.description,
|
||||
startTime: Date.now(),
|
||||
outputLines: [],
|
||||
outputBuffer: {
|
||||
stdout: '',
|
||||
stderr: '',
|
||||
combined: '',
|
||||
},
|
||||
};
|
||||
|
||||
set(
|
||||
(state) => {
|
||||
const currentCalls = state.nodeToolCalls[nodeId] || [];
|
||||
return {
|
||||
nodeToolCalls: {
|
||||
...state.nodeToolCalls,
|
||||
[nodeId]: [...currentCalls, newToolCall],
|
||||
},
|
||||
};
|
||||
},
|
||||
false,
|
||||
'startToolCall'
|
||||
);
|
||||
},
|
||||
|
||||
updateToolCall: (
|
||||
nodeId: string,
|
||||
callId: string,
|
||||
update: {
|
||||
status?: ToolCallExecution['status'];
|
||||
outputChunk?: string;
|
||||
stream?: 'stdout' | 'stderr';
|
||||
}
|
||||
) => {
|
||||
set(
|
||||
(state) => {
|
||||
const calls = state.nodeToolCalls[nodeId];
|
||||
if (!calls) return state;
|
||||
|
||||
const index = calls.findIndex((c) => c.callId === callId);
|
||||
if (index === -1) return state;
|
||||
|
||||
const updatedCalls = [...calls];
|
||||
const current = updatedCalls[index];
|
||||
|
||||
// Update status if provided
|
||||
if (update.status) {
|
||||
current.status = update.status;
|
||||
if (update.status !== 'executing' && !current.endTime) {
|
||||
current.endTime = Date.now();
|
||||
current.duration = current.endTime - current.startTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Append output chunk if provided
|
||||
if (update.outputChunk !== undefined) {
|
||||
const outputLine: CliOutputLine = {
|
||||
type: update.stream === 'stderr' ? 'stderr' : 'stdout',
|
||||
content: update.outputChunk,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
current.outputLines.push(outputLine);
|
||||
|
||||
// Update buffer
|
||||
if (update.stream === 'stderr') {
|
||||
current.outputBuffer.stderr += update.outputChunk;
|
||||
current.outputBuffer.combined += update.outputChunk;
|
||||
} else {
|
||||
current.outputBuffer.stdout += update.outputChunk;
|
||||
current.outputBuffer.combined += update.outputChunk;
|
||||
}
|
||||
}
|
||||
|
||||
updatedCalls[index] = current;
|
||||
|
||||
return {
|
||||
nodeToolCalls: {
|
||||
...state.nodeToolCalls,
|
||||
[nodeId]: updatedCalls,
|
||||
},
|
||||
};
|
||||
},
|
||||
false,
|
||||
'updateToolCall'
|
||||
);
|
||||
},
|
||||
|
||||
completeToolCall: (
|
||||
nodeId: string,
|
||||
callId: string,
|
||||
result: {
|
||||
status: ToolCallExecution['status'];
|
||||
exitCode?: number;
|
||||
error?: string;
|
||||
result?: unknown;
|
||||
}
|
||||
) => {
|
||||
set(
|
||||
(state) => {
|
||||
const calls = state.nodeToolCalls[nodeId];
|
||||
if (!calls) return state;
|
||||
|
||||
const index = calls.findIndex((c) => c.callId === callId);
|
||||
if (index === -1) return state;
|
||||
|
||||
const updatedCalls = [...calls];
|
||||
const current = { ...updatedCalls[index] };
|
||||
|
||||
current.status = result.status;
|
||||
current.endTime = Date.now();
|
||||
current.duration = current.endTime - current.startTime;
|
||||
|
||||
if (result.exitCode !== undefined) {
|
||||
current.exitCode = result.exitCode;
|
||||
}
|
||||
if (result.error !== undefined) {
|
||||
current.error = result.error;
|
||||
}
|
||||
if (result.result !== undefined) {
|
||||
current.result = result.result;
|
||||
}
|
||||
|
||||
updatedCalls[index] = current;
|
||||
|
||||
return {
|
||||
nodeToolCalls: {
|
||||
...state.nodeToolCalls,
|
||||
[nodeId]: updatedCalls,
|
||||
},
|
||||
};
|
||||
},
|
||||
false,
|
||||
'completeToolCall'
|
||||
);
|
||||
},
|
||||
|
||||
toggleToolCallExpanded: (nodeId: string, callId: string) => {
|
||||
set(
|
||||
(state) => {
|
||||
const calls = state.nodeToolCalls[nodeId];
|
||||
if (!calls) return state;
|
||||
|
||||
const index = calls.findIndex((c) => c.callId === callId);
|
||||
if (index === -1) return state;
|
||||
|
||||
const updatedCalls = [...calls];
|
||||
updatedCalls[index] = {
|
||||
...updatedCalls[index],
|
||||
isExpanded: !updatedCalls[index].isExpanded,
|
||||
};
|
||||
|
||||
return {
|
||||
nodeToolCalls: {
|
||||
...state.nodeToolCalls,
|
||||
[nodeId]: updatedCalls,
|
||||
},
|
||||
};
|
||||
},
|
||||
false,
|
||||
'toggleToolCallExpanded'
|
||||
);
|
||||
},
|
||||
|
||||
// ========== Node Selection ==========
|
||||
|
||||
selectNode: (nodeId: string | null) => {
|
||||
set({ selectedNodeId: nodeId }, false, 'selectNode');
|
||||
},
|
||||
|
||||
// ========== Getters ==========
|
||||
|
||||
getNodeOutputs: (nodeId: string) => {
|
||||
return get().nodeOutputs[nodeId];
|
||||
},
|
||||
|
||||
getToolCallsForNode: (nodeId: string) => {
|
||||
return get().nodeToolCalls[nodeId] || [];
|
||||
},
|
||||
}),
|
||||
{ name: 'ExecutionStore' }
|
||||
)
|
||||
@@ -216,6 +470,13 @@ export const selectLogs = (state: ExecutionStore) => state.logs;
|
||||
export const selectIsMonitorPanelOpen = (state: ExecutionStore) => state.isMonitorPanelOpen;
|
||||
export const selectAutoScrollLogs = (state: ExecutionStore) => state.autoScrollLogs;
|
||||
|
||||
// Node output selectors (new)
|
||||
export const selectNodeOutputs = (state: ExecutionStore, nodeId: string) =>
|
||||
state.nodeOutputs[nodeId];
|
||||
export const selectNodeToolCalls = (state: ExecutionStore, nodeId: string) =>
|
||||
state.nodeToolCalls[nodeId] || [];
|
||||
export const selectSelectedNodeId = (state: ExecutionStore) => state.selectedNodeId;
|
||||
|
||||
// Helper to check if execution is active
|
||||
export const selectIsExecuting = (state: ExecutionStore) => {
|
||||
return state.currentExecution?.status === 'running';
|
||||
@@ -225,3 +486,9 @@ export const selectIsExecuting = (state: ExecutionStore) => {
|
||||
export const selectNodeStatus = (nodeId: string) => (state: ExecutionStore) => {
|
||||
return state.nodeStates[nodeId]?.status ?? 'pending';
|
||||
};
|
||||
|
||||
// Helper to get selected node's tool calls
|
||||
export const selectSelectedNodeToolCalls = (state: ExecutionStore) => {
|
||||
if (!state.selectedNodeId) return [];
|
||||
return state.nodeToolCalls[state.selectedNodeId] || [];
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user