@synth1s/cloak 1.4.1 → 1.5.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/README.md +41 -0
- package/package.json +1 -1
- package/src/commands/create.js +9 -11
- package/src/commands/delete.js +9 -9
- package/src/commands/list.js +5 -8
- package/src/commands/rename.js +7 -7
- package/src/commands/switch.js +17 -17
- package/src/commands/whoami.js +2 -2
- package/src/lib/messages.js +149 -0
- package/src/lib/tip.js +2 -5
package/README.md
CHANGED
|
@@ -98,6 +98,47 @@ Each cloak is an isolated directory that acts as a [`CLAUDE_CONFIG_DIR`](https:/
|
|
|
98
98
|
|
|
99
99
|
When you run `claude -a work`, Cloak sets `CLAUDE_CONFIG_DIR=~/.cloak/profiles/work` in your current shell and launches Claude Code. Each terminal gets its own environment, so you can wear different cloaks simultaneously.
|
|
100
100
|
|
|
101
|
+
## FAQ
|
|
102
|
+
|
|
103
|
+
### Will switching accounts overwrite my settings or preferences?
|
|
104
|
+
|
|
105
|
+
No. Each account is a completely isolated directory. Switching only changes which directory Claude Code reads from — it doesn't copy, move, or overwrite any files. Your settings, MCP servers, and preferences for each account stay exactly where they are.
|
|
106
|
+
|
|
107
|
+
### Can I lose data when running multiple accounts simultaneously?
|
|
108
|
+
|
|
109
|
+
No, as long as each terminal uses a **different** account. Each account has its own directory (`~/.cloak/profiles/<name>/`), so there's no file overlap. Terminal A writing to `work/` and Terminal B writing to `home/` never interfere.
|
|
110
|
+
|
|
111
|
+
### What about token renewals? Are they preserved when I switch?
|
|
112
|
+
|
|
113
|
+
Yes. When Claude Code renews your OAuth token during a session, it writes the new token to the active account's directory. When you switch away and back, the renewed token is still there — Cloak never touches those files.
|
|
114
|
+
|
|
115
|
+
### What happens if I create a new account? Does it affect existing ones?
|
|
116
|
+
|
|
117
|
+
No. `cloak create` copies your current session into a **new** directory. Existing accounts are not modified. It's a snapshot, not a move.
|
|
118
|
+
|
|
119
|
+
### What if I run the same account in two terminals at once?
|
|
120
|
+
|
|
121
|
+
This is not recommended. Two Claude Code instances writing to the same directory (`~/.cloak/profiles/work/`) can cause token conflicts. This is a Claude Code limitation, not specific to Cloak — the same issue exists without Cloak if you open two `claude` instances normally.
|
|
122
|
+
|
|
123
|
+
### What happens if I uninstall Cloak?
|
|
124
|
+
|
|
125
|
+
Your account directories remain in `~/.cloak/`. Claude Code continues to work normally with its default config. To use a saved account manually, set the environment variable:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
export CLAUDE_CONFIG_DIR=~/.cloak/profiles/work
|
|
129
|
+
claude
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
To clean up completely: `rm -rf ~/.cloak`
|
|
133
|
+
|
|
134
|
+
### Is my auth token safe?
|
|
135
|
+
|
|
136
|
+
Cloak never transmits, logs, or modifies your tokens. It only copies files during `cloak create` (from Claude Code's config to a profile directory) and changes an environment variable during `cloak switch`. All data stays local on your machine.
|
|
137
|
+
|
|
138
|
+
### Does Cloak work with Claude Code IDE extensions (VSCode, JetBrains)?
|
|
139
|
+
|
|
140
|
+
IDE extensions may not respect `CLAUDE_CONFIG_DIR` ([known limitation](https://github.com/anthropics/claude-code/issues/4739)). Cloak is designed for terminal-based Claude Code usage.
|
|
141
|
+
|
|
101
142
|
## Requirements
|
|
102
143
|
|
|
103
144
|
- Node.js >= 18
|
package/package.json
CHANGED
package/src/commands/create.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { existsSync, copyFileSync, mkdirSync } from 'fs'
|
|
2
|
-
import chalk from 'chalk'
|
|
3
2
|
import inquirer from 'inquirer'
|
|
4
3
|
import {
|
|
5
4
|
claudeAuthPath,
|
|
@@ -11,14 +10,14 @@ import {
|
|
|
11
10
|
ensureProfilesDir,
|
|
12
11
|
} from '../lib/paths.js'
|
|
13
12
|
import { validateAccountName } from '../lib/validate.js'
|
|
13
|
+
import * as msg from '../lib/messages.js'
|
|
14
14
|
|
|
15
15
|
export async function createAccount(name, options = {}) {
|
|
16
|
-
// Interactive prompt if no name given
|
|
17
16
|
if (!name) {
|
|
18
17
|
const answer = await inquirer.prompt([{
|
|
19
18
|
type: 'input',
|
|
20
19
|
name: 'accountName',
|
|
21
|
-
message:
|
|
20
|
+
message: msg.prompts.accountName,
|
|
22
21
|
validate: (v) => {
|
|
23
22
|
const result = validateAccountName(v.trim())
|
|
24
23
|
return result.valid || result.error
|
|
@@ -29,37 +28,36 @@ export async function createAccount(name, options = {}) {
|
|
|
29
28
|
|
|
30
29
|
const validation = validateAccountName(name)
|
|
31
30
|
if (!validation.valid) {
|
|
32
|
-
console.error(
|
|
31
|
+
console.error(msg.validationError(validation.error))
|
|
33
32
|
process.exit(1)
|
|
34
33
|
return
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
const authSource = claudeAuthPath()
|
|
38
37
|
if (!existsSync(authSource)) {
|
|
39
|
-
console.error(
|
|
40
|
-
console.log(
|
|
38
|
+
console.error(msg.noActiveSession())
|
|
39
|
+
console.log(msg.loginFirst())
|
|
41
40
|
process.exit(1)
|
|
42
41
|
return
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
if (profileExists(name)) {
|
|
46
45
|
if (options.confirm === false) {
|
|
47
|
-
console.log(
|
|
46
|
+
console.log(msg.cancelled())
|
|
48
47
|
return
|
|
49
48
|
}
|
|
50
49
|
if (options.confirm === undefined) {
|
|
51
50
|
const { overwrite } = await inquirer.prompt([{
|
|
52
51
|
type: 'confirm',
|
|
53
52
|
name: 'overwrite',
|
|
54
|
-
message:
|
|
53
|
+
message: msg.prompts.overwriteConfirm(name),
|
|
55
54
|
default: false,
|
|
56
55
|
}])
|
|
57
56
|
if (!overwrite) {
|
|
58
|
-
console.log(
|
|
57
|
+
console.log(msg.cancelled())
|
|
59
58
|
return
|
|
60
59
|
}
|
|
61
60
|
}
|
|
62
|
-
// options.confirm === true → proceed
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
ensureProfilesDir()
|
|
@@ -73,5 +71,5 @@ export async function createAccount(name, options = {}) {
|
|
|
73
71
|
copyFileSync(settingsSource, profileSettingsPath(name))
|
|
74
72
|
}
|
|
75
73
|
|
|
76
|
-
console.log(
|
|
74
|
+
console.log(msg.cloakCreated(name))
|
|
77
75
|
}
|
package/src/commands/delete.js
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
import { rmSync } from 'fs'
|
|
2
|
-
import chalk from 'chalk'
|
|
3
2
|
import inquirer from 'inquirer'
|
|
4
3
|
import { profileDir, profileExists, getActiveProfile } from '../lib/paths.js'
|
|
5
4
|
import { validateAccountName } from '../lib/validate.js'
|
|
5
|
+
import * as msg from '../lib/messages.js'
|
|
6
6
|
|
|
7
7
|
export async function deleteAccount(name, options = {}) {
|
|
8
8
|
const validation = validateAccountName(name)
|
|
9
9
|
if (!validation.valid) {
|
|
10
|
-
console.error(
|
|
10
|
+
console.error(msg.validationError(validation.error))
|
|
11
11
|
process.exit(1)
|
|
12
12
|
return
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
if (!profileExists(name)) {
|
|
16
|
-
console.error(
|
|
16
|
+
console.error(msg.accountNotFound(name))
|
|
17
17
|
process.exit(1)
|
|
18
18
|
return
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
if (getActiveProfile() === name) {
|
|
22
|
-
console.error(
|
|
23
|
-
console.log(
|
|
22
|
+
console.error(msg.cannotDiscardActive())
|
|
23
|
+
console.log(msg.suggestSwitchFirst())
|
|
24
24
|
process.exit(1)
|
|
25
25
|
return
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
if (options.confirm === false) {
|
|
29
|
-
console.log(
|
|
29
|
+
console.log(msg.cancelled())
|
|
30
30
|
return
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -34,15 +34,15 @@ export async function deleteAccount(name, options = {}) {
|
|
|
34
34
|
const { confirm } = await inquirer.prompt([{
|
|
35
35
|
type: 'confirm',
|
|
36
36
|
name: 'confirm',
|
|
37
|
-
message:
|
|
37
|
+
message: msg.prompts.deleteConfirm(name),
|
|
38
38
|
default: false,
|
|
39
39
|
}])
|
|
40
40
|
if (!confirm) {
|
|
41
|
-
console.log(
|
|
41
|
+
console.log(msg.cancelled())
|
|
42
42
|
return
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
rmSync(profileDir(name), { recursive: true, force: true })
|
|
47
|
-
console.log(
|
|
47
|
+
console.log(msg.cloakDiscarded(name))
|
|
48
48
|
}
|
package/src/commands/list.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import chalk from 'chalk'
|
|
2
1
|
import { listProfileNames, getActiveProfile } from '../lib/paths.js'
|
|
2
|
+
import * as msg from '../lib/messages.js'
|
|
3
3
|
|
|
4
4
|
export function listAccounts() {
|
|
5
5
|
const names = listProfileNames().sort()
|
|
@@ -11,17 +11,14 @@ export function listAccounts() {
|
|
|
11
11
|
}))
|
|
12
12
|
|
|
13
13
|
if (accounts.length === 0) {
|
|
14
|
-
console.log(
|
|
15
|
-
console.log(
|
|
14
|
+
console.log(msg.noCloaksYet())
|
|
15
|
+
console.log(msg.suggestCreate())
|
|
16
16
|
return accounts
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
console.log(
|
|
19
|
+
console.log(msg.accountListHeader())
|
|
20
20
|
accounts.forEach(({ name, active: isActive }) => {
|
|
21
|
-
|
|
22
|
-
const label = isActive ? chalk.green.bold(name) : chalk.white(name)
|
|
23
|
-
const tag = isActive ? chalk.green(' (active)') : ''
|
|
24
|
-
console.log(` ${marker}${label}${tag}`)
|
|
21
|
+
console.log(msg.accountListItem(name, isActive))
|
|
25
22
|
})
|
|
26
23
|
console.log()
|
|
27
24
|
|
package/src/commands/rename.js
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
import { renameSync } from 'fs'
|
|
2
|
-
import chalk from 'chalk'
|
|
3
2
|
import { profileDir, profileExists, getActiveProfile } from '../lib/paths.js'
|
|
4
3
|
import { validateAccountName } from '../lib/validate.js'
|
|
4
|
+
import * as msg from '../lib/messages.js'
|
|
5
5
|
|
|
6
6
|
export async function renameAccount(oldName, newName) {
|
|
7
7
|
const oldValidation = validateAccountName(oldName)
|
|
8
8
|
if (!oldValidation.valid) {
|
|
9
|
-
console.error(
|
|
9
|
+
console.error(msg.validationError(oldValidation.error))
|
|
10
10
|
process.exit(1)
|
|
11
11
|
return
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
const newValidation = validateAccountName(newName)
|
|
15
15
|
if (!newValidation.valid) {
|
|
16
|
-
console.error(
|
|
16
|
+
console.error(msg.validationError(newValidation.error))
|
|
17
17
|
process.exit(1)
|
|
18
18
|
return
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
if (!profileExists(oldName)) {
|
|
22
|
-
console.error(
|
|
22
|
+
console.error(msg.accountNotFound(oldName))
|
|
23
23
|
process.exit(1)
|
|
24
24
|
return
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
if (profileExists(newName)) {
|
|
28
|
-
console.error(
|
|
28
|
+
console.error(msg.accountAlreadyInUse(newName))
|
|
29
29
|
process.exit(1)
|
|
30
30
|
return
|
|
31
31
|
}
|
|
@@ -33,8 +33,8 @@ export async function renameAccount(oldName, newName) {
|
|
|
33
33
|
renameSync(profileDir(oldName), profileDir(newName))
|
|
34
34
|
|
|
35
35
|
if (getActiveProfile() === oldName) {
|
|
36
|
-
console.log(
|
|
36
|
+
console.log(msg.updateSessionAfterRename(newName))
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
console.log(
|
|
39
|
+
console.log(msg.cloakRenamed(oldName, newName))
|
|
40
40
|
}
|
package/src/commands/switch.js
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
import chalk from 'chalk'
|
|
2
1
|
import inquirer from 'inquirer'
|
|
3
2
|
import { profileDir, profileExists, getActiveProfile } from '../lib/paths.js'
|
|
4
3
|
import { validateAccountName } from '../lib/validate.js'
|
|
5
4
|
import { getRcFilePath, isAlreadyInstalled, installToRcFile } from '../lib/setup.js'
|
|
5
|
+
import * as msg from '../lib/messages.js'
|
|
6
6
|
|
|
7
7
|
export async function switchAccount(name, options = {}) {
|
|
8
8
|
const validation = validateAccountName(name)
|
|
9
9
|
if (!validation.valid) {
|
|
10
|
-
console.error(
|
|
10
|
+
console.error(msg.validationError(validation.error))
|
|
11
11
|
process.exit(1)
|
|
12
12
|
return
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
if (!profileExists(name)) {
|
|
16
|
-
console.error(
|
|
17
|
-
console.log(
|
|
16
|
+
console.error(msg.accountNotFound(name))
|
|
17
|
+
console.log(msg.suggestCreate(name))
|
|
18
18
|
process.exit(1)
|
|
19
19
|
return
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
const active = getActiveProfile()
|
|
23
23
|
if (active === name) {
|
|
24
|
-
console.log(
|
|
24
|
+
console.log(msg.alreadyWearing(name))
|
|
25
25
|
return
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const dir = profileDir(name)
|
|
29
29
|
|
|
30
|
-
// Shell integration is active — output for eval
|
|
31
30
|
if (options.printEnv) {
|
|
32
|
-
process.stdout.write(
|
|
33
|
-
process.stdout.write(
|
|
31
|
+
process.stdout.write(msg.printEnvExport(dir))
|
|
32
|
+
process.stdout.write(msg.printEnvEcho(name))
|
|
34
33
|
return
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
// No shell integration — prompt user to set it up
|
|
38
|
-
console.log(
|
|
37
|
+
console.log('\n' + msg.switchRequired() + '\n')
|
|
39
38
|
|
|
40
39
|
let choice = options.setupChoice
|
|
41
40
|
if (choice === undefined) {
|
|
42
41
|
const answer = await inquirer.prompt([{
|
|
43
42
|
type: 'list',
|
|
44
43
|
name: 'choice',
|
|
45
|
-
message:
|
|
44
|
+
message: msg.prompts.setupChoice,
|
|
46
45
|
choices: [
|
|
47
|
-
{ name:
|
|
48
|
-
{ name:
|
|
46
|
+
{ name: msg.prompts.setupAuto, value: 'auto' },
|
|
47
|
+
{ name: msg.prompts.setupManual, value: 'manual' },
|
|
49
48
|
],
|
|
50
49
|
}])
|
|
51
50
|
choice = answer.choice
|
|
52
51
|
}
|
|
53
52
|
|
|
53
|
+
const rcFile = getRcFilePath()
|
|
54
|
+
|
|
54
55
|
if (choice === 'auto') {
|
|
55
|
-
const rcFile = getRcFilePath()
|
|
56
56
|
if (!isAlreadyInstalled(rcFile)) {
|
|
57
57
|
installToRcFile(rcFile)
|
|
58
|
-
console.log(
|
|
58
|
+
console.log(msg.shellIntegrationAdded(rcFile))
|
|
59
59
|
} else {
|
|
60
|
-
console.log(
|
|
60
|
+
console.log(msg.alreadyInstalled(rcFile))
|
|
61
61
|
}
|
|
62
|
-
console.log(
|
|
62
|
+
console.log(msg.setupRunCommand(rcFile, name))
|
|
63
63
|
} else {
|
|
64
|
-
console.log(
|
|
64
|
+
console.log(msg.setupManualCommand(rcFile, name))
|
|
65
65
|
}
|
|
66
66
|
}
|
package/src/commands/whoami.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import chalk from 'chalk'
|
|
2
1
|
import { getActiveProfile } from '../lib/paths.js'
|
|
2
|
+
import * as msg from '../lib/messages.js'
|
|
3
3
|
|
|
4
4
|
export function whoami() {
|
|
5
5
|
const active = getActiveProfile()
|
|
6
6
|
if (!active) {
|
|
7
|
-
console.log(
|
|
7
|
+
console.log(msg.noCloak())
|
|
8
8
|
return null
|
|
9
9
|
}
|
|
10
10
|
console.log(active)
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import chalk from 'chalk'
|
|
2
|
+
|
|
3
|
+
// Icons — consistent across all messages
|
|
4
|
+
const icon = {
|
|
5
|
+
success: chalk.green('✔'),
|
|
6
|
+
error: chalk.red('✖'),
|
|
7
|
+
warning: chalk.yellow('⚠'),
|
|
8
|
+
info: chalk.blue('ℹ'),
|
|
9
|
+
tip: '💡',
|
|
10
|
+
active: chalk.green('●'),
|
|
11
|
+
inactive: chalk.dim('○'),
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// --- Success messages ---
|
|
15
|
+
|
|
16
|
+
export function cloakCreated(name) {
|
|
17
|
+
return `${icon.success} Cloak ${chalk.bold(`"${name}"`)} created.`
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function cloakSwitched(name) {
|
|
21
|
+
return `${icon.success} Now wearing cloak ${chalk.bold(`"${name}"`)}.`
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function cloakDiscarded(name) {
|
|
25
|
+
return `${icon.success} Cloak ${chalk.bold(`"${name}"`)} discarded.`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function cloakRenamed(oldName, newName) {
|
|
29
|
+
return `${icon.success} Cloak ${chalk.bold(`"${oldName}"`)} renamed to ${chalk.bold(`"${newName}"`)}.`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function shellIntegrationAdded(rcFile) {
|
|
33
|
+
return `${icon.success} Shell integration added to ${chalk.bold(rcFile)}`
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// --- Error messages ---
|
|
37
|
+
|
|
38
|
+
export function validationError(error) {
|
|
39
|
+
return `${icon.error} ${error}`
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function accountNotFound(name) {
|
|
43
|
+
return `${icon.error} Account ${chalk.bold(`"${name}"`)} not found.`
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function noActiveSession() {
|
|
47
|
+
return `${icon.error} No active Claude Code session found.`
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function cannotDiscardActive() {
|
|
51
|
+
return `${icon.error} Can't discard a cloak you're wearing.`
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function accountAlreadyInUse(name) {
|
|
55
|
+
return `${icon.error} Account ${chalk.bold(`"${name}"`)} is already in use.`
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// --- Warning messages ---
|
|
59
|
+
|
|
60
|
+
export function alreadyWearing(name) {
|
|
61
|
+
return `${icon.warning} Already wearing cloak ${chalk.bold(`"${name}"`)}.`
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function switchRequired() {
|
|
65
|
+
return `${icon.warning} Shell integration is required to switch accounts.`
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function updateSessionAfterRename(newName) {
|
|
69
|
+
return `${icon.warning} Run ${chalk.white(`claude account switch ${newName}`)} to update your session.`
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// --- Info / hints ---
|
|
73
|
+
|
|
74
|
+
export function suggestCreate(name) {
|
|
75
|
+
return chalk.dim(` Run: claude account create ${name || '<name>'}`)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function suggestSwitchFirst() {
|
|
79
|
+
return chalk.dim(' Switch to another account first.')
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function loginFirst() {
|
|
83
|
+
return chalk.dim(' Open Claude Code and log in first.')
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function cancelled() {
|
|
87
|
+
return chalk.dim('Cancelled.')
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function noCloak() {
|
|
91
|
+
return chalk.dim('No cloak. Using default Claude Code config.')
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function noCloaksYet() {
|
|
95
|
+
return chalk.dim('No cloaks in your wardrobe yet.')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function accountListHeader() {
|
|
99
|
+
return chalk.bold('\nClaude Code Accounts\n')
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function accountListItem(name, isActive) {
|
|
103
|
+
const marker = isActive ? icon.active : icon.inactive
|
|
104
|
+
const label = isActive ? chalk.green.bold(name) : chalk.white(name)
|
|
105
|
+
const tag = isActive ? chalk.green(' (active)') : ''
|
|
106
|
+
return ` ${marker} ${label}${tag}`
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function alreadyInstalled(rcFile) {
|
|
110
|
+
return chalk.dim(` Already installed in ${rcFile}`)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// --- Setup instructions ---
|
|
114
|
+
|
|
115
|
+
export function setupRunCommand(rcFile, name) {
|
|
116
|
+
return chalk.dim('\n Run: ') + chalk.white(`source ${rcFile} && cloak switch ${name}\n`)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function setupManualCommand(rcFile, name) {
|
|
120
|
+
return chalk.dim('\n Run: ') + chalk.white(`echo 'eval "$(cloak init)"' >> ${rcFile} && source ${rcFile} && cloak switch ${name}\n`)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// --- Tip ---
|
|
124
|
+
|
|
125
|
+
export function shellIntegrationTip() {
|
|
126
|
+
return chalk.dim('\n💡 Tip: Run this once to enable "claude -a" and "claude account":\n') +
|
|
127
|
+
chalk.dim(' echo \'eval "$(cloak init)"\' >> ~/.bashrc && source ~/.bashrc\n\n')
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// --- Print-env (stdout, no chalk — evaluated by shell) ---
|
|
131
|
+
|
|
132
|
+
export function printEnvExport(dir) {
|
|
133
|
+
return `export CLAUDE_CONFIG_DIR=${dir}\n`
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function printEnvEcho(name) {
|
|
137
|
+
return `echo "${cloakSwitched(name)}"\n`
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// --- Prompt messages ---
|
|
141
|
+
|
|
142
|
+
export const prompts = {
|
|
143
|
+
accountName: 'Account name:',
|
|
144
|
+
overwriteConfirm: (name) => `Cloak "${name}" already exists. Overwrite?`,
|
|
145
|
+
deleteConfirm: (name) => `Delete cloak "${name}"?`,
|
|
146
|
+
setupChoice: 'How would you like to proceed?',
|
|
147
|
+
setupAuto: 'Set it up now (recommended)',
|
|
148
|
+
setupManual: 'Show manual instructions',
|
|
149
|
+
}
|
package/src/lib/tip.js
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { shellIntegrationTip } from './messages.js'
|
|
2
2
|
|
|
3
3
|
export function showTipIfNeeded() {
|
|
4
4
|
if (process.env.CLOAK_SHELL_INTEGRATION === '1') return
|
|
5
5
|
if (process.env.CLOAK_TIP_SHOWN === '1') return
|
|
6
6
|
if (!process.stdout.isTTY) return
|
|
7
7
|
|
|
8
|
-
process.stderr.write(
|
|
9
|
-
chalk.dim('\n💡 Tip: Run this once to enable "claude -a" and "claude account":\n') +
|
|
10
|
-
chalk.dim(' echo \'eval "$(cloak init)"\' >> ~/.bashrc && source ~/.bashrc\n\n')
|
|
11
|
-
)
|
|
8
|
+
process.stderr.write(shellIntegrationTip())
|
|
12
9
|
|
|
13
10
|
process.env.CLOAK_TIP_SHOWN = '1'
|
|
14
11
|
}
|