@lucashca/claudecontrol 0.3.29 → 0.3.31

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.
@@ -43,7 +43,7 @@ export function createBypassCanUseTool(agentId: string, workspaceId: string) {
43
43
  * Creates canUseTool for default (secure) mode.
44
44
  * Shows permission prompt in the frontend and waits for user response.
45
45
  */
46
- export function createCanUseTool(agentId: string, workspaceId: string) {
46
+ export function createCanUseTool(agentId: string, workspaceId: string, isOrchestrator = false) {
47
47
  return (toolName: string, input: Record<string, unknown>, options: CanUseToolOptions) => {
48
48
  const requestId = genId();
49
49
  const session = agents.get(agentId);
@@ -252,12 +252,12 @@ export async function sendToAgent(id: string, message: string, attachments?: Att
252
252
  }
253
253
  broadcast({ type: 'agent_working', agentId: id, workspaceId: session.workspaceId, task: displayText });
254
254
 
255
+ // Only the orchestrator role gets native subagent tools; specialists just execute tasks
256
+ const isOrchestrator = session.isOrchestrator === true || session.role === getOrchestratorRole(session.workspaceId);
257
+
255
258
  const permissionOpts = session.bypass
256
259
  ? { permissionMode: 'bypassPermissions' as const, allowDangerouslySkipPermissions: true, canUseTool: createBypassCanUseTool(id, session.workspaceId) }
257
- : { permissionMode: 'default' as const, canUseTool: createCanUseTool(id, session.workspaceId) };
258
-
259
- // Only the orchestrator role gets native subagent tools; specialists just execute tasks
260
- const isOrchestrator = session.role === getOrchestratorRole(session.workspaceId);
260
+ : { permissionMode: 'default' as const, canUseTool: createCanUseTool(id, session.workspaceId, isOrchestrator) };
261
261
  const subagents = (isOrchestrator && runtime.enableSubagents) ? buildSubagents(cwd, session.role) : {};
262
262
  const hasAttachments = attachments && attachments.length > 0;
263
263
 
@@ -368,8 +368,9 @@ export async function runAgentQuery(session: AgentSession, task: string, bypass
368
368
  const isOrchestrator = session.isOrchestrator === true || session.role === getOrchestratorRole(session.workspaceId);
369
369
  const subagents = (isOrchestrator && runtime.enableSubagents) ? buildSubagents(cwd, session.role) : {};
370
370
  const poolContext = (!runtime.enableSubagents && isOrchestrator) ? buildPoolContext(session.workspaceId, session.id) : '';
371
+ const specialistCtx = !isOrchestrator && !session.canSpawnSubagents ? '[INSTRUCAO] Voce e um especialista. Execute suas tarefas diretamente usando suas proprias ferramentas. Nao use o Agent tool nem inicie subagentes.' : '';
371
372
  // poolContext first so the model sees the delegation rules before the role instructions
372
- const systemAppend = [poolContext, customContext, context].filter(Boolean).join('\n\n');
373
+ const systemAppend = [poolContext, specialistCtx, customContext, context].filter(Boolean).join('\n\n');
373
374
  const prompt = task;
374
375
 
375
376
  const abortController = new AbortController();
@@ -389,7 +390,7 @@ export async function runAgentQuery(session: AgentSession, task: string, bypass
389
390
  stderr: (text: string) => console.error(`[agent:${session.id}]`, text),
390
391
  ...(bypass
391
392
  ? { permissionMode: 'bypassPermissions' as const, allowDangerouslySkipPermissions: true, canUseTool: createBypassCanUseTool(session.id, session.workspaceId) }
392
- : { permissionMode: 'default' as const, canUseTool: createCanUseTool(session.id, session.workspaceId) }),
393
+ : { permissionMode: 'default' as const, canUseTool: createCanUseTool(session.id, session.workspaceId, isOrchestrator) }),
393
394
  };
394
395
 
395
396
  try {
@@ -75,6 +75,7 @@ export async function handleAgentRoutes(
75
75
  const body = await parseBody(req);
76
76
  if (body.customName !== undefined) agent.customName = body.customName as string;
77
77
  if (body.isOrchestrator !== undefined) agent.isOrchestrator = body.isOrchestrator as boolean;
78
+ if (body.canSpawnSubagents !== undefined) agent.canSpawnSubagents = body.canSpawnSubagents as boolean;
78
79
  persistAgents();
79
80
  broadcast({ type: 'agent_updated', agentId: agent.id, workspaceId: agent.workspaceId, agent });
80
81
  json(res, agent);
package/backend/types.ts CHANGED
@@ -92,4 +92,5 @@ export interface AgentSession {
92
92
  lastContextTokens?: number; // cache_read_input_tokens from last turn = current context size
93
93
  model?: string; // per-agent model override
94
94
  isOrchestrator?: boolean; // only orchestrators can delegate to other agents
95
+ canSpawnSubagents?: boolean; // allows using Agent tool even for non-orchestrators
95
96
  }
@@ -1,5 +1,5 @@
1
1
  import type { LucideIcon } from 'lucide-react';
2
- import { Blocks, Code2, TestTube2, Cloud, Database, Layout, ChevronRight, Loader2, GitBranch, Square } from 'lucide-react';
2
+ import { Blocks, Code2, TestTube2, Cloud, Database, Layout, ChevronRight, Loader2, GitBranch, Square, Network } from 'lucide-react';
3
3
  import { useAtomValue } from 'jotai';
4
4
  import { useState } from 'react';
5
5
  import { agentsMapAtom } from '@/atoms';
@@ -59,6 +59,10 @@ export function ChatPanel({ agentId, compact }: { agentId: string; compact?: boo
59
59
  api.patchAgent(agentId, { isOrchestrator: !agent!.isOrchestrator }).catch(() => {});
60
60
  }
61
61
 
62
+ function handleToggleSubagents() {
63
+ api.patchAgent(agentId, { canSpawnSubagents: !agent!.canSpawnSubagents }).catch(() => {});
64
+ }
65
+
62
66
  return (
63
67
  <div className="flex flex-1 flex-col min-w-0 min-h-0 h-full overflow-hidden bg-cc-panel">
64
68
  {/* Header */}
@@ -79,6 +83,18 @@ export function ChatPanel({ agentId, compact }: { agentId: string; compact?: boo
79
83
  </div>
80
84
  </div>
81
85
  <div className="flex items-center gap-2">
86
+ <Tooltip text={agent.canSpawnSubagents ? 'Subagentes ativados' : 'Ativar subagentes'} position="bottom">
87
+ <button
88
+ onClick={handleToggleSubagents}
89
+ className={`inline-flex items-center justify-center w-6 h-6 rounded-md border-none cursor-pointer transition-colors ${
90
+ agent.canSpawnSubagents
91
+ ? 'text-cc-info bg-cc-info/15 hover:bg-cc-info/25'
92
+ : 'text-cc-muted hover:text-cc-text-secondary hover:bg-cc-surface'
93
+ }`}
94
+ >
95
+ <Network size={12} />
96
+ </button>
97
+ </Tooltip>
82
98
  <Tooltip text={agent.isOrchestrator ? 'Orquestrador — pode delegar' : 'Marcar como orquestrador'} position="bottom">
83
99
  <button
84
100
  onClick={handleToggleOrchestrator}
@@ -19,6 +19,7 @@ export interface Agent {
19
19
  customName?: string;
20
20
  closed?: boolean;
21
21
  isOrchestrator?: boolean;
22
+ canSpawnSubagents?: boolean;
22
23
  todos?: Array<{ content: string; status: 'pending' | 'in_progress' | 'completed'; activeForm: string }>;
23
24
  }
24
25
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucashca/claudecontrol",
3
- "version": "0.3.29",
3
+ "version": "0.3.31",
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.29","build":"2026-04-03T23:43:47.390Z"}
1
+ {"version":"0.3.31","build":"2026-04-04T00:03:24.295Z"}