(plan: TaskLaunchPlan)
| 2709 | } |
| 2710 | |
| 2711 | private async startReservedAgentTask(plan: TaskLaunchPlan): Promise<void> { |
| 2712 | assert(plan.taskId.length > 0, "startReservedAgentTask requires taskId"); |
| 2713 | assert(plan.parentWorkspaceId.length > 0, "startReservedAgentTask requires parentWorkspaceId"); |
| 2714 | if (plan.start.kind === "sendMessage") { |
| 2715 | assert(plan.start.prompt.length > 0, "startReservedAgentTask requires prompt"); |
| 2716 | } |
| 2717 | |
| 2718 | const entryAtStart = findWorkspaceEntry(this.config.loadConfigOrDefault(), plan.taskId); |
| 2719 | if (entryAtStart?.workspace.taskStatus !== "starting") { |
| 2720 | return; |
| 2721 | } |
| 2722 | |
| 2723 | // isolation: "none" tasks were queued pointing at the parent's checkout. When that checkout |
| 2724 | // still exists, materialization reuses it (no fork); if it disappeared, materialization falls |
| 2725 | // back to forking a real workspace and the shared flag must be cleared below. |
| 2726 | const taskWasShared = entryAtStart.workspace.taskIsolation === "none"; |
| 2727 | const persistedSharedPath = taskWasShared |
| 2728 | ? coerceNonEmptyString(entryAtStart.workspace.path) |
| 2729 | : undefined; |
| 2730 | |
| 2731 | const initLogger = this.startWorkspaceInit(plan.taskId, plan.parentMeta.projectPath); |
| 2732 | // Supply the parent's persisted path so override-aware runtimes (worktree/SSH) fork from the |
| 2733 | // parent's REAL checkout when the parent is itself an isolation: "none" task (see create()). |
| 2734 | const parentEntryForLaunch = findWorkspaceEntry( |
| 2735 | this.config.loadConfigOrDefault(), |
| 2736 | plan.parentWorkspaceId |
| 2737 | ); |
| 2738 | const runtime = createRuntimeForWorkspace({ |
| 2739 | runtimeConfig: plan.taskRuntimeConfig, |
| 2740 | projectPath: plan.parentMeta.projectPath, |
| 2741 | name: plan.parentMeta.name, |
| 2742 | namedWorkspacePath: coerceNonEmptyString(parentEntryForLaunch?.workspace.path), |
| 2743 | }); |
| 2744 | |
| 2745 | let materialized: MaterializedTaskLaunch | null; |
| 2746 | try { |
| 2747 | materialized = await this.materializeReservedTaskWorkspace(plan, runtime, initLogger); |
| 2748 | } catch (error: unknown) { |
| 2749 | initLogger.logComplete(-1); |
| 2750 | throw error; |
| 2751 | } |
| 2752 | if (!materialized) { |
| 2753 | initLogger.logComplete(-1); |
| 2754 | return; |
| 2755 | } |
| 2756 | |
| 2757 | // Reuse of the persisted shared path means the task still runs in the parent's checkout; |
| 2758 | // any other materialized path means the fork fallback created a real (deletable) workspace. |
| 2759 | const sharesParentCheckout = |
| 2760 | taskWasShared && materialized.workspacePath === persistedSharedPath; |
| 2761 | |
| 2762 | const entryAfterMaterialize = findWorkspaceEntry( |
| 2763 | this.config.loadConfigOrDefault(), |
| 2764 | plan.taskId |
| 2765 | ); |
| 2766 | if (!entryAfterMaterialize) { |
| 2767 | initLogger.logComplete(-1); |
| 2768 | await this.cleanupMaterializedTaskWorkspace( |
no test coverage detected