init claude-code
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Teammate Initialization Module
|
||||
*
|
||||
* Handles initialization for Claude Code instances running as teammates in a swarm.
|
||||
* Registers a Stop hook to notify the team leader when the teammate becomes idle.
|
||||
*/
|
||||
|
||||
import type { AppState } from '../../state/AppState.js'
|
||||
import { logForDebugging } from '../debug.js'
|
||||
import { addFunctionHook } from '../hooks/sessionHooks.js'
|
||||
import { applyPermissionUpdate } from '../permissions/PermissionUpdate.js'
|
||||
import { jsonStringify } from '../slowOperations.js'
|
||||
import { getTeammateColor } from '../teammate.js'
|
||||
import {
|
||||
createIdleNotification,
|
||||
getLastPeerDmSummary,
|
||||
writeToMailbox,
|
||||
} from '../teammateMailbox.js'
|
||||
import { readTeamFile, setMemberActive } from './teamHelpers.js'
|
||||
|
||||
/**
|
||||
* Initializes hooks for a teammate running in a swarm.
|
||||
* Should be called early in session startup after AppState is available.
|
||||
*
|
||||
* Registers a Stop hook that sends an idle notification to the team leader
|
||||
* when this teammate's session stops.
|
||||
*/
|
||||
export function initializeTeammateHooks(
|
||||
setAppState: (updater: (prev: AppState) => AppState) => void,
|
||||
sessionId: string,
|
||||
teamInfo: { teamName: string; agentId: string; agentName: string },
|
||||
): void {
|
||||
const { teamName, agentId, agentName } = teamInfo
|
||||
|
||||
// Read team file to get leader ID
|
||||
const teamFile = readTeamFile(teamName)
|
||||
if (!teamFile) {
|
||||
logForDebugging(`[TeammateInit] Team file not found for team: ${teamName}`)
|
||||
return
|
||||
}
|
||||
|
||||
const leadAgentId = teamFile.leadAgentId
|
||||
|
||||
// Apply team-wide allowed paths if any exist
|
||||
if (teamFile.teamAllowedPaths && teamFile.teamAllowedPaths.length > 0) {
|
||||
logForDebugging(
|
||||
`[TeammateInit] Found ${teamFile.teamAllowedPaths.length} team-wide allowed path(s)`,
|
||||
)
|
||||
|
||||
for (const allowedPath of teamFile.teamAllowedPaths) {
|
||||
// For absolute paths (starting with /), prepend one / to create //path/** pattern
|
||||
// For relative paths, just use path/**
|
||||
const ruleContent = allowedPath.path.startsWith('/')
|
||||
? `/${allowedPath.path}/**`
|
||||
: `${allowedPath.path}/**`
|
||||
|
||||
logForDebugging(
|
||||
`[TeammateInit] Applying team permission: ${allowedPath.toolName} allowed in ${allowedPath.path} (rule: ${ruleContent})`,
|
||||
)
|
||||
|
||||
setAppState(prev => ({
|
||||
...prev,
|
||||
toolPermissionContext: applyPermissionUpdate(
|
||||
prev.toolPermissionContext,
|
||||
{
|
||||
type: 'addRules',
|
||||
rules: [
|
||||
{
|
||||
toolName: allowedPath.toolName,
|
||||
ruleContent,
|
||||
},
|
||||
],
|
||||
behavior: 'allow',
|
||||
destination: 'session',
|
||||
},
|
||||
),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
// Find the leader's name from the members array
|
||||
const leadMember = teamFile.members.find(m => m.agentId === leadAgentId)
|
||||
const leadAgentName = leadMember?.name || 'team-lead'
|
||||
|
||||
// Don't register hook if this agent is the leader
|
||||
if (agentId === leadAgentId) {
|
||||
logForDebugging(
|
||||
'[TeammateInit] This agent is the team leader - skipping idle notification hook',
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
logForDebugging(
|
||||
`[TeammateInit] Registering Stop hook for teammate ${agentName} to notify leader ${leadAgentName}`,
|
||||
)
|
||||
|
||||
// Register Stop hook to notify leader when this teammate stops
|
||||
addFunctionHook(
|
||||
setAppState,
|
||||
sessionId,
|
||||
'Stop',
|
||||
'', // No matcher - applies to all Stop events
|
||||
async (messages, _signal) => {
|
||||
// Mark this teammate as idle in the team config (fire and forget)
|
||||
void setMemberActive(teamName, agentName, false)
|
||||
|
||||
// Send idle notification to the team leader using agent name (not UUID)
|
||||
// Must await to ensure the write completes before process shutdown
|
||||
const notification = createIdleNotification(agentName, {
|
||||
idleReason: 'available',
|
||||
summary: getLastPeerDmSummary(messages),
|
||||
})
|
||||
await writeToMailbox(leadAgentName, {
|
||||
from: agentName,
|
||||
text: jsonStringify(notification),
|
||||
timestamp: new Date().toISOString(),
|
||||
color: getTeammateColor(),
|
||||
})
|
||||
logForDebugging(
|
||||
`[TeammateInit] Sent idle notification to leader ${leadAgentName}`,
|
||||
)
|
||||
return true // Don't block the Stop
|
||||
},
|
||||
'Failed to send idle notification to team leader',
|
||||
{
|
||||
timeout: 10000,
|
||||
},
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user