(ancestorWorkspaceId: string, taskId: string)
| 6402 | } |
| 6403 | |
| 6404 | async isDescendantAgentTask(ancestorWorkspaceId: string, taskId: string): Promise<boolean> { |
| 6405 | assert(ancestorWorkspaceId.length > 0, "isDescendantAgentTask: ancestorWorkspaceId required"); |
| 6406 | assert(taskId.length > 0, "isDescendantAgentTask: taskId required"); |
| 6407 | |
| 6408 | const cfg = this.config.loadConfigOrDefault(); |
| 6409 | const parentById = this.buildAgentTaskIndex(cfg).parentById; |
| 6410 | if (this.isDescendantAgentTaskUsingParentById(parentById, ancestorWorkspaceId, taskId)) { |
| 6411 | return true; |
| 6412 | } |
| 6413 | |
| 6414 | // The task workspace may have been removed after it settled (cleanup/restart). Preserve scope |
| 6415 | // checks by consulting persisted report AND failure artifacts in the ancestor session dir — |
| 6416 | // a terminally-failed child must stay awaitable so its typed failure can be surfaced. |
| 6417 | const cached = this.completedReportsByTaskId.get(taskId); |
| 6418 | if (hasAncestorWorkspaceId(cached, ancestorWorkspaceId)) { |
| 6419 | return true; |
| 6420 | } |
| 6421 | |
| 6422 | const sessionDir = this.config.getSessionDir(ancestorWorkspaceId); |
| 6423 | const [reports, failures] = await Promise.all([ |
| 6424 | readSubagentReportArtifactsFile(sessionDir), |
| 6425 | readSubagentFailureArtifactsFile(sessionDir), |
| 6426 | ]); |
| 6427 | return ( |
| 6428 | hasAncestorWorkspaceId(reports.artifactsByChildTaskId[taskId], ancestorWorkspaceId) || |
| 6429 | hasAncestorWorkspaceId(failures.failuresByChildTaskId[taskId], ancestorWorkspaceId) |
| 6430 | ); |
| 6431 | } |
| 6432 | |
| 6433 | private isDescendantAgentTaskUsingParentById( |
| 6434 | parentById: Map<string, string>, |
no test coverage detected