firstsun-dev_git-files-sync/progress.md
ClaudiaFang 563a28e44f Merge remote-tracking branch 'origin/claude/fix-directory-symlink-pull-260713'
Resolves conflicts between issue #78 (delete-remote-only-file) fixes and
the i18n work landed on this branch in parallel: the delete-result Notice
now uses the i18n t() helper with a new 'partialWithMessage' key (en +
zh-tw) that carries the real error text.
2026-07-14 09:13:45 +00:00

8.2 KiB

Session Progress Log

Completed work is archived in archive/, one file per calendar month — this file only tracks what's still open.

Current State

Last Updated: 2026-07-14 09:20 Session ID: current Active Feature: issue #78 (blog repo, misfiled — actually a git-files-sync bug: delete remote-only file fails) — two root causes fixed, user re-testing after rebuild

Status

What's Done

  • feat-001..009 (project setup, settings UX bundle, folder picker, symlink pull fix, tree-SHA refresh, HTML-response error clarity, what's-new modal, i18n/multi-language support) — see archive/2026-07.md
  • All consolidated onto branch claude/fix-directory-symlink-pull-260713PR #51 (open, all CI green as of last check), per user's explicit request to keep the PR count down rather than one PR per issue.
  • "Root path" folder picker now suggests folders from the remote repo tree instead of the local vault. Added src/ui/RemoteFolderSuggest.ts (derives folder paths from gitService.listFiles(branch, false)); wired into the Root path field in src/settings.ts. Vault folder field untouched (still uses local FolderSuggest).
  • Issue #78 (filed in firstsun-dev/blog but actually a git-files-sync bug — user confirmed to fix it here regardless of repo mismatch): "delete remote only file fail". Two distinct root causes found and fixed:
    1. URL encoding + silent empty-sha delete: github-service.ts/gitea-service.ts getApiUrl() built the Contents API URL without encodeURIComponent on path segments (unlike gitlab-service.ts, which already encodes), so paths with spaces/non-ASCII (e.g. Chinese filenames) 404'd on the pre-delete sha lookup; that 404 silently produced an empty sha, and the resulting DELETE with sha: '' was rejected — silently, since the UI swallowed all delete errors. Fixed: encode path segments in both services; deleteFile() now throws a clear error if the pre-delete lookup's sha is empty; SyncStatusView.ts delete flow now captures {path, message} per failure and surfaces the real message in the Notice (syncStatus.notice.deleteResult.partialWithMessage i18n key, added to both en.ts/zh-tw.ts) instead of a bare "N failed".
    2. EISDIR on local-only symlinked folders: user confirmed the actual file they tried to delete was not a symlink, but a real console error they pasted (EISDIR: illegal operation on a directory, read for .claude/skills/polish-blog) revealed a second bug: SyncStatusView.ts readFileContent() called adapter.read() directly on string paths with no symlink guard — only the sha-based path (readLocalContentForSha) checked for symlinks, and only when the remote already knew the entry was a symlink. A local-only symlinked folder not yet pushed hit adapter.read() on a directory and crashed, leaving its status stuck. Fixed by extracting readStringPathContent() with a catch-and-fallback to readLocalSymlinkTarget().
    • Added 4 new tests (2 in tests/services/github-service.test.ts, 2 in tests/services/gitea-service.test.ts) covering the empty-sha throw and non-ASCII/space path encoding.
    • Evidence: npx eslint . → 0 errors; npm run build → clean; npx vitest run → 306/306 passed.
    • Committed as 896d77b, merged with the i18n branch's concurrent changes to the same files (45ea8fa-range merge commit), pushed to claude/fix-directory-symlink-pull-260713.
    • Not yet confirmed fixed: the user's last live test (before this push) still showed the old bare "N failed" text with a genuinely non-symlink file on GitHub — that was because the fix hadn't reached their test vault yet (everything was uncommitted). Now pushed; next step is the user rebuilding/reloading and re-testing to confirm root cause #1 (or find a third cause) with the new detailed error message.
    • Not yet done: comment on/reference issue #78 (in the blog repo) noting the fix landed in git-files-sync instead — flag to user before doing so since it crosses repos.

What's In Progress

  • Nothing else actively in progress.

What's Next

  1. Get user confirmation that delete now works (or a new detailed error message) after they rebuild/reload with the latest push.
  2. Issue #37 (Bitbucket provider support, feat-010) — large, was deferred until #38 (i18n) landed. Now unblocked.
  3. Re-sync against gh issue list --repo firstsun-dev/git-files-sync --state open. Remaining genuinely-unstarted issues as of this session: #47 (regex ignore lists), #45 (SonarQube findings), #37 (Bitbucket), #28 (non-engineering: community visibility).
  4. PR #51 is large (7+ issues' worth of changes now). If the user wants to review/merge it before more work piles on, flag this rather than continuing to add commits indefinitely.

Blockers / Risks

  • None currently.

Decisions Made

  • All work goes into one PR (#51): user explicitly said "不要那麼多pr merge" (don't want so many PRs). Any further issue work should commit directly onto claude/fix-directory-symlink-pull-260713, not a new branch.
  • feat-009 scope (i18n): settings.ts + all Notice() messages, done in one pass rather than split into infra-first/settings-only phases.
  • Flat key-value i18n dict, not nested namespaces: matches this plugin's small scale; simpler t(key, vars) lookup, no external i18n library dependency.
  • Locale detection via window.moment.locale(): per issue #38's suggested approach; unresolvable/unsupported locales fall back to English. A bare zh locale code maps to zh-tw, the only Chinese variant shipped.
  • Diff-format markers, changelog release-note text, and proper nouns (GitHub/GitLab/Gitea) were left untranslated — out of scope for UI-chrome i18n.
  • src/changelog.ts is hand-curated, separate from the auto-generated CHANGELOG.md: semantic-release already maintains CHANGELOG.md from Conventional Commit messages, but it's commit-log-level detail; the what's-new modal needs a small, hand-written, user-facing "highlights" list instead.
  • Fixed two duplication regressions mid-session (SonarCloud gate is 3% on new code, learned the hard way on PR #49 earlier): deduped TextComponent/TextAreaComponent test mocks, and deduped the GitHub/Gitea getBlob() bodies into a shared fetchGitHubStyleBlob() base helper.

Files Modified This Session

  • Issue #78 fix: src/services/github-service.ts, src/services/gitea-service.ts, src/ui/SyncStatusView.ts, src/i18n/locales/en.ts, src/i18n/locales/zh-tw.ts, tests/services/github-service.test.ts, tests/services/gitea-service.test.ts.
  • Root path picker fix: src/ui/RemoteFolderSuggest.ts (new), src/settings.ts.
  • feat-009 (i18n, prior parallel session): src/i18n/index.ts, src/i18n/locales/en.ts, src/i18n/locales/zh-tw.ts, tests/i18n/index.test.ts (all new); src/settings.ts, src/main.ts, src/ui/SyncStatusView.ts, src/ui/SyncConflictModal.ts, src/ui/WhatsNewModal.ts, src/ui/ConfirmModal.ts, src/ui/components/ActionBar.ts, FileListItem.ts, DiffPanel.ts (modified).
  • See archive/2026-07.md entries feat-003/005/006/007/008 for earlier features' file lists.

Evidence of Completion

  • Tests pass: npx vitest run → 306/306 passed (post-merge, this session)
  • Type check clean: npm run build (tsc + Obsidian 1.11.0 compat typecheck + esbuild) → clean
  • Lint clean: npx eslint . → 0 errors
  • Manual verification in Obsidian: in progress — user is re-testing the delete fix live; not yet confirmed resolved.

Notes for Next Session

  • Working branch for all further commits: claude/fix-directory-symlink-pull-260713 (PR #51). Do not open a new branch/PR for the next issue unless the user says otherwise.
  • feature_list.json's backlog is a snapshot from this session — re-check gh issue list before trusting it.
  • If the user reports delete still failing after this push, get the exact new error message (should no longer be a bare "N failed") to find the next root cause.