drawer-so
v0.18.1
Published
Drawer CLI — publish files and directories to drawer.so from the terminal.
Downloads
24
Maintainers
Readme
drawer-so
Publish files and directories to Drawer from the terminal.
The CLI targets https://drawer.so by default; override with DRAWER_BASE_URL.
Install
npm install -g drawer-so
# verify
drawer --helpQuick start
# one-time: paste your drawer API key (drw_…)
drawer auth login
# create a new artifact from a single file (defaults to private)
drawer create ./report.html --title "Q3 report"
# create from a directory (zipped + uploaded as a multi-file artifact)
drawer create ./site --title "demo site"
# update an existing artifact in place (cannot change visibility — use publish)
drawer update art_abc1234567 ./report.html
# patch — surgical find/replace
drawer patch art_abc1234567 --find "Q3" --replace "Q4"
# flip visibility — public requires a y/N prompt (or --yes)
drawer publish art_abc1234567 --visibility unlisted
drawer publish art_abc1234567 --public --yes
# make private again
drawer unpublish art_abc1234567
# list / open
drawer list
drawer open art_abc1234567Config
API key + base URL are stored in ~/.config/drawer/cli-config.json (chmod 600).
Override per-invocation with env vars:
DRAWER_API_KEY— override the saved keyDRAWER_BASE_URL— override the base URL (defaulthttps://drawer.so)
Commands
drawer auth login Paste an API key and save it
drawer auth logout Delete saved key
drawer auth whoami Show stored key prefix + base URL
drawer create <file|dir> Create a new artifact (defaults to private)
--title <text> Title shown in the browser tab
--visibility <tier> private (default) | unlisted | public
--private / --unlisted / --public Shorthand visibility flags
--password <text> Gate the artifact (unlisted/public only)
--tag <name> Apply a tag (repeatable)
--tags <a,b,c> Comma-separated tags
drawer update <artifact_id> <file|dir> Push a new version (no visibility change)
--title <text> Update the title
--tag / --tags Replace the tag set
--expected-version <vid> / --force Optimistic concurrency (same as patch/revert)
drawer publish <artifact_id> Flip visibility of an existing artifact
--visibility <tier> private | unlisted | public
--private / --unlisted / --public Shorthand visibility flags
--password <text> Set or rotate the password
--clear-password Remove the password modifier
--yes / -y Skip the public-visibility y/N prompt
drawer unpublish <artifact_id> Alias for `publish <id> --private`
drawer list List your artifacts
--tag <name> Filter by tag
--favorited Only starred artifacts
drawer get <artifact_id> Print artifact metadata as JSON
--include-content Include current file contents (MCP get_artifact)
--version <version_id> Inspect a historical version
drawer read <artifact_id> <path> Read one file from an artifact
--lines <start:end> 1-indexed inclusive line range
--offset <n> --limit <n> 0-indexed MCP-style window (offset + count)
--version <version_id> Read a historical version
drawer grep <artifact_id> <pattern> Search for a pattern across files
--files / --path <a,b,c> Limit search to these paths
--max-results <n> Cap matches returned (default 50, max 200)
--case-sensitive Case-sensitive matching (default off)
drawer open <artifact_id> Open the artifact URL in your default browser
drawer delete <artifact_id> [--yes] Permanently delete (asks first)
drawer patch <artifact_id> Find/replace surgical edits — single or batch
--file <path> Defaults to the artifact's entry file
--find <text> --replace <text> Single-edit form (mutually exclusive with --edit/--edits)
--replace-all Replace every occurrence (single-edit form only)
--edit "path:old:new" Batch edit (repeatable; first `:` splits path, LAST splits new)
--edits <file.json> Batch edits from a JSON array
--expected-version <vid> Fail-fast version pinning (optimistic concurrency)
--force Skip the implicit drift check
drawer regex <id> <pattern> <replacement> Regex-based find/replace on one file
--path <path> Defaults to the entry file
--flags <imsu> Regex flags (g/y forbidden)
--replace-all Replace every match (default: require exactly one)
--preview Dry-run, don't write
--expected-version <vid> / --force Same as patch
drawer revert <artifact_id> [--to <ver>] Promote a prior version back to current
--expected-version <vid> / --force Same as patch
drawer diff <artifact_id> <from> [to] Unified diff between versions
drawer files add <id> <files...> Add files to an existing artifact (new version)
--mode error|overwrite Collision behavior (default: error)
--path <slot> Targeted slot (single-file only; overrides source name)
--expected-version <vid> / --force Optimistic concurrency
drawer files rename <id> <from> <to> Rename a file within an artifact
drawer files rm <id> <path> Delete a file from an artifact
drawer upload-request <id> Mint a back-channel upload URL and await the drop
--paths <p1,p2,...> Slot paths the upload page should render
--mode error|overwrite Collision behavior
--note <text> Note shown to the user above the form
--timeout <secs> Total wait budget (default 300)
--no-await Just mint the URL; don't block
drawer comments list <id> List comments on an artifact
--status active|resolved|all Filter (default: active)
drawer comments post <id> <body...> Post a comment (flagged via=agent)
--force Skip the implicit drift check
drawer comments enable <id> Enable comments on an artifact you own
drawer comments disable <id> Disable comments on an artifact you own
drawer duplicate <id> Duplicate an artifact (templates v1)
--title <text> Title for the new artifactNotes
- Uploads use the unified
/api/artifacts/uploadendpoint, which dispatches byContent-Type(single file vs. zip archive). - Directories are bundled into a zip in-memory and uploaded;
node_modulesand.gitare skipped by default. - Uploads cap at 100 MB raw / 200 MB extracted.
- All commands honor per-API-key rate limits (60 mutating requests/min, 1000/hour).
Tests
Light vitest smoke suite covering CLI-unique behavior (flag parsing, command dispatch, error rendering — HTTP layer is mocked, no live server).
cd cli && npm test # run the cli suite directlyThe root repo's npm test runs both the root vitest suite and the CLI suite.
For maintainers — publishing
One-liner to publish a release from a clean checkout:
git pull && cd cli && npm install && npm run build && npm publish --access publicnpm loginis a one-time setup on the publishing machine.- Bumping versions:
npm version patch && git push --follow-tags && npm publish --access public(useminorormajoras appropriate). TheprepublishOnlyscript re-runs the build. - See PUBLISHING.md for the full pre-flight checklist.
