Commit graph

368 commits

Author SHA1 Message Date
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
b258ae558d fix(ui): type safety, echo protection, error filtering, close guard in TaskManagerModal
T2: Add TFile instanceof guards in openFile/getTaskLine, remove as any casts
T3: Filter deleteIssueTask catch to only ignore 404 errors
T4: Add isSyncingFromTodoist echo protection for Keep Todoist resolve
T7: Add _closed flag to prevent post-close DOM operations

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-24 02:40:15 +08:00
HeroBlackInk
8a7deb8a46 fix(ui): add missing .tm-warning and new CSS classes for TaskManagerModal
Add .tm-warning, .tm-refresh-btn, .tm-bulk-bar, and .tm-confirm CSS classes needed for upcoming TaskManagerModal improvements.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-24 02:40:05 +08:00
HeroBlackInk
d8eb2298f3 fix(ui): eliminate N+1 network requests in TaskManagerModal
- loadAndRender(): Added loading indicator and single incrementalSync() call at modal open with warning banner on sync failure
- renderConflictedSection(): Replaced GetTaskById with getTaskByIdLocal for local lookup
- resolveConflict(): Replaced 3 GetTaskById calls with getTaskByIdLocal, preserved post-mutation incrementalSync()

This eliminates the N+1 network requests that prevented the modal from displaying all tasks.
2026-02-24 01:47:15 +08:00
HeroBlackInk
0490881316 fix(api): add getTaskByIdLocal for network-free local task lookup 2026-02-24 01:39:39 +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
04b788e3ab style(ui): redesign Task Manager Modal with proper CSS classes
- Extract all inline styles to styles.css with tm-* class namespace
- Add structured header with summary badges (conflict/issue/inactive counts)
- Improve conflict diff table with change markers and column headers
- Add proper empty state with icon and message
- Use card-based layout with header/body/actions sections
- Add hover effects on table rows, proper button styles
- Consistent spacing, typography, and Obsidian theme variable usage
2026-02-23 19:20:23 +08:00
HeroBlackInk
c19a03d0d1 feat(ui): add Task Manager Modal for viewing and resolving problem tasks
- Add TaskManagerModal class with three sections: Conflicted (5-field diff
  with Keep Obsidian/Keep Todoist), Issue (table + Delete), NonActive (read-only)
- Add unbindTaskInFile() to FileOperation for removing todoist metadata from
  vault lines (todoist_id, links, #todoist tag)
- Add 'Manage Problem Tasks' button to Settings > Tools section
2026-02-23 18:59:56 +08:00
HeroBlackInk
1620cc6810 feat(sync): add device management, echo prevention, and dead code cleanup
- Add isPrimaryDevice setting with UI toggle and device status display
- Add post-push incrementalSync + updated_at to all push methods (echo prevention)
- Add non-primary device push interception to all 6 push methods
- Delete 4 unused getNonObsidian* methods from syncApi.ts
2026-02-23 18:10:24 +08:00
HeroBlackInk
e0364a31f6 feat(sync): add periodic full sync and auto databaseChecker to scheduler 2026-02-23 18:05:19 +08:00
HeroBlackInk
6231294d12 feat(sync): add sync_token expiration detection with auto full-sync fallback 2026-02-23 18:05:19 +08:00
HeroBlackInk
542d26a8d5 feat(settings): add lastFullSyncTime and lastDatabaseCheckAutoTime fields 2026-02-23 18:05:19 +08:00
HeroBlackInk
bef51ceffc fix(sync): unify event handler lock release to try/finally pattern 2026-02-23 18:03:37 +08:00
HeroBlackInk
47c4d37403 fix(sync): move scheduler inProgress reset to finally block 2026-02-23 18:03:32 +08:00
HeroBlackInk
85b0d1163e refactor(data): remove lineNumber from taskFileMapping interface and all callers 2026-02-23 17:20:58 +08:00
HeroBlackInk
9d3a0cabe0 refactor(vault): updateTaskIdInVault scan by ID instead of lineNumber
Ultraworked with Sisyphus
2026-02-23 17:15:35 +08:00
HeroBlackInk
8912c980b8 refactor(data): remove dead code — resolveConflicts, getLineTextFromFilePath
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-23 17:08:11 +08:00
HeroBlackInk
9edb9f1347 fix(sync): remove redundant saveSettings in onKeyUp after deletedTaskCheck
deletedTaskCheck now calls saveSettings() internally when tasks are deleted,
so the outer if (deletedCount > 0) { saveSettings() } in onKeyUp was a
double-save. Remove it.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-23 15:58:53 +08:00
HeroBlackInk
29d52088d9 fix(sync): make deletedTaskCheck and fullTextNewTaskCheck atomic per-task
deletedTaskCheck: replace Promise.all parallel map with for...of serial loop;
each task deletion immediately calls deleteTaskFileMapping then continues to
the next — no more partial-state windows.

fullTextNewTaskCheck: rewrite as per-task atomic cycle — AddTask → setMapping
→ CloseTask (if completed) → vault.modify → saveSettings → vault.read before
next iteration. Rollback (deleteTask + deleteMapping) on any per-task failure.
isProcessingModify guard prevents vault.modify from re-triggering the handler.

Also removes the unused deleteTasksByIds method (zero callers).

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-23 15:58:40 +08:00
HeroBlackInk
9a03072eb6 fix(sync): remove blanket bg incrementalSync and add API-level sync lock
Remove the fire-and-forget incrementalSync() call inside executeCommands that
caused concurrent sync_token conflicts. Replace with an API-level lock using
_syncRunning/_syncDirty/_syncWaiters so concurrent callers queue up and dirty
requests are retried via do-while loop instead of being silently dropped.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-23 15:58:25 +08:00
HeroBlackInk
3c0406c47b fix(sync): prevent newly-created tasks from being marked as deleted
After lineContentNewTaskCheck creates a task, lineModifiedTaskCheck could fire before syncData was updated, causing GetTaskById to return undefined and the task to be incorrectly marked as 'issue'.

Three-layer defense:
1. Immediate incrementalSync after task creation
2. GetTaskById retries with incrementalSync on cache miss
3. lineModifiedTaskCheck skips tasks with mapping age < 30s

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-23 14:11:32 +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
62dbb443c4 feat: expose detailed stats from rebuildCache and show report in Fix Database flow
RebuildCacheResult now returns tasksProcessed, conflictsCount, nonActiveCount,
issueCount, convertedCount, tasksWithoutIdCount. Fix Database button displays
a summary notice after rebuild so users can see exactly what was found.

🤖 Sisyphus via OhMyOpenCode
2026-02-22 15:50:40 +08:00
HeroBlackInk
ac1871c3c5 fix: improve rebuildCache reliability and observability
- Show Notice to user when conflicts are found during rebuild
  (previously only logged to debug, user had no visibility)
- Use vault.read() instead of cachedRead() in scanVaultTasks so
  rebuild always reads fresh disk content, not stale memory cache
- Warn to console when duplicate taskId found across files instead
  of silently dropping the second occurrence
- Downgrade legacy ID conversion failure from error to warn and
  include note that affected tasks will retry on next rebuild

🤖 Sisyphus via OhMyOpenCode
2026-02-22 15:44:09 +08:00
HeroBlackInk
54ee959867 fix: populate updated_at in rebuildCache for consistent tasks
When Vault and Todoist content/status match (active), write the
Todoist updated_at into the cache entry. This prevents toObsidian
from treating every task as changed after a rebuild, which would
cause unnecessary full pulls and risk overwriting local edits.
Conflicted/nonActive/issue entries intentionally leave updated_at
unset since syncEnabled=false already guards them.

🤖 Sisyphus via OhMyOpenCode
2026-02-22 15:37:14 +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
5865673927 feat: replace Notice log viewer with scrollable LogViewerModal (search + direction filter)
🤖 Sisyphus via OhMyOpenCode
2026-02-22 15:18:53 +08:00
HeroBlackInk
5879343b06 feat: add sync direction to log entries (obsidian→todoist / todoist→obsidian)
🤖 Sisyphus via OhMyOpenCode
2026-02-22 15:14:54 +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
75fe2080fb refactor: decouple sync master switch from database check results
Previously, Fix Database would force-enable or force-disable syncEnabled based on check results. Now the master sync switch is fully user-controlled and independent of database health.

Database issues are now shown as a non-blocking warning appended to the status text instead of replacing it. This allows users to:
- Keep sync enabled even with database issues (at their own risk)
- Disable sync independently of database health
- See both sync status and database warnings simultaneously

Changes:
- Remove syncEnabled updates from database check/fix operations
- Append database warning to status text instead of replacing it
- Update user-facing notices to remove sync enable/disable messaging

🤖 Sisyphus via OhMyOpenCode
<!-- OMO_INTERNAL_INITIATOR -->
2026-02-22 15:01:10 +08:00
HeroBlackInk
93f6e2f6b8 feat: render file paths as Obsidian wiki links in database check report
Update the database check report generator to display file paths as clickable Obsidian wiki links ([[path|filename]]) in the issues table, enabling users to navigate directly to affected files from the report.

🤖 Sisyphus via OhMyOpenCode
<!-- OMO_INTERNAL_INITIATOR -->
2026-02-22 14:56:30 +08:00
HeroBlackInk
98935525f8 feat: add Verify Database button in settings for read-only database health check
Adds a new 'Verify Database' button in the settings UI that:
- Runs checkDatabase() in read-only mode
- Displays task counts from Todoist and vault mappings
- Shows health status ( Healthy or ⚠️ N issues)
- Generates and links to a detailed report
- No data is modified during verification

🤖 Sisyphus via OhMyOpenCode
<!-- OMO_INTERNAL_INITIATOR -->
2026-02-22 14:53:11 +08:00
HeroBlackInk
e680ae1d96 refactor: consolidate database maintenance into single 'Fix Database' button
Combines three redundant buttons (Rebuild Cache, Check Database, Fix & Enable Sync) into one unified workflow:

- Step 1: Check database for inconsistencies
- Step 2: Auto-rebuild cache if issues found
- Step 3: Re-check and report fixed vs remaining issues

Provides clearer user feedback with progress indicators and distinguishes between auto-fixable issues (missing mappings, orphan records) and manual fixes (content conflicts, missing files).

🤖 Sisyphus via OhMyOpenCode
<!-- OMO_INTERNAL_INITIATOR -->
2026-02-22 14:48:56 +08:00
HeroBlackInk
0bd4417bd4 feat: add conflict resolution strategy with todoist-wins/obsidian-wins/manual modes
- Add conflictResolutionStrategy setting (interface, DEFAULT_SETTINGS, UI dropdown)
- lineModifiedTaskCheck: handle GetTaskById returning undefined (deleted task → mark issue)
- lineModifiedTaskCheck: apply strategy instead of always marking conflicted
  - todoist-wins: clear cached updated_at, let next pull overwrite Obsidian
  - obsidian-wins: fall through to push Obsidian content to Todoist
  - manual: disable sync until user resolves (existing behavior)
- closeTask/repoenTask: add same conflict detection + strategy logic before API calls

Co-authored-by: Sisyphus <sisyphus@ohmyopencode.ai>
2026-02-22 14:38:18 +08:00
HeroBlackInk
7bb1112098 fix: add context to bare console.error calls in syncApi
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-22 14:24:09 +08:00
HeroBlackInk
6040d736a4 fix: show Notice when rebuildCache fails without a noticeCallback
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-22 14:23:58 +08:00
HeroBlackInk
14ee235002 fix: add missing Notice on error paths in sync engines and logOperation in fullTextNewTaskCheck
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-22 14:23:48 +08:00
HeroBlackInk
6d325b724c fix: conflict detection in lineModifiedTaskCheck, rollback on AddTask failure, and batch saveSettings in fullTextNewTaskCheck
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-22 14:14:21 +08:00
HeroBlackInk
48dcf79c1c fix: add rollback on rebuildCache failure and persist syncMeta via safeSettings
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-22 14:14:14 +08:00
HeroBlackInk
21bcfb30dc fix: remove redundant cache preload in initializeSync and use system timezone
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-22 14:14:07 +08:00
HeroBlackInk
8245bb7755 fix: add missing await on checkModuleClass in scheduler
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-22 14:14:02 +08:00
HeroBlackInk
b1fc17e430 refactor: move Last Check display to Check Database section
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-22 13:40:18 +08:00
HeroBlackInk
ab635a3230 fix: instanceof check always false in backup and dead if(false) in databaseChecker
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-22 13:31:52 +08:00
HeroBlackInk
5533d0b517 fix: hardcoded UTC+8 timezone, dead return statement, and wrong async return type
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-22 13:31:41 +08:00
HeroBlackInk
eb32a6a985 fix: non-existent method call and empty project dropdown in settings
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-22 13:31:31 +08:00
HeroBlackInk
a425ff6083 fix: missing await on async calls in event handlers and sync pipeline
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-22 13:31:22 +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