@@ -8,6 +8,7 @@ import fs from "fs/promises"
88import { pathToFileURL } from "url"
99import { Global } from "../../src/global"
1010import { Filesystem } from "../../src/util/filesystem"
11+ import { ConfigPaths } from "../../src/config/paths"
1112
1213// Get managed config directory from environment (set in preload.ts)
1314const managedConfigDir = process . env . OPENCODE_TEST_MANAGED_CONFIG_DIR !
@@ -1949,3 +1950,72 @@ describe("OPENCODE_CONFIG_CONTENT token substitution", () => {
19491950 }
19501951 } )
19511952} )
1953+
1954+ describe ( "ConfigPaths linked worktree" , ( ) => {
1955+ test ( "projectFiles: finds config in worktree root when directory is on a different filesystem branch" , async ( ) => {
1956+ // Simulate a linked worktree scenario:
1957+ // worktreeRoot = ~/code/myproject/ (git common dir)
1958+ // linkedDir = ~/.local/share/opencode/worktree/<hash>/<name>/ (linked worktree)
1959+ // The two paths are on completely different branches of the directory tree.
1960+ await using worktreeRoot = await tmpdir ( {
1961+ init : async ( dir ) => {
1962+ // Place opencode.json directly in the worktree root
1963+ await fs . writeFile ( path . join ( dir , "opencode.json" ) , JSON . stringify ( { model : "from-worktree-root" } ) )
1964+ } ,
1965+ } )
1966+ await using linkedDir = await tmpdir ( )
1967+
1968+ // Sanity: linkedDir is NOT under worktreeRoot
1969+ expect ( linkedDir . path . startsWith ( worktreeRoot . path + path . sep ) ) . toBe ( false )
1970+
1971+ const files = await ConfigPaths . projectFiles ( "opencode" , linkedDir . path , worktreeRoot . path )
1972+
1973+ // The worktree root's opencode.json should be included
1974+ expect ( files ) . toContain ( path . join ( worktreeRoot . path , "opencode.json" ) )
1975+ } )
1976+
1977+ test ( "directories: finds .opencode dir in worktree root when directory is on a different filesystem branch" , async ( ) => {
1978+ await using worktreeRoot = await tmpdir ( {
1979+ init : async ( dir ) => {
1980+ // Place .opencode/opencode.json in the worktree root
1981+ await fs . mkdir ( path . join ( dir , ".opencode" ) , { recursive : true } )
1982+ await fs . writeFile (
1983+ path . join ( dir , ".opencode" , "opencode.json" ) ,
1984+ JSON . stringify ( { model : "from-dotOpencode" } ) ,
1985+ )
1986+ } ,
1987+ } )
1988+ await using linkedDir = await tmpdir ( )
1989+
1990+ // Sanity: linkedDir is NOT under worktreeRoot
1991+ expect ( linkedDir . path . startsWith ( worktreeRoot . path + path . sep ) ) . toBe ( false )
1992+
1993+ const dirs = await ConfigPaths . directories ( linkedDir . path , worktreeRoot . path )
1994+
1995+ // The worktree root's .opencode directory should be included
1996+ expect ( dirs ) . toContain ( path . join ( worktreeRoot . path , ".opencode" ) )
1997+ } )
1998+
1999+ test ( "projectFiles: normal (non-linked) project still works correctly" , async ( ) => {
2000+ // directory IS under worktree — existing behaviour should be unchanged
2001+ await using worktreeRoot = await tmpdir ( {
2002+ init : async ( dir ) => {
2003+ await fs . writeFile ( path . join ( dir , "opencode.json" ) , JSON . stringify ( { model : "root-model" } ) )
2004+ } ,
2005+ } )
2006+ // Create a subdirectory that IS under worktreeRoot
2007+ const subDir = path . join ( worktreeRoot . path , "subproject" )
2008+ await fs . mkdir ( subDir , { recursive : true } )
2009+ await fs . writeFile ( path . join ( subDir , "opencode.json" ) , JSON . stringify ( { model : "sub-model" } ) )
2010+
2011+ const files = await ConfigPaths . projectFiles ( "opencode" , subDir , worktreeRoot . path )
2012+
2013+ // Both root and subproject files should appear; subproject wins (applied last)
2014+ expect ( files ) . toContain ( path . join ( worktreeRoot . path , "opencode.json" ) )
2015+ expect ( files ) . toContain ( path . join ( subDir , "opencode.json" ) )
2016+ // subproject entry must come after root entry so it takes precedence when merged
2017+ expect ( files . indexOf ( path . join ( subDir , "opencode.json" ) ) ) . toBeGreaterThan (
2018+ files . indexOf ( path . join ( worktreeRoot . path , "opencode.json" ) ) ,
2019+ )
2020+ } )
2021+ } )
0 commit comments