cursor-keys 1.2.3 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -91,23 +91,24 @@ Settings flow one way, main to profiles: `sync` re-copies your main `settings.js
91
91
 
92
92
  ## Commands
93
93
 
94
- | Command | What it does |
95
- | ---------------------------------------------- | ------------------------------------------------------------ |
96
- | `init [--root DIR] [--all]` | Discover git repos and register them |
97
- | `add <name> [--path] [--color] [--clone main]` | Create a project profile |
98
- | `clone <name> [--from main]` | Copy sign-in + settings + model config from a donor profile |
99
- | `set-key <name> [--key sk-...]` | Inject the project API key (encrypted, verified) |
100
- | `open [name]` | Launch Cursor with the profile (auto-detect from cwd) |
101
- | `status` | Projects, colors, running windows, key configured |
102
- | `current` | Mapping for the current directory |
103
- | `config [get <key> · baseUrl [URL]]` | Show summary, print one value, or set the gateway base URL |
104
- | `sync [name]` | Re-copy main Cursor settings into profiles |
105
- | `doctor [name]` | Health checks: key row, base URL, subagent overrides |
106
- | `wrap [--install]` | zsh function so plain `cursor <path>` auto-picks the profile |
94
+ | Command | What it does |
95
+ | ---------------------------------------------- | --------------------------------------------------------------- |
96
+ | `init [--root DIR] [--all]` | Discover git repos and register them |
97
+ | `add <name> [--path] [--color] [--clone main]` | Create a project profile |
98
+ | `clone <name> [--from main]` | Copy sign-in + settings + model config from a donor profile |
99
+ | `set-key <name> [--key sk-...]` | Inject the project API key (encrypted, verified) |
100
+ | `color <name> [#hex]` | Show or set the project title bar color |
101
+ | `open [name]` | Launch Cursor with the profile (auto-detect from cwd) |
102
+ | `status` | Projects, colors, running windows, key configured |
103
+ | `current` | Mapping for the current directory |
104
+ | `config [get <key> · baseUrl [URL]]` | Show summary, print one value, or set the gateway base URL |
105
+ | `sync [name]` | Re-copy main Cursor settings into profiles |
106
+ | `doctor [name]` | Health checks: key row, base URL, subagent overrides |
107
+ | `wrap [--install]` | zsh function so plain `cursor <path>` auto-picks the profile |
107
108
  | `aliases [--install]` | Per-project shell aliases (also `ck` shortcut + tab completion) |
108
- | `completion` | Print zsh tab completion (auto-sourced by `aliases --install`) |
109
- | `install-extension` | Link the Cursor extension (auto-linked on global npm install) |
110
- | `rm <name> [--delete]` | Unregister (optionally delete the profile) |
109
+ | `completion` | Print zsh tab completion (auto-sourced by `aliases --install`) |
110
+ | `install-extension` | Link the Cursor extension (auto-linked on global npm install) |
111
+ | `rm <name> [--delete]` | Unregister (optionally delete the profile) |
111
112
 
112
113
  `cursor-keys ls` prints registered project names one per line for scripts and tab completion; it is hidden from `--help`.
113
114
 
@@ -27,6 +27,9 @@ function printHelp() {
27
27
  console.log(
28
28
  " set-key <name> Inject the project API key (encrypted)",
29
29
  );
30
+ console.log(
31
+ " color <name> [#hex] Show or set the project title bar color",
32
+ );
30
33
  console.log(
31
34
  " open [name] Open Cursor with this project's profile",
32
35
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cursor-keys",
3
- "version": "1.2.3",
3
+ "version": "1.2.4",
4
4
  "description": "Per-project Cursor profiles so each window uses the correct BYOK API key. Zero dependencies.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/commands.mjs CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  findProjectByPath,
14
14
  getConfigValue,
15
15
  getProject,
16
+ isHexColor,
16
17
  loadConfig,
17
18
  pickColorForName,
18
19
  pickUnusedColor,
@@ -89,6 +90,8 @@ export async function runCommand(argv) {
89
90
  return cmdInstallExtension(rest);
90
91
  case "set-key":
91
92
  return cmdSetKey(rest);
93
+ case "color":
94
+ return cmdColor(rest);
92
95
  case "clone":
93
96
  return cmdClone(rest);
94
97
  case "rm":
@@ -637,7 +640,7 @@ function shellEscapeName(name) {
637
640
  }
638
641
 
639
642
  const COMPLETION_COMMANDS =
640
- "init add clone set-key open status current config sync doctor aliases wrap install-extension completion ls rm";
643
+ "init add clone set-key color open status current config sync doctor aliases wrap install-extension completion ls rm";
641
644
 
642
645
  /**
643
646
  * Pure builder for the zsh completion script. Sourced via
@@ -648,7 +651,7 @@ export function completionScript() {
648
651
  return `#compdef cursor-keys ckeys ck
649
652
  _cursor_keys() {
650
653
  local -a projects
651
- if (( CURRENT == 3 )) && [[ \${words[2]} == (open|clone|set-key|doctor|sync|rm) ]]; then
654
+ if (( CURRENT == 3 )) && [[ \${words[2]} == (open|clone|set-key|color|doctor|sync|rm) ]]; then
652
655
  projects=(\${(f)"$(cursor-keys ls 2>/dev/null)"})
653
656
  _describe 'project' projects
654
657
  else
@@ -843,6 +846,39 @@ async function cmdInstallExtension() {
843
846
  console.log(`Look for ${bold}$(key) <project>${reset} in the status bar.`);
844
847
  }
845
848
 
849
+ async function cmdColor(args) {
850
+ const { flags, positional } = parseFlags(args);
851
+ if (flags.help) {
852
+ console.log("Usage: cursor-keys color <name> [#RRGGBB]");
853
+ console.log("Show or set the project's title bar color.");
854
+ return;
855
+ }
856
+ const name = positional[0];
857
+ if (!name) throw new Error("Usage: cursor-keys color <name> [#RRGGBB]");
858
+ const config = loadConfig();
859
+ const project = getProject(config, name);
860
+ if (!project) throw new Error(`Unknown project: ${name}. Run cursor-keys init or add.`);
861
+
862
+ const hex = positional[1];
863
+ if (!hex) {
864
+ console.log(`${blockSwatch(project.color)} ${project.color}`);
865
+ return;
866
+ }
867
+ if (!isHexColor(hex)) {
868
+ throw new Error(`Invalid color: ${hex} (expected #RRGGBB, e.g. #852e00)`);
869
+ }
870
+
871
+ updateConfig((c) => {
872
+ if (!c.projects[name]) throw new Error(`Unknown project: ${name}`);
873
+ c.projects[name].color = hex;
874
+ });
875
+ if (fs.existsSync(project.profileDir)) {
876
+ writeProfileSettings(project.profileDir, name, hex);
877
+ }
878
+ console.log(ok(`Color for ${name}: `) + `${blockSwatch(hex)} ${hex}`);
879
+ console.log(`${dim}Open Cursor windows reload settings automatically.${reset}`);
880
+ }
881
+
846
882
  function promptHidden(question) {
847
883
  return new Promise((resolve) => {
848
884
  const rl = readline.createInterface({
package/src/config.mjs CHANGED
@@ -24,6 +24,11 @@ export const DEFAULT_PROFILES_ROOT = path.join(
24
24
 
25
25
  const HEX_COLOR = /^#[0-9a-fA-F]{6}$/;
26
26
 
27
+ /** @param {unknown} s */
28
+ export function isHexColor(s) {
29
+ return typeof s === "string" && HEX_COLOR.test(s);
30
+ }
31
+
27
32
  /** @param {string} p */
28
33
  export function expandHome(p) {
29
34
  if (!p || typeof p !== "string") return p;