claude-code-workflow 6.3.36 → 6.3.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/workflow/lite-fix.md +108 -9
- package/.claude/skills/ccw-loop/README.md +303 -0
- package/.claude/skills/ccw-loop/SKILL.md +259 -0
- package/.claude/skills/ccw-loop/phases/actions/action-complete.md +320 -0
- package/.claude/skills/ccw-loop/phases/actions/action-debug-with-file.md +485 -0
- package/.claude/skills/ccw-loop/phases/actions/action-develop-with-file.md +365 -0
- package/.claude/skills/ccw-loop/phases/actions/action-init.md +200 -0
- package/.claude/skills/ccw-loop/phases/actions/action-menu.md +192 -0
- package/.claude/skills/ccw-loop/phases/actions/action-validate-with-file.md +307 -0
- package/.claude/skills/ccw-loop/phases/orchestrator.md +486 -0
- package/.claude/skills/ccw-loop/phases/state-schema.md +474 -0
- package/.claude/skills/ccw-loop/specs/action-catalog.md +300 -0
- package/.claude/skills/ccw-loop/specs/loop-requirements.md +192 -0
- package/.claude/skills/ccw-loop/templates/progress-template.md +175 -0
- package/.claude/skills/ccw-loop/templates/understanding-template.md +303 -0
- package/.claude/skills/ccw-loop/templates/validation-template.md +258 -0
- package/ccw/dist/cli.d.ts.map +1 -1
- package/ccw/dist/cli.js +8 -1
- package/ccw/dist/cli.js.map +1 -1
- package/ccw/dist/commands/cli.d.ts.map +1 -1
- package/ccw/dist/commands/cli.js +14 -1
- package/ccw/dist/commands/cli.js.map +1 -1
- package/ccw/dist/commands/loop.d.ts +10 -0
- package/ccw/dist/commands/loop.d.ts.map +1 -0
- package/ccw/dist/commands/loop.js +289 -0
- package/ccw/dist/commands/loop.js.map +1 -0
- package/ccw/dist/core/dashboard-generator.d.ts.map +1 -1
- package/ccw/dist/core/dashboard-generator.js +4 -1
- package/ccw/dist/core/dashboard-generator.js.map +1 -1
- package/ccw/dist/core/routes/claude-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/claude-routes.js +5 -3
- package/ccw/dist/core/routes/claude-routes.js.map +1 -1
- package/ccw/dist/core/routes/cli-routes.d.ts +6 -0
- package/ccw/dist/core/routes/cli-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/cli-routes.js +42 -13
- package/ccw/dist/core/routes/cli-routes.js.map +1 -1
- package/ccw/dist/core/routes/cli-settings-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/cli-settings-routes.js +44 -0
- package/ccw/dist/core/routes/cli-settings-routes.js.map +1 -1
- package/ccw/dist/core/routes/codexlens/semantic-handlers.d.ts.map +1 -1
- package/ccw/dist/core/routes/codexlens/semantic-handlers.js +3 -2
- package/ccw/dist/core/routes/codexlens/semantic-handlers.js.map +1 -1
- package/ccw/dist/core/routes/core-memory-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/core-memory-routes.js +4 -2
- package/ccw/dist/core/routes/core-memory-routes.js.map +1 -1
- package/ccw/dist/core/routes/files-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/files-routes.js +4 -2
- package/ccw/dist/core/routes/files-routes.js.map +1 -1
- package/ccw/dist/core/routes/loop-routes.d.ts +24 -0
- package/ccw/dist/core/routes/loop-routes.d.ts.map +1 -0
- package/ccw/dist/core/routes/loop-routes.js +334 -0
- package/ccw/dist/core/routes/loop-routes.js.map +1 -0
- package/ccw/dist/core/routes/loop-v2-routes.d.ts +35 -0
- package/ccw/dist/core/routes/loop-v2-routes.d.ts.map +1 -0
- package/ccw/dist/core/routes/loop-v2-routes.js +1208 -0
- package/ccw/dist/core/routes/loop-v2-routes.js.map +1 -0
- package/ccw/dist/core/routes/memory-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/memory-routes.js +2 -1
- package/ccw/dist/core/routes/memory-routes.js.map +1 -1
- package/ccw/dist/core/routes/task-routes.d.ts +12 -0
- package/ccw/dist/core/routes/task-routes.d.ts.map +1 -0
- package/ccw/dist/core/routes/task-routes.js +321 -0
- package/ccw/dist/core/routes/task-routes.js.map +1 -0
- package/ccw/dist/core/routes/test-loop-routes.d.ts +11 -0
- package/ccw/dist/core/routes/test-loop-routes.d.ts.map +1 -0
- package/ccw/dist/core/routes/test-loop-routes.js +298 -0
- package/ccw/dist/core/routes/test-loop-routes.js.map +1 -0
- package/ccw/dist/core/server.d.ts.map +1 -1
- package/ccw/dist/core/server.js +43 -3
- package/ccw/dist/core/server.js.map +1 -1
- package/ccw/dist/core/websocket.d.ts +59 -0
- package/ccw/dist/core/websocket.d.ts.map +1 -1
- package/ccw/dist/core/websocket.js +34 -0
- package/ccw/dist/core/websocket.js.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.d.ts +40 -0
- package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.js +119 -0
- package/ccw/dist/tools/claude-cli-tools.js.map +1 -1
- package/ccw/dist/tools/loop-manager.d.ts +84 -0
- package/ccw/dist/tools/loop-manager.d.ts.map +1 -0
- package/ccw/dist/tools/loop-manager.js +425 -0
- package/ccw/dist/tools/loop-manager.js.map +1 -0
- package/ccw/dist/tools/loop-state-manager.d.ts +47 -0
- package/ccw/dist/tools/loop-state-manager.d.ts.map +1 -0
- package/ccw/dist/tools/loop-state-manager.js +149 -0
- package/ccw/dist/tools/loop-state-manager.js.map +1 -0
- package/ccw/dist/tools/loop-task-manager.d.ts +138 -0
- package/ccw/dist/tools/loop-task-manager.d.ts.map +1 -0
- package/ccw/dist/tools/loop-task-manager.js +270 -0
- package/ccw/dist/tools/loop-task-manager.js.map +1 -0
- package/ccw/dist/types/index.d.ts +1 -0
- package/ccw/dist/types/index.d.ts.map +1 -1
- package/ccw/dist/types/index.js +1 -0
- package/ccw/dist/types/index.js.map +1 -1
- package/ccw/dist/types/loop.d.ts +257 -0
- package/ccw/dist/types/loop.d.ts.map +1 -0
- package/ccw/dist/types/loop.js +17 -0
- package/ccw/dist/types/loop.js.map +1 -0
- package/ccw/src/cli.ts +9 -1
- package/ccw/src/commands/cli.ts +14 -1
- package/ccw/src/commands/loop.ts +344 -0
- package/ccw/src/core/dashboard-generator.ts +4 -1
- package/ccw/src/core/routes/claude-routes.ts +5 -3
- package/ccw/src/core/routes/cli-routes.ts +47 -15
- package/ccw/src/core/routes/cli-settings-routes.ts +47 -0
- package/ccw/src/core/routes/codexlens/semantic-handlers.ts +3 -2
- package/ccw/src/core/routes/core-memory-routes.ts +4 -2
- package/ccw/src/core/routes/files-routes.ts +4 -2
- package/ccw/src/core/routes/loop-routes.ts +386 -0
- package/ccw/src/core/routes/loop-v2-routes.ts +1412 -0
- package/ccw/src/core/routes/memory-routes.ts +2 -1
- package/ccw/src/core/routes/task-routes.ts +361 -0
- package/ccw/src/core/routes/test-loop-routes.ts +312 -0
- package/ccw/src/core/server.ts +44 -3
- package/ccw/src/core/websocket.ts +104 -0
- package/ccw/src/templates/dashboard-css/12-cli-legacy.css +56 -0
- package/ccw/src/templates/dashboard-css/33-cli-stream-viewer.css +55 -0
- package/ccw/src/templates/dashboard-css/36-loop-monitor.css +1896 -0
- package/ccw/src/templates/dashboard-css/36-loop-monitor.css.backup +1877 -0
- package/ccw/src/templates/dashboard-js/components/cli-status.js +64 -3
- package/ccw/src/templates/dashboard-js/components/cli-stream-viewer.js +251 -110
- package/ccw/src/templates/dashboard-js/components/navigation.js +10 -0
- package/ccw/src/templates/dashboard-js/components/notifications.js +16 -0
- package/ccw/src/templates/dashboard-js/i18n.js +475 -1
- package/ccw/src/templates/dashboard-js/views/cli-manager.js +3 -2
- package/ccw/src/templates/dashboard-js/views/loop-monitor.js +3244 -0
- package/ccw/src/templates/dashboard.html +20 -2
- package/ccw/src/tools/claude-cli-tools.ts +143 -0
- package/ccw/src/tools/loop-manager.ts +519 -0
- package/ccw/src/tools/loop-state-manager.ts +173 -0
- package/ccw/src/tools/loop-task-manager.ts +380 -0
- package/ccw/src/types/index.ts +1 -0
- package/ccw/src/types/loop.ts +316 -0
- package/package.json +1 -1
package/ccw/src/core/server.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { resolvePath, getRecentPaths, normalizePathForDisplay } from '../utils/p
|
|
|
6
6
|
|
|
7
7
|
// Import route handlers
|
|
8
8
|
import { handleStatusRoutes } from './routes/status-routes.js';
|
|
9
|
-
import { handleCliRoutes } from './routes/cli-routes.js';
|
|
9
|
+
import { handleCliRoutes, cleanupStaleExecutions } from './routes/cli-routes.js';
|
|
10
10
|
import { handleCliSettingsRoutes } from './routes/cli-settings-routes.js';
|
|
11
11
|
import { handleMemoryRoutes } from './routes/memory-routes.js';
|
|
12
12
|
import { handleCoreMemoryRoutes } from './routes/core-memory-routes.js';
|
|
@@ -28,6 +28,10 @@ import { handleLiteLLMRoutes } from './routes/litellm-routes.js';
|
|
|
28
28
|
import { handleLiteLLMApiRoutes } from './routes/litellm-api-routes.js';
|
|
29
29
|
import { handleNavStatusRoutes } from './routes/nav-status-routes.js';
|
|
30
30
|
import { handleAuthRoutes } from './routes/auth-routes.js';
|
|
31
|
+
import { handleLoopRoutes } from './routes/loop-routes.js';
|
|
32
|
+
import { handleLoopV2Routes } from './routes/loop-v2-routes.js';
|
|
33
|
+
import { handleTestLoopRoutes } from './routes/test-loop-routes.js';
|
|
34
|
+
import { handleTaskRoutes } from './routes/task-routes.js';
|
|
31
35
|
|
|
32
36
|
// Import WebSocket handling
|
|
33
37
|
import { handleWebSocketUpgrade, broadcastToClients, extractSessionIdFromPath } from './websocket.js';
|
|
@@ -102,7 +106,8 @@ const MODULE_CSS_FILES = [
|
|
|
102
106
|
'31-api-settings.css',
|
|
103
107
|
'32-issue-manager.css',
|
|
104
108
|
'33-cli-stream-viewer.css',
|
|
105
|
-
'34-discovery.css'
|
|
109
|
+
'34-discovery.css',
|
|
110
|
+
'36-loop-monitor.css'
|
|
106
111
|
];
|
|
107
112
|
|
|
108
113
|
// Modular JS files in dependency order
|
|
@@ -162,6 +167,7 @@ const MODULE_FILES = [
|
|
|
162
167
|
'views/help.js',
|
|
163
168
|
'views/issue-manager.js',
|
|
164
169
|
'views/issue-discovery.js',
|
|
170
|
+
'views/loop-monitor.js',
|
|
165
171
|
'main.js'
|
|
166
172
|
];
|
|
167
173
|
|
|
@@ -359,7 +365,14 @@ function generateServerDashboard(initialPath: string): string {
|
|
|
359
365
|
// Read and concatenate modular JS files in dependency order
|
|
360
366
|
let jsContent = MODULE_FILES.map(file => {
|
|
361
367
|
const filePath = join(MODULE_JS_DIR, file);
|
|
362
|
-
|
|
368
|
+
if (!existsSync(filePath)) {
|
|
369
|
+
console.error(`[Dashboard] Critical module file not found: ${filePath}`);
|
|
370
|
+
console.error(`[Dashboard] Expected path relative to: ${MODULE_JS_DIR}`);
|
|
371
|
+
console.error(`[Dashboard] Check that the file exists and is included in the build.`);
|
|
372
|
+
// Return empty string with error comment to make the issue visible in browser
|
|
373
|
+
return `console.error('[Dashboard] Module not loaded: ${file} (see server console for details)');\n`;
|
|
374
|
+
}
|
|
375
|
+
return readFileSync(filePath, 'utf8');
|
|
363
376
|
}).join('\n\n');
|
|
364
377
|
|
|
365
378
|
// Inject CSS content
|
|
@@ -556,6 +569,26 @@ export async function startServer(options: ServerOptions = {}): Promise<http.Ser
|
|
|
556
569
|
if (await handleCcwRoutes(routeContext)) return;
|
|
557
570
|
}
|
|
558
571
|
|
|
572
|
+
// Loop V2 routes (/api/loops/v2/*) - must be checked before v1
|
|
573
|
+
if (pathname.startsWith('/api/loops/v2')) {
|
|
574
|
+
if (await handleLoopV2Routes(routeContext)) return;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// Loop V1 routes (/api/loops/*) - backward compatibility
|
|
578
|
+
if (pathname.startsWith('/api/loops')) {
|
|
579
|
+
if (await handleLoopRoutes(routeContext)) return;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// Task routes (/api/tasks)
|
|
583
|
+
if (pathname.startsWith('/api/tasks')) {
|
|
584
|
+
if (await handleTaskRoutes(routeContext)) return;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// Test loop routes (/api/test/loop*)
|
|
588
|
+
if (pathname.startsWith('/api/test/loop')) {
|
|
589
|
+
if (await handleTestLoopRoutes(routeContext)) return;
|
|
590
|
+
}
|
|
591
|
+
|
|
559
592
|
// Skills routes (/api/skills*)
|
|
560
593
|
if (pathname.startsWith('/api/skills')) {
|
|
561
594
|
if (await handleSkillsRoutes(routeContext)) return;
|
|
@@ -690,6 +723,14 @@ export async function startServer(options: ServerOptions = {}): Promise<http.Ser
|
|
|
690
723
|
console.log(`WebSocket endpoint available at ws://${host}:${serverPort}/ws`);
|
|
691
724
|
console.log(`Hook endpoint available at POST http://${host}:${serverPort}/api/hook`);
|
|
692
725
|
|
|
726
|
+
// Start periodic cleanup of stale CLI executions (every 2 minutes)
|
|
727
|
+
const CLEANUP_INTERVAL_MS = 2 * 60 * 1000;
|
|
728
|
+
const cleanupInterval = setInterval(cleanupStaleExecutions, CLEANUP_INTERVAL_MS);
|
|
729
|
+
server.on('close', () => {
|
|
730
|
+
clearInterval(cleanupInterval);
|
|
731
|
+
console.log('[Server] Stopped CLI execution cleanup interval');
|
|
732
|
+
});
|
|
733
|
+
|
|
693
734
|
// Start health check service for all enabled providers
|
|
694
735
|
try {
|
|
695
736
|
const healthCheckService = getHealthCheckService();
|
|
@@ -5,6 +5,64 @@ import type { Duplex } from 'stream';
|
|
|
5
5
|
// WebSocket clients for real-time notifications
|
|
6
6
|
export const wsClients = new Set<Duplex>();
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* WebSocket message types for Loop monitoring
|
|
10
|
+
*/
|
|
11
|
+
export type LoopMessageType =
|
|
12
|
+
| 'LOOP_STATE_UPDATE'
|
|
13
|
+
| 'LOOP_STEP_COMPLETED'
|
|
14
|
+
| 'LOOP_COMPLETED'
|
|
15
|
+
| 'LOOP_LOG_ENTRY';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Loop State Update - fired when loop status changes
|
|
19
|
+
*/
|
|
20
|
+
export interface LoopStateUpdateMessage {
|
|
21
|
+
type: 'LOOP_STATE_UPDATE';
|
|
22
|
+
loop_id: string;
|
|
23
|
+
status: 'created' | 'running' | 'paused' | 'completed' | 'failed';
|
|
24
|
+
current_iteration: number;
|
|
25
|
+
current_cli_step: number;
|
|
26
|
+
updated_at: string;
|
|
27
|
+
timestamp: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Loop Step Completed - fired when a CLI step finishes
|
|
32
|
+
*/
|
|
33
|
+
export interface LoopStepCompletedMessage {
|
|
34
|
+
type: 'LOOP_STEP_COMPLETED';
|
|
35
|
+
loop_id: string;
|
|
36
|
+
step_id: string;
|
|
37
|
+
exit_code: number;
|
|
38
|
+
duration_ms: number;
|
|
39
|
+
output: string;
|
|
40
|
+
timestamp: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Loop Completed - fired when entire loop finishes
|
|
45
|
+
*/
|
|
46
|
+
export interface LoopCompletedMessage {
|
|
47
|
+
type: 'LOOP_COMPLETED';
|
|
48
|
+
loop_id: string;
|
|
49
|
+
final_status: 'completed' | 'failed';
|
|
50
|
+
total_iterations: number;
|
|
51
|
+
reason?: string;
|
|
52
|
+
timestamp: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Loop Log Entry - fired for streaming log lines
|
|
57
|
+
*/
|
|
58
|
+
export interface LoopLogEntryMessage {
|
|
59
|
+
type: 'LOOP_LOG_ENTRY';
|
|
60
|
+
loop_id: string;
|
|
61
|
+
step_id: string;
|
|
62
|
+
line: string;
|
|
63
|
+
timestamp: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
8
66
|
export function handleWebSocketUpgrade(req: IncomingMessage, socket: Duplex, _head: Buffer): void {
|
|
9
67
|
const header = req.headers['sec-websocket-key'];
|
|
10
68
|
const key = Array.isArray(header) ? header[0] : header;
|
|
@@ -196,3 +254,49 @@ export function extractSessionIdFromPath(filePath: string): string | null {
|
|
|
196
254
|
|
|
197
255
|
return null;
|
|
198
256
|
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Loop-specific broadcast with throttling
|
|
260
|
+
* Throttles LOOP_STATE_UPDATE messages to avoid flooding clients
|
|
261
|
+
*/
|
|
262
|
+
let lastLoopBroadcast = 0;
|
|
263
|
+
const LOOP_BROADCAST_THROTTLE = 1000; // 1 second
|
|
264
|
+
|
|
265
|
+
export type LoopMessage =
|
|
266
|
+
| Omit<LoopStateUpdateMessage, 'timestamp'>
|
|
267
|
+
| Omit<LoopStepCompletedMessage, 'timestamp'>
|
|
268
|
+
| Omit<LoopCompletedMessage, 'timestamp'>
|
|
269
|
+
| Omit<LoopLogEntryMessage, 'timestamp'>;
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Broadcast loop state update with throttling
|
|
273
|
+
*/
|
|
274
|
+
export function broadcastLoopUpdate(message: LoopMessage): void {
|
|
275
|
+
const now = Date.now();
|
|
276
|
+
|
|
277
|
+
// Throttle LOOP_STATE_UPDATE to reduce WebSocket traffic
|
|
278
|
+
if (message.type === 'LOOP_STATE_UPDATE' && now - lastLoopBroadcast < LOOP_BROADCAST_THROTTLE) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
lastLoopBroadcast = now;
|
|
283
|
+
|
|
284
|
+
broadcastToClients({
|
|
285
|
+
...message,
|
|
286
|
+
timestamp: new Date().toISOString()
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Broadcast loop log entry (no throttling)
|
|
292
|
+
* Used for streaming real-time logs to Dashboard
|
|
293
|
+
*/
|
|
294
|
+
export function broadcastLoopLog(loop_id: string, step_id: string, line: string): void {
|
|
295
|
+
broadcastToClients({
|
|
296
|
+
type: 'LOOP_LOG_ENTRY',
|
|
297
|
+
loop_id,
|
|
298
|
+
step_id,
|
|
299
|
+
line,
|
|
300
|
+
timestamp: new Date().toISOString()
|
|
301
|
+
});
|
|
302
|
+
}
|
|
@@ -2,6 +2,41 @@
|
|
|
2
2
|
* Legacy Container Styles (kept for compatibility)
|
|
3
3
|
* ======================================== */
|
|
4
4
|
|
|
5
|
+
/* CLI Stream Recovery Badge Styles */
|
|
6
|
+
.cli-stream-recovery-badge {
|
|
7
|
+
font-size: 0.5625rem;
|
|
8
|
+
font-weight: 600;
|
|
9
|
+
padding: 0.125rem 0.375rem;
|
|
10
|
+
background: hsl(38 92% 50% / 0.15);
|
|
11
|
+
color: hsl(38 92% 50%);
|
|
12
|
+
border-radius: 9999px;
|
|
13
|
+
text-transform: uppercase;
|
|
14
|
+
letter-spacing: 0.03em;
|
|
15
|
+
margin-left: 0.375rem;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.cli-status-recovery-badge {
|
|
19
|
+
font-size: 0.625rem;
|
|
20
|
+
font-weight: 600;
|
|
21
|
+
padding: 0.125rem 0.5rem;
|
|
22
|
+
background: hsl(38 92% 50% / 0.15);
|
|
23
|
+
color: hsl(38 92% 50%);
|
|
24
|
+
border-radius: 0.25rem;
|
|
25
|
+
text-transform: uppercase;
|
|
26
|
+
letter-spacing: 0.03em;
|
|
27
|
+
margin-left: 0.5rem;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Tab styling for recovered sessions */
|
|
31
|
+
.cli-stream-tab.recovered {
|
|
32
|
+
border-color: hsl(38 92% 50% / 0.3);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.cli-stream-tab.recovered .cli-stream-recovery-badge {
|
|
36
|
+
background: hsl(38 92% 50% / 0.2);
|
|
37
|
+
color: hsl(38 92% 55%);
|
|
38
|
+
}
|
|
39
|
+
|
|
5
40
|
/* Container */
|
|
6
41
|
.cli-manager-container {
|
|
7
42
|
display: flex;
|
|
@@ -66,6 +101,27 @@
|
|
|
66
101
|
color: hsl(var(--muted-foreground));
|
|
67
102
|
}
|
|
68
103
|
|
|
104
|
+
/* CLI status actions container */
|
|
105
|
+
.cli-status-actions {
|
|
106
|
+
display: flex;
|
|
107
|
+
align-items: center;
|
|
108
|
+
gap: 0.375rem;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* Spin animation for sync icon */
|
|
112
|
+
@keyframes spin {
|
|
113
|
+
from {
|
|
114
|
+
transform: rotate(0deg);
|
|
115
|
+
}
|
|
116
|
+
to {
|
|
117
|
+
transform: rotate(360deg);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.spin {
|
|
122
|
+
animation: spin 1s linear infinite;
|
|
123
|
+
}
|
|
124
|
+
|
|
69
125
|
.cli-tools-grid {
|
|
70
126
|
display: grid;
|
|
71
127
|
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
|
@@ -161,6 +161,8 @@
|
|
|
161
161
|
display: flex;
|
|
162
162
|
align-items: center;
|
|
163
163
|
gap: 8px;
|
|
164
|
+
/* Isolate from parent transform to fix native tooltip positioning */
|
|
165
|
+
will-change: transform;
|
|
164
166
|
}
|
|
165
167
|
|
|
166
168
|
.cli-stream-action-btn {
|
|
@@ -196,6 +198,10 @@
|
|
|
196
198
|
color: hsl(var(--muted-foreground));
|
|
197
199
|
cursor: pointer;
|
|
198
200
|
transition: all 0.15s;
|
|
201
|
+
/* Fix native tooltip positioning under transformed parent */
|
|
202
|
+
position: relative;
|
|
203
|
+
z-index: 1;
|
|
204
|
+
transform: translateZ(0);
|
|
199
205
|
}
|
|
200
206
|
|
|
201
207
|
.cli-stream-close-btn:hover {
|
|
@@ -203,6 +209,49 @@
|
|
|
203
209
|
color: hsl(var(--destructive));
|
|
204
210
|
}
|
|
205
211
|
|
|
212
|
+
/* Icon-only action buttons (cleaner style matching close button) */
|
|
213
|
+
.cli-stream-icon-btn {
|
|
214
|
+
display: flex;
|
|
215
|
+
align-items: center;
|
|
216
|
+
justify-content: center;
|
|
217
|
+
width: 28px;
|
|
218
|
+
height: 28px;
|
|
219
|
+
padding: 0;
|
|
220
|
+
background: transparent;
|
|
221
|
+
border: none;
|
|
222
|
+
border-radius: 4px;
|
|
223
|
+
color: hsl(var(--muted-foreground));
|
|
224
|
+
cursor: pointer;
|
|
225
|
+
transition: all 0.15s;
|
|
226
|
+
/* Fix native tooltip positioning under transformed parent */
|
|
227
|
+
position: relative;
|
|
228
|
+
z-index: 1;
|
|
229
|
+
/* Create new stacking context to isolate from parent transform */
|
|
230
|
+
transform: translateZ(0);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.cli-stream-icon-btn svg {
|
|
234
|
+
width: 16px;
|
|
235
|
+
height: 16px;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.cli-stream-icon-btn:hover {
|
|
239
|
+
background: hsl(var(--hover));
|
|
240
|
+
color: hsl(var(--foreground));
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.cli-stream-icon-btn:first-child:hover {
|
|
244
|
+
/* Clear completed - green/success tint */
|
|
245
|
+
background: hsl(142 76% 36% / 0.1);
|
|
246
|
+
color: hsl(142 76% 36%);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.cli-stream-icon-btn:nth-child(2):hover {
|
|
250
|
+
/* Clear all - orange/warning tint */
|
|
251
|
+
background: hsl(38 92% 50% / 0.1);
|
|
252
|
+
color: hsl(38 92% 50%);
|
|
253
|
+
}
|
|
254
|
+
|
|
206
255
|
/* ===== Tab Bar ===== */
|
|
207
256
|
.cli-stream-tabs {
|
|
208
257
|
display: flex;
|
|
@@ -787,6 +836,12 @@
|
|
|
787
836
|
animation: streamBadgePulse 1.5s ease-in-out infinite;
|
|
788
837
|
}
|
|
789
838
|
|
|
839
|
+
.cli-stream-badge.has-completed {
|
|
840
|
+
display: flex;
|
|
841
|
+
background: hsl(var(--muted) / 0.8);
|
|
842
|
+
color: hsl(var(--muted-foreground));
|
|
843
|
+
}
|
|
844
|
+
|
|
790
845
|
@keyframes streamBadgePulse {
|
|
791
846
|
0%, 100% { transform: scale(1); }
|
|
792
847
|
50% { transform: scale(1.15); }
|