feat: add issue discovery view for managing discovery sessions and findings

- Implemented main render function for the issue discovery view.
- Added data loading functions to fetch discoveries, details, findings, and progress.
- Created rendering functions for discovery list and detail sections.
- Introduced filtering and searching capabilities for findings.
- Implemented actions for exporting and dismissing findings.
- Added polling mechanism to track discovery progress.
- Included utility functions for HTML escaping and cleanup.
This commit is contained in:
catlog22
2025-12-28 17:21:07 +08:00
parent a2c88ba885
commit 7aa1cda367
28 changed files with 7730 additions and 2 deletions

View File

@@ -0,0 +1,219 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "discovery-finding-schema",
"title": "Discovery Finding Schema",
"description": "Schema for perspective-based issue discovery results",
"type": "object",
"required": ["perspective", "discovery_id", "analysis_timestamp", "cli_tool_used", "summary", "findings"],
"properties": {
"perspective": {
"type": "string",
"enum": ["bug", "ux", "test", "quality", "security", "performance", "maintainability", "best-practices"],
"description": "Discovery perspective"
},
"discovery_id": {
"type": "string",
"pattern": "^DSC-\\d{8}-\\d{6}$",
"description": "Parent discovery session ID"
},
"analysis_timestamp": {
"type": "string",
"format": "date-time",
"description": "ISO 8601 timestamp of analysis"
},
"cli_tool_used": {
"type": "string",
"enum": ["gemini", "qwen", "codex"],
"description": "CLI tool that performed the analysis"
},
"model": {
"type": "string",
"description": "Specific model version used",
"examples": ["gemini-2.5-pro", "qwen-max"]
},
"analysis_duration_ms": {
"type": "integer",
"minimum": 0,
"description": "Analysis duration in milliseconds"
},
"summary": {
"type": "object",
"required": ["total_findings"],
"properties": {
"total_findings": { "type": "integer", "minimum": 0 },
"critical": { "type": "integer", "minimum": 0 },
"high": { "type": "integer", "minimum": 0 },
"medium": { "type": "integer", "minimum": 0 },
"low": { "type": "integer", "minimum": 0 },
"files_analyzed": { "type": "integer", "minimum": 0 }
},
"description": "Summary statistics (FLAT structure, NOT nested)"
},
"findings": {
"type": "array",
"items": {
"type": "object",
"required": ["id", "title", "perspective", "priority", "category", "description", "file", "line"],
"properties": {
"id": {
"type": "string",
"pattern": "^dsc-[a-z]+-\\d{3}-[a-f0-9]{8}$",
"description": "Unique finding ID: dsc-{perspective}-{seq}-{uuid8}",
"examples": ["dsc-bug-001-a1b2c3d4"]
},
"title": {
"type": "string",
"minLength": 10,
"maxLength": 200,
"description": "Concise finding title"
},
"perspective": {
"type": "string",
"enum": ["bug", "ux", "test", "quality", "security", "performance", "maintainability", "best-practices"]
},
"priority": {
"type": "string",
"enum": ["critical", "high", "medium", "low"],
"description": "Priority level (lowercase only)"
},
"category": {
"type": "string",
"description": "Perspective-specific category",
"examples": ["null-check", "edge-case", "missing-test", "complexity", "injection"]
},
"description": {
"type": "string",
"minLength": 20,
"description": "Detailed description of the finding"
},
"file": {
"type": "string",
"description": "File path relative to project root"
},
"line": {
"type": "integer",
"minimum": 1,
"description": "Line number of the finding"
},
"snippet": {
"type": "string",
"description": "Relevant code snippet"
},
"suggested_issue": {
"type": "object",
"required": ["title", "type", "priority"],
"properties": {
"title": {
"type": "string",
"description": "Suggested issue title for export"
},
"type": {
"type": "string",
"enum": ["bug", "feature", "enhancement", "refactor", "test", "docs"],
"description": "Issue type"
},
"priority": {
"type": "integer",
"minimum": 1,
"maximum": 5,
"description": "Priority 1-5 (1=critical, 5=low)"
},
"labels": {
"type": "array",
"items": { "type": "string" },
"description": "Suggested labels for the issue"
}
},
"description": "Pre-filled issue suggestion for export"
},
"external_reference": {
"type": ["object", "null"],
"properties": {
"source": { "type": "string" },
"url": { "type": "string", "format": "uri" },
"relevance": { "type": "string" }
},
"description": "External reference from Exa research (if applicable)"
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "Confidence score 0.0-1.0"
},
"impact": {
"type": "string",
"description": "Description of potential impact"
},
"recommendation": {
"type": "string",
"description": "Specific recommendation to address the finding"
},
"metadata": {
"type": "object",
"additionalProperties": true,
"description": "Additional metadata (CWE ID, OWASP category, etc.)"
}
}
},
"description": "Array of discovered findings"
},
"cross_references": {
"type": "array",
"items": {
"type": "object",
"properties": {
"finding_id": { "type": "string" },
"related_perspectives": {
"type": "array",
"items": { "type": "string" }
},
"reason": { "type": "string" }
}
},
"description": "Cross-references to findings in other perspectives"
}
},
"examples": [
{
"perspective": "bug",
"discovery_id": "DSC-20250128-143022",
"analysis_timestamp": "2025-01-28T14:35:00Z",
"cli_tool_used": "gemini",
"model": "gemini-2.5-pro",
"analysis_duration_ms": 45000,
"summary": {
"total_findings": 8,
"critical": 1,
"high": 2,
"medium": 3,
"low": 2,
"files_analyzed": 5
},
"findings": [
{
"id": "dsc-bug-001-a1b2c3d4",
"title": "Missing null check in user validation",
"perspective": "bug",
"priority": "high",
"category": "null-check",
"description": "User object is accessed without null check after database query, which may fail if user doesn't exist",
"file": "src/auth/validator.ts",
"line": 45,
"snippet": "const user = await db.findUser(id);\nreturn user.email; // user may be null",
"suggested_issue": {
"title": "Add null check in user validation",
"type": "bug",
"priority": 2,
"labels": ["bug", "auth"]
},
"external_reference": null,
"confidence": 0.85,
"impact": "Runtime error when user not found",
"recommendation": "Add null check: if (!user) throw new NotFoundError('User not found');"
}
],
"cross_references": []
}
]
}

View File

@@ -0,0 +1,108 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "discovery-state-schema",
"title": "Discovery State Schema",
"description": "Schema for issue discovery session state machine",
"type": "object",
"required": ["discovery_id", "target_pattern", "metadata", "phase"],
"properties": {
"discovery_id": {
"type": "string",
"description": "Unique discovery session ID",
"pattern": "^DSC-\\d{8}-\\d{6}$",
"examples": ["DSC-20250128-143022"]
},
"target_pattern": {
"type": "string",
"description": "File/directory pattern being analyzed",
"examples": ["src/auth/**", "src/payment/**,src/api/**"]
},
"metadata": {
"type": "object",
"required": ["created_at", "resolved_files", "perspectives"],
"properties": {
"created_at": {
"type": "string",
"format": "date-time",
"description": "ISO 8601 timestamp of discovery creation"
},
"resolved_files": {
"type": "array",
"items": { "type": "string" },
"description": "List of resolved file paths from pattern"
},
"perspectives": {
"type": "array",
"items": {
"type": "string",
"enum": ["bug", "ux", "test", "quality", "security", "performance", "maintainability", "best-practices"]
},
"description": "Selected discovery perspectives"
},
"external_research_enabled": {
"type": "boolean",
"default": false,
"description": "Whether Exa research is enabled"
}
}
},
"phase": {
"type": "string",
"enum": ["initialization", "parallel", "external", "aggregation", "complete"],
"description": "Current execution phase"
},
"perspectives_completed": {
"type": "array",
"items": { "type": "string" },
"description": "List of completed perspective analyses"
},
"total_findings": {
"type": "integer",
"minimum": 0,
"description": "Total number of findings across all perspectives"
},
"priority_distribution": {
"type": "object",
"properties": {
"critical": { "type": "integer", "minimum": 0 },
"high": { "type": "integer", "minimum": 0 },
"medium": { "type": "integer", "minimum": 0 },
"low": { "type": "integer", "minimum": 0 }
},
"description": "Count of findings by priority level"
},
"issues_generated": {
"type": "integer",
"minimum": 0,
"description": "Number of issues generated from discoveries"
},
"completed_at": {
"type": "string",
"format": "date-time",
"description": "ISO 8601 timestamp of discovery completion"
}
},
"examples": [
{
"discovery_id": "DSC-20250128-143022",
"target_pattern": "src/auth/**",
"metadata": {
"created_at": "2025-01-28T14:30:22Z",
"resolved_files": ["src/auth/service.ts", "src/auth/validator.ts"],
"perspectives": ["bug", "ux", "test", "quality", "security"],
"external_research_enabled": true
},
"phase": "complete",
"perspectives_completed": ["bug", "ux", "test", "quality", "security"],
"total_findings": 45,
"priority_distribution": {
"critical": 2,
"high": 8,
"medium": 20,
"low": 15
},
"issues_generated": 10,
"completed_at": "2025-01-28T14:45:00Z"
}
]
}