mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2026-01-23 04:52:02 -08:00
Improve logging and cleanup in file system watcher and git ops
Added detailed logging to WatchFileSystemAdaptor and FileSystemWatcher for better traceability during initialization and test stabilization. Introduced a constant for the temporary git index prefix in gitOperations. Removed the unused comparison.ts utility for tiddler comparison. Enhanced comments and logging for AI commit message generation context.
This commit is contained in:
parent
d04f497a02
commit
fe66b9ecb9
5 changed files with 25 additions and 63 deletions
|
|
@ -8,6 +8,14 @@ import { exec as gitExec } from 'dugite';
|
|||
import * as fs from 'node:fs/promises';
|
||||
import * as path from 'node:path';
|
||||
|
||||
// Limits for how much git content we send to the AI service.
|
||||
// These values are chosen to balance useful context vs. token / payload size:
|
||||
// - MAX_UNTRACKED_FILES: cap the number of untracked files included so a large
|
||||
// number of new files does not overwhelm the prompt or increase latency.
|
||||
// - MAX_FILE_CONTENT_LENGTH: truncate individual file contents to keep the
|
||||
// prompt small while still giving the model enough context about changes.
|
||||
// - MAX_DIFF_LENGTH: hard cap on total diff length to stay within typical
|
||||
// model/token limits and avoid request failures due to oversized payloads.
|
||||
const MAX_UNTRACKED_FILES = 5;
|
||||
const MAX_FILE_CONTENT_LENGTH = 500;
|
||||
const MAX_DIFF_LENGTH = 3000;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ import * as path from 'node:path';
|
|||
import { defaultGitInfo } from './defaultGitInfo';
|
||||
import type { GitFileStatus, IFileDiffResult, IGitLogOptions, IGitLogResult } from './interface';
|
||||
|
||||
/** Prefix for temporary Git index directories used during amend/undo operations */
|
||||
const TEMP_GIT_INDEX_PREFIX = 'tidgi-git-index-';
|
||||
|
||||
/**
|
||||
* Helper to create git environment variables for commit operations
|
||||
* This ensures commits work in environments without git config (like CI)
|
||||
|
|
@ -181,7 +184,8 @@ function parseGitStatusCode(statusCode: string): GitFileStatus {
|
|||
export async function getCommitFiles(repoPath: string, commitHash: string): Promise<Array<import('./interface').IFileWithStatus>> {
|
||||
// Handle uncommitted changes
|
||||
if (!commitHash || commitHash === '') {
|
||||
// Use -uall to show all untracked files, not just directories
|
||||
// Use -uall to show all untracked files, not just directories.
|
||||
// This is important for AI commit message generation to see the full context.
|
||||
const result = await gitExec(['-c', 'core.quotePath=false', 'status', '--porcelain', '-uall'], repoPath);
|
||||
|
||||
if (result.exitCode !== 0) {
|
||||
|
|
@ -710,7 +714,7 @@ export async function addToGitignore(repoPath: string, pattern: string): Promise
|
|||
export async function amendCommitMessage(repoPath: string, newMessage: string): Promise<void> {
|
||||
// Use a temporary index so we amend only the commit message and do not
|
||||
// accidentally include user's staged changes or alter their index state.
|
||||
const temporaryDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'tidgi-git-index-'));
|
||||
const temporaryDirectory = await fs.mkdtemp(path.join(os.tmpdir(), TEMP_GIT_INDEX_PREFIX));
|
||||
const temporaryIndex = path.join(temporaryDirectory, 'index');
|
||||
try {
|
||||
const baseEnvironment = { ...process.env, GIT_INDEX_FILE: temporaryIndex } as NodeJS.ProcessEnv;
|
||||
|
|
|
|||
|
|
@ -152,11 +152,13 @@ export class FileSystemWatcher {
|
|||
*/
|
||||
async initialize(): Promise<void> {
|
||||
if (!this.watchPathBase) {
|
||||
this.logger.log('[test-id-WATCH_FS_STABILIZED] Watcher has stabilized (no watch path)');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if file system watch is enabled for this workspace
|
||||
if (this.workspaceConfig && !this.workspaceConfig.enableFileSystemWatch) {
|
||||
this.logger.log('[test-id-WATCH_FS_STABILIZED] Watcher has stabilized (disabled by config)');
|
||||
this.logger.log('FileSystemWatcher File system watching is disabled for this workspace');
|
||||
return;
|
||||
}
|
||||
|
|
@ -412,6 +414,9 @@ export class FileSystemWatcher {
|
|||
this.logger.log('[test-id-WATCH_FS_STABILIZED] Watcher has stabilized');
|
||||
} catch (error) {
|
||||
this.logger.alert('FileSystemWatcher Failed to initialize file watching:', error);
|
||||
// Still log stabilized marker even if initialization failed
|
||||
// This prevents tests from hanging waiting for the marker
|
||||
this.logger.log('[test-id-WATCH_FS_STABILIZED] Watcher has stabilized (with errors)');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,20 +38,24 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor {
|
|||
}
|
||||
|
||||
private async initializeAsync(): Promise<void> {
|
||||
this.logger.log('WatchFileSystemAdaptor initializeAsync starting');
|
||||
try {
|
||||
const workspaceId = this.workspaceID;
|
||||
this.logger.log(`WatchFileSystemAdaptor loading workspace config for ${workspaceId}`);
|
||||
if (workspaceId) {
|
||||
const loadedWorkspaceData = await workspace.get(workspaceId);
|
||||
if (!loadedWorkspaceData || typeof loadedWorkspaceData !== 'object' || !isWikiWorkspace(loadedWorkspaceData)) {
|
||||
throw new Error('Invalid workspace data');
|
||||
}
|
||||
this.workspace = loadedWorkspaceData;
|
||||
this.logger.log(`WatchFileSystemAdaptor workspace config loaded, enableFileSystemWatch=${this.workspace.enableFileSystemWatch}`);
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
this.logger.log(`Failed to load workspace data: ${errorMessage}`);
|
||||
}
|
||||
|
||||
this.logger.log('WatchFileSystemAdaptor creating FileSystemWatcher');
|
||||
// Create and initialize the file watcher
|
||||
this.watcher = new FileSystemWatcher({
|
||||
wiki: this.wiki,
|
||||
|
|
@ -61,7 +65,9 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor {
|
|||
workspaceConfig: this.workspace,
|
||||
});
|
||||
|
||||
this.logger.log('WatchFileSystemAdaptor calling watcher.initialize()');
|
||||
await this.watcher.initialize();
|
||||
this.logger.log('WatchFileSystemAdaptor initialization complete');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
/**
|
||||
* High-performance tiddler comparison utilities
|
||||
* Used to detect if a tiddler has actually changed to prevent unnecessary saves
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fields that change automatically during save and should be excluded from comparison
|
||||
*/
|
||||
const EXCLUDED_FIELDS = new Set([
|
||||
'modified', // Always updated on save
|
||||
'revision', // Internal TiddlyWiki revision counter
|
||||
'bag', // TiddlyWeb specific
|
||||
'created', // May be auto-generated
|
||||
]);
|
||||
|
||||
/**
|
||||
* Fast comparison of two tiddlers to detect real content changes
|
||||
* Strategy:
|
||||
* 1. Quick length check on text field (most common change)
|
||||
* 2. Compare field counts
|
||||
* 3. Deep compare only if needed
|
||||
*
|
||||
* @param oldTiddler - Existing tiddler in wiki
|
||||
* @param newTiddler - New tiddler from file
|
||||
* @returns true if tiddlers are meaningfully different
|
||||
*/
|
||||
export function hasMeaningfulChanges(
|
||||
oldTiddler: Record<string, unknown>,
|
||||
newTiddler: Record<string, unknown>,
|
||||
): boolean {
|
||||
// Fast path: Compare text field length first (most common change)
|
||||
const oldText = oldTiddler.text as string | undefined;
|
||||
const newText = newTiddler.text as string | undefined;
|
||||
|
||||
if ((oldText?.length ?? 0) !== (newText?.length ?? 0)) {
|
||||
return true; // Text length changed - definitely different
|
||||
}
|
||||
|
||||
// Get field keys excluding auto-generated ones
|
||||
const oldKeys = new Set(Object.keys(oldTiddler)).difference(EXCLUDED_FIELDS);
|
||||
const newKeys = new Set(Object.keys(newTiddler)).difference(EXCLUDED_FIELDS);
|
||||
|
||||
// Quick check: Different number of fields
|
||||
if (oldKeys.size !== newKeys.size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if there are any different keys (fields added or removed)
|
||||
if (oldKeys.difference(newKeys).size > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Deep comparison: Check each field value (keys are the same at this point)
|
||||
for (const key of oldKeys) {
|
||||
if (oldTiddler[key] !== newTiddler[key]) {
|
||||
return true; // Field value changed
|
||||
}
|
||||
}
|
||||
|
||||
return false; // No meaningful changes
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue