feat: Add RClone Queue widget + code-review fixes - #523
Open
elhoim wants to merge 13 commits into
Open
Conversation
Covers data source (log-tailing since --rc isn't enabled), widget behavior, caching strategy, and registration/testing plan.
Discard a partial first line in the 64KB read window instead of leaving the edge case unspecified.
4 tasks: data layer (log tail + cache), widget class, remote-name editor, registration. TDD throughout, using bun test (not bunx vitest, which fails to load this repo's vitest.config.ts in this environment).
The previous test implementation batched all backspace writes into a single call using '\b'.repeat(7), causing Ink to coalesce them into one 'data' event that contained control characters. This was not recognized as individual key.backspace events, so the backspaces were ignored. Fixed by writing each backspace separately with an await/flush between each write, mirroring how a real keystroke stream arrives. This ensures each backspace is received as a separate key.backspace event by Ink's useInput hook. Fixes: - "saves the typed remote name on Enter" test now actually deletes the pre-filled text and correctly saves "gdrive" instead of "dropboxgdrive" - "falls back to the default remote name when saved empty" test now exercises the empty-string fallback logic instead of passing vacuously All 35 tests now pass (previously 34 pass / 1 fail). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…er fill fs.readSync can return fewer bytes than requested (e.g. the log file shrinks between fstatSync and readSync during a logrotate copytruncate). readLogTail ignored the return value and always stringified the full pre-allocated buffer, silently mixing stale zero-fill bytes into the most recent (tail) portion of the parsed log text. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…oss statusline invocations ccstatusline's piped mode runs as a fresh process per statusline refresh, so the in-process Map cache was always empty on every invocation and never actually avoided the 64KB tail-read + regex re-parse it was meant to save, contrary to the design's stated intent. Mirror src/utils/git.ts's pattern: pair the in-process cache with a persistent JSON cache under ~/.cache/ccstatusline/, same 15s TTL, so a fresh process can reuse a still-fresh reading instead of re-parsing the log. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…teName is blank getRemoteName used ?? so it only fell back to DEFAULT_REMOTE_NAME for null/undefined metadata, not for an empty or whitespace-only string (a value the metadata schema happily accepts). That diverged from the editor's own save-time fallback, so a blank remoteName reaching metadata through any other path (manual settings edit, future import/migration) resolved to a log path that could never exist. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ide the rclone cache dir The remote-name editor only blocked control characters, so a remoteName containing "../" segments made getRcloneLogPath resolve outside ~/.cache/rclone/, letting the widget tail-read and display digits from arbitrary *.log files reachable by relative traversal. path.basename strips any directory separators before the path is joined, so the result can never escape the intended cache directory. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ote-name editor RCloneRemoteEditor indexed the remote-name string with plain UTF-16 code units (text[i], slice(pos-1)), unlike CustomText.tsx's editor for the same interaction. A character outside the BMP (e.g. an emoji) could split a surrogate pair on backspace/delete, corrupt the cursor highlight, and leave an unpaired surrogate saved into metadata.remoteName. Reuse the same Intl.Segmenter-based grapheme-index helpers CustomText.tsx already uses. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
elhoim
force-pushed
the
worktree-rclone-dropbox-queue-counter
branch
from
August 2, 2026 22:09
5f63e54 to
06d0c7e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
RCloneQueueWidget: a status-line widget that tails the rclone VFS log (default remotedropbox) and surfaces the pending-upload queue length (RClone: <N>/n/a), with an in-TUI remote-name editor./code-review highpass on this branch (one commit each):readLogTailnow uses the actualbytesReadfromfs.readSyncinstead of assuming the buffer was fully populated (avoids mixing stale/zero bytes into the tail read on a logrotate race).~/.cache/ccstatusline/rclone-queue-cache.json, mirroringsrc/utils/git.ts's pattern) so the 15s cache actually helps — ccstatusline's piped mode runs as a fresh process per refresh, so the in-process-only cache never survived across invocations.getRemoteNamenow falls back to the default remote for a blank/whitespace-onlymetadata.remoteName, matching the editor's own save-time fallback.getRcloneLogPathnow sanitizesremoteNameviapath.basename, preventing directory-traversal segments from escaping~/.cache/rclone/.Intl.Segmenterhelpers asCustomText.tsx), so a multi-code-unit character (e.g. an emoji) can't split a surrogate pair on backspace/delete.Test plan
bun test src/widgets/__tests__/RCloneQueue.test.tsx— 43/43 passbun test(full suite) — all failures are pre-existing, unrelated Ink-input-timing flakiness (timezone-editor,PowerlineThemeSelector,TerminalWidthMenu,usage-fetch), confirmed non-deterministic across repeated runs and untouched by this diffbun run lint— clean🤖 Generated with Claude Code