diff --git a/packages/coding-agent/src/core/extensions/builtin/rules/changes.md b/packages/coding-agent/src/core/extensions/builtin/rules/changes.md index 85e797ee2e..d2c10a8886 100644 --- a/packages/coding-agent/src/core/extensions/builtin/rules/changes.md +++ b/packages/coding-agent/src/core/extensions/builtin/rules/changes.md @@ -7,7 +7,8 @@ Vendored from [`code-yeongyu/pi-rules`](https://github.com/code-yeongyu/pi-rules - Imports rewritten by `scripts/vendor-transform.mjs`: `@mariozechner/pi-tui` -> `@earendil-works/pi-tui`; `@mariozechner/pi-coding-agent` symbols -> `../../types.ts` (and `Theme` -> `modes/interactive/theme/theme.ts`); relative `.js` import suffixes -> `.ts`. - `ui/dynamic-border.ts` and `ui/rules-banner.ts`: constructor parameter properties (`private readonly …`) -> explicit fields + constructor assignment (senpi's root tsconfig is `erasableSyntaxOnly`; parameter properties are disallowed). - Runtime dep `picomatch` (+ `@types/picomatch`) added to `package.json`. -- No behavior changes. Registers `/rules` and `/reload-rules` and discovers rule files from `.sisyphus/rules`, `.claude/rules`, `.cursor/rules`, `.github/instructions`, `AGENTS.md`, `CLAUDE.md`. +- `rules/project-root.ts`: `findProjectRoot` stops the marker walk when `dirname()` stops progressing, fixing an infinite synchronous loop for targets on a different Windows drive than cwd (or UNC shares). Behavior fix also submitted upstream: https://github.com/code-yeongyu/pi-rules/pull/19 — drop this adaptation once a fixed pi-rules release is re-vendored. +- No other behavior changes. Registers `/rules` and `/reload-rules` and discovers rule files from `.sisyphus/rules`, `.claude/rules`, `.cursor/rules`, `.github/instructions`, `AGENTS.md`, `CLAUDE.md`. ## Conflict zones diff --git a/packages/coding-agent/src/core/extensions/builtin/rules/rules/project-root.ts b/packages/coding-agent/src/core/extensions/builtin/rules/rules/project-root.ts index 2c3f387309..bf2c4decc4 100644 --- a/packages/coding-agent/src/core/extensions/builtin/rules/rules/project-root.ts +++ b/packages/coding-agent/src/core/extensions/builtin/rules/rules/project-root.ts @@ -25,6 +25,13 @@ export function findProjectRoot(startPath: string, markers: ReadonlyArray ({ + cwdRoot: "E:\\", + startPath: "C:\\workspace\\plain\\nested", +})); + +vi.mock("node:fs", () => ({ + existsSync: (path: string) => path === startPath, + statSync: () => ({ isDirectory: () => true }), +})); + +vi.mock("node:path", async (importOriginal) => { + const path = await importOriginal(); + return { + ...path, + dirname: path.win32.dirname, + join: path.win32.join, + resolve: (input: string) => (input === "/" ? cwdRoot : path.win32.resolve(input)), + }; +}); + +describe("rules findProjectRoot cross-drive termination", () => { + it("#given startPath on a different drive than cwd (Windows cross-drive) #when finding root #then terminates with null instead of looping forever", () => { + // given + expect(win32.dirname("C:\\")).toBe("C:\\"); + + // when + const result = findProjectRoot(startPath, [".nonexistent-marker-senpi"]); + + // then + expect(result).toBeNull(); + }); +});