@@ -161,11 +161,22 @@ async function loadGitignore(cwd: string): Promise<GitignoreResult> {
161161 return { ignore : ig , globPatterns } ;
162162}
163163
164+ /**
165+ * Check if a glob pattern references paths outside cwd.
166+ * Patterns traversing to parent directories start with ../ (or ./../).
167+ */
168+ function isExternalPattern ( pattern : string ) : boolean {
169+ // Handle redundant ./ prefix (e.g., ./../other)
170+ const normalized = pattern . startsWith ( "./" ) ? pattern . slice ( 2 ) : pattern ;
171+ return normalized . startsWith ( "../" ) ;
172+ }
173+
164174/**
165175 * Resolve bundle config to a list of file paths.
166176 * - Regular patterns respect .gitignore
167177 * - Force patterns (+prefix) bypass .gitignore
168178 * - Exclude patterns (!prefix) filter both
179+ * - External patterns (../) skip .gitignore entirely
169180 */
170181export async function resolvePatterns (
171182 config : BundleConfigInput ,
@@ -176,10 +187,13 @@ export async function resolvePatterns(
176187 const { ignore : gitignore , globPatterns } = await loadGitignore ( cwd ) ;
177188 const files = new Set < string > ( ) ;
178189
179- // Regular includes: respect .gitignore
180- // Pass gitignore patterns to fast-glob to skip ignored directories during traversal
181- if ( include . length > 0 ) {
182- const matches = await glob ( include , {
190+ // Split patterns into internal (within cwd) and external (../ prefixed)
191+ const internalPatterns = include . filter ( ( p ) => ! isExternalPattern ( p ) ) ;
192+ const externalPatterns = include . filter ( isExternalPattern ) ;
193+
194+ // Internal patterns: respect .gitignore
195+ if ( internalPatterns . length > 0 ) {
196+ const matches = await glob ( internalPatterns , {
183197 cwd,
184198 onlyFiles : true ,
185199 dot : true ,
@@ -195,6 +209,23 @@ export async function resolvePatterns(
195209 }
196210 }
197211
212+ // External patterns: skip .gitignore (it doesn't apply outside cwd)
213+ if ( externalPatterns . length > 0 ) {
214+ const matches = await glob ( externalPatterns , {
215+ cwd,
216+ onlyFiles : true ,
217+ dot : true ,
218+ } ) ;
219+ for ( const match of matches ) {
220+ if ( ! isExcluded ( match , excludeMatchers ) ) {
221+ const fullPath = join ( cwd , match ) ;
222+ if ( ! ( await isBinary ( fullPath ) ) ) {
223+ files . add ( match ) ;
224+ }
225+ }
226+ }
227+ }
228+
198229 // Force includes: bypass .gitignore (no ignore patterns passed to glob)
199230 if ( force . length > 0 ) {
200231 const matches = await glob ( force , { cwd, onlyFiles : true , dot : true } ) ;
0 commit comments