mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-11 02:33:51 +08:00
feat: add API settings page for managing providers, endpoints, cache, model pools, and CLI settings
feat: implement semantic install dialog for CodexLens with GPU mode selection feat: add radio group component for GPU mode selection feat: update navigation and localization for API settings and semantic install
This commit is contained in:
1
ccw/src/tools/.gitignore
vendored
Normal file
1
ccw/src/tools/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.ace-tool/
|
||||
@@ -748,6 +748,11 @@ async function executeCliTool(
|
||||
conversationId = `${Date.now()}-${tool}`;
|
||||
}
|
||||
|
||||
// Generate transaction ID for concurrent session disambiguation
|
||||
// This will be injected into the prompt for exact session matching during resume
|
||||
const transactionId = generateTransactionId(conversationId);
|
||||
debugLog('TX_ID', `Generated transaction ID: ${transactionId}`, { conversationId });
|
||||
|
||||
// Determine resume strategy (native vs prompt-concat vs hybrid)
|
||||
let resumeDecision: ResumeDecision | null = null;
|
||||
let nativeResumeConfig: NativeResumeConfig | undefined;
|
||||
@@ -811,6 +816,11 @@ async function executeCliTool(
|
||||
}
|
||||
}
|
||||
|
||||
// Inject transaction ID at the start of the final prompt for session tracking
|
||||
// This enables exact session matching during parallel execution scenarios
|
||||
finalPrompt = injectTransactionId(finalPrompt, transactionId);
|
||||
debugLog('TX_ID', `Injected transaction ID into prompt`, { transactionId, promptLength: finalPrompt.length });
|
||||
|
||||
// Check tool availability
|
||||
const toolStatus = await checkToolAvailability(tool);
|
||||
if (!toolStatus.available) {
|
||||
@@ -1207,11 +1217,11 @@ async function executeCliTool(
|
||||
}
|
||||
|
||||
// Track native session after execution (awaited to prevent process hang)
|
||||
// Pass prompt for precise matching in parallel execution scenarios
|
||||
// Pass prompt and transactionId for precise matching in parallel execution scenarios
|
||||
try {
|
||||
const nativeSession = await trackNewSession(tool, new Date(startTime), workingDir, prompt);
|
||||
const nativeSession = await trackNewSession(tool, new Date(startTime), workingDir, prompt, transactionId);
|
||||
if (nativeSession) {
|
||||
// Save native session mapping
|
||||
// Save native session mapping with transaction ID
|
||||
try {
|
||||
store.saveNativeSessionMapping({
|
||||
ccw_id: conversationId,
|
||||
@@ -1219,6 +1229,7 @@ async function executeCliTool(
|
||||
native_session_id: nativeSession.sessionId,
|
||||
native_session_path: nativeSession.filePath,
|
||||
project_hash: nativeSession.projectHash,
|
||||
transaction_id: transactionId,
|
||||
created_at: new Date().toISOString()
|
||||
});
|
||||
} catch (err) {
|
||||
|
||||
@@ -1010,6 +1010,7 @@ export class CliHistoryStore {
|
||||
native_session_id: row.native_session_id,
|
||||
native_session_path: row.native_session_path,
|
||||
project_hash: row.project_hash,
|
||||
transaction_id: row.transaction_id,
|
||||
created_at: row.created_at
|
||||
};
|
||||
}
|
||||
@@ -1033,6 +1034,7 @@ export class CliHistoryStore {
|
||||
native_session_id: row.native_session_id,
|
||||
native_session_path: row.native_session_path,
|
||||
project_hash: row.project_hash,
|
||||
transaction_id: row.transaction_id,
|
||||
created_at: row.created_at
|
||||
};
|
||||
}
|
||||
|
||||
@@ -73,34 +73,50 @@ abstract class SessionDiscoverer {
|
||||
* @param beforeTimestamp - Filter sessions created after this time
|
||||
* @param workingDir - Project working directory
|
||||
* @param prompt - Optional prompt content for precise matching (fallback)
|
||||
* @param transactionId - Optional transaction ID for exact matching (highest priority)
|
||||
*/
|
||||
async trackNewSession(
|
||||
beforeTimestamp: Date,
|
||||
workingDir: string,
|
||||
prompt?: string
|
||||
prompt?: string,
|
||||
transactionId?: string
|
||||
): Promise<NativeSession | null> {
|
||||
const sessions = this.getSessions({
|
||||
workingDir,
|
||||
afterTimestamp: beforeTimestamp,
|
||||
limit: 10 // Get more candidates for prompt matching
|
||||
limit: 10 // Get more candidates for matching
|
||||
});
|
||||
|
||||
if (sessions.length === 0) return null;
|
||||
|
||||
// If only one session or no prompt provided, return the latest
|
||||
if (sessions.length === 1 || !prompt) {
|
||||
// Priority 1: Match by transaction ID (exact match, highest confidence)
|
||||
if (transactionId) {
|
||||
const matched = this.matchSessionByTransactionId(transactionId, sessions);
|
||||
if (matched) {
|
||||
return matched;
|
||||
}
|
||||
// Transaction ID provided but no match - fall through to other methods
|
||||
}
|
||||
|
||||
// If only one session, return it
|
||||
if (sessions.length === 1) {
|
||||
return sessions[0];
|
||||
}
|
||||
|
||||
// Try to match by prompt content (fallback for parallel execution)
|
||||
const matched = this.matchSessionByPrompt(sessions, prompt);
|
||||
// Priority 2: Match by prompt content (fallback for parallel execution)
|
||||
if (prompt) {
|
||||
const matched = this.matchSessionByPrompt(sessions, prompt);
|
||||
if (matched) {
|
||||
return matched;
|
||||
}
|
||||
}
|
||||
|
||||
// Warn if multiple sessions and no prompt match found (low confidence)
|
||||
if (!matched && sessions.length > 1) {
|
||||
// Warn if multiple sessions and no match found (low confidence)
|
||||
if (sessions.length > 1) {
|
||||
console.warn(`[ccw] Session tracking: multiple candidates found (${sessions.length}), using latest session`);
|
||||
}
|
||||
|
||||
return matched || sessions[0]; // Fallback to latest if no match
|
||||
return sessions[0]; // Fallback to latest if no match
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,6 +141,33 @@ abstract class SessionDiscoverer {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match session by transaction ID
|
||||
* Extracts transaction ID from session's first user message and compares
|
||||
* @param txId - Transaction ID to match (format: ccw-tx-${conversationId}-${uniquePart})
|
||||
* @param sessions - Candidate sessions to search
|
||||
* @returns Matching session or null
|
||||
*/
|
||||
matchSessionByTransactionId(txId: string, sessions: NativeSession[]): NativeSession | null {
|
||||
if (!txId) return null;
|
||||
|
||||
for (const session of sessions) {
|
||||
try {
|
||||
const userMessage = this.extractFirstUserMessage(session.filePath);
|
||||
if (userMessage) {
|
||||
// Extract transaction ID from user message
|
||||
const match = userMessage.match(/\[CCW-TX-ID:\s+([^\]]+)\]/);
|
||||
if (match && match[1] === txId) {
|
||||
return session;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Skip sessions that can't be read
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract first user message from session file
|
||||
* Override in subclass for tool-specific format
|
||||
@@ -956,16 +999,18 @@ export function findNativeSessionById(
|
||||
* @param beforeTimestamp - Filter sessions created after this time
|
||||
* @param workingDir - Project working directory
|
||||
* @param prompt - Optional prompt for precise matching in parallel execution
|
||||
* @param transactionId - Optional transaction ID for exact session matching
|
||||
*/
|
||||
export async function trackNewSession(
|
||||
tool: string,
|
||||
beforeTimestamp: Date,
|
||||
workingDir: string,
|
||||
prompt?: string
|
||||
prompt?: string,
|
||||
transactionId?: string
|
||||
): Promise<NativeSession | null> {
|
||||
const discoverer = discoverers[tool];
|
||||
if (!discoverer) return null;
|
||||
return discoverer.trackNewSession(beforeTimestamp, workingDir, prompt);
|
||||
return discoverer.trackNewSession(beforeTimestamp, workingDir, prompt, transactionId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user