mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-28 09:23:08 +08:00
Add benchmark results for fast3 and fast4, implement KeepAliveLspBridge, and add tests for staged strategies
- Added new benchmark result files: compare_2026-02-09_score_fast3.json and compare_2026-02-09_score_fast4.json. - Implemented KeepAliveLspBridge to maintain a persistent LSP connection across multiple queries, improving performance. - Created unit tests for staged clustering strategies in test_staged_stage3_fast_strategies.py, ensuring correct behavior of score and dir_rr strategies.
This commit is contained in:
132
ccw/frontend/src/stores/cliSessionStore.ts
Normal file
132
ccw/frontend/src/stores/cliSessionStore.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
// ========================================
|
||||
// CLI Session Store (PTY-backed terminals)
|
||||
// ========================================
|
||||
// Zustand store for managing PTY session metadata and output chunks.
|
||||
|
||||
import { create } from 'zustand';
|
||||
import { devtools } from 'zustand/middleware';
|
||||
|
||||
export interface CliSessionMeta {
|
||||
sessionKey: string;
|
||||
shellKind: string;
|
||||
workingDir: string;
|
||||
tool?: string;
|
||||
model?: string;
|
||||
resumeKey?: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface CliSessionOutputChunk {
|
||||
data: string;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
interface CliSessionState {
|
||||
sessions: Record<string, CliSessionMeta>;
|
||||
outputChunks: Record<string, CliSessionOutputChunk[]>;
|
||||
outputBytes: Record<string, number>;
|
||||
|
||||
setSessions: (sessions: CliSessionMeta[]) => void;
|
||||
upsertSession: (session: CliSessionMeta) => void;
|
||||
removeSession: (sessionKey: string) => void;
|
||||
|
||||
setBuffer: (sessionKey: string, buffer: string) => void;
|
||||
appendOutput: (sessionKey: string, data: string, timestamp?: number) => void;
|
||||
clearOutput: (sessionKey: string) => void;
|
||||
}
|
||||
|
||||
const MAX_OUTPUT_BYTES_PER_SESSION = 2 * 1024 * 1024; // 2MB
|
||||
|
||||
const utf8Encoder = new TextEncoder();
|
||||
function utf8ByteLength(value: string): number {
|
||||
// Browser-safe alternative to Buffer.byteLength
|
||||
return utf8Encoder.encode(value).length;
|
||||
}
|
||||
|
||||
export const useCliSessionStore = create<CliSessionState>()(
|
||||
devtools(
|
||||
(set, get) => ({
|
||||
sessions: {},
|
||||
outputChunks: {},
|
||||
outputBytes: {},
|
||||
|
||||
setSessions: (sessions) =>
|
||||
set((state) => {
|
||||
const nextSessions: Record<string, CliSessionMeta> = {};
|
||||
for (const session of sessions) {
|
||||
nextSessions[session.sessionKey] = session;
|
||||
}
|
||||
|
||||
const keepKeys = new Set(Object.keys(nextSessions));
|
||||
const nextChunks = { ...state.outputChunks };
|
||||
const nextBytes = { ...state.outputBytes };
|
||||
for (const key of Object.keys(nextChunks)) {
|
||||
if (!keepKeys.has(key)) delete nextChunks[key];
|
||||
}
|
||||
for (const key of Object.keys(nextBytes)) {
|
||||
if (!keepKeys.has(key)) delete nextBytes[key];
|
||||
}
|
||||
|
||||
return { sessions: nextSessions, outputChunks: nextChunks, outputBytes: nextBytes };
|
||||
}),
|
||||
|
||||
upsertSession: (session) =>
|
||||
set((state) => ({
|
||||
sessions: { ...state.sessions, [session.sessionKey]: session },
|
||||
})),
|
||||
|
||||
removeSession: (sessionKey) =>
|
||||
set((state) => {
|
||||
const nextSessions = { ...state.sessions };
|
||||
const nextChunks = { ...state.outputChunks };
|
||||
const nextBytes = { ...state.outputBytes };
|
||||
delete nextSessions[sessionKey];
|
||||
delete nextChunks[sessionKey];
|
||||
delete nextBytes[sessionKey];
|
||||
return { sessions: nextSessions, outputChunks: nextChunks, outputBytes: nextBytes };
|
||||
}),
|
||||
|
||||
setBuffer: (sessionKey, buffer) =>
|
||||
set((state) => ({
|
||||
outputChunks: {
|
||||
...state.outputChunks,
|
||||
[sessionKey]: buffer ? [{ data: buffer, timestamp: Date.now() }] : [],
|
||||
},
|
||||
outputBytes: {
|
||||
...state.outputBytes,
|
||||
[sessionKey]: buffer ? utf8ByteLength(buffer) : 0,
|
||||
},
|
||||
})),
|
||||
|
||||
appendOutput: (sessionKey, data, timestamp = Date.now()) => {
|
||||
if (!data) return;
|
||||
const chunkBytes = utf8ByteLength(data);
|
||||
const { outputChunks, outputBytes } = get();
|
||||
const existingChunks = outputChunks[sessionKey] ?? [];
|
||||
const existingBytes = outputBytes[sessionKey] ?? 0;
|
||||
|
||||
const nextChunks = [...existingChunks, { data, timestamp }];
|
||||
let nextBytes = existingBytes + chunkBytes;
|
||||
|
||||
// Ring-buffer by bytes
|
||||
while (nextBytes > MAX_OUTPUT_BYTES_PER_SESSION && nextChunks.length > 0) {
|
||||
const removed = nextChunks.shift();
|
||||
if (removed) nextBytes -= utf8ByteLength(removed.data);
|
||||
}
|
||||
|
||||
set((state) => ({
|
||||
outputChunks: { ...state.outputChunks, [sessionKey]: nextChunks },
|
||||
outputBytes: { ...state.outputBytes, [sessionKey]: Math.max(0, nextBytes) },
|
||||
}));
|
||||
},
|
||||
|
||||
clearOutput: (sessionKey) =>
|
||||
set((state) => ({
|
||||
outputChunks: { ...state.outputChunks, [sessionKey]: [] },
|
||||
outputBytes: { ...state.outputBytes, [sessionKey]: 0 },
|
||||
})),
|
||||
}),
|
||||
{ name: 'cliSessionStore' }
|
||||
)
|
||||
);
|
||||
Reference in New Issue
Block a user