mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-09 02:24:11 +08:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5114a942dc | ||
|
|
edef937822 |
@@ -67,7 +67,9 @@ Phase 4: Execution Strategy & Task Execution
|
|||||||
├─ Get next in_progress task from TodoWrite
|
├─ Get next in_progress task from TodoWrite
|
||||||
├─ Lazy load task JSON
|
├─ Lazy load task JSON
|
||||||
├─ Launch agent with task context
|
├─ Launch agent with task context
|
||||||
├─ Mark task completed
|
├─ Mark task completed (update IMPL-*.json status)
|
||||||
|
│ # Quick fix: Update task status for ccw dashboard
|
||||||
|
│ # TS=$(date -Iseconds) && jq --arg ts "$TS" '.status="completed" | .status_history=(.status_history // [])+[{"from":"in_progress","to":"completed","changed_at":$ts}]' IMPL-X.json > tmp.json && mv tmp.json IMPL-X.json
|
||||||
└─ Advance to next task
|
└─ Advance to next task
|
||||||
|
|
||||||
Phase 5: Completion
|
Phase 5: Completion
|
||||||
|
|||||||
@@ -39,6 +39,11 @@ function scanLiteDir(dir, type) {
|
|||||||
tasks: loadTaskJsons(sessionPath)
|
tasks: loadTaskJsons(sessionPath)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// For lite-fix sessions, also load diagnoses separately
|
||||||
|
if (type === 'lite-fix') {
|
||||||
|
session.diagnoses = loadDiagnoses(sessionPath);
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate progress
|
// Calculate progress
|
||||||
session.progress = calculateProgress(session.tasks);
|
session.progress = calculateProgress(session.tasks);
|
||||||
|
|
||||||
@@ -268,7 +273,7 @@ export function getLiteTaskDetail(workflowDir, type, sessionId) {
|
|||||||
|
|
||||||
if (!existsSync(dir)) return null;
|
if (!existsSync(dir)) return null;
|
||||||
|
|
||||||
return {
|
const detail = {
|
||||||
id: sessionId,
|
id: sessionId,
|
||||||
type,
|
type,
|
||||||
path: dir,
|
path: dir,
|
||||||
@@ -277,6 +282,13 @@ export function getLiteTaskDetail(workflowDir, type, sessionId) {
|
|||||||
explorations: loadExplorations(dir),
|
explorations: loadExplorations(dir),
|
||||||
clarifications: loadClarifications(dir)
|
clarifications: loadClarifications(dir)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// For lite-fix sessions, also load diagnoses
|
||||||
|
if (type === 'lite-fix') {
|
||||||
|
detail.diagnoses = loadDiagnoses(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
return detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -312,3 +324,50 @@ function loadClarifications(sessionPath) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load diagnosis files for lite-fix sessions
|
||||||
|
* Loads diagnosis-*.json files from session root directory
|
||||||
|
* @param {string} sessionPath - Session directory path
|
||||||
|
* @returns {Object} - Diagnoses data with manifest and items
|
||||||
|
*/
|
||||||
|
function loadDiagnoses(sessionPath) {
|
||||||
|
const result = {
|
||||||
|
manifest: null,
|
||||||
|
items: []
|
||||||
|
};
|
||||||
|
|
||||||
|
// Try to load diagnoses-manifest.json first
|
||||||
|
const manifestPath = join(sessionPath, 'diagnoses-manifest.json');
|
||||||
|
if (existsSync(manifestPath)) {
|
||||||
|
try {
|
||||||
|
result.manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
||||||
|
} catch {
|
||||||
|
// Continue without manifest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load all diagnosis-*.json files from session root
|
||||||
|
try {
|
||||||
|
const diagnosisFiles = readdirSync(sessionPath)
|
||||||
|
.filter(f => f.startsWith('diagnosis-') && f.endsWith('.json'));
|
||||||
|
|
||||||
|
for (const file of diagnosisFiles) {
|
||||||
|
const filePath = join(sessionPath, file);
|
||||||
|
try {
|
||||||
|
const content = JSON.parse(readFileSync(filePath, 'utf8'));
|
||||||
|
result.items.push({
|
||||||
|
id: file.replace('diagnosis-', '').replace('.json', ''),
|
||||||
|
filename: file,
|
||||||
|
...content
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// Skip invalid files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Return empty items if directory read fails
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
@@ -841,3 +841,331 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===================================
|
||||||
|
Fix Plan Enhanced Styles
|
||||||
|
=================================== */
|
||||||
|
|
||||||
|
.plan-root-cause-text,
|
||||||
|
.plan-strategy-text,
|
||||||
|
.plan-requirements-text {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
padding: 0.75rem;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
border-left: 3px solid hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.severity-badge,
|
||||||
|
.risk-badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.125rem 0.5rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.severity-badge.critical,
|
||||||
|
.risk-badge.high {
|
||||||
|
background: hsl(0 70% 50% / 0.15);
|
||||||
|
color: hsl(0 70% 45%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.severity-badge.high,
|
||||||
|
.risk-badge.medium {
|
||||||
|
background: hsl(30 90% 50% / 0.15);
|
||||||
|
color: hsl(30 90% 40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.severity-badge.medium {
|
||||||
|
background: hsl(45 90% 50% / 0.15);
|
||||||
|
color: hsl(45 80% 35%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.severity-badge.low,
|
||||||
|
.risk-badge.low {
|
||||||
|
background: hsl(142 70% 50% / 0.15);
|
||||||
|
color: hsl(142 70% 35%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fix-tasks-summary {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fix-task-summary-item {
|
||||||
|
background: hsl(var(--card));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fix-task-summary-item .collapsible-header {
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-num {
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-title-brief {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-scope-badge {
|
||||||
|
padding: 0.125rem 0.5rem;
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-detail-section {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-detail-section:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-detail-section strong {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.025em;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mod-points-list,
|
||||||
|
.verify-list {
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 1rem;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mod-points-list li,
|
||||||
|
.verify-list li {
|
||||||
|
margin-bottom: 0.375rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mod-points-list code {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.func-name {
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.change-type {
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
font-size: 0.7rem;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===================================
|
||||||
|
Diagnoses Tab Styles
|
||||||
|
=================================== */
|
||||||
|
|
||||||
|
.diagnoses-tab-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diagnoses-section-title {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diagnoses-manifest-section {
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manifest-meta-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diagnoses-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diagnosis-card {
|
||||||
|
background: hsl(var(--card));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diagnosis-header {
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.diagnosis-id {
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diag-section {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
border-bottom: 1px solid hsl(var(--border) / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.diag-section:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diag-section strong {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.025em;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diag-section p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.issues-list {
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 1rem;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.issue-item {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.issue-title {
|
||||||
|
font-weight: 500;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.issue-location {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.issue-location code {
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.contracts-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contract-item {
|
||||||
|
padding: 0.75rem;
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contract-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contract-endpoint {
|
||||||
|
font-weight: 500;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.contract-method {
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
background: hsl(var(--primary) / 0.15);
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contract-desc {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.contract-issues {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: hsl(0 70% 50%);
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dataflow-details {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.df-item {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.df-label {
|
||||||
|
font-weight: 500;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.df-transforms {
|
||||||
|
margin: 0.25rem 0 0 1rem;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recommendations-list {
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 1.25rem;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recommendations-list li {
|
||||||
|
margin-bottom: 0.375rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -136,6 +136,13 @@ function showLiteTaskDetailPage(sessionKey) {
|
|||||||
<span class="tab-icon"><i data-lucide="ruler" class="w-4 h-4"></i></span>
|
<span class="tab-icon"><i data-lucide="ruler" class="w-4 h-4"></i></span>
|
||||||
<span class="tab-text">Plan</span>
|
<span class="tab-text">Plan</span>
|
||||||
</button>
|
</button>
|
||||||
|
${session.type === 'lite-fix' ? `
|
||||||
|
<button class="detail-tab" data-tab="diagnoses" onclick="switchLiteDetailTab('diagnoses')">
|
||||||
|
<span class="tab-icon"><i data-lucide="stethoscope" class="w-4 h-4"></i></span>
|
||||||
|
<span class="tab-text">Diagnoses</span>
|
||||||
|
${session.diagnoses?.items?.length ? `<span class="tab-count">${session.diagnoses.items.length}</span>` : ''}
|
||||||
|
</button>
|
||||||
|
` : ''}
|
||||||
<button class="detail-tab" data-tab="context" onclick="switchLiteDetailTab('context')">
|
<button class="detail-tab" data-tab="context" onclick="switchLiteDetailTab('context')">
|
||||||
<span class="tab-icon"><i data-lucide="package" class="w-4 h-4"></i></span>
|
<span class="tab-icon"><i data-lucide="package" class="w-4 h-4"></i></span>
|
||||||
<span class="tab-text">Context</span>
|
<span class="tab-text">Context</span>
|
||||||
@@ -196,6 +203,17 @@ function switchLiteDetailTab(tabName) {
|
|||||||
break;
|
break;
|
||||||
case 'plan':
|
case 'plan':
|
||||||
contentArea.innerHTML = renderLitePlanTab(session);
|
contentArea.innerHTML = renderLitePlanTab(session);
|
||||||
|
// Re-initialize collapsible sections for plan tab
|
||||||
|
setTimeout(() => {
|
||||||
|
initCollapsibleSections(contentArea);
|
||||||
|
}, 50);
|
||||||
|
break;
|
||||||
|
case 'diagnoses':
|
||||||
|
contentArea.innerHTML = renderDiagnosesTab(session);
|
||||||
|
// Re-initialize collapsible sections for diagnoses tab
|
||||||
|
setTimeout(() => {
|
||||||
|
initCollapsibleSections(contentArea);
|
||||||
|
}, 50);
|
||||||
break;
|
break;
|
||||||
case 'context':
|
case 'context':
|
||||||
loadAndRenderLiteContextTab(session, contentArea);
|
loadAndRenderLiteContextTab(session, contentArea);
|
||||||
@@ -287,13 +305,14 @@ function openTaskDrawerForLite(sessionId, taskId) {
|
|||||||
|
|
||||||
function renderLitePlanTab(session) {
|
function renderLitePlanTab(session) {
|
||||||
const plan = session.plan;
|
const plan = session.plan;
|
||||||
|
const isFixPlan = session.type === 'lite-fix';
|
||||||
|
|
||||||
if (!plan) {
|
if (!plan) {
|
||||||
return `
|
return `
|
||||||
<div class="tab-empty-state">
|
<div class="tab-empty-state">
|
||||||
<div class="empty-icon"><i data-lucide="ruler" class="w-12 h-12"></i></div>
|
<div class="empty-icon"><i data-lucide="ruler" class="w-12 h-12"></i></div>
|
||||||
<div class="empty-title">No Plan Data</div>
|
<div class="empty-title">No Plan Data</div>
|
||||||
<div class="empty-text">No plan.json found for this session.</div>
|
<div class="empty-text">No ${isFixPlan ? 'fix-plan.json' : 'plan.json'} found for this session.</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -308,6 +327,22 @@ function renderLitePlanTab(session) {
|
|||||||
</div>
|
</div>
|
||||||
` : ''}
|
` : ''}
|
||||||
|
|
||||||
|
<!-- Root Cause (fix-plan specific) -->
|
||||||
|
${plan.root_cause ? `
|
||||||
|
<div class="plan-section">
|
||||||
|
<h4 class="plan-section-title"><i data-lucide="search" class="w-4 h-4 inline mr-1"></i> Root Cause</h4>
|
||||||
|
<p class="plan-root-cause-text">${escapeHtml(plan.root_cause)}</p>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
|
||||||
|
<!-- Strategy (fix-plan specific) -->
|
||||||
|
${plan.strategy ? `
|
||||||
|
<div class="plan-section">
|
||||||
|
<h4 class="plan-section-title"><i data-lucide="route" class="w-4 h-4 inline mr-1"></i> Fix Strategy</h4>
|
||||||
|
<p class="plan-strategy-text">${escapeHtml(plan.strategy)}</p>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
|
||||||
<!-- Approach -->
|
<!-- Approach -->
|
||||||
${plan.approach ? `
|
${plan.approach ? `
|
||||||
<div class="plan-section">
|
<div class="plan-section">
|
||||||
@@ -316,6 +351,14 @@ function renderLitePlanTab(session) {
|
|||||||
</div>
|
</div>
|
||||||
` : ''}
|
` : ''}
|
||||||
|
|
||||||
|
<!-- User Requirements (fix-plan specific) -->
|
||||||
|
${plan.user_requirements ? `
|
||||||
|
<div class="plan-section">
|
||||||
|
<h4 class="plan-section-title"><i data-lucide="user" class="w-4 h-4 inline mr-1"></i> User Requirements</h4>
|
||||||
|
<p class="plan-requirements-text">${escapeHtml(plan.user_requirements)}</p>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
|
||||||
<!-- Focus Paths -->
|
<!-- Focus Paths -->
|
||||||
${plan.focus_paths?.length ? `
|
${plan.focus_paths?.length ? `
|
||||||
<div class="plan-section">
|
<div class="plan-section">
|
||||||
@@ -330,16 +373,74 @@ function renderLitePlanTab(session) {
|
|||||||
<div class="plan-section">
|
<div class="plan-section">
|
||||||
<h4 class="plan-section-title"><i data-lucide="info" class="w-4 h-4 inline mr-1"></i> Metadata</h4>
|
<h4 class="plan-section-title"><i data-lucide="info" class="w-4 h-4 inline mr-1"></i> Metadata</h4>
|
||||||
<div class="plan-meta-grid">
|
<div class="plan-meta-grid">
|
||||||
|
${plan.severity ? `<div class="meta-item"><span class="meta-label">Severity:</span> <span class="severity-badge ${escapeHtml(plan.severity)}">${escapeHtml(plan.severity)}</span></div>` : ''}
|
||||||
|
${plan.risk_level ? `<div class="meta-item"><span class="meta-label">Risk Level:</span> <span class="risk-badge ${escapeHtml(plan.risk_level)}">${escapeHtml(plan.risk_level)}</span></div>` : ''}
|
||||||
${plan.estimated_time ? `<div class="meta-item"><span class="meta-label">Estimated Time:</span> ${escapeHtml(plan.estimated_time)}</div>` : ''}
|
${plan.estimated_time ? `<div class="meta-item"><span class="meta-label">Estimated Time:</span> ${escapeHtml(plan.estimated_time)}</div>` : ''}
|
||||||
${plan.complexity ? `<div class="meta-item"><span class="meta-label">Complexity:</span> ${escapeHtml(plan.complexity)}</div>` : ''}
|
${plan.complexity ? `<div class="meta-item"><span class="meta-label">Complexity:</span> ${escapeHtml(plan.complexity)}</div>` : ''}
|
||||||
${plan.recommended_execution ? `<div class="meta-item"><span class="meta-label">Execution:</span> ${escapeHtml(plan.recommended_execution)}</div>` : ''}
|
${plan.recommended_execution ? `<div class="meta-item"><span class="meta-label">Execution:</span> ${escapeHtml(plan.recommended_execution)}</div>` : ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Fix Tasks Summary (fix-plan specific) -->
|
||||||
|
${plan.tasks?.length ? `
|
||||||
|
<div class="plan-section">
|
||||||
|
<h4 class="plan-section-title"><i data-lucide="list-checks" class="w-4 h-4 inline mr-1"></i> Fix Tasks (${plan.tasks.length})</h4>
|
||||||
|
<div class="fix-tasks-summary">
|
||||||
|
${plan.tasks.map((task, idx) => `
|
||||||
|
<div class="fix-task-summary-item collapsible-section">
|
||||||
|
<div class="collapsible-header">
|
||||||
|
<span class="collapse-icon">▶</span>
|
||||||
|
<span class="task-num">#${idx + 1}</span>
|
||||||
|
<span class="task-title-brief">${escapeHtml(task.title || task.summary || 'Untitled')}</span>
|
||||||
|
${task.scope ? `<span class="task-scope-badge">${escapeHtml(task.scope)}</span>` : ''}
|
||||||
|
</div>
|
||||||
|
<div class="collapsible-content collapsed">
|
||||||
|
${task.modification_points?.length ? `
|
||||||
|
<div class="task-detail-section">
|
||||||
|
<strong>Modification Points:</strong>
|
||||||
|
<ul class="mod-points-list">
|
||||||
|
${task.modification_points.map(mp => `
|
||||||
|
<li>
|
||||||
|
<code>${escapeHtml(mp.file || '')}</code>
|
||||||
|
${mp.function_name ? `<span class="func-name">→ ${escapeHtml(mp.function_name)}</span>` : ''}
|
||||||
|
${mp.change_type ? `<span class="change-type">(${escapeHtml(mp.change_type)})</span>` : ''}
|
||||||
|
</li>
|
||||||
|
`).join('')}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
${task.implementation?.length ? `
|
||||||
|
<div class="task-detail-section">
|
||||||
|
<strong>Implementation Steps:</strong>
|
||||||
|
<ol class="impl-steps-list">
|
||||||
|
${task.implementation.map(step => `<li>${escapeHtml(step)}</li>`).join('')}
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
${task.verification?.length ? `
|
||||||
|
<div class="task-detail-section">
|
||||||
|
<strong>Verification:</strong>
|
||||||
|
<ul class="verify-list">
|
||||||
|
${task.verification.map(v => `<li>${escapeHtml(v)}</li>`).join('')}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
|
||||||
<!-- Raw JSON -->
|
<!-- Raw JSON -->
|
||||||
<div class="plan-section">
|
<div class="plan-section collapsible-section">
|
||||||
<h4 class="plan-section-title">{ } Raw JSON</h4>
|
<div class="collapsible-header">
|
||||||
<pre class="json-content">${escapeHtml(JSON.stringify(plan, null, 2))}</pre>
|
<span class="collapse-icon">▶</span>
|
||||||
|
<span class="section-label">{ } Raw JSON</span>
|
||||||
|
</div>
|
||||||
|
<div class="collapsible-content collapsed">
|
||||||
|
<pre class="json-content">${escapeHtml(JSON.stringify(plan, null, 2))}</pre>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -393,3 +494,192 @@ async function loadAndRenderLiteSummaryTab(session, contentArea) {
|
|||||||
contentArea.innerHTML = `<div class="tab-error">Failed to load summaries: ${err.message}</div>`;
|
contentArea.innerHTML = `<div class="tab-error">Failed to load summaries: ${err.message}</div>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// DIAGNOSES TAB RENDERING (lite-fix specific)
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
function renderDiagnosesTab(session) {
|
||||||
|
const diagnoses = session.diagnoses;
|
||||||
|
|
||||||
|
if (!diagnoses || (!diagnoses.manifest && diagnoses.items?.length === 0)) {
|
||||||
|
return `
|
||||||
|
<div class="tab-empty-state">
|
||||||
|
<div class="empty-icon"><i data-lucide="stethoscope" class="w-12 h-12"></i></div>
|
||||||
|
<div class="empty-title">No Diagnoses</div>
|
||||||
|
<div class="empty-text">No diagnosis-*.json files found for this session.</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
let sections = [];
|
||||||
|
|
||||||
|
// Manifest summary (if available)
|
||||||
|
if (diagnoses.manifest) {
|
||||||
|
sections.push(`
|
||||||
|
<div class="diagnoses-manifest-section">
|
||||||
|
<h4 class="diagnoses-section-title"><i data-lucide="clipboard-check" class="w-4 h-4 inline mr-1"></i> Diagnosis Summary</h4>
|
||||||
|
<div class="manifest-meta-grid">
|
||||||
|
${diagnoses.manifest.total_diagnoses ? `<div class="meta-item"><span class="meta-label">Total Diagnoses:</span> ${diagnoses.manifest.total_diagnoses}</div>` : ''}
|
||||||
|
${diagnoses.manifest.diagnosis_angles ? `<div class="meta-item"><span class="meta-label">Angles:</span> ${diagnoses.manifest.diagnosis_angles.join(', ')}</div>` : ''}
|
||||||
|
${diagnoses.manifest.created_at ? `<div class="meta-item"><span class="meta-label">Created:</span> ${formatDate(diagnoses.manifest.created_at)}</div>` : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Individual diagnosis items
|
||||||
|
if (diagnoses.items && diagnoses.items.length > 0) {
|
||||||
|
const diagnosisCards = diagnoses.items.map(diag => renderDiagnosisCard(diag)).join('');
|
||||||
|
sections.push(`
|
||||||
|
<div class="diagnoses-items-section">
|
||||||
|
<h4 class="diagnoses-section-title"><i data-lucide="search" class="w-4 h-4 inline mr-1"></i> Diagnosis Details (${diagnoses.items.length})</h4>
|
||||||
|
<div class="diagnoses-grid">
|
||||||
|
${diagnosisCards}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return `<div class="diagnoses-tab-content">${sections.join('')}</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderDiagnosisCard(diag) {
|
||||||
|
const diagJsonId = `diag-json-${diag.id}`.replace(/[^a-zA-Z0-9-]/g, '-');
|
||||||
|
taskJsonStore[diagJsonId] = diag;
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="diagnosis-card collapsible-section">
|
||||||
|
<div class="collapsible-header diagnosis-header">
|
||||||
|
<span class="collapse-icon">▶</span>
|
||||||
|
<span class="diagnosis-id"><i data-lucide="file-search" class="w-4 h-4 inline mr-1"></i>${escapeHtml(diag.id)}</span>
|
||||||
|
<button class="btn-view-json" onclick="event.stopPropagation(); showJsonModal('${diagJsonId}', '${escapeHtml(diag.id)}')">{ } JSON</button>
|
||||||
|
</div>
|
||||||
|
<div class="collapsible-content collapsed">
|
||||||
|
${renderDiagnosisContent(diag)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderDiagnosisContent(diag) {
|
||||||
|
let content = [];
|
||||||
|
|
||||||
|
// Summary/Overview
|
||||||
|
if (diag.summary || diag.overview) {
|
||||||
|
content.push(`
|
||||||
|
<div class="diag-section">
|
||||||
|
<strong>Summary:</strong>
|
||||||
|
<p>${escapeHtml(diag.summary || diag.overview)}</p>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Root Cause Analysis
|
||||||
|
if (diag.root_cause || diag.root_cause_analysis) {
|
||||||
|
content.push(`
|
||||||
|
<div class="diag-section">
|
||||||
|
<strong>Root Cause:</strong>
|
||||||
|
<p>${escapeHtml(diag.root_cause || diag.root_cause_analysis)}</p>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issues/Findings
|
||||||
|
if (diag.issues && Array.isArray(diag.issues)) {
|
||||||
|
content.push(`
|
||||||
|
<div class="diag-section">
|
||||||
|
<strong>Issues Found (${diag.issues.length}):</strong>
|
||||||
|
<ul class="issues-list">
|
||||||
|
${diag.issues.map(issue => `
|
||||||
|
<li class="issue-item">
|
||||||
|
${typeof issue === 'string' ? escapeHtml(issue) : `
|
||||||
|
<div class="issue-title">${escapeHtml(issue.title || issue.description || 'Unknown')}</div>
|
||||||
|
${issue.location ? `<div class="issue-location"><code>${escapeHtml(issue.location)}</code></div>` : ''}
|
||||||
|
${issue.severity ? `<span class="severity-badge ${issue.severity}">${escapeHtml(issue.severity)}</span>` : ''}
|
||||||
|
`}
|
||||||
|
</li>
|
||||||
|
`).join('')}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Affected Files
|
||||||
|
if (diag.affected_files && Array.isArray(diag.affected_files)) {
|
||||||
|
content.push(`
|
||||||
|
<div class="diag-section">
|
||||||
|
<strong>Affected Files:</strong>
|
||||||
|
<div class="path-tags">
|
||||||
|
${diag.affected_files.map(f => `<span class="path-tag">${escapeHtml(typeof f === 'string' ? f : f.path || f.file)}</span>`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// API Contracts (for api-contracts diagnosis)
|
||||||
|
if (diag.contracts && Array.isArray(diag.contracts)) {
|
||||||
|
content.push(`
|
||||||
|
<div class="diag-section">
|
||||||
|
<strong>API Contracts (${diag.contracts.length}):</strong>
|
||||||
|
<div class="contracts-list">
|
||||||
|
${diag.contracts.map(contract => `
|
||||||
|
<div class="contract-item">
|
||||||
|
<div class="contract-header">
|
||||||
|
<span class="contract-endpoint">${escapeHtml(contract.endpoint || contract.name || 'Unknown')}</span>
|
||||||
|
${contract.method ? `<span class="contract-method">${escapeHtml(contract.method)}</span>` : ''}
|
||||||
|
</div>
|
||||||
|
${contract.description ? `<div class="contract-desc">${escapeHtml(contract.description)}</div>` : ''}
|
||||||
|
${contract.issues?.length ? `<div class="contract-issues">${contract.issues.length} issue(s)</div>` : ''}
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dataflow Analysis (for dataflow diagnosis)
|
||||||
|
if (diag.dataflow || diag.data_flow) {
|
||||||
|
const df = diag.dataflow || diag.data_flow;
|
||||||
|
content.push(`
|
||||||
|
<div class="diag-section">
|
||||||
|
<strong>Data Flow Analysis:</strong>
|
||||||
|
${typeof df === 'string' ? `<p>${escapeHtml(df)}</p>` : `
|
||||||
|
<div class="dataflow-details">
|
||||||
|
${df.source ? `<div class="df-item"><span class="df-label">Source:</span> ${escapeHtml(df.source)}</div>` : ''}
|
||||||
|
${df.sink ? `<div class="df-item"><span class="df-label">Sink:</span> ${escapeHtml(df.sink)}</div>` : ''}
|
||||||
|
${df.transformations?.length ? `
|
||||||
|
<div class="df-item">
|
||||||
|
<span class="df-label">Transformations:</span>
|
||||||
|
<ol class="df-transforms">${df.transformations.map(t => `<li>${escapeHtml(t)}</li>`).join('')}</ol>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
`}
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recommendations
|
||||||
|
if (diag.recommendations && Array.isArray(diag.recommendations)) {
|
||||||
|
content.push(`
|
||||||
|
<div class="diag-section">
|
||||||
|
<strong>Recommendations:</strong>
|
||||||
|
<ol class="recommendations-list">
|
||||||
|
${diag.recommendations.map(rec => `<li>${escapeHtml(typeof rec === 'string' ? rec : rec.description || rec.action)}</li>`).join('')}
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no specific content was rendered, show raw JSON preview
|
||||||
|
if (content.length === 0) {
|
||||||
|
content.push(`
|
||||||
|
<div class="diag-section">
|
||||||
|
<pre class="json-content">${escapeHtml(JSON.stringify(diag, null, 2))}</pre>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return content.join('');
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "claude-code-workflow",
|
"name": "claude-code-workflow",
|
||||||
"version": "6.1.3",
|
"version": "6.1.4",
|
||||||
"description": "JSON-driven multi-agent development framework with intelligent CLI orchestration (Gemini/Qwen/Codex), context-first architecture, and automated workflow execution",
|
"description": "JSON-driven multi-agent development framework with intelligent CLI orchestration (Gemini/Qwen/Codex), context-first architecture, and automated workflow execution",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "ccw/src/index.js",
|
"main": "ccw/src/index.js",
|
||||||
|
|||||||
Reference in New Issue
Block a user