From c0a48ce727472056094eb803dbf656021bbca863 Mon Sep 17 00:00:00 2001 From: lin onetwo Date: Mon, 24 Nov 2025 16:04:11 +0800 Subject: [PATCH 1/7] Update release.yml --- .github/workflows/release.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 49ed3972..0bec4d73 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -134,7 +134,9 @@ jobs: draft: true generate_release_notes: true files: | - ${{ matrix.platform == 'win' && 'out/make/**/*.{exe,msix,appx}' || 'out/make/**/*' }} + ${{ matrix.platform == 'win' && 'out/make/**/*.exe + out/make/**/*.msix + out/make/**/*.appx' || 'out/make/**/*' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From e00addeffc4c7d3292b9d6166bb3b1ca897e1b8a Mon Sep 17 00:00:00 2001 From: lin onetwo Date: Mon, 24 Nov 2025 16:05:38 +0800 Subject: [PATCH 2/7] fix: unstable test --- features/filesystemPlugin.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/filesystemPlugin.feature b/features/filesystemPlugin.feature index dd2f1016..206f8e84 100644 --- a/features/filesystemPlugin.feature +++ b/features/filesystemPlugin.feature @@ -83,6 +83,7 @@ Feature: Filesystem Plugin # Modify the tiddler file externally - need to preserve .tid format with metadata When I modify file "{tmpDir}/SubWiki/TestTiddlerTitle.tid" to contain "Content modified in SubWiki symlink" # Wait for watch-fs to detect the change + And I wait for 1 seconds for "watch-fs to detect file change" Then I wait for tiddler "TestTiddlerTitle" to be updated by watch-fs And I wait for 2 seconds # Verify the modified content appears in the wiki From e2634e9aa56183c5d9242f719fbe79e9973837af Mon Sep 17 00:00:00 2001 From: lin onetwo Date: Mon, 24 Nov 2025 16:05:56 +0800 Subject: [PATCH 3/7] v0.13.0-prerelease8 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ade033bc..288b47e0 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "tidgi", "productName": "TidGi", "description": "Customizable personal knowledge-base with Github as unlimited storage and blogging platform.", - "version": "0.13.0-prerelease7", + "version": "0.13.0-prerelease8", "license": "MPL 2.0", "packageManager": "pnpm@10.18.2", "scripts": { From f3454b71e5f415cab6fe468e0eba8c2749500c46 Mon Sep 17 00:00:00 2001 From: lin onetwo Date: Mon, 24 Nov 2025 16:54:18 +0800 Subject: [PATCH 4/7] fix: shouldn't watch .git folder for file system plugin --- .../WatchFileSystemAdaptor.ts | 54 ++++++++++++++----- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/src/services/wiki/plugin/watchFileSystemAdaptor/WatchFileSystemAdaptor.ts b/src/services/wiki/plugin/watchFileSystemAdaptor/WatchFileSystemAdaptor.ts index 32b9a50b..7f581a42 100644 --- a/src/services/wiki/plugin/watchFileSystemAdaptor/WatchFileSystemAdaptor.ts +++ b/src/services/wiki/plugin/watchFileSystemAdaptor/WatchFileSystemAdaptor.ts @@ -63,8 +63,10 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor { private inverseFilesIndex: InverseFilesIndex = new InverseFilesIndex(); /** NSFW watcher instance for main wiki */ private watcher: nsfw.NSFW | undefined; - /** Base excluded paths (permanent) */ + /** Base excluded paths (permanent) - absolute paths for main wiki */ private baseExcludedPaths: string[] = []; + /** Excluded path patterns that apply to all wikis (main and sub-wikis) */ + private readonly excludedPathPatterns: string[] = ['.git', 'node_modules', '.DS_Store']; /** * Track pending file deletions to handle git revert/checkout scenarios. * Maps absolute file path to deletion timer. @@ -233,23 +235,40 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor { this.logger.log('WatchFileSystemAdaptor File system watching is disabled for this workspace'); return; } + + // Initialize inverse index from boot.files + this.initializeInverseFilesIndex(); + + // Setup base excluded paths (permanent exclusions) for main wiki + // wikiFolderLocation is the parent of watchPathBase (tiddlers folder) + const wikiFolderLocation = currentWorkspace && 'wikiFolderLocation' in currentWorkspace + ? currentWorkspace.wikiFolderLocation + : path.dirname(this.watchPathBase); + + this.baseExcludedPaths = [ + path.join(this.watchPathBase, 'subwiki'), + path.join(this.watchPathBase, '$__StoryList'), + // Add pattern-based exclusions at wiki folder level (not tiddlers folder) + // .git is at wiki folder level: wiki/.git, not wiki/tiddlers/.git + ...this.excludedPathPatterns.map(pattern => path.join(wikiFolderLocation, pattern)), + ]; } catch (error) { this.logger.alert('WatchFileSystemAdaptor Failed to check enableFileSystemWatch setting:', error); return; } + } else { + // Fallback when workspaceID is not available + this.initializeInverseFilesIndex(); + // Use parent directory as wikiFolderLocation fallback + const wikiFolderLocation = path.dirname(this.watchPathBase); + this.baseExcludedPaths = [ + path.join(this.watchPathBase, 'subwiki'), + path.join(this.watchPathBase, '$__StoryList'), + // Add pattern-based exclusions at wiki folder level + ...this.excludedPathPatterns.map(pattern => path.join(wikiFolderLocation, pattern)), + ]; } - // Initialize inverse index from boot.files - this.initializeInverseFilesIndex(); - - // Setup base excluded paths (permanent exclusions) - this.baseExcludedPaths = [ - path.join(this.watchPathBase, 'subwiki'), - path.join(this.watchPathBase, '.git'), - path.join(this.watchPathBase, '$__StoryList'), - path.join(this.watchPathBase, '.DS_Store'), - ]; - // Setup nsfw watcher try { this.watcher = await nsfw( @@ -262,7 +281,7 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor { errorCallback: (error) => { this.logger.alert('WatchFileSystemAdaptor NSFW error:', error); }, - // Start with base excluded paths + // Start with base excluded paths - nsfw will filter these at the native level // @ts-expect-error - nsfw types are incorrect, it accepts string[] not just [string] excludedPaths: [...this.baseExcludedPaths], }, @@ -320,6 +339,9 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor { errorCallback: (error) => { this.logger.alert(`WatchFileSystemAdaptor NSFW error for sub-wiki ${subWiki.name}:`, error); }, + // Exclude common patterns for sub-wikis (e.g., .git, node_modules) + // @ts-expect-error - nsfw types are incorrect, it accepts string[] not just [string] + excludedPaths: this.excludedPathPatterns.map(pattern => path.join(subWikiPath, pattern)), }, ); @@ -436,7 +458,7 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor { // Compute absolute path const fileAbsolutePath = path.join(directory, fileName); - // Check if this file is in our exclusion list - if so, skip processing + // Check if this file is in our dynamic exclusion list (for files being saved/deleted by the app) const subWikiForExclusion = this.inverseFilesIndex.getSubWikiForFile(fileAbsolutePath); const isExcluded = subWikiForExclusion ? this.inverseFilesIndex.isSubWikiFileExcluded(subWikiForExclusion.id, fileAbsolutePath) @@ -595,10 +617,14 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor { const isCreatingNewNonTiddlerFile = changeType === 'add' && !fs.existsSync(metaFileAbsolutePath) && !ignoredExtension.includes(fileExtension.slice(1)); if (isCreatingNewNonTiddlerFile) { const createdTime = $tw.utils.formatDateString(new Date(), '[UTC]YYYY0MM0DD0hh0mm0ss0XXX'); + // Exclude the .meta file before creating it to avoid triggering another watch event + this.excludeFile(metaFileAbsolutePath); fs.writeFileSync( metaFileAbsolutePath, `caption: ${fileNameBase}\ncreated: ${createdTime}\nmodified: ${createdTime}\ntitle: ${fileName}\ntype: ${fileMimeType}\n`, ); + // Schedule re-inclusion after delay + this.scheduleFileInclusion(metaFileAbsolutePath); // After creating .meta, continue to process the file normally // TiddlyWiki will detect the .meta file on next event } From 5310365a8a83bcaebfef70842ba31cfa304d08d5 Mon Sep 17 00:00:00 2001 From: lin onetwo Date: Mon, 24 Nov 2025 16:54:30 +0800 Subject: [PATCH 5/7] v0.13.0-prerelease9 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 288b47e0..7b35b688 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "tidgi", "productName": "TidGi", "description": "Customizable personal knowledge-base with Github as unlimited storage and blogging platform.", - "version": "0.13.0-prerelease8", + "version": "0.13.0-prerelease9", "license": "MPL 2.0", "packageManager": "pnpm@10.18.2", "scripts": { From 23aa09eaacd38f34c7a8fa671f26f75cede8be9b Mon Sep 17 00:00:00 2001 From: lin onetwo Date: Mon, 24 Nov 2025 17:37:01 +0800 Subject: [PATCH 6/7] fix: nsfw can't watch parent folder, just ignore .git in symlink sub wiki folder before any side-effect --- .../WatchFileSystemAdaptor.ts | 88 ++++++++++--------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/src/services/wiki/plugin/watchFileSystemAdaptor/WatchFileSystemAdaptor.ts b/src/services/wiki/plugin/watchFileSystemAdaptor/WatchFileSystemAdaptor.ts index 7f581a42..d6db767a 100644 --- a/src/services/wiki/plugin/watchFileSystemAdaptor/WatchFileSystemAdaptor.ts +++ b/src/services/wiki/plugin/watchFileSystemAdaptor/WatchFileSystemAdaptor.ts @@ -235,40 +235,22 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor { this.logger.log('WatchFileSystemAdaptor File system watching is disabled for this workspace'); return; } - - // Initialize inverse index from boot.files - this.initializeInverseFilesIndex(); - - // Setup base excluded paths (permanent exclusions) for main wiki - // wikiFolderLocation is the parent of watchPathBase (tiddlers folder) - const wikiFolderLocation = currentWorkspace && 'wikiFolderLocation' in currentWorkspace - ? currentWorkspace.wikiFolderLocation - : path.dirname(this.watchPathBase); - - this.baseExcludedPaths = [ - path.join(this.watchPathBase, 'subwiki'), - path.join(this.watchPathBase, '$__StoryList'), - // Add pattern-based exclusions at wiki folder level (not tiddlers folder) - // .git is at wiki folder level: wiki/.git, not wiki/tiddlers/.git - ...this.excludedPathPatterns.map(pattern => path.join(wikiFolderLocation, pattern)), - ]; } catch (error) { this.logger.alert('WatchFileSystemAdaptor Failed to check enableFileSystemWatch setting:', error); return; } - } else { - // Fallback when workspaceID is not available - this.initializeInverseFilesIndex(); - // Use parent directory as wikiFolderLocation fallback - const wikiFolderLocation = path.dirname(this.watchPathBase); - this.baseExcludedPaths = [ - path.join(this.watchPathBase, 'subwiki'), - path.join(this.watchPathBase, '$__StoryList'), - // Add pattern-based exclusions at wiki folder level - ...this.excludedPathPatterns.map(pattern => path.join(wikiFolderLocation, pattern)), - ]; } + // Initialize inverse index from boot.files + this.initializeInverseFilesIndex(); + + // Setup base excluded paths (permanent exclusions) for main wiki + // Only include paths that are subdirectories of watchPathBase + this.baseExcludedPaths = [ + path.join(this.watchPathBase, 'subwiki'), + path.join(this.watchPathBase, '$__StoryList'), + ]; + // Setup nsfw watcher try { this.watcher = await nsfw( @@ -438,6 +420,23 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor { this.pendingDeletions.set(fileAbsolutePath, timer); } + /** + * Check if a path contains any excluded pattern (like .git, node_modules) + * This checks all parts of the path, so it will catch: + * - Direct .git directories: wiki/.git/config + * - Sub-wiki .git directories: wiki/tiddlers/subwiki/.git/index.lock + * - Symlinked .git directories: wiki/tiddlers/link-to-subwiki/.git/config + * @param filePath File or directory path to check + * @returns true if path should be excluded + */ + private shouldExcludeByPattern(filePath: string): boolean { + // Check if any part of the path contains excluded patterns + return this.excludedPathPatterns.some(pattern => { + const pathParts = filePath.split(path.sep); + return pathParts.includes(pattern); + }); + } + /** * Handle NSFW file system change events */ @@ -458,6 +457,27 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor { // Compute absolute path const fileAbsolutePath = path.join(directory, fileName); + // Early check: skip files in excluded patterns (e.g., .git, node_modules) + if (this.shouldExcludeByPattern(fileAbsolutePath) || this.shouldExcludeByPattern(directory)) { + this.logger.log(`WatchFileSystemAdaptor Skipping file in excluded pattern directory: ${fileAbsolutePath}`); + continue; + } + + // Early check: skip if it's a directory (nsfw sometimes reports directory changes) + // Must check before processing to avoid creating tiddlers for .git files + if (action === nsfw.actions.CREATED || action === nsfw.actions.MODIFIED) { + try { + const stats = fs.statSync(fileAbsolutePath); + if (stats.isDirectory()) { + this.logger.log(`WatchFileSystemAdaptor Skipping directory: ${fileAbsolutePath}`); + continue; + } + } catch { + // File might have been deleted already, skip + continue; + } + } + // Check if this file is in our dynamic exclusion list (for files being saved/deleted by the app) const subWikiForExclusion = this.inverseFilesIndex.getSubWikiForFile(fileAbsolutePath); const isExcluded = subWikiForExclusion @@ -484,18 +504,6 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor { // Handle different event types if (action === nsfw.actions.CREATED || action === nsfw.actions.MODIFIED) { - // Skip if it's a directory (nsfw sometimes reports directory changes) - try { - const stats = fs.statSync(fileAbsolutePath); - if (stats.isDirectory()) { - this.logger.log(`WatchFileSystemAdaptor Skipping directory: ${fileAbsolutePath}`); - continue; - } - } catch { - // File might have been deleted already, skip - continue; - } - // Cancel any pending deletion for this file (e.g., git revert scenario) this.cancelPendingDeletion(fileAbsolutePath); From d242d9a63c1d0da56ebe8ee47e348ce31e430771 Mon Sep 17 00:00:00 2001 From: lin onetwo Date: Mon, 24 Nov 2025 17:37:22 +0800 Subject: [PATCH 7/7] v0.13.0-prerelease10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7b35b688..6939ba29 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "tidgi", "productName": "TidGi", "description": "Customizable personal knowledge-base with Github as unlimited storage and blogging platform.", - "version": "0.13.0-prerelease9", + "version": "0.13.0-prerelease10", "license": "MPL 2.0", "packageManager": "pnpm@10.18.2", "scripts": {