feat(cards): move and copy cards to other projects

RO
4h ago
+2001-70

Why

On the web, a card's Move… and Copy… menus send it to a card table in any project. The CLI could only cross projects through a wormhole someone had already set up. It couldn't copy a card, and after a wormhole move it never said where the card landed. CLI users miss all three.

What changed

  • cards move <card> --to-project <project> (or --to-card-table) moves the card to that project's card table. cards copy <card> copies it onto its own table or, with --to-project, another project's, and --include-comments brings the comments. Both wait for Basecamp to finish and print the new card. As on the web, the card lands in Triage, or in Done if it's completed.
  • --to-wormhole now prints the card that landed, and --to with another project's column points to --to-project.
  • cards show, cards steps and todos show follow a moved card or to-do from its old id to its new one.

Scope

  • Uses basecamp-sdk v0.30.0, the release of basecamp/basecamp-sdk#1053. v0.30.0 also adds the SDK's project-logo operations. The built-in MCP server serves remove_project_logo and skips the upload, as it skips the other uploads. CLI logo commands come in a separate PR stacked on this one.
  • The bump also adds move_recording, copy_recording and get_filing to the built-in MCP server's catalog.

Tradeoffs

A copy is never retried. A copy that fails to start with a 5xx, or that's still running when the wait ends, says "don't copy again" and is not marked retryable, because Basecamp may already be making it.

Verification

  • bin/ci passes.
  • A local bc3 harness ran each web card path through the CLI: columns, On hold, Done, another table, wormhole, move to a project, and copy to a project and to its own table. Every path works, and a column from another project still fails. By hand, --include-comments carried a comment and a completed card landed in Done.
  • An independent GPT-6.1-sol review converged after 4 rounds. Each finding it raised has a test that fails without the fix.

Summary by cubic

Adds cross-project card moves and copies to the CLI, matching the web's Move… and Copy… menus.

  • cards move <card> --to-project <project> (or --to-card-table) files the card into that project's card table; it lands in Triage, or Done if completed, under a new id, with a bounded backoff wait on Basecamp's background move.
  • New cards copy <card> copies onto its own table or, with --to-project, another project's; --include-comments carries the comments. A copy that fails is never retried unless Basecamp answered 4xx, because a 5xx, dropped connection, or wait time-out may already have started it; rate limits stay retryable.
  • --to-wormhole now prints where the card landed, and cards show, cards steps, and todos show follow a moved record from its old id to its new one; --to a foreign column suggests --to-project.
  • Source cards, card URLs, and destination card tables must belong to the session account on a trusted host, an explicit --in/--project must match the card's own project, and a destination table URL whose project disagrees with --to-project is refused. A record that reads back as any type other than a card is refused.

Scope
Bumps basecamp-sdk to v0.30.0, the release of the move, copy, and filing operations. It also brings project logos: the built-in MCP server serves remove_project_logo and skips the multipart upload.