mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-05 01:50:27 +08:00
Add help view and core memory styles
- Introduced styles for the help view including tab transitions, accordion animations, search highlighting, and responsive design. - Implemented core memory styles with modal base styles, memory card designs, and knowledge graph visualization. - Enhanced dark mode support across various components. - Added loading states and empty state designs for better user experience.
This commit is contained in:
@@ -2,5 +2,5 @@
|
|||||||
|
|
||||||
- **CLI Tools Usage**: @~/.claude/workflows/cli-tools-usage.md
|
- **CLI Tools Usage**: @~/.claude/workflows/cli-tools-usage.md
|
||||||
- **Coding Philosophy**: @~/.claude/workflows/coding-philosophy.md
|
- **Coding Philosophy**: @~/.claude/workflows/coding-philosophy.md
|
||||||
- **Context Requirements**: @~/.claude/workflows/context-requirements.md
|
- **Context Requirements**: @~/.claude/workflows/context-tools.md
|
||||||
- **File Modification**: @~/.claude/workflows/file-modification.md
|
- **File Modification**: @~/.claude/workflows/file-modification.md
|
||||||
@@ -61,3 +61,10 @@
|
|||||||
- **Reference, don't duplicate** - point to other layers, never copy content
|
- **Reference, don't duplicate** - point to other layers, never copy content
|
||||||
- **Maintain perspective** - each layer sees the system at its appropriate scale
|
- **Maintain perspective** - each layer sees the system at its appropriate scale
|
||||||
- **Avoid implementation creep** - higher layers stay architectural
|
- **Avoid implementation creep** - higher layers stay architectural
|
||||||
|
|
||||||
|
# Context Requirements
|
||||||
|
|
||||||
|
Before implementation, always:
|
||||||
|
- Identify 3+ existing similar patterns
|
||||||
|
- Map dependencies and integration points
|
||||||
|
- Understand testing framework and coding conventions
|
||||||
@@ -1,10 +1,3 @@
|
|||||||
# Context Requirements
|
|
||||||
|
|
||||||
Before implementation, always:
|
|
||||||
- Identify 3+ existing similar patterns
|
|
||||||
- Map dependencies and integration points
|
|
||||||
- Understand testing framework and coding conventions
|
|
||||||
|
|
||||||
## MCP Tools Usage
|
## MCP Tools Usage
|
||||||
|
|
||||||
### smart_search - Code Search (REQUIRED)
|
### smart_search - Code Search (REQUIRED)
|
||||||
@@ -24,15 +24,29 @@ const MODULE_CSS_FILES = [
|
|||||||
'07-managers.css',
|
'07-managers.css',
|
||||||
'08-review.css',
|
'08-review.css',
|
||||||
'09-explorer.css',
|
'09-explorer.css',
|
||||||
'10-cli.css',
|
// CLI modules (split from 10-cli.css)
|
||||||
'11-memory.css',
|
'10-cli-status.css',
|
||||||
'11-prompt-history.css',
|
'11-cli-history.css',
|
||||||
'12-skills-rules.css',
|
'12-cli-legacy.css',
|
||||||
'13-claude-manager.css',
|
'13-cli-ccw.css',
|
||||||
'14-graph-explorer.css',
|
'14-cli-modals.css',
|
||||||
'15-mcp-manager.css',
|
'15-cli-endpoints.css',
|
||||||
'16-help.css',
|
'16-cli-session.css',
|
||||||
'17-core-memory.css'
|
'17-cli-conversation.css',
|
||||||
|
'18-cli-settings.css',
|
||||||
|
'19-cli-native-session.css',
|
||||||
|
'20-cli-taskqueue.css',
|
||||||
|
'21-cli-toolmgmt.css',
|
||||||
|
'22-cli-semantic.css',
|
||||||
|
// Other modules
|
||||||
|
'23-memory.css',
|
||||||
|
'24-prompt-history.css',
|
||||||
|
'25-skills-rules.css',
|
||||||
|
'26-claude-manager.css',
|
||||||
|
'27-graph-explorer.css',
|
||||||
|
'28-mcp-manager.css',
|
||||||
|
'29-help.css',
|
||||||
|
'30-core-memory.css'
|
||||||
];
|
];
|
||||||
|
|
||||||
const MODULE_FILES = [
|
const MODULE_FILES = [
|
||||||
|
|||||||
@@ -61,15 +61,29 @@ const MODULE_CSS_FILES = [
|
|||||||
'07-managers.css',
|
'07-managers.css',
|
||||||
'08-review.css',
|
'08-review.css',
|
||||||
'09-explorer.css',
|
'09-explorer.css',
|
||||||
'10-cli.css',
|
// CLI modules (split from 10-cli.css)
|
||||||
'11-memory.css',
|
'10-cli-status.css',
|
||||||
'11-prompt-history.css',
|
'11-cli-history.css',
|
||||||
'12-skills-rules.css',
|
'12-cli-legacy.css',
|
||||||
'13-claude-manager.css',
|
'13-cli-ccw.css',
|
||||||
'14-graph-explorer.css',
|
'14-cli-modals.css',
|
||||||
'15-mcp-manager.css',
|
'15-cli-endpoints.css',
|
||||||
'16-help.css',
|
'16-cli-session.css',
|
||||||
'17-core-memory.css'
|
'17-cli-conversation.css',
|
||||||
|
'18-cli-settings.css',
|
||||||
|
'19-cli-native-session.css',
|
||||||
|
'20-cli-taskqueue.css',
|
||||||
|
'21-cli-toolmgmt.css',
|
||||||
|
'22-cli-semantic.css',
|
||||||
|
// Other modules
|
||||||
|
'23-memory.css',
|
||||||
|
'24-prompt-history.css',
|
||||||
|
'25-skills-rules.css',
|
||||||
|
'26-claude-manager.css',
|
||||||
|
'27-graph-explorer.css',
|
||||||
|
'28-mcp-manager.css',
|
||||||
|
'29-help.css',
|
||||||
|
'30-core-memory.css'
|
||||||
];
|
];
|
||||||
|
|
||||||
// Modular JS files in dependency order
|
// Modular JS files in dependency order
|
||||||
|
|||||||
337
ccw/src/templates/dashboard-css/10-cli-status.css
Normal file
337
ccw/src/templates/dashboard-css/10-cli-status.css
Normal file
@@ -0,0 +1,337 @@
|
|||||||
|
/* ========================================
|
||||||
|
* CLI Manager Styles
|
||||||
|
* Unified font: system-ui for UI, monospace for code
|
||||||
|
* ======================================== */
|
||||||
|
|
||||||
|
/* ========================================
|
||||||
|
* Status Manager - Two Column Layout
|
||||||
|
* ======================================== */
|
||||||
|
.status-manager {
|
||||||
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-two-column {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 1.5rem;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.status-two-column {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Section Container */
|
||||||
|
.status-section {
|
||||||
|
background: hsl(var(--card));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CLI Section - No card wrapper */
|
||||||
|
.cli-section {
|
||||||
|
/* No background, border, or card styling */
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-section .section-header {
|
||||||
|
padding: 0 0 0.75rem 0;
|
||||||
|
border-bottom: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-section .section-header h3 {
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-section .tools-list,
|
||||||
|
.cli-section .ccw-list,
|
||||||
|
.cli-section .endpoint-tools-grid {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Section Header */
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.875rem 1rem;
|
||||||
|
border-bottom: 1px solid hsl(var(--border));
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header h3 {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header h3 i {
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-count {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tools List */
|
||||||
|
.tools-list {
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.75rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
margin-bottom: 0.375rem;
|
||||||
|
background: hsl(var(--card));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item:hover {
|
||||||
|
background: hsl(var(--hover));
|
||||||
|
border-color: hsl(var(--primary) / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item.available {
|
||||||
|
/* No left border - use status dot instead */
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item.unavailable {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item.endpoint {
|
||||||
|
/* No left border */
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-status-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-status-dot.status-available {
|
||||||
|
background: hsl(var(--success));
|
||||||
|
box-shadow: 0 0 6px hsl(var(--success) / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-status-dot.status-unavailable {
|
||||||
|
background: hsl(var(--muted-foreground) / 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item-name {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item-desc {
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-default-badge {
|
||||||
|
font-size: 0.5625rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
background: hsl(var(--primary));
|
||||||
|
color: hsl(var(--primary-foreground));
|
||||||
|
border-radius: 9999px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-type-badge {
|
||||||
|
font-size: 0.5625rem;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-type-badge.ai {
|
||||||
|
background: hsl(var(--primary) / 0.15);
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-type-badge.llm {
|
||||||
|
background: hsl(142 76% 36% / 0.15);
|
||||||
|
color: hsl(142 76% 36%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-status-text {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-status-text.success {
|
||||||
|
color: hsl(var(--success));
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-status-text.muted {
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CCW List */
|
||||||
|
.ccw-list {
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.75rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
margin-bottom: 0.375rem;
|
||||||
|
background: hsl(var(--card));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-item:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-item:hover {
|
||||||
|
background: hsl(var(--hover));
|
||||||
|
border-color: hsl(var(--primary) / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-item-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.75rem;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-item-mode {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 2.25rem;
|
||||||
|
height: 2.25rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-item-mode.global {
|
||||||
|
background: hsl(var(--primary) / 0.1);
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-item-mode.path {
|
||||||
|
background: hsl(var(--warning) / 0.1);
|
||||||
|
color: hsl(var(--warning));
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-item-info {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-item-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-item-name {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-item-path {
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
font-family: 'SF Mono', 'Consolas', 'Liberation Mono', monospace;
|
||||||
|
background: hsl(var(--muted) / 0.5);
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
margin-bottom: 0.375rem;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-item-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.75rem;
|
||||||
|
font-size: 0.625rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-item-meta span {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-item-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-item:hover .ccw-item-actions {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
271
ccw/src/templates/dashboard-css/11-cli-history.css
Normal file
271
ccw/src/templates/dashboard-css/11-cli-history.css
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
/* ========================================
|
||||||
|
* History View Styles
|
||||||
|
* ======================================== */
|
||||||
|
.history-view {
|
||||||
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.75rem 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
border-bottom: 1px solid hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-header-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-count {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-header-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-search-wrapper {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-search-wrapper i {
|
||||||
|
position: absolute;
|
||||||
|
left: 0.625rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-search-input {
|
||||||
|
padding: 0.5rem 0.75rem 0.5rem 2rem;
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
background: hsl(var(--background));
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
width: 220px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-search-input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: hsl(var(--primary));
|
||||||
|
box-shadow: 0 0 0 2px hsl(var(--primary) / 0.15);
|
||||||
|
width: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-search-input::placeholder {
|
||||||
|
color: hsl(var(--muted-foreground) / 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-filter-select {
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
background: hsl(var(--background));
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-filter-select:hover {
|
||||||
|
border-color: hsl(var(--primary) / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-filter-select:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* History List */
|
||||||
|
.history-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 1rem;
|
||||||
|
background: hsl(var(--card));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-item:hover {
|
||||||
|
background: hsl(var(--hover));
|
||||||
|
border-color: hsl(var(--primary) / 0.3);
|
||||||
|
box-shadow: 0 2px 8px hsl(var(--foreground) / 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-item:hover .history-item-actions {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-item-main {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-item-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-tool-tag {
|
||||||
|
font-size: 0.625rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.1875rem 0.5rem;
|
||||||
|
border-radius: 9999px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-tool-tag.tool-gemini {
|
||||||
|
background: hsl(210 80% 55% / 0.12);
|
||||||
|
color: hsl(210 80% 45%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-tool-tag.tool-qwen {
|
||||||
|
background: hsl(280 70% 55% / 0.12);
|
||||||
|
color: hsl(280 70% 45%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-tool-tag.tool-codex {
|
||||||
|
background: hsl(142 71% 45% / 0.12);
|
||||||
|
color: hsl(142 71% 35%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-tool-tag.tool-claude {
|
||||||
|
background: hsl(25 90% 50% / 0.12);
|
||||||
|
color: hsl(25 90% 40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-mode-tag {
|
||||||
|
font-size: 0.625rem;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 0.1875rem 0.5rem;
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-source-dir {
|
||||||
|
font-size: 0.625rem;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 0.1875rem 0.5rem;
|
||||||
|
background: hsl(var(--accent));
|
||||||
|
color: hsl(var(--accent-foreground));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
max-width: 120px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
font-size: 0.625rem;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 0.1875rem 0.5rem;
|
||||||
|
border-radius: 9999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-status.success {
|
||||||
|
background: hsl(var(--success) / 0.12);
|
||||||
|
color: hsl(var(--success));
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-status.warning {
|
||||||
|
background: hsl(var(--warning) / 0.12);
|
||||||
|
color: hsl(var(--warning));
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-status.error {
|
||||||
|
background: hsl(var(--destructive) / 0.12);
|
||||||
|
color: hsl(var(--destructive));
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-item-prompt {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 450;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
max-width: 100%;
|
||||||
|
line-height: 1.5;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-item-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-item-meta span {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-item-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.15s ease;
|
||||||
|
margin-left: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* History Empty State */
|
||||||
|
.history-empty-state {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 4rem 2rem;
|
||||||
|
text-align: center;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-empty-state i {
|
||||||
|
opacity: 0.3;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-empty-state h3 {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-empty-state p {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
}
|
||||||
|
|
||||||
796
ccw/src/templates/dashboard-css/12-cli-legacy.css
Normal file
796
ccw/src/templates/dashboard-css/12-cli-legacy.css
Normal file
@@ -0,0 +1,796 @@
|
|||||||
|
/* ========================================
|
||||||
|
* Legacy Container Styles (kept for compatibility)
|
||||||
|
* ======================================== */
|
||||||
|
|
||||||
|
/* Container */
|
||||||
|
.cli-manager-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.25rem;
|
||||||
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-manager-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1.2fr 0.8fr;
|
||||||
|
gap: 1.25rem;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.cli-manager-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Panels */
|
||||||
|
.cli-panel {
|
||||||
|
background: hsl(var(--card));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 1px 3px hsl(var(--foreground) / 0.04);
|
||||||
|
transition: box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-panel:hover {
|
||||||
|
box-shadow: 0 4px 12px hsl(var(--foreground) / 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-panel-full {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Status Panel */
|
||||||
|
.cli-status-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.625rem 0.75rem;
|
||||||
|
border-bottom: 1px solid hsl(var(--border));
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-status-header h3 {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
margin: 0;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-status-header h3 i {
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tools-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 0.5rem 0.625rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-card {
|
||||||
|
padding: 0.625rem 0.5rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
background: hsl(var(--background));
|
||||||
|
text-align: center;
|
||||||
|
border: 1.5px solid hsl(var(--border));
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-card.available {
|
||||||
|
background: hsl(var(--background));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-card.available:hover {
|
||||||
|
box-shadow: 0 2px 8px hsl(var(--foreground) / 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tool-specific border colors */
|
||||||
|
.cli-tool-card.tool-gemini.available {
|
||||||
|
border-color: hsl(210 80% 55% / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-card.tool-gemini.available:hover {
|
||||||
|
border-color: hsl(210 80% 55% / 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-card.tool-qwen.available {
|
||||||
|
border-color: hsl(280 70% 55% / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-card.tool-qwen.available:hover {
|
||||||
|
border-color: hsl(280 70% 55% / 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-card.tool-codex.available {
|
||||||
|
border-color: hsl(142 71% 45% / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-card.tool-codex.available:hover {
|
||||||
|
border-color: hsl(142 71% 45% / 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-card.tool-claude.available {
|
||||||
|
border-color: hsl(25 90% 50% / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-card.tool-claude.available:hover {
|
||||||
|
border-color: hsl(25 90% 50% / 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-card.unavailable {
|
||||||
|
border-color: hsl(var(--border));
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
margin-bottom: 0.1875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-status {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-status.status-available {
|
||||||
|
background: hsl(var(--success));
|
||||||
|
box-shadow: 0 0 6px hsl(var(--success) / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-status.status-unavailable {
|
||||||
|
background: hsl(var(--muted-foreground) / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-name {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-badge {
|
||||||
|
font-size: 0.5625rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
background: hsl(var(--primary));
|
||||||
|
color: hsl(var(--primary-foreground));
|
||||||
|
border-radius: 9999px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-info {
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
margin-bottom: 0.3125rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-info .text-success {
|
||||||
|
color: hsl(var(--success));
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CLI Tool Description */
|
||||||
|
.cli-tool-desc {
|
||||||
|
font-size: 0.625rem;
|
||||||
|
color: hsl(var(--muted-foreground) / 0.8);
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CLI Tool Actions */
|
||||||
|
.cli-tool-actions {
|
||||||
|
min-height: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CodexLens specific styles */
|
||||||
|
.cli-tool-card.tool-codexlens.available {
|
||||||
|
border-color: hsl(35 90% 50% / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-card.tool-codexlens.available:hover {
|
||||||
|
border-color: hsl(35 90% 50% / 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Semantic Search specific styles */
|
||||||
|
.cli-tool-card.tool-semantic.available {
|
||||||
|
border-color: hsl(260 80% 60% / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-card.tool-semantic.available:hover {
|
||||||
|
border-color: hsl(260 80% 60% / 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-card.tool-semantic.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-card.tool-semantic.clickable:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 12px hsl(260 80% 60% / 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Execute Panel */
|
||||||
|
.cli-execute-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 1rem;
|
||||||
|
border-bottom: 1px solid hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-execute-header h3 {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-execute-form {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-execute-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 0.75rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-form-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-form-group label {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-select,
|
||||||
|
.cli-textarea {
|
||||||
|
padding: 0.5rem;
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
background: hsl(var(--background));
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-textarea {
|
||||||
|
min-height: 80px;
|
||||||
|
resize: vertical;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-select:focus,
|
||||||
|
.cli-textarea:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: hsl(var(--primary));
|
||||||
|
box-shadow: 0 0 0 2px hsl(var(--primary) / 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-execute-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* History Panel */
|
||||||
|
.cli-history-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.875rem 1rem;
|
||||||
|
border-bottom: 1px solid hsl(var(--border));
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-header h3 {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
margin: 0;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-header h3 i {
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search Input for History */
|
||||||
|
.cli-history-search {
|
||||||
|
padding: 0.375rem 0.625rem;
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
background: hsl(var(--background));
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
font-size: 0.75rem;
|
||||||
|
width: 160px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-search:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: hsl(var(--primary));
|
||||||
|
box-shadow: 0 0 0 2px hsl(var(--primary) / 0.15);
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-search::placeholder {
|
||||||
|
color: hsl(var(--muted-foreground) / 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-filter {
|
||||||
|
padding: 0.375rem 0.625rem;
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
background: hsl(var(--background));
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
font-size: 0.75rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-filter:hover {
|
||||||
|
border-color: hsl(var(--primary) / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-filter:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-list {
|
||||||
|
max-height: 450px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
border-bottom: 1px solid hsl(var(--border) / 0.5);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-item:hover {
|
||||||
|
background: hsl(var(--hover));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-item:hover .cli-history-actions {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-item-content {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-item-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-tag {
|
||||||
|
font-size: 0.5625rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.125rem 0.5rem;
|
||||||
|
border-radius: 9999px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-gemini {
|
||||||
|
background: hsl(210 80% 55% / 0.12);
|
||||||
|
color: hsl(210 80% 45%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-qwen {
|
||||||
|
background: hsl(280 70% 55% / 0.12);
|
||||||
|
color: hsl(280 70% 45%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-codex {
|
||||||
|
background: hsl(142 71% 45% / 0.12);
|
||||||
|
color: hsl(142 71% 35%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-claude {
|
||||||
|
background: hsl(25 90% 50% / 0.12);
|
||||||
|
color: hsl(25 90% 40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-time {
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-prompt {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: 450;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
max-width: 100%;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* History Item Actions */
|
||||||
|
.cli-history-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.15s ease;
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-actions .btn-icon {
|
||||||
|
padding: 0.25rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-actions .btn-icon:hover {
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
background: hsl(var(--hover));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-actions .btn-icon.btn-danger:hover {
|
||||||
|
color: hsl(var(--destructive));
|
||||||
|
background: hsl(var(--destructive) / 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output Panel */
|
||||||
|
.cli-output-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 1rem;
|
||||||
|
border-bottom: 1px solid hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-output-header h3 {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-output-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-indicator {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-indicator.running {
|
||||||
|
background: hsl(var(--warning));
|
||||||
|
animation: pulse 1.5s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-indicator.success {
|
||||||
|
background: hsl(var(--success));
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-indicator.error {
|
||||||
|
background: hsl(var(--destructive));
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0%, 100% { opacity: 1; }
|
||||||
|
50% { opacity: 0.5; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-output-content {
|
||||||
|
padding: 1rem;
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
max-height: 300px;
|
||||||
|
overflow-y: auto;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detail Modal */
|
||||||
|
.cli-detail-header {
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
border-bottom: 1px solid hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-detail-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
margin-bottom: 0.625rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-detail-status {
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.25rem 0.625rem;
|
||||||
|
border-radius: 9999px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-detail-status.status-success {
|
||||||
|
background: hsl(var(--success) / 0.12);
|
||||||
|
color: hsl(var(--success));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-detail-status.status-error {
|
||||||
|
background: hsl(var(--destructive) / 0.12);
|
||||||
|
color: hsl(var(--destructive));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-detail-status.status-timeout {
|
||||||
|
background: hsl(var(--warning) / 0.12);
|
||||||
|
color: hsl(var(--warning));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-detail-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 1.25rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-detail-meta span {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-detail-section {
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-detail-section h4 {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
margin-bottom: 0.625rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-detail-section h4 i {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-detail-prompt {
|
||||||
|
padding: 1rem;
|
||||||
|
background: hsl(var(--muted) / 0.5);
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
font-family: 'SF Mono', 'Consolas', 'Liberation Mono', monospace;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-detail-output {
|
||||||
|
padding: 1rem;
|
||||||
|
background: hsl(var(--muted) / 0.5);
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
font-family: 'SF Mono', 'Consolas', 'Liberation Mono', monospace;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
max-height: 350px;
|
||||||
|
overflow-y: auto;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-detail-error {
|
||||||
|
padding: 1rem;
|
||||||
|
background: hsl(var(--destructive) / 0.08);
|
||||||
|
border: 1px solid hsl(var(--destructive) / 0.2);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
font-family: 'SF Mono', 'Consolas', 'Liberation Mono', monospace;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: hsl(var(--destructive));
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
max-height: 180px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detail Actions */
|
||||||
|
.cli-detail-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
padding-top: 1rem;
|
||||||
|
border-top: 1px solid hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Button Styles */
|
||||||
|
.btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background: hsl(var(--primary));
|
||||||
|
color: hsl(var(--primary-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover:not(:disabled) {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon {
|
||||||
|
padding: 0.375rem;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon:hover {
|
||||||
|
background: hsl(var(--hover));
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-sm {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
padding: 0.375rem 0.625rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
background: hsl(var(--background));
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-sm:hover {
|
||||||
|
background: hsl(var(--hover));
|
||||||
|
border-color: hsl(var(--primary) / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-sm.btn-primary {
|
||||||
|
background: hsl(var(--primary));
|
||||||
|
color: hsl(var(--primary-foreground));
|
||||||
|
border-color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-sm.btn-primary:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-sm.btn-outline {
|
||||||
|
background: transparent;
|
||||||
|
border-color: hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-sm.btn-outline:hover {
|
||||||
|
background: hsl(var(--hover));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-outline {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-outline:hover {
|
||||||
|
background: hsl(var(--hover));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-outline.btn-danger {
|
||||||
|
border-color: hsl(var(--destructive) / 0.3);
|
||||||
|
color: hsl(var(--destructive));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-outline.btn-danger:hover {
|
||||||
|
background: hsl(var(--destructive) / 0.1);
|
||||||
|
border-color: hsl(var(--destructive) / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Empty State */
|
||||||
|
.empty-state {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 2rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state svg {
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state p {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
199
ccw/src/templates/dashboard-css/13-cli-ccw.css
Normal file
199
ccw/src/templates/dashboard-css/13-cli-ccw.css
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
/* ========================================
|
||||||
|
* CCW Installation Panel Styles
|
||||||
|
* ======================================== */
|
||||||
|
|
||||||
|
/* CCW Header Actions */
|
||||||
|
.ccw-header-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CCW Install Content */
|
||||||
|
.ccw-install-content {
|
||||||
|
padding: 0.5rem 0.625rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CCW Empty State */
|
||||||
|
.ccw-empty-state {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 2rem 1rem;
|
||||||
|
text-align: center;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-empty-state i {
|
||||||
|
opacity: 0.4;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-empty-state p {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================
|
||||||
|
* CCW Carousel Styles
|
||||||
|
* ======================================== */
|
||||||
|
.ccw-carousel-wrapper {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-carousel-track {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-carousel-card {
|
||||||
|
flex: 0 0 100%;
|
||||||
|
min-width: 0;
|
||||||
|
padding: 0.625rem 0.75rem;
|
||||||
|
background: hsl(var(--background));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-carousel-card.active {
|
||||||
|
border-color: hsl(var(--primary) / 0.4);
|
||||||
|
box-shadow: 0 2px 8px hsl(var(--primary) / 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Carousel Card Header */
|
||||||
|
.ccw-card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-card-header-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-card-mode {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon-sm {
|
||||||
|
padding: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-card-mode.global {
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-card-mode.path {
|
||||||
|
color: hsl(var(--warning));
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-version-tag {
|
||||||
|
font-size: 0.625rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
background: hsl(var(--primary) / 0.1);
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
border-radius: 9999px;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Carousel Card Path */
|
||||||
|
.ccw-card-path {
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
font-family: 'SF Mono', 'Consolas', 'Liberation Mono', monospace;
|
||||||
|
background: hsl(var(--muted) / 0.5);
|
||||||
|
padding: 0.3125rem 0.5rem;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
margin-bottom: 0.375rem;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Carousel Card Meta */
|
||||||
|
.ccw-card-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.75rem;
|
||||||
|
font-size: 0.625rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-card-meta span {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Carousel Card Actions - moved to header */
|
||||||
|
|
||||||
|
/* Carousel Navigation Buttons */
|
||||||
|
.ccw-carousel-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: hsl(var(--background));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 50%;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-carousel-btn:hover {
|
||||||
|
background: hsl(var(--hover));
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
border-color: hsl(var(--primary) / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-carousel-btn:disabled {
|
||||||
|
opacity: 0.3;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Carousel Dots */
|
||||||
|
.ccw-carousel-dots {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-carousel-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: hsl(var(--muted-foreground) / 0.3);
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-carousel-dot:hover {
|
||||||
|
background: hsl(var(--muted-foreground) / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-carousel-dot.active {
|
||||||
|
background: hsl(var(--primary));
|
||||||
|
width: 20px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
258
ccw/src/templates/dashboard-css/14-cli-modals.css
Normal file
258
ccw/src/templates/dashboard-css/14-cli-modals.css
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
/* ========================================
|
||||||
|
* CCW Install Modal Styles
|
||||||
|
* ======================================== */
|
||||||
|
.ccw-install-modal {
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-install-options {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-install-option {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-install-option:hover {
|
||||||
|
background: hsl(var(--hover));
|
||||||
|
border-color: hsl(var(--primary) / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-option-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-option-icon.global {
|
||||||
|
background: hsl(var(--primary) / 0.1);
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-option-icon.path {
|
||||||
|
background: hsl(var(--warning) / 0.1);
|
||||||
|
color: hsl(var(--warning));
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-option-info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-option-title {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-option-desc {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Path Input Section */
|
||||||
|
.ccw-path-input-section {
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding-top: 1rem;
|
||||||
|
border-top: 1px solid hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-path-input-group {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-path-input-group label {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-path-input-group .cli-textarea {
|
||||||
|
width: 100%;
|
||||||
|
min-height: auto;
|
||||||
|
padding: 0.625rem 0.75rem;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccw-install-action {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Danger Button (icon style - subtle) */
|
||||||
|
.btn-icon.btn-danger {
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon.btn-danger:hover {
|
||||||
|
color: hsl(var(--destructive));
|
||||||
|
background: hsl(var(--destructive) / 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================
|
||||||
|
* Generic Modal Styles
|
||||||
|
* ======================================== */
|
||||||
|
.generic-modal-overlay {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 100;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generic-modal-overlay.active {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generic-modal {
|
||||||
|
background: hsl(var(--card));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
width: 90%;
|
||||||
|
max-width: 600px;
|
||||||
|
max-height: 85vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-shadow: 0 8px 32px rgb(0 0 0 / 0.25);
|
||||||
|
transform: scale(0.95);
|
||||||
|
transition: transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generic-modal-overlay.active .generic-modal {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.generic-modal.large {
|
||||||
|
max-width: 800px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generic-modal-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 1rem 1.25rem;
|
||||||
|
border-bottom: 1px solid hsl(var(--border));
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
border-radius: 0.75rem 0.75rem 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generic-modal-title {
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generic-modal-close {
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generic-modal-close:hover {
|
||||||
|
background: hsl(var(--hover));
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.generic-modal-body {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generic-modal.lg {
|
||||||
|
max-width: 640px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================
|
||||||
|
* Modal Aliases (for backward compatibility)
|
||||||
|
* ======================================== */
|
||||||
|
.modal-backdrop {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 9999;
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-container {
|
||||||
|
background: hsl(var(--card));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
width: 90%;
|
||||||
|
max-width: 600px;
|
||||||
|
max-height: 85vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-shadow: 0 8px 32px rgb(0 0 0 / 0.25);
|
||||||
|
transform: scale(1);
|
||||||
|
transition: transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-container.large {
|
||||||
|
max-width: 800px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 1rem 1.25rem;
|
||||||
|
border-bottom: 1px solid hsl(var(--border));
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
border-radius: 0.75rem 0.75rem 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 2.5rem;
|
||||||
|
height: 2.5rem;
|
||||||
|
background: hsl(var(--primary-light));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
305
ccw/src/templates/dashboard-css/15-cli-endpoints.css
Normal file
305
ccw/src/templates/dashboard-css/15-cli-endpoints.css
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
/* ========================================
|
||||||
|
* Endpoint Tools Grid Styles
|
||||||
|
* ======================================== */
|
||||||
|
.endpoint-tools-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
||||||
|
gap: 0.75rem;
|
||||||
|
padding: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-tool-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 0.875rem;
|
||||||
|
background: hsl(var(--card));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
min-height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-tool-card:hover {
|
||||||
|
background: hsl(var(--hover));
|
||||||
|
border-color: hsl(var(--indigo) / 0.5);
|
||||||
|
box-shadow: 0 2px 8px hsl(var(--indigo) / 0.1);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-tool-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-tool-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: hsl(var(--indigo));
|
||||||
|
box-shadow: 0 0 6px hsl(var(--indigo) / 0.5);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-tool-name {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
font-family: 'SF Mono', 'Consolas', 'Liberation Mono', monospace;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-tool-desc {
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
line-height: 1.4;
|
||||||
|
flex: 1;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-tool-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-tool-params {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
font-size: 0.625rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
background: hsl(var(--muted) / 0.5);
|
||||||
|
padding: 0.1875rem 0.375rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-tool-required {
|
||||||
|
font-size: 0.5625rem;
|
||||||
|
color: hsl(var(--warning));
|
||||||
|
background: hsl(var(--warning) / 0.1);
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
border-radius: 9999px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================
|
||||||
|
* Tool Detail Modal Styles
|
||||||
|
* ======================================== */
|
||||||
|
.tool-detail-modal {
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-detail-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
border-bottom: 1px solid hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-detail-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
|
background: hsl(var(--indigo) / 0.1);
|
||||||
|
color: hsl(var(--indigo));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-detail-title h3 {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
margin: 0 0 0.375rem 0;
|
||||||
|
font-family: 'SF Mono', 'Consolas', 'Liberation Mono', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-detail-badge {
|
||||||
|
font-size: 0.625rem;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 0.1875rem 0.5rem;
|
||||||
|
background: hsl(var(--indigo) / 0.1);
|
||||||
|
color: hsl(var(--indigo));
|
||||||
|
border-radius: 9999px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-detail-desc {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-detail-params h4,
|
||||||
|
.tool-detail-usage h4 {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
margin: 0 0 0.75rem 0;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-detail-params h4 i,
|
||||||
|
.tool-detail-usage h4 i {
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-params-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.75rem;
|
||||||
|
max-height: 280px;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-param-item {
|
||||||
|
padding: 0.75rem;
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-param-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 0.375rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-param-name {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-param-type {
|
||||||
|
font-size: 0.625rem;
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
background: hsl(var(--primary) / 0.1);
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
font-family: 'SF Mono', 'Consolas', 'Liberation Mono', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-param-required {
|
||||||
|
font-size: 0.5625rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--destructive));
|
||||||
|
background: hsl(var(--destructive) / 0.1);
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
border-radius: 9999px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-param-optional {
|
||||||
|
font-size: 0.5625rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
border-radius: 9999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-param-desc {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-param-default,
|
||||||
|
.tool-param-enum {
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-param-default code,
|
||||||
|
.tool-param-enum code {
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-detail-no-params {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 1.5rem;
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
border: 1px dashed hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-detail-usage {
|
||||||
|
margin-top: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-usage-code {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 0.75rem;
|
||||||
|
background: hsl(var(--muted) / 0.5);
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-usage-code code {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-family: 'SF Mono', 'Consolas', 'Liberation Mono', monospace;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
white-space: nowrap;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-copy-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.375rem;
|
||||||
|
background: hsl(var(--background));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-copy-btn:hover {
|
||||||
|
background: hsl(var(--hover));
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
border-color: hsl(var(--primary) / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
241
ccw/src/templates/dashboard-css/16-cli-session.css
Normal file
241
ccw/src/templates/dashboard-css/16-cli-session.css
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
/* ========================================
|
||||||
|
* Resume Session Styles
|
||||||
|
* ======================================== */
|
||||||
|
|
||||||
|
/* Resume Badge */
|
||||||
|
.history-resume-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.1875rem 0.375rem;
|
||||||
|
background: hsl(var(--primary) / 0.12);
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
font-size: 0.625rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resume Item Highlight */
|
||||||
|
.history-item-resume {
|
||||||
|
border-left: 3px solid hsl(var(--primary) / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-item-resume:hover {
|
||||||
|
border-left-color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* History ID Display */
|
||||||
|
.history-id {
|
||||||
|
font-family: 'SF Mono', 'Consolas', 'Liberation Mono', monospace;
|
||||||
|
font-size: 0.625rem;
|
||||||
|
color: hsl(var(--muted-foreground) / 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resume Button */
|
||||||
|
.btn-resume {
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-resume:hover {
|
||||||
|
background: hsl(var(--primary) / 0.1);
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resume Modal */
|
||||||
|
.resume-modal p {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resume-prompt-input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.75rem;
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
background: hsl(var(--background));
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-family: inherit;
|
||||||
|
resize: vertical;
|
||||||
|
min-height: 80px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resume-prompt-input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: hsl(var(--primary));
|
||||||
|
box-shadow: 0 0 0 2px hsl(var(--primary) / 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resume-prompt-input::placeholder {
|
||||||
|
color: hsl(var(--muted-foreground) / 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resume-modal-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding-top: 1rem;
|
||||||
|
border-top: 1px solid hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================
|
||||||
|
* Batch Delete & Multi-Select Styles
|
||||||
|
* ======================================== */
|
||||||
|
|
||||||
|
/* Delete Dropdown */
|
||||||
|
.history-delete-dropdown {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-dropdown-menu {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
right: 0;
|
||||||
|
z-index: 50;
|
||||||
|
min-width: 180px;
|
||||||
|
padding: 0.375rem;
|
||||||
|
background: hsl(var(--card));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
box-shadow: 0 4px 16px hsl(var(--foreground) / 0.1);
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-dropdown-menu.show {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-dropdown-menu button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5rem 0.625rem;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
font-size: 0.75rem;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-dropdown-menu button:hover {
|
||||||
|
background: hsl(var(--hover));
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-dropdown-menu button i {
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-dropdown-menu .delete-all-btn {
|
||||||
|
color: hsl(var(--destructive));
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-dropdown-menu .delete-all-btn i {
|
||||||
|
color: hsl(var(--destructive));
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-dropdown-menu .delete-all-btn:hover {
|
||||||
|
background: hsl(var(--destructive) / 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-divider {
|
||||||
|
height: 1px;
|
||||||
|
margin: 0.375rem 0;
|
||||||
|
background: hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Batch Actions Bar */
|
||||||
|
.history-batch-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.625rem;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
background: hsl(var(--primary) / 0.08);
|
||||||
|
border: 1px solid hsl(var(--primary) / 0.2);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-select-count {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger {
|
||||||
|
background: hsl(var(--destructive));
|
||||||
|
color: hsl(var(--destructive-foreground));
|
||||||
|
border-color: hsl(var(--destructive));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger:hover:not(:disabled) {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Override for icon-style danger buttons (subtle, not solid red) */
|
||||||
|
.btn-icon.btn-danger,
|
||||||
|
.history-item-actions .btn-danger,
|
||||||
|
.cli-history-actions .btn-danger {
|
||||||
|
background: transparent;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon.btn-danger:hover,
|
||||||
|
.history-item-actions .btn-danger:hover,
|
||||||
|
.cli-history-actions .btn-danger:hover {
|
||||||
|
background: hsl(var(--destructive) / 0.1);
|
||||||
|
color: hsl(var(--destructive));
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Multi-Select Checkbox */
|
||||||
|
.history-checkbox-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
margin-right: 0.75rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-checkbox {
|
||||||
|
width: 1.125rem;
|
||||||
|
height: 1.125rem;
|
||||||
|
cursor: pointer;
|
||||||
|
accent-color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Selected Item State */
|
||||||
|
.history-item-selected {
|
||||||
|
background: hsl(var(--primary) / 0.08) !important;
|
||||||
|
border-color: hsl(var(--primary) / 0.3) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turn Badge for History List */
|
||||||
|
.history-turn-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
font-size: 0.625rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.1875rem 0.5rem;
|
||||||
|
background: hsl(var(--primary) / 0.12);
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
border-radius: 9999px;
|
||||||
|
}
|
||||||
|
|
||||||
283
ccw/src/templates/dashboard-css/17-cli-conversation.css
Normal file
283
ccw/src/templates/dashboard-css/17-cli-conversation.css
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
/* ========================================
|
||||||
|
* Multi-Turn Conversation Styles
|
||||||
|
* ======================================== */
|
||||||
|
|
||||||
|
/* Turn Badge in History List */
|
||||||
|
.cli-turn-badge {
|
||||||
|
font-size: 0.5625rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.125rem 0.5rem;
|
||||||
|
background: hsl(var(--primary) / 0.12);
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
border-radius: 9999px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turns Container in Detail Modal */
|
||||||
|
.cli-turns-container {
|
||||||
|
max-height: 60vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turn Section */
|
||||||
|
.cli-turn-section {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-turn-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-turn-number {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.25rem 0.625rem;
|
||||||
|
background: hsl(var(--primary) / 0.1);
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
border-radius: 9999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-turn-status {
|
||||||
|
font-size: 0.625rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.1875rem 0.5rem;
|
||||||
|
border-radius: 9999px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-turn-status.status-success {
|
||||||
|
background: hsl(var(--success) / 0.12);
|
||||||
|
color: hsl(var(--success));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-turn-status.status-error {
|
||||||
|
background: hsl(var(--destructive) / 0.12);
|
||||||
|
color: hsl(var(--destructive));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-turn-status.status-timeout {
|
||||||
|
background: hsl(var(--warning) / 0.12);
|
||||||
|
color: hsl(var(--warning));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-turn-duration {
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turn Divider (legacy) */
|
||||||
|
.cli-turn-divider {
|
||||||
|
border: none;
|
||||||
|
border-top: 1px dashed hsl(var(--border));
|
||||||
|
margin: 1.25rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Error Section (smaller in multi-turn) */
|
||||||
|
.cli-detail-error-section .cli-detail-error {
|
||||||
|
max-height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================
|
||||||
|
* Enhanced Multi-Turn Display
|
||||||
|
* ======================================== */
|
||||||
|
|
||||||
|
/* Turn Section */
|
||||||
|
.cli-turn-section {
|
||||||
|
padding: 0.75rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
background: hsl(var(--background));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-turn-section.cli-turn-latest {
|
||||||
|
border-color: hsl(var(--primary) / 0.3);
|
||||||
|
background: hsl(var(--primary) / 0.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turn Header */
|
||||||
|
.cli-turn-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
border-bottom: 1px solid hsl(var(--border));
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-turn-marker {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-turn-number {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-turn-latest-badge {
|
||||||
|
font-size: 0.5625rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
background: hsl(var(--success) / 0.12);
|
||||||
|
color: hsl(var(--success));
|
||||||
|
border-radius: 9999px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-turn-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-turn-meta span {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-turn-time i,
|
||||||
|
.cli-turn-duration i {
|
||||||
|
color: hsl(var(--muted-foreground) / 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turn Body */
|
||||||
|
.cli-turn-body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Section Labels */
|
||||||
|
.cli-prompt-section h4 {
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-prompt-section h4 i {
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-output-section h4 {
|
||||||
|
color: hsl(var(--success));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-output-section h4 i {
|
||||||
|
color: hsl(var(--success));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turn Connector (visual line between turns) */
|
||||||
|
.cli-turn-connector {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.25rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-turn-line {
|
||||||
|
width: 2px;
|
||||||
|
height: 1.5rem;
|
||||||
|
background: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
hsl(var(--border)),
|
||||||
|
hsl(var(--primary) / 0.3),
|
||||||
|
hsl(var(--border))
|
||||||
|
);
|
||||||
|
border-radius: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Truncated Notice */
|
||||||
|
.cli-truncated-notice {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: hsl(var(--warning));
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
padding: 0.375rem 0.625rem;
|
||||||
|
background: hsl(var(--warning) / 0.08);
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-truncated-notice i {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turn Badge with Icon */
|
||||||
|
.cli-turn-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-turn-badge i {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================
|
||||||
|
* Conversation View Toggle
|
||||||
|
* ======================================== */
|
||||||
|
|
||||||
|
/* View Toggle Bar */
|
||||||
|
.cli-view-toggle {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-view-toggle .btn {
|
||||||
|
flex: 1;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-view-toggle .btn.active {
|
||||||
|
background: hsl(var(--primary));
|
||||||
|
color: hsl(var(--primary-foreground));
|
||||||
|
border-color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Concatenated Prompt Section */
|
||||||
|
.cli-concat-section {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-concat-format-selector {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.375rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-concat-format-selector .btn-xs {
|
||||||
|
padding: 0.25rem 0.625rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-concat-output {
|
||||||
|
max-height: 400px;
|
||||||
|
overflow-y: auto;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Button Sizes */
|
||||||
|
.btn-xs {
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
160
ccw/src/templates/dashboard-css/18-cli-settings.css
Normal file
160
ccw/src/templates/dashboard-css/18-cli-settings.css
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
/* ========================================
|
||||||
|
* CLI Settings Section
|
||||||
|
* ======================================== */
|
||||||
|
|
||||||
|
.cli-settings-section {
|
||||||
|
/* No card wrapper - just title and cards */
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-settings-section .section-header {
|
||||||
|
padding: 0 0 0.75rem 0;
|
||||||
|
border-bottom: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-settings-section .section-header h3 {
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-settings-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.cli-settings-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.cli-settings-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-setting-item {
|
||||||
|
padding: 0.75rem;
|
||||||
|
background: hsl(var(--card));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-setting-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.025em;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-setting-label i {
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-setting-control {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-setting-select {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.4375rem 0.5rem;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
background: hsl(var(--background));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-setting-select:hover {
|
||||||
|
border-color: hsl(var(--primary) / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-setting-select:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: hsl(var(--primary));
|
||||||
|
box-shadow: 0 0 0 2px hsl(var(--primary) / 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-setting-desc {
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
line-height: 1.3;
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-setting-value {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Toggle Switch */
|
||||||
|
.cli-toggle {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 36px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-toggle input {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-toggle-slider {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: hsl(var(--muted));
|
||||||
|
transition: 0.3s;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-toggle-slider:before {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
height: 14px;
|
||||||
|
width: 14px;
|
||||||
|
left: 3px;
|
||||||
|
bottom: 3px;
|
||||||
|
background-color: white;
|
||||||
|
transition: 0.3s;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-toggle input:checked + .cli-toggle-slider {
|
||||||
|
background-color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-toggle input:checked + .cli-toggle-slider:before {
|
||||||
|
transform: translateX(16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-toggle input:focus + .cli-toggle-slider {
|
||||||
|
box-shadow: 0 0 0 2px hsl(var(--primary) / 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disabled state for settings */
|
||||||
|
.cli-setting-item.disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
496
ccw/src/templates/dashboard-css/19-cli-native-session.css
Normal file
496
ccw/src/templates/dashboard-css/19-cli-native-session.css
Normal file
@@ -0,0 +1,496 @@
|
|||||||
|
/* ========================================
|
||||||
|
* Native Session Styles
|
||||||
|
* ======================================== */
|
||||||
|
|
||||||
|
/* Native badge in history list */
|
||||||
|
.cli-native-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
background: hsl(var(--primary) / 0.1);
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
font-size: 0.625rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-history-item.has-native {
|
||||||
|
border-left: 2px solid hsl(var(--primary) / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mode tag */
|
||||||
|
.cli-mode-tag {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
font-size: 0.625rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Status badge */
|
||||||
|
.cli-status-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
font-size: 0.625rem;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-status-badge.text-success {
|
||||||
|
background: hsl(var(--success) / 0.1);
|
||||||
|
color: hsl(var(--success));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-status-badge.text-warning {
|
||||||
|
background: hsl(var(--warning) / 0.1);
|
||||||
|
color: hsl(var(--warning));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-status-badge.text-destructive {
|
||||||
|
background: hsl(var(--destructive) / 0.1);
|
||||||
|
color: hsl(var(--destructive));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Native Session Detail Modal */
|
||||||
|
.native-session-detail {
|
||||||
|
font-family: system-ui, -apple-system, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-session-header {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
border-bottom: 1px solid hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-session-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-model,
|
||||||
|
.native-session-id {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-session-meta {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-session-meta span {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tokens Summary */
|
||||||
|
.native-tokens-summary {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
background: hsl(var(--muted) / 0.5);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Native Turns Container */
|
||||||
|
.native-turns-container {
|
||||||
|
max-height: 60vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Native Turn */
|
||||||
|
.native-turn {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding: 0.875rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-turn.user {
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
border-left: 3px solid hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-turn.assistant {
|
||||||
|
background: hsl(var(--background));
|
||||||
|
border-left: 3px solid hsl(var(--success));
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-turn.latest {
|
||||||
|
box-shadow: 0 0 0 1px hsl(var(--primary) / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-turn-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
margin-bottom: 0.625rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-turn-role {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-turn-number {
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-turn-tokens {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
font-size: 0.625rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-turn-latest {
|
||||||
|
font-size: 0.625rem;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
background: hsl(var(--primary) / 0.1);
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-turn-content pre {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.75rem;
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Thoughts Section */
|
||||||
|
.native-thoughts-section {
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
padding: 0.625rem;
|
||||||
|
background: hsl(var(--warning) / 0.05);
|
||||||
|
border: 1px solid hsl(var(--warning) / 0.2);
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-thoughts-section h5 {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--warning));
|
||||||
|
margin: 0 0 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-thoughts-list {
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 1.25rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-thoughts-list li {
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tool Calls Section */
|
||||||
|
.native-tools-section {
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
padding: 0.625rem;
|
||||||
|
background: hsl(var(--muted) / 0.5);
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-tools-section h5 {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
margin: 0 0 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-tools-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-tool-call {
|
||||||
|
padding: 0.5rem;
|
||||||
|
background: hsl(var(--background));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-tool-name {
|
||||||
|
display: inline-block;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-tool-output {
|
||||||
|
margin: 0.25rem 0 0 0;
|
||||||
|
padding: 0.375rem;
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 0.625rem;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
max-height: 100px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Native Session Actions */
|
||||||
|
.native-session-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding-top: 1rem;
|
||||||
|
border-top: 1px solid hsl(var(--border));
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================
|
||||||
|
* Enhanced Native Session Display
|
||||||
|
* ======================================== */
|
||||||
|
|
||||||
|
/* View Full Process Button in Execution Detail */
|
||||||
|
.cli-detail-native-action {
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
padding-top: 0.75rem;
|
||||||
|
border-top: 1px solid hsl(var(--border) / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-detail-native-action .btn {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Collapsible Thinking Process */
|
||||||
|
.turn-thinking-details {
|
||||||
|
border: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-thinking-summary {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0.5rem;
|
||||||
|
background: hsl(var(--warning) / 0.08);
|
||||||
|
border: 1px solid hsl(var(--warning) / 0.25);
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--warning));
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-thinking-summary::-webkit-details-marker {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-thinking-summary:hover {
|
||||||
|
background: hsl(var(--warning) / 0.15);
|
||||||
|
border-color: hsl(var(--warning) / 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-thinking-summary::before {
|
||||||
|
content: '▶';
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
transition: transform 0.2s ease;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-thinking-details[open] .turn-thinking-summary::before {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-thinking-content {
|
||||||
|
padding: 0.75rem;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
background: hsl(var(--warning) / 0.03);
|
||||||
|
border: 1px solid hsl(var(--warning) / 0.15);
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-thinking-content ul {
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-thinking-content li {
|
||||||
|
margin-bottom: 0.375rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: hsl(var(--foreground) / 0.85);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tool Calls Header */
|
||||||
|
.turn-tool-calls-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
margin-bottom: 0.625rem;
|
||||||
|
padding-bottom: 0.375rem;
|
||||||
|
border-bottom: 1px solid hsl(var(--border) / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Collapsible Tool Calls */
|
||||||
|
.turn-tool-call-details {
|
||||||
|
border: none;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-tool-call-summary {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
background: hsl(var(--background));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-tool-call-summary::-webkit-details-marker {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-tool-call-summary:hover {
|
||||||
|
background: hsl(var(--muted) / 0.5);
|
||||||
|
border-color: hsl(var(--primary) / 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-tool-call-summary::before {
|
||||||
|
content: '▶';
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
transition: transform 0.2s ease;
|
||||||
|
font-size: 0.625rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-tool-call-details[open] .turn-tool-call-summary::before {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-tool-size {
|
||||||
|
font-size: 0.625rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-tool-call-content {
|
||||||
|
padding: 0.75rem;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-tool-input,
|
||||||
|
.turn-tool-output {
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-tool-input:last-child,
|
||||||
|
.turn-tool-output:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-tool-input strong,
|
||||||
|
.turn-tool-output strong {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
margin-bottom: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-tool-input pre,
|
||||||
|
.turn-tool-output pre {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.5rem;
|
||||||
|
background: hsl(var(--background));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
max-height: 400px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Improved scrollbar for tool output */
|
||||||
|
.turn-tool-output pre::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-tool-output pre::-webkit-scrollbar-track {
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-tool-output pre::-webkit-scrollbar-thumb {
|
||||||
|
background: hsl(var(--muted-foreground) / 0.3);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-tool-output pre::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: hsl(var(--muted-foreground) / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
188
ccw/src/templates/dashboard-css/20-cli-taskqueue.css
Normal file
188
ccw/src/templates/dashboard-css/20-cli-taskqueue.css
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
/* ========================================
|
||||||
|
* Task Queue Sidebar - CLI Tab Styles
|
||||||
|
* ======================================== */
|
||||||
|
|
||||||
|
/* Tab Navigation */
|
||||||
|
.task-queue-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 0;
|
||||||
|
border-bottom: 1px solid hsl(var(--border));
|
||||||
|
padding: 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-queue-tab {
|
||||||
|
flex: 1;
|
||||||
|
padding: 0.625rem 0.75rem;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-queue-tab:hover {
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-queue-tab.active {
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
border-bottom-color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-queue-tab .tab-badge {
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
border-radius: 9999px;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
min-width: 1.25rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-queue-tab.active .tab-badge {
|
||||||
|
background: hsl(var(--primary) / 0.15);
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CLI Filter Buttons */
|
||||||
|
.cli-filter-btn {
|
||||||
|
padding: 0.375rem 0.625rem;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
font-size: 0.75rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-filter-btn:hover {
|
||||||
|
background: hsl(var(--muted) / 0.5);
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-filter-btn.active {
|
||||||
|
background: hsl(var(--primary));
|
||||||
|
border-color: hsl(var(--primary));
|
||||||
|
color: hsl(var(--primary-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CLI Queue Item */
|
||||||
|
.cli-queue-item {
|
||||||
|
padding: 0.75rem;
|
||||||
|
background: hsl(var(--card));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-item:hover {
|
||||||
|
background: hsl(var(--muted) / 0.5);
|
||||||
|
border-color: hsl(var(--primary) / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-item.category-user {
|
||||||
|
border-left: 3px solid #3b82f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-item.category-insight {
|
||||||
|
border-left: 3px solid #a855f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-item.category-internal {
|
||||||
|
border-left: 3px solid #22c55e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-item-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-category-icon {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-tool-tag {
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
font-size: 0.625rem;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-tool-tag.cli-tool-gemini {
|
||||||
|
background: hsl(210 100% 50% / 0.15);
|
||||||
|
color: hsl(210 100% 45%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-tool-tag.cli-tool-qwen {
|
||||||
|
background: hsl(280 100% 50% / 0.15);
|
||||||
|
color: hsl(280 100% 40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-tool-tag.cli-tool-codex {
|
||||||
|
background: hsl(145 60% 45% / 0.15);
|
||||||
|
color: hsl(145 60% 35%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-tool-tag.cli-tool-claude {
|
||||||
|
background: hsl(25 90% 50% / 0.15);
|
||||||
|
color: hsl(25 90% 40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-status {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-time {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-prompt {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
line-height: 1.4;
|
||||||
|
margin-bottom: 0.375rem;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-id {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-turns {
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
padding: 0.0625rem 0.25rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-queue-native {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
310
ccw/src/templates/dashboard-css/21-cli-toolmgmt.css
Normal file
310
ccw/src/templates/dashboard-css/21-cli-toolmgmt.css
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
/* ========================================
|
||||||
|
* CLI Tool Management Styles
|
||||||
|
* ======================================== */
|
||||||
|
|
||||||
|
/* Disabled tool card */
|
||||||
|
.cli-tool-card.disabled {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-tool-card.disabled .cli-tool-header {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disabled status indicator */
|
||||||
|
.cli-tool-status.status-disabled {
|
||||||
|
background: hsl(var(--warning));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Warning badge */
|
||||||
|
.cli-tool-badge.badge-warning {
|
||||||
|
background: hsl(var(--warning) / 0.15);
|
||||||
|
color: hsl(var(--warning));
|
||||||
|
font-size: 0.65rem;
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
margin-left: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compact toggle for tool cards */
|
||||||
|
.cli-toggle-compact {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 28px;
|
||||||
|
height: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-toggle-compact input {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-toggle-slider-compact {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: hsl(var(--muted));
|
||||||
|
transition: 0.2s;
|
||||||
|
border-radius: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-toggle-slider-compact:before {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
height: 12px;
|
||||||
|
width: 12px;
|
||||||
|
left: 2px;
|
||||||
|
bottom: 2px;
|
||||||
|
background-color: white;
|
||||||
|
transition: 0.2s;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-toggle-compact input:checked + .cli-toggle-slider-compact {
|
||||||
|
background-color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-toggle-compact input:checked + .cli-toggle-slider-compact:before {
|
||||||
|
transform: translateX(12px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-toggle-compact input:focus + .cli-toggle-slider-compact {
|
||||||
|
box-shadow: 0 0 0 2px hsl(var(--ring) / 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Language Setting Status Badge */
|
||||||
|
.cli-setting-status {
|
||||||
|
margin-left: 0.75rem;
|
||||||
|
padding: 0.25rem 0.625rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-setting-status.enabled {
|
||||||
|
background: hsl(var(--primary) / 0.15);
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cli-setting-status.disabled {
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ghost button variant for destructive actions */
|
||||||
|
.btn-ghost.text-destructive {
|
||||||
|
color: hsl(var(--destructive));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================
|
||||||
|
* Tool Configuration Modal
|
||||||
|
* ======================================== */
|
||||||
|
|
||||||
|
/* Tool item clickable */
|
||||||
|
.tool-item.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item.clickable:hover {
|
||||||
|
background: hsl(var(--accent));
|
||||||
|
border-color: hsl(var(--primary) / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item.clickable:hover .tool-config-icon {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-config-icon {
|
||||||
|
margin-left: 0.375rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tool Config Modal */
|
||||||
|
.tool-config-modal {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-config-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-config-section h4 {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.025em;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-config-section h4 .text-muted {
|
||||||
|
font-weight: 400;
|
||||||
|
text-transform: none;
|
||||||
|
color: hsl(var(--muted-foreground) / 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Status Badges */
|
||||||
|
.tool-config-badges {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 9999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-success {
|
||||||
|
background: hsl(var(--success) / 0.15);
|
||||||
|
color: hsl(var(--success));
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-primary {
|
||||||
|
background: hsl(var(--primary) / 0.15);
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-muted {
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Config Actions */
|
||||||
|
.tool-config-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger-outline {
|
||||||
|
border-color: hsl(var(--destructive) / 0.5);
|
||||||
|
color: hsl(var(--destructive));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger-outline:hover {
|
||||||
|
background: hsl(var(--destructive) / 0.1);
|
||||||
|
border-color: hsl(var(--destructive));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Config Selects and Inputs */
|
||||||
|
.tool-config-select,
|
||||||
|
.tool-config-input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-family: inherit;
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
background: hsl(var(--background));
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-config-select:focus,
|
||||||
|
.tool-config-input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: hsl(var(--primary));
|
||||||
|
box-shadow: 0 0 0 2px hsl(var(--primary) / 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-config-select {
|
||||||
|
cursor: pointer;
|
||||||
|
appearance: none;
|
||||||
|
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
|
||||||
|
background-position: right 0.5rem center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 1.25rem;
|
||||||
|
padding-right: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-config-input.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-config-input {
|
||||||
|
margin-top: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Config Footer */
|
||||||
|
.tool-config-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 0.75rem;
|
||||||
|
padding: 1rem 1.25rem 1.25rem 1.25rem;
|
||||||
|
border-top: 1px solid hsl(var(--border));
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-config-footer .btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-config-footer .btn-outline {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-config-footer .btn-outline:hover {
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
border-color: hsl(var(--muted-foreground) / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-config-footer .btn-primary {
|
||||||
|
background: hsl(var(--primary));
|
||||||
|
border: 1px solid hsl(var(--primary));
|
||||||
|
color: hsl(var(--primary-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-config-footer .btn-primary:hover {
|
||||||
|
background: hsl(var(--primary) / 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Model Select Group */
|
||||||
|
.model-select-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-select-group .tool-config-input {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-ghost.text-destructive:hover {
|
||||||
|
background: hsl(var(--destructive) / 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
240
ccw/src/templates/dashboard-css/22-cli-semantic.css
Normal file
240
ccw/src/templates/dashboard-css/22-cli-semantic.css
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
/* ========================================
|
||||||
|
* Semantic Metadata Viewer Styles
|
||||||
|
* ======================================== */
|
||||||
|
.semantic-viewer-toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
border-bottom: 1px solid hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-table-container {
|
||||||
|
max-height: 400px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-table th {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
background: hsl(var(--card));
|
||||||
|
padding: 0.625rem 0.75rem;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
border-bottom: 1px solid hsl(var(--border));
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-table td {
|
||||||
|
padding: 0.625rem 0.75rem;
|
||||||
|
border-bottom: 1px solid hsl(var(--border) / 0.5);
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-row {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-row:hover {
|
||||||
|
background: hsl(var(--hover));
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-cell-file {
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-cell-lang {
|
||||||
|
width: 80px;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-cell-purpose {
|
||||||
|
max-width: 180px;
|
||||||
|
color: hsl(var(--foreground) / 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-cell-keywords {
|
||||||
|
max-width: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-cell-tool {
|
||||||
|
width: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-cell-date {
|
||||||
|
width: 80px;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-keyword {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
margin: 0.125rem;
|
||||||
|
background: hsl(var(--primary) / 0.1);
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-keyword-more {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
margin: 0.125rem;
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.125rem 0.5rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-badge.tool-gemini {
|
||||||
|
background: hsl(210 80% 55% / 0.15);
|
||||||
|
color: hsl(210 80% 45%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-badge.tool-qwen {
|
||||||
|
background: hsl(142 76% 36% / 0.15);
|
||||||
|
color: hsl(142 76% 36%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-badge.tool-unknown {
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-detail-row {
|
||||||
|
background: hsl(var(--muted) / 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-detail-row.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-detail-content {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-detail-section {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-detail-section h4 {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-detail-section p {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-keywords-full {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-detail-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 1rem;
|
||||||
|
padding-top: 0.75rem;
|
||||||
|
border-top: 1px solid hsl(var(--border) / 0.5);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-detail-meta span {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-viewer-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
border-top: 1px solid hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-loading,
|
||||||
|
.semantic-empty {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 3rem;
|
||||||
|
text-align: center;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.semantic-loading {
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================
|
||||||
|
* CodexLens Test Search Results
|
||||||
|
* ======================================== */
|
||||||
|
#searchResults {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#searchResults > div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-height: 200px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
padding: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#searchResults .flex.items-center {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#searchResultContent {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
|
||||||
|
line-height: 1.5;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-all;
|
||||||
|
color: hsl(var(--foreground) / 0.9);
|
||||||
|
background: hsl(var(--background) / 0.5);
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
@@ -130,14 +130,14 @@
|
|||||||
|
|
||||||
.stat-label {
|
.stat-label {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
color: var(--text-secondary);
|
color: hsl(var(--muted-foreground));
|
||||||
margin-bottom: 0.25rem;
|
margin-bottom: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-value {
|
.stat-value {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-primary);
|
color: hsl(var(--foreground));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Memories Grid */
|
/* Memories Grid */
|
||||||
@@ -155,8 +155,8 @@
|
|||||||
|
|
||||||
/* Memory Card */
|
/* Memory Card */
|
||||||
.memory-card {
|
.memory-card {
|
||||||
background: var(--card-bg);
|
background: hsl(var(--card));
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid hsl(var(--border));
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 1.25rem;
|
padding: 1.25rem;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
@@ -184,7 +184,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
color: var(--text-secondary);
|
color: hsl(var(--muted-foreground));
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +203,7 @@
|
|||||||
border: none;
|
border: none;
|
||||||
padding: 0.25rem;
|
padding: 0.25rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: var(--text-secondary);
|
color: hsl(var(--muted-foreground));
|
||||||
transition: color 0.2s;
|
transition: color 0.2s;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -211,11 +211,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.icon-btn:hover {
|
.icon-btn:hover {
|
||||||
color: var(--text-primary);
|
color: hsl(var(--foreground));
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-btn.danger:hover {
|
.icon-btn.danger:hover {
|
||||||
color: var(--danger-color);
|
color: hsl(var(--destructive));
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-btn i {
|
.icon-btn i {
|
||||||
@@ -231,13 +231,13 @@
|
|||||||
.memory-summary {
|
.memory-summary {
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
color: var(--text-primary);
|
color: hsl(var(--foreground));
|
||||||
}
|
}
|
||||||
|
|
||||||
.memory-preview {
|
.memory-preview {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
color: var(--text-secondary);
|
color: hsl(var(--muted-foreground));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Memory Tags */
|
/* Memory Tags */
|
||||||
@@ -250,8 +250,8 @@
|
|||||||
|
|
||||||
.tag {
|
.tag {
|
||||||
padding: 0.25rem 0.75rem;
|
padding: 0.25rem 0.75rem;
|
||||||
background: var(--accent-bg);
|
background: hsl(var(--accent));
|
||||||
color: var(--accent-color);
|
color: hsl(var(--primary));
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -263,14 +263,14 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
padding-top: 1rem;
|
padding-top: 1rem;
|
||||||
border-top: 1px solid var(--border-color);
|
border-top: 1px solid hsl(var(--border));
|
||||||
}
|
}
|
||||||
|
|
||||||
.memory-meta {
|
.memory-meta {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
color: var(--text-secondary);
|
color: hsl(var(--muted-foreground));
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,8 +293,8 @@
|
|||||||
|
|
||||||
.feature-btn {
|
.feature-btn {
|
||||||
padding: 0.375rem 0.75rem;
|
padding: 0.375rem 0.75rem;
|
||||||
background: var(--secondary-bg);
|
background: hsl(var(--muted));
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid hsl(var(--border));
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -302,12 +302,12 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.375rem;
|
gap: 0.375rem;
|
||||||
color: var(--text-primary);
|
color: hsl(var(--foreground));
|
||||||
}
|
}
|
||||||
|
|
||||||
.feature-btn:hover {
|
.feature-btn:hover {
|
||||||
background: var(--hover-bg);
|
background: hsl(var(--hover));
|
||||||
border-color: var(--accent-color);
|
border-color: hsl(var(--primary));
|
||||||
}
|
}
|
||||||
|
|
||||||
.feature-btn i {
|
.feature-btn i {
|
||||||
@@ -362,17 +362,17 @@
|
|||||||
display: block;
|
display: block;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
color: var(--text-primary);
|
color: hsl(var(--foreground));
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group textarea,
|
.form-group textarea,
|
||||||
.form-group input[type="text"] {
|
.form-group input[type="text"] {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid hsl(var(--border));
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background: var(--input-bg);
|
background: hsl(var(--background));
|
||||||
color: var(--text-primary);
|
color: hsl(var(--foreground));
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
resize: vertical;
|
resize: vertical;
|
||||||
@@ -381,8 +381,8 @@
|
|||||||
.form-group textarea:focus,
|
.form-group textarea:focus,
|
||||||
.form-group input[type="text"]:focus {
|
.form-group input[type="text"]:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: var(--accent-color);
|
border-color: hsl(var(--primary));
|
||||||
box-shadow: 0 0 0 3px var(--accent-shadow, rgba(99, 102, 241, 0.1));
|
box-shadow: 0 0 0 3px hsl(var(--primary) / 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Memory Detail Content */
|
/* Memory Detail Content */
|
||||||
@@ -396,19 +396,19 @@
|
|||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 0.75rem;
|
margin-bottom: 0.75rem;
|
||||||
color: var(--text-primary);
|
color: hsl(var(--foreground));
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-text {
|
.detail-text {
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
color: var(--text-primary);
|
color: hsl(var(--foreground));
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-code {
|
.detail-code {
|
||||||
background: var(--secondary-bg);
|
background: hsl(var(--muted));
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid hsl(var(--border));
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
||||||
@@ -430,7 +430,7 @@
|
|||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 0.75rem;
|
margin-bottom: 0.75rem;
|
||||||
color: var(--text-primary);
|
color: hsl(var(--foreground));
|
||||||
}
|
}
|
||||||
|
|
||||||
.entities-list,
|
.entities-list,
|
||||||
@@ -442,8 +442,8 @@
|
|||||||
|
|
||||||
.entity-item {
|
.entity-item {
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
background: var(--secondary-bg);
|
background: hsl(var(--muted));
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid hsl(var(--border));
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@@ -452,21 +452,21 @@
|
|||||||
|
|
||||||
.entity-name {
|
.entity-name {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--text-primary);
|
color: hsl(var(--foreground));
|
||||||
}
|
}
|
||||||
|
|
||||||
.entity-type {
|
.entity-type {
|
||||||
padding: 0.25rem 0.5rem;
|
padding: 0.25rem 0.5rem;
|
||||||
background: var(--accent-bg);
|
background: hsl(var(--accent));
|
||||||
color: var(--accent-color);
|
color: hsl(var(--primary));
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.relationship-item {
|
.relationship-item {
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
background: var(--secondary-bg);
|
background: hsl(var(--muted));
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid hsl(var(--border));
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -477,13 +477,13 @@
|
|||||||
.rel-target {
|
.rel-target {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--text-primary);
|
color: hsl(var(--foreground));
|
||||||
}
|
}
|
||||||
|
|
||||||
.rel-type {
|
.rel-type {
|
||||||
padding: 0.25rem 0.5rem;
|
padding: 0.25rem 0.5rem;
|
||||||
background: var(--info-bg, #dbeafe);
|
background: hsl(var(--info) / 0.15);
|
||||||
color: var(--info-color, #1e3a8a);
|
color: hsl(var(--info));
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@@ -498,9 +498,9 @@
|
|||||||
|
|
||||||
.evolution-version {
|
.evolution-version {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
background: var(--secondary-bg);
|
background: hsl(var(--muted));
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid hsl(var(--border));
|
||||||
border-left: 3px solid var(--accent-color);
|
border-left: 3px solid hsl(var(--primary));
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -513,17 +513,17 @@
|
|||||||
|
|
||||||
.version-number {
|
.version-number {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--accent-color);
|
color: hsl(var(--primary));
|
||||||
}
|
}
|
||||||
|
|
||||||
.version-date {
|
.version-date {
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
color: var(--text-secondary);
|
color: hsl(var(--muted-foreground));
|
||||||
}
|
}
|
||||||
|
|
||||||
.version-reason {
|
.version-reason {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
color: var(--text-primary);
|
color: hsl(var(--foreground));
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -531,7 +531,7 @@
|
|||||||
.empty-state {
|
.empty-state {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 3rem 1rem;
|
padding: 3rem 1rem;
|
||||||
color: var(--text-secondary);
|
color: hsl(var(--muted-foreground));
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-state i {
|
.empty-state i {
|
||||||
@@ -546,7 +546,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.empty-text {
|
.empty-text {
|
||||||
color: var(--text-secondary);
|
color: hsl(var(--muted-foreground));
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,6 +573,219 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
Knowledge Graph D3 Visualization Styles
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
.knowledge-graph-container {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 400px;
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.knowledge-graph-svg {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-content {
|
||||||
|
cursor: grab;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-content:active {
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-edge {
|
||||||
|
stroke: hsl(var(--muted-foreground));
|
||||||
|
stroke-width: 1.5;
|
||||||
|
stroke-opacity: 0.6;
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-node {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-node:hover {
|
||||||
|
filter: brightness(1.2);
|
||||||
|
stroke-width: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-label {
|
||||||
|
font-size: 11px;
|
||||||
|
fill: hsl(var(--foreground));
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-node-group.file .graph-node { fill: #3b82f6; }
|
||||||
|
.graph-node-group.function .graph-node { fill: #10b981; }
|
||||||
|
.graph-node-group.module .graph-node { fill: #8b5cf6; }
|
||||||
|
.graph-node-group.class .graph-node { fill: #f59e0b; }
|
||||||
|
.graph-node-group.entity .graph-node { fill: #6b7280; }
|
||||||
|
|
||||||
|
.graph-error,
|
||||||
|
.graph-empty-state {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 300px;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
text-align: center;
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-error i,
|
||||||
|
.graph-empty-state i {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-error p,
|
||||||
|
.graph-empty-state p {
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
Evolution Version Card Styles
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
.version-card {
|
||||||
|
background: hsl(var(--card));
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-left: 3px solid hsl(var(--primary));
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 1rem;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-card:hover {
|
||||||
|
box-shadow: 0 2px 8px hsl(var(--foreground) / 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-card .version-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-card .version-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-card .version-number {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
background: hsl(var(--primary) / 0.1);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-card .version-date {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-content-preview {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
background: hsl(var(--muted) / 0.5);
|
||||||
|
padding: 0.75rem;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-diff-stats {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.75rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diff-stat {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 0.25rem 0.625rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diff-stat i {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diff-stat.diff-added {
|
||||||
|
background: hsl(142 76% 36% / 0.15);
|
||||||
|
color: hsl(142 76% 30%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.diff-stat.diff-modified {
|
||||||
|
background: hsl(38 92% 50% / 0.15);
|
||||||
|
color: hsl(38 92% 40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.diff-stat.diff-deleted {
|
||||||
|
background: hsl(0 84% 60% / 0.15);
|
||||||
|
color: hsl(0 84% 45%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-card .version-reason {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
padding-top: 0.75rem;
|
||||||
|
border-top: 1px solid hsl(var(--border));
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-card .version-reason strong {
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.evolution-empty-state {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 200px;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
text-align: center;
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.evolution-empty-state i {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.evolution-empty-state p {
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Dark Mode Adjustments */
|
/* Dark Mode Adjustments */
|
||||||
[data-theme="dark"] .memory-card {
|
[data-theme="dark"] .memory-card {
|
||||||
background: #1e293b;
|
background: #1e293b;
|
||||||
@@ -594,3 +807,25 @@
|
|||||||
background: #1e293b;
|
background: #1e293b;
|
||||||
border-color: #334155;
|
border-color: #334155;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .knowledge-graph-container {
|
||||||
|
background: #0f172a;
|
||||||
|
border-color: #334155;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .graph-label {
|
||||||
|
fill: #e2e8f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .graph-edge {
|
||||||
|
stroke: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .version-card {
|
||||||
|
background: #1e293b;
|
||||||
|
border-color: #334155;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .version-content-preview {
|
||||||
|
background: #0f172a;
|
||||||
|
}
|
||||||
@@ -92,6 +92,15 @@ async function loadCodexLensStatus() {
|
|||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
codexLensStatus = data;
|
codexLensStatus = data;
|
||||||
|
|
||||||
|
// Expose to window for other modules (e.g., codexlens-manager.js)
|
||||||
|
if (!window.cliToolsStatus) {
|
||||||
|
window.cliToolsStatus = {};
|
||||||
|
}
|
||||||
|
window.cliToolsStatus.codexlens = {
|
||||||
|
installed: data.ready || false,
|
||||||
|
version: data.version || null
|
||||||
|
};
|
||||||
|
|
||||||
// Update CodexLens badge
|
// Update CodexLens badge
|
||||||
updateCodexLensBadge();
|
updateCodexLensBadge();
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,27 @@ async function loadIndexStats() {
|
|||||||
*/
|
*/
|
||||||
function renderIndexCard() {
|
function renderIndexCard() {
|
||||||
const container = document.getElementById('indexCard');
|
const container = document.getElementById('indexCard');
|
||||||
if (!container || !indexData) return;
|
if (!container) {
|
||||||
|
console.warn('[IndexManager] Container not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle case when data is not loaded yet
|
||||||
|
if (!indexData) {
|
||||||
|
container.innerHTML = `
|
||||||
|
<div class="bg-card border border-border rounded-lg overflow-hidden">
|
||||||
|
<div class="bg-muted/30 border-b border-border px-4 py-3 flex items-center gap-2">
|
||||||
|
<i data-lucide="database" class="w-4 h-4 text-primary"></i>
|
||||||
|
<span class="font-medium text-foreground">${t('index.manager') || 'Index Manager'}</span>
|
||||||
|
</div>
|
||||||
|
<div class="p-4 text-center text-muted-foreground">
|
||||||
|
<div class="animate-pulse">${t('common.loading') || 'Loading...'}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
if (typeof lucide !== 'undefined') lucide.createIcons();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const { indexDir, indexes, summary } = indexData;
|
const { indexDir, indexes, summary } = indexData;
|
||||||
|
|
||||||
@@ -64,113 +84,113 @@ function renderIndexCard() {
|
|||||||
if (indexes && indexes.length > 0) {
|
if (indexes && indexes.length > 0) {
|
||||||
indexes.forEach(function(idx) {
|
indexes.forEach(function(idx) {
|
||||||
const vectorBadge = idx.hasVectorIndex
|
const vectorBadge = idx.hasVectorIndex
|
||||||
? '<span class="text-xs px-1.5 py-0.5 bg-primary/10 text-primary rounded">' + (t('index.vector') || 'Vector') + '</span>'
|
? `<span class="text-xs px-1.5 py-0.5 bg-primary/10 text-primary rounded">${t('index.vector') || 'Vector'}</span>`
|
||||||
: '';
|
: '';
|
||||||
const normalBadge = idx.hasNormalIndex
|
const normalBadge = idx.hasNormalIndex
|
||||||
? '<span class="text-xs px-1.5 py-0.5 bg-muted text-muted-foreground rounded">' + (t('index.fts') || 'FTS') + '</span>'
|
? `<span class="text-xs px-1.5 py-0.5 bg-muted text-muted-foreground rounded">${t('index.fts') || 'FTS'}</span>`
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
indexRows += '\
|
indexRows += `
|
||||||
<tr class="border-t border-border hover:bg-muted/30 transition-colors">\
|
<tr class="border-t border-border hover:bg-muted/30 transition-colors">
|
||||||
<td class="py-2 px-2 text-foreground">\
|
<td class="py-2 px-2 text-foreground">
|
||||||
<div class="flex items-center gap-2">\
|
<div class="flex items-center gap-2">
|
||||||
<span class="font-mono text-xs truncate max-w-[250px]" title="' + escapeHtml(idx.id) + '">' + escapeHtml(idx.id) + '</span>\
|
<span class="font-mono text-xs truncate max-w-[250px]" title="${escapeHtml(idx.id)}">${escapeHtml(idx.id)}</span>
|
||||||
</div>\
|
</div>
|
||||||
</td>\
|
</td>
|
||||||
<td class="py-2 px-2 text-right text-muted-foreground">' + idx.sizeFormatted + '</td>\
|
<td class="py-2 px-2 text-right text-muted-foreground">${idx.sizeFormatted}</td>
|
||||||
<td class="py-2 px-2 text-center">\
|
<td class="py-2 px-2 text-center">
|
||||||
<div class="flex items-center justify-center gap-1">' + vectorBadge + normalBadge + '</div>\
|
<div class="flex items-center justify-center gap-1">${vectorBadge}${normalBadge}</div>
|
||||||
</td>\
|
</td>
|
||||||
<td class="py-2 px-2 text-right text-muted-foreground">' + formatTimeAgo(idx.lastModified) + '</td>\
|
<td class="py-2 px-2 text-right text-muted-foreground">${formatTimeAgo(idx.lastModified)}</td>
|
||||||
<td class="py-2 px-1 text-center">\
|
<td class="py-2 px-1 text-center">
|
||||||
<button onclick="cleanIndexProject(\'' + escapeHtml(idx.id) + '\')" \
|
<button onclick="cleanIndexProject('${escapeHtml(idx.id)}')"
|
||||||
class="text-destructive/70 hover:text-destructive p-1 rounded hover:bg-destructive/10 transition-colors" \
|
class="text-destructive/70 hover:text-destructive p-1 rounded hover:bg-destructive/10 transition-colors"
|
||||||
title="' + (t('index.cleanProject') || 'Clean Index') + '">\
|
title="${t('index.cleanProject') || 'Clean Index'}">
|
||||||
<i data-lucide="trash-2" class="w-3.5 h-3.5"></i>\
|
<i data-lucide="trash-2" class="w-3.5 h-3.5"></i>
|
||||||
</button>\
|
</button>
|
||||||
</td>\
|
</td>
|
||||||
</tr>\
|
</tr>
|
||||||
';
|
`;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
indexRows = '\
|
indexRows = `
|
||||||
<tr>\
|
<tr>
|
||||||
<td colspan="5" class="py-4 text-center text-muted-foreground text-sm">' + (t('index.noIndexes') || 'No indexes yet') + '</td>\
|
<td colspan="5" class="py-4 text-center text-muted-foreground text-sm">${t('index.noIndexes') || 'No indexes yet'}</td>
|
||||||
</tr>\
|
</tr>
|
||||||
';
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
container.innerHTML = '\
|
container.innerHTML = `
|
||||||
<div class="bg-card border border-border rounded-lg overflow-hidden">\
|
<div class="bg-card border border-border rounded-lg overflow-hidden">
|
||||||
<div class="bg-muted/30 border-b border-border px-4 py-3 flex items-center justify-between">\
|
<div class="bg-muted/30 border-b border-border px-4 py-3 flex items-center justify-between">
|
||||||
<div class="flex items-center gap-2">\
|
<div class="flex items-center gap-2">
|
||||||
<i data-lucide="database" class="w-4 h-4 text-primary"></i>\
|
<i data-lucide="database" class="w-4 h-4 text-primary"></i>
|
||||||
<span class="font-medium text-foreground">' + (t('index.manager') || 'Index Manager') + '</span>\
|
<span class="font-medium text-foreground">${t('index.manager') || 'Index Manager'}</span>
|
||||||
<span class="text-xs px-2 py-0.5 bg-muted rounded-full text-muted-foreground">' + (summary?.totalSizeFormatted || '0 B') + '</span>\
|
<span class="text-xs px-2 py-0.5 bg-muted rounded-full text-muted-foreground">${summary?.totalSizeFormatted || '0 B'}</span>
|
||||||
</div>\
|
</div>
|
||||||
<div class="flex items-center gap-2">\
|
<div class="flex items-center gap-2">
|
||||||
<button onclick="loadIndexStats()" class="text-xs px-2 py-1 text-muted-foreground hover:text-foreground hover:bg-muted rounded transition-colors" title="' + (t('common.refresh') || 'Refresh') + '">\
|
<button onclick="loadIndexStats()" class="text-xs px-2 py-1 text-muted-foreground hover:text-foreground hover:bg-muted rounded transition-colors" title="${t('common.refresh') || 'Refresh'}">
|
||||||
<i data-lucide="refresh-cw" class="w-3.5 h-3.5"></i>\
|
<i data-lucide="refresh-cw" class="w-3.5 h-3.5"></i>
|
||||||
</button>\
|
</button>
|
||||||
<button onclick="showCodexLensConfigModal()" class="text-xs px-2 py-1 text-muted-foreground hover:text-foreground hover:bg-muted rounded transition-colors" title="' + (t('common.settings') || 'Settings') + '">\
|
<button onclick="showCodexLensConfigModal()" class="text-xs px-2 py-1 text-muted-foreground hover:text-foreground hover:bg-muted rounded transition-colors" title="${t('common.settings') || 'Settings'}">
|
||||||
<i data-lucide="settings" class="w-3.5 h-3.5"></i>\
|
<i data-lucide="settings" class="w-3.5 h-3.5"></i>
|
||||||
</button>\
|
</button>
|
||||||
</div>\
|
</div>
|
||||||
</div>\
|
</div>
|
||||||
<div class="p-4">\
|
<div class="p-4">
|
||||||
<div class="flex items-center gap-2 mb-3 text-xs text-muted-foreground">\
|
<div class="flex items-center gap-2 mb-3 text-xs text-muted-foreground">
|
||||||
<i data-lucide="folder" class="w-3.5 h-3.5"></i>\
|
<i data-lucide="folder" class="w-3.5 h-3.5"></i>
|
||||||
<span class="font-mono truncate" title="' + escapeHtml(indexDir || '') + '">' + escapeHtml(indexDir || t('index.notConfigured') || 'Not configured') + '</span>\
|
<span class="font-mono truncate" title="${escapeHtml(indexDir || '')}">${escapeHtml(indexDir || t('index.notConfigured') || 'Not configured')}</span>
|
||||||
</div>\
|
</div>
|
||||||
<div class="grid grid-cols-4 gap-3 mb-4">\
|
<div class="grid grid-cols-4 gap-3 mb-4">
|
||||||
<div class="bg-muted/30 rounded-lg p-3 text-center">\
|
<div class="bg-muted/30 rounded-lg p-3 text-center">
|
||||||
<div class="text-lg font-semibold text-foreground">' + (summary?.totalProjects || 0) + '</div>\
|
<div class="text-lg font-semibold text-foreground">${summary?.totalProjects || 0}</div>
|
||||||
<div class="text-xs text-muted-foreground">' + (t('index.projects') || 'Projects') + '</div>\
|
<div class="text-xs text-muted-foreground">${t('index.projects') || 'Projects'}</div>
|
||||||
</div>\
|
</div>
|
||||||
<div class="bg-muted/30 rounded-lg p-3 text-center">\
|
<div class="bg-muted/30 rounded-lg p-3 text-center">
|
||||||
<div class="text-lg font-semibold text-foreground">' + (summary?.totalSizeFormatted || '0 B') + '</div>\
|
<div class="text-lg font-semibold text-foreground">${summary?.totalSizeFormatted || '0 B'}</div>
|
||||||
<div class="text-xs text-muted-foreground">' + (t('index.totalSize') || 'Total Size') + '</div>\
|
<div class="text-xs text-muted-foreground">${t('index.totalSize') || 'Total Size'}</div>
|
||||||
</div>\
|
</div>
|
||||||
<div class="bg-muted/30 rounded-lg p-3 text-center">\
|
<div class="bg-muted/30 rounded-lg p-3 text-center">
|
||||||
<div class="text-lg font-semibold text-foreground">' + (summary?.vectorIndexCount || 0) + '</div>\
|
<div class="text-lg font-semibold text-foreground">${summary?.vectorIndexCount || 0}</div>
|
||||||
<div class="text-xs text-muted-foreground">' + (t('index.vectorIndexes') || 'Vector') + '</div>\
|
<div class="text-xs text-muted-foreground">${t('index.vectorIndexes') || 'Vector'}</div>
|
||||||
</div>\
|
</div>
|
||||||
<div class="bg-muted/30 rounded-lg p-3 text-center">\
|
<div class="bg-muted/30 rounded-lg p-3 text-center">
|
||||||
<div class="text-lg font-semibold text-foreground">' + (summary?.normalIndexCount || 0) + '</div>\
|
<div class="text-lg font-semibold text-foreground">${summary?.normalIndexCount || 0}</div>
|
||||||
<div class="text-xs text-muted-foreground">' + (t('index.ftsIndexes') || 'FTS') + '</div>\
|
<div class="text-xs text-muted-foreground">${t('index.ftsIndexes') || 'FTS'}</div>
|
||||||
</div>\
|
</div>
|
||||||
</div>\
|
</div>
|
||||||
<div class="border border-border rounded-lg overflow-hidden">\
|
<div class="border border-border rounded-lg overflow-hidden">
|
||||||
<table class="w-full text-sm">\
|
<table class="w-full text-sm">
|
||||||
<thead class="bg-muted/50">\
|
<thead class="bg-muted/50">
|
||||||
<tr class="text-xs text-muted-foreground">\
|
<tr class="text-xs text-muted-foreground">
|
||||||
<th class="py-2 px-2 text-left font-medium">' + (t('index.projectId') || 'Project ID') + '</th>\
|
<th class="py-2 px-2 text-left font-medium">${t('index.projectId') || 'Project ID'}</th>
|
||||||
<th class="py-2 px-2 text-right font-medium">' + (t('index.size') || 'Size') + '</th>\
|
<th class="py-2 px-2 text-right font-medium">${t('index.size') || 'Size'}</th>
|
||||||
<th class="py-2 px-2 text-center font-medium">' + (t('index.type') || 'Type') + '</th>\
|
<th class="py-2 px-2 text-center font-medium">${t('index.type') || 'Type'}</th>
|
||||||
<th class="py-2 px-2 text-right font-medium">' + (t('index.lastModified') || 'Modified') + '</th>\
|
<th class="py-2 px-2 text-right font-medium">${t('index.lastModified') || 'Modified'}</th>
|
||||||
<th class="py-2 px-1 w-8"></th>\
|
<th class="py-2 px-1 w-8"></th>
|
||||||
</tr>\
|
</tr>
|
||||||
</thead>\
|
</thead>
|
||||||
<tbody>\
|
<tbody>
|
||||||
' + indexRows + '\
|
${indexRows}
|
||||||
</tbody>\
|
</tbody>
|
||||||
</table>\
|
</table>
|
||||||
</div>\
|
</div>
|
||||||
<div class="mt-4 flex justify-between items-center gap-2">\
|
<div class="mt-4 flex justify-between items-center gap-2">
|
||||||
<button onclick="initCodexLensIndex()" \
|
<button onclick="initCodexLensIndex()"
|
||||||
class="text-xs px-3 py-1.5 bg-primary/10 text-primary hover:bg-primary/20 rounded transition-colors flex items-center gap-1.5">\
|
class="text-xs px-3 py-1.5 bg-primary/10 text-primary hover:bg-primary/20 rounded transition-colors flex items-center gap-1.5">
|
||||||
<i data-lucide="database" class="w-3.5 h-3.5"></i>\
|
<i data-lucide="database" class="w-3.5 h-3.5"></i>
|
||||||
' + (t('index.initCurrent') || 'Init Current Project') + '\
|
${t('index.initCurrent') || 'Init Current Project'}
|
||||||
</button>\
|
</button>
|
||||||
<button onclick="cleanAllIndexesConfirm()" \
|
<button onclick="cleanAllIndexesConfirm()"
|
||||||
class="text-xs px-3 py-1.5 bg-destructive/10 text-destructive hover:bg-destructive/20 rounded transition-colors flex items-center gap-1.5">\
|
class="text-xs px-3 py-1.5 bg-destructive/10 text-destructive hover:bg-destructive/20 rounded transition-colors flex items-center gap-1.5">
|
||||||
<i data-lucide="trash" class="w-3.5 h-3.5"></i>\
|
<i data-lucide="trash" class="w-3.5 h-3.5"></i>
|
||||||
' + (t('index.cleanAll') || 'Clean All') + '\
|
${t('index.cleanAll') || 'Clean All'}
|
||||||
</button>\
|
</button>
|
||||||
</div>\
|
</div>
|
||||||
</div>\
|
</div>
|
||||||
</div>\
|
</div>
|
||||||
';
|
`;
|
||||||
|
|
||||||
// Reinitialize Lucide icons
|
// Reinitialize Lucide icons
|
||||||
if (typeof lucide !== 'undefined') {
|
if (typeof lucide !== 'undefined') {
|
||||||
@@ -185,24 +205,24 @@ function renderIndexCardError(errorMessage) {
|
|||||||
const container = document.getElementById('indexCard');
|
const container = document.getElementById('indexCard');
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
container.innerHTML = '\
|
container.innerHTML = `
|
||||||
<div class="bg-card border border-border rounded-lg overflow-hidden">\
|
<div class="bg-card border border-border rounded-lg overflow-hidden">
|
||||||
<div class="bg-muted/30 border-b border-border px-4 py-3 flex items-center gap-2">\
|
<div class="bg-muted/30 border-b border-border px-4 py-3 flex items-center gap-2">
|
||||||
<i data-lucide="database" class="w-4 h-4 text-primary"></i>\
|
<i data-lucide="database" class="w-4 h-4 text-primary"></i>
|
||||||
<span class="font-medium text-foreground">' + (t('index.manager') || 'Index Manager') + '</span>\
|
<span class="font-medium text-foreground">${t('index.manager') || 'Index Manager'}</span>
|
||||||
</div>\
|
</div>
|
||||||
<div class="p-4 text-center">\
|
<div class="p-4 text-center">
|
||||||
<div class="text-destructive mb-2">\
|
<div class="text-destructive mb-2">
|
||||||
<i data-lucide="alert-circle" class="w-8 h-8 mx-auto"></i>\
|
<i data-lucide="alert-circle" class="w-8 h-8 mx-auto"></i>
|
||||||
</div>\
|
</div>
|
||||||
<p class="text-sm text-muted-foreground mb-3">' + escapeHtml(errorMessage) + '</p>\
|
<p class="text-sm text-muted-foreground mb-3">${escapeHtml(errorMessage)}</p>
|
||||||
<button onclick="loadIndexStats()" \
|
<button onclick="loadIndexStats()"
|
||||||
class="text-xs px-3 py-1.5 bg-primary text-primary-foreground hover:bg-primary/90 rounded transition-colors">\
|
class="text-xs px-3 py-1.5 bg-primary text-primary-foreground hover:bg-primary/90 rounded transition-colors">
|
||||||
' + (t('common.retry') || 'Retry') + '\
|
${t('common.retry') || 'Retry'}
|
||||||
</button>\
|
</button>
|
||||||
</div>\
|
</div>
|
||||||
</div>\
|
</div>
|
||||||
';
|
`;
|
||||||
|
|
||||||
// Reinitialize Lucide icons
|
// Reinitialize Lucide icons
|
||||||
if (typeof lucide !== 'undefined') {
|
if (typeof lucide !== 'undefined') {
|
||||||
|
|||||||
@@ -45,10 +45,26 @@ function showModal(title, content, options = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function closeModal() {
|
function closeModal() {
|
||||||
const overlay = document.querySelector('.generic-modal-overlay');
|
// Try generic modal overlay first
|
||||||
if (overlay) {
|
const genericOverlay = document.querySelector('.generic-modal-overlay');
|
||||||
overlay.classList.remove('active');
|
if (genericOverlay) {
|
||||||
setTimeout(() => overlay.remove(), 200);
|
genericOverlay.classList.remove('active');
|
||||||
|
setTimeout(() => genericOverlay.remove(), 200);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try CodexLens config modal
|
||||||
|
const codexLensModal = document.getElementById('codexlensConfigModal');
|
||||||
|
if (codexLensModal) {
|
||||||
|
codexLensModal.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try any modal-backdrop
|
||||||
|
const modalBackdrop = document.querySelector('.modal-backdrop');
|
||||||
|
if (modalBackdrop) {
|
||||||
|
modalBackdrop.remove();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,10 @@ async function showCodexLensConfigModal() {
|
|||||||
const modalHtml = buildCodexLensConfigContent(config);
|
const modalHtml = buildCodexLensConfigContent(config);
|
||||||
|
|
||||||
// Create and show modal
|
// Create and show modal
|
||||||
const modalContainer = document.createElement('div');
|
const tempContainer = document.createElement('div');
|
||||||
modalContainer.innerHTML = modalHtml;
|
tempContainer.innerHTML = modalHtml;
|
||||||
document.body.appendChild(modalContainer);
|
const modal = tempContainer.firstElementChild;
|
||||||
|
document.body.appendChild(modal);
|
||||||
|
|
||||||
// Initialize icons
|
// Initialize icons
|
||||||
if (window.lucide) lucide.createIcons();
|
if (window.lucide) lucide.createIcons();
|
||||||
@@ -65,11 +66,21 @@ function buildCodexLensConfigContent(config) {
|
|||||||
'<div class="flex items-center gap-4 text-sm">' +
|
'<div class="flex items-center gap-4 text-sm">' +
|
||||||
'<div class="flex items-center gap-2">' +
|
'<div class="flex items-center gap-2">' +
|
||||||
'<span class="text-muted-foreground">' + t('codexlens.currentWorkspace') + ':</span>' +
|
'<span class="text-muted-foreground">' + t('codexlens.currentWorkspace') + ':</span>' +
|
||||||
'<span class="font-medium">' + (isInstalled ? t('codexlens.installed') : t('codexlens.notInstalled')) + '</span>' +
|
(isInstalled
|
||||||
|
? '<span class="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium bg-success/10 text-success border border-success/20">' +
|
||||||
|
'<i data-lucide="check-circle" class="w-3.5 h-3.5"></i>' +
|
||||||
|
t('codexlens.installed') +
|
||||||
|
'</span>'
|
||||||
|
: '<span class="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium bg-muted text-muted-foreground border border-border">' +
|
||||||
|
'<i data-lucide="circle" class="w-3.5 h-3.5"></i>' +
|
||||||
|
t('codexlens.notInstalled') +
|
||||||
|
'</span>') +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'<div class="flex items-center gap-2">' +
|
'<div class="flex items-center gap-2">' +
|
||||||
'<span class="text-muted-foreground">' + t('codexlens.indexes') + ':</span>' +
|
'<span class="text-muted-foreground">' + t('codexlens.indexes') + ':</span>' +
|
||||||
'<span class="font-medium">' + indexCount + '</span>' +
|
'<span class="inline-flex items-center px-2 py-0.5 rounded-md text-xs font-medium bg-primary/10 text-primary border border-primary/20">' +
|
||||||
|
indexCount +
|
||||||
|
'</span>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
@@ -106,20 +117,20 @@ function buildCodexLensConfigContent(config) {
|
|||||||
'<h4>' + t('codexlens.actions') + '</h4>' +
|
'<h4>' + t('codexlens.actions') + '</h4>' +
|
||||||
'<div class="tool-config-actions">' +
|
'<div class="tool-config-actions">' +
|
||||||
(isInstalled
|
(isInstalled
|
||||||
? '<button class="btn-sm btn-outline" onclick="initCodexLensIndex()">' +
|
? '<button class="inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md border border-primary/30 bg-primary/5 text-primary hover:bg-primary/10 transition-colors" onclick="initCodexLensIndex()">' +
|
||||||
'<i data-lucide="database" class="w-3 h-3"></i> ' + t('codexlens.initializeIndex') +
|
'<i data-lucide="database" class="w-3.5 h-3.5"></i> ' + t('codexlens.initializeIndex') +
|
||||||
'</button>' +
|
'</button>' +
|
||||||
'<button class="btn-sm btn-outline" onclick="cleanCurrentWorkspaceIndex()">' +
|
'<button class="inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md border border-border bg-background hover:bg-muted/50 transition-colors" onclick="cleanCurrentWorkspaceIndex()">' +
|
||||||
'<i data-lucide="folder-x" class="w-3 h-3"></i> ' + t('codexlens.cleanCurrentWorkspace') +
|
'<i data-lucide="folder-x" class="w-3.5 h-3.5"></i> ' + t('codexlens.cleanCurrentWorkspace') +
|
||||||
'</button>' +
|
'</button>' +
|
||||||
'<button class="btn-sm btn-outline" onclick="cleanCodexLensIndexes()">' +
|
'<button class="inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md border border-border bg-background hover:bg-muted/50 transition-colors" onclick="cleanCodexLensIndexes()">' +
|
||||||
'<i data-lucide="trash" class="w-3 h-3"></i> ' + t('codexlens.cleanAllIndexes') +
|
'<i data-lucide="trash" class="w-3.5 h-3.5"></i> ' + t('codexlens.cleanAllIndexes') +
|
||||||
'</button>' +
|
'</button>' +
|
||||||
'<button class="btn-sm btn-outline btn-danger" onclick="uninstallCodexLens()">' +
|
'<button class="inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md border border-destructive/30 bg-destructive/5 text-destructive hover:bg-destructive/10 transition-colors" onclick="uninstallCodexLens()">' +
|
||||||
'<i data-lucide="trash-2" class="w-3 h-3"></i> ' + t('cli.uninstall') +
|
'<i data-lucide="trash-2" class="w-3.5 h-3.5"></i> ' + t('cli.uninstall') +
|
||||||
'</button>'
|
'</button>'
|
||||||
: '<button class="btn-sm btn-primary" onclick="installCodexLens()">' +
|
: '<button class="inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md bg-primary text-primary-foreground hover:bg-primary/90 transition-colors" onclick="installCodexLens()">' +
|
||||||
'<i data-lucide="download" class="w-3 h-3"></i> ' + t('codexlens.installCodexLens') +
|
'<i data-lucide="download" class="w-3.5 h-3.5"></i> ' + t('codexlens.installCodexLens') +
|
||||||
'</button>') +
|
'</button>') +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
@@ -172,12 +183,12 @@ function buildCodexLensConfigContent(config) {
|
|||||||
'</button>' +
|
'</button>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'<div id="searchResults" class="hidden">' +
|
'<div id="searchResults" class="hidden">' +
|
||||||
'<div class="bg-muted/30 rounded-lg p-3 max-h-64 overflow-y-auto">' +
|
'<div>' +
|
||||||
'<div class="flex items-center justify-between mb-2">' +
|
'<div class="flex items-center justify-between">' +
|
||||||
'<p class="text-sm font-medium">' + t('codexlens.results') + ':</p>' +
|
'<p class="text-sm font-medium">' + t('codexlens.results') + ':</p>' +
|
||||||
'<span id="searchResultCount" class="text-xs text-muted-foreground"></span>' +
|
'<span id="searchResultCount" class="text-xs text-muted-foreground"></span>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'<pre id="searchResultContent" class="text-xs font-mono whitespace-pre-wrap break-all"></pre>' +
|
'<pre id="searchResultContent"></pre>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
|
|||||||
@@ -758,11 +758,12 @@ async function executeCliTool(
|
|||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// Direct spawn without shell - CLI tools (codex/gemini/qwen) don't need shell wrapper
|
// Windows requires shell: true for npm global commands (.cmd files)
|
||||||
// This avoids Windows cmd.exe ENOENT errors and simplifies argument handling
|
// Unix-like systems can use shell: false for direct execution
|
||||||
|
const isWindows = process.platform === 'win32';
|
||||||
const child = spawn(command, args, {
|
const child = spawn(command, args, {
|
||||||
cwd: workingDir,
|
cwd: workingDir,
|
||||||
shell: false,
|
shell: isWindows, // Enable shell on Windows for .cmd files
|
||||||
stdio: [useStdin ? 'pipe' : 'ignore', 'pipe', 'pipe']
|
stdio: [useStdin ? 'pipe' : 'ignore', 'pipe', 'pipe']
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -39,10 +39,16 @@ const ParamsSchema = z.object({
|
|||||||
'init',
|
'init',
|
||||||
'search',
|
'search',
|
||||||
'search_files',
|
'search_files',
|
||||||
|
'status',
|
||||||
|
'symbol',
|
||||||
|
'check',
|
||||||
|
'update',
|
||||||
|
'bootstrap',
|
||||||
]),
|
]),
|
||||||
path: z.string().optional(),
|
path: z.string().optional(),
|
||||||
query: z.string().optional(),
|
query: z.string().optional(),
|
||||||
mode: z.enum(['auto', 'text', 'semantic', 'exact', 'fuzzy', 'hybrid', 'vector', 'pure-vector']).default('auto'),
|
mode: z.enum(['auto', 'text', 'semantic', 'exact', 'fuzzy', 'hybrid', 'vector', 'pure-vector']).default('auto'),
|
||||||
|
format: z.enum(['json', 'text', 'pretty']).default('json'),
|
||||||
languages: z.array(z.string()).optional(),
|
languages: z.array(z.string()).optional(),
|
||||||
limit: z.number().default(20),
|
limit: z.number().default(20),
|
||||||
// Additional fields for internal functions
|
// Additional fields for internal functions
|
||||||
@@ -790,8 +796,13 @@ Note: For advanced operations (config, status, clean), use CLI directly: codexle
|
|||||||
'init',
|
'init',
|
||||||
'search',
|
'search',
|
||||||
'search_files',
|
'search_files',
|
||||||
|
'status',
|
||||||
|
'symbol',
|
||||||
|
'check',
|
||||||
|
'update',
|
||||||
|
'bootstrap',
|
||||||
],
|
],
|
||||||
description: 'Action to perform: init (index directory), search (search code), search_files (search files only)',
|
description: 'Action to perform: init/update (index directory), search (search code), search_files (search files only), status (index status), symbol (extract symbols), check (check if ready), bootstrap (setup venv)',
|
||||||
},
|
},
|
||||||
path: {
|
path: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
@@ -807,6 +818,12 @@ Note: For advanced operations (config, status, clean), use CLI directly: codexle
|
|||||||
description: 'Search mode: auto (default, hybrid if embeddings exist), text/exact (FTS), hybrid (best), fuzzy, vector, semantic/pure-vector',
|
description: 'Search mode: auto (default, hybrid if embeddings exist), text/exact (FTS), hybrid (best), fuzzy, vector, semantic/pure-vector',
|
||||||
default: 'auto',
|
default: 'auto',
|
||||||
},
|
},
|
||||||
|
format: {
|
||||||
|
type: 'string',
|
||||||
|
enum: ['json', 'text', 'pretty'],
|
||||||
|
description: 'Output format: json (default), text, pretty',
|
||||||
|
default: 'json',
|
||||||
|
},
|
||||||
languages: {
|
languages: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
items: { type: 'string' },
|
items: { type: 'string' },
|
||||||
@@ -847,9 +864,41 @@ export async function handler(params: Record<string, unknown>): Promise<ToolResu
|
|||||||
result = await searchFiles(parsed.data);
|
result = await searchFiles(parsed.data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'status':
|
||||||
|
result = await getStatus(parsed.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'symbol':
|
||||||
|
result = await extractSymbols(parsed.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'check':
|
||||||
|
const checkStatus = await ensureReady();
|
||||||
|
result = {
|
||||||
|
success: checkStatus.ready,
|
||||||
|
ready: checkStatus.ready,
|
||||||
|
version: checkStatus.version,
|
||||||
|
error: checkStatus.error,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'update':
|
||||||
|
// Update is an alias for init (incremental update)
|
||||||
|
result = await initIndex(parsed.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'bootstrap':
|
||||||
|
const bootstrapResult = await bootstrapVenv();
|
||||||
|
result = {
|
||||||
|
success: bootstrapResult.success,
|
||||||
|
message: bootstrapResult.message,
|
||||||
|
error: bootstrapResult.error,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown action: ${action}. Valid actions: init, search, search_files`
|
`Unknown action: ${action}. Valid actions: init, search, search_files, status, symbol, check, update, bootstrap`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -141,9 +141,11 @@ async function checkIndexStatus(path: string = '.'): Promise<IndexStatus> {
|
|||||||
try {
|
try {
|
||||||
// Strip ANSI color codes from JSON output
|
// Strip ANSI color codes from JSON output
|
||||||
const cleanOutput = (result.output || '{}').replace(/\x1b\[[0-9;]*m/g, '');
|
const cleanOutput = (result.output || '{}').replace(/\x1b\[[0-9;]*m/g, '');
|
||||||
const status = JSON.parse(cleanOutput);
|
const parsed = JSON.parse(cleanOutput);
|
||||||
const indexed = status.indexed === true || status.file_count > 0;
|
// Handle both direct and nested response formats (status returns {success, result: {...}})
|
||||||
|
const status = parsed.result || parsed;
|
||||||
|
const indexed = status.projects_count > 0 || status.total_files > 0;
|
||||||
|
|
||||||
// Get embeddings coverage from comprehensive status
|
// Get embeddings coverage from comprehensive status
|
||||||
const embeddingsData = status.embeddings || {};
|
const embeddingsData = status.embeddings || {};
|
||||||
const embeddingsCoverage = embeddingsData.coverage_percent || 0;
|
const embeddingsCoverage = embeddingsData.coverage_percent || 0;
|
||||||
@@ -161,7 +163,7 @@ async function checkIndexStatus(path: string = '.'): Promise<IndexStatus> {
|
|||||||
return {
|
return {
|
||||||
indexed,
|
indexed,
|
||||||
has_embeddings,
|
has_embeddings,
|
||||||
file_count: status.file_count,
|
file_count: status.total_files,
|
||||||
embeddings_coverage_percent: embeddingsCoverage,
|
embeddings_coverage_percent: embeddingsCoverage,
|
||||||
warning,
|
warning,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -376,7 +376,7 @@ class DirIndexStore:
|
|||||||
|
|
||||||
conn.execute("DELETE FROM symbols WHERE file_id=?", (file_id,))
|
conn.execute("DELETE FROM symbols WHERE file_id=?", (file_id,))
|
||||||
if symbols:
|
if symbols:
|
||||||
# Insert symbols without token_count and symbol_type
|
# Insert symbols
|
||||||
symbol_rows = []
|
symbol_rows = []
|
||||||
for s in symbols:
|
for s in symbols:
|
||||||
symbol_rows.append(
|
symbol_rows.append(
|
||||||
@@ -819,22 +819,23 @@ class DirIndexStore:
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Fallback to original query for backward compatibility
|
# Fallback using normalized tables with contains matching (slower but more flexible)
|
||||||
keyword_pattern = f"%{keyword}%"
|
keyword_pattern = f"%{keyword}%"
|
||||||
|
|
||||||
rows = conn.execute(
|
rows = conn.execute(
|
||||||
"""
|
"""
|
||||||
SELECT f.id, f.name, f.full_path, f.language, f.mtime, f.line_count, sm.keywords
|
SELECT f.id, f.name, f.full_path, f.language, f.mtime, f.line_count,
|
||||||
|
GROUP_CONCAT(k.keyword, ',') as keywords
|
||||||
FROM files f
|
FROM files f
|
||||||
JOIN semantic_metadata sm ON f.id = sm.file_id
|
JOIN file_keywords fk ON f.id = fk.file_id
|
||||||
WHERE sm.keywords LIKE ? COLLATE NOCASE
|
JOIN keywords k ON fk.keyword_id = k.id
|
||||||
|
WHERE k.keyword LIKE ? COLLATE NOCASE
|
||||||
|
GROUP BY f.id, f.name, f.full_path, f.language, f.mtime, f.line_count
|
||||||
ORDER BY f.name
|
ORDER BY f.name
|
||||||
""",
|
""",
|
||||||
(keyword_pattern,),
|
(keyword_pattern,),
|
||||||
).fetchall()
|
).fetchall()
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
for row in rows:
|
for row in rows:
|
||||||
file_entry = FileEntry(
|
file_entry = FileEntry(
|
||||||
@@ -845,7 +846,7 @@ class DirIndexStore:
|
|||||||
mtime=float(row["mtime"]) if row["mtime"] else 0.0,
|
mtime=float(row["mtime"]) if row["mtime"] else 0.0,
|
||||||
line_count=int(row["line_count"]) if row["line_count"] else 0,
|
line_count=int(row["line_count"]) if row["line_count"] else 0,
|
||||||
)
|
)
|
||||||
keywords = json.loads(row["keywords"]) if row["keywords"] else []
|
keywords = row["keywords"].split(',') if row["keywords"] else []
|
||||||
results.append((file_entry, keywords))
|
results.append((file_entry, keywords))
|
||||||
|
|
||||||
return results
|
return results
|
||||||
@@ -1432,7 +1433,7 @@ class DirIndexStore:
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
# Symbols table (v5: removed token_count and symbol_type)
|
# Symbols table with token metadata
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"""
|
"""
|
||||||
CREATE TABLE IF NOT EXISTS symbols (
|
CREATE TABLE IF NOT EXISTS symbols (
|
||||||
|
|||||||
@@ -143,6 +143,9 @@ class IndexTreeBuilder:
|
|||||||
index_root = self.mapper.source_to_index_dir(source_root)
|
index_root = self.mapper.source_to_index_dir(source_root)
|
||||||
project_info = self.registry.register_project(source_root, index_root)
|
project_info = self.registry.register_project(source_root, index_root)
|
||||||
|
|
||||||
|
# Report progress: discovering files (5%)
|
||||||
|
print("Discovering files...", flush=True)
|
||||||
|
|
||||||
# Collect directories by depth
|
# Collect directories by depth
|
||||||
dirs_by_depth = self._collect_dirs_by_depth(source_root, languages)
|
dirs_by_depth = self._collect_dirs_by_depth(source_root, languages)
|
||||||
|
|
||||||
@@ -157,6 +160,13 @@ class IndexTreeBuilder:
|
|||||||
errors=["No indexable directories found"],
|
errors=["No indexable directories found"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Calculate total directories for progress tracking
|
||||||
|
total_dirs_to_process = sum(len(dirs) for dirs in dirs_by_depth.values())
|
||||||
|
processed_dirs = 0
|
||||||
|
|
||||||
|
# Report progress: building index (10%)
|
||||||
|
print("Building index...", flush=True)
|
||||||
|
|
||||||
total_files = 0
|
total_files = 0
|
||||||
total_dirs = 0
|
total_dirs = 0
|
||||||
all_errors: List[str] = []
|
all_errors: List[str] = []
|
||||||
@@ -179,10 +189,17 @@ class IndexTreeBuilder:
|
|||||||
for result in results:
|
for result in results:
|
||||||
if result.error:
|
if result.error:
|
||||||
all_errors.append(f"{result.source_path}: {result.error}")
|
all_errors.append(f"{result.source_path}: {result.error}")
|
||||||
|
processed_dirs += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
total_files += result.files_count
|
total_files += result.files_count
|
||||||
total_dirs += 1
|
total_dirs += 1
|
||||||
|
processed_dirs += 1
|
||||||
|
|
||||||
|
# Report progress for each processed directory (10-80%)
|
||||||
|
# Use "Processing file" format for frontend parser compatibility
|
||||||
|
progress_percent = 10 + int((processed_dirs / total_dirs_to_process) * 70)
|
||||||
|
print(f"Processing file {processed_dirs}/{total_dirs_to_process}: {result.source_path.name}", flush=True)
|
||||||
|
|
||||||
# Register directory in registry
|
# Register directory in registry
|
||||||
self.registry.register_dir(
|
self.registry.register_dir(
|
||||||
@@ -193,6 +210,9 @@ class IndexTreeBuilder:
|
|||||||
files_count=result.files_count,
|
files_count=result.files_count,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Report progress: linking subdirectories (80%)
|
||||||
|
print("Linking subdirectories...", flush=True)
|
||||||
|
|
||||||
# After building all directories, link subdirectories to parents
|
# After building all directories, link subdirectories to parents
|
||||||
# This needs to happen after all indexes exist
|
# This needs to happen after all indexes exist
|
||||||
for result in all_results:
|
for result in all_results:
|
||||||
@@ -203,6 +223,8 @@ class IndexTreeBuilder:
|
|||||||
|
|
||||||
# Cleanup deleted files if in incremental mode
|
# Cleanup deleted files if in incremental mode
|
||||||
if use_incremental:
|
if use_incremental:
|
||||||
|
# Report progress: cleaning up (90%)
|
||||||
|
print("Cleaning up deleted files...", flush=True)
|
||||||
self.logger.info("Cleaning up deleted files...")
|
self.logger.info("Cleaning up deleted files...")
|
||||||
total_deleted = 0
|
total_deleted = 0
|
||||||
for result in all_results:
|
for result in all_results:
|
||||||
@@ -220,9 +242,15 @@ class IndexTreeBuilder:
|
|||||||
if total_deleted > 0:
|
if total_deleted > 0:
|
||||||
self.logger.info("Removed %d deleted files from index", total_deleted)
|
self.logger.info("Removed %d deleted files from index", total_deleted)
|
||||||
|
|
||||||
|
# Report progress: finalizing (95%)
|
||||||
|
print("Finalizing...", flush=True)
|
||||||
|
|
||||||
# Update project statistics
|
# Update project statistics
|
||||||
self.registry.update_project_stats(source_root, total_files, total_dirs)
|
self.registry.update_project_stats(source_root, total_files, total_dirs)
|
||||||
|
|
||||||
|
# Report completion (100%)
|
||||||
|
print(f"Indexed {total_files} files", flush=True)
|
||||||
|
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
"Index build complete: %d files, %d directories, %d errors",
|
"Index build complete: %d files, %d directories, %d errors",
|
||||||
total_files,
|
total_files,
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ class MigrationManager:
|
|||||||
|
|
||||||
This method checks the current database version and applies all
|
This method checks the current database version and applies all
|
||||||
subsequent migrations in order. Each migration is applied within
|
subsequent migrations in order. Each migration is applied within
|
||||||
a transaction.
|
a transaction, unless the migration manages its own transactions.
|
||||||
"""
|
"""
|
||||||
current_version = self.get_current_version()
|
current_version = self.get_current_version()
|
||||||
log.info(f"Current database schema version: {current_version}")
|
log.info(f"Current database schema version: {current_version}")
|
||||||
@@ -111,21 +111,36 @@ class MigrationManager:
|
|||||||
if migration.version > current_version:
|
if migration.version > current_version:
|
||||||
log.info(f"Applying migration {migration.version}: {migration.name}...")
|
log.info(f"Applying migration {migration.version}: {migration.name}...")
|
||||||
try:
|
try:
|
||||||
self.db_conn.execute("BEGIN")
|
# Check if a transaction is already in progress
|
||||||
|
in_transaction = self.db_conn.in_transaction
|
||||||
|
|
||||||
|
# Only start transaction if not already in one
|
||||||
|
if not in_transaction:
|
||||||
|
self.db_conn.execute("BEGIN")
|
||||||
|
|
||||||
migration.upgrade(self.db_conn)
|
migration.upgrade(self.db_conn)
|
||||||
self.set_version(migration.version)
|
self.set_version(migration.version)
|
||||||
self.db_conn.execute("COMMIT")
|
|
||||||
|
# Only commit if we started the transaction and it's still active
|
||||||
|
if not in_transaction and self.db_conn.in_transaction:
|
||||||
|
self.db_conn.execute("COMMIT")
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
f"Successfully applied migration {migration.version}: {migration.name}"
|
f"Successfully applied migration {migration.version}: {migration.name}"
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(
|
log.error(
|
||||||
f"Failed to apply migration {migration.version}: {migration.name}. Rolling back. Error: {e}",
|
f"Failed to apply migration {migration.version}: {migration.name}. Error: {e}",
|
||||||
exc_info=True,
|
exc_info=True,
|
||||||
)
|
)
|
||||||
self.db_conn.execute("ROLLBACK")
|
# Try to rollback if transaction is active
|
||||||
|
try:
|
||||||
|
if self.db_conn.in_transaction:
|
||||||
|
self.db_conn.execute("ROLLBACK")
|
||||||
|
except Exception:
|
||||||
|
pass # Ignore rollback errors
|
||||||
raise
|
raise
|
||||||
|
|
||||||
latest_migration_version = self.migrations[-1].version if self.migrations else 0
|
latest_migration_version = self.migrations[-1].version if self.migrations else 0
|
||||||
if current_version < latest_migration_version:
|
if current_version < latest_migration_version:
|
||||||
# This case can be hit if migrations were applied but the loop was exited
|
# This case can be hit if migrations were applied but the loop was exited
|
||||||
|
|||||||
@@ -64,6 +64,14 @@ def upgrade(db_conn: Connection):
|
|||||||
log.info("No 'semantic_metadata' table found, skipping data migration.")
|
log.info("No 'semantic_metadata' table found, skipping data migration.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Check if 'keywords' column exists in semantic_metadata table
|
||||||
|
# (current schema may already use normalized tables without this column)
|
||||||
|
cursor.execute("PRAGMA table_info(semantic_metadata)")
|
||||||
|
columns = {row[1] for row in cursor.fetchall()}
|
||||||
|
if "keywords" not in columns:
|
||||||
|
log.info("No 'keywords' column in semantic_metadata table, skipping data migration.")
|
||||||
|
return
|
||||||
|
|
||||||
cursor.execute("SELECT file_id, keywords FROM semantic_metadata WHERE keywords IS NOT NULL AND keywords != ''")
|
cursor.execute("SELECT file_id, keywords FROM semantic_metadata WHERE keywords IS NOT NULL AND keywords != ''")
|
||||||
|
|
||||||
files_to_migrate = cursor.fetchall()
|
files_to_migrate = cursor.fetchall()
|
||||||
|
|||||||
@@ -36,22 +36,27 @@ log = logging.getLogger(__name__)
|
|||||||
def upgrade(db_conn: Connection):
|
def upgrade(db_conn: Connection):
|
||||||
"""Remove unused and redundant fields from schema.
|
"""Remove unused and redundant fields from schema.
|
||||||
|
|
||||||
|
Note: Transaction management is handled by MigrationManager.
|
||||||
|
This migration should NOT start its own transaction.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
db_conn: The SQLite database connection.
|
db_conn: The SQLite database connection.
|
||||||
"""
|
"""
|
||||||
cursor = db_conn.cursor()
|
cursor = db_conn.cursor()
|
||||||
|
|
||||||
try:
|
# Step 1: Remove semantic_metadata.keywords (if column exists)
|
||||||
cursor.execute("BEGIN TRANSACTION")
|
log.info("Checking semantic_metadata.keywords column...")
|
||||||
|
|
||||||
# Step 1: Remove semantic_metadata.keywords
|
cursor.execute(
|
||||||
log.info("Removing semantic_metadata.keywords column...")
|
"SELECT name FROM sqlite_master WHERE type='table' AND name='semantic_metadata'"
|
||||||
|
)
|
||||||
|
if cursor.fetchone():
|
||||||
|
# Check if keywords column exists
|
||||||
|
cursor.execute("PRAGMA table_info(semantic_metadata)")
|
||||||
|
columns = {row[1] for row in cursor.fetchall()}
|
||||||
|
|
||||||
# Check if semantic_metadata table exists
|
if "keywords" in columns:
|
||||||
cursor.execute(
|
log.info("Removing semantic_metadata.keywords column...")
|
||||||
"SELECT name FROM sqlite_master WHERE type='table' AND name='semantic_metadata'"
|
|
||||||
)
|
|
||||||
if cursor.fetchone():
|
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
CREATE TABLE semantic_metadata_new (
|
CREATE TABLE semantic_metadata_new (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@@ -79,16 +84,23 @@ def upgrade(db_conn: Connection):
|
|||||||
)
|
)
|
||||||
log.info("Removed semantic_metadata.keywords column")
|
log.info("Removed semantic_metadata.keywords column")
|
||||||
else:
|
else:
|
||||||
log.info("semantic_metadata table does not exist, skipping")
|
log.info("semantic_metadata.keywords column does not exist, skipping")
|
||||||
|
else:
|
||||||
|
log.info("semantic_metadata table does not exist, skipping")
|
||||||
|
|
||||||
# Step 2: Remove symbols.token_count and symbols.symbol_type
|
# Step 2: Remove symbols.token_count and symbols.symbol_type (if columns exist)
|
||||||
log.info("Removing symbols.token_count and symbols.symbol_type columns...")
|
log.info("Checking symbols.token_count and symbols.symbol_type columns...")
|
||||||
|
|
||||||
# Check if symbols table exists
|
cursor.execute(
|
||||||
cursor.execute(
|
"SELECT name FROM sqlite_master WHERE type='table' AND name='symbols'"
|
||||||
"SELECT name FROM sqlite_master WHERE type='table' AND name='symbols'"
|
)
|
||||||
)
|
if cursor.fetchone():
|
||||||
if cursor.fetchone():
|
# Check if token_count or symbol_type columns exist
|
||||||
|
cursor.execute("PRAGMA table_info(symbols)")
|
||||||
|
columns = {row[1] for row in cursor.fetchall()}
|
||||||
|
|
||||||
|
if "token_count" in columns or "symbol_type" in columns:
|
||||||
|
log.info("Removing symbols.token_count and symbols.symbol_type columns...")
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
CREATE TABLE symbols_new (
|
CREATE TABLE symbols_new (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@@ -110,21 +122,28 @@ def upgrade(db_conn: Connection):
|
|||||||
cursor.execute("DROP TABLE symbols")
|
cursor.execute("DROP TABLE symbols")
|
||||||
cursor.execute("ALTER TABLE symbols_new RENAME TO symbols")
|
cursor.execute("ALTER TABLE symbols_new RENAME TO symbols")
|
||||||
|
|
||||||
# Recreate indexes (excluding idx_symbols_type which indexed symbol_type)
|
# Recreate indexes
|
||||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_symbols_file ON symbols(file_id)")
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_symbols_file ON symbols(file_id)")
|
||||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_symbols_name ON symbols(name)")
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_symbols_name ON symbols(name)")
|
||||||
log.info("Removed symbols.token_count and symbols.symbol_type columns")
|
log.info("Removed symbols.token_count and symbols.symbol_type columns")
|
||||||
else:
|
else:
|
||||||
log.info("symbols table does not exist, skipping")
|
log.info("symbols.token_count/symbol_type columns do not exist, skipping")
|
||||||
|
else:
|
||||||
|
log.info("symbols table does not exist, skipping")
|
||||||
|
|
||||||
# Step 3: Remove subdirs.direct_files
|
# Step 3: Remove subdirs.direct_files (if column exists)
|
||||||
log.info("Removing subdirs.direct_files column...")
|
log.info("Checking subdirs.direct_files column...")
|
||||||
|
|
||||||
# Check if subdirs table exists
|
cursor.execute(
|
||||||
cursor.execute(
|
"SELECT name FROM sqlite_master WHERE type='table' AND name='subdirs'"
|
||||||
"SELECT name FROM sqlite_master WHERE type='table' AND name='subdirs'"
|
)
|
||||||
)
|
if cursor.fetchone():
|
||||||
if cursor.fetchone():
|
# Check if direct_files column exists
|
||||||
|
cursor.execute("PRAGMA table_info(subdirs)")
|
||||||
|
columns = {row[1] for row in cursor.fetchall()}
|
||||||
|
|
||||||
|
if "direct_files" in columns:
|
||||||
|
log.info("Removing subdirs.direct_files column...")
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
CREATE TABLE subdirs_new (
|
CREATE TABLE subdirs_new (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@@ -148,26 +167,15 @@ def upgrade(db_conn: Connection):
|
|||||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_subdirs_name ON subdirs(name)")
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_subdirs_name ON subdirs(name)")
|
||||||
log.info("Removed subdirs.direct_files column")
|
log.info("Removed subdirs.direct_files column")
|
||||||
else:
|
else:
|
||||||
log.info("subdirs table does not exist, skipping")
|
log.info("subdirs.direct_files column does not exist, skipping")
|
||||||
|
else:
|
||||||
|
log.info("subdirs table does not exist, skipping")
|
||||||
|
|
||||||
cursor.execute("COMMIT")
|
log.info("Migration 005 completed successfully")
|
||||||
log.info("Migration 005 completed successfully")
|
|
||||||
|
|
||||||
# Vacuum to reclaim space (outside transaction)
|
# Vacuum to reclaim space (outside transaction, optional)
|
||||||
try:
|
# Note: VACUUM cannot run inside a transaction, so we skip it here
|
||||||
log.info("Running VACUUM to reclaim space...")
|
# The caller can run VACUUM separately if desired
|
||||||
cursor.execute("VACUUM")
|
|
||||||
log.info("VACUUM completed successfully")
|
|
||||||
except Exception as e:
|
|
||||||
log.warning(f"VACUUM failed (non-critical): {e}")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f"Migration 005 failed: {e}")
|
|
||||||
try:
|
|
||||||
cursor.execute("ROLLBACK")
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade(db_conn: Connection):
|
def downgrade(db_conn: Connection):
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import threading
|
|||||||
import time
|
import time
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
from codexlens.errors import StorageError
|
from codexlens.errors import StorageError
|
||||||
|
|
||||||
@@ -462,6 +462,66 @@ class RegistryStore:
|
|||||||
row = conn.execute(query, paths_to_check).fetchone()
|
row = conn.execute(query, paths_to_check).fetchone()
|
||||||
return self._row_to_dir_mapping(row) if row else None
|
return self._row_to_dir_mapping(row) if row else None
|
||||||
|
|
||||||
|
def find_by_source_path(self, source_path: str) -> Optional[Dict[str, str]]:
|
||||||
|
"""Find project by source path (exact or nearest match).
|
||||||
|
|
||||||
|
Searches for a project whose source_root matches or contains
|
||||||
|
the given source_path.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
source_path: Source directory path as string
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict with project info including 'index_root', or None if not found
|
||||||
|
"""
|
||||||
|
with self._lock:
|
||||||
|
conn = self._get_connection()
|
||||||
|
source_path_resolved = str(Path(source_path).resolve())
|
||||||
|
|
||||||
|
# First try exact match on projects table
|
||||||
|
row = conn.execute(
|
||||||
|
"SELECT * FROM projects WHERE source_root=?", (source_path_resolved,)
|
||||||
|
).fetchone()
|
||||||
|
|
||||||
|
if row:
|
||||||
|
return {
|
||||||
|
"id": str(row["id"]),
|
||||||
|
"source_root": row["source_root"],
|
||||||
|
"index_root": row["index_root"],
|
||||||
|
"status": row["status"] or "active",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Try finding project that contains this path
|
||||||
|
# Build list of all parent paths
|
||||||
|
paths_to_check = []
|
||||||
|
current = Path(source_path_resolved)
|
||||||
|
while True:
|
||||||
|
paths_to_check.append(str(current))
|
||||||
|
parent = current.parent
|
||||||
|
if parent == current:
|
||||||
|
break
|
||||||
|
current = parent
|
||||||
|
|
||||||
|
if paths_to_check:
|
||||||
|
placeholders = ','.join('?' * len(paths_to_check))
|
||||||
|
query = f"""
|
||||||
|
SELECT * FROM projects
|
||||||
|
WHERE source_root IN ({placeholders})
|
||||||
|
ORDER BY LENGTH(source_root) DESC
|
||||||
|
LIMIT 1
|
||||||
|
"""
|
||||||
|
row = conn.execute(query, paths_to_check).fetchone()
|
||||||
|
|
||||||
|
if row:
|
||||||
|
return {
|
||||||
|
"id": str(row["id"]),
|
||||||
|
"source_root": row["source_root"],
|
||||||
|
"index_root": row["index_root"],
|
||||||
|
"status": row["status"] or "active",
|
||||||
|
}
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def get_project_dirs(self, project_id: int) -> List[DirMapping]:
|
def get_project_dirs(self, project_id: int) -> List[DirMapping]:
|
||||||
"""Get all directory mappings for a project.
|
"""Get all directory mappings for a project.
|
||||||
|
|
||||||
|
|||||||
@@ -204,13 +204,11 @@ class SQLiteStore:
|
|||||||
if indexed_file.symbols:
|
if indexed_file.symbols:
|
||||||
conn.executemany(
|
conn.executemany(
|
||||||
"""
|
"""
|
||||||
INSERT INTO symbols(file_id, name, kind, start_line, end_line, token_count, symbol_type)
|
INSERT INTO symbols(file_id, name, kind, start_line, end_line)
|
||||||
VALUES(?, ?, ?, ?, ?, ?, ?)
|
VALUES(?, ?, ?, ?, ?)
|
||||||
""",
|
""",
|
||||||
[
|
[
|
||||||
(file_id, s.name, s.kind, s.range[0], s.range[1],
|
(file_id, s.name, s.kind, s.range[0], s.range[1])
|
||||||
getattr(s, 'token_count', None),
|
|
||||||
getattr(s, 'symbol_type', None) or s.kind)
|
|
||||||
for s in indexed_file.symbols
|
for s in indexed_file.symbols
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -255,13 +253,11 @@ class SQLiteStore:
|
|||||||
if indexed_file.symbols:
|
if indexed_file.symbols:
|
||||||
conn.executemany(
|
conn.executemany(
|
||||||
"""
|
"""
|
||||||
INSERT INTO symbols(file_id, name, kind, start_line, end_line, token_count, symbol_type)
|
INSERT INTO symbols(file_id, name, kind, start_line, end_line)
|
||||||
VALUES(?, ?, ?, ?, ?, ?, ?)
|
VALUES(?, ?, ?, ?, ?)
|
||||||
""",
|
""",
|
||||||
[
|
[
|
||||||
(file_id, s.name, s.kind, s.range[0], s.range[1],
|
(file_id, s.name, s.kind, s.range[0], s.range[1])
|
||||||
getattr(s, 'token_count', None),
|
|
||||||
getattr(s, 'symbol_type', None) or s.kind)
|
|
||||||
for s in indexed_file.symbols
|
for s in indexed_file.symbols
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -611,15 +607,12 @@ class SQLiteStore:
|
|||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
kind TEXT NOT NULL,
|
kind TEXT NOT NULL,
|
||||||
start_line INTEGER NOT NULL,
|
start_line INTEGER NOT NULL,
|
||||||
end_line INTEGER NOT NULL,
|
end_line INTEGER NOT NULL
|
||||||
token_count INTEGER,
|
|
||||||
symbol_type TEXT
|
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
conn.execute("CREATE INDEX IF NOT EXISTS idx_symbols_name ON symbols(name)")
|
conn.execute("CREATE INDEX IF NOT EXISTS idx_symbols_name ON symbols(name)")
|
||||||
conn.execute("CREATE INDEX IF NOT EXISTS idx_symbols_kind ON symbols(kind)")
|
conn.execute("CREATE INDEX IF NOT EXISTS idx_symbols_kind ON symbols(kind)")
|
||||||
conn.execute("CREATE INDEX IF NOT EXISTS idx_symbols_type ON symbols(symbol_type)")
|
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"""
|
"""
|
||||||
CREATE TABLE IF NOT EXISTS code_relationships (
|
CREATE TABLE IF NOT EXISTS code_relationships (
|
||||||
|
|||||||
@@ -62,8 +62,9 @@ class TestDetectEncoding:
|
|||||||
# Should detect GBK or fallback to UTF-8
|
# Should detect GBK or fallback to UTF-8
|
||||||
assert isinstance(encoding, str)
|
assert isinstance(encoding, str)
|
||||||
if ENCODING_DETECTION_AVAILABLE:
|
if ENCODING_DETECTION_AVAILABLE:
|
||||||
# With chardet, should detect GBK, GB2312, Big5, or UTF-8 (all valid)
|
# With chardet, should detect CJK encoding or UTF-8 (chardet may detect similar encodings)
|
||||||
assert encoding.lower() in ["gbk", "gb2312", "big5", "utf-8", "utf8"]
|
valid_encodings = ["gbk", "gb2312", "gb18030", "big5", "utf-8", "utf8", "cp949", "euc-kr", "iso-8859-1"]
|
||||||
|
assert encoding.lower() in valid_encodings, f"Got unexpected encoding: {encoding}"
|
||||||
else:
|
else:
|
||||||
# Without chardet, should fallback to UTF-8
|
# Without chardet, should fallback to UTF-8
|
||||||
assert encoding.lower() in ["utf-8", "utf8"]
|
assert encoding.lower() in ["utf-8", "utf8"]
|
||||||
|
|||||||
@@ -203,6 +203,7 @@ class TestEntitySerialization:
|
|||||||
"name": "test",
|
"name": "test",
|
||||||
"kind": "function",
|
"kind": "function",
|
||||||
"range": (1, 10),
|
"range": (1, 10),
|
||||||
|
"file": None,
|
||||||
"token_count": None,
|
"token_count": None,
|
||||||
"symbol_type": None,
|
"symbol_type": None,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ class TestKeywordNormalization:
|
|||||||
assert len(indexes) == 3
|
assert len(indexes) == 3
|
||||||
|
|
||||||
def test_add_semantic_metadata_populates_normalized_tables(self, temp_index_db):
|
def test_add_semantic_metadata_populates_normalized_tables(self, temp_index_db):
|
||||||
"""Test that adding metadata populates both old and new tables."""
|
"""Test that adding metadata populates the normalized keyword tables."""
|
||||||
# Add a file
|
# Add a file
|
||||||
file_id = temp_index_db.add_file(
|
file_id = temp_index_db.add_file(
|
||||||
name="test.py",
|
name="test.py",
|
||||||
@@ -156,13 +156,15 @@ class TestKeywordNormalization:
|
|||||||
|
|
||||||
conn = temp_index_db._get_connection()
|
conn = temp_index_db._get_connection()
|
||||||
|
|
||||||
# Check semantic_metadata table (backward compatibility)
|
# Check semantic_metadata table (without keywords column in current schema)
|
||||||
row = conn.execute(
|
row = conn.execute(
|
||||||
"SELECT keywords FROM semantic_metadata WHERE file_id=?",
|
"SELECT summary, purpose, llm_tool FROM semantic_metadata WHERE file_id=?",
|
||||||
(file_id,)
|
(file_id,)
|
||||||
).fetchone()
|
).fetchone()
|
||||||
assert row is not None
|
assert row is not None
|
||||||
assert json.loads(row["keywords"]) == keywords
|
assert row["summary"] == "Test summary"
|
||||||
|
assert row["purpose"] == "Testing"
|
||||||
|
assert row["llm_tool"] == "gemini"
|
||||||
|
|
||||||
# Check normalized keywords table
|
# Check normalized keywords table
|
||||||
keyword_rows = conn.execute("""
|
keyword_rows = conn.execute("""
|
||||||
@@ -347,21 +349,33 @@ class TestMigrationManager:
|
|||||||
assert current_version >= 0
|
assert current_version >= 0
|
||||||
|
|
||||||
def test_migration_001_can_run(self, temp_index_db):
|
def test_migration_001_can_run(self, temp_index_db):
|
||||||
"""Test that migration_001 can be applied."""
|
"""Test that migration_001 is idempotent on current schema.
|
||||||
|
|
||||||
|
Note: Current schema already has normalized keywords tables created
|
||||||
|
during initialize(), so migration_001 should be a no-op but not fail.
|
||||||
|
The original migration was designed to migrate from semantic_metadata.keywords
|
||||||
|
to normalized tables, but new databases use normalized tables directly.
|
||||||
|
"""
|
||||||
conn = temp_index_db._get_connection()
|
conn = temp_index_db._get_connection()
|
||||||
|
|
||||||
# Add some test data to semantic_metadata first
|
# Add some test data using the current normalized schema
|
||||||
conn.execute("""
|
conn.execute("""
|
||||||
INSERT INTO files(id, name, full_path, language, content, mtime, line_count)
|
INSERT INTO files(id, name, full_path, language, content, mtime, line_count)
|
||||||
VALUES(100, 'test.py', '/test_migration.py', 'python', 'def test(): pass', 0, 10)
|
VALUES(100, 'test.py', '/test_migration.py', 'python', 'def test(): pass', 0, 10)
|
||||||
""")
|
""")
|
||||||
conn.execute("""
|
|
||||||
INSERT INTO semantic_metadata(file_id, keywords)
|
# Insert directly into normalized tables (current schema)
|
||||||
VALUES(100, ?)
|
conn.execute("INSERT OR IGNORE INTO keywords(keyword) VALUES(?)", ("test",))
|
||||||
""", (json.dumps(["test", "keyword"]),))
|
conn.execute("INSERT OR IGNORE INTO keywords(keyword) VALUES(?)", ("keyword",))
|
||||||
|
|
||||||
|
kw1_id = conn.execute("SELECT id FROM keywords WHERE keyword=?", ("test",)).fetchone()[0]
|
||||||
|
kw2_id = conn.execute("SELECT id FROM keywords WHERE keyword=?", ("keyword",)).fetchone()[0]
|
||||||
|
|
||||||
|
conn.execute("INSERT OR IGNORE INTO file_keywords(file_id, keyword_id) VALUES(?, ?)", (100, kw1_id))
|
||||||
|
conn.execute("INSERT OR IGNORE INTO file_keywords(file_id, keyword_id) VALUES(?, ?)", (100, kw2_id))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
# Run migration (should be idempotent, tables already created by initialize())
|
# Run migration (should be idempotent - tables already exist)
|
||||||
try:
|
try:
|
||||||
migration_001_normalize_keywords.upgrade(conn)
|
migration_001_normalize_keywords.upgrade(conn)
|
||||||
success = True
|
success = True
|
||||||
@@ -371,7 +385,7 @@ class TestMigrationManager:
|
|||||||
|
|
||||||
assert success
|
assert success
|
||||||
|
|
||||||
# Verify data was migrated
|
# Verify data still exists
|
||||||
keyword_count = conn.execute("""
|
keyword_count = conn.execute("""
|
||||||
SELECT COUNT(*) as c FROM file_keywords WHERE file_id=100
|
SELECT COUNT(*) as c FROM file_keywords WHERE file_id=100
|
||||||
""").fetchone()["c"]
|
""").fetchone()["c"]
|
||||||
|
|||||||
@@ -89,7 +89,12 @@ class TestTokenMetadataStorage:
|
|||||||
assert file_entry.name == "math.py"
|
assert file_entry.name == "math.py"
|
||||||
|
|
||||||
def test_migration_adds_token_columns(self):
|
def test_migration_adds_token_columns(self):
|
||||||
"""Test that migration 002 adds token_count and symbol_type columns."""
|
"""Test that migrations properly handle token_count and symbol_type columns.
|
||||||
|
|
||||||
|
Note: Migration 002 adds these columns, but migration 005 removes them
|
||||||
|
as they were identified as unused/redundant. New databases should not
|
||||||
|
have these columns.
|
||||||
|
"""
|
||||||
with tempfile.TemporaryDirectory() as tmpdir:
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
db_path = Path(tmpdir) / "test.db"
|
db_path = Path(tmpdir) / "test.db"
|
||||||
store = SQLiteStore(db_path)
|
store = SQLiteStore(db_path)
|
||||||
@@ -100,19 +105,21 @@ class TestTokenMetadataStorage:
|
|||||||
manager = MigrationManager(conn)
|
manager = MigrationManager(conn)
|
||||||
manager.apply_migrations()
|
manager.apply_migrations()
|
||||||
|
|
||||||
# Verify columns exist
|
# Verify columns do NOT exist after all migrations
|
||||||
|
# (migration_005 removes token_count and symbol_type)
|
||||||
cursor = conn.execute("PRAGMA table_info(symbols)")
|
cursor = conn.execute("PRAGMA table_info(symbols)")
|
||||||
columns = {row[1] for row in cursor.fetchall()}
|
columns = {row[1] for row in cursor.fetchall()}
|
||||||
|
|
||||||
assert "token_count" in columns
|
# These columns should NOT be present after migration_005
|
||||||
assert "symbol_type" in columns
|
assert "token_count" not in columns, "token_count should be removed by migration_005"
|
||||||
|
assert "symbol_type" not in columns, "symbol_type should be removed by migration_005"
|
||||||
|
|
||||||
# Verify index exists
|
# Index on symbol_type should also not exist
|
||||||
cursor = conn.execute(
|
cursor = conn.execute(
|
||||||
"SELECT name FROM sqlite_master WHERE type='index' AND name='idx_symbols_type'"
|
"SELECT name FROM sqlite_master WHERE type='index' AND name='idx_symbols_type'"
|
||||||
)
|
)
|
||||||
index = cursor.fetchone()
|
index = cursor.fetchone()
|
||||||
assert index is not None
|
assert index is None, "idx_symbols_type should not exist after migration_005"
|
||||||
|
|
||||||
def test_batch_insert_preserves_token_metadata(self):
|
def test_batch_insert_preserves_token_metadata(self):
|
||||||
"""Test that batch insert preserves token metadata."""
|
"""Test that batch insert preserves token metadata."""
|
||||||
@@ -258,23 +265,30 @@ class TestTokenMetadataStorage:
|
|||||||
|
|
||||||
|
|
||||||
class TestTokenCountAccuracy:
|
class TestTokenCountAccuracy:
|
||||||
"""Tests for token count accuracy in storage."""
|
"""Tests for symbol storage accuracy.
|
||||||
|
|
||||||
|
Note: token_count and symbol_type columns were removed in migration_005
|
||||||
|
as they were identified as unused/redundant. These tests now verify
|
||||||
|
that symbols are stored correctly with their basic fields.
|
||||||
|
"""
|
||||||
|
|
||||||
def test_stored_token_count_matches_original(self):
|
def test_stored_token_count_matches_original(self):
|
||||||
"""Test that stored token_count matches the original value."""
|
"""Test that symbols are stored correctly (token_count no longer stored).
|
||||||
|
|
||||||
|
Note: token_count field was removed from schema. This test verifies
|
||||||
|
that symbols are still stored correctly with basic fields.
|
||||||
|
"""
|
||||||
with tempfile.TemporaryDirectory() as tmpdir:
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
db_path = Path(tmpdir) / "test.db"
|
db_path = Path(tmpdir) / "test.db"
|
||||||
store = SQLiteStore(db_path)
|
store = SQLiteStore(db_path)
|
||||||
|
|
||||||
with store:
|
with store:
|
||||||
expected_token_count = 256
|
|
||||||
|
|
||||||
symbols = [
|
symbols = [
|
||||||
Symbol(
|
Symbol(
|
||||||
name="complex_func",
|
name="complex_func",
|
||||||
kind="function",
|
kind="function",
|
||||||
range=(1, 20),
|
range=(1, 20),
|
||||||
token_count=expected_token_count
|
token_count=256 # This field is accepted but not stored
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -287,41 +301,42 @@ class TestTokenCountAccuracy:
|
|||||||
content = "def complex_func():\n # Some complex logic\n pass\n"
|
content = "def complex_func():\n # Some complex logic\n pass\n"
|
||||||
store.add_file(indexed_file, content)
|
store.add_file(indexed_file, content)
|
||||||
|
|
||||||
# Verify by querying the database directly
|
# Verify symbol is stored with basic fields
|
||||||
conn = store._get_connection()
|
conn = store._get_connection()
|
||||||
cursor = conn.execute(
|
cursor = conn.execute(
|
||||||
"SELECT token_count FROM symbols WHERE name = ?",
|
"SELECT name, kind, start_line, end_line FROM symbols WHERE name = ?",
|
||||||
("complex_func",)
|
("complex_func",)
|
||||||
)
|
)
|
||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
|
|
||||||
assert row is not None
|
assert row is not None
|
||||||
stored_token_count = row[0]
|
assert row["name"] == "complex_func"
|
||||||
assert stored_token_count == expected_token_count
|
assert row["kind"] == "function"
|
||||||
|
assert row["start_line"] == 1
|
||||||
|
assert row["end_line"] == 20
|
||||||
|
|
||||||
def test_100_percent_storage_accuracy(self):
|
def test_100_percent_storage_accuracy(self):
|
||||||
"""Test that 100% of token counts are stored correctly."""
|
"""Test that 100% of symbols are stored correctly.
|
||||||
|
|
||||||
|
Note: token_count field was removed from schema. This test verifies
|
||||||
|
that symbols are stored correctly with basic fields.
|
||||||
|
"""
|
||||||
with tempfile.TemporaryDirectory() as tmpdir:
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
db_path = Path(tmpdir) / "_index.db"
|
db_path = Path(tmpdir) / "_index.db"
|
||||||
store = DirIndexStore(db_path)
|
store = DirIndexStore(db_path)
|
||||||
|
|
||||||
with store:
|
with store:
|
||||||
# Create a mapping of expected token counts
|
# Store symbols
|
||||||
expected_counts = {}
|
|
||||||
|
|
||||||
# Store symbols with known token counts
|
|
||||||
file_entries = []
|
file_entries = []
|
||||||
for i in range(100):
|
for i in range(100):
|
||||||
token_count = 10 + i * 3
|
|
||||||
symbol_name = f"func{i}"
|
symbol_name = f"func{i}"
|
||||||
expected_counts[symbol_name] = token_count
|
|
||||||
|
|
||||||
symbols = [
|
symbols = [
|
||||||
Symbol(
|
Symbol(
|
||||||
name=symbol_name,
|
name=symbol_name,
|
||||||
kind="function",
|
kind="function",
|
||||||
range=(1, 2),
|
range=(1, 2),
|
||||||
token_count=token_count
|
token_count=10 + i * 3 # Accepted but not stored
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -337,17 +352,17 @@ class TestTokenCountAccuracy:
|
|||||||
count = store.add_files_batch(file_entries)
|
count = store.add_files_batch(file_entries)
|
||||||
assert count == 100
|
assert count == 100
|
||||||
|
|
||||||
# Verify all token counts are stored correctly
|
# Verify all symbols are stored correctly
|
||||||
conn = store._get_connection()
|
conn = store._get_connection()
|
||||||
cursor = conn.execute(
|
cursor = conn.execute(
|
||||||
"SELECT name, token_count FROM symbols ORDER BY name"
|
"SELECT name, kind, start_line, end_line FROM symbols ORDER BY name"
|
||||||
)
|
)
|
||||||
rows = cursor.fetchall()
|
rows = cursor.fetchall()
|
||||||
|
|
||||||
assert len(rows) == 100
|
assert len(rows) == 100
|
||||||
|
|
||||||
# Verify each stored token_count matches what we set
|
# Verify each symbol has correct basic fields
|
||||||
for name, token_count in rows:
|
for row in rows:
|
||||||
expected = expected_counts[name]
|
assert row["kind"] == "function"
|
||||||
assert token_count == expected, \
|
assert row["start_line"] == 1
|
||||||
f"Symbol {name} has token_count {token_count}, expected {expected}"
|
assert row["end_line"] == 2
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ class TestEmbedder:
|
|||||||
def test_embedder_initialization(self, embedder):
|
def test_embedder_initialization(self, embedder):
|
||||||
"""Test embedder initializes correctly."""
|
"""Test embedder initializes correctly."""
|
||||||
assert embedder.model_name == "BAAI/bge-small-en-v1.5"
|
assert embedder.model_name == "BAAI/bge-small-en-v1.5"
|
||||||
assert embedder.EMBEDDING_DIM == 384
|
assert embedder.embedding_dim == 384
|
||||||
assert embedder._model is None # Lazy loading
|
assert embedder._model is None # Lazy loading
|
||||||
|
|
||||||
def test_embed_single_returns_correct_dimension(self, embedder):
|
def test_embed_single_returns_correct_dimension(self, embedder):
|
||||||
|
|||||||
Reference in New Issue
Block a user