ccconfig 1.5.0 → 1.5.2
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 +40 -0
- package/README_zh.md +40 -0
- package/ccconfig.js +133 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -264,6 +264,46 @@ Do you want to set ANTHROPIC_SMALL_FAST_MODEL? (y/N) [n]:
|
|
|
264
264
|
- Use `ccconfig start work` to launch Claude Code with the updated profile
|
|
265
265
|
- Or use `ccconfig use work` to activate it in current shell
|
|
266
266
|
|
|
267
|
+
### Copy Configuration (fork)
|
|
268
|
+
|
|
269
|
+
If you need to create a new configuration based on an existing one, use the `fork` command:
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
# Fork a configuration interactively
|
|
273
|
+
ccconfig fork work
|
|
274
|
+
|
|
275
|
+
# The tool will:
|
|
276
|
+
# 1. Ask for a new configuration name
|
|
277
|
+
# 2. Copy all environment variables from the source
|
|
278
|
+
# 3. Allow you to update values (press Enter to keep current value)
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**Example:**
|
|
282
|
+
```bash
|
|
283
|
+
$ ccconfig fork work
|
|
284
|
+
Please enter source configuration name to copy from: work
|
|
285
|
+
Please enter new configuration name: work-dev
|
|
286
|
+
Creating configuration 'work-dev' from 'work'...
|
|
287
|
+
Press Enter to keep current value/default, or enter new value to update
|
|
288
|
+
|
|
289
|
+
ANTHROPIC_BASE_URL [https://api.company.com]: https://dev-api.company.com
|
|
290
|
+
ANTHROPIC_AUTH_TOKEN [sk-ant-api...]: <press Enter to keep>
|
|
291
|
+
ANTHROPIC_API_KEY [sk-...]: <press Enter to keep>
|
|
292
|
+
ANTHROPIC_MODEL [claude-sonnet-4-5-20250929]: <press Enter to keep>
|
|
293
|
+
|
|
294
|
+
✓ Configuration 'work-dev' created from 'work'
|
|
295
|
+
Environment variables:
|
|
296
|
+
ANTHROPIC_BASE_URL=https://dev-api.company.com
|
|
297
|
+
ANTHROPIC_AUTH_TOKEN=sk-ant-api...
|
|
298
|
+
ANTHROPIC_API_KEY=sk-...
|
|
299
|
+
ANTHROPIC_MODEL=claude-sonnet-4-5-20250929
|
|
300
|
+
|
|
301
|
+
Run the following command to activate:
|
|
302
|
+
ccconfig use work-dev
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
This is useful when you need similar configurations with slight variations (e.g., production vs development endpoints).
|
|
306
|
+
|
|
267
307
|
### Shell Completion
|
|
268
308
|
|
|
269
309
|
ccconfig supports shell completion for commands, profile names, and options. This makes it easier to discover and use commands.
|
package/README_zh.md
CHANGED
|
@@ -264,6 +264,46 @@ Do you want to set ANTHROPIC_SMALL_FAST_MODEL? (y/N) [n]:
|
|
|
264
264
|
- 使用 `ccconfig start work` 以更新后的配置启动 Claude Code
|
|
265
265
|
- 或使用 `ccconfig use work` 在当前 shell 中激活配置
|
|
266
266
|
|
|
267
|
+
### 复制配置 (fork)
|
|
268
|
+
|
|
269
|
+
如果您需要基于现有配置创建新配置,使用 `fork` 命令:
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
# 交互式复制配置
|
|
273
|
+
ccconfig fork work
|
|
274
|
+
|
|
275
|
+
# 工具会:
|
|
276
|
+
# 1. 要求输入新配置名称
|
|
277
|
+
# 2. 从源配置复制所有环境变量
|
|
278
|
+
# 3. 允许您更新值(按 Enter 保持当前值)
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**示例:**
|
|
282
|
+
```bash
|
|
283
|
+
$ ccconfig fork work
|
|
284
|
+
Please enter source configuration name to copy from: work
|
|
285
|
+
Please enter new configuration name: work-dev
|
|
286
|
+
Creating configuration 'work-dev' from 'work'...
|
|
287
|
+
Press Enter to keep current value/default, or enter new value to update
|
|
288
|
+
|
|
289
|
+
ANTHROPIC_BASE_URL [https://api.company.com]: https://dev-api.company.com
|
|
290
|
+
ANTHROPIC_AUTH_TOKEN [sk-ant-api...]: <按 Enter 保持不变>
|
|
291
|
+
ANTHROPIC_API_KEY [sk-...]: <按 Enter 保持不变>
|
|
292
|
+
ANTHROPIC_MODEL [claude-sonnet-4-5-20250929]: <按 Enter 保持不变>
|
|
293
|
+
|
|
294
|
+
✓ Configuration 'work-dev' created from 'work'
|
|
295
|
+
Environment variables:
|
|
296
|
+
ANTHROPIC_BASE_URL=https://dev-api.company.com
|
|
297
|
+
ANTHROPIC_AUTH_TOKEN=sk-ant-api...
|
|
298
|
+
ANTHROPIC_API_KEY=sk-...
|
|
299
|
+
ANTHROPIC_MODEL=claude-sonnet-4-5-20250929
|
|
300
|
+
|
|
301
|
+
Run the following command to activate:
|
|
302
|
+
ccconfig use work-dev
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
当您需要相似配置但略有差异时很有用(例如生产环境与开发环境端点)。
|
|
306
|
+
|
|
267
307
|
### Shell 自动补全
|
|
268
308
|
|
|
269
309
|
ccconfig 支持命令、配置名称和选项的 shell 自动补全,让您更容易发现和使用命令。
|
package/ccconfig.js
CHANGED
|
@@ -89,7 +89,7 @@ function ensureProfileAvailable(
|
|
|
89
89
|
|
|
90
90
|
// All supported commands
|
|
91
91
|
const COMMANDS = [
|
|
92
|
-
'list', 'ls', 'add', 'update', 'use', 'start', 'safe-start', 'remove', 'rm',
|
|
92
|
+
'list', 'ls', 'add', 'update', 'fork', 'use', 'start', 'safe-start', 'remove', 'rm',
|
|
93
93
|
'current', 'mode', 'env', 'completion'
|
|
94
94
|
];
|
|
95
95
|
|
|
@@ -180,46 +180,61 @@ class ReadlineHelper {
|
|
|
180
180
|
|
|
181
181
|
async ask(question, defaultValue = '', options = {}) {
|
|
182
182
|
this.ensureInterface();
|
|
183
|
-
const {brackets = 'parentheses'} = options;
|
|
183
|
+
const {brackets = 'parentheses', prefill = false} = options;
|
|
184
184
|
const left = brackets === 'square' ? '[' : '(';
|
|
185
185
|
const right = brackets === 'square' ? ']' : ')';
|
|
186
|
-
|
|
186
|
+
// Don't show value in brackets if it will be pre-filled
|
|
187
|
+
const suffix = (defaultValue && !prefill) ? ` ${left}${defaultValue}${right}` : '';
|
|
187
188
|
|
|
188
189
|
return new Promise(resolve => {
|
|
189
190
|
this.rl.question(`${question}${suffix}: `, answer => {
|
|
190
191
|
const trimmed = answer.trim();
|
|
191
192
|
resolve(trimmed || defaultValue);
|
|
192
193
|
});
|
|
194
|
+
// Pre-fill input with default value if prefill option is enabled
|
|
195
|
+
if (prefill && defaultValue) {
|
|
196
|
+
this.rl.write(defaultValue);
|
|
197
|
+
}
|
|
193
198
|
});
|
|
194
199
|
}
|
|
195
200
|
|
|
196
201
|
async askEnvVars(existingEnv = {}) {
|
|
202
|
+
const hasExisting = key => !!existingEnv[key];
|
|
203
|
+
|
|
197
204
|
const baseUrl = await this.ask(
|
|
198
205
|
'ANTHROPIC_BASE_URL (press Enter to keep current/default)',
|
|
199
|
-
existingEnv.ANTHROPIC_BASE_URL || 'https://api.anthropic.com',
|
|
200
|
-
|
|
206
|
+
existingEnv.ANTHROPIC_BASE_URL || 'https://api.anthropic.com', {
|
|
207
|
+
brackets: hasExisting('ANTHROPIC_BASE_URL') ? 'square' : 'parentheses',
|
|
208
|
+
prefill: hasExisting('ANTHROPIC_BASE_URL')
|
|
209
|
+
});
|
|
201
210
|
|
|
202
211
|
const authToken = await this.ask(
|
|
203
212
|
'ANTHROPIC_AUTH_TOKEN (press Enter to keep current/set empty)',
|
|
204
213
|
existingEnv.ANTHROPIC_AUTH_TOKEN || '', {
|
|
205
|
-
brackets:
|
|
214
|
+
brackets: hasExisting('ANTHROPIC_AUTH_TOKEN') ? 'square' : 'parentheses',
|
|
215
|
+
prefill: hasExisting('ANTHROPIC_AUTH_TOKEN')
|
|
206
216
|
});
|
|
207
217
|
|
|
208
218
|
const apiKey = await this.ask(
|
|
209
219
|
'ANTHROPIC_API_KEY (press Enter to keep current/set empty)',
|
|
210
|
-
existingEnv.ANTHROPIC_API_KEY || '',
|
|
211
|
-
|
|
220
|
+
existingEnv.ANTHROPIC_API_KEY || '', {
|
|
221
|
+
brackets: hasExisting('ANTHROPIC_API_KEY') ? 'square' : 'parentheses',
|
|
222
|
+
prefill: hasExisting('ANTHROPIC_API_KEY')
|
|
223
|
+
});
|
|
212
224
|
|
|
213
225
|
const model = await this.ask(
|
|
214
226
|
'ANTHROPIC_MODEL (press Enter to skip/keep current)',
|
|
215
|
-
existingEnv.ANTHROPIC_MODEL || '',
|
|
216
|
-
|
|
227
|
+
existingEnv.ANTHROPIC_MODEL || '', {
|
|
228
|
+
brackets: hasExisting('ANTHROPIC_MODEL') ? 'square' : 'parentheses',
|
|
229
|
+
prefill: hasExisting('ANTHROPIC_MODEL')
|
|
230
|
+
});
|
|
217
231
|
|
|
218
232
|
const smallFastModel = await this.ask(
|
|
219
233
|
'ANTHROPIC_SMALL_FAST_MODEL (press Enter to skip/keep current)',
|
|
220
234
|
existingEnv.ANTHROPIC_SMALL_FAST_MODEL || '', {
|
|
221
|
-
brackets:
|
|
222
|
-
|
|
235
|
+
brackets:
|
|
236
|
+
hasExisting('ANTHROPIC_SMALL_FAST_MODEL') ? 'square' : 'parentheses',
|
|
237
|
+
prefill: hasExisting('ANTHROPIC_SMALL_FAST_MODEL')
|
|
223
238
|
});
|
|
224
239
|
|
|
225
240
|
const envVars = {
|
|
@@ -819,6 +834,88 @@ async function update(name) {
|
|
|
819
834
|
}
|
|
820
835
|
}
|
|
821
836
|
|
|
837
|
+
/**
|
|
838
|
+
* Fork (copy) existing configuration
|
|
839
|
+
*/
|
|
840
|
+
async function fork(sourceName) {
|
|
841
|
+
initIfNeeded();
|
|
842
|
+
requireInteractive('forking configurations');
|
|
843
|
+
|
|
844
|
+
const helper = new ReadlineHelper();
|
|
845
|
+
|
|
846
|
+
try {
|
|
847
|
+
if (!sourceName) {
|
|
848
|
+
sourceName = await helper.ask('Please enter source configuration name to copy from');
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
validateConfigName(sourceName);
|
|
852
|
+
|
|
853
|
+
const {profile: sourceProfile} = ensureProfileAvailable(sourceName, {
|
|
854
|
+
allowEmptyEnv: true,
|
|
855
|
+
onEmptyProfiles: () => {
|
|
856
|
+
console.error('Error: Configuration file does not exist');
|
|
857
|
+
},
|
|
858
|
+
onMissingProfile: () => {
|
|
859
|
+
console.error(`Error: Configuration '${sourceName}' does not exist`);
|
|
860
|
+
console.error('');
|
|
861
|
+
console.error('Run ccconfig list to see available configurations');
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
const profiles = loadProfiles() || {profiles: {}};
|
|
866
|
+
const profilesMap = getProfilesMap(profiles);
|
|
867
|
+
|
|
868
|
+
// Ask for new name with validation loop (default to source name)
|
|
869
|
+
let newName = '';
|
|
870
|
+
while (true) {
|
|
871
|
+
newName = await helper.ask(
|
|
872
|
+
`Please enter new configuration name`, sourceName);
|
|
873
|
+
|
|
874
|
+
// Validate name format
|
|
875
|
+
try {
|
|
876
|
+
validateConfigName(newName);
|
|
877
|
+
} catch (error) {
|
|
878
|
+
// validateConfigName calls process.exit, but just in case
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// Check if name already exists
|
|
883
|
+
if (profilesMap[newName]) {
|
|
884
|
+
console.error(`Error: Configuration '${newName}' already exists`);
|
|
885
|
+
console.error('Please choose a different name.');
|
|
886
|
+
console.error('');
|
|
887
|
+
continue;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
// Name is valid and unique
|
|
891
|
+
break;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
console.log(`Creating configuration '${newName}' from '${sourceName}'...`);
|
|
895
|
+
console.log('Press Enter to keep current value/default, or enter new value to update');
|
|
896
|
+
console.log('');
|
|
897
|
+
|
|
898
|
+
// Get environment variables (inherited from source)
|
|
899
|
+
const existingEnv = sourceProfile.env || {};
|
|
900
|
+
const envVars = await helper.askEnvVars(existingEnv);
|
|
901
|
+
|
|
902
|
+
// Now save everything at once
|
|
903
|
+
profilesMap[newName] = {env: envVars};
|
|
904
|
+
saveProfiles(profiles);
|
|
905
|
+
|
|
906
|
+
console.log(`✓ Configuration '${newName}' created from '${sourceName}'`);
|
|
907
|
+
console.log('');
|
|
908
|
+
console.log('Environment variables:');
|
|
909
|
+
displayEnvVars(envVars);
|
|
910
|
+
console.log('');
|
|
911
|
+
console.log('Run the following command to activate:');
|
|
912
|
+
console.log(` ccconfig use ${newName}`);
|
|
913
|
+
|
|
914
|
+
} finally {
|
|
915
|
+
helper.close();
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
|
|
822
919
|
/**
|
|
823
920
|
* Remove configuration
|
|
824
921
|
*/
|
|
@@ -1685,7 +1782,7 @@ _ccconfig_completions() {
|
|
|
1685
1782
|
;;
|
|
1686
1783
|
2)
|
|
1687
1784
|
case "\${prev}" in
|
|
1688
|
-
use|start|safe-start|update|remove|rm)
|
|
1785
|
+
use|start|safe-start|update|fork|remove|rm)
|
|
1689
1786
|
COMPREPLY=( $(compgen -W "\${profiles}" -- \${cur}) )
|
|
1690
1787
|
;;
|
|
1691
1788
|
mode)
|
|
@@ -1694,6 +1791,9 @@ _ccconfig_completions() {
|
|
|
1694
1791
|
env)
|
|
1695
1792
|
COMPREPLY=( $(compgen -W "bash zsh fish sh powershell pwsh dotenv" -- \${cur}) )
|
|
1696
1793
|
;;
|
|
1794
|
+
completion)
|
|
1795
|
+
COMPREPLY=( $(compgen -W "bash zsh fish powershell pwsh" -- \${cur}) )
|
|
1796
|
+
;;
|
|
1697
1797
|
esac
|
|
1698
1798
|
;;
|
|
1699
1799
|
3)
|
|
@@ -1722,6 +1822,7 @@ _ccconfig() {
|
|
|
1722
1822
|
'ls:List all configurations'
|
|
1723
1823
|
'add:Add new configuration'
|
|
1724
1824
|
'update:Update existing configuration'
|
|
1825
|
+
'fork:Copy existing configuration and update'
|
|
1725
1826
|
'use:Switch to specified configuration'
|
|
1726
1827
|
'start:Start Claude Code (auto-approve mode)'
|
|
1727
1828
|
'safe-start:Start Claude Code (safe mode, requires confirmation)'
|
|
@@ -1746,7 +1847,7 @@ _ccconfig() {
|
|
|
1746
1847
|
;;
|
|
1747
1848
|
3)
|
|
1748
1849
|
case $words[2] in
|
|
1749
|
-
use|start|safe-start|update|remove|rm)
|
|
1850
|
+
use|start|safe-start|update|fork|remove|rm)
|
|
1750
1851
|
_describe 'profile' profiles
|
|
1751
1852
|
;;
|
|
1752
1853
|
mode)
|
|
@@ -1755,6 +1856,11 @@ _ccconfig() {
|
|
|
1755
1856
|
env)
|
|
1756
1857
|
_describe 'format' formats
|
|
1757
1858
|
;;
|
|
1859
|
+
completion)
|
|
1860
|
+
local -a shells
|
|
1861
|
+
shells=('bash' 'zsh' 'fish' 'powershell' 'pwsh')
|
|
1862
|
+
_describe 'shell' shells
|
|
1863
|
+
;;
|
|
1758
1864
|
esac
|
|
1759
1865
|
;;
|
|
1760
1866
|
4)
|
|
@@ -1782,6 +1888,7 @@ complete -c ccconfig -f -n "__fish_use_subcommand" -a "list" -d "List all config
|
|
|
1782
1888
|
complete -c ccconfig -f -n "__fish_use_subcommand" -a "ls" -d "List all configurations"
|
|
1783
1889
|
complete -c ccconfig -f -n "__fish_use_subcommand" -a "add" -d "Add new configuration"
|
|
1784
1890
|
complete -c ccconfig -f -n "__fish_use_subcommand" -a "update" -d "Update existing configuration"
|
|
1891
|
+
complete -c ccconfig -f -n "__fish_use_subcommand" -a "fork" -d "Copy existing configuration and update"
|
|
1785
1892
|
complete -c ccconfig -f -n "__fish_use_subcommand" -a "use" -d "Switch to specified configuration"
|
|
1786
1893
|
complete -c ccconfig -f -n "__fish_use_subcommand" -a "start" -d "Start Claude Code (auto-approve mode)"
|
|
1787
1894
|
complete -c ccconfig -f -n "__fish_use_subcommand" -a "safe-start" -d "Start Claude Code (safe mode, requires confirmation)"
|
|
@@ -1798,8 +1905,8 @@ function __ccconfig_profiles
|
|
|
1798
1905
|
end
|
|
1799
1906
|
end
|
|
1800
1907
|
|
|
1801
|
-
# Profile name completion for use, start, safe-start, update, remove
|
|
1802
|
-
complete -c ccconfig -f -n "__fish_seen_subcommand_from use start safe-start update remove rm" -a "(__ccconfig_profiles)"
|
|
1908
|
+
# Profile name completion for use, start, safe-start, update, fork, remove
|
|
1909
|
+
complete -c ccconfig -f -n "__fish_seen_subcommand_from use start safe-start update fork remove rm" -a "(__ccconfig_profiles)"
|
|
1803
1910
|
|
|
1804
1911
|
# Mode options
|
|
1805
1912
|
complete -c ccconfig -f -n "__fish_seen_subcommand_from mode" -a "settings env"
|
|
@@ -1807,6 +1914,9 @@ complete -c ccconfig -f -n "__fish_seen_subcommand_from mode" -a "settings env"
|
|
|
1807
1914
|
# Env format options
|
|
1808
1915
|
complete -c ccconfig -f -n "__fish_seen_subcommand_from env" -a "bash zsh fish sh powershell pwsh dotenv"
|
|
1809
1916
|
|
|
1917
|
+
# Completion shell options
|
|
1918
|
+
complete -c ccconfig -f -n "__fish_seen_subcommand_from completion" -a "bash zsh fish powershell pwsh"
|
|
1919
|
+
|
|
1810
1920
|
# Flags for use command
|
|
1811
1921
|
complete -c ccconfig -f -n "__fish_seen_subcommand_from use" -s p -l permanent -d "Write permanently to shell config"
|
|
1812
1922
|
|
|
@@ -1841,7 +1951,7 @@ function Get-CconfigProfiles {
|
|
|
1841
1951
|
Register-ArgumentCompleter -Native -CommandName ccconfig -ScriptBlock {
|
|
1842
1952
|
param($wordToComplete, $commandAst, $cursorPosition)
|
|
1843
1953
|
|
|
1844
|
-
$commands = @('list', 'ls', 'add', 'update', 'use', 'start', 'safe-start', 'remove', 'rm', 'current', 'mode', 'env', 'completion')
|
|
1954
|
+
$commands = @('list', 'ls', 'add', 'update', 'fork', 'use', 'start', 'safe-start', 'remove', 'rm', 'current', 'mode', 'env', 'completion')
|
|
1845
1955
|
$modes = @('settings', 'env')
|
|
1846
1956
|
$formats = @('bash', 'zsh', 'fish', 'sh', 'powershell', 'pwsh', 'dotenv')
|
|
1847
1957
|
|
|
@@ -1863,7 +1973,7 @@ Register-ArgumentCompleter -Native -CommandName ccconfig -ScriptBlock {
|
|
|
1863
1973
|
# Second argument completions based on command
|
|
1864
1974
|
if ($position -eq 2 -or ($position -eq 3 -and $wordToComplete)) {
|
|
1865
1975
|
switch ($command) {
|
|
1866
|
-
{ $_ -in 'use', 'start', 'safe-start', 'update', 'remove', 'rm' } {
|
|
1976
|
+
{ $_ -in 'use', 'start', 'safe-start', 'update', 'fork', 'remove', 'rm' } {
|
|
1867
1977
|
Get-CconfigProfiles | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
|
|
1868
1978
|
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
|
|
1869
1979
|
}
|
|
@@ -1940,6 +2050,8 @@ function help() {
|
|
|
1940
2050
|
' add [name] Add new configuration (interactive)');
|
|
1941
2051
|
console.log(
|
|
1942
2052
|
' update [name] Update existing configuration (interactive)');
|
|
2053
|
+
console.log(
|
|
2054
|
+
' fork [source-name] Copy existing configuration and update (interactive)');
|
|
1943
2055
|
console.log(
|
|
1944
2056
|
' use <name> [-p|--permanent] Switch to specified configuration');
|
|
1945
2057
|
console.log(
|
|
@@ -2062,6 +2174,9 @@ async function main() {
|
|
|
2062
2174
|
case 'update':
|
|
2063
2175
|
await update(filteredArgs[1]);
|
|
2064
2176
|
break;
|
|
2177
|
+
case 'fork':
|
|
2178
|
+
await fork(filteredArgs[1]);
|
|
2179
|
+
break;
|
|
2065
2180
|
case 'remove':
|
|
2066
2181
|
case 'rm':
|
|
2067
2182
|
await remove(filteredArgs[1]);
|