Commit graph

138 commits

Author SHA1 Message Date
ClaudiaFang
1111308a2d chore(skills): install clean-code, design-taste-frontend, frontend-design skills
Adds skill files pulled from firstsun-dev/skills and their lockfile
entries, used during this session's UX review and fixes.
2026-07-05 05:15:47 +00:00
ClaudiaFang
d11ca94073 fix(lint): resolve Obsidian plugin linter warnings
- drop unnecessary type assertion in SyncStatusView tab rendering
- use window.setTimeout instead of global setTimeout
- use window instead of globalThis when resolving Electron's require

docs: list supported Git providers at the top of README
2026-07-05 05:14:28 +00:00
ClaudiaFang
acebafd94a fix(ui): keep ribbon/command labels in sync with configured Git service
The push ribbon icon's tooltip and the "Push/Pull current file"
command names embedded the configured service name (e.g. "Push to
GitHub") but were only set once at plugin load. Switching service in
Settings afterward left them stale until Obsidian was reloaded.

- Ribbon tooltip is now re-applied via setTooltip() on every
  saveSettings(), so it always reflects the current service.
- Command names have no rename API in Obsidian, so they're now
  generic ("Push current file" / "Pull current file"), matching the
  wording already used by "Push all files" / "Pull all files".
2026-07-05 05:13:52 +00:00
ClaudiaFang
1364b94f0a fix(sync): stop batch push/pull from silently overwriting conflicts
Single-file push/pull already detected when both local and remote
changed since the last sync and prompted via SyncConflictModal, but
"Push all"/"Pull all"/multi-select batch actions skipped that check
and force-overwrote. Batch operations now skip conflicting files and
report a conflicts count so nothing is silently clobbered.

Also correct delete-confirmation copy: it claimed local deletes are
recoverable ("moved to trash") unconditionally, but the actual
destination depends on the vault's "Deleted files" setting (which can
be permanent). Wording now defers to that setting instead of
asserting recoverability.
2026-07-05 05:05:54 +00:00
ClaudiaFang
2f6859a2f1 fix(sync): clearer branch-not-found errors and connection test
- listFilesDetailed rethrows 404 branch-resolution failures with a
  message naming the branch, instead of a bare "Git Service Error (404)"
- testConnection now also checks the configured branch exists and
  reports repoOk/branchOk separately so the settings UI can warn when
  the repo is reachable but the branch is missing
- fixes settings.ts silently reporting "connection successful" even
  when testConnection's result was never checked

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 04:57:47 +00:00
Claude
1e21061aa8
perf(ui): parallelize refresh status checks and throttle re-renders
Refresh checked files one at a time (a sequential network request per
file) and re-rendered the whole view after every file, so a large vault
was slow. Run the per-file checks with a bounded concurrency pool (8) and
re-render on a ~150ms throttle plus a final render. Behavior and results
are unchanged; wall time drops roughly in line with the concurrency.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DwioG4CNKUBuKiZdowLFWe
2026-06-28 05:36:47 +00:00
Claude
9bcaed65f4
feat(sync): real symbolic link support (GitHub) with configurable handling
Adds end-to-end symlink syncing driven by the "Symbolic links" setting
(real / follow / skip; default real), building on the earlier detection.

- Pull: on desktop with "real", a remote symlink is recreated as a real OS
  link via Node fs (utils/symlink.ts, guarded by Platform/FileSystemAdapter);
  otherwise the target path is written as content.
- Push: GitHubService.pushSymlink commits a real symlink blob (mode 120000)
  through the Git Data API (blob -> tree -> commit -> ref). getFile now
  reports isSymlink/symlinkTarget.
- Config 防呆: only GitHub offers "real"; on GitLab/Gitea (no API to create
  symlinks) "real" resolves to "skip" via getEffectiveSymlinkHandling.
- Safety: a "follow" push never overwrites a detected remote symlink with a
  regular file; it is skipped with a notice.
- Docs: docs/symlink-handling.md plus a README settings note.

Lint is satisfied without disables (Electron global require, minimal Node
type shims). Adds tests for getFile detection, the pushSymlink Git Data
sequence, and the remote-symlink push guard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DwioG4CNKUBuKiZdowLFWe
2026-06-28 05:14:35 +00:00
ClaudiaFang
13d802e33e
Merge pull request #35 from firstsun-dev/claude/trusting-volta-qlg8bk
Claude/trusting volta qlg8bk
2026-06-28 13:01:07 +08:00
Claude
90981261a5
Merge remote-tracking branch 'origin/claude/git-files-sync-issue-31-54izdm' into claude/trusting-volta-qlg8bk
# Conflicts:
#	.github/workflows/ci.yml
#	package-lock.json
2026-06-28 04:50:34 +00:00
Claude
62b475d632
feat(sync): detect symbolic links and add a configurable handling setting
Symlinks are Git blobs with mode 120000 whose content is the target path.
They were treated as ordinary files, which caused 404s on fetch and could
corrupt the file on pull. Add detection and let the user choose behavior.

- Settings: new "Symbolic links" option (symlinkHandling) with real
  (default) / follow / skip.
- Services: listFilesDetailed() reports each entry's symlink flag from the
  tree mode (120000) for GitHub and GitLab; listFiles() now delegates to it.
- Refresh/discovery: with "skip", remote symlinks are excluded from sync;
  with "follow"/"real" they are included and synced as the target content.

Note: true OS-level symlink recreation on desktop and pushing files as
symlinks (Git Data API) are not yet implemented — on all platforms "real"
currently syncs the target content like "follow"; mobile has no symlink
API regardless. Tracked as a follow-up.

Add tests for symlink detection on both services and update settings fixtures.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DwioG4CNKUBuKiZdowLFWe
2026-06-28 04:45:41 +00:00
Claude
c474a7e6c4
fix(services): stop logging expected 404s as errors during refresh
Loading .gitignore files probes paths that often don't exist remotely.
getFile already treats 404 as "empty file" (handleFileNotFound) and the
gitignore lookup ignores failures, but safeRequest logged every 404 as an
error — twice, because its own catch re-caught the error it had just
thrown. This produced scary "Git Service Request Failed (404): Not Found"
console output during a normal pull/refresh.

Restructure safeRequest so the catch only wraps the network call (no
double-logging of HTTP-status errors), and log an expected 404 at debug
level instead of error. Non-404 statuses are still logged as errors and
all statuses still throw so callers can handle them.

Add a debug level to the logger and regression tests for 404 vs 500.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DwioG4CNKUBuKiZdowLFWe
2026-06-28 04:27:25 +00:00
Claude
9bc8ab7d08
fix(ui): match Open sync status ribbon icon to the view icon
The ribbon button used 'list-checks' while the Sync Status view itself
uses 'git-compare' (getIcon). Use 'git-compare' for the ribbon too so the
"Open sync status" icon matches the sync status view icon.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DwioG4CNKUBuKiZdowLFWe
2026-06-28 04:23:57 +00:00
Claude
f2037f955a
ci: drop removed skip-sonar input and SONAR_TOKEN secret
The shared workflow obsidian-plugin-ci.yml@v1 no longer defines the
skip-sonar input or the SONAR_TOKEN secret, which made the caller
workflow invalid ("Invalid input/secret ... is not defined in the
referenced workflow"). Remove both so the workflow validates again.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DwioG4CNKUBuKiZdowLFWe
2026-06-27 09:10:45 +00:00
Claude
76405cf2f7
fix(sync): fall back to adapter read for symlinked files
Reading a symlinked file via Obsidian's cached vault.read(TFile) can fail
(notably on mobile), which broke both refresh and push: the status check
swallowed the error and mislabeled the file as 'unsynced', so the user
saw a Push button that then failed re-reading the symlink.

Fall back to vault.adapter.read/readBinary(path) when vault.read throws,
in both the status view and the sync manager. Also stop silently
swallowing the status-check error so the real cause is logged.

Add a regression test covering the adapter fallback on push.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DwioG4CNKUBuKiZdowLFWe
2026-06-26 06:28:25 +00:00
Claude
d8d6f9dcb1
refactor(ui): unify Sync Status icons via Lucide setIcon
The view mixed hand-picked Unicode glyphs (✓ ⚠ ↑ ↓ ⟳ ↻ ✕ ≡ ⎇ 📁),
duplicated across files, which rendered at inconsistent sizes/weights
across platforms and could drift (e.g. the Refresh button used ↻ while
the "checking" status used ⟳).

Centralize every icon in src/ui/components/icons.ts as Lucide icon ids and
render them with Obsidian's setIcon, so status, action-bar, tab, and
info-strip icons all share one consistent icon set. Tabs now derive their
icon from statusMeta so they can no longer diverge from the file list.
Add CSS to size the SVGs uniformly.

Add setIcon to the obsidian test mock and update statusMeta expectations.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DwioG4CNKUBuKiZdowLFWe
2026-06-26 06:22:53 +00:00
Claude
339d5cbe77
fix(services): omit blank sha so creating a new file doesn't 422
Pushing a new file via the single-file push button failed with GitHub
HTTP 422. A 404 lookup returns sha === '' for new files, and the manual
push path (sync-manager pushFile/conflict resolution) forwarded that
empty string into the Contents API request body as "sha":"", which
GitHub rejects. Batch push avoided this via `remote.sha || undefined`.

Fix at the service layer so every caller is safe: only include sha in the
GitHub request body when it is non-empty. Apply the same guard to the
GitLab service's last_commit_id for symmetry.

Add regression tests for blank-sha pushes on both services.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DwioG4CNKUBuKiZdowLFWe
2026-06-26 06:07:59 +00:00
Claude
bcc5cda69c
fix(services): clear error when Git API returns HTML instead of JSON
Refresh failed with the cryptic "Unexpected token '<', "<!DOCTYPE ..."
is not valid JSON" whenever the Git server returned an HTML page (login,
SSO redirect, or proxy/error page) on a 2xx/3xx response. safeRequest
only threw on status >= 400, so such bodies slipped through and crashed
at response.json.

Add BaseGitService.parseJson() which detects non-JSON/HTML bodies and
throws an actionable message, and use it for all response.json reads in
the GitHub and GitLab services. Also harden parseErrorResponse so HTML
error pages produce a clear message instead of dumping the raw document.

Add tests covering HTML 2xx responses, HTML detection by leading '<',
malformed JSON, and HTML error pages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DwioG4CNKUBuKiZdowLFWe
2026-06-26 06:02:40 +00:00
ClaudiaFang
49bfe9f4c2
docs: add video (#30)
Updated video link to a GitHub asset for better accessibility.
2026-06-19 20:23:03 +08:00
ClaudiaFang
df44a96c9b docs: update intro video with refreshed content 2026-06-19 11:59:00 +00:00
semantic-release-bot
9a4d136e63 chore(release): 1.1.2 [skip ci]
## [1.1.2](https://github.com/firstsun-dev/git-files-sync/compare/1.1.1...1.1.2) (2026-06-16)

### Bug Fixes

* **lint:** replace activeWindow.setTimeout with setTimeout ([4099f44](4099f44fa5))
2026-06-16 13:34:20 +00:00
ClaudiaFang
4099f44fa5 fix(lint): replace activeWindow.setTimeout with setTimeout
Removes the eslint-disable comment and uses the standard setTimeout
which is properly typed in the DOM lib and satisfies the obsidianmd
lint rule requiring window-prefixed timer functions to use bare form.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 13:32:44 +00:00
Claude
e4d72e0f87
ci: upgrade actions to Node 24 compatible versions
- actions/checkout: v4 → v6
- actions/setup-node: v4 → v6
- actions/upload-artifact: v4 → v5
- actions/checkout (codeql.yml): v4 → v6

https://claude.ai/code/session_019Jbz6HpQvWU1wpm5M6MZpd
2026-06-16 04:26:39 +00:00
Claude
8eb5903336
ci: fix artifact name by sanitizing branch name slashes
Replace / with - in branch name and use short SHA (7 chars)
e.g. plugin-claude-trusting-volta-qlg8bk-c2c5dd5

https://claude.ai/code/session_019Jbz6HpQvWU1wpm5M6MZpd
2026-06-16 04:24:39 +00:00
Claude
21a6f984ee
ci: update GitHub Actions to latest versions
- actions/setup-node: node 20 → 22 (Node 20 EOL Apr 2026)
- github/codeql-action: v3 → v4 (v3 deprecated Dec 2026)

https://claude.ai/code/session_019Jbz6HpQvWU1wpm5M6MZpd
2026-06-16 04:23:56 +00:00
Claude
c2c5dd584c
ci: upload build artifact on non-main branches for testing
https://claude.ai/code/session_019Jbz6HpQvWU1wpm5M6MZpd
2026-06-16 04:22:32 +00:00
Claude
8024939a89
ci: remove SonarQube from CI/CD pipeline
https://claude.ai/code/session_019Jbz6HpQvWU1wpm5M6MZpd
2026-06-16 04:15:01 +00:00
Claude
615819c39e
docs: update USAGE_zh.md with Gitea support and provider compatibility table
https://claude.ai/code/session_019Jbz6HpQvWU1wpm5M6MZpd
2026-06-16 04:12:06 +00:00
Claude
6afeaf673d
chore: update package-lock.json
https://claude.ai/code/session_019Jbz6HpQvWU1wpm5M6MZpd
2026-06-16 04:10:00 +00:00
Claude
7648eef279
fix: use two-step branch→SHA resolution in GiteaService.listFiles
Gitea's git/trees endpoint requires a tree or commit SHA, not a branch
name, on instances older than ~1.17. Resolve branch to commit SHA via
/branches/{branch} first, then fetch /git/trees/{commitSha}?recursive=1.

Also updates README with provider compatibility table and SVG icons for
GitHub, GitLab, and Gitea.

https://claude.ai/code/session_019Jbz6HpQvWU1wpm5M6MZpd
2026-06-16 04:09:29 +00:00
Claude
130bd93f84
feat: add Gitea support as third-party Git provider
- Add GiteaService implementing BaseGitService/GitServiceInterface
  - Uses Gitea API v1 endpoints (/api/v1/repos/{owner}/{repo}/...)
  - POST for file creation, PUT for updates (differs from GitHub)
  - Authorization: token {token} header
- Add giteaToken, giteaBaseUrl, giteaOwner, giteaRepo settings fields
- Add Gitea option to service type dropdown in settings UI
- Add displayGiteaSettings() panel in settings tab
- Update initializeGitService() to instantiate GiteaService
- Update getServiceName() to handle 'gitea' type
- Add comprehensive test suite (gitea-service.test.ts, 15 test cases)
- Update existing test fixtures to include new Gitea settings fields

Closes #26

https://claude.ai/code/session_019Jbz6HpQvWU1wpm5M6MZpd
2026-06-16 04:04:01 +00:00
semantic-release-bot
e18851934a chore(release): 1.1.1 [skip ci]
## [1.1.1](https://github.com/firstsun-dev/git-files-sync/compare/1.1.0...1.1.1) (2026-06-16)

### Bug Fixes

* **ci:** switch to shared workflow v1 and fix repository url ([3a0f99e](3a0f99e383))
2026-06-16 03:54:45 +00:00
ClaudiaFang
3a0f99e383 fix(ci): switch to shared workflow v1 and fix repository url 2026-06-16 03:53:29 +00:00
semantic-release-bot
1bde1c33e9 chore(release): 1.1.0 [skip ci]
## [1.1.0](https://github.com/firstsun-dev/git-files-sync/compare/1.0.6...1.1.0) (2026-06-16)

### Features

* support hidden file sync and expand binary extension list ([649d732](649d732781))

### Documentation

* remove SonarCloud quality gate badge from README ([d907baf](d907baf229))
* update README badges ([7cd9e38](7cd9e38e65))

### Code Refactoring

* **test:** eliminate duplicate code flagged by SonarCloud ([f49600e](f49600eb66))
* **test:** extract shared SyncManager mock setup to reduce duplication ([1f71a43](1f71a43980))
2026-06-16 03:50:36 +00:00
ClaudiaFang
6d475cef6c
Merge pull request #27 from firstsun-dev/dependabot/npm_and_yarn/npm_and_yarn-53cbaf2a5b
chore(deps-dev): bump esbuild from 0.28.0 to 0.28.1 in the npm_and_yarn group across 1 directory
2026-06-16 01:41:16 +08:00
dependabot[bot]
44b3db39a3
chore(deps-dev): bump esbuild
Bumps the npm_and_yarn group with 1 update in the / directory: [esbuild](https://github.com/evanw/esbuild).


Updates `esbuild` from 0.28.0 to 0.28.1
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.28.0...v0.28.1)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-version: 0.28.1
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-13 01:43:47 +00:00
ClaudiaFang
eefd72846e
Merge pull request #25 from firstsun-dev/issue-23-code-quality
feat: support hidden file sync and expand binary extension list
2026-05-26 12:51:11 +08:00
ClaudiaFang
8d7a25f30c ci: add CodeQL static analysis workflow 2026-05-25 02:47:07 +00:00
ClaudiaFang
7cd9e38e65 docs: update README badges 2026-05-25 02:35:58 +00:00
ClaudiaFang
f49600eb66 refactor(test): eliminate duplicate code flagged by SonarCloud
- Extract adapter variable and loadWith() helper in gitignore hidden-file tests
- Hoist shared ArrayBuffer constants in path.test.ts
Reduces new_duplicated_lines_density from ~78%/46% to near 0%.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 03:52:32 +00:00
ClaudiaFang
d907baf229 docs: remove SonarCloud quality gate badge from README
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 03:45:56 +00:00
ClaudiaFang
1f71a43980 refactor(test): extract shared SyncManager mock setup to reduce duplication
Move repeated beforeEach mock initialization into createSyncManagerMocks()
helper to eliminate ~45 lines of copy-paste across binary and hidden test files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 03:40:45 +00:00
ClaudiaFang
fcb9447733 test: expand coverage for binary files, hidden paths, and edge cases
- Add sync-manager-binary.test.ts: push/pull ArrayBuffer via adapter.readBinary/writeBinary
- Add sync-manager-hidden.test.ts: hidden path mkdir, push, pull via string paths
- Add utils/path.test.ts: isBinaryPath and contentsEqual full coverage
- Add metadata-on-equal assertion to sync-manager tests
- Add GitHub truncated result and GitLab pagination boundary tests
- Add hidden file gitignore filter tests
- Add docs/test-coverage.md with all 189 test cases documented

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 03:35:36 +00:00
ClaudiaFang
49acf05241 chore(agent): update obsidian skills 2026-05-22 03:16:30 +00:00
ClaudiaFang
d5379c1f3f
Merge branch 'master' into issue-23-code-quality 2026-05-22 11:09:44 +08:00
ClaudiaFang
649d732781 feat: support hidden file sync and expand binary extension list
- Use FileSystemAdapter.list() recursively to discover hidden files (e.g. .claude)
- Fix ensureParentDirs to use adapter.mkdir() for hidden directory creation
- Expand BINARY_EXTENSIONS with modern image, audio, video, archive, and design formats
- Exclude .agents/** from ESLint to prevent project-service parse errors

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 03:08:15 +00:00
semantic-release-bot
d41d98d0b3 chore(release): 1.0.6 [skip ci]
## [1.0.6](https://github.com/firstsun-dev/git-files-sync/compare/1.0.5...1.0.6) (2026-05-20)

### Bug Fixes

* **release:** trigger patch release on chore(deps) commits ([910305a](910305a81c))
* **test:** add @types/jsdom and fix Element type cast in setup-dom ([8f7207a](8f7207a388))
* **ui:** real-time file status during refresh and unsynced file actions ([c6152a6](c6152a61bb))

### Code Refactoring

* code quality enhancements for issue [#23](https://github.com/firstsun-dev/git-files-sync/issues/23) ([7f223e3](7f223e33b8))
* code quality enhancements for issue [#23](https://github.com/firstsun-dev/git-files-sync/issues/23) ([31ac918](31ac9189cf))
* eliminate code duplication flagged by SonarCloud ([556f9e9](556f9e930d))
2026-05-20 09:12:47 +00:00
ClaudiaFang
f9499a4895
Merge pull request #24 from firstsun-dev/issue-23-code-quality
fix: code quality enhancements and UI improvements (#23)
2026-05-20 17:11:30 +08:00
ClaudiaFang
556f9e930d refactor: eliminate code duplication flagged by SonarCloud
- Move contentsEqual to src/utils/path.ts (shared by sync-manager + SyncStatusView)
- Replace private isBinary in both files with isBinaryPath from path.ts
- Extract fileItemCallbacks() in SyncStatusView to remove duplicate callback objects
- Create tests/services/service-test-helpers.ts with shared testConnection,
  getRepoGitignores, getFile error handling, getLastRequestCall helpers
- Refactor github/gitlab service tests to use shared helpers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 09:09:02 +00:00
ClaudiaFang
8f7207a388 fix(test): add @types/jsdom and fix Element type cast in setup-dom
jsdom v29 uses exports field for types, incompatible with moduleResolution
"node" in CI — adding @types/jsdom provides standalone type declarations.
Cast el to HTMLInputElement directly instead of instanceof window.HTMLInputElement
to avoid unresolvable type narrowing across jsdom window context.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 08:59:05 +00:00
ClaudiaFang
7f223e33b8 refactor: code quality enhancements for issue #23
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 08:56:28 +00:00