Commit graph

108 commits

Author SHA1 Message Date
HeroBlackInk
a053fa06e9 fix(sync): harden startup sync flow and preserve HTTP errors 2026-02-26 16:51:08 +08:00
HeroBlackInk
b64032399f fix(settings): harden data lifecycle with schema migration, safety guards, and validation
Wave 1 - Safety fixes:
- onunload skips save when load failed (prevents corrupt data persistence)
- rebuildCache no longer persists empty mapping to disk mid-rebuild
- Backup dir computed from settings when storagePathManager unavailable
- Restore operations use atomic temp-file write pattern

Wave 2 - Schema migration framework:
- Add schemaVersion field (CURRENT_SCHEMA_VERSION = 1)
- runMigrations() with forced backup before migration
- v0→v1: isPrimaryDevice boolean → primaryDeviceId string

Wave 3 - Cleanup (depends on Wave 2):
- Replace GHOST_FIELDS denylist with KNOWN_SETTINGS_KEYS allowlist
- stripUnknownFields() auto-removes any key not in DEFAULT_SETTINGS
- sanitizeTaskFileMapping() validates filePath, upgrades missing status/syncEnabled
2026-02-25 10:59:09 +08:00
HeroBlackInk
2d69723a91 fix(settings): improve settings UI controls with Apply buttons and validation
- Sync interval: replace per-keystroke onChange with number input + Apply button
- Add restartSyncSchedulerInterval() to apply interval changes without reload
- Storage directory: replace onChange with Apply button + confirm dialog
- Default project dropdown: fix duplicate current item, add setValue()
- Backup button: add await, loading state, error handling, null checks
- Fix Database: add cacheOperation null check, local variable capture
- Error notices: use error instanceof Error pattern for safe message access
- API token description: update to reference Connect button
2026-02-25 10:44:55 +08:00
HeroBlackInk
d2fe770245 fix(settings): improve API token input security and UX
- 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
2026-02-25 09:06:04 +08:00
HeroBlackInk
0071505886 feat(ui): register Open Task Manager command in command palette
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>
2026-02-24 02:40:22 +08:00
HeroBlackInk
57d629dfdd feat(device): secondary device early return — skip all sync on non-primary
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
2026-02-24 00:35:11 +08:00
HeroBlackInk
055285649e refactor(device): replace isPrimaryDevice boolean with primaryDeviceId string
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
2026-02-24 00:17:52 +08:00
HeroBlackInk
c907fd78f8 fix(sync): remove lastDatabaseCheckPassed gate that blocks sync on fresh installs
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>
2026-02-23 14:11:19 +08:00
HeroBlackInk
fdf5da0c0c fix: replace literal $$$ with correct debugLog arguments in main.ts
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
2026-02-22 15:32:01 +08:00
HeroBlackInk
c98d990d90 refactor: gate all console.log behind debugMode via debugLog() method
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
2026-02-22 15:29:28 +08:00
HeroBlackInk
615a11c805 fix: remove forced syncEnabled=false on startup database check failure
🤖 Sisyphus via OhMyOpenCode
2026-02-22 15:10:46 +08:00
HeroBlackInk
f7ca2d558f fix: prevent bidirectional sync infinite loop via isSyncingFromTodoist flag
🤖 Sisyphus via OhMyOpenCode
2026-02-22 15:08:58 +08:00
HeroBlackInk
e8e476634c fix: scheduler field visibility and missing await in checkModuleClass
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-22 13:31:12 +08:00
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
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
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
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
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
ac849a8709 Fix: add sync lock check to closeTask and repoenTask 2026-02-17 16:55:45 +08:00
HeroBlackInk
630272ff67 Add three-way sync direction controls
- 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
2026-02-17 16:50:28 +08:00
HeroBlackInk
1702ae8950 feat: persist complete syncData to settings
- 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
2026-02-17 15:26:36 +08:00
HeroBlackInk
839a58d01c refactor: start data architecture refactoring - replace todoistTasksData with taskFileMapping
- Remove todoistTasksData from settings, add taskFileMapping
- Modify GetAllProjects/GetTaskById/GetActiveTasks to read from syncData
- Add getProjectById/getProjectByName methods to todoistSyncAPI
- Add taskFileMapping methods to cacheOperation (get/set/delete/getAll)
- Replace cacheOperation calls in obsidianToTodoist.ts
- Replace loadTaskFromCacheyID calls in fileOperation.ts

Build verified successfully.
2026-02-17 14:50:59 +08:00
HeroBlackInk
d7b4167468 fix: improve sync status display and check order - show blocked status when user enables sync with database issues 2026-02-16 12:26:40 +08:00
HeroBlackInk
d83ebf1e46 feat: add database sync control module with auto-check on startup 2026-02-16 12:02:51 +08:00
HeroBlackInk
a68940f12d refactor: extract checkDatabase to separate databaseChecker module 2026-02-16 10:03:33 +08:00
HeroBlackInk
ebb9709a09 fix: resolve module initialization and date handling bugs
- Refactor initializePlugin() to avoid duplicate module initialization
- Fix AddTask date conversion bug (use dueDate instead of dueDatetime)
- Remove unused WorkspaceLeaf import from main.ts
- Remove unused variables (view, editor) in keyup/click handlers
- Clean up commented code in modal.ts
2026-02-16 04:31:23 +08:00
HeroBlackInk
7f4fe92113 feat: add automatic file backup before modifications
- Add BackupOperation class for file backup management
- Backup files to .todoist-backups/ folder before any modification
- Keep max 5 backups per file with automatic cleanup
- Backup triggered in:
  - fileOperation.ts: task complete/uncomplete, tag/link add, content/date/note sync
  - obsidianToTodoist.ts: new task creation
  - cacheOperation.ts: conflict resolution
- Unified backup location with Todoist data backups
2026-02-16 04:13:34 +08:00
HeroBlackInk
3138c0fffb fix: resolve critical bugs and improve backup handling
- 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
2026-02-16 03:51:24 +08:00
HeroBlackInk
21d220028a feat: implement comprehensive operation logging system
- Add LogOperation class with 30+ log action types
- Log Obsidian file operations (modify, rename, task complete/uncomplete)
- Log Cache operations (task add/update/delete/complete/reopen)
- Log Todoist API operations (task create/update/delete)
- Log sync operations (start/complete/error)
- Log backup creation and cache rebuild events
- Add log settings to plugin UI (enable toggle, view/clear buttons)
- Update settings interface with LogAction type
2026-02-16 03:32:39 +08:00
HeroBlackInk
c3c38705e1 release 1.0.43 2023-06-22 17:18:17 +08:00
HeroBlackInk
9ab9f4e521 Added debug mode. 2023-06-11 21:43:49 +08:00