Commit graph

368 commits

Author SHA1 Message Date
HeroBlackInk
ff1ae48525 refactor: extract main.ts into focused modules (eventHandlers, syncLock, scheduler)
Ultraworked with Sisyphus

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-22 12:46:30 +08:00
HeroBlackInk
9fe16e29cc fix: 6 bugs in log module — memory leak, duplicate writes, broken clear/load, size check, concurrency 2026-02-22 12:00:19 +08:00
HeroBlackInk
0b9711d4f5 fix: fullVaultSync stale content scan, missing real-time sync for active file, and dead code 2026-02-22 05:48:43 +08:00
HeroBlackInk
7e155a6d00 feat: enforce per-task syncEnabled guard in both sync directions 2026-02-22 05:30:27 +08:00
HeroBlackInk
92219511ae refactor: reorganize src/ into domain-based subdirectories
- Move 13 files into 8 subdirectories: api/, sync/, data/, vault/, settings/, storage/, ui/, utils/
- Merge modal.ts + conflictModal.ts → ui/modals.ts
- Merge safeSettings.ts + settingsBackup.ts → settings/safeSettings.ts
- Remove syncModule.ts (62-line pure proxy), inline direct references in main.ts
- Rename files for clarity: todoistRestAPI→restApi, todoistSyncAPI→syncApi, etc.
- Update all import paths across 15 source files + main.ts
- File count: 18 → 15, src/ root is now clean subdirectories only
2026-02-22 05:16:18 +08:00
HeroBlackInk
2b4d548db6 fix: throttle API token notice to once per 60s instead of every event 2026-02-22 04:45:51 +08:00
HeroBlackInk
e6d48f4279 fix: rebuildCache and databaseChecker bugs, settings data optimization
rebuildCache (cacheOperation.ts):
- syncData not refreshed after initializeSync, breaking legacy ID conversion
- checked field 0/1 vs boolean coercion causing false conflict detection
- ID conversion branch missing status/syncEnabled fields
- 6 direct settings mutations replaced with local nextMapping + single safeSettings.update
- serial GetTaskById replaced with in-memory Map lookup
- removed 4 debug console.log statements left in production code
- resolveConflicts: added TFile type guard for vault.read
- removed dead DatabaseCheckIssue/Result interfaces (~100 lines)

databaseChecker:
- checked field 0/1 vs boolean causing false status_mismatch reports
- priority check extracting from labels instead of !!<n> text format (disabled)
- Object.assign overwrote previously accumulated summary counts
- error catch used wrong issue type (task_not_in_vault → unknown_issue)
- deduplicated identical Vault+Mapping branches (~30 lines)
- startup check made non-blocking to avoid slow plugin init

fileOperation (shared by both modules):
- getTodoistTasksFromSyncData: task.projectId → task.project_id (snake_case)
- scanVaultTasks: exclude plugin storage directory and hidden dirs

settings optimization (from prior analysis):
- strip 7 ghost fields from data.json on load (3.5MB → ~160KB)
- remove dead statistics and deviceIdGenerated from interface
- safeSettings backup throttled to once per 5 minutes
- sanitize corrupted taskFileMapping entries on load
2026-02-22 04:32:56 +08:00
HeroBlackInk
2568ec3c70 fix: 9 bugs in Obsidian→Todoist sync pipeline
- fullTextNewTaskCheck: passed line text instead of line index to setTaskFileMapping
- convertTextToTodoistTaskObject: parentTaskObject.projectId → project_id (Sync API snake_case)
- taskTagCompare: clone arrays before sort to prevent mutating syncData cache
- taskStatusCompare: use !! coercion for checked (0/1 vs boolean)
- compareTaskDueDate: rewrite dead code, compare date strings directly (no timezone conversion)
- localDateStringToUTCDateString: remove T08:00 hardcode that broke non-UTC+8 timezones
- getAllTagsFromLineText: return [] instead of null when no tags
- lineModifiedTaskCheck: remove dead projectModified/parentIdModified comparisons
- fullTextModifiedTaskCheck: remove unused hasModifiedTask variable
2026-02-22 03:47:59 +08:00
HeroBlackInk
6e042b2b21 refactor: replace Activities API with updated_at comparison for Todoist→Obsidian sync
- syncTodoistToObsidian now uses incremental sync + updated_at field comparison
  instead of unreliable Activities API with client string filtering
- Naturally deduplicates: same updated_at = no action (idempotent)
- Field-level comparison: checked, content, due date synced individually
- Note sync via note_count tracking in taskFileMapping
- Extended taskFileMapping with updated_at and note_count fields
- Fixed checkboxEventhandle: await closeTask/repoenTask + try/finally for syncLock
- Added withSyncLock() helper to prevent lock leaks across all sync operations
- scheduledSynchronization: added re-entry guard, changed return→continue in file loop
- Removed obsolete Activity event pass-through methods from syncModule
2026-02-22 03:33:13 +08:00
HeroBlackInk
b4819aa7a0 fix: newTask.url undefined in Sync API v1 — construct task URLs from ID 2026-02-22 03:13:44 +08:00
HeroBlackInk
e797c530d0 fix: taskParser not recognizing todoist:// app URI links
- TODOIST_LINK regex now matches both https://todoist.com and todoist:// URIs
- Added REMOVE_TODOIST_LINK_APP_URI regex to strip todoist://task?id=xxx from task content
- getTaskContentFromLineText() now removes app URI links before sending content to API
2026-02-22 03:00:38 +08:00
HeroBlackInk
dea874ae98 fix: task creation failing and backup cleanup ENOENT error
- generateTempId() now uses UUID format instead of 'temp_' prefix (Todoist API requires UUID)
- AddTask() no longer sends empty project_id when defaultProjectId is unset (API defaults to Inbox)
- executeCommands() now validates sync_status and logs per-command API errors
- addTask() error messages now include actual API error details instead of generic 'no response'
- cleanOldBackups() checks file existence before removal to avoid ENOENT on concurrent cleanup
2026-02-22 02:52:17 +08:00
HeroBlackInk
b6dfcaa442 fix: task creation failing due to invalid temp_id format and empty project_id
- generateTempId() now uses UUID format instead of 'temp_' prefix (Todoist API requires UUID)
- AddTask() no longer sends empty project_id when defaultProjectId is unset (API defaults to Inbox)
- executeCommands() now validates sync_status and logs per-command API errors
- addTask() error messages now include actual API error details instead of generic 'no response'
2026-02-22 02:43:59 +08:00
HeroBlackInk
6e6eb5c846 fix: critical bugs in todoistSyncAPI — broken CRUD, invalid command, missing error handling
- Fix executeCommands() using response.json()/text() as functions instead of properties (Obsidian requestUrl returns properties, not methods) — all write operations were crashing
- Fix reopenTask() using non-existent 'item_reopen' Sync API command, correct command is 'item_uncomplete' per official docs
- Fix getNonObsidianAllActivityEvents() returning undefined on error, causing caller to crash on .filter()
- Fix 6 getter methods (GetAllProjects, GetTaskById, etc.) discarding getAllResources() return value instead of assigning to syncData
- Fix backupTodoistAllResources() using incremental sync instead of full sync for backups
- Fix startup not performing incremental sync after loading from cache, leaving data stale
2026-02-22 02:28:25 +08:00
HeroBlackInk
eb4338d15e fix: remove unconditional saveSettings() on every editor keystroke
editor-change handler called saveSettings() regardless of whether a new
task was found. lineContentNewTaskCheck() already saves internally when
a task is actually created, making the outer call redundant and causing
unnecessary disk writes on every keystroke.
2026-02-22 02:05:25 +08:00
HeroBlackInk
63f32cc493 refactor: unify all settings mutations through SafeSettings
- Remove backup logic from saveSettings() (now owned by SafeSettings)
- Convert all direct this.settings.xxx = yyy mutations to safeSettings.update()
- Add SafeSettings.reset() for wholesale settings replacement
- Files changed: main.ts, settings.ts, todoistSyncAPI.ts, storagePathManager.ts, cacheOperation.ts, safeSettings.ts
- Zero direct settings mutations remain in source code
2026-02-22 01:59:54 +08:00
HeroBlackInk
1c49958c8a refactor: add defensive checks in SafeSettings
- Add check for settingsBackup existence before backup
- Warn if settingsBackup not initialized instead of silently skipping
- Simplify error handling with proper restore attempt
2026-02-22 01:33:18 +08:00
HeroBlackInk
f0ae4e4be3 refactor: unify SafeSettings to single async update method
- Remove updateSync (duplicate)
- Make setTaskFileMapping and deleteTaskFileMapping async
- All settings updates now use await safeSettings.update()
- Simplifies code and ensures proper async handling
2026-02-22 01:27:55 +08:00
HeroBlackInk
c873c488d3 refactor: simplify SafeSettings by removing redundant memory backup
- Remove redundant memory backup (rely on SettingsBackup for file-level backup)
- Simplified logic: only backup → update → (optional) save → on error restore
- Fix async/await consistency in updateSync
2026-02-22 01:17:38 +08:00
HeroBlackInk
397e246599 refactor: use SafeSettings for settings updates in cacheOperation
- Replace direct settings assignments with safeSettings.update/updateSync
- setTaskFileMapping and deleteTaskFileMapping use updateSync (no immediate save)
- updateRenamedFilePath and rebuildCache use update with shouldSave=true
- Provides automatic backup and rollback on failure
2026-02-22 01:11:32 +08:00
HeroBlackInk
bad55ae564 feat: add SafeSettings class for unified settings updates
- Create SafeSettings class with update() and updateSync() methods
- Provides automatic backup and rollback on failure
- Initialize in main.ts
2026-02-22 01:02:56 +08:00
HeroBlackInk
fb73690b53 fix: only save settings when tasks are actually deleted
- Modify deletedTaskCheck() to return number of deleted tasks
- Only call saveSettings() when deletedCount > 0
- This prevents unnecessary SettingsBackup triggers on every Delete/Backspace keypress
2026-02-22 00:39:41 +08:00
HeroBlackInk
c209a6d1ea refactor: redesign logging system with single file + size-based cleanup
- Change LogAction to string type for flexibility
- Rename todayLogs to memoryLogs
- Use single log file (todoist-sync-logs.json)
- Add size-based cleanup (maxLogFileSize, logRetentionPercent)
- Remove batch buffer, use memoryLogs directly
- Update settings with new log config options
- Remove legacy logs array and logRetentionDays
2026-02-22 00:19:56 +08:00
HeroBlackInk
1450a120b3 fix: enhance logging system with multiple improvements
- Fix filename regex to match actual format (deviceId_date.json)
- Load today's logs from file on startup
- Implement maxLogs limit (500 entries)
- Flush log buffer after scheduled sync completes
- Flush log buffer on plugin unload
2026-02-21 23:54:56 +08:00
HeroBlackInk
d65ceaaffe fix: optimize logging to prevent infinite loop
- Remove todayLogs from settings (no longer persisted)
- Add batch write logic: write to JSON file every 20 logs
- Remove FILE_MODIFIED log to reduce unnecessary logging
- Logs are now stored only in JSON files, not in data.json
2026-02-21 23:41:37 +08:00
HeroBlackInk
dee227c9da fix: skip storage directory files in modify event handler
Prevent infinite loop by skipping files in storage directory
(logs, backups, reports) when handling vault modify events.
2026-02-21 20:08:26 +08:00
HeroBlackInk
69cd489a66 fix: prevent infinite loop in modify event handler
Add isProcessingModify flag to prevent re-entry when fullTextNewTaskCheck
modifies the vault, which would otherwise trigger another modify event.
2026-02-21 19:57:35 +08:00
HeroBlackInk
df2e668d70 refactor: replace fileMetadata.todoistTasks with taskFileMapping
- Remove deprecated fileMetadata.todoistTasks and todoistCount usage
- Use taskFileMapping-derived methods (getTasksInFile, getTaskCountInFile)
- Delete obsolete frontMatter update logic in obsidianToTodoist.ts
- Remove redundant saveSettings() calls
- Simplify fileOperation.ts metadata checks
2026-02-21 19:54:56 +08:00
HeroBlackInk
876c7ddeca fix: derive file list from taskFileMapping instead of fileMetadata
- Since fileMetadata now only stores defaultProjectId (no longer todoistTasks array)
- Changed sync loop to derive file list from taskFileMapping
- Uses Set to get unique file paths from taskFileMapping
- Fixes sync functionality that was broken after fileMetadata refactor
2026-02-21 18:57:50 +08:00
HeroBlackInk
1ac24feba7 refactor: simplify fileMetadata to only store defaultProjectId
- Remove todoistTasks and todoistCount from fileMetadata (can be derived from taskFileMapping)
- Simplify fileMetadata type to Record<string, { defaultProjectId?: string }>
- Add helper methods getTasksInFile() and getTaskCountInFile() to derive task info
- Remove deprecated deleteTaskIdFromMetadata() method
- Update comments to reflect new data structure
- Eliminates data redundancy and avoids sync issues
2026-02-21 18:47:27 +08:00
HeroBlackInk
cc75874362 fix: move database check reports to storage directory
- Add getReportsPath() method to StoragePathManager
- Add reports directory to ensureAllDirs()
- Save database check reports to ultimate-todoist-sync/reports/ instead of vault root
2026-02-21 18:18:12 +08:00
HeroBlackInk
0ea2074296 feat: add customizable storage directory with auto-migration
- Change default storage dir from .ultimate-todoist-sync to ultimate-todoist-sync (visible in file manager)
- Add storageDirectory and lastStorageDirectory to settings
- Implement migrateToNewDirectory() for automatic data migration when directory changes
- Smart merge: keep newer files during migration (compare mtime)
- Fix listFiles() to use adapter.list() instead of vault.getFiles()
- Add Storage Directory setting in Backup & Recovery section
- Update BackupOperation and TodoistToObsidian to use new dynamic paths
2026-02-21 18:11:02 +08:00
HeroBlackInk
d1ac1bcb40 fix: use adapter.list() to access hidden backup directory
- vault.getFiles() doesn't return files in hidden directories (starting with '.')
- Changed getLatestBackup(), getBackupList(), and cleanOldBackups() to use adapter.list() and adapter.stat()
- This fixes the 'No backups found' issue in settings UI
2026-02-21 17:56:36 +08:00
HeroBlackInk
c570e646e5 refactor: reorganize settings UI with clear分组 and logical ordering
- Remove unused MyProject interface
- Reorganize settings into 6 logical sections:
  - API Configuration
  - Sync Settings
  - Sync Direction
  - Tools
  - Logs & Debug
  - Backup & Recovery
- Add status display in Sync Direction section
- Simplify descriptions for better readability
- Fix type issues (Number -> number, any -> proper types)
2026-02-21 17:42:57 +08:00
HeroBlackInk
6742eec237 refactor: enhance StoragePathManager with 10 improvements
- Extract generateTimestamp() to avoid code duplication
- Instance methods now reuse static constants
- Add writeJsonFileAtomic() for atomic JSON writes
- Add cleanOldBackups() for backup management
- Add device ID to log filenames for better区分
- Add getFileSize() and getDirSize() methods
- Add joinPath() for platform-independent path handling
- Add appendLock to prevent concurrent append operations
- Improve ensureAllDirs() with proper error handling and return values
2026-02-21 17:35:56 +08:00
HeroBlackInk
12437b76e7 fix: improve backup reliability with validation and atomic writes
- Add file existence verification after backup writes
- Implement atomic write with temp file pattern for all backups
- Add content validation in restoreFromBackup()
- Use StoragePathManager constants for all backup paths
- Rollback initialized state on initialization failure
- Add backup history view button in settings UI
2026-02-21 17:26:40 +08:00
HeroBlackInk
7e1879a793 fix: improve settings save/load reliability with 7 major fixes
- Add temp file check on load (recoverFromTempFile)
- Add JSON validation before backup/restore operations
- Use StoragePathManager constants for settings paths
- Add user notifications for backup failures
- Initialize settingsBackup earlier in loadSettings
- Add Notice messages for better user feedback
- Refactor settingsBackup to use centralized path constants
2026-02-21 17:08:48 +08:00
HeroBlackInk
9ce39efcdb feat: add settings save lock, backup and recovery mechanism
- Add saveLock to prevent concurrent writes
- Create SettingsBackup class for automatic backup before save
- Implement atomic write with backup/restore on failure
- Add validation on load with auto-recovery from backup
- Add settings backup UI in settings tab (backup/restore/reset)
- Integrate with storagePathManager for unified path management
2026-02-21 16:51:43 +08:00
HeroBlackInk
8cb9bd75ed add storagePathManager module 2026-02-21 16:16:31 +08:00
HeroBlackInk
c856983eaa fix: 修复 databaseChecker 报告统计错误,使用第一步实际统计 2026-02-19 01:30:14 +08:00
HeroBlackInk
0acb0b2d54 refactor: 使用 taskParser.getAllTagsFromLineText 统一标签提取 2026-02-19 01:16:57 +08:00
HeroBlackInk
a133480516 fix: 移除 obsidianLabels 的 # 前缀以便与 Todoist 标签比较 2026-02-19 01:06:47 +08:00
HeroBlackInk
6f78edc203 fix: 过滤 todoist 标签避免 label mismatch 2026-02-19 00:55:57 +08:00
HeroBlackInk
2d17fd8922 fix: 修正 databaseChecker 报告表格计算错误 2026-02-19 00:45:38 +08:00
HeroBlackInk
b8538d99cc refactor: 重构 databaseChecker 为两步对比,增加交叉统计表格
- 新增 unknown_issue 问题类型
- 重构 compareThreeSources 为两步对比:Vault vs Mapping (4种组合) + 与 Todoist 对比 (8种情况)
- 更新 generateReport:添加 Vault vs Mapping Summary 和 8 Cases Detail
- 添加交叉统计表格,支持横向纵向累计
2026-02-19 00:40:28 +08:00
HeroBlackInk
c0c7106ff7 refactor: 统一 scanVaultTasks 和 getTodoistTasksFromSyncData 到 fileOperation
- 在 fileOperation.ts 中创建 scanVaultTasks() 和 getTodoistTasksFromSyncData() 公共方法
- 更新 cacheOperation.ts 使用新的公共方法
- 更新 databaseChecker.ts 使用新的公共方法并删除重复代码
- 新增 task_nonactive 和 task_issue 问题类型,区分非活跃任务
- 更新 taskFileMapping 注释,添加 status 和 syncEnabled 字段说明
- 添加 CACHE_TASK_NON_ID 日志类型
2026-02-18 23:36:56 +08:00
HeroBlackInk
0193d3541f feat: 添加 issue 状态,Vault未完成+Todoist不存在时标记为issue 2026-02-18 22:20:41 +08:00
HeroBlackInk
5826145216 feat: 添加 taskFileMapping status 和 syncEnabled 字段,支持 nonActive 和 conflicted 任务 2026-02-18 22:12:45 +08:00
HeroBlackInk
5fdd8a9f29 fix: convertLegacyIds 单个任务失败不影响其他任务 2026-02-18 14:05:40 +08:00
HeroBlackInk
abfd8046ad fix: 添加 node:sqlite 到 esbuild external 列表 2026-02-18 13:58:17 +08:00