mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-23 00:35:51 +00:00
feat: 添加 builtin-tools 增强与测试覆盖
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -14,11 +14,26 @@ import {
|
||||
} from 'src/utils/swarm/teamHelpers.js'
|
||||
import { clearTeammateColors } from 'src/utils/swarm/teammateLayoutManager.js'
|
||||
import { clearLeaderTeamName } from 'src/utils/tasks.js'
|
||||
import { ensureBackendsRegistered, getBackendByType, getInProcessBackend } from 'src/utils/swarm/backends/registry.js'
|
||||
import { createPaneBackendExecutor } from 'src/utils/swarm/backends/PaneBackendExecutor.js'
|
||||
import { isPaneBackend } from 'src/utils/swarm/backends/types.js'
|
||||
import { sleep } from 'src/utils/sleep.js'
|
||||
import { TEAM_DELETE_TOOL_NAME } from './constants.js'
|
||||
import { getPrompt } from './prompt.js'
|
||||
import { renderToolResultMessage, renderToolUseMessage } from './UI.js'
|
||||
|
||||
const inputSchema = lazySchema(() => z.strictObject({}))
|
||||
const inputSchema = lazySchema(() =>
|
||||
z.strictObject({
|
||||
wait_ms: z
|
||||
.number()
|
||||
.min(0)
|
||||
.max(30_000)
|
||||
.optional()
|
||||
.describe(
|
||||
'Optional time to wait for active teammates to acknowledge shutdown before cleanup.',
|
||||
),
|
||||
}),
|
||||
)
|
||||
type InputSchema = ReturnType<typeof inputSchema>
|
||||
|
||||
export type Output = {
|
||||
@@ -68,7 +83,7 @@ export const TeamDeleteTool: Tool<InputSchema, Output> = buildTool({
|
||||
}
|
||||
},
|
||||
|
||||
async call(_input, context) {
|
||||
async call(input, context) {
|
||||
const { setAppState, getAppState } = context
|
||||
const appState = getAppState()
|
||||
const teamName = appState.teamContext?.teamName
|
||||
@@ -87,13 +102,82 @@ export const TeamDeleteTool: Tool<InputSchema, Output> = buildTool({
|
||||
const activeMembers = nonLeadMembers.filter(m => m.isActive !== false)
|
||||
|
||||
if (activeMembers.length > 0) {
|
||||
const memberNames = activeMembers.map(m => m.name).join(', ')
|
||||
return {
|
||||
data: {
|
||||
success: false,
|
||||
message: `Cannot cleanup team with ${activeMembers.length} active member(s): ${memberNames}. Use requestShutdown to gracefully terminate teammates first.`,
|
||||
team_name: teamName,
|
||||
},
|
||||
const requested: string[] = []
|
||||
for (const member of activeMembers) {
|
||||
let sent = false
|
||||
if (member.backendType === 'in-process') {
|
||||
const executor = getInProcessBackend()
|
||||
executor.setContext?.(context)
|
||||
sent = await executor.terminate(
|
||||
member.agentId,
|
||||
'Team cleanup requested by team lead',
|
||||
)
|
||||
} else if (member.backendType && isPaneBackend(member.backendType)) {
|
||||
await ensureBackendsRegistered()
|
||||
const executor = createPaneBackendExecutor(
|
||||
getBackendByType(member.backendType),
|
||||
)
|
||||
executor.setContext?.(context)
|
||||
sent = await executor.terminate(
|
||||
member.agentId,
|
||||
'Team cleanup requested by team lead',
|
||||
)
|
||||
}
|
||||
if (sent) {
|
||||
requested.push(member.name)
|
||||
}
|
||||
}
|
||||
const waitMs = input.wait_ms ?? 0
|
||||
if (waitMs > 0 && requested.length > 0) {
|
||||
const deadline = Date.now() + waitMs
|
||||
while (Date.now() < deadline) {
|
||||
await sleep(Math.min(250, Math.max(0, deadline - Date.now())))
|
||||
const refreshed = readTeamFile(teamName)
|
||||
const stillActive =
|
||||
refreshed?.members.filter(
|
||||
m => m.name !== TEAM_LEAD_NAME && m.isActive !== false,
|
||||
) ?? []
|
||||
if (stillActive.length === 0) {
|
||||
break
|
||||
}
|
||||
}
|
||||
const refreshed = readTeamFile(teamName)
|
||||
const stillActive =
|
||||
refreshed?.members.filter(
|
||||
m => m.name !== TEAM_LEAD_NAME && m.isActive !== false,
|
||||
) ?? []
|
||||
if (stillActive.length === 0) {
|
||||
// Fall through to cleanup with the refreshed team file state.
|
||||
} else {
|
||||
const memberNames = stillActive.map(m => m.name).join(', ')
|
||||
return {
|
||||
data: {
|
||||
success: false,
|
||||
message: `Shutdown requested for active teammate(s): ${requested.join(', ')}. Cleanup is still blocked after waiting ${waitMs}ms: ${memberNames}.`,
|
||||
team_name: teamName,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
const latestTeamFile = readTeamFile(teamName)
|
||||
const latestActiveMembers =
|
||||
latestTeamFile?.members.filter(
|
||||
m => m.name !== TEAM_LEAD_NAME && m.isActive !== false,
|
||||
) ?? []
|
||||
if (latestActiveMembers.length === 0) {
|
||||
// Continue to cleanup below.
|
||||
} else {
|
||||
const memberNames = latestActiveMembers.map(m => m.name).join(', ')
|
||||
return {
|
||||
data: {
|
||||
success: false,
|
||||
message:
|
||||
requested.length > 0
|
||||
? `Shutdown requested for active teammate(s): ${requested.join(', ')}. Cleanup is blocked until they exit: ${memberNames}.`
|
||||
: `Cannot cleanup team with ${latestActiveMembers.length} active member(s): ${memberNames}. Use requestShutdown to gracefully terminate teammates first.`,
|
||||
team_name: teamName,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user