yingclaw 2.3.0 → 2.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/README.md +1 -0
- package/bin/cli.js +85 -4
- package/lib/config.js +34 -6
- package/package.json +1 -1
package/README.md
CHANGED
package/bin/cli.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const { Command } = require('commander');
|
|
4
|
-
const { select, input, confirm } = require('@inquirer/prompts');
|
|
4
|
+
const { select, input, confirm, editor } = require('@inquirer/prompts');
|
|
5
5
|
const {
|
|
6
6
|
loadConfig,
|
|
7
7
|
saveConfig,
|
|
8
|
+
getSystemPrompt,
|
|
9
|
+
setSystemPrompt,
|
|
8
10
|
writeEnvToZshrc,
|
|
9
11
|
clearClaudeCodeEnv,
|
|
10
12
|
fetchModels,
|
|
@@ -354,7 +356,7 @@ async function runConfigFlow({ writeCodeEnv = false } = {}) {
|
|
|
354
356
|
cfg = customConfig || { provider: providerKey, model, fastModel, apiKey, baseUrl: provider.baseUrl, availableModels };
|
|
355
357
|
saveConfig(cfg);
|
|
356
358
|
if (writeCodeEnv) {
|
|
357
|
-
({ file } = writeEnvToZshrc(cfg.baseUrl, cfg.apiKey, cfg.model, cfg.fastModel));
|
|
359
|
+
({ file } = writeEnvToZshrc(cfg.baseUrl, cfg.apiKey, cfg.model, cfg.fastModel, { systemPrompt: getSystemPrompt(cfg) }));
|
|
358
360
|
}
|
|
359
361
|
spinner.succeed(chalk.green(writeCodeEnv ? 'API 连接已保存,Claude Code 终端已接入' : 'API 连接已保存'));
|
|
360
362
|
} catch (e) {
|
|
@@ -482,7 +484,7 @@ program
|
|
|
482
484
|
const spinner = ora('写入 Claude Code 终端环境变量...').start();
|
|
483
485
|
let file;
|
|
484
486
|
try {
|
|
485
|
-
({ file } = writeEnvToZshrc(config.baseUrl, config.apiKey, config.model, config.fastModel));
|
|
487
|
+
({ file } = writeEnvToZshrc(config.baseUrl, config.apiKey, config.model, config.fastModel, { systemPrompt: getSystemPrompt(config) }));
|
|
486
488
|
spinner.succeed(chalk.green(`Claude Code 终端已接入 → ${file}`));
|
|
487
489
|
} catch (e) {
|
|
488
490
|
spinner.fail(chalk.red(`写入失败: ${e.message}`));
|
|
@@ -633,6 +635,82 @@ program
|
|
|
633
635
|
await offerDesktopSync(chalk, ora, newConfig);
|
|
634
636
|
});
|
|
635
637
|
|
|
638
|
+
program
|
|
639
|
+
.command('prompt')
|
|
640
|
+
.description('配置系统提示词')
|
|
641
|
+
.action(async () => {
|
|
642
|
+
const chalk = (await import('chalk')).default;
|
|
643
|
+
const ora = (await import('ora')).default;
|
|
644
|
+
const boxen = (await import('boxen')).default;
|
|
645
|
+
|
|
646
|
+
console.log(await getBanner());
|
|
647
|
+
|
|
648
|
+
const config = loadConfig();
|
|
649
|
+
if (!config) {
|
|
650
|
+
console.log(chalk.red('\n未配置 API 连接,请先运行: claw config\n'));
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
const provider = PROVIDERS[config.provider];
|
|
655
|
+
const providerName = config.providerName || provider?.name || config.provider;
|
|
656
|
+
const currentPrompt = getSystemPrompt(config);
|
|
657
|
+
|
|
658
|
+
console.log(chalk.dim(` 当前模型:${providerName} · ${config.model}\n`));
|
|
659
|
+
|
|
660
|
+
if (currentPrompt) {
|
|
661
|
+
const preview = currentPrompt.length > 300 ? currentPrompt.slice(0, 300) + '\n...' : currentPrompt;
|
|
662
|
+
console.log(boxen(
|
|
663
|
+
chalk.bold('当前系统提示词\n\n') + chalk.dim(preview),
|
|
664
|
+
{ padding: { top: 0, bottom: 0, left: 2, right: 2 }, borderStyle: 'round', borderColor: 'cyan', margin: { top: 1, bottom: 1 } }
|
|
665
|
+
));
|
|
666
|
+
} else {
|
|
667
|
+
console.log(chalk.dim(' 当前模型未配置系统提示词\n'));
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
const action = await select({ loop: false,
|
|
671
|
+
message: chalk.cyan('操作'),
|
|
672
|
+
choices: [
|
|
673
|
+
{ name: currentPrompt ? '✏️ 编辑系统提示词' : '✏️ 设置系统提示词', value: 'edit' },
|
|
674
|
+
...(currentPrompt ? [{ name: '🗑 清除当前模型提示词', value: 'clear' }] : []),
|
|
675
|
+
{ name: chalk.dim('↩ 返回'), value: '__BACK__' },
|
|
676
|
+
],
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
if (action === '__BACK__') return;
|
|
680
|
+
|
|
681
|
+
if (action === 'clear') {
|
|
682
|
+
const yes = await confirm({ message: '确定清除该模型的系统提示词?', default: false });
|
|
683
|
+
if (!yes) { console.log(chalk.dim('已取消')); return; }
|
|
684
|
+
const spinner = ora('清除中...').start();
|
|
685
|
+
setSystemPrompt(config, null);
|
|
686
|
+
saveConfig(config);
|
|
687
|
+
spinner.succeed(chalk.green('系统提示词已清除'));
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
const newPrompt = await editor({
|
|
692
|
+
message: chalk.cyan('编辑系统提示词(保存并关闭编辑器后生效)'),
|
|
693
|
+
default: currentPrompt || '',
|
|
694
|
+
waitForUseInput: false,
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
if (!newPrompt || !newPrompt.trim()) {
|
|
698
|
+
console.log(chalk.dim('内容为空,已取消'));
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
const spinner = ora('保存中...').start();
|
|
703
|
+
setSystemPrompt(config, newPrompt);
|
|
704
|
+
saveConfig(config);
|
|
705
|
+
spinner.succeed(chalk.green('系统提示词已保存'));
|
|
706
|
+
|
|
707
|
+
console.log(boxen(
|
|
708
|
+
chalk.dim('• 通过菜单"启动 Claude Code"时自动应用\n') +
|
|
709
|
+
chalk.dim('• 终端直接使用 claude 命令请重新运行 ') + chalk.cyan('claw code'),
|
|
710
|
+
{ padding: { top: 0, bottom: 0, left: 2, right: 2 }, borderStyle: 'round', borderColor: 'green', margin: { top: 1, bottom: 1 } }
|
|
711
|
+
));
|
|
712
|
+
});
|
|
713
|
+
|
|
636
714
|
program
|
|
637
715
|
.command('status')
|
|
638
716
|
.description('查看当前配置和 Key 有效性')
|
|
@@ -1065,6 +1143,7 @@ async function runMenu() {
|
|
|
1065
1143
|
{ name: '📦 安装 Claude Code', value: 'install' },
|
|
1066
1144
|
{ name: config ? '🔑 重新配置 API 连接' : '🔑 配置 API 连接', value: 'config' },
|
|
1067
1145
|
{ name: '🔄 切换厂商或模型', value: 'switch', disabled: disabledHint },
|
|
1146
|
+
{ name: getSystemPrompt(config) ? '📝 系统提示词(已配置)' : '📝 配置系统提示词', value: 'prompt', disabled: !config && '需先配置 API 连接' },
|
|
1068
1147
|
{ name: '💻 接入 Claude Code 终端', value: 'code', disabled: disabledHint },
|
|
1069
1148
|
{ name: '🖥 接入 Claude 桌面应用', value: 'desktop', disabled: disabledHint },
|
|
1070
1149
|
{ name: '📊 查看当前配置', value: 'status', disabled: !config && '需先配置 API 连接' },
|
|
@@ -1091,8 +1170,9 @@ async function runMenu() {
|
|
|
1091
1170
|
if (resolvedAction === 'launch') {
|
|
1092
1171
|
const cfg = loadConfig();
|
|
1093
1172
|
if (!cfg || getConfigValidationMessage(cfg)) continue;
|
|
1173
|
+
const launchArgs = getSystemPrompt(cfg) ? ['--append-system-prompt', getSystemPrompt(cfg)] : [];
|
|
1094
1174
|
await new Promise((resolve) => {
|
|
1095
|
-
const child = spawn('claude',
|
|
1175
|
+
const child = spawn('claude', launchArgs, {
|
|
1096
1176
|
stdio: 'inherit',
|
|
1097
1177
|
env: { ...process.env, ...buildClaudeEnv(cfg) },
|
|
1098
1178
|
shell: process.platform === 'win32',
|
|
@@ -1112,6 +1192,7 @@ async function runMenu() {
|
|
|
1112
1192
|
code: 'code',
|
|
1113
1193
|
'code-reset': 'code-reset',
|
|
1114
1194
|
switch: 'switch',
|
|
1195
|
+
prompt: 'prompt',
|
|
1115
1196
|
desktop: 'desktop',
|
|
1116
1197
|
'desktop-reset': 'desktop-reset',
|
|
1117
1198
|
status: 'status',
|
package/lib/config.js
CHANGED
|
@@ -128,6 +128,26 @@ function normalizeAnthropicBaseUrl(baseUrl) {
|
|
|
128
128
|
return url.toString().replace(/\/+$/, '');
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
function systemPromptKey(config) {
|
|
132
|
+
return `${config.provider}::${config.model}`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function getSystemPrompt(config) {
|
|
136
|
+
if (!config?.systemPrompts) return null;
|
|
137
|
+
return config.systemPrompts[systemPromptKey(config)] || null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function setSystemPrompt(config, prompt) {
|
|
141
|
+
const key = systemPromptKey(config);
|
|
142
|
+
if (!config.systemPrompts) config.systemPrompts = {};
|
|
143
|
+
if (prompt && prompt.trim()) {
|
|
144
|
+
config.systemPrompts[key] = prompt.trim();
|
|
145
|
+
} else {
|
|
146
|
+
delete config.systemPrompts[key];
|
|
147
|
+
if (Object.keys(config.systemPrompts).length === 0) delete config.systemPrompts;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
131
151
|
function buildModelUrlCandidates(baseUrl) {
|
|
132
152
|
let url;
|
|
133
153
|
try { url = new URL(normalizeAnthropicBaseUrl(baseUrl)); } catch { return []; }
|
|
@@ -324,10 +344,10 @@ function shellQuote(value) {
|
|
|
324
344
|
}
|
|
325
345
|
|
|
326
346
|
// 构造完整的 clawai 环境变量块
|
|
327
|
-
function buildEnvBlock(baseUrl, apiKey, model, fastModel) {
|
|
347
|
+
function buildEnvBlock(baseUrl, apiKey, model, fastModel, systemPrompt) {
|
|
328
348
|
const provider = providerKeyFromBaseUrl(baseUrl);
|
|
329
349
|
const env = buildClaudeEnv({ provider, baseUrl, apiKey, model, fastModel });
|
|
330
|
-
|
|
350
|
+
const lines = [
|
|
331
351
|
'',
|
|
332
352
|
'# clawai-start',
|
|
333
353
|
`export ANTHROPIC_BASE_URL=${shellQuote(env.ANTHROPIC_BASE_URL)}`,
|
|
@@ -339,9 +359,15 @@ function buildEnvBlock(baseUrl, apiKey, model, fastModel) {
|
|
|
339
359
|
`export ANTHROPIC_DEFAULT_HAIKU_MODEL=${shellQuote(env.ANTHROPIC_DEFAULT_HAIKU_MODEL)}`,
|
|
340
360
|
`export CLAUDE_CODE_SUBAGENT_MODEL=${shellQuote(env.CLAUDE_CODE_SUBAGENT_MODEL)}`,
|
|
341
361
|
`export CLAUDE_CODE_EFFORT_LEVEL=${shellQuote(env.CLAUDE_CODE_EFFORT_LEVEL)}`,
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
362
|
+
];
|
|
363
|
+
|
|
364
|
+
if (systemPrompt && systemPrompt.trim()) {
|
|
365
|
+
lines.push(`_claw_system_prompt=${shellQuote(systemPrompt.trim())}`);
|
|
366
|
+
lines.push(`claude() { command claude --append-system-prompt "$_claw_system_prompt" "$@"; }`);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
lines.push('# clawai-end', '');
|
|
370
|
+
return lines.join('\n');
|
|
345
371
|
}
|
|
346
372
|
|
|
347
373
|
// 写入或更新 shell 配置文件中的环境变量块
|
|
@@ -364,7 +390,7 @@ function writeEnvToZshrc(baseUrl, apiKey, model, fastModel, options = {}) {
|
|
|
364
390
|
rcFile = path.join(os.homedir(), '.zshrc');
|
|
365
391
|
}
|
|
366
392
|
|
|
367
|
-
const block = buildEnvBlock(baseUrl, apiKey, model, fastModel);
|
|
393
|
+
const block = buildEnvBlock(baseUrl, apiKey, model, fastModel, options.systemPrompt);
|
|
368
394
|
const current = fs.existsSync(rcFile) ? fs.readFileSync(rcFile, 'utf8') : '';
|
|
369
395
|
|
|
370
396
|
// 兼容旧版(# clawai 单行块)和新版(# clawai-start...# clawai-end 多行块)
|
|
@@ -424,6 +450,8 @@ function resetConfig(options = {}) {
|
|
|
424
450
|
module.exports = {
|
|
425
451
|
loadConfig,
|
|
426
452
|
saveConfig,
|
|
453
|
+
getSystemPrompt,
|
|
454
|
+
setSystemPrompt,
|
|
427
455
|
writeEnvToZshrc,
|
|
428
456
|
buildWindowsSetEnvCommands,
|
|
429
457
|
buildWindowsClearEnvCommands,
|