mirror of
https://github.com/stablyai/orca.git
synced 2026-10-29 08:07:18 +00:00
fix(agent-status): prune persisted idle Claude children
This commit is contained in:
@@ -6046,6 +6046,58 @@ describe('Last-status persistence', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('drops persisted idle Claude child rows from hydration replay', async () => {
|
||||
mkdirSync(join(userDataPath, 'agent-hooks'), { recursive: true })
|
||||
const receivedAt = recentTs()
|
||||
writeFileSync(
|
||||
lastStatusPath(),
|
||||
JSON.stringify({
|
||||
version: 2,
|
||||
entries: {
|
||||
[PANE]: {
|
||||
paneKey: PANE,
|
||||
tabId: 'tab-1',
|
||||
worktreeId: 'wt-1',
|
||||
receivedAt,
|
||||
stateStartedAt: recentTs(-1000),
|
||||
payload: {
|
||||
state: 'done',
|
||||
prompt: 'finished orchestration',
|
||||
agentType: 'claude',
|
||||
subagents: [
|
||||
{ id: 'aweb-research-8a76b7d7', state: 'idle', startedAt: receivedAt - 5000 },
|
||||
{ id: 'apr-history-9b87c6e6', state: 'idle', startedAt: receivedAt - 4000 }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
const server = new AgentHookServer()
|
||||
await server.start({ env: 'production', userDataPath })
|
||||
try {
|
||||
const listener = vi.fn()
|
||||
server.setListener(listener)
|
||||
|
||||
expect(listener).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
payload: expect.objectContaining({ subagents: undefined })
|
||||
})
|
||||
)
|
||||
expect(server.getStatusSnapshot()).toEqual([
|
||||
expect.objectContaining({
|
||||
state: 'done',
|
||||
prompt: 'finished orchestration',
|
||||
subagents: undefined
|
||||
})
|
||||
])
|
||||
} finally {
|
||||
server.stop()
|
||||
}
|
||||
})
|
||||
|
||||
it('treats a corrupt file as empty hydration without throwing', async () => {
|
||||
mkdirSync(join(userDataPath, 'agent-hooks'), { recursive: true })
|
||||
writeFileSync(lastStatusPath(), 'not-json{{', 'utf8')
|
||||
|
||||
@@ -174,6 +174,24 @@ export function isValidPaneKey(value: unknown): value is string {
|
||||
)
|
||||
}
|
||||
|
||||
function dropHydratedIdleClaudeSubagents(
|
||||
payload: ParsedAgentStatusPayload
|
||||
): ParsedAgentStatusPayload {
|
||||
if (
|
||||
payload.agentType !== 'claude' ||
|
||||
!payload.subagents?.some((subagent) => subagent.state === 'idle')
|
||||
) {
|
||||
return payload
|
||||
}
|
||||
const workingSubagents = payload.subagents.filter((subagent) => subagent.state === 'working')
|
||||
// Why: older builds persisted finished Claude children as idle rows. Prune
|
||||
// them from the replay payload itself so restart cannot resurrect the pile.
|
||||
return {
|
||||
...payload,
|
||||
subagents: workingSubagents.length > 0 ? workingSubagents : undefined
|
||||
}
|
||||
}
|
||||
|
||||
function sanitizeHydratedEntry(
|
||||
paneKey: string,
|
||||
rawEntry: unknown
|
||||
@@ -226,10 +244,11 @@ function sanitizeHydratedEntry(
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
const payload = normalizeAgentStatusPayload(record.payload)
|
||||
if (!payload) {
|
||||
const normalizedPayload = normalizeAgentStatusPayload(record.payload)
|
||||
if (!normalizedPayload) {
|
||||
return null
|
||||
}
|
||||
const payload = dropHydratedIdleClaudeSubagents(normalizedPayload)
|
||||
return {
|
||||
paneKey,
|
||||
launchToken: typeof record.launchToken === 'string' ? record.launchToken : undefined,
|
||||
|
||||
@@ -34,8 +34,8 @@ export const CLAUDE_EVENTS = [
|
||||
{ eventName: 'StopFailure', definition: { hooks: [{ type: 'command', command: '' }] } },
|
||||
// Why: subagent/teammate lifecycle feeds the sidebar's child rows and keeps
|
||||
// a pane 'working' while background children outlive the lead's turn.
|
||||
// TeammateIdle is required because idle-but-alive teammates still report
|
||||
// status "running" in Stop's background_tasks.
|
||||
// TeammateIdle retires the working-only row when SubagentStop is lost;
|
||||
// idle teammates still report status "running" in Stop's background_tasks.
|
||||
// Older Claude builds ignore unregistered event names (StopFailure precedent).
|
||||
{ eventName: 'SubagentStart', definition: { hooks: [{ type: 'command', command: '' }] } },
|
||||
{ eventName: 'SubagentStop', definition: { hooks: [{ type: 'command', command: '' }] } },
|
||||
|
||||
Reference in New Issue
Block a user