claude-switch-profile 1.0.2 → 1.4.0
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/CHANGELOG.md +69 -0
- package/README.md +205 -55
- package/bin/csp.js +52 -3
- package/package.json +1 -1
- package/src/commands/create.js +76 -18
- package/src/commands/current.js +8 -3
- package/src/commands/deactivate.js +22 -0
- package/src/commands/delete.js +19 -7
- package/src/commands/diff.js +19 -9
- package/src/commands/export.js +30 -5
- package/src/commands/import.js +11 -2
- package/src/commands/init.js +10 -8
- package/src/commands/launch.js +216 -0
- package/src/commands/list.js +2 -1
- package/src/commands/save.js +11 -4
- package/src/commands/select.js +126 -0
- package/src/commands/status.js +48 -0
- package/src/commands/toggle.js +25 -0
- package/src/commands/uninstall.js +99 -0
- package/src/commands/use.js +67 -58
- package/src/constants.js +43 -16
- package/src/file-operations.js +80 -1
- package/src/item-manager.js +155 -0
- package/src/launch-effective-env-resolver.js +192 -0
- package/src/platform.js +24 -0
- package/src/profile-store.js +139 -7
- package/src/profile-validator.js +7 -9
- package/src/runtime-instance-manager.js +190 -0
- package/src/safety.js +72 -35
- package/src/symlink-manager.js +0 -69
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `claude-switch-profile` are documented here.
|
|
4
|
+
|
|
5
|
+
## [1.3.0] - 2026-03-28
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- ✨ **Interactive profile selector** — Run `csp` with no arguments to get an arrow-key profile picker that launches isolated sessions. Supports ↑/↓/j/k navigation, Enter to select, Esc to cancel.
|
|
9
|
+
- ✨ **`csp status`** — Dashboard showing active profile, profile count, last launch info, and Claude running status at a glance.
|
|
10
|
+
- ✨ **`csp toggle`** — Quick-switch to the previous profile (like `cd -`). Uses isolated launch, never touches ~/.claude.
|
|
11
|
+
- ✨ **`csp select`** — Explicit alias for the interactive selector.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- 🔒 **`~/.claude` is never modified** — All profile operations now use isolated runtime (`CLAUDE_CONFIG_DIR`). The `default` profile is a virtual alias for `~/.claude` as-is.
|
|
15
|
+
- 🔒 **`default` profile is virtual** — `csp init` no longer creates a physical directory for the default profile. Default means "use ~/.claude directly".
|
|
16
|
+
- 🔒 **`csp launch default`** — Launches Claude with native `~/.claude` (no runtime dir, no `CLAUDE_CONFIG_DIR` override).
|
|
17
|
+
- 🔒 **`csp deactivate`** — Now simply resets active marker to `default`. No longer deletes files from `~/.claude`.
|
|
18
|
+
- ⚠️ **`csp use` deprecated** — Shows warning that it modifies `~/.claude` (legacy mode). Users should prefer `csp launch`.
|
|
19
|
+
- 🔄 **`csp toggle`** — Now uses `launch` (isolated) instead of `use` (legacy).
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- 🐛 Removed dead `--force` option from `csp use`.
|
|
23
|
+
- 🐛 Fixed double `getActive()` call in `init` command.
|
|
24
|
+
- 🐛 Fixed stale "symlink targets" comment in safety.js.
|
|
25
|
+
- 🐛 Removed unused parameter in diff.js.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## [1.1.0] - 2026-03-13
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
- ✨ **`csp uninstall` command** — Cleanly remove CSP and restore a chosen profile to `~/.claude` before wiping all profile data. Supports `--force` and `--profile <name>` flags.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
- 🔄 **`saveSymlinks` now handles real dirs/files** — When a managed item in `~/.claude` is a real directory or file (not yet a symlink), `saveSymlinks` moves it into the profile directory and replaces it with a symlink in-place. Fixes the case where switching from a fresh `~/.claude` setup left the default profile empty.
|
|
36
|
+
- 🔄 **`removeSymlinks` now removes real dirs/files** — Previously only removed symlinks; now also removes real directories and files for managed items so `createSymlinks` is never blocked.
|
|
37
|
+
- 🔄 **`createSymlinks` uses `rmSync` instead of `unlinkSync`** — Correctly handles pre-existing directories (not just files/symlinks) when restoring a profile.
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
- 🐛 **`statusline.cjs` broken after switch to default profile** — `saveSymlinks` was copying the file into the profile directory, causing `require('./lib/...')` to fail because `lib/` does not exist there. Now the file stays as a symlink pointing to the source project.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## [1.0.2] - 2026-03-12
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
- 🐛 **`csp create` produces clean profiles** — New profiles no longer inherit the current session state; they start empty and isolated.
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
- 🔄 **Max backups reduced to 2** — Keeps `.backup/` lean.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## [1.0.1] - 2026-03-11
|
|
55
|
+
|
|
56
|
+
### Fixed
|
|
57
|
+
- 🐛 Initial bug fixes after first release.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## [1.0.0] - 2026-03-11
|
|
62
|
+
|
|
63
|
+
### Added
|
|
64
|
+
- ✨ Initial release of `claude-switch-profile`
|
|
65
|
+
- `csp init`, `csp create`, `csp use`, `csp save`, `csp list`, `csp current`
|
|
66
|
+
- `csp delete`, `csp export`, `csp import`, `csp diff`
|
|
67
|
+
- Symlink + copy strategy for isolating Claude Code profiles
|
|
68
|
+
- Lock file, automatic backups, Claude process detection
|
|
69
|
+
- Environment variable overrides (`CSP_HOME`, `CSP_CLAUDE_DIR`, `CSP_PROFILES_DIR`)
|
package/README.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Claude Switch Profile (CSP)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/claude-switch-profile)
|
|
4
|
+
[](https://nodejs.org)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
A CLI tool for managing multiple Claude Code configurations and profiles. Use legacy global switching (`csp use`) or concurrent isolated account sessions (`csp launch`) with per-profile runtime roots.
|
|
4
8
|
|
|
5
9
|
## Overview
|
|
6
10
|
|
|
@@ -42,7 +46,8 @@ csp --help
|
|
|
42
46
|
### Requirements
|
|
43
47
|
|
|
44
48
|
- Node.js >= 18.0.0
|
|
45
|
-
- Unix/Linux/macOS
|
|
49
|
+
- Unix/Linux/macOS
|
|
50
|
+
- Windows 10+
|
|
46
51
|
|
|
47
52
|
## Quick Start
|
|
48
53
|
|
|
@@ -104,13 +109,22 @@ csp list
|
|
|
104
109
|
Output example:
|
|
105
110
|
|
|
106
111
|
```
|
|
107
|
-
* default —
|
|
112
|
+
* default — Vanilla Claude defaults (2026-03-11)
|
|
108
113
|
work — Work setup (2026-03-11)
|
|
109
114
|
experimental (2026-03-11)
|
|
110
115
|
```
|
|
111
116
|
|
|
112
117
|
The `*` marks the active profile.
|
|
113
118
|
|
|
119
|
+
### 6. Uninstall CSP
|
|
120
|
+
|
|
121
|
+
Remove CSP and restore your Claude Code to its original state:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
csp uninstall
|
|
125
|
+
# Uninstall CSP and remove all profiles? This cannot be undone. (y/N)
|
|
126
|
+
```
|
|
127
|
+
|
|
114
128
|
## Commands Reference
|
|
115
129
|
|
|
116
130
|
### init
|
|
@@ -133,7 +147,7 @@ csp init
|
|
|
133
147
|
|
|
134
148
|
### current
|
|
135
149
|
|
|
136
|
-
Display the currently active profile.
|
|
150
|
+
Display the currently active **legacy** profile and isolated launch metadata (if present).
|
|
137
151
|
|
|
138
152
|
```bash
|
|
139
153
|
csp current
|
|
@@ -141,8 +155,10 @@ csp current
|
|
|
141
155
|
|
|
142
156
|
**Output:**
|
|
143
157
|
```
|
|
144
|
-
✓ Active profile: default
|
|
158
|
+
✓ Active legacy profile: default
|
|
145
159
|
ℹ Location: /home/user/.claude-profiles/default
|
|
160
|
+
ℹ Last isolated launch: 2026-03-26T14:45:00.000Z
|
|
161
|
+
ℹ Isolated runtime: /home/user/.claude-profiles/.runtime/default
|
|
146
162
|
```
|
|
147
163
|
|
|
148
164
|
---
|
|
@@ -158,8 +174,8 @@ csp ls
|
|
|
158
174
|
|
|
159
175
|
**Output format:**
|
|
160
176
|
```
|
|
161
|
-
* profile-name — optional description (YYYY-MM-DD)
|
|
162
|
-
other-profile (YYYY-MM-DD)
|
|
177
|
+
* profile-name — optional description (YYYY-MM-DD) [legacy|account-session]
|
|
178
|
+
other-profile (YYYY-MM-DD) [account-session]
|
|
163
179
|
```
|
|
164
180
|
|
|
165
181
|
The `*` marks the currently active profile.
|
|
@@ -213,7 +229,7 @@ csp save
|
|
|
213
229
|
```
|
|
214
230
|
|
|
215
231
|
**Behavior:**
|
|
216
|
-
- Captures all managed
|
|
232
|
+
- Captures all managed items and files from `~/.claude`
|
|
217
233
|
- Overwrites profile's `source.json` and file copies
|
|
218
234
|
- Useful after modifying rules, settings, or other configuration
|
|
219
235
|
- Requires active profile (run `csp create` if none exists)
|
|
@@ -231,7 +247,7 @@ csp use <name> [options]
|
|
|
231
247
|
**Options:**
|
|
232
248
|
- `--dry-run` — Show what would change without executing
|
|
233
249
|
- `--no-save` — Skip saving current profile before switching
|
|
234
|
-
- `--force` —
|
|
250
|
+
- `--force` — Accepted for compatibility (current switch path does not block on target-link validation)
|
|
235
251
|
|
|
236
252
|
**Examples:**
|
|
237
253
|
|
|
@@ -256,14 +272,13 @@ csp use legacy --force
|
|
|
256
272
|
```
|
|
257
273
|
|
|
258
274
|
**Behavior:**
|
|
259
|
-
1. Validates target profile exists and is valid
|
|
260
|
-
2. (
|
|
275
|
+
1. Validates target profile exists and profile structure is valid
|
|
276
|
+
2. Refuses to switch while Claude Code is running (legacy/global switching mutates `~/.claude` directly)
|
|
261
277
|
3. If active profile exists and `--no-save` is not set: saves current state
|
|
262
|
-
4.
|
|
263
|
-
5.
|
|
264
|
-
6.
|
|
265
|
-
7.
|
|
266
|
-
8. **Important:** Claude Code session must be restarted for changes to apply
|
|
278
|
+
4. Removes managed items/files from `~/.claude` as needed
|
|
279
|
+
5. Restores target profile configuration into `~/.claude`
|
|
280
|
+
6. Updates active marker
|
|
281
|
+
7. **Important:** Claude Code session must be restarted for changes to apply
|
|
267
282
|
|
|
268
283
|
---
|
|
269
284
|
|
|
@@ -326,7 +341,7 @@ csp export staging -o ~/backups/claude-staging.tar.gz
|
|
|
326
341
|
|
|
327
342
|
**Behavior:**
|
|
328
343
|
- Creates tar.gz archive of entire profile directory
|
|
329
|
-
- Includes source.json (
|
|
344
|
+
- Includes `source.json` (managed item map) and copied profile files/directories
|
|
330
345
|
- Useful for backup, sharing, or version control
|
|
331
346
|
|
|
332
347
|
---
|
|
@@ -390,7 +405,7 @@ csp diff current backup
|
|
|
390
405
|
```
|
|
391
406
|
Comparing: staging ↔ production
|
|
392
407
|
|
|
393
|
-
|
|
408
|
+
Managed item map (source.json): identical
|
|
394
409
|
|
|
395
410
|
File differences:
|
|
396
411
|
settings.json — different
|
|
@@ -399,10 +414,118 @@ File differences:
|
|
|
399
414
|
```
|
|
400
415
|
|
|
401
416
|
**Behavior:**
|
|
402
|
-
- Compares `source.json` (
|
|
417
|
+
- Compares `source.json` (managed item map)
|
|
403
418
|
- Lists file presence and content differences
|
|
404
419
|
- Shows which files differ and in which profile they exist
|
|
405
420
|
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
### deactivate
|
|
424
|
+
|
|
425
|
+
Deactivate the currently active non-default profile and clear `.active` without switching to another profile.
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
csp deactivate
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
**Options:**
|
|
432
|
+
- `--no-save` — Skip saving current profile state before deactivation
|
|
433
|
+
|
|
434
|
+
**Behavior:**
|
|
435
|
+
1. Exits early if no active profile or active profile is `default`
|
|
436
|
+
2. Optionally saves active profile state
|
|
437
|
+
3. Removes managed items/files from `~/.claude`
|
|
438
|
+
4. Clears active marker
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
### launch (la)
|
|
443
|
+
|
|
444
|
+
Launch an isolated Claude session for a profile. This does **not** change global active profile. All extra arguments are forwarded to `claude`.
|
|
445
|
+
|
|
446
|
+
```bash
|
|
447
|
+
csp launch <name> [claude-args...]
|
|
448
|
+
csp la <name> [claude-args...]
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
**Options:**
|
|
452
|
+
- `--legacy-global` — Use old behavior (`csp use <name>` then launch)
|
|
453
|
+
|
|
454
|
+
**Examples:**
|
|
455
|
+
|
|
456
|
+
Launch isolated session:
|
|
457
|
+
```bash
|
|
458
|
+
csp launch work
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
Launch isolated with Claude flags:
|
|
462
|
+
```bash
|
|
463
|
+
csp launch work --dangerously-skip-permissions
|
|
464
|
+
csp la dev --model opus
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
Launch legacy/global mode:
|
|
468
|
+
```bash
|
|
469
|
+
csp launch work --legacy-global
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
**Behavior (default isolated mode):**
|
|
473
|
+
1. Validates target profile exists
|
|
474
|
+
2. Prepares per-profile runtime under `~/.claude-profiles/.runtime/<name>`
|
|
475
|
+
3. Resolves effective allowlisted `ANTHROPIC_*` launch env (`ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_BASE_URL`, `ANTHROPIC_MODEL`) with precedence: `settings.json env` > profile `.env` allowlist > parent process env
|
|
476
|
+
4. Strips inherited `CLAUDECODE`, inherited `CLAUDE_CONFIG_DIR`, and inherited `ANTHROPIC_*` before applying resolved allowlisted values
|
|
477
|
+
5. Spawns `claude` with `CLAUDE_CONFIG_DIR=<runtimeDir>`
|
|
478
|
+
6. Inherits stdin/stdout/stderr for interactive use
|
|
479
|
+
7. Forwards Claude's exit code
|
|
480
|
+
8. Keeps `.active` unchanged and never mutates global `~/.claude`
|
|
481
|
+
|
|
482
|
+
`ANTHROPIC_*` keys currently in isolated launch scope:
|
|
483
|
+
- `ANTHROPIC_AUTH_TOKEN`
|
|
484
|
+
- `ANTHROPIC_BASE_URL`
|
|
485
|
+
- `ANTHROPIC_MODEL`
|
|
486
|
+
|
|
487
|
+
Set `CSP_DEBUG_LAUNCH_ENV=1` to print key-level launch diagnostics (sources only, values are never printed).
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
### uninstall
|
|
492
|
+
|
|
493
|
+
Remove all profiles and restore Claude Code to its pre-CSP state.
|
|
494
|
+
|
|
495
|
+
```bash
|
|
496
|
+
csp uninstall
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
**Options:**
|
|
500
|
+
- `-f, --force` — Skip confirmation prompt
|
|
501
|
+
- `--profile <name>` — Restore a specific profile instead of the active one
|
|
502
|
+
|
|
503
|
+
**Examples:**
|
|
504
|
+
|
|
505
|
+
Uninstall with confirmation:
|
|
506
|
+
```bash
|
|
507
|
+
csp uninstall
|
|
508
|
+
# Uninstall CSP and remove all profiles? This cannot be undone. (y/N)
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
Restore a specific profile during uninstall:
|
|
512
|
+
```bash
|
|
513
|
+
csp uninstall --profile production
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
Force uninstall without prompt:
|
|
517
|
+
```bash
|
|
518
|
+
csp uninstall --force
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
**Behavior:**
|
|
522
|
+
1. Creates a final backup at `~/.claude-profiles/.backup/`
|
|
523
|
+
2. Restores the active profile (or `--profile` choice) to `~/.claude`
|
|
524
|
+
3. Removes `~/.claude-profiles/` entirely
|
|
525
|
+
4. Prints reminder to run `npm uninstall -g claude-switch-profile`
|
|
526
|
+
|
|
527
|
+
---
|
|
528
|
+
|
|
406
529
|
## How Profiles Work
|
|
407
530
|
|
|
408
531
|
### Profile Storage
|
|
@@ -411,10 +534,13 @@ Profiles are stored in `~/.claude-profiles/`:
|
|
|
411
534
|
|
|
412
535
|
```
|
|
413
536
|
~/.claude-profiles/
|
|
414
|
-
├── .active # Current active profile name
|
|
415
|
-
├── profiles.json # Metadata for all profiles
|
|
537
|
+
├── .active # Current active profile name (legacy use mode)
|
|
538
|
+
├── profiles.json # Metadata for all profiles (v2 schema)
|
|
539
|
+
├── .runtime/ # Isolated launch roots
|
|
540
|
+
│ ├── work/
|
|
541
|
+
│ └── personal/
|
|
416
542
|
├── default/
|
|
417
|
-
│ ├── source.json #
|
|
543
|
+
│ ├── source.json # Managed item map
|
|
418
544
|
│ ├── settings.json # Copied from ~/.claude
|
|
419
545
|
│ ├── .env # Copied from ~/.claude
|
|
420
546
|
│ ├── .ck.json # Copied from ~/.claude
|
|
@@ -429,7 +555,7 @@ Profiles are stored in `~/.claude-profiles/`:
|
|
|
429
555
|
|
|
430
556
|
### What Gets Managed
|
|
431
557
|
|
|
432
|
-
**
|
|
558
|
+
**Managed Static Items** (via `source.json`):
|
|
433
559
|
- `CLAUDE.md` — Project-specific Claude configuration
|
|
434
560
|
- `rules/` — Development rules and guidelines
|
|
435
561
|
- `agents/` — Agent scripts and configurations
|
|
@@ -440,35 +566,49 @@ Profiles are stored in `~/.claude-profiles/`:
|
|
|
440
566
|
|
|
441
567
|
**Copied Files**:
|
|
442
568
|
- `settings.json` — Editor settings
|
|
443
|
-
- `.env` — Environment variables
|
|
444
|
-
- `.ck.json` — Custom settings
|
|
445
|
-
- `.
|
|
569
|
+
- `.env`, `.env.example` — Environment variables
|
|
570
|
+
- `.ck.json`, `.ckignore` — Custom settings and ignore patterns
|
|
571
|
+
- `.mcp.json`, `.mcp.json.example` — MCP configuration
|
|
572
|
+
- `.gitignore` — Local ignore settings
|
|
446
573
|
|
|
447
574
|
**Copied Directories**:
|
|
448
|
-
- `commands/` — Custom commands
|
|
449
|
-
- `
|
|
575
|
+
- `commands/`, `plugins/` — Custom commands/plugins
|
|
576
|
+
- `workflows/`, `scripts/` — Automation and workflow assets
|
|
577
|
+
- `output-styles/`, `schemas/` — Output and schema assets
|
|
450
578
|
|
|
451
579
|
**Never Touched** (runtime/session data):
|
|
452
580
|
- `.credentials.json`
|
|
453
|
-
- `projects/`
|
|
454
|
-
- `
|
|
455
|
-
- `
|
|
456
|
-
- `
|
|
457
|
-
- `plans/`, `todos/`, `tasks/`
|
|
458
|
-
- `agent-memory/`, `session-env/`
|
|
581
|
+
- `projects/`, `sessions/`, `session-env/`, `ide/`
|
|
582
|
+
- `cache/`, `paste-cache/`, `downloads/`, `telemetry/`, `debug/`, `statsig/`
|
|
583
|
+
- `history.jsonl`, `metadata.json`, `stats-cache.json`, `active-plan`
|
|
584
|
+
- `backups/`, `command-archive/`, `commands-archived/`
|
|
585
|
+
- `plans/`, `todos/`, `tasks/`, `teams/`, `agent-memory/`, `file-history/`, `shell-snapshots/`
|
|
459
586
|
- All other session-specific data
|
|
460
587
|
|
|
461
|
-
###
|
|
588
|
+
### Legacy vs Isolated Launch Modes
|
|
589
|
+
|
|
590
|
+
CSP now supports two paths:
|
|
591
|
+
|
|
592
|
+
- **Legacy global mode (`csp use`)**
|
|
593
|
+
- Mutates `~/.claude`
|
|
594
|
+
- Updates `.active`
|
|
595
|
+
- Preserves old behavior for existing scripts
|
|
596
|
+
|
|
597
|
+
- **Isolated launch mode (`csp launch`)**
|
|
598
|
+
- Does not mutate `~/.claude`
|
|
599
|
+
- Does not change `.active`
|
|
600
|
+
- Creates/updates runtime root per profile at `~/.claude-profiles/.runtime/<name>`
|
|
601
|
+
- Launches Claude with `CLAUDE_CONFIG_DIR` pointing to that runtime root
|
|
602
|
+
|
|
603
|
+
### Runtime Sync Policy (isolated launch)
|
|
462
604
|
|
|
463
|
-
|
|
464
|
-
- Rules, agents, skills often live in external git repos
|
|
465
|
-
- Multiple profiles may share the same rules/skills
|
|
466
|
-
- Symlinks avoid duplication and keep everything in sync
|
|
605
|
+
For each launch, CSP syncs static profile config into runtime root:
|
|
467
606
|
|
|
468
|
-
|
|
469
|
-
-
|
|
470
|
-
-
|
|
471
|
-
|
|
607
|
+
- Managed items (`CLAUDE.md`, `rules`, `agents`, `skills`, `hooks`, statusline files, `.luna.json`)
|
|
608
|
+
- Copied files (`settings.json`, `.env`, `.ck.json`, `.ckignore`, etc.)
|
|
609
|
+
- Copied directories (`commands`, `plugins`, `workflows`, `scripts`, ...)
|
|
610
|
+
|
|
611
|
+
Runtime/account continuity stays isolated per runtime root and is not globally swapped.
|
|
472
612
|
|
|
473
613
|
## Safety Features
|
|
474
614
|
|
|
@@ -500,7 +640,7 @@ Every profile switch creates a timestamped backup:
|
|
|
500
640
|
└── ...
|
|
501
641
|
```
|
|
502
642
|
|
|
503
|
-
Backups are
|
|
643
|
+
Backups are pruned automatically; CSP keeps only the 2 most recent backups. You can manually restore by copying from backup directory.
|
|
504
644
|
|
|
505
645
|
### Claude Process Detection
|
|
506
646
|
|
|
@@ -512,14 +652,19 @@ When switching profiles, CSP detects if Claude Code is running:
|
|
|
512
652
|
|
|
513
653
|
**Important:** Changes only take effect after restarting Claude Code.
|
|
514
654
|
|
|
655
|
+
### Windows Support
|
|
656
|
+
|
|
657
|
+
Process detection uses `tasklist` instead of `pgrep` on Windows.
|
|
658
|
+
|
|
659
|
+
Export/import commands use the built-in `tar.exe` available on Windows 10+.
|
|
660
|
+
|
|
515
661
|
### Validation
|
|
516
662
|
|
|
517
663
|
Before switching, CSP validates:
|
|
518
664
|
1. Target profile exists
|
|
519
665
|
2. Profile structure is valid
|
|
520
|
-
3. (Optional with `--force`) Symlink targets are accessible
|
|
521
666
|
|
|
522
|
-
|
|
667
|
+
`--force` is currently accepted for compatibility:
|
|
523
668
|
|
|
524
669
|
```bash
|
|
525
670
|
csp use legacy --force
|
|
@@ -667,15 +812,11 @@ csp delete default
|
|
|
667
812
|
rm ~/.claude-profiles/.lock
|
|
668
813
|
```
|
|
669
814
|
|
|
670
|
-
###
|
|
815
|
+
### Invalid profile structure
|
|
671
816
|
|
|
672
|
-
**
|
|
817
|
+
**Error:** `Profile "name" is invalid: Missing source.json — no managed items defined`
|
|
673
818
|
|
|
674
|
-
**Solution:**
|
|
675
|
-
|
|
676
|
-
```bash
|
|
677
|
-
csp use production --force
|
|
678
|
-
```
|
|
819
|
+
**Solution:** Recreate the profile or import a valid profile archive.
|
|
679
820
|
|
|
680
821
|
### Changes not applying
|
|
681
822
|
|
|
@@ -699,6 +840,10 @@ npm run test:cli # CLI integration tests
|
|
|
699
840
|
npm run test:safety # Safety feature tests
|
|
700
841
|
```
|
|
701
842
|
|
|
843
|
+
### Changelog
|
|
844
|
+
|
|
845
|
+
See [CHANGELOG.md](CHANGELOG.md) for version history and migration guidance.
|
|
846
|
+
|
|
702
847
|
### Project Structure
|
|
703
848
|
|
|
704
849
|
```
|
|
@@ -716,10 +861,15 @@ npm run test:safety # Safety feature tests
|
|
|
716
861
|
│ │ ├── delete.js
|
|
717
862
|
│ │ ├── export.js
|
|
718
863
|
│ │ ├── import.js
|
|
719
|
-
│ │
|
|
864
|
+
│ │ ├── diff.js
|
|
865
|
+
│ │ ├── launch.js
|
|
866
|
+
│ │ ├── deactivate.js
|
|
867
|
+
│ │ └── uninstall.js
|
|
720
868
|
│ ├── constants.js # Configuration constants
|
|
869
|
+
│ ├── platform.js # Cross-platform compatibility
|
|
721
870
|
│ ├── profile-store.js # Profile metadata management
|
|
722
|
-
│ ├──
|
|
871
|
+
│ ├── runtime-instance-manager.js # Isolated runtime sync
|
|
872
|
+
│ ├── item-manager.js # Managed item copy/move operations
|
|
723
873
|
│ ├── file-operations.js # File copy/restore operations
|
|
724
874
|
│ ├── safety.js # Locking, backups, validation
|
|
725
875
|
│ ├── profile-validator.js # Profile validation
|
package/bin/csp.js
CHANGED
|
@@ -15,6 +15,12 @@ import { exportCommand } from '../src/commands/export.js';
|
|
|
15
15
|
import { importCommand } from '../src/commands/import.js';
|
|
16
16
|
import { diffCommand } from '../src/commands/diff.js';
|
|
17
17
|
import { initCommand } from '../src/commands/init.js';
|
|
18
|
+
import { uninstallCommand } from '../src/commands/uninstall.js';
|
|
19
|
+
import { launchCommand } from '../src/commands/launch.js';
|
|
20
|
+
import { deactivateCommand } from '../src/commands/deactivate.js';
|
|
21
|
+
import { toggleCommand } from '../src/commands/toggle.js';
|
|
22
|
+
import { statusCommand } from '../src/commands/status.js';
|
|
23
|
+
import { selectCommand } from '../src/commands/select.js';
|
|
18
24
|
|
|
19
25
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
20
26
|
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
@@ -24,7 +30,13 @@ const program = new Command();
|
|
|
24
30
|
program
|
|
25
31
|
.name('csp')
|
|
26
32
|
.description('Claude Switch Profile — manage multiple Claude Code configurations')
|
|
27
|
-
.version(pkg.version)
|
|
33
|
+
.version(pkg.version)
|
|
34
|
+
.enablePositionalOptions();
|
|
35
|
+
|
|
36
|
+
program
|
|
37
|
+
.command('select', { isDefault: true })
|
|
38
|
+
.description('Interactive profile selector (default when no command given)')
|
|
39
|
+
.action(selectCommand);
|
|
28
40
|
|
|
29
41
|
program
|
|
30
42
|
.command('init')
|
|
@@ -33,7 +45,7 @@ program
|
|
|
33
45
|
|
|
34
46
|
program
|
|
35
47
|
.command('current')
|
|
36
|
-
.description('Show the active profile')
|
|
48
|
+
.description('Show the active legacy profile and isolated launch metadata')
|
|
37
49
|
.action(currentCommand);
|
|
38
50
|
|
|
39
51
|
program
|
|
@@ -42,6 +54,11 @@ program
|
|
|
42
54
|
.description('List all profiles')
|
|
43
55
|
.action(listCommand);
|
|
44
56
|
|
|
57
|
+
program
|
|
58
|
+
.command('status')
|
|
59
|
+
.description('Show CSP status dashboard')
|
|
60
|
+
.action(statusCommand);
|
|
61
|
+
|
|
45
62
|
program
|
|
46
63
|
.command('create <name>')
|
|
47
64
|
.description('Create a new profile from current Claude Code state')
|
|
@@ -60,9 +77,13 @@ program
|
|
|
60
77
|
.description('Switch to a different profile')
|
|
61
78
|
.option('--dry-run', 'Show what would change without executing')
|
|
62
79
|
.option('--no-save', 'Skip saving current profile before switching')
|
|
63
|
-
.option('--force', 'Switch even if symlink targets are missing')
|
|
64
80
|
.action(useCommand);
|
|
65
81
|
|
|
82
|
+
program
|
|
83
|
+
.command('toggle')
|
|
84
|
+
.description('Switch to the previous profile')
|
|
85
|
+
.action(toggleCommand);
|
|
86
|
+
|
|
66
87
|
program
|
|
67
88
|
.command('delete <name>')
|
|
68
89
|
.alias('rm')
|
|
@@ -88,4 +109,32 @@ program
|
|
|
88
109
|
.description('Compare two profiles (use "current" for active profile)')
|
|
89
110
|
.action(diffCommand);
|
|
90
111
|
|
|
112
|
+
program
|
|
113
|
+
.command('deactivate')
|
|
114
|
+
.description('Deactivate the current profile (remove managed items from ~/.claude)')
|
|
115
|
+
.option('--no-save', 'Skip saving current profile before deactivating')
|
|
116
|
+
.action(deactivateCommand);
|
|
117
|
+
|
|
118
|
+
program
|
|
119
|
+
.command('launch <name> [args...]')
|
|
120
|
+
.alias('la')
|
|
121
|
+
.description('Launch isolated Claude session for a profile (use --legacy-global for old switch+launch behavior)')
|
|
122
|
+
.option('--legacy-global', 'Use legacy global switch path before launching Claude')
|
|
123
|
+
.allowUnknownOption(true)
|
|
124
|
+
.enablePositionalOptions(true)
|
|
125
|
+
.passThroughOptions(true)
|
|
126
|
+
.action((name, args, options, cmd) => {
|
|
127
|
+
// Merge explicit positional args with unknown options (e.g. --dangerously-skip-permissions)
|
|
128
|
+
const unknownOpts = cmd.args.filter((a) => a !== name && !args.includes(a));
|
|
129
|
+
const claudeArgs = [...args, ...unknownOpts];
|
|
130
|
+
launchCommand(name, claudeArgs, options);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
program
|
|
134
|
+
.command('uninstall')
|
|
135
|
+
.description('Remove all profiles and restore Claude Code to pre-CSP state')
|
|
136
|
+
.option('-f, --force', 'Skip confirmation prompt')
|
|
137
|
+
.option('--profile <name>', 'Restore specific profile instead of active one')
|
|
138
|
+
.action(uninstallCommand);
|
|
139
|
+
|
|
91
140
|
program.parse();
|