claude-switch-profile 1.4.8 → 1.4.12
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 +70 -0
- package/README.md +70 -869
- package/package.json +1 -1
- package/src/runtime-instance-manager.js +35 -3
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,76 @@ All notable changes to `claude-switch-profile` are documented here.
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
+
## [1.4.11] - 2026-04-01
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- Version bump only — no functional code changes from `1.4.10`.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## [1.4.10] - 2026-04-01
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- **Settings Path Mutation Bug**: Fixed a severe issue where hook paths in `settings.json` could exponentially multiply (like `.runtime/default-profiles/.runtime/...`) when saving a profile post-launch. Path mapping logic was strengthened to use exact-boundary Regular Expressions, preventing `.claude` patterns from incorrectly matching adjacent nested paths like `.claude-profiles`.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## [1.4.9] - 2026-04-01
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
- **Hooks execution in isolated mode**: Fixed an issue where Claude Code hook scripts failed to execute in isolated profiles. The runtime instance manager now correctly resolves shell variables (`$HOME`, `${HOME}`, `~`) within `settings.json` hook commands to accurately point to the isolated runtime directory.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## [1.4.8] - 2026-04-01
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
- Re-ran release flow to publish the latest patch after `1.4.7`.
|
|
37
|
+
- No functional code changes compared with `1.4.7`; this release aligns npm package/version metadata.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## [1.4.7] - 2026-04-01
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
- Release pipeline now restores annotated git tag publishing.
|
|
45
|
+
- Local agent artifacts are ignored by git to keep release working tree clean.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## [1.4.6] - 2026-03-31
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
- Excluded cocoindex cache from npm package to reduce published size.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## [1.4.5] - 2026-03-31
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
- Release pipeline: stopped creating duplicate git tags during release.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## [1.4.4] - 2026-03-31
|
|
64
|
+
|
|
65
|
+
### Fixed
|
|
66
|
+
- Release pipeline: handled noisy test output that could interrupt release flow.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## [1.4.3] - 2026-03-31
|
|
71
|
+
|
|
72
|
+
### Added
|
|
73
|
+
- ✨ **`csp exec` command** — Run an arbitrary command inside an isolated profile runtime environment. Similar to `csp launch` but runs any command (not just Claude) under profile-scoped env. Supports `--` separator for command arguments.
|
|
74
|
+
- ✨ **Dynamic shell support for `csp exec`** — On Unix-like systems, commands run through the user's interactive shell so shell aliases and functions resolve naturally while keeping runtime isolation intact.
|
|
75
|
+
|
|
76
|
+
### Changed
|
|
77
|
+
- Refactored `launch.js` to share context setup with `exec` via `isolated-launch-context.js`.
|
|
78
|
+
- On Windows, `exec` falls back to direct spawn with `.cmd` / `.bat` wrapper detection.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
12
82
|
## [1.4.2] - 2026-03-31
|
|
13
83
|
|
|
14
84
|
### Changed
|
package/README.md
CHANGED
|
@@ -20,618 +20,87 @@ Profiles are stored in `~/.claude-profiles/` and are never managed by Claude Cod
|
|
|
20
20
|
|
|
21
21
|
## Installation
|
|
22
22
|
|
|
23
|
-
### Global Installation
|
|
24
|
-
|
|
25
23
|
```bash
|
|
26
24
|
npm install -g claude-switch-profile
|
|
27
25
|
```
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
csp list
|
|
33
|
-
csp current
|
|
34
|
-
csp create my-profile
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
### Local Development
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
# In the project root
|
|
41
|
-
npm install
|
|
42
|
-
npm link
|
|
43
|
-
|
|
44
|
-
# Now available as `csp` command
|
|
45
|
-
csp --help
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### Requirements
|
|
49
|
-
|
|
50
|
-
- Node.js >= 18.0.0
|
|
51
|
-
- Unix/Linux/macOS
|
|
52
|
-
- Windows 10+
|
|
27
|
+
**Requirements:** Node.js >= 18.0.0 | macOS/Linux/Windows 10+
|
|
53
28
|
|
|
54
29
|
## Quick Start
|
|
55
30
|
|
|
56
|
-
### 1. Initialize
|
|
57
|
-
|
|
58
|
-
Capture your current Claude Code setup as the physical `default` profile snapshot:
|
|
59
|
-
|
|
60
31
|
```bash
|
|
32
|
+
# 1. Initialize — capture current setup as "default" profile
|
|
61
33
|
csp init
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
This creates `~/.claude-profiles/default/` from the current managed contents of `~/.claude`. Protected and session/runtime files remain excluded.
|
|
65
|
-
|
|
66
|
-
### 2. Create Additional Profiles
|
|
67
|
-
|
|
68
|
-
Create a new profile from your current state:
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
csp create work --description "Work setup with company rules"
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
Or clone from an existing profile:
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
csp create experimental --from default --description "Testing new tools"
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### 3. Switch Between Profiles
|
|
81
|
-
|
|
82
|
-
Switch to a profile (automatically saves current state):
|
|
83
|
-
|
|
84
|
-
```bash
|
|
85
|
-
csp use work
|
|
86
|
-
# Restart your Claude Code session for changes to take effect
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
Use `--dry-run` to preview changes:
|
|
90
|
-
|
|
91
|
-
```bash
|
|
92
|
-
csp use work --dry-run
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### 4. Save Current State
|
|
96
|
-
|
|
97
|
-
Save the active profile with current configuration:
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
csp save
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### 5. List All Profiles
|
|
104
|
-
|
|
105
|
-
View all available profiles with their status:
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
csp list
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
Output example:
|
|
112
34
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
experimental (2026-03-11)
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
The `*` marks the active profile.
|
|
120
|
-
|
|
121
|
-
### 6. Launch via Interactive Selector (Default Command)
|
|
122
|
-
|
|
123
|
-
Run `csp` without a subcommand to open the interactive selector and launch a profile immediately:
|
|
124
|
-
|
|
125
|
-
```bash
|
|
126
|
-
csp
|
|
127
|
-
```
|
|
35
|
+
# 2. Create additional profiles
|
|
36
|
+
csp create work -d "Work setup with company rules"
|
|
37
|
+
csp create experimental --from default -d "Testing new tools"
|
|
128
38
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
```bash
|
|
134
|
-
csp uninstall
|
|
135
|
-
# Uninstall CSP and remove all profiles? This cannot be undone. (y/N)
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## Commands Reference
|
|
139
|
-
|
|
140
|
-
### select (default)
|
|
141
|
-
|
|
142
|
-
Open interactive profile selector (default behavior when you run `csp` without subcommand).
|
|
39
|
+
# 3. Launch isolated sessions (recommended — does NOT touch ~/.claude)
|
|
40
|
+
csp launch work
|
|
41
|
+
csp launch experimental
|
|
143
42
|
|
|
144
|
-
|
|
43
|
+
# 4. Or use the interactive selector
|
|
145
44
|
csp
|
|
146
|
-
csp select
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
**Behavior:**
|
|
150
|
-
- If TTY and multiple profiles exist: shows arrow-key menu and launches selected profile via `csp launch <name>`
|
|
151
|
-
- If only one profile exists: shows informational message and exits
|
|
152
|
-
- If non-interactive terminal: asks to use `csp launch <name>` or `csp use <name>` directly
|
|
153
|
-
|
|
154
|
-
---
|
|
155
|
-
|
|
156
|
-
### init
|
|
157
|
-
|
|
158
|
-
Initialize the profile system and capture current state as "default" profile.
|
|
159
|
-
|
|
160
|
-
```bash
|
|
161
|
-
csp init
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
**Options:** None
|
|
165
|
-
|
|
166
|
-
**Behavior:**
|
|
167
|
-
- Creates `~/.claude-profiles/` directory
|
|
168
|
-
- Captures current `~/.claude` configuration
|
|
169
|
-
- Creates `default` profile and marks it active
|
|
170
|
-
- If already initialized, displays current active profile
|
|
171
|
-
|
|
172
|
-
---
|
|
173
|
-
|
|
174
|
-
### current
|
|
175
|
-
|
|
176
|
-
Display the currently active **legacy** profile and isolated launch metadata (if present).
|
|
177
|
-
|
|
178
|
-
```bash
|
|
179
|
-
csp current
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
**Output:**
|
|
183
|
-
```
|
|
184
|
-
✓ Active legacy profile: default
|
|
185
|
-
ℹ Location: /home/user/.claude-profiles/default
|
|
186
|
-
ℹ Last isolated launch: 2026-03-26T14:45:00.000Z
|
|
187
|
-
ℹ Isolated runtime: /home/user/.claude-profiles/.runtime/default
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
---
|
|
191
|
-
|
|
192
|
-
### list (ls)
|
|
193
|
-
|
|
194
|
-
List all profiles with descriptions and creation dates.
|
|
195
|
-
|
|
196
|
-
```bash
|
|
197
|
-
csp list
|
|
198
|
-
csp ls
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
**Output format:**
|
|
202
|
-
```
|
|
203
|
-
* profile-name — optional description (YYYY-MM-DD) [legacy|account-session]
|
|
204
|
-
other-profile (YYYY-MM-DD) [account-session]
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
The `*` marks the currently active profile.
|
|
208
|
-
|
|
209
|
-
---
|
|
210
|
-
|
|
211
|
-
### status
|
|
212
|
-
|
|
213
|
-
Show CSP status dashboard (active profile, profile count, last launch, Claude process state).
|
|
214
|
-
|
|
215
|
-
```bash
|
|
216
|
-
csp status
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
---
|
|
220
|
-
|
|
221
|
-
### create
|
|
222
|
-
|
|
223
|
-
Create a new profile from current state or clone existing profile.
|
|
224
|
-
|
|
225
|
-
```bash
|
|
226
|
-
csp create <name> [options]
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
**Options:**
|
|
230
|
-
- `--from <profile>` — Clone from existing profile instead of current state
|
|
231
|
-
- `-s, --source <path>` — Create from a specific kit directory, then inherit missing managed items from current `~/.claude`
|
|
232
|
-
- `-d, --description <text>` — Add description to profile
|
|
233
|
-
|
|
234
|
-
**Examples:**
|
|
235
|
-
|
|
236
|
-
Create from current state:
|
|
237
|
-
```bash
|
|
238
|
-
csp create production
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
Create with description:
|
|
242
|
-
```bash
|
|
243
|
-
csp create staging -d "Staging environment with logging enabled"
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
Clone from existing:
|
|
247
|
-
```bash
|
|
248
|
-
csp create backup --from production
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
Create from kit directory:
|
|
252
|
-
```bash
|
|
253
|
-
csp create team-kit --source ~/my-kit/.agents -d "Team baseline"
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
**Behavior:**
|
|
257
|
-
- Creates profile directory: `~/.claude-profiles/<name>/`
|
|
258
|
-
- If `--from` is specified, clones all content from source profile
|
|
259
|
-
- If `--source` is specified, copies managed items from that directory, then fills missing managed items from current `~/.claude`
|
|
260
|
-
- Otherwise, performs full clone of current `~/.claude` excluding protected/session items
|
|
261
|
-
- If this is the first profile, automatically sets it as active
|
|
262
|
-
- Saves metadata (created timestamp, description)
|
|
263
|
-
|
|
264
|
-
---
|
|
265
|
-
|
|
266
|
-
### save
|
|
267
|
-
|
|
268
|
-
Save the current `~/.claude` state to the active profile.
|
|
269
|
-
|
|
270
|
-
```bash
|
|
271
|
-
csp save
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
**Behavior:**
|
|
275
|
-
- Captures all managed items and copied files/directories from `~/.claude`
|
|
276
|
-
- Overwrites the active profile snapshot (`source.json` plus copied content)
|
|
277
|
-
- When `default` is active, updates the physical `default` snapshot like any other profile
|
|
278
|
-
- Protected and session/runtime files remain excluded
|
|
279
|
-
- Requires an active profile
|
|
280
|
-
|
|
281
|
-
---
|
|
282
|
-
|
|
283
|
-
### use
|
|
284
|
-
|
|
285
|
-
Switch to a different profile.
|
|
286
|
-
|
|
287
|
-
```bash
|
|
288
|
-
csp use <name> [options]
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
**Options:**
|
|
292
|
-
- `--dry-run` — Show what would change without executing
|
|
293
|
-
- `--no-save` — Skip saving current profile before switching
|
|
294
|
-
|
|
295
|
-
**Examples:**
|
|
296
|
-
|
|
297
|
-
Simple switch:
|
|
298
|
-
```bash
|
|
299
|
-
csp use production
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
Preview changes first:
|
|
303
|
-
```bash
|
|
304
|
-
csp use staging --dry-run
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
Switch without saving current state:
|
|
308
|
-
```bash
|
|
309
|
-
csp use backup --no-save
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
**Behavior:**
|
|
313
|
-
1. Validates target profile exists and profile structure is valid
|
|
314
|
-
2. Refuses to switch while Claude Code is running (legacy/global switching mutates `~/.claude` directly)
|
|
315
|
-
3. If the active profile exists and `--no-save` is not set: saves its current snapshot first
|
|
316
|
-
4. Removes managed items/files from `~/.claude`
|
|
317
|
-
5. Restores the target profile snapshot into `~/.claude` — including `default`
|
|
318
|
-
6. Updates active marker
|
|
319
|
-
7. On older installs missing `profiles/default`, CSP only backfills that snapshot when the active profile is `default` or no active profile is set; otherwise it fails closed with repair guidance
|
|
320
|
-
8. **Important:** Claude Code session must be restarted for changes to apply
|
|
321
|
-
|
|
322
|
-
---
|
|
323
|
-
|
|
324
|
-
### toggle
|
|
325
|
-
|
|
326
|
-
Launch the previous profile (does not mutate global active profile in isolated mode).
|
|
327
|
-
|
|
328
|
-
```bash
|
|
329
|
-
csp toggle
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
**Behavior:**
|
|
333
|
-
- Reads previous profile marker from `~/.claude-profiles/.previous`
|
|
334
|
-
- Validates previous profile still exists
|
|
335
|
-
- Delegates to `csp launch <previous>`
|
|
336
|
-
|
|
337
|
-
---
|
|
338
|
-
|
|
339
|
-
### delete (rm)
|
|
340
|
-
|
|
341
|
-
Delete a profile.
|
|
342
|
-
|
|
343
|
-
```bash
|
|
344
|
-
csp delete <name> [options]
|
|
345
|
-
csp rm <name> [options]
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
**Options:**
|
|
349
|
-
- `-f, --force` — Skip confirmation prompt
|
|
350
|
-
|
|
351
|
-
**Examples:**
|
|
352
|
-
|
|
353
|
-
Delete with confirmation:
|
|
354
|
-
```bash
|
|
355
|
-
csp delete experimental
|
|
356
|
-
# Delete profile "experimental"? This cannot be undone. (y/N)
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
Force delete without prompt:
|
|
360
|
-
```bash
|
|
361
|
-
csp delete old-setup --force
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
**Behavior:**
|
|
365
|
-
- Cannot delete `default`
|
|
366
|
-
- Prompts for confirmation unless `--force` is used
|
|
367
|
-
- Permanently removes profile directory and metadata
|
|
368
|
-
- If deleting the currently active non-default profile: clears active marker only (does not mutate `~/.claude`)
|
|
369
|
-
- Cannot be undone
|
|
370
|
-
|
|
371
|
-
---
|
|
372
|
-
|
|
373
|
-
### export
|
|
374
|
-
|
|
375
|
-
Export a profile as a compressed tar.gz archive.
|
|
376
|
-
|
|
377
|
-
```bash
|
|
378
|
-
csp export <name> [options]
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
**Options:**
|
|
382
|
-
- `-o, --output <path>` — Output file path (defaults to `./{name}.csp.tar.gz`)
|
|
383
|
-
|
|
384
|
-
**Examples:**
|
|
385
|
-
|
|
386
|
-
Export with default filename:
|
|
387
|
-
```bash
|
|
388
|
-
csp export production
|
|
389
|
-
# Exports to ./production.csp.tar.gz
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
Export to custom location:
|
|
393
|
-
```bash
|
|
394
|
-
csp export staging -o ~/backups/claude-staging.tar.gz
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
**Behavior:**
|
|
398
|
-
- Creates tar.gz archive of the profile snapshot directory
|
|
399
|
-
- Includes `source.json` plus copied profile files/directories
|
|
400
|
-
- Exporting `default` works like any other profile snapshot
|
|
401
|
-
- Protected and session/runtime files remain excluded from the archive
|
|
402
|
-
- Useful for backup, sharing, or version control
|
|
403
|
-
|
|
404
|
-
---
|
|
405
|
-
|
|
406
|
-
### import
|
|
407
|
-
|
|
408
|
-
Import a profile from tar.gz archive.
|
|
409
|
-
|
|
410
|
-
```bash
|
|
411
|
-
csp import <file> [options]
|
|
412
|
-
```
|
|
413
|
-
|
|
414
|
-
**Options:**
|
|
415
|
-
- `-n, --name <name>` — Profile name (defaults to archive filename without extension)
|
|
416
|
-
- `-d, --description <text>` — Profile description
|
|
417
|
-
|
|
418
|
-
**Examples:**
|
|
419
|
-
|
|
420
|
-
Import with default name:
|
|
421
|
-
```bash
|
|
422
|
-
csp import production.csp.tar.gz
|
|
423
|
-
# Creates profile named "production"
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
Import with custom name and description:
|
|
427
|
-
```bash
|
|
428
|
-
csp import backup.tar.gz -n restored -d "Restored from backup"
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
**Behavior:**
|
|
432
|
-
- Extracts archive to `~/.claude-profiles/<name>/`
|
|
433
|
-
- Uses filename as profile name if `--name` not specified
|
|
434
|
-
- Validates imported profile structure
|
|
435
|
-
- Rejects import if managed/copied items contain symlink targets outside profile directory (safety check)
|
|
436
|
-
- Creates metadata entry for profile
|
|
437
|
-
- Profile is ready to use immediately
|
|
438
|
-
|
|
439
|
-
---
|
|
440
|
-
|
|
441
|
-
### diff
|
|
442
|
-
|
|
443
|
-
Compare two profiles to identify differences.
|
|
444
|
-
|
|
445
|
-
```bash
|
|
446
|
-
csp diff <profileA> <profileB>
|
|
447
45
|
```
|
|
448
46
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
**Examples:**
|
|
452
|
-
|
|
453
|
-
Compare two profiles:
|
|
454
|
-
```bash
|
|
455
|
-
csp diff staging production
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
Compare current profile with another:
|
|
459
|
-
```bash
|
|
460
|
-
csp diff current backup
|
|
461
|
-
```
|
|
462
|
-
|
|
463
|
-
**Output:**
|
|
464
|
-
```
|
|
465
|
-
Comparing: staging ↔ production
|
|
466
|
-
|
|
467
|
-
Managed item map (source.json): identical
|
|
468
|
-
|
|
469
|
-
File differences:
|
|
470
|
-
settings.json — different
|
|
471
|
-
.env — only in production
|
|
472
|
-
rules/CLAUDE.md — different
|
|
473
|
-
```
|
|
474
|
-
|
|
475
|
-
**Behavior:**
|
|
476
|
-
- Compares `source.json` (managed item map)
|
|
477
|
-
- Lists file presence and content differences
|
|
478
|
-
- Shows which files differ and in which profile they exist
|
|
479
|
-
|
|
480
|
-
---
|
|
481
|
-
|
|
482
|
-
### deactivate
|
|
483
|
-
|
|
484
|
-
Deactivate the currently active non-default profile by switching back to the physical `default` snapshot.
|
|
485
|
-
|
|
486
|
-
```bash
|
|
487
|
-
csp deactivate
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
**Options:**
|
|
491
|
-
- `--no-save` — Skip saving current profile state before deactivation
|
|
492
|
-
|
|
493
|
-
**Behavior:**
|
|
494
|
-
1. Exits early if no active profile or active profile is `default`
|
|
495
|
-
2. Delegates to `csp use default`
|
|
496
|
-
3. Optionally saves the current non-default profile state
|
|
497
|
-
4. Restores the physical `default` snapshot into `~/.claude`
|
|
498
|
-
5. Marks `default` as the active legacy profile
|
|
499
|
-
|
|
500
|
-
---
|
|
47
|
+
## Core Commands
|
|
501
48
|
|
|
502
|
-
|
|
49
|
+
| Command | Description |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `csp` / `csp select` | Interactive profile selector (default) |
|
|
52
|
+
| `csp init` | Initialize and capture current state as `default` profile |
|
|
53
|
+
| `csp create <name>` | Create a new profile (`--from`, `--source`, `-d` options) |
|
|
54
|
+
| `csp launch <name>` | Launch isolated Claude session for a profile |
|
|
55
|
+
| `csp exec <name> -- <cmd>` | Run any command inside isolated profile runtime |
|
|
56
|
+
| `csp use <name>` | Legacy global switch (mutates `~/.claude`) |
|
|
57
|
+
| `csp save` | Save current state to active profile |
|
|
58
|
+
| `csp list` / `csp ls` | List all profiles |
|
|
59
|
+
| `csp status` | Show CSP status dashboard |
|
|
60
|
+
| `csp current` | Show active legacy profile |
|
|
61
|
+
| `csp toggle` | Quick-switch to previous profile |
|
|
62
|
+
| `csp diff <a> <b>` | Compare two profiles |
|
|
63
|
+
| `csp export <name>` | Export profile as `.tar.gz` archive |
|
|
64
|
+
| `csp import <file>` | Import profile from archive |
|
|
65
|
+
| `csp delete <name>` | Delete a profile |
|
|
66
|
+
| `csp deactivate` | Switch back to `default` profile |
|
|
67
|
+
| `csp uninstall` | Remove CSP and restore Claude to pre-CSP state |
|
|
503
68
|
|
|
504
|
-
|
|
69
|
+
> 📖 **Full command reference with all options and detailed behavior:** [docs/commands-reference.md](docs/commands-reference.md)
|
|
505
70
|
|
|
506
|
-
|
|
507
|
-
csp launch <name> [claude-args...]
|
|
508
|
-
csp la <name> [claude-args...]
|
|
509
|
-
```
|
|
510
|
-
|
|
511
|
-
**Options:**
|
|
512
|
-
- `--legacy-global` — Use old behavior (`csp use <name>` then launch)
|
|
71
|
+
## Two Launch Modes
|
|
513
72
|
|
|
514
|
-
|
|
73
|
+
### Isolated Launch (recommended)
|
|
515
74
|
|
|
516
|
-
Launch isolated session:
|
|
517
75
|
```bash
|
|
518
76
|
csp launch work
|
|
519
|
-
```
|
|
520
|
-
|
|
521
|
-
Launch isolated with Claude flags:
|
|
522
|
-
```bash
|
|
523
77
|
csp launch work --dangerously-skip-permissions
|
|
524
78
|
csp la dev --model opus
|
|
525
79
|
```
|
|
526
80
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
**Behavior (default isolated mode):**
|
|
533
|
-
1. Validates target profile exists
|
|
534
|
-
2. Ensures the profile snapshot exists; for legacy installs missing `default/`, guarded backfill only runs when the active profile is `default` or no active profile is set
|
|
535
|
-
3. Prepares per-profile runtime under `~/.claude-profiles/.runtime/<name>`
|
|
536
|
-
4. 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
|
|
537
|
-
5. Strips inherited `CLAUDECODE`, inherited `CLAUDE_CONFIG_DIR`, inherited `ANTHROPIC_*`, and Claude session env vars before applying resolved allowlisted values
|
|
538
|
-
6. Spawns `claude` with `CLAUDE_CONFIG_DIR=<runtimeDir>`
|
|
539
|
-
7. Inherits stdin/stdout/stderr for interactive use
|
|
540
|
-
8. Forwards Claude's exit code
|
|
541
|
-
9. Keeps `.active` unchanged and never mutates global `~/.claude`
|
|
542
|
-
10. Launching `default` preserves its `legacy` mode metadata even though it uses an isolated runtime snapshot
|
|
543
|
-
|
|
544
|
-
`ANTHROPIC_*` keys currently in isolated launch scope:
|
|
545
|
-
- `ANTHROPIC_AUTH_TOKEN`
|
|
546
|
-
- `ANTHROPIC_BASE_URL`
|
|
547
|
-
- `ANTHROPIC_MODEL`
|
|
548
|
-
|
|
549
|
-
Set `CSP_DEBUG_LAUNCH_ENV=1` to print extended launch diagnostics. Do not use in shared logs because it can include resolved `ANTHROPIC_*` values.
|
|
550
|
-
|
|
551
|
-
---
|
|
81
|
+
- Does **not** mutate `~/.claude` or change `.active`
|
|
82
|
+
- Creates per-profile runtime at `~/.claude-profiles/.runtime/<name>`
|
|
83
|
+
- Spawns Claude with `CLAUDE_CONFIG_DIR` pointing to runtime root
|
|
84
|
+
- Supports `ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_BASE_URL`, `ANTHROPIC_MODEL` env resolution
|
|
552
85
|
|
|
553
|
-
###
|
|
86
|
+
### Legacy Global Switch
|
|
554
87
|
|
|
555
|
-
Run an arbitrary command inside isolated profile runtime env. This does **not** change global active profile.
|
|
556
|
-
|
|
557
|
-
```bash
|
|
558
|
-
csp exec <name> -- <command> [args...]
|
|
559
|
-
```
|
|
560
|
-
|
|
561
|
-
**Examples:**
|
|
562
|
-
|
|
563
|
-
Run any CLI tool with profile runtime env:
|
|
564
88
|
```bash
|
|
565
|
-
csp
|
|
566
|
-
|
|
567
|
-
```
|
|
568
|
-
|
|
569
|
-
Run a shell function/alias defined by your interactive shell:
|
|
570
|
-
```bash
|
|
571
|
-
csp exec hd -- claude-hd2
|
|
572
|
-
```
|
|
573
|
-
|
|
574
|
-
**Behavior:**
|
|
575
|
-
1. Validates target profile exists
|
|
576
|
-
2. Ensures the profile snapshot exists; for legacy installs missing `default/`, guarded backfill only runs when the active profile is `default` or no active profile is set
|
|
577
|
-
3. Prepares per-profile runtime under `~/.claude-profiles/.runtime/<name>`
|
|
578
|
-
4. 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
|
|
579
|
-
5. Strips inherited `CLAUDECODE`, inherited `CLAUDE_CONFIG_DIR`, inherited `ANTHROPIC_*`, and Claude session env vars before applying resolved allowlisted values
|
|
580
|
-
6. On Unix-like systems, runs the command through your interactive shell so shell functions/aliases can resolve like a normal terminal command; on Windows, keeps direct spawn behavior with `.cmd` / `.bat` wrapper detection
|
|
581
|
-
7. Reasserts `CLAUDE_CONFIG_DIR` and allowlisted `ANTHROPIC_*` after shell init so profile isolation wins over shell startup overrides
|
|
582
|
-
8. Inherits stdin/stdout/stderr and forwards child exit code
|
|
583
|
-
9. Keeps `.active` unchanged and never mutates global `~/.claude`
|
|
584
|
-
|
|
585
|
-
---
|
|
586
|
-
|
|
587
|
-
### uninstall
|
|
588
|
-
|
|
589
|
-
Remove all profiles and restore Claude Code to its pre-CSP state.
|
|
590
|
-
|
|
591
|
-
```bash
|
|
592
|
-
csp uninstall
|
|
593
|
-
```
|
|
594
|
-
|
|
595
|
-
**Options:**
|
|
596
|
-
- `-f, --force` — Skip confirmation prompt
|
|
597
|
-
- `--profile <name>` — Restore a specific profile instead of the active one
|
|
598
|
-
|
|
599
|
-
**Examples:**
|
|
600
|
-
|
|
601
|
-
Uninstall with confirmation:
|
|
602
|
-
```bash
|
|
603
|
-
csp uninstall
|
|
604
|
-
# Uninstall CSP and remove all profiles? This cannot be undone. (y/N)
|
|
605
|
-
```
|
|
606
|
-
|
|
607
|
-
Restore a specific profile during uninstall:
|
|
608
|
-
```bash
|
|
609
|
-
csp uninstall --profile production
|
|
610
|
-
```
|
|
611
|
-
|
|
612
|
-
Force uninstall without prompt:
|
|
613
|
-
```bash
|
|
614
|
-
csp uninstall --force
|
|
89
|
+
csp use work
|
|
90
|
+
# Restart Claude Code for changes to take effect
|
|
615
91
|
```
|
|
616
92
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
3. If `default` is restored, it uses the physical `default` snapshot like any other profile
|
|
621
|
-
4. Removes `~/.claude-profiles/` entirely
|
|
622
|
-
5. Prints reminder to run `npm uninstall -g claude-switch-profile`
|
|
623
|
-
|
|
624
|
-
---
|
|
93
|
+
- Mutates `~/.claude` directly
|
|
94
|
+
- Updates `.active` marker
|
|
95
|
+
- Requires Claude restart
|
|
625
96
|
|
|
626
97
|
## How Profiles Work
|
|
627
98
|
|
|
628
99
|
### Profile Storage
|
|
629
100
|
|
|
630
|
-
Profiles are stored in `~/.claude-profiles/`:
|
|
631
|
-
|
|
632
101
|
```
|
|
633
102
|
~/.claude-profiles/
|
|
634
|
-
├── .active # Current active profile name (legacy
|
|
103
|
+
├── .active # Current active profile name (legacy)
|
|
635
104
|
├── profiles.json # Metadata for all profiles (v2 schema)
|
|
636
105
|
├── .runtime/ # Isolated launch roots
|
|
637
106
|
│ ├── work/
|
|
@@ -640,329 +109,65 @@ Profiles are stored in `~/.claude-profiles/`:
|
|
|
640
109
|
│ ├── source.json # Managed item map
|
|
641
110
|
│ ├── settings.json # Copied from ~/.claude
|
|
642
111
|
│ ├── .env # Copied from ~/.claude
|
|
643
|
-
│
|
|
644
|
-
│ ├── .ckignore # Copied from ~/.claude
|
|
645
|
-
│ ├── commands/ # Copied from ~/.claude
|
|
646
|
-
│ └── plugins/ # Copied from ~/.claude
|
|
112
|
+
│ └── ...
|
|
647
113
|
└── production/
|
|
648
114
|
├── source.json
|
|
649
|
-
├── settings.json
|
|
650
115
|
└── ...
|
|
651
116
|
```
|
|
652
117
|
|
|
653
118
|
### What Gets Managed
|
|
654
119
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
- `statusline.cjs`, `statusline.sh`, `statusline.ps1` — Custom statusline scripts
|
|
662
|
-
- `.luna.json` — Luna configuration
|
|
663
|
-
|
|
664
|
-
**Copied Files**:
|
|
665
|
-
- `settings.json` — Editor settings
|
|
666
|
-
- `.env`, `.env.example` — Environment variables
|
|
667
|
-
- `.ck.json`, `.ckignore` — Custom settings and ignore patterns
|
|
668
|
-
- `.mcp.json`, `.mcp.json.example` — MCP configuration
|
|
669
|
-
- `.gitignore` — Local ignore settings
|
|
670
|
-
|
|
671
|
-
**Copied Directories**:
|
|
672
|
-
- `commands/`, `plugins/` — Custom commands/plugins
|
|
673
|
-
- `workflows/`, `scripts/` — Automation and workflow assets
|
|
674
|
-
- `output-styles/`, `schemas/` — Output and schema assets
|
|
675
|
-
|
|
676
|
-
**Never Touched** (runtime/session data):
|
|
677
|
-
- `.credentials.json`
|
|
678
|
-
- `projects/`, `sessions/`, `session-env/`, `ide/`
|
|
679
|
-
- `cache/`, `paste-cache/`, `downloads/`, `telemetry/`, `debug/`, `statsig/`
|
|
680
|
-
- `history.jsonl`, `metadata.json`, `stats-cache.json`, `active-plan`
|
|
681
|
-
- `backups/`, `command-archive/`, `commands-archived/`
|
|
682
|
-
- `plans/`, `todos/`, `tasks/`, `teams/`, `agent-memory/`, `file-history/`, `shell-snapshots/`
|
|
683
|
-
- All other protected or session-specific data
|
|
684
|
-
|
|
685
|
-
### Legacy vs Isolated Launch Modes
|
|
686
|
-
|
|
687
|
-
CSP now supports two paths:
|
|
688
|
-
|
|
689
|
-
- **Legacy global mode (`csp use`)**
|
|
690
|
-
- Mutates `~/.claude`
|
|
691
|
-
- Updates `.active`
|
|
692
|
-
- Preserves old behavior for existing scripts
|
|
693
|
-
|
|
694
|
-
- **Isolated launch mode (`csp launch`)**
|
|
695
|
-
- Does not mutate `~/.claude`
|
|
696
|
-
- Does not change `.active`
|
|
697
|
-
- Creates/updates runtime root per profile at `~/.claude-profiles/.runtime/<name>`
|
|
698
|
-
- Launches Claude with `CLAUDE_CONFIG_DIR` pointing to that runtime root
|
|
699
|
-
|
|
700
|
-
### Runtime Sync Policy (isolated launch)
|
|
701
|
-
|
|
702
|
-
For each launch, CSP syncs static profile config into runtime root:
|
|
703
|
-
|
|
704
|
-
- Managed items (`CLAUDE.md`, `rules`, `agents`, `skills`, `hooks`, statusline files, `.luna.json`)
|
|
705
|
-
- Copied files (`settings.json`, `.env`, `.ck.json`, `.ckignore`, etc.)
|
|
706
|
-
- Copied directories (`commands`, `plugins`, `workflows`, `scripts`, ...)
|
|
707
|
-
|
|
708
|
-
Runtime/account continuity stays isolated per runtime root and is not globally swapped.
|
|
120
|
+
| Category | Items |
|
|
121
|
+
|---|---|
|
|
122
|
+
| **Managed Static** | `CLAUDE.md`, `rules/`, `agents/`, `skills/`, `hooks/`, `statusline.*`, `.luna.json` |
|
|
123
|
+
| **Copied Files** | `settings.json`, `.env`, `.ck.json`, `.ckignore`, `.mcp.json`, `.gitignore`, etc. |
|
|
124
|
+
| **Copied Dirs** | `commands/`, `plugins/`, `workflows/`, `scripts/`, `output-styles/`, `schemas/` |
|
|
125
|
+
| **Never Touched** | `.credentials.json`, `projects/`, `sessions/`, `cache/`, `telemetry/`, etc. |
|
|
709
126
|
|
|
710
127
|
## Safety Features
|
|
711
128
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
-
|
|
716
|
-
-
|
|
717
|
-
- Auto-detects stale locks (process no longer running)
|
|
718
|
-
- Throws error if another switch is in progress
|
|
719
|
-
|
|
720
|
-
```
|
|
721
|
-
Another csp operation is running (PID: 12345).
|
|
722
|
-
Remove ~/.claude-profiles/.lock if stale.
|
|
723
|
-
```
|
|
724
|
-
|
|
725
|
-
### Claude Process Detection
|
|
726
|
-
|
|
727
|
-
When switching profiles, CSP detects if Claude Code is running:
|
|
728
|
-
|
|
729
|
-
```
|
|
730
|
-
⚠ Claude Code appears to be running. Restart your Claude session after switching profiles.
|
|
731
|
-
```
|
|
732
|
-
|
|
733
|
-
**Important:** Changes only take effect after restarting Claude Code.
|
|
734
|
-
|
|
735
|
-
### Windows Support
|
|
736
|
-
|
|
737
|
-
Process detection uses `tasklist` instead of `pgrep` on Windows.
|
|
738
|
-
|
|
739
|
-
Export/import commands use the built-in `tar.exe` available on Windows 10+.
|
|
740
|
-
|
|
741
|
-
### Validation
|
|
742
|
-
|
|
743
|
-
Before switching, CSP validates:
|
|
744
|
-
1. Target profile exists
|
|
745
|
-
2. Profile structure is valid
|
|
746
|
-
|
|
747
|
-
During import, CSP also validates profile contents and rejects unsafe symlinks that point outside the imported profile tree.
|
|
748
|
-
|
|
749
|
-
## Configuration via Environment Variables
|
|
750
|
-
|
|
751
|
-
Override default behavior for testing or advanced use:
|
|
752
|
-
|
|
753
|
-
### CSP_HOME
|
|
754
|
-
|
|
755
|
-
Override the home directory (default: `process.env.HOME`).
|
|
756
|
-
|
|
757
|
-
```bash
|
|
758
|
-
CSP_HOME=/tmp/test csp list
|
|
759
|
-
```
|
|
760
|
-
|
|
761
|
-
### CSP_CLAUDE_DIR
|
|
762
|
-
|
|
763
|
-
Override Claude config directory (default: `~/.claude`).
|
|
764
|
-
|
|
765
|
-
```bash
|
|
766
|
-
CSP_CLAUDE_DIR=/tmp/test-claude csp init
|
|
767
|
-
```
|
|
768
|
-
|
|
769
|
-
### CSP_PROFILES_DIR
|
|
770
|
-
|
|
771
|
-
Override profiles storage directory (default: `~/.claude-profiles`).
|
|
772
|
-
|
|
773
|
-
```bash
|
|
774
|
-
CSP_PROFILES_DIR=/tmp/test-profiles csp list
|
|
775
|
-
```
|
|
776
|
-
|
|
777
|
-
**Use case:** Testing in isolated environments without affecting your real configuration.
|
|
129
|
+
- **Lock file** — prevents concurrent profile switches (PID-based, auto-detects stale locks)
|
|
130
|
+
- **Claude process detection** — warns when Claude is running during switch
|
|
131
|
+
- **Import validation** — rejects unsafe symlinks pointing outside profile tree
|
|
132
|
+
- **Profile validation** — checks structure before applying
|
|
133
|
+
- **Auto-backups** — created before destructive operations
|
|
778
134
|
|
|
779
135
|
## Workflow Examples
|
|
780
136
|
|
|
781
|
-
###
|
|
137
|
+
### Work vs. Personal
|
|
782
138
|
|
|
783
139
|
```bash
|
|
784
|
-
# Initial setup
|
|
785
140
|
csp init
|
|
786
|
-
|
|
787
|
-
# Create work profile
|
|
788
|
-
csp create work -d "Work environment with company rules"
|
|
789
|
-
# ... modify rules, settings, etc. ...
|
|
790
|
-
csp save
|
|
791
|
-
|
|
792
|
-
# Create personal profile
|
|
793
|
-
csp use default
|
|
141
|
+
csp create work -d "Work environment"
|
|
794
142
|
csp create personal -d "Personal projects"
|
|
795
|
-
csp save
|
|
796
|
-
|
|
797
|
-
# Switch between them
|
|
798
|
-
csp use work # Switch to work
|
|
799
|
-
csp use personal # Switch to personal
|
|
800
|
-
```
|
|
801
143
|
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
# Clone current profile
|
|
806
|
-
csp create experimental --from default -d "Testing new Luna skills"
|
|
807
|
-
|
|
808
|
-
# Switch and experiment
|
|
809
|
-
csp use experimental
|
|
810
|
-
# ... install new skills, modify rules ...
|
|
811
|
-
csp save
|
|
812
|
-
|
|
813
|
-
# If good, merge back to default
|
|
814
|
-
csp diff current default
|
|
815
|
-
# ... review differences ...
|
|
816
|
-
csp use default
|
|
817
|
-
# ... copy changes manually or recreate ...
|
|
818
|
-
|
|
819
|
-
# Clean up
|
|
820
|
-
csp delete experimental
|
|
144
|
+
# Launch whichever you need
|
|
145
|
+
csp launch work
|
|
146
|
+
csp launch personal
|
|
821
147
|
```
|
|
822
148
|
|
|
823
|
-
###
|
|
149
|
+
### Backup and Restore
|
|
824
150
|
|
|
825
151
|
```bash
|
|
826
|
-
# Backup production profile
|
|
827
152
|
csp export production -o ~/backups/production-2026-03.tar.gz
|
|
828
|
-
|
|
829
|
-
# ... time passes ...
|
|
830
|
-
|
|
831
|
-
# Restore if needed
|
|
832
153
|
csp import ~/backups/production-2026-03.tar.gz -n production-restored
|
|
833
|
-
csp use production-restored
|
|
834
154
|
```
|
|
835
155
|
|
|
836
|
-
###
|
|
156
|
+
### Share with Team
|
|
837
157
|
|
|
838
158
|
```bash
|
|
839
|
-
# Export your setup
|
|
840
159
|
csp export my-setup -o ./my-setup.csp.tar.gz
|
|
841
|
-
|
|
842
|
-
# Teammate imports
|
|
160
|
+
# Teammate:
|
|
843
161
|
csp import my-setup.csp.tar.gz -n shared-team-setup
|
|
844
|
-
csp use shared-team-setup
|
|
845
162
|
```
|
|
846
163
|
|
|
847
|
-
##
|
|
164
|
+
## Documentation
|
|
848
165
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
```bash
|
|
856
|
-
csp init
|
|
857
|
-
```
|
|
858
|
-
|
|
859
|
-
### Profile doesn't exist
|
|
860
|
-
|
|
861
|
-
**Error:** `Profile "name" does not exist. Run "csp list" to see available profiles.`
|
|
862
|
-
|
|
863
|
-
**Solution:** Check available profiles and use exact name.
|
|
864
|
-
|
|
865
|
-
```bash
|
|
866
|
-
csp list
|
|
867
|
-
csp use production # if "production" exists
|
|
868
|
-
```
|
|
869
|
-
|
|
870
|
-
### Cannot delete default profile
|
|
871
|
-
|
|
872
|
-
**Error:** `Cannot delete the default profile.`
|
|
873
|
-
|
|
874
|
-
**Solution:** Keep `default` and delete only non-default profiles.
|
|
875
|
-
|
|
876
|
-
```bash
|
|
877
|
-
csp delete experimental
|
|
878
|
-
```
|
|
879
|
-
|
|
880
|
-
### Stale lock file
|
|
881
|
-
|
|
882
|
-
**Error:** `Another csp operation is running (PID: 12345). Remove ~/.claude-profiles/.lock if stale.`
|
|
883
|
-
|
|
884
|
-
**Solution:** If the process is not running, manually remove the lock:
|
|
885
|
-
|
|
886
|
-
```bash
|
|
887
|
-
rm ~/.claude-profiles/.lock
|
|
888
|
-
```
|
|
889
|
-
|
|
890
|
-
### Invalid profile structure
|
|
891
|
-
|
|
892
|
-
**Error:** `Profile "name" is invalid: Missing source.json — no managed items defined`
|
|
893
|
-
|
|
894
|
-
**Solution:** Recreate the profile or import a valid profile archive.
|
|
895
|
-
|
|
896
|
-
### Changes not applying
|
|
897
|
-
|
|
898
|
-
**Issue:** Switched profiles but changes don't appear in Claude Code.
|
|
899
|
-
|
|
900
|
-
**Solution:** Restart Claude Code session after switching.
|
|
901
|
-
|
|
902
|
-
```bash
|
|
903
|
-
csp use staging
|
|
904
|
-
# Close and restart Claude Code
|
|
905
|
-
```
|
|
906
|
-
|
|
907
|
-
## Development
|
|
908
|
-
|
|
909
|
-
### Run Tests
|
|
910
|
-
|
|
911
|
-
```bash
|
|
912
|
-
npm test # All tests
|
|
913
|
-
npm run test:core # Core library tests
|
|
914
|
-
npm run test:cli # CLI integration tests
|
|
915
|
-
npm run test:safety # Safety feature tests
|
|
916
|
-
```
|
|
917
|
-
|
|
918
|
-
### Changelog
|
|
919
|
-
|
|
920
|
-
See [CHANGELOG.md](CHANGELOG.md) for version history and migration guidance.
|
|
921
|
-
|
|
922
|
-
### Project Structure
|
|
923
|
-
|
|
924
|
-
```
|
|
925
|
-
.
|
|
926
|
-
├── bin/
|
|
927
|
-
│ └── csp.js # CLI entry point
|
|
928
|
-
├── src/
|
|
929
|
-
│ ├── commands/ # Command implementations
|
|
930
|
-
│ │ ├── init.js
|
|
931
|
-
│ │ ├── current.js
|
|
932
|
-
│ │ ├── list.js
|
|
933
|
-
│ │ ├── status.js
|
|
934
|
-
│ │ ├── create.js
|
|
935
|
-
│ │ ├── save.js
|
|
936
|
-
│ │ ├── use.js
|
|
937
|
-
│ │ ├── toggle.js
|
|
938
|
-
│ │ ├── delete.js
|
|
939
|
-
│ │ ├── export.js
|
|
940
|
-
│ │ ├── import.js
|
|
941
|
-
│ │ ├── diff.js
|
|
942
|
-
│ │ ├── select.js
|
|
943
|
-
│ │ ├── launch.js
|
|
944
|
-
│ │ ├── deactivate.js
|
|
945
|
-
│ │ └── uninstall.js
|
|
946
|
-
│ ├── constants.js # Configuration constants
|
|
947
|
-
│ ├── platform.js # Cross-platform compatibility
|
|
948
|
-
│ ├── profile-store.js # Profile metadata management
|
|
949
|
-
│ ├── runtime-instance-manager.js # Isolated runtime sync
|
|
950
|
-
│ ├── item-manager.js # Managed item copy/move operations
|
|
951
|
-
│ ├── file-operations.js # File copy/restore operations
|
|
952
|
-
│ ├── launch-effective-env-resolver.js # ANTHROPIC_* launch env resolution
|
|
953
|
-
│ ├── safety.js # Locking, backups, validation
|
|
954
|
-
│ ├── profile-validator.js # Profile validation
|
|
955
|
-
│ └── output-helpers.js # Console output formatting
|
|
956
|
-
├── tests/
|
|
957
|
-
│ ├── core-library.test.js
|
|
958
|
-
│ ├── cli-integration.test.js
|
|
959
|
-
│ └── safety.test.js
|
|
960
|
-
└── package.json
|
|
961
|
-
```
|
|
962
|
-
|
|
963
|
-
## Planned / Future Features
|
|
964
|
-
|
|
965
|
-
- Automatic backups during profile switch flow (`csp use`) with backup retention/pruning.
|
|
166
|
+
- [Commands Reference](docs/commands-reference.md) — Full command options, behavior, and troubleshooting
|
|
167
|
+
- [System Architecture](docs/system-architecture.md) — Module architecture, data flows, and internals
|
|
168
|
+
- [Project Overview](docs/project-overview-pdr.md) — Product design review and requirements
|
|
169
|
+
- [Code Standards](docs/code-standards.md) — Coding conventions and guidelines
|
|
170
|
+
- [Changelog](CHANGELOG.md) — Version history and migration guidance
|
|
966
171
|
|
|
967
172
|
## License
|
|
968
173
|
|
|
@@ -970,8 +175,4 @@ MIT
|
|
|
970
175
|
|
|
971
176
|
## Contributing
|
|
972
177
|
|
|
973
|
-
Contributions welcome!
|
|
974
|
-
|
|
975
|
-
```bash
|
|
976
|
-
npm test
|
|
977
|
-
```
|
|
178
|
+
Contributions welcome! See the [docs/](docs/) for architecture and code standards.
|
package/package.json
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
readlinkSync,
|
|
12
12
|
} from 'node:fs';
|
|
13
13
|
import { join, dirname } from 'node:path';
|
|
14
|
+
import { homedir } from 'node:os';
|
|
14
15
|
import { MANAGED_ITEMS, COPY_ITEMS, COPY_DIRS, CLAUDE_DIR } from './constants.js';
|
|
15
16
|
import {
|
|
16
17
|
getActive,
|
|
@@ -76,6 +77,8 @@ const shouldSyncDir = (src, dest) => {
|
|
|
76
77
|
}
|
|
77
78
|
};
|
|
78
79
|
|
|
80
|
+
const escapeRegExp = (string) => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
81
|
+
|
|
79
82
|
const replacePathVariants = (content, fromPath, toPath) => {
|
|
80
83
|
const fromEscaped = fromPath.replaceAll('\\', '\\\\');
|
|
81
84
|
const toEscaped = toPath.replaceAll('\\', '\\\\');
|
|
@@ -83,10 +86,20 @@ const replacePathVariants = (content, fromPath, toPath) => {
|
|
|
83
86
|
const toFwd = toPath.replaceAll('\\', '/');
|
|
84
87
|
|
|
85
88
|
let updated = content;
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
|
|
90
|
+
// Prevent matching substrings of other paths (e.g. ~/.claude matching ~/.claude-profiles)
|
|
91
|
+
// by ensuring it's not immediately followed by an alphanumeric character or hyphen.
|
|
92
|
+
const negativeLookahead = '(?![a-zA-Z0-9\\-])';
|
|
93
|
+
|
|
94
|
+
const replaceWithRegex = (str, targetF, targetT) => {
|
|
95
|
+
const re = new RegExp(escapeRegExp(targetF) + negativeLookahead, 'g');
|
|
96
|
+
return str.replace(re, targetT);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
updated = replaceWithRegex(updated, fromEscaped, toEscaped);
|
|
100
|
+
updated = replaceWithRegex(updated, fromFwd, toFwd);
|
|
88
101
|
if (fromPath !== fromEscaped) {
|
|
89
|
-
updated = updated
|
|
102
|
+
updated = replaceWithRegex(updated, fromPath, toPath);
|
|
90
103
|
}
|
|
91
104
|
|
|
92
105
|
return updated;
|
|
@@ -103,6 +116,25 @@ const rewriteSettingsForRuntime = (runtimeDir, sourceDir) => {
|
|
|
103
116
|
updated = replacePathVariants(updated, sourceDir, runtimeDir);
|
|
104
117
|
updated = replacePathVariants(updated, CLAUDE_DIR, runtimeDir);
|
|
105
118
|
|
|
119
|
+
// Also replace shell variable patterns commonly used in hook commands.
|
|
120
|
+
// Hook commands in settings.json often reference paths like:
|
|
121
|
+
// $HOME/.claude/hooks/... or ${HOME}/.claude/hooks/... or ~/.claude/hooks/...
|
|
122
|
+
// These won't match the literal path replacement above.
|
|
123
|
+
const home = homedir();
|
|
124
|
+
const claudeRelSuffix = CLAUDE_DIR.startsWith(home) ? CLAUDE_DIR.slice(home.length) : '/.claude';
|
|
125
|
+
|
|
126
|
+
const shellPatterns = [
|
|
127
|
+
`$HOME${claudeRelSuffix}`,
|
|
128
|
+
`\${HOME}${claudeRelSuffix}`,
|
|
129
|
+
`~${claudeRelSuffix}`,
|
|
130
|
+
];
|
|
131
|
+
|
|
132
|
+
for (const pattern of shellPatterns) {
|
|
133
|
+
if (updated.includes(pattern)) {
|
|
134
|
+
updated = updated.replaceAll(pattern, runtimeDir);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
106
138
|
if (updated !== raw) {
|
|
107
139
|
writeFileSync(settingsPath, updated);
|
|
108
140
|
}
|