Skip to content

feat(remote): Tailscale/SSH source for Claude usage logs (library only, wiring follow-up)#1015

Closed
Nicolas0315 wants to merge 1 commit into
ccusage:mainfrom
Nicolas0315:feat/remote-tailscale-ssh
Closed

feat(remote): Tailscale/SSH source for Claude usage logs (library only, wiring follow-up)#1015
Nicolas0315 wants to merge 1 commit into
ccusage:mainfrom
Nicolas0315:feat/remote-tailscale-ssh

Conversation

@Nicolas0315

@Nicolas0315 Nicolas0315 commented May 17, 2026

Copy link
Copy Markdown

Summary

Adds library-level support for fetching Claude usage logs from Tailscale-connected or SSH-reachable Unix-like hosts and aggregating them alongside local logs. CLI flags are defined but not yet wired into the report commands — that wiring is intended as a follow-up so this PR stays small and reviewable.

What's in this PR

  • New module apps/ccusage/src/remote/
    • types.tsRemoteHostSpec, RemoteOptions, MaterializedRemoteClaudeRoots.
    • ssh.ts — host whitelist validator, buildSSHFetchCommand (ssh -o BatchMode=yes -o ConnectTimeout=10 <host> 'tar -czf - -C "$HOME" .claude/projects'), and fetchClaudeProjectsViaSSH that pipes ssh stdout into tar -xz.
    • tailscale.tsparseTailscaleStatus for tailscale status --json, returns active macOS/linux/*bsd peers.
    • index.tsmaterializeRemoteClaudeRoots, withRemoteClaudeRoots (augments CLAUDE_CONFIG_DIR, restores on finally, cleans up tmp via async rm plus a process.once('exit', rmSync) fallback for process.exit(0) paths).
  • Shared CLI flags (apps/ccusage/src/shared-args.ts)
    • --remote-host <host[,host,...]>
    • --remote-tailscale
    • --remote-tmp <path>
  • In-source vitest for: parseHostSpec, buildSSHFetchCommand, parseTailscaleStatus, parseRemoteHostsArg, shouldUseRemote, withRemoteClaudeRoots passthrough.

Out of scope (deliberate)

  • Wiring withRemoteClaudeRoots into daily/weekly/monthly/session/blocks — this PR is library-only. CLI flags will surface as no-ops until wired.
  • Windows remote hosts (the fetch command embeds $HOME and assumes Unix-like remote shell).
  • Per-host row breakdown / --per-host output mode.
  • Docs site updates (per repo CLAUDE.md: "Do not proactively create documentation files unless explicitly requested").

Security notes

  • Only ~/.claude/projects is transferred. ~/.claude/.credentials.json and other sibling files are never read.
  • Host/user names pass a strict whitelist (^\w[\w.-]*$) to block ssh option spoofing (-oProxyCommand=...) and shell metacharacter escapes.
  • ssh -o BatchMode=yes disables interactive prompts; agent/key auth only.
  • All child processes use child_process.spawn with shell: false.
  • Tmp directories are created under os.tmpdir() with mkdtemp and removed on dispose (async) or interpreter exit (sync fallback).

Test plan

  • pnpm typecheck — green
  • pnpm run format — green
  • pnpm run test — new module 19 tests all pass; remaining 24 failures match main baseline on Windows (paths.ts test asserts POSIX root, cli.ts bun path test) and are not introduced by this PR.
  • Manual smoke once wiring lands (follow-up): ccusage daily --remote-host ca-20036826 --offline

Follow-ups

  1. Wire withRemoteClaudeRoots into report commands so the flags become end-user usable.
  2. Optional: --per-host for row-level breakdown using agent metadata.
  3. Optional: ccusage.config.json remoteHosts entry.

🤖 Generated with Claude Code


Summary by cubic

Adds library support to fetch Claude usage logs from SSH and Tailscale-reachable Unix-like hosts and merge them with local data. CLI flags are defined but not yet wired into report commands.

  • New Features
    • Fetches ~/.claude/projects over SSH from explicit hosts and from active Tailscale peers discovered via tailscale status --json.
    • Materializes remote data into a temp dir and augments CLAUDE_CONFIG_DIR so reports can aggregate remote and local logs.
    • Adds CLI flags: --remote-host, --remote-tailscale, --remote-tmp (no-op until follow-up wiring).
    • Safety: transfers only ~/.claude/projects, enforces strict host/user validation, uses ssh -o BatchMode=yes with shell: false, and cleans up temp dirs on exit.

Written for commit fdca3ea. Summary will update on new commits. Review in cubic

Library-level support for fetching ~/.claude/projects from Unix-like
remote hosts over SSH and aggregating their usage alongside local logs.

- apps/ccusage/src/remote/types.ts: shared types for host specs and
  materialized roots.
- apps/ccusage/src/remote/ssh.ts: host validation, BatchMode SSH fetch
  pipeline (ssh | tar -xz), and command builders. Whitelists host/user
  characters to block option spoofing and shell-metacharacter escapes.
- apps/ccusage/src/remote/tailscale.ts: parser for `tailscale status
  --json` that emits active Unix-like peers and skips offline ones.
- apps/ccusage/src/remote/index.ts: materialize roots into a temp
  directory, augment CLAUDE_CONFIG_DIR for the wrapped run, and clean
  up via async dispose plus a `process.once('exit')` sync fallback.
- apps/ccusage/src/shared-args.ts: define --remote-host,
  --remote-tailscale, and --remote-tmp on the shared CLI arg set.

Only ~/.claude/projects is fetched; credential files such as
.credentials.json are never transferred. Includes in-source vitest for
host parsing, SSH command building, Tailscale status parsing, and the
withRemoteClaudeRoots passthrough path.

Wiring these flags into the daily/weekly/monthly/session/blocks
commands is intentionally left for a follow-up commit.

🤖 Co-authored by Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fef519df-da75-45ba-8a2a-59ba2eca90fd

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown
Contributor

This PR was auto-closed. Only contributors approved with lgtm can open PRs. Open an issue first.

Maintainers review auto-closed issues and reopen worthwhile ones. Issues that do not meet the quality bar in CONTRIBUTING.md may not be reopened or receive a reply.

If a maintainer replies lgtmi, your future issues will stay open. If a maintainer replies lgtm, your future issues and PRs will stay open.

See CONTRIBUTING.md.

@github-actions github-actions Bot closed this May 17, 2026
@Nicolas0315 Nicolas0315 deleted the feat/remote-tailscale-ssh branch May 17, 2026 12:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant