init claude-code

This commit is contained in:
2026-04-01 17:32:37 +02:00
commit 73b208c009
1902 changed files with 513237 additions and 0 deletions
+139
View File
@@ -0,0 +1,139 @@
import { z } from 'zod/v4'
import { logEvent } from '../../services/analytics/index.js'
import type { AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from '../../services/analytics/metadata.js'
import type { Tool } from '../../Tool.js'
import { buildTool, type ToolDef } from '../../Tool.js'
import { isAgentSwarmsEnabled } from '../../utils/agentSwarmsEnabled.js'
import { lazySchema } from '../../utils/lazySchema.js'
import { jsonStringify } from '../../utils/slowOperations.js'
import { TEAM_LEAD_NAME } from '../../utils/swarm/constants.js'
import {
cleanupTeamDirectories,
readTeamFile,
unregisterTeamForSessionCleanup,
} from '../../utils/swarm/teamHelpers.js'
import { clearTeammateColors } from '../../utils/swarm/teammateLayoutManager.js'
import { clearLeaderTeamName } from '../../utils/tasks.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({}))
type InputSchema = ReturnType<typeof inputSchema>
export type Output = {
success: boolean
message: string
team_name?: string
}
export type Input = z.infer<InputSchema>
export const TeamDeleteTool: Tool<InputSchema, Output> = buildTool({
name: TEAM_DELETE_TOOL_NAME,
searchHint: 'disband a swarm team and clean up',
maxResultSizeChars: 100_000,
shouldDefer: true,
userFacingName() {
return ''
},
get inputSchema(): InputSchema {
return inputSchema()
},
isEnabled() {
return isAgentSwarmsEnabled()
},
async description() {
return 'Clean up team and task directories when the swarm is complete'
},
async prompt() {
return getPrompt()
},
mapToolResultToToolResultBlockParam(data, toolUseID) {
return {
tool_use_id: toolUseID,
type: 'tool_result' as const,
content: [
{
type: 'text' as const,
text: jsonStringify(data),
},
],
}
},
async call(_input, context) {
const { setAppState, getAppState } = context
const appState = getAppState()
const teamName = appState.teamContext?.teamName
if (teamName) {
// Read team config to check for active members
const teamFile = readTeamFile(teamName)
if (teamFile) {
// Filter out the team lead - only count non-lead members
const nonLeadMembers = teamFile.members.filter(
m => m.name !== TEAM_LEAD_NAME,
)
// Separate truly active members from idle/dead ones
// Members with isActive === false are idle (finished their turn or crashed)
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,
},
}
}
}
await cleanupTeamDirectories(teamName)
// Already cleaned — don't try again on gracefulShutdown.
unregisterTeamForSessionCleanup(teamName)
// Clear color assignments so new teams start fresh
clearTeammateColors()
// Clear leader team name so getTaskListId() falls back to session ID
clearLeaderTeamName()
logEvent('tengu_team_deleted', {
team_name:
teamName as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
})
}
// Clear team context and inbox from app state
setAppState(prev => ({
...prev,
teamContext: undefined,
inbox: {
messages: [], // Clear any queued messages
},
}))
return {
data: {
success: true,
message: teamName
? `Cleaned up directories and worktrees for team "${teamName}"`
: 'No team name found, nothing to clean up',
team_name: teamName,
},
}
},
renderToolUseMessage,
renderToolResultMessage,
} satisfies ToolDef<InputSchema, Output>)
+20
View File
@@ -0,0 +1,20 @@
import React from 'react';
import { jsonParse } from '../../utils/slowOperations.js';
import type { Output } from './TeamDeleteTool.js';
export function renderToolUseMessage(_input: Record<string, unknown>): React.ReactNode {
return 'cleanup team: current';
}
export function renderToolResultMessage(content: Output | string, _progressMessages: unknown, {
verbose: _verbose
}: {
verbose: boolean;
}): React.ReactNode {
const result: Output = typeof content === 'string' ? jsonParse(content) : content;
// Suppress cleanup result - the batched shutdown message covers this
if ('success' in result && 'team_name' in result && 'message' in result) {
return null;
}
return null;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsImpzb25QYXJzZSIsIk91dHB1dCIsInJlbmRlclRvb2xVc2VNZXNzYWdlIiwiX2lucHV0IiwiUmVjb3JkIiwiUmVhY3ROb2RlIiwicmVuZGVyVG9vbFJlc3VsdE1lc3NhZ2UiLCJjb250ZW50IiwiX3Byb2dyZXNzTWVzc2FnZXMiLCJ2ZXJib3NlIiwiX3ZlcmJvc2UiLCJyZXN1bHQiXSwic291cmNlcyI6WyJVSS50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsganNvblBhcnNlIH0gZnJvbSAnLi4vLi4vdXRpbHMvc2xvd09wZXJhdGlvbnMuanMnXG5pbXBvcnQgdHlwZSB7IE91dHB1dCB9IGZyb20gJy4vVGVhbURlbGV0ZVRvb2wuanMnXG5cbmV4cG9ydCBmdW5jdGlvbiByZW5kZXJUb29sVXNlTWVzc2FnZShcbiAgX2lucHV0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbik6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIHJldHVybiAnY2xlYW51cCB0ZWFtOiBjdXJyZW50J1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVuZGVyVG9vbFJlc3VsdE1lc3NhZ2UoXG4gIGNvbnRlbnQ6IE91dHB1dCB8IHN0cmluZyxcbiAgX3Byb2dyZXNzTWVzc2FnZXM6IHVua25vd24sXG4gIHsgdmVyYm9zZTogX3ZlcmJvc2UgfTogeyB2ZXJib3NlOiBib29sZWFuIH0sXG4pOiBSZWFjdC5SZWFjdE5vZGUge1xuICBjb25zdCByZXN1bHQ6IE91dHB1dCA9XG4gICAgdHlwZW9mIGNvbnRlbnQgPT09ICdzdHJpbmcnID8ganNvblBhcnNlKGNvbnRlbnQpIDogY29udGVudFxuXG4gIC8vIFN1cHByZXNzIGNsZWFudXAgcmVzdWx0IC0gdGhlIGJhdGNoZWQgc2h1dGRvd24gbWVzc2FnZSBjb3ZlcnMgdGhpc1xuICBpZiAoJ3N1Y2Nlc3MnIGluIHJlc3VsdCAmJiAndGVhbV9uYW1lJyBpbiByZXN1bHQgJiYgJ21lc3NhZ2UnIGluIHJlc3VsdCkge1xuICAgIHJldHVybiBudWxsXG4gIH1cblxuICByZXR1cm4gbnVsbFxufVxuIl0sIm1hcHBpbmdzIjoiQUFBQSxPQUFPQSxLQUFLLE1BQU0sT0FBTztBQUN6QixTQUFTQyxTQUFTLFFBQVEsK0JBQStCO0FBQ3pELGNBQWNDLE1BQU0sUUFBUSxxQkFBcUI7QUFFakQsT0FBTyxTQUFTQyxvQkFBb0JBLENBQ2xDQyxNQUFNLEVBQUVDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQ2hDLEVBQUVMLEtBQUssQ0FBQ00sU0FBUyxDQUFDO0VBQ2pCLE9BQU8sdUJBQXVCO0FBQ2hDO0FBRUEsT0FBTyxTQUFTQyx1QkFBdUJBLENBQ3JDQyxPQUFPLEVBQUVOLE1BQU0sR0FBRyxNQUFNLEVBQ3hCTyxpQkFBaUIsRUFBRSxPQUFPLEVBQzFCO0VBQUVDLE9BQU8sRUFBRUM7QUFBK0IsQ0FBckIsRUFBRTtFQUFFRCxPQUFPLEVBQUUsT0FBTztBQUFDLENBQUMsQ0FDNUMsRUFBRVYsS0FBSyxDQUFDTSxTQUFTLENBQUM7RUFDakIsTUFBTU0sTUFBTSxFQUFFVixNQUFNLEdBQ2xCLE9BQU9NLE9BQU8sS0FBSyxRQUFRLEdBQUdQLFNBQVMsQ0FBQ08sT0FBTyxDQUFDLEdBQUdBLE9BQU87O0VBRTVEO0VBQ0EsSUFBSSxTQUFTLElBQUlJLE1BQU0sSUFBSSxXQUFXLElBQUlBLE1BQU0sSUFBSSxTQUFTLElBQUlBLE1BQU0sRUFBRTtJQUN2RSxPQUFPLElBQUk7RUFDYjtFQUVBLE9BQU8sSUFBSTtBQUNiIiwiaWdub3JlTGlzdCI6W119
+1
View File
@@ -0,0 +1 @@
export const TEAM_DELETE_TOOL_NAME = 'TeamDelete'
+16
View File
@@ -0,0 +1,16 @@
export function getPrompt(): string {
return `
# TeamDelete
Remove team and task directories when the swarm work is complete.
This operation:
- Removes the team directory (\`~/.claude/teams/{team-name}/\`)
- Removes the task directory (\`~/.claude/tasks/{team-name}/\`)
- Clears team context from the current session
**IMPORTANT**: TeamDelete will fail if the team still has active members. Gracefully terminate teammates first, then call TeamDelete after all teammates have shut down.
Use this when all teammates have finished their work and you want to clean up the team resources. The team name is automatically determined from the current session's team context.
`.trim()
}