@lucashca/claudecontrol 0.3.25 → 0.3.27
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/backend/agents/store.ts +8 -0
- package/backend/routes/agents.ts +14 -1
- package/backend/types.ts +1 -0
- package/frontend/src/api.ts +1 -0
- package/frontend/src/components/chat/DelegationStatusBar.tsx +15 -3
- package/frontend/src/hooks/useWebSocket.ts +10 -0
- package/frontend/src/types/index.ts +1 -0
- package/package.json +1 -1
- package/version.json +1 -1
package/backend/agents/store.ts
CHANGED
|
@@ -118,6 +118,14 @@ export function pushLog(session: AgentSession, entry: LogEntry) {
|
|
|
118
118
|
persistLogEntry(session.workspaceId, session.id, entry);
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
export function hideLogEntry(session: AgentSession, predicate: (e: LogEntry) => boolean) {
|
|
122
|
+
for (const entry of session.log) {
|
|
123
|
+
if (predicate(entry)) entry.hidden = true;
|
|
124
|
+
}
|
|
125
|
+
const logPath = agentLogPath(session.workspaceId, session.id);
|
|
126
|
+
try { writeFileSync(logPath, session.log.map(e => JSON.stringify(e)).join('\n') + (session.log.length ? '\n' : '')); } catch { /* ignore */ }
|
|
127
|
+
}
|
|
128
|
+
|
|
121
129
|
export function genId(): string {
|
|
122
130
|
return Math.random().toString(36).slice(2, 10);
|
|
123
131
|
}
|
package/backend/routes/agents.ts
CHANGED
|
@@ -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, hideLogEntry,
|
|
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
|
+
// ── PATCH /api/agents/:id/log?delegationId=xxx (hide log entry) ──
|
|
85
|
+
const hideLogParams = matchRoute(path, '/api/agents/:id/log');
|
|
86
|
+
if (hideLogParams && method === 'PATCH') {
|
|
87
|
+
const agent = agents.get(hideLogParams.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
|
+
hideLogEntry(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') {
|
package/backend/types.ts
CHANGED
package/frontend/src/api.ts
CHANGED
|
@@ -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
|
+
hideLogEntry: (agentId: string, delegationId: string) => patch(`/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,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,16 +48,24 @@ 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;
|
|
57
66
|
|
|
58
67
|
const allDelegations = agent.log.filter(
|
|
59
|
-
e => e.type === 'delegation' && e.delegationTo && e.delegationStatus,
|
|
68
|
+
e => e.type === 'delegation' && e.delegationTo && e.delegationStatus && !e.hidden,
|
|
60
69
|
);
|
|
61
70
|
|
|
62
71
|
const delegations = allDelegations.filter(e => !dismissed[e.delegationId!]);
|
|
@@ -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={() =>
|
|
105
|
+
onClick={() => {
|
|
106
|
+
setDismissed(prev => { const next = { ...prev, [delegation.delegationId!]: true }; saveDismissed(next); return next; });
|
|
107
|
+
api.hideLogEntry(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
package/version.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.3.
|
|
1
|
+
{"version":"0.3.27","build":"2026-04-03T23:24:27.772Z"}
|