- Change input type to password (token no longer visible by default)
- Add eye toggle button to show/hide token
- Replace per-keystroke onChange with blur-based save (only saves on change)
- Add loading/success/failure feedback on send button
- Add tooltips to eye and send buttons
- Fix modifyTodoistAPI() to return boolean for success/failure detection
Add open-task-manager command so users can access Task Manager without navigating to Settings.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Non-primary devices now exit onload() immediately after loading settings,
keeping only the settings tab and status bar. No scheduler, no event
handlers, no API connections, no commands registered.
- onload: check deviceId vs primaryDeviceId before initializePlugin()
- onload: skip deviceId generation when no API token (fresh install safety)
- initializePlugin: auto-claim primary when primaryDeviceId is empty
- Settings UI: button text 'Switch to Primary' + reload notice
Fixes multi-device bug where Obsidian Sync copies data.json across devices,
causing all devices to claim primary role. Now stores the primary device's
ID string and compares against local device-id file (not synced).
- Settings: isPrimaryDevice:boolean → primaryDeviceId:string (default empty)
- Migration: auto-migrates isPrimaryDevice=true → primaryDeviceId=<deviceId>
- GHOST_FIELDS: strips legacy isPrimaryDevice from loaded data
- main.ts: cachedDeviceId property + synchronous isPrimaryDevice() helper
- toTodoist.ts: 6 push guards use isPrimaryDevice() method
- Settings UI: toggle replaced with 'Claim as Primary' button + status display
- checkModuleClass: added deviceManager to guard list
The field defaults to false, so after data.json loss or fresh install, sync was permanently blocked until manual database fix. Each task already has its own syncEnabled flag, making this global gate redundant.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
ast-grep metavariable $$$ was written literally instead of being
expanded during the previous refactor, causing ReferenceError at runtime.
Restored original log message strings for all 8 affected call sites.
🤖 Sisyphus via OhMyOpenCode
Replace all console.log calls in main.ts and src/ with this.debugLog() /
this.plugin.debugLog() so debug output is suppressed unless Debug Mode
is enabled in settings.
🤖 Sisyphus via OhMyOpenCode
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
- 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
- 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
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.
- 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
- Modify deletedTaskCheck() to return number of deleted tasks
- Only call saveSettings() when deletedCount > 0
- This prevents unnecessary SettingsBackup triggers on every Delete/Backspace keypress
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- Add obsidianToTodoistEnabled (default: true) and todoistToObsidianEnabled (default: false) settings
- Modify checkAndHandleSyncLock to accept direction parameter
- Update all 11 call sites with appropriate direction values
- Add UI toggles for both new settings in settings tab
- Update sync status display to show direction states
- Add syncDataCache field to settings to store raw API response
- Change syncData type to Record<string, any> to hold complete API response
- Add loadFromCache() method to load cached data on startup
- Save syncData to cache after full sync and incremental sync
- On startup, try loading from cache first before full sync
- Fix checkbox regex to support string IDs (\d+ -> \w+) in main.ts
- Fix taskParser regex to support string IDs
- Remove unused imports (Notice from logOperation, Plugin from settings)
- Move backup files to .todoist-backups/ folder to avoid polluting vault
- Add backup folder creation if not exists