11import { describe , it , expect } from "vitest" ;
2+ import { resolve as pathResolve } from "node:path" ;
23import {
34 parseFileOps ,
45 handleBashPostTool ,
56} from "../../../src/intercept/handlers/bash-postool.js" ;
67
8+ /**
9+ * Path helpers: expected values are built via pathResolve to match the
10+ * platform-native output of the implementation (Windows produces
11+ * backslashes, macOS/Linux produces forward slashes). Hard-coding POSIX
12+ * paths broke Windows CI on v2.1 PR #15 — this file is the fix.
13+ *
14+ * Uses a platform-appropriate "project root": on Windows pathResolve
15+ * pins to the current drive, which is fine because the tests only
16+ * compare against the same pathResolve output.
17+ */
18+ const CWD = pathResolve ( "/proj" ) ;
19+ const expectedAbs = ( rel : string ) => pathResolve ( CWD , rel ) ;
20+
721describe ( "bash-postool — parseFileOps: rm variants" , ( ) => {
822 it ( "parses bare rm with single file" , ( ) => {
9- const r = parseFileOps ( "rm src/foo.ts" , "/proj" ) ;
10- expect ( r ) . toEqual ( [ { action : "prune" , path : "/proj/ src/foo.ts" } ] ) ;
23+ const r = parseFileOps ( "rm src/foo.ts" , CWD ) ;
24+ expect ( r ) . toEqual ( [ { action : "prune" , path : expectedAbs ( " src/foo.ts") } ] ) ;
1125 } ) ;
1226
1327 it ( "parses rm -f" , ( ) => {
14- const r = parseFileOps ( "rm -f src/foo.ts" , "/proj" ) ;
15- expect ( r ) . toEqual ( [ { action : "prune" , path : "/proj/ src/foo.ts" } ] ) ;
28+ const r = parseFileOps ( "rm -f src/foo.ts" , CWD ) ;
29+ expect ( r ) . toEqual ( [ { action : "prune" , path : expectedAbs ( " src/foo.ts") } ] ) ;
1630 } ) ;
1731
1832 it ( "parses rm -rf with multiple files" , ( ) => {
19- const r = parseFileOps ( "rm -rf src/a.ts src/b.ts" , "/proj" ) ;
33+ const r = parseFileOps ( "rm -rf src/a.ts src/b.ts" , CWD ) ;
2034 expect ( r ) . toEqual ( [
21- { action : "prune" , path : "/proj/ src/a.ts" } ,
22- { action : "prune" , path : "/proj/ src/b.ts" } ,
35+ { action : "prune" , path : expectedAbs ( " src/a.ts") } ,
36+ { action : "prune" , path : expectedAbs ( " src/b.ts") } ,
2337 ] ) ;
2438 } ) ;
2539
2640 it ( "keeps absolute paths absolute" , ( ) => {
27- const r = parseFileOps ( "rm /tmp/foo.ts" , "/proj" ) ;
28- expect ( r ) . toEqual ( [ { action : "prune" , path : "/tmp/foo.ts" } ] ) ;
41+ // Use a platform-native absolute path so this test is consistent
42+ // across macOS/Linux (/tmp) and Windows (resolves under current drive).
43+ const abs = pathResolve ( "/tmp/foo.ts" ) ;
44+ const r = parseFileOps ( `rm ${ abs } ` , CWD ) ;
45+ expect ( r ) . toEqual ( [ { action : "prune" , path : abs } ] ) ;
2946 } ) ;
3047} ) ;
3148
3249describe ( "bash-postool — parseFileOps: mv and cp" , ( ) => {
3350 it ( "mv prunes src and reindexes dst" , ( ) => {
34- const r = parseFileOps ( "mv src/old.ts src/new.ts" , "/proj" ) ;
51+ const r = parseFileOps ( "mv src/old.ts src/new.ts" , CWD ) ;
3552 expect ( r ) . toEqual ( [
36- { action : "prune" , path : "/proj/ src/old.ts" } ,
37- { action : "reindex" , path : "/proj/ src/new.ts" } ,
53+ { action : "prune" , path : expectedAbs ( " src/old.ts") } ,
54+ { action : "reindex" , path : expectedAbs ( " src/new.ts") } ,
3855 ] ) ;
3956 } ) ;
4057
4158 it ( "mv with -v flag still parses" , ( ) => {
42- const r = parseFileOps ( "mv -v src/old.ts src/new.ts" , "/proj" ) ;
59+ const r = parseFileOps ( "mv -v src/old.ts src/new.ts" , CWD ) ;
4360 expect ( r ) . toEqual ( [
44- { action : "prune" , path : "/proj/ src/old.ts" } ,
45- { action : "reindex" , path : "/proj/ src/new.ts" } ,
61+ { action : "prune" , path : expectedAbs ( " src/old.ts") } ,
62+ { action : "reindex" , path : expectedAbs ( " src/new.ts") } ,
4663 ] ) ;
4764 } ) ;
4865
4966 it ( "cp reindexes dst only" , ( ) => {
50- const r = parseFileOps ( "cp src/a.ts src/b.ts" , "/proj" ) ;
51- expect ( r ) . toEqual ( [ { action : "reindex" , path : "/proj/ src/b.ts" } ] ) ;
67+ const r = parseFileOps ( "cp src/a.ts src/b.ts" , CWD ) ;
68+ expect ( r ) . toEqual ( [ { action : "reindex" , path : expectedAbs ( " src/b.ts") } ] ) ;
5269 } ) ;
5370
5471 it ( "mv with wrong arg count returns empty" , ( ) => {
55- expect ( parseFileOps ( "mv a.ts" , "/proj" ) ) . toEqual ( [ ] ) ;
56- expect ( parseFileOps ( "mv a.ts b.ts c.ts" , "/proj" ) ) . toEqual ( [ ] ) ;
72+ expect ( parseFileOps ( "mv a.ts" , CWD ) ) . toEqual ( [ ] ) ;
73+ expect ( parseFileOps ( "mv a.ts b.ts c.ts" , CWD ) ) . toEqual ( [ ] ) ;
5774 } ) ;
5875} ) ;
5976
6077describe ( "bash-postool — parseFileOps: git variants" , ( ) => {
6178 it ( "git rm prunes" , ( ) => {
62- const r = parseFileOps ( "git rm src/foo.ts" , "/proj" ) ;
63- expect ( r ) . toEqual ( [ { action : "prune" , path : "/proj/ src/foo.ts" } ] ) ;
79+ const r = parseFileOps ( "git rm src/foo.ts" , CWD ) ;
80+ expect ( r ) . toEqual ( [ { action : "prune" , path : expectedAbs ( " src/foo.ts") } ] ) ;
6481 } ) ;
6582
6683 it ( "git rm -r prunes" , ( ) => {
67- const r = parseFileOps ( "git rm -r src/foo.ts" , "/proj" ) ;
68- expect ( r ) . toEqual ( [ { action : "prune" , path : "/proj/ src/foo.ts" } ] ) ;
84+ const r = parseFileOps ( "git rm -r src/foo.ts" , CWD ) ;
85+ expect ( r ) . toEqual ( [ { action : "prune" , path : expectedAbs ( " src/foo.ts") } ] ) ;
6986 } ) ;
7087
7188 it ( "git mv prunes src and reindexes dst" , ( ) => {
72- const r = parseFileOps ( "git mv old.ts new.ts" , "/proj" ) ;
89+ const r = parseFileOps ( "git mv old.ts new.ts" , CWD ) ;
7390 expect ( r ) . toEqual ( [
74- { action : "prune" , path : "/proj/ old.ts" } ,
75- { action : "reindex" , path : "/proj/ new.ts" } ,
91+ { action : "prune" , path : expectedAbs ( " old.ts") } ,
92+ { action : "reindex" , path : expectedAbs ( " new.ts") } ,
7693 ] ) ;
7794 } ) ;
7895
7996 it ( "unknown git subcommand returns empty" , ( ) => {
80- expect ( parseFileOps ( "git status" , "/proj" ) ) . toEqual ( [ ] ) ;
81- expect ( parseFileOps ( "git commit -m foo" , "/proj" ) ) . toEqual ( [ ] ) ;
97+ expect ( parseFileOps ( "git status" , CWD ) ) . toEqual ( [ ] ) ;
98+ expect ( parseFileOps ( "git commit -m foo" , CWD ) ) . toEqual ( [ ] ) ;
8299 } ) ;
83100} ) ;
84101
85102describe ( "bash-postool — parseFileOps: redirections" , ( ) => {
86103 it ( "cat with single > redirect reindexes dst" , ( ) => {
87- const r = parseFileOps ( "cat template.ts > out.ts" , "/proj" ) ;
88- expect ( r ) . toEqual ( [ { action : "reindex" , path : "/proj/ out.ts" } ] ) ;
104+ const r = parseFileOps ( "cat template.ts > out.ts" , CWD ) ;
105+ expect ( r ) . toEqual ( [ { action : "reindex" , path : expectedAbs ( " out.ts") } ] ) ;
89106 } ) ;
90107
91108 it ( ">> append redirect reindexes dst" , ( ) => {
92- const r = parseFileOps ( "echo foo >> log.ts" , "/proj" ) ;
93- expect ( r ) . toEqual ( [ { action : "reindex" , path : "/proj/ log.ts" } ] ) ;
109+ const r = parseFileOps ( "echo foo >> log.ts" , CWD ) ;
110+ expect ( r ) . toEqual ( [ { action : "reindex" , path : expectedAbs ( " log.ts") } ] ) ;
94111 } ) ;
95112} ) ;
96113
97114describe ( "bash-postool — parseFileOps: pass-through cases" , ( ) => {
98115 it ( "globs pass through" , ( ) => {
99- expect ( parseFileOps ( "rm src/*.ts" , "/proj" ) ) . toEqual ( [ ] ) ;
116+ expect ( parseFileOps ( "rm src/*.ts" , CWD ) ) . toEqual ( [ ] ) ;
100117 } ) ;
101118
102119 it ( "pipes pass through" , ( ) => {
103- expect ( parseFileOps ( "find . | xargs rm" , "/proj" ) ) . toEqual ( [ ] ) ;
120+ expect ( parseFileOps ( "find . | xargs rm" , CWD ) ) . toEqual ( [ ] ) ;
104121 } ) ;
105122
106123 it ( "subshells pass through" , ( ) => {
107- expect ( parseFileOps ( "rm $(find . -name auth)" , "/proj" ) ) . toEqual ( [ ] ) ;
124+ expect ( parseFileOps ( "rm $(find . -name auth)" , CWD ) ) . toEqual ( [ ] ) ;
108125 } ) ;
109126
110127 it ( "backticks pass through" , ( ) => {
111- expect ( parseFileOps ( "rm `find . -name auth`" , "/proj" ) ) . toEqual ( [ ] ) ;
128+ expect ( parseFileOps ( "rm `find . -name auth`" , CWD ) ) . toEqual ( [ ] ) ;
112129 } ) ;
113130
114131 it ( "unrelated commands pass through" , ( ) => {
115- expect ( parseFileOps ( "ls src/" , "/proj" ) ) . toEqual ( [ ] ) ;
116- expect ( parseFileOps ( "grep foo src/*" , "/proj" ) ) . toEqual ( [ ] ) ;
117- expect ( parseFileOps ( "npm test" , "/proj" ) ) . toEqual ( [ ] ) ;
132+ expect ( parseFileOps ( "ls src/" , CWD ) ) . toEqual ( [ ] ) ;
133+ expect ( parseFileOps ( "grep foo src/*" , CWD ) ) . toEqual ( [ ] ) ;
134+ expect ( parseFileOps ( "npm test" , CWD ) ) . toEqual ( [ ] ) ;
118135 } ) ;
119136
120137 it ( "empty / invalid input passes through" , ( ) => {
121- expect ( parseFileOps ( "" , "/proj" ) ) . toEqual ( [ ] ) ;
122- expect ( parseFileOps ( " " , "/proj" ) ) . toEqual ( [ ] ) ;
138+ expect ( parseFileOps ( "" , CWD ) ) . toEqual ( [ ] ) ;
139+ expect ( parseFileOps ( " " , CWD ) ) . toEqual ( [ ] ) ;
123140 // @ts -expect-error — testing runtime guard
124- expect ( parseFileOps ( null , "/proj" ) ) . toEqual ( [ ] ) ;
141+ expect ( parseFileOps ( null , CWD ) ) . toEqual ( [ ] ) ;
125142 } ) ;
126143
127144 it ( "oversized command passes through" , ( ) => {
128145 const huge = "rm " + "x" . repeat ( 501 ) ;
129- expect ( parseFileOps ( huge , "/proj" ) ) . toEqual ( [ ] ) ;
146+ expect ( parseFileOps ( huge , CWD ) ) . toEqual ( [ ] ) ;
130147 } ) ;
131148
132149 it ( "touch passes through (empty file, nothing to index)" , ( ) => {
133- expect ( parseFileOps ( "touch foo.ts" , "/proj" ) ) . toEqual ( [ ] ) ;
150+ expect ( parseFileOps ( "touch foo.ts" , CWD ) ) . toEqual ( [ ] ) ;
134151 } ) ;
135152} ) ;
136153
@@ -139,7 +156,7 @@ describe("bash-postool — handleBashPostTool", () => {
139156 const r = handleBashPostTool ( {
140157 tool_name : "Read" ,
141158 tool_input : { command : "rm foo.ts" } ,
142- cwd : "/proj" ,
159+ cwd : CWD ,
143160 } ) ;
144161 expect ( r . ops ) . toEqual ( [ ] ) ;
145162 } ) ;
@@ -148,7 +165,7 @@ describe("bash-postool — handleBashPostTool", () => {
148165 const r = handleBashPostTool ( {
149166 tool_name : "Bash" ,
150167 tool_input : { } ,
151- cwd : "/proj" ,
168+ cwd : CWD ,
152169 } ) ;
153170 expect ( r . ops ) . toEqual ( [ ] ) ;
154171 } ) ;
@@ -157,8 +174,8 @@ describe("bash-postool — handleBashPostTool", () => {
157174 const r = handleBashPostTool ( {
158175 tool_name : "Bash" ,
159176 tool_input : { command : "rm src/foo.ts" } ,
160- cwd : "/proj" ,
177+ cwd : CWD ,
161178 } ) ;
162- expect ( r . ops ) . toEqual ( [ { action : "prune" , path : "/proj/ src/foo.ts" } ] ) ;
179+ expect ( r . ops ) . toEqual ( [ { action : "prune" , path : expectedAbs ( " src/foo.ts") } ] ) ;
163180 } ) ;
164181} ) ;
0 commit comments