feat: add cursor auth and dashboard sync#17
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an explicit Cursor auth/sync workflow to codetok, including local credential storage and an on-demand dashboard CSV sync, while ensuring the existing local Cursor provider can discover the synced cache.
Changes:
- Introduces
codetok cursor login|status|sync|logoutvia a new Cobra command wired into the root CLI. - Adds a new
cursordomain package: credential storage (atomic + owner-only), Cursor API client (validate + export CSV), and sync orchestration. - Extends Cursor provider tests to confirm synced CSVs in a nested
synced/directory remain discoverable.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| provider/cursor/parser_test.go | Adds coverage ensuring nested synced/usage.csv is discovered by the existing provider. |
| docs/plans/2026-03-16-cursor-dashboard-sync-implementation.md | Documents the implementation plan for Cursor auth + dashboard sync. |
| cursor/auth.go | Implements Service for login/status/logout backed by storage + API client abstraction. |
| cursor/client.go | Adds Cursor HTTP client for session validation and CSV export. |
| cursor/storage.go | Adds credential + synced CSV storage with atomic writes and restricted perms. |
| cursor/sync.go | Implements sync orchestration: load creds → fetch CSV → atomically write cache. |
| cmd/cursor.go | Adds codetok cursor command group and subcommands. |
| *_test.go files | Adds unit tests across cmd/ and cursor/ plus provider coverage for synced CSV discovery. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if err := os.Rename(tmpPath, path); err != nil { | ||
| return err | ||
| } |
There was a problem hiding this comment.
Fixed. Atomic writes now use a replace helper that retries via remove-and-rename when destination replacement is required, and coverage now exercises overwriting an existing cache file.
| func (s Store) CredentialsPath() string { | ||
| path, _ := s.credentialsPath() | ||
| return path | ||
| } | ||
|
|
||
| // SyncedCSVPath returns the path to the tool-owned synced CSV cache file. | ||
| func (s Store) SyncedCSVPath() string { | ||
| path, _ := s.syncedCSVPath() | ||
| return path |
There was a problem hiding this comment.
Fixed. CredentialsPath now returns (string, error) so home-dir resolution failures surface directly, with regression coverage for the default-root failure path.
| func (s Store) CredentialsPath() string { | ||
| path, _ := s.credentialsPath() | ||
| return path | ||
| } | ||
|
|
||
| // SyncedCSVPath returns the path to the tool-owned synced CSV cache file. | ||
| func (s Store) SyncedCSVPath() string { | ||
| path, _ := s.syncedCSVPath() | ||
| return path |
There was a problem hiding this comment.
Fixed. SyncedCSVPath now returns (string, error) instead of swallowing root-resolution failures, and the tests cover that error path.
| if err != nil { | ||
| return nil, fmt.Errorf("read usage CSV: %w", err) | ||
| } | ||
| if !bytes.HasPrefix(bytes.TrimSpace(data), []byte("Date,")) { |
There was a problem hiding this comment.
Fixed. FetchUsageCSV now tolerates an optional UTF-8 BOM before the Date, header, and there is regression coverage for BOM-prefixed CSV exports.
Summary
codetok cursor login,status,sync, andlogoutsubcommandsWorkosCursorSessionTokenagainst Cursor before saving it locally and store credentials with atomic owner-only writes~/.codetok/cursor/synced/usage.csvwith failure-safe cache preservation and test coverageValidation
make fmtmake vetmake testmake build./bin/codetok cursor --helpHOME=$(mktemp -d) ./bin/codetok cursor status./bin/codetok daily --all --cursor-dir "$(pwd)/e2e/testdata/cursor" --kimi-dir "$EMPTY_DIR" --claude-dir "$EMPTY_DIR" --codex-dir "$EMPTY_DIR"make lint(golangci-lintnot installed in this environment, target skipped)Notes
daily/sessionflows remain local-only and do not call Cursor APIs