From b2e7e34567e9875c6985b39add4be1ac8e0a44ac Mon Sep 17 00:00:00 2001 From: roboomp Date: Tue, 21 Jul 2026 22:33:33 +0000 Subject: [PATCH] fix(write): let conflict:// writes reach the resolver - Exempted the handler-less conflict:// scheme from the URI-like guard so parseConflictUri still splices registered blocks. - Extended the near-miss regression to assert conflict://1 reaches the resolver. Fixes #6123 --- packages/coding-agent/src/tools/write.ts | 3 +++ packages/coding-agent/test/write-xdev-dispatch.test.ts | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/packages/coding-agent/src/tools/write.ts b/packages/coding-agent/src/tools/write.ts index e4391bb2b..c1972faf0 100644 --- a/packages/coding-agent/src/tools/write.ts +++ b/packages/coding-agent/src/tools/write.ts @@ -104,6 +104,9 @@ function assertWriteTargetAddressable(target: string, router: InternalUrlRouter) if (!uriLike) return; const scheme = uriLike[1]!.toLowerCase(); + // conflict:// has no router handler but is spliced downstream by + // parseConflictUri (which emits its own precise id/scope errors); let it pass. + if (scheme === "conflict") return; const canonicalScheme = router.getHandler(scheme) ? scheme : XD_SCHEME_NEAR_MISSES[scheme] ? "xd" : undefined; const suggestion = canonicalScheme ? ` Did you mean '${canonicalScheme}://${uriLike[2]}'?` diff --git a/packages/coding-agent/test/write-xdev-dispatch.test.ts b/packages/coding-agent/test/write-xdev-dispatch.test.ts index 811c1446b..aa8f7539c 100644 --- a/packages/coding-agent/test/write-xdev-dispatch.test.ts +++ b/packages/coding-agent/test/write-xdev-dispatch.test.ts @@ -107,6 +107,12 @@ describe("read and write route xd:// device URLs", () => { }); expect(escaped.isError).toBeUndefined(); expect(await Bun.file(path.join(tempDir, "xd/web_search")).text()).toBe("intentional file"); + + // conflict:// has no router handler but is a documented write scheme — + // the guard must let it reach the conflict resolver, not reject it. + await expect(write!.execute("write-conflict", { path: "conflict://1", content: "x" })).rejects.toThrow( + "Conflict #1 not found", + ); } finally { await removeWithRetries(tempDir); }