From 7158dcd9b3bbee27ddf9983c40f71e299058e4c8 Mon Sep 17 00:00:00 2001 From: can1357 Date: Thu, 23 Jul 2026 21:54:35 +0200 Subject: [PATCH] fix(coding-agent): deferred hub tool renderer access to avoid temporal dead zone - Convert the hub tool renderer to a lazy getter to prevent initialization-order temporal dead zone issues. - Add session move support to the fake ACP builtin session runtime. --- packages/coding-agent/src/tools/renderers.ts | 8 +++++++- packages/coding-agent/test/acp-builtins.test.ts | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/coding-agent/src/tools/renderers.ts b/packages/coding-agent/src/tools/renderers.ts index 895718bc2..b45b717b9 100644 --- a/packages/coding-agent/src/tools/renderers.ts +++ b/packages/coding-agent/src/tools/renderers.ts @@ -90,7 +90,13 @@ export const toolRenderers: Record = { grep: grepToolRenderer as ToolRenderer, lsp: lspToolRenderer as ToolRenderer, inspect_image: inspectImageToolRenderer as ToolRenderer, - hub: hubToolRenderer as ToolRenderer, + // Lazy getter: `hubToolRenderer` lives in a module whose deps (messaging → + // persisted-agents → vibe/runtime → task/executor → sdk) close an import + // cycle back here, so reading it at init order-dependently hits its + // temporal dead zone. Deferring the read to first access sidesteps it. + get hub(): ToolRenderer { + return hubToolRenderer as ToolRenderer; + }, read: readToolRenderer as ToolRenderer, // Keyed by xd:// resolution-device names: the write dispatch delegates here // by dispatch tool, and historical `resolve` tool transcripts still render diff --git a/packages/coding-agent/test/acp-builtins.test.ts b/packages/coding-agent/test/acp-builtins.test.ts index 1f5995fe4..627b65b4e 100644 --- a/packages/coding-agent/test/acp-builtins.test.ts +++ b/packages/coding-agent/test/acp-builtins.test.ts @@ -38,6 +38,7 @@ interface FakeAcpBuiltinSession { model: { provider: string; id: string } | undefined; newSession(opts?: { drop?: boolean; parentSession?: string }): Promise; switchSession(sessionPath: string): Promise; + moveSession(newCwd: string, targetSessionDir?: string): Promise; markMovedFromEmptySessionFile(sessionFile: string): void; fork(): Promise; handoff(instr?: string): Promise<{ document: string; savedPath?: string } | undefined>; @@ -121,6 +122,10 @@ function createRuntime() { await fakeSessionManager.setSessionFile(this._switchedTo); return true; }, + async moveSession(newCwd: string, _targetSessionDir?: string) { + if (!fakeSessionManager) throw new Error("fake session manager not initialized"); + await fakeSessionManager.moveTo(newCwd); + }, markMovedFromEmptySessionFile(sessionFile: string) { this._movedFromEmptySessionFile = path.resolve(sessionFile); },