mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-11 02:33:51 +08:00
feat: 增加失败分析功能,改进问题规划和解决方案生成
This commit is contained in:
@@ -279,6 +279,58 @@
|
||||
color: hsl(var(--destructive));
|
||||
}
|
||||
|
||||
/* Issue Failure Info */
|
||||
.issue-failure-info {
|
||||
margin-top: 0.75rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: hsl(var(--destructive) / 0.08);
|
||||
border: 1px solid hsl(var(--destructive) / 0.2);
|
||||
border-radius: 0.375rem;
|
||||
border-left: 3px solid hsl(var(--destructive));
|
||||
}
|
||||
|
||||
.issue-failure-info .failure-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
color: hsl(var(--destructive));
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.issue-failure-info .failure-label {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.issue-failure-info .failure-task {
|
||||
font-family: var(--font-mono);
|
||||
background: hsl(var(--destructive) / 0.15);
|
||||
padding: 0 0.25rem;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.6875rem;
|
||||
}
|
||||
|
||||
.issue-failure-info .failure-message {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem;
|
||||
font-size: 0.75rem;
|
||||
color: hsl(var(--muted-foreground));
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.issue-failure-info .failure-type {
|
||||
font-family: var(--font-mono);
|
||||
color: hsl(var(--destructive) / 0.8);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.issue-failure-info .failure-text {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* Priority Badges */
|
||||
.issue-priority {
|
||||
display: inline-flex;
|
||||
@@ -2014,6 +2066,41 @@
|
||||
border-left: 3px solid hsl(0 84% 60%);
|
||||
}
|
||||
|
||||
/* Queue Item Failure Info */
|
||||
.queue-item-failure {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
color: hsl(var(--destructive));
|
||||
background: hsl(var(--destructive) / 0.1);
|
||||
padding: 0.125rem 0.375rem;
|
||||
border-radius: 0.25rem;
|
||||
max-width: 250px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.queue-item-failure i {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.queue-item-failure .failure-type {
|
||||
font-family: var(--font-mono);
|
||||
font-weight: 500;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.queue-item-failure .failure-msg {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: hsl(var(--muted-foreground));
|
||||
}
|
||||
|
||||
/* Hide failure in parallel view to save space */
|
||||
.queue-items.parallel .queue-item .queue-item-failure {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Blocked - Purple/violet blocked state */
|
||||
.queue-item.blocked {
|
||||
border-color: hsl(262 83% 58%);
|
||||
|
||||
@@ -431,10 +431,60 @@ function renderIssueCard(issue) {
|
||||
<span>Archived on ${archivedDate}</span>
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
${renderFailureInfo(issue)}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Render failure information for failed issues
|
||||
function renderFailureInfo(issue) {
|
||||
// Check if issue has failure feedback
|
||||
if (!issue.feedback || issue.feedback.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Extract failure feedbacks
|
||||
const failures = issue.feedback.filter(f => f.type === 'failure' && f.stage === 'execute');
|
||||
if (failures.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Get latest failure
|
||||
const latestFailure = failures[failures.length - 1];
|
||||
let failureDetail;
|
||||
try {
|
||||
failureDetail = JSON.parse(latestFailure.content);
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
|
||||
const errorMessage = failureDetail.message || 'Unknown error';
|
||||
const errorType = failureDetail.error_type || 'error';
|
||||
const taskId = failureDetail.task_id;
|
||||
const failureCount = failures.length;
|
||||
|
||||
return `
|
||||
<div class="issue-failure-info">
|
||||
<div class="failure-header">
|
||||
<i data-lucide="alert-circle" class="w-3.5 h-3.5"></i>
|
||||
<span class="failure-label">${failureCount > 1 ? `Failed ${failureCount} times` : 'Execution Failed'}</span>
|
||||
${taskId ? `<span class="failure-task">${taskId}</span>` : ''}
|
||||
</div>
|
||||
<div class="failure-message">
|
||||
<span class="failure-type">${errorType}:</span>
|
||||
<span class="failure-text" title="${escapeHtml(errorMessage)}">${escapeHtml(truncateText(errorMessage, 80))}</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Helper: Truncate text to max length
|
||||
function truncateText(text, maxLength) {
|
||||
if (!text || text.length <= maxLength) return text;
|
||||
return text.substring(0, maxLength - 3) + '...';
|
||||
}
|
||||
|
||||
function renderPriorityStars(priority) {
|
||||
const maxStars = 5;
|
||||
let stars = '';
|
||||
@@ -879,6 +929,7 @@ function renderQueueItemWithDelete(item, index, total, queueId) {
|
||||
<i data-lucide="link" class="w-3 h-3"></i>
|
||||
</span>
|
||||
` : ''}
|
||||
${renderQueueItemFailureInfo(item)}
|
||||
<button class="queue-item-delete btn-icon" onclick="event.stopPropagation(); deleteQueueItem('${safeQueueId}', '${safeItemId}')" title="Delete item">
|
||||
<i data-lucide="trash-2" class="w-3 h-3"></i>
|
||||
</button>
|
||||
@@ -886,6 +937,47 @@ function renderQueueItemWithDelete(item, index, total, queueId) {
|
||||
`;
|
||||
}
|
||||
|
||||
// Render failure info for queue items
|
||||
function renderQueueItemFailureInfo(item) {
|
||||
// Only show for failed items
|
||||
if (item.status !== 'failed') {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Check failure_details or failure_reason
|
||||
const failureDetails = item.failure_details;
|
||||
const failureReason = item.failure_reason;
|
||||
|
||||
if (!failureDetails && !failureReason) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let errorType = 'error';
|
||||
let errorMessage = 'Unknown error';
|
||||
|
||||
if (failureDetails) {
|
||||
errorType = failureDetails.error_type || 'error';
|
||||
errorMessage = failureDetails.message || 'Unknown error';
|
||||
} else if (failureReason) {
|
||||
// Try to parse as JSON
|
||||
try {
|
||||
const parsed = JSON.parse(failureReason);
|
||||
errorType = parsed.error_type || 'error';
|
||||
errorMessage = parsed.message || failureReason;
|
||||
} catch {
|
||||
errorMessage = failureReason;
|
||||
}
|
||||
}
|
||||
|
||||
return `
|
||||
<span class="queue-item-failure text-xs" title="${escapeHtml(errorMessage)}">
|
||||
<i data-lucide="alert-circle" class="w-3 h-3"></i>
|
||||
<span class="failure-type">${escapeHtml(errorType)}:</span>
|
||||
<span class="failure-msg">${escapeHtml(truncateText(errorMessage, 40))}</span>
|
||||
</span>
|
||||
`;
|
||||
}
|
||||
|
||||
async function deleteQueueItem(queueId, itemId) {
|
||||
if (!confirm('Delete this item from queue?')) return;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user