From 20a6aefb6a9dc5f2607f172a72e569b2b9c861f5 Mon Sep 17 00:00:00 2001 From: Bao Ha Date: Sat, 18 Apr 2026 22:07:49 +0700 Subject: [PATCH] feat: [ENG-2154] Add OS system/temp files to CONTEXT_TREE_GITIGNORE_PATTERNS --- src/server/constants.ts | 25 +++++++++++++++++++++- test/unit/server/constants.test.ts | 34 ++++++++++++++++++++++++++++++ test/unit/utils/gitignore.test.ts | 21 +++++------------- 3 files changed, 63 insertions(+), 17 deletions(-) diff --git a/src/server/constants.ts b/src/server/constants.ts index 6ce65745f..df6a905a1 100644 --- a/src/server/constants.ts +++ b/src/server/constants.ts @@ -120,14 +120,37 @@ export const MANIFEST_FILE = '_manifest.json' export const ARCHIVE_IMPORTANCE_THRESHOLD = 35 export const DEFAULT_GHOST_CUE_MAX_TOKENS = 220 -/** Patterns the context-tree .gitignore must contain (derived artifacts only). */ +/** Patterns the context-tree .gitignore must contain. */ export const CONTEXT_TREE_GITIGNORE_PATTERNS = [ + // Derived artifacts '.gitignore', '.snapshot.json', '_manifest.json', '_index.md', '*.abstract.md', '*.overview.md', + + // macOS + '.DS_Store', + '._*', + + // Windows + 'Thumbs.db', + 'ehthumbs.db', + 'Desktop.ini', + + // Linux + '.directory', + '.fuse_hidden*', + '.nfs*', + + // Editor swap / backup / temp + '*.swp', + '*.swo', + '*~', + '.#*', + '*.bak', + '*.tmp', ] export const CONTEXT_TREE_GITIGNORE_HEADER = '# Derived artifacts — do not track' diff --git a/test/unit/server/constants.test.ts b/test/unit/server/constants.test.ts index b59ef9fe3..095695fb1 100644 --- a/test/unit/server/constants.test.ts +++ b/test/unit/server/constants.test.ts @@ -17,4 +17,38 @@ describe('CONTEXT_TREE_GITIGNORE_PATTERNS', () => { expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.include('_manifest.json') expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.include('_index.md') }) + + describe('OS-generated junk files', () => { + it('should exclude macOS junk (Finder metadata + AppleDouble forks)', () => { + expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.include('.DS_Store') + expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.include('._*') + }) + + it('should exclude Windows junk (thumbnail cache + folder config)', () => { + expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.include('Thumbs.db') + expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.include('ehthumbs.db') + expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.include('Desktop.ini') + }) + + it('should exclude Linux junk (KDE metadata + FUSE/NFS hidden files)', () => { + expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.include('.directory') + expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.include('.fuse_hidden*') + expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.include('.nfs*') + }) + + it('should exclude editor swap / backup / temp files', () => { + expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.include('*.swp') + expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.include('*.swo') + expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.include('*~') + expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.include('.#*') + expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.include('*.bak') + expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.include('*.tmp') + }) + + it('should deliberately NOT include trash folders (out of scope per ENG-2154)', () => { + expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.not.include('.Trashes') + expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.not.include('.Trash-*') + expect(CONTEXT_TREE_GITIGNORE_PATTERNS).to.not.include('$RECYCLE.BIN/') + }) + }) }) diff --git a/test/unit/utils/gitignore.test.ts b/test/unit/utils/gitignore.test.ts index 69430b0cc..79d4844ef 100644 --- a/test/unit/utils/gitignore.test.ts +++ b/test/unit/utils/gitignore.test.ts @@ -348,14 +348,10 @@ _index.md }) it('should handle lines with leading/trailing whitespace', async () => { - const withSpaces = `# Derived artifacts — do not track - .gitignore - .snapshot.json -_manifest.json -_index.md - *.abstract.md -*.overview.md -` + const withSpaces = FULL_GITIGNORE + .replace(/^\.gitignore$/m, ' .gitignore') + .replace(/^\.snapshot\.json$/m, ' .snapshot.json') + .replace(/^\*\.abstract\.md$/m, ' *.abstract.md') writeFileSync(path.join(testDir, '.gitignore'), withSpaces) await ensureContextTreeGitignore(testDir) @@ -365,14 +361,7 @@ _index.md }) it('should skip pattern when a variant already covers it — /_manifest.json contains _manifest.json', async () => { - const withSlash = `# Derived artifacts — do not track -.gitignore -.snapshot.json -/_manifest.json -_index.md -*.abstract.md -*.overview.md -` + const withSlash = FULL_GITIGNORE.replace(/^_manifest\.json$/m, '/_manifest.json') writeFileSync(path.join(testDir, '.gitignore'), withSlash) await ensureContextTreeGitignore(testDir)