{"id":51569323,"url":"https://github.com/refinist/ccstatusline-apply","last_synced_at":"2026-07-10T18:01:59.313Z","repository":{"id":369102327,"uuid":"1287977490","full_name":"refinist/ccstatusline-apply","owner":"refinist","description":"Apply a ccstatusline-editor config to ~/.config/ccstatusline/settings.json, with an automatic backup of the old file.      把 ccstatusline-editor 生成的配置写入 ~/.config/ccstatusline/settings.json，并自动备份旧文件。","archived":false,"fork":false,"pushed_at":"2026-07-03T15:01:29.000Z","size":79,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-03T17:05:34.900Z","etag":null,"topics":["ccsa","ccstatusline","claude-code","cli","statusline"],"latest_commit_sha":null,"homepage":"https://npmjs.com/@refinist/ccsa","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/refinist.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-07-03T07:00:05.000Z","updated_at":"2026-07-03T15:02:59.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/refinist/ccstatusline-apply","commit_stats":null,"previous_names":["refinist/ccstatusline-apply"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/refinist/ccstatusline-apply","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/refinist%2Fccstatusline-apply","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/refinist%2Fccstatusline-apply/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/refinist%2Fccstatusline-apply/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/refinist%2Fccstatusline-apply/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/refinist","download_url":"https://codeload.github.com/refinist/ccstatusline-apply/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/refinist%2Fccstatusline-apply/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35338653,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-10T02:00:06.465Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ccsa","ccstatusline","claude-code","cli","statusline"],"created_at":"2026-07-10T18:01:58.186Z","updated_at":"2026-07-10T18:01:59.307Z","avatar_url":"https://github.com/refinist.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"logo.png\" alt=\"ccsa logo\" width=\"300\" /\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003e@refinist/ccsa\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eEnglish\u003c/strong\u003e | \u003ca href=\"README.zh-CN.md\"\u003e简体中文\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  Apply a \u003ca href=\"https://github.com/refinist/ccstatusline-editor\"\u003eccstatusline-editor\u003c/a\u003e config to\n  \u003ccode\u003e~/.config/ccstatusline/settings.json\u003c/code\u003e, with an automatic backup of the old file.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://ccse.refineup.com\"\u003e\u003cstrong\u003eBuild a config in the editor →\u003c/strong\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Usage\n\n```sh\n# Paste the JSON the editor gives you (single-quoted, one line) — `apply` is\n# the default command, so it can be omitted:\nnpx -y @refinist/ccsa@latest '{\"version\":3,\"lines\":[[]]}'\n\n# …or point it at a downloaded config file:\nnpx -y @refinist/ccsa@latest -f ./ccstatusline-settings.json\n\n# …or pipe JSON in:\ncat ccstatusline-settings.json | npx -y @refinist/ccsa@latest --stdin\n\n# See the current config and every backup:\nnpx -y @refinist/ccsa@latest list\n\n# Undo — roll back to the most recent backup:\nnpx -y @refinist/ccsa@latest restore\n\n# Pull your current config back out (auto-copies to your clipboard), to keep\n# adjusting it in the editor:\nnpx -y @refinist/ccsa@latest export\n\n# Delete every backup ccsa has made for this config:\nnpx -y @refinist/ccsa@latest clean\n\n# Rotate between multiple themes automatically (bundle built in the editor):\nnpx -y @refinist/ccsa@latest rotate on -f ./ccsa-rotation.json\n\n# …check what's rotating, or turn it off and get your previous config back:\nnpx -y @refinist/ccsa@latest rotate status\nnpx -y @refinist/ccsa@latest rotate off\n```\n\n## What it does\n\nApply a [ccstatusline](https://github.com/sirmalloc/ccstatusline) config produced by\n[**ccstatusline-editor**](https://github.com/refinist/ccstatusline-editor) straight to your\nlocal `~/.config/ccstatusline/settings.json` — with an automatic, timestamped backup of the\nprevious file.\n\nThe editor runs in the browser, which can't write to disk. This tiny CLI is the bridge:\ncopy one command from the editor, run it, done. The next status line refresh picks it up —\nno restart, no wrapper script, no editing `~/.claude/settings.json`.\n\n1. Parses and sanity-checks the config (must be a JSON object with `version` + `lines`).\n2. Locates `~/.config/ccstatusline/settings.json` (creating the folder if needed).\n3. Copies the current file to a timestamped `~/.config/ccsa/settings.\u003cYYYY-MM-DD_HH-MM-SS\u003e.json`\n   backup — a directory of its own, separate from ccstatusline's config dir, so an upstream\n   ccstatusline upgrade never touches your backup history.\n4. **Preserves** keys ccstatusline manages itself — notably `installation` — so applying a new\n   config never drops the tool's own bookkeeping. Everything the editor manages is replaced.\n5. Writes the new file atomically (temp file + rename), **preserving the file's permission bits**.\n\nEach apply keeps its own backup — they're never overwritten, so you can always go back.\n`restore` rolls the settings file back to the **newest** backup, saving the current file\nfirst, so the rollback is itself undoable — which means each `restore` adds one more backup\nof its own rather than just toggling between two files; the pool only shrinks if you run\n`clean`.\n\n`export` reads the current settings file back out and prints it verbatim (not\nreformatted) to stdout — the other direction of the bridge, for when you want to keep\nadjusting an already-applied config in the editor. Run in a terminal, it also tries to\ncopy the JSON straight to your clipboard (`pbcopy` / `clip` / `wl-copy` / `xclip` / `xsel`,\nwhichever the platform has); piped or redirected (`export | pbcopy`, `export \u003e out.json`),\nonly stdout carries the JSON so it composes like any other Unix command.\n\n`clean` deletes every backup in the pool for this config — irreversible, and `restore` has\nnothing left afterward. The live `settings.json` itself is never touched.\n\nExtra safety:\n\n- If the config is a **symlink** (dotfiles managed by stow/chezmoi), it's written _through_ the\n  link — the link is kept and its real target is updated, not replaced by a regular file.\n- If the existing file is corrupt, it's still backed up but not merged from.\n- stdin is opt-in: it's only read with `--stdin` (never auto-detected).\n\n## Theme rotation\n\n`rotate` cycles your status line through a pool of themes automatically — a different\none every hour, day, or week. You build the pool in the editor, which exports a single\n**rotation bundle**; one command turns the whole thing on, one turns it off:\n\n```sh\nnpx -y @refinist/ccsa@latest rotate on -f ./ccsa-rotation.json   # or a positional \u003cjson|base64\u003e, or --stdin\nnpx -y @refinist/ccsa@latest rotate off\n```\n\nA bundle looks like this — `themes` holds full ccstatusline configs, in order:\n\n```json\n{\n  \"version\": 1,\n  \"period\": \"day\",\n  \"strategy\": \"cycle\",\n  \"themes\": [\n    { \"name\": \"ocean\", \"config\": { \"version\": 3, \"lines\": [...] } },\n    { \"name\": \"sunset\", \"config\": { \"version\": 3, \"lines\": [...] } }\n  ]\n}\n```\n\n- **`version`** — the bundle's own format version (same field name and idea as\n  a ccstatusline config's `version` — each theme's nested `config.version` is\n  a separate number, one level down); currently always `1`. A bundle from a\n  newer format makes the CLI tell you to run the latest instead of guessing.\n- **`period`** — how often the theme advances, and how often the scheduled job fires:\n  - `\"hour\"`, `\"day\"` or `\"week\"` — calendar-aligned presets;\n  - `{ \"every\": 6, \"unit\": \"hour\" }` — any custom interval (`every` 1–100,\n    `unit` `\"minute\"`/`\"hour\"`/`\"day\"`). Custom intervals count\n    from the moment `rotate on` ran — that timestamp is stamped into\n    `rotation.json` as `anchor`, so the slot math stays a pure function of time.\n- **`strategy`** — which theme a moment in time maps to:\n  - `\"cycle\"` — walk the list one step per period, wrapping around;\n  - `\"random\"` — a deterministic pick per period (stable within the slot, varies across).\n\n  Both work with any theme count (up to 20 themes per bundle). A 7-theme daily\n  cycle gives you a repeating weekly wardrobe — one theme per day of the week.\n\n  All three are pure functions of the current time — no counter is stored — so missed,\n  late, or duplicate scheduler firings can never make the rotation drift.\n\n`rotate on` does everything in one shot: it validates the bundle, saves your current\nconfig as a **pre-rotation snapshot**, writes the state to `~/.config/ccsa/rotation.json`,\nregisters a user-level scheduled job that re-runs `ccsa rotate` every period, and applies\nthe current slot's theme immediately. Re-running `rotate on` with a new bundle updates\neverything but keeps the original snapshot. `rotate off` is the symmetric undo:\nunregister the job, restore the snapshot, delete the state.\n\nThe scheduled job — nothing to install, both schedulers ship with the OS:\n\n- **macOS**: a LaunchAgent at `~/Library/LaunchAgents/com.refineup.ccsa.rotate.plist`.\n  macOS 13+ shows a one-time \"background item added\" notification — informational,\n  nothing to approve. Firings missed while asleep run once on wake, and `RunAtLoad`\n  catches up at login.\n- **Windows**: a Task Scheduler task named `ccsa-rotate` — current user only, least\n  privilege, no UAC prompt, no stored password. It catches up after sleep\n  (`StartWhenAvailable`) and at logon.\n- **Other platforms**: not managed — `rotate on` still sets everything up and prints a\n  ready-made cron line to paste instead.\n\nThe job bakes in **absolute paths** to your node binary and to ccsa (launchd's minimal\n`PATH` never has fnm/nvm/homebrew installs). Symlinks are resolved first, so a\nper-shell path like fnm's `fnm_multishells/…` never ends up in the schedule — the job\npoints at the real file, which outlives the shell that ran `rotate on`. Running through\n`npx` needs no global install: the schedule can't point at the prunable npx cache, so\n`rotate on` first copies the (single-file, zero-dependency) CLI into\n`~/.config/ccsa/runtime/` and points the job there — a stable path nothing prunes.\n`rotate off` removes that copy again.\n\nBare `ccsa rotate` (what the scheduler runs) is idempotent: it computes the current\nslot's theme and exits without touching anything when that theme is already showing.\nRotation never writes to the backup pool at all — theme writes are machine-made and\nreproducible from `rotation.json`, and your human-made config is protected by the\nsnapshot (which `rotate off` restores from).\n\n## Commands\n\n| Command                | Description                                                        |\n| ---------------------- | ------------------------------------------------------------------ |\n| `apply \u003cjson\\|base64\u003e` | Apply a config (raw JSON or base64)                                |\n| `list`                 | Show the current config and every backup in the pool               |\n| `restore`              | Roll back to the newest `settings.\u003cdate\u003e.json` backup              |\n| `export`               | Print the current config to stdout (and copy it to the clipboard)  |\n| `clean`                | Delete every backup in the pool for this config                    |\n| `rotate on \u003cbundle\u003e`   | Turn on theme rotation (accepts `-f` / `--stdin` like `apply`)     |\n| `rotate off`           | Turn rotation off: unregister the job, restore the previous config |\n| `rotate status`        | Current theme, next switch, schedule registration                  |\n| `rotate`               | Apply the current slot's theme (what the scheduled job runs)       |\n\n`apply` is the default command, so the word itself may be omitted:\n`ccsa '\u003cjson\u003e'` does the same thing. A command word, if given, must come\nfirst: `ccsa restore`, not `ccsa --restore`.\n\n## Options\n\n| Option              | Description                                                               |\n| ------------------- | ------------------------------------------------------------------------- |\n| `-f, --file \u003cpath\u003e` | Read config from a JSON file (for `apply`)                                |\n| `--stdin`           | Read config from stdin (for `apply`)                                      |\n| `--no-backup`       | Skip the timestamped backup (for `apply` / `restore`)                     |\n| `--no-merge`        | Replace the whole file (drop `installation` \u0026 unknown keys) (for `apply`) |\n| `-h, --help`        | Show help                                                                 |\n| `-v, --version`     | Print version                                                             |\n\nThe positional argument is treated as raw JSON if it starts with `{`, otherwise as base64.\n\n## Config location\n\n`ccstatusline` reads a hardcoded `~/.config/ccstatusline/settings.json` on every platform —\nthere is no `XDG_CONFIG_HOME` or Windows `APPDATA` special-casing — so this tool always targets\nthat exact path (there's no `--config` override: a config written anywhere else is a file\nccstatusline would never read anyway). Backups live in their own `~/.config/ccsa/`\ndirectory (same `homedir()/.config/…` scheme, just a different folder), independent of\nccstatusline. To test against a throwaway path, override `$HOME` for the invocation (see\n\"Local development\" below).\n\n## Local development\n\nNo build or `npx` needed — Node 24 runs the TypeScript sources directly:\n\n```sh\nnode src/cli.ts --help                                              # run the CLI\nHOME=/tmp/ccsl-test node src/cli.ts '{\"version\":3,\"lines\":[[]]}'     # safe test, doesn't touch the real config\npnpm dev -- --help                                                  # same, with --watch\npnpm test                                                            # vitest on the .ts sources\npnpm build                                                           # tsc → dist/ (what gets published)\n```\n\nAlways override `$HOME` for manual testing so you never clobber your real\n`~/.config/ccstatusline/settings.json`.\n\n## License\n\n[MIT](./LICENSE)\n\nCopyright (c) 2026-present, [REFINIST](https://github.com/refinist)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frefinist%2Fccstatusline-apply","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frefinist%2Fccstatusline-apply","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frefinist%2Fccstatusline-apply/lists"}