@lucashca/claudecontrol 0.3.24 → 0.3.26

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.
@@ -118,6 +118,12 @@ export function pushLog(session: AgentSession, entry: LogEntry) {
118
118
  persistLogEntry(session.workspaceId, session.id, entry);
119
119
  }
120
120
 
121
+ export function removeLogEntry(session: AgentSession, predicate: (e: LogEntry) => boolean) {
122
+ session.log = session.log.filter(e => !predicate(e));
123
+ const logPath = agentLogPath(session.workspaceId, session.id);
124
+ try { writeFileSync(logPath, session.log.map(e => JSON.stringify(e)).join('\n') + (session.log.length ? '\n' : '')); } catch { /* ignore */ }
125
+ }
126
+
121
127
  export function genId(): string {
122
128
  return Math.random().toString(36).slice(2, 10);
123
129
  }
@@ -5,7 +5,7 @@ import { broadcast } from '../ws.js';
5
5
  import { getWorkspaceById } from '../workspaces.js';
6
6
  import {
7
7
  genId, agents, agentAbortControllers, agentConversations,
8
- persistAgents, persistLogEntry, addAgentToIndex, pushLog,
8
+ persistAgents, persistLogEntry, addAgentToIndex, pushLog, removeLogEntry,
9
9
  delegations, agentQueues,
10
10
  } from '../agents/store.js';
11
11
  import { sendToAgent, runAgentQuery, delegateTask, compactAgentContext } from '../agents/lifecycle.js';
@@ -81,6 +81,19 @@ export async function handleAgentRoutes(
81
81
  return true;
82
82
  }
83
83
 
84
+ // ── DELETE /api/agents/:id/log?delegationId=xxx (remove log entry) ──
85
+ const deleteLogParams = matchRoute(path, '/api/agents/:id/log');
86
+ if (deleteLogParams && method === 'DELETE') {
87
+ const agent = agents.get(deleteLogParams.id);
88
+ if (!agent) { jsonError(res, 'Agent not found', 404); return true; }
89
+ const delegationId = _urlObj.searchParams.get('delegationId');
90
+ if (!delegationId) { jsonError(res, 'delegationId is required'); return true; }
91
+ removeLogEntry(agent, e => e.delegationId === delegationId);
92
+ broadcast({ type: 'agent_log_updated', agentId: agent.id, workspaceId: agent.workspaceId, log: agent.log });
93
+ json(res, { ok: true });
94
+ return true;
95
+ }
96
+
84
97
  // ── DELETE /api/agents/:id (close — move to history) ──
85
98
  const deleteAgentParams = matchRoute(path, '/api/agents/:id');
86
99
  if (deleteAgentParams && method === 'DELETE') {
@@ -86,6 +86,7 @@ export const api = {
86
86
  post(`/workspaces/${wsId}/agents`, data),
87
87
 
88
88
  deleteAgent: (id: string) => del(`/agents/${id}`),
89
+ removeLogEntry: (agentId: string, delegationId: string) => del(`/agents/${agentId}/log?delegationId=${encodeURIComponent(delegationId)}`),
89
90
 
90
91
  sendMessage: (agentId: string, message: string, attachments?: import('./types').Attachment[], effort?: string, model?: string) =>
91
92
  post(`/agents/${agentId}/send`, { message, attachments, effort, model }),
@@ -1,6 +1,6 @@
1
1
  import { useState, useRef, useEffect } from 'react';
2
2
  import {
3
- Plus, X, Wifi, WifiOff, Settings, RefreshCw, Shield, ShieldOff, Eye, EyeOff, Lock, Code2, Menu, Loader2, Bell, BellOff,
3
+ Plus, X, Wifi, WifiOff, Settings, RefreshCw, Shield, ShieldOff, Eye, EyeOff, Lock, Code2, Menu, Loader2, Bell, BellOff, Trash2,
4
4
  } from 'lucide-react';
5
5
  import { useAtomValue, useSetAtom } from 'jotai';
6
6
  import { Logo } from '@/ui';
@@ -28,8 +28,8 @@ const PALETTE = [
28
28
  '#ec4899','#06b6d4','#f97316','#c8ee44','#a78bfa',
29
29
  ];
30
30
 
31
- function EditPopover({ wsId, wsName, wsColor, wsOrchestratorRole, isHidden, onToggleHidden, onClose, anchorEl }: {
32
- wsId: string; wsName: string; wsColor: string; wsOrchestratorRole?: string; isHidden: boolean; onToggleHidden: () => void; onClose: () => void; anchorEl: HTMLElement | null;
31
+ function EditPopover({ wsId, wsName, wsColor, wsOrchestratorRole, isHidden, onToggleHidden, onDelete, onClose, anchorEl }: {
32
+ wsId: string; wsName: string; wsColor: string; wsOrchestratorRole?: string; isHidden: boolean; onToggleHidden: () => void; onDelete: () => void; onClose: () => void; anchorEl: HTMLElement | null;
33
33
  }) {
34
34
  const [name, setName] = useState(wsName);
35
35
  const [color, setColor] = useState(wsColor);
@@ -96,6 +96,10 @@ function EditPopover({ wsId, wsName, wsColor, wsOrchestratorRole, isHidden, onTo
96
96
  {isHidden ? 'Mostrar workspace' : 'Ocultar workspace'}
97
97
  </Button>
98
98
  <Button variant="primary" size="sm" onClick={save} className="w-full mt-2">Salvar</Button>
99
+ <Button variant="ghost" size="sm" onClick={onDelete}
100
+ className="w-full justify-start gap-2 mt-1 px-2 py-1.5 text-[11px] text-cc-error hover:bg-cc-error/10">
101
+ <Trash2 size={12} /> Excluir workspace
102
+ </Button>
99
103
  </div>
100
104
  );
101
105
  }
@@ -203,6 +207,7 @@ export function Header() {
203
207
  isHidden={hidden}
204
208
  anchorEl={settingsAnchorRefs.current[w.id]}
205
209
  onToggleHidden={() => { toggleHiddenWorkspace(w.id); setEditingWs(null); }}
210
+ onDelete={() => { api.deleteWorkspace(w.id).then(() => { closeWs(w.id); refresh(); }); setEditingWs(null); }}
206
211
  onClose={() => setEditingWs(null)}
207
212
  />
208
213
  )}
@@ -1,6 +1,7 @@
1
1
  import { useState } from 'react';
2
2
  import { useAtomValue } from 'jotai';
3
3
  import { agentsMapAtom } from '@/atoms';
4
+ import { api } from '@/api';
4
5
  import { ChevronDown, ChevronUp, Loader2, CheckCircle2, XCircle, Clock, Wrench, MessageSquare, X } from 'lucide-react';
5
6
  import type { LogEntry } from '@/types';
6
7
 
@@ -47,10 +48,18 @@ const STATUS_CONFIG = {
47
48
  },
48
49
  };
49
50
 
51
+ function loadDismissed(): Record<string, boolean> {
52
+ try { return JSON.parse(localStorage.getItem('cc-dismissed-delegations') || '{}'); } catch { return {}; }
53
+ }
54
+
55
+ function saveDismissed(d: Record<string, boolean>) {
56
+ localStorage.setItem('cc-dismissed-delegations', JSON.stringify(d));
57
+ }
58
+
50
59
  export function DelegationStatusBar({ agentId }: { agentId: string }) {
51
60
  const agentsMap = useAtomValue(agentsMapAtom);
52
61
  const [expanded, setExpanded] = useState<Record<string, boolean>>({});
53
- const [dismissed, setDismissed] = useState<Record<string, boolean>>({});
62
+ const [dismissed, setDismissed] = useState<Record<string, boolean>>(loadDismissed);
54
63
 
55
64
  const agent = agentsMap.get(agentId);
56
65
  if (!agent) return null;
@@ -93,7 +102,10 @@ export function DelegationStatusBar({ agentId }: { agentId: string }) {
93
102
  <div key={delegation.delegationId} className="border-b border-cc-border/30 last:border-b-0">
94
103
  <div className={`flex items-center transition-colors ${cfg.bg}`}>
95
104
  <button
96
- onClick={() => setDismissed(prev => ({ ...prev, [delegation.delegationId!]: true }))}
105
+ onClick={() => {
106
+ setDismissed(prev => { const next = { ...prev, [delegation.delegationId!]: true }; saveDismissed(next); return next; });
107
+ api.removeLogEntry(agentId, delegation.delegationId!).catch(() => {});
108
+ }}
97
109
  className="px-2 py-1.5 text-cc-muted hover:text-cc-text-secondary transition-colors shrink-0"
98
110
  >
99
111
  <X size={10} />
@@ -223,6 +223,16 @@ function handleMessage(msg: any) {
223
223
  store.set(agentsMapAtom, next);
224
224
  break;
225
225
  }
226
+ case 'agent_log_updated': {
227
+ if (!isActive) break;
228
+ const prev = store.get(agentsMapAtom);
229
+ const existing = prev.get(msg.agentId);
230
+ if (!existing) break;
231
+ const next = new Map(prev);
232
+ next.set(msg.agentId, { ...existing, log: msg.log });
233
+ store.set(agentsMapAtom, next);
234
+ break;
235
+ }
226
236
  case 'agent_removed':
227
237
  if (isActive) removeAgent(msg.agentId);
228
238
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucashca/claudecontrol",
3
- "version": "0.3.24",
3
+ "version": "0.3.26",
4
4
  "description": "AI Agent Dashboard — manage multiple Claude Code agents across projects",
5
5
  "type": "module",
6
6
  "bin": {
package/version.json CHANGED
@@ -1 +1 @@
1
- {"version":"0.3.24","build":"2026-04-03T23:07:39.778Z"}
1
+ {"version":"0.3.26","build":"2026-04-03T23:17:53.310Z"}