Skip to content

GUI parity audit, live transfer view, and --json as a contract #7

Description

@kud
branch: main

Problem

The CLI covers what it grew to cover — files, trash, rewind, shares, links, sync inspection — but nobody has ever compared it against what pCloud's own clients can do. So the gaps are unknown rather than chosen, and --json is applied by habit rather than by contract.

Three strands, related enough to plan together and ship separately.

1 · GUI parity audit

Inventory what the desktop client and web app expose, mark each as covered / missing / deliberately excluded, and let that table decide the roadmap rather than whatever comes to mind next.

Known gaps already identified:

  • pcloud transfers — what is uploading or downloading right now. The daemon's queue is already in data.db: task carries name and inprogress, alongside fstask, fstaskupload, localfileupload, upload_tasks, uptask_fileupload. pcloud sync surfaces only a per-pair count today.
  • pcloud crypto status — whether Crypto is currently unlocked and mounted. Read-only, touching no key material, respecting the existing table allowlist.
  • Account/usage — quota, plan, region.
  • File versions and restore beyond the current rewind surface.
  • Shared-link management parity — expiry edits, download counts.

Deliberately excluded, with reasons

These are not gaps and should be recorded as closed so nobody reopens them:

2 · Live transfer view

What is moving right now — observing the daemon's activity, not performing transfers. pcloud sync shows a per-pair queue count and nothing else, so "is it still uploading, and what?" currently has no answer outside the GUI.

  • pcloud transfers — a snapshot: file name, direction, which pair, in-progress or queued.
  • pcloud transfers --watch — a live display, refreshing as the daemon works. Ink is already a dependency and pcloud browse establishes the TUI pattern.
  • Source tables: task (name, inprogress, syncid), fstask, fstaskupload, localfileupload, upload_tasks, uptask_fileupload. Which of these the daemon actually drives during a transfer is unverified — establish that first with a large file and a poll loop.

The obstacle worth solving before designing the UI

snapshot() copies the whole database to read it, because pCloud Drive holds an exclusive WAL lock while running. That is fine at ~120 MB for a one-shot command and unworkable for a display refreshing every second.

Options, cheapest first:

  • Open read-only with SQLite's immutable=1 or mode=ro&nolock=1 and accept a possibly-torn read — acceptable for a progress display, unacceptable for the health checks in sync.
  • Copy once, then re-read only the -wal file on each tick.
  • Poll slowly (2–5s) and copy each time. Simplest, and possibly good enough — measure before rejecting it.

Whichever is chosen must not weaken readPairs(), which needs a consistent snapshot. A live view can tolerate a stale or torn frame; a health check cannot.

Account stats — separate and lower value

pcloud stats (quota, plan, file counts, largest folders) is a different feature that happens to share a word. Worth having, not what this section is about, and it comes from the API rather than the local database.

3 · --json everywhere, as a contract rather than a habit

Currently applied to every data-returning command plus upload/download. Remaining work:

  • Audit every command for the flag; the rule is that any command may be passed --json without the caller first checking a list.
  • Cover mutations too — mkdir, rmdir, move-file, rename-file, delete-file, share and link mutations — emitting their result object.
  • A test that enumerates the command tree and asserts the flag exists, so a new command cannot ship without it. This is the part that makes it a contract; documentation alone will drift.
  • State the contract once in docs/index.mdx and stop repeating it per command.

Decisions

  • --json is registered per command, never globally. enablePositionalOptions() binds an option to the subcommand it follows, so a program-level flag would only parse as pcloud --json ls — the wrong end of the line. The jsonOption() helper plus emit() keeps it one-line per command.
  • Bare single values stay bare by default. get-link, zip and the publink commands print a URL so it pipes without jq; --json wraps it only when asked.
  • Local-database features stay read-only. sync and settings established that boundary and pcloud sync add — create a folder and its sync pair in one command #5 demonstrated the cost of crossing it.

Next steps

  1. Build the parity table first — it is the artefact that makes the rest schedulable, and it is cheap.
  2. Ship the --json completeness test before adding commands, so new surface inherits the contract automatically.
  3. Then take the gaps in whatever order is actually useful, transfers first on current evidence.

Metadata

Metadata

Assignees

Labels

planScoped work ready to be picked up by a fresh session

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions