@@ -181,9 +181,10 @@ describe('createAIInstructions()', () => {
181181
182182 // Then
183183 expect ( downloadGitRepository ) . toHaveBeenCalled ( )
184- // github, cursor, claude
185- expect ( readFile ) . toHaveBeenCalledTimes ( 3 )
186- expect ( writeFile ) . toHaveBeenCalledTimes ( 3 )
184+ // Read source file once, write AGENTS.md once
185+ expect ( readFile ) . toHaveBeenCalledTimes ( 1 )
186+ expect ( writeFile ) . toHaveBeenCalledTimes ( 1 )
187+ // Create symlinks for github, cursor, claude
187188 expect ( symlink ) . toHaveBeenCalledTimes ( 3 )
188189 expect ( symlink ) . toHaveBeenCalledWith ( '/path/to/theme/AGENTS.md' , '/path/to/theme/copilot-instructions.md' )
189190 expect ( symlink ) . toHaveBeenCalledWith ( '/path/to/theme/AGENTS.md' , '/path/to/theme/.cursorrules' )
@@ -200,8 +201,8 @@ describe('createAIInstructions()', () => {
200201} )
201202
202203describe ( 'createAIInstructionFiles()' , ( ) => {
203- const tempDir = '/tmp'
204204 const themeRoot = '/path/to/theme'
205+ const agentsPath = '/path/to/theme/AGENTS.md'
205206
206207 beforeEach ( ( ) => {
207208 vi . mocked ( joinPath ) . mockImplementation ( ( ...paths ) => paths . join ( '/' ) )
@@ -210,45 +211,53 @@ describe('createAIInstructionFiles()', () => {
210211 vi . mocked ( symlink ) . mockResolvedValue ( )
211212 } )
212213
213- test ( 'creates AGENTS.md with prepended header for github instruction' , async ( ) => {
214+ test ( 'creates symlink for github instruction' , async ( ) => {
214215 // When
215- await createAIInstructionFiles ( tempDir , themeRoot , 'github' )
216+ const result = await createAIInstructionFiles ( themeRoot , agentsPath , 'github' )
216217
217218 // Then
218- expect ( readFile ) . toHaveBeenCalledWith ( '/tmp/ai/github/copilot-instructions.md' )
219- expect ( writeFile ) . toHaveBeenCalledWith ( '/path/to/theme/AGENTS.md' , '# AGENTS.md\n\nAI instruction content' )
220219 expect ( symlink ) . toHaveBeenCalledWith ( '/path/to/theme/AGENTS.md' , '/path/to/theme/copilot-instructions.md' )
220+ expect ( result . copiedFile ) . toBeUndefined ( )
221221 } )
222222
223- test ( 'creates AGENTS.md and .cursorrules symlink for cursor instruction' , async ( ) => {
223+ test ( 'creates symlink for cursor instruction' , async ( ) => {
224224 // When
225- await createAIInstructionFiles ( tempDir , themeRoot , 'cursor' )
225+ const result = await createAIInstructionFiles ( themeRoot , agentsPath , 'cursor' )
226226
227227 // Then
228- expect ( readFile ) . toHaveBeenCalledWith ( '/tmp/ai/github/copilot-instructions.md' )
229- expect ( writeFile ) . toHaveBeenCalledWith ( '/path/to/theme/AGENTS.md' , '# AGENTS.md\n\nAI instruction content' )
230228 expect ( symlink ) . toHaveBeenCalledWith ( '/path/to/theme/AGENTS.md' , '/path/to/theme/.cursorrules' )
229+ expect ( result . copiedFile ) . toBeUndefined ( )
231230 } )
232231
233- test ( 'creates AGENTS.md and CLAUDE.md symlink for claude instruction' , async ( ) => {
232+ test ( 'creates symlink for claude instruction' , async ( ) => {
234233 // When
235- await createAIInstructionFiles ( tempDir , themeRoot , 'claude' )
234+ const result = await createAIInstructionFiles ( themeRoot , agentsPath , 'claude' )
236235
237236 // Then
238- expect ( readFile ) . toHaveBeenCalledWith ( '/tmp/ai/github/copilot-instructions.md' )
239- expect ( writeFile ) . toHaveBeenCalledWith ( '/path/to/theme/AGENTS.md' , '# AGENTS.md\n\nAI instruction content' )
240237 expect ( symlink ) . toHaveBeenCalledWith ( '/path/to/theme/AGENTS.md' , '/path/to/theme/CLAUDE.md' )
238+ expect ( result . copiedFile ) . toBeUndefined ( )
241239 } )
242240
243- test ( 'prepends header to source content ' , async ( ) => {
241+ test ( 'falls back to copying file when symlink fails with EPERM ' , async ( ) => {
244242 // Given
245- const sourceContent = 'Original content from repo'
246- vi . mocked ( readFile ) . mockResolvedValue ( sourceContent as any )
243+ vi . mocked ( symlink ) . mockRejectedValue ( new Error ( 'EPERM: operation not permitted' ) )
244+ vi . mocked ( readFile ) . mockResolvedValue ( 'AGENTS.md content' as any )
247245
248246 // When
249- await createAIInstructionFiles ( tempDir , themeRoot , 'github' )
247+ const result = await createAIInstructionFiles ( themeRoot , agentsPath , 'github' )
250248
251249 // Then
252- expect ( writeFile ) . toHaveBeenCalledWith ( '/path/to/theme/AGENTS.md' , `# AGENTS.md\n\n${ sourceContent } ` )
250+ expect ( symlink ) . toHaveBeenCalled ( )
251+ expect ( readFile ) . toHaveBeenCalledWith ( agentsPath )
252+ expect ( writeFile ) . toHaveBeenCalledWith ( '/path/to/theme/copilot-instructions.md' , 'AGENTS.md content' )
253+ expect ( result . copiedFile ) . toBe ( 'copilot-instructions.md' )
254+ } )
255+
256+ test ( 'throws error when symlink fails with non-EPERM error' , async ( ) => {
257+ // Given
258+ vi . mocked ( symlink ) . mockRejectedValue ( new Error ( 'Some other error' ) )
259+
260+ // When/Then
261+ await expect ( createAIInstructionFiles ( themeRoot , agentsPath , 'github' ) ) . rejects . toThrow ( 'Some other error' )
253262 } )
254263} )
0 commit comments