@aiyiran/myclaw 1.0.50 → 1.0.52
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/index.js +17 -3
- package/inject-minimax.js +165 -0
- package/package.json +1 -1
- package/patch-skill.js +171 -0
- package/skills/minimax-inject/SKILL.md +33 -0
- package/skills/minimax-inject/scripts/inject.js +187 -0
package/index.js
CHANGED
|
@@ -581,16 +581,22 @@ function runOpen() {
|
|
|
581
581
|
|
|
582
582
|
function runPatch() {
|
|
583
583
|
const { patch, status: patchStatus } = require('./patch');
|
|
584
|
+
const { patchSkills } = require('./patch-skill');
|
|
584
585
|
const bar = '----------------------------------------';
|
|
585
586
|
|
|
586
587
|
console.log('');
|
|
587
|
-
console.log('[' + colors.blue + 'MyClaw' + colors.nc + '] ' + colors.blue + 'UI
|
|
588
|
+
console.log('[' + colors.blue + 'MyClaw' + colors.nc + '] ' + colors.blue + 'Patch (UI + Skills)' + colors.nc);
|
|
588
589
|
console.log(bar);
|
|
589
590
|
console.log('');
|
|
590
591
|
|
|
591
|
-
|
|
592
|
+
// 1. UI 注入
|
|
593
|
+
const uiResult = patch();
|
|
592
594
|
|
|
593
|
-
|
|
595
|
+
// 2. Skill 注入
|
|
596
|
+
console.log('');
|
|
597
|
+
const skillResult = patchSkills();
|
|
598
|
+
|
|
599
|
+
if (uiResult.success || skillResult.success) {
|
|
594
600
|
console.log('');
|
|
595
601
|
console.log(bar);
|
|
596
602
|
console.log('下一步: 运行 ' + colors.yellow + 'myclaw restart' + colors.nc + ' 重启 Gateway 使注入生效');
|
|
@@ -728,6 +734,7 @@ function showHelp() {
|
|
|
728
734
|
console.log(' bat 在桌面生成一键启动脚本 (仅限 Windows)');
|
|
729
735
|
console.log(' patch 注入 MyClaw UI 扩展到 WebChat');
|
|
730
736
|
console.log(' unpatch 回滚 UI 注入(恢复原版)');
|
|
737
|
+
console.log(' minimax 注入 MiniMax 模型配置 (可选: --key sk-xxx)');
|
|
731
738
|
console.log(' restart 重启 OpenClaw Gateway');
|
|
732
739
|
console.log(' help 显示帮助信息');
|
|
733
740
|
console.log('');
|
|
@@ -781,6 +788,13 @@ if (!command || command === 'help' || command === '--help' || command === '-h')
|
|
|
781
788
|
runUnpatch();
|
|
782
789
|
} else if (command === 'restart') {
|
|
783
790
|
runRestart();
|
|
791
|
+
} else if (command === 'minimax') {
|
|
792
|
+
const minimax = require('./inject-minimax');
|
|
793
|
+
minimax.run(args.slice(1));
|
|
794
|
+
// 注入完成后自动重启 Gateway
|
|
795
|
+
console.log('🔄 正在重启 Gateway 使配置生效...');
|
|
796
|
+
console.log('');
|
|
797
|
+
runRestart();
|
|
784
798
|
} else {
|
|
785
799
|
console.error('[' + colors.red + '错误' + colors.nc + '] 未知命令: ' + command);
|
|
786
800
|
showHelp();
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* inject-minimax.js
|
|
5
|
+
*
|
|
6
|
+
* 将 openclaw.json 中的模型配置清空,注入为唯一的 MiniMax 模型。
|
|
7
|
+
* 自动查找 ~/.openclaw/openclaw.json
|
|
8
|
+
*
|
|
9
|
+
* 入口: myclaw minimax [--key sk-xxx]
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const os = require('os');
|
|
15
|
+
|
|
16
|
+
function run(cliArgs) {
|
|
17
|
+
// 解析 --key 参数
|
|
18
|
+
let apiKey = null;
|
|
19
|
+
for (let i = 0; i < cliArgs.length; i++) {
|
|
20
|
+
if (cliArgs[i] === '--key' && cliArgs[i + 1]) {
|
|
21
|
+
apiKey = cliArgs[i + 1];
|
|
22
|
+
i++;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 自动查找 openclaw.json
|
|
27
|
+
const openclawDir = path.join(os.homedir(), '.openclaw');
|
|
28
|
+
const targetPath = path.join(openclawDir, 'openclaw.json');
|
|
29
|
+
|
|
30
|
+
if (!fs.existsSync(targetPath)) {
|
|
31
|
+
console.error('❌ 未找到 openclaw.json');
|
|
32
|
+
console.error(' 期望路径: ' + targetPath);
|
|
33
|
+
console.error(' 请先安装 OpenClaw: myclaw install');
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
console.log('📍 找到配置: ' + targetPath);
|
|
38
|
+
|
|
39
|
+
// 读取并修改
|
|
40
|
+
const config = JSON.parse(fs.readFileSync(targetPath, 'utf8'));
|
|
41
|
+
|
|
42
|
+
// 1. auth.profiles → 只保留 minimax
|
|
43
|
+
config.auth = {
|
|
44
|
+
profiles: {
|
|
45
|
+
"minimax:cn": {
|
|
46
|
+
provider: "minimax",
|
|
47
|
+
mode: "api_key"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// 2. models.providers → 只保留 minimax
|
|
53
|
+
config.models = {
|
|
54
|
+
mode: "merge",
|
|
55
|
+
providers: {
|
|
56
|
+
minimax: {
|
|
57
|
+
baseUrl: "https://api.minimaxi.com/anthropic",
|
|
58
|
+
api: "anthropic-messages",
|
|
59
|
+
authHeader: true,
|
|
60
|
+
headers: {
|
|
61
|
+
"Authorization": "Bearer ${env:MINIMAX_API_KEY}"
|
|
62
|
+
},
|
|
63
|
+
models: [
|
|
64
|
+
{
|
|
65
|
+
id: "MiniMax-M2.7",
|
|
66
|
+
name: "MiniMax M2.7",
|
|
67
|
+
reasoning: true,
|
|
68
|
+
input: ["text"],
|
|
69
|
+
cost: {
|
|
70
|
+
input: 0.3,
|
|
71
|
+
output: 1.2,
|
|
72
|
+
cacheRead: 0.06,
|
|
73
|
+
cacheWrite: 0.375
|
|
74
|
+
},
|
|
75
|
+
contextWindow: 204800,
|
|
76
|
+
maxTokens: 131072
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// 3. agents.defaults → 使用 minimax 模型
|
|
84
|
+
if (!config.agents) config.agents = {};
|
|
85
|
+
if (!config.agents.defaults) config.agents.defaults = {};
|
|
86
|
+
|
|
87
|
+
config.agents.defaults.model = {
|
|
88
|
+
primary: "minimax/MiniMax-M2.7-highspeed"
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
config.agents.defaults.imageGenerationModel = {
|
|
92
|
+
primary: "minimax/image-01"
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
config.agents.defaults.models = {
|
|
96
|
+
"minimax/MiniMax-M2.7-highspeed": {}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// 写回文件
|
|
100
|
+
const output = JSON.stringify(config, null, 2) + '\n';
|
|
101
|
+
fs.writeFileSync(targetPath, output, 'utf8');
|
|
102
|
+
|
|
103
|
+
console.log('✅ MiniMax 模型配置已注入');
|
|
104
|
+
console.log('');
|
|
105
|
+
console.log(' auth.profiles → minimax:cn');
|
|
106
|
+
console.log(' models.providers → minimax (MiniMax-M2.7)');
|
|
107
|
+
console.log(' agents.defaults → minimax/MiniMax-M2.7-highspeed');
|
|
108
|
+
|
|
109
|
+
// 4. 如果传了 --key,写入环境变量
|
|
110
|
+
if (apiKey) {
|
|
111
|
+
console.log('');
|
|
112
|
+
console.log('🔑 设置 MINIMAX_API_KEY 环境变量...');
|
|
113
|
+
|
|
114
|
+
const platform = os.platform();
|
|
115
|
+
|
|
116
|
+
if (platform === 'win32') {
|
|
117
|
+
try {
|
|
118
|
+
const { execSync } = require('child_process');
|
|
119
|
+
execSync('setx MINIMAX_API_KEY "' + apiKey + '"', { stdio: 'pipe' });
|
|
120
|
+
console.log(' ✅ 已通过 setx 写入 Windows 用户环境变量');
|
|
121
|
+
} catch (err) {
|
|
122
|
+
console.log(' ❌ setx 写入失败: ' + err.message);
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
const shell = process.env.SHELL || '/bin/bash';
|
|
126
|
+
let rcFiles = [];
|
|
127
|
+
if (shell.includes('zsh')) {
|
|
128
|
+
rcFiles = [path.join(os.homedir(), '.zshrc')];
|
|
129
|
+
} else {
|
|
130
|
+
rcFiles = [path.join(os.homedir(), '.bashrc')];
|
|
131
|
+
}
|
|
132
|
+
const profilePath = path.join(os.homedir(), '.profile');
|
|
133
|
+
if (fs.existsSync(profilePath) && !rcFiles.includes(profilePath)) {
|
|
134
|
+
rcFiles.push(profilePath);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const exportLine = 'export MINIMAX_API_KEY="' + apiKey + '"';
|
|
138
|
+
|
|
139
|
+
for (const rcFile of rcFiles) {
|
|
140
|
+
let content = '';
|
|
141
|
+
try { content = fs.readFileSync(rcFile, 'utf8'); } catch {}
|
|
142
|
+
|
|
143
|
+
if (content.includes('MINIMAX_API_KEY')) {
|
|
144
|
+
content = content.replace(/^export MINIMAX_API_KEY=.*$/m, exportLine);
|
|
145
|
+
fs.writeFileSync(rcFile, content, 'utf8');
|
|
146
|
+
console.log(' ✅ 已更新: ' + rcFile);
|
|
147
|
+
} else {
|
|
148
|
+
fs.appendFileSync(rcFile, '\n# MiniMax API Key (by myclaw minimax)\n' + exportLine + '\n');
|
|
149
|
+
console.log(' ✅ 已追加: ' + rcFile);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
process.env.MINIMAX_API_KEY = apiKey;
|
|
154
|
+
console.log(' ✅ 当前进程已设置 MINIMAX_API_KEY');
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
console.log('');
|
|
158
|
+
console.log('💡 未传入 --key,API Key 将使用环境变量 MINIMAX_API_KEY');
|
|
159
|
+
console.log(' 设置方法: myclaw minimax --key sk-xxx');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
console.log('');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
module.exports = { run };
|
package/package.json
CHANGED
package/patch-skill.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================================
|
|
3
|
+
* MyClaw Patch Skill Engine
|
|
4
|
+
* ============================================================================
|
|
5
|
+
*
|
|
6
|
+
* 功能:
|
|
7
|
+
* 1. 探测 OpenClaw 安装路径下的 skills/ 目录
|
|
8
|
+
* 2. 将 myclaw 自带的 skill 复制到 openclaw/skills/ 下
|
|
9
|
+
* 3. 幂等:重复执行覆盖更新
|
|
10
|
+
*
|
|
11
|
+
* 使用:
|
|
12
|
+
* const { patchSkills, listSkills } = require('./patch-skill');
|
|
13
|
+
* patchSkills(); // 注入所有 skill
|
|
14
|
+
* listSkills(); // 列出已注入的 skill
|
|
15
|
+
* ============================================================================
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 探测 OpenClaw 的 skills 目录
|
|
23
|
+
*/
|
|
24
|
+
function findSkillsDir() {
|
|
25
|
+
const candidates = [];
|
|
26
|
+
|
|
27
|
+
// 全局 node_modules 路径
|
|
28
|
+
const globalPaths = [
|
|
29
|
+
'/usr/lib/node_modules',
|
|
30
|
+
'/usr/local/lib/node_modules',
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
const { execSync } = require('child_process');
|
|
35
|
+
const prefix = execSync('npm config get prefix 2>/dev/null', { encoding: 'utf8' }).trim();
|
|
36
|
+
if (prefix) {
|
|
37
|
+
globalPaths.push(path.join(prefix, 'lib', 'node_modules'));
|
|
38
|
+
}
|
|
39
|
+
} catch {}
|
|
40
|
+
|
|
41
|
+
for (const globalPath of globalPaths) {
|
|
42
|
+
candidates.push(path.join(globalPath, 'openclaw', 'skills'));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 通过 which openclaw 推断
|
|
46
|
+
try {
|
|
47
|
+
const { execSync } = require('child_process');
|
|
48
|
+
const bin = execSync('which openclaw 2>/dev/null', { encoding: 'utf8' }).trim();
|
|
49
|
+
if (bin) {
|
|
50
|
+
const real = fs.realpathSync(bin);
|
|
51
|
+
const pkgRoot = path.dirname(real);
|
|
52
|
+
candidates.push(path.join(pkgRoot, 'skills'));
|
|
53
|
+
candidates.push(path.join(path.dirname(pkgRoot), 'skills'));
|
|
54
|
+
}
|
|
55
|
+
} catch {}
|
|
56
|
+
|
|
57
|
+
// 找到第一个存在的
|
|
58
|
+
for (const dir of candidates) {
|
|
59
|
+
try {
|
|
60
|
+
if (fs.existsSync(dir) && fs.statSync(dir).isDirectory()) {
|
|
61
|
+
return dir;
|
|
62
|
+
}
|
|
63
|
+
} catch {}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 递归复制目录
|
|
71
|
+
*/
|
|
72
|
+
function copyDirSync(src, dest) {
|
|
73
|
+
if (!fs.existsSync(dest)) {
|
|
74
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
78
|
+
for (const entry of entries) {
|
|
79
|
+
const srcPath = path.join(src, entry.name);
|
|
80
|
+
const destPath = path.join(dest, entry.name);
|
|
81
|
+
|
|
82
|
+
if (entry.isDirectory()) {
|
|
83
|
+
copyDirSync(srcPath, destPath);
|
|
84
|
+
} else {
|
|
85
|
+
fs.copyFileSync(srcPath, destPath);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 注入所有 myclaw skills
|
|
92
|
+
*/
|
|
93
|
+
function patchSkills() {
|
|
94
|
+
const skillsDir = findSkillsDir();
|
|
95
|
+
if (!skillsDir) {
|
|
96
|
+
console.log('[myclaw-skill] ❌ 未找到 OpenClaw skills 目录');
|
|
97
|
+
console.log('[myclaw-skill] 提示: 确保 openclaw 已全局安装');
|
|
98
|
+
return { success: false, reason: 'skills-dir-not-found' };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.log('[myclaw-skill] 📍 找到 skills 目录: ' + skillsDir);
|
|
102
|
+
|
|
103
|
+
// myclaw 自带的 skills 源目录
|
|
104
|
+
const myclawSkillsDir = path.join(__dirname, 'skills');
|
|
105
|
+
|
|
106
|
+
if (!fs.existsSync(myclawSkillsDir)) {
|
|
107
|
+
console.log('[myclaw-skill] ⚠️ 无 skill 可注入 (skills/ 目录不存在)');
|
|
108
|
+
return { success: true, count: 0 };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 遍历 skills/ 目录下的每个子目录 = 一个 skill
|
|
112
|
+
const skillDirs = fs.readdirSync(myclawSkillsDir, { withFileTypes: true })
|
|
113
|
+
.filter(d => d.isDirectory());
|
|
114
|
+
|
|
115
|
+
if (skillDirs.length === 0) {
|
|
116
|
+
console.log('[myclaw-skill] ⚠️ 无 skill 可注入 (skills/ 目录为空)');
|
|
117
|
+
return { success: true, count: 0 };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
let count = 0;
|
|
121
|
+
for (const skillDir of skillDirs) {
|
|
122
|
+
const srcDir = path.join(myclawSkillsDir, skillDir.name);
|
|
123
|
+
const destDir = path.join(skillsDir, skillDir.name);
|
|
124
|
+
|
|
125
|
+
// 检查是否有 SKILL.md(必须有才是合法 skill)
|
|
126
|
+
if (!fs.existsSync(path.join(srcDir, 'SKILL.md'))) {
|
|
127
|
+
console.log('[myclaw-skill] ⚠️ 跳过 ' + skillDir.name + ' (缺少 SKILL.md)');
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
copyDirSync(srcDir, destDir);
|
|
132
|
+
count++;
|
|
133
|
+
console.log('[myclaw-skill] ✅ 已注入: ' + skillDir.name);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
console.log('[myclaw-skill] 🎉 共注入 ' + count + ' 个 skill');
|
|
137
|
+
return { success: true, count };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* 列出已注入的 myclaw skills
|
|
142
|
+
*/
|
|
143
|
+
function listSkills() {
|
|
144
|
+
const skillsDir = findSkillsDir();
|
|
145
|
+
if (!skillsDir) {
|
|
146
|
+
console.log('[myclaw-skill] ❌ 未找到 OpenClaw skills 目录');
|
|
147
|
+
return [];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const myclawSkillsDir = path.join(__dirname, 'skills');
|
|
151
|
+
if (!fs.existsSync(myclawSkillsDir)) {
|
|
152
|
+
return [];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const mySkillNames = fs.readdirSync(myclawSkillsDir, { withFileTypes: true })
|
|
156
|
+
.filter(d => d.isDirectory())
|
|
157
|
+
.map(d => d.name);
|
|
158
|
+
|
|
159
|
+
const installed = [];
|
|
160
|
+
for (const name of mySkillNames) {
|
|
161
|
+
const destDir = path.join(skillsDir, name);
|
|
162
|
+
installed.push({
|
|
163
|
+
name,
|
|
164
|
+
installed: fs.existsSync(destDir),
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return installed;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
module.exports = { patchSkills, listSkills, findSkillsDir };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: minimax-inject
|
|
3
|
+
description: 将 OpenClaw 的模型配置替换为 MiniMax M2.7,并可选设置 API Key。执行后自动重启 Gateway。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# MiniMax 模型注入
|
|
7
|
+
|
|
8
|
+
将 OpenClaw 的模型配置清空,替换为唯一的 MiniMax M2.7 模型。
|
|
9
|
+
|
|
10
|
+
## 使用方法
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# 只注入模型配置(API Key 使用环境变量 MINIMAX_API_KEY)
|
|
14
|
+
node scripts/inject.js
|
|
15
|
+
|
|
16
|
+
# 注入模型 + 设置 API Key
|
|
17
|
+
node scripts/inject.js --key sk-你的key
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 注入内容
|
|
21
|
+
|
|
22
|
+
| 字段 | 值 |
|
|
23
|
+
|------|-----|
|
|
24
|
+
| auth.profiles | minimax:cn |
|
|
25
|
+
| models.providers | minimax (MiniMax-M2.7) |
|
|
26
|
+
| agents.defaults.model | minimax/MiniMax-M2.7-highspeed |
|
|
27
|
+
| imageGenerationModel | minimax/image-01 |
|
|
28
|
+
|
|
29
|
+
## 执行后
|
|
30
|
+
|
|
31
|
+
- 自动修改 `~/.openclaw/openclaw.json`
|
|
32
|
+
- 自动重启 Gateway 使配置生效
|
|
33
|
+
- 如果传了 `--key`,会将 MINIMAX_API_KEY 写入 shell 配置文件
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MiniMax 模型注入脚本
|
|
5
|
+
*
|
|
6
|
+
* 独立运行,不依赖 myclaw CLI。
|
|
7
|
+
* OpenClaw agent 可直接调用此脚本。
|
|
8
|
+
*
|
|
9
|
+
* 用法:
|
|
10
|
+
* node inject.js # 注入模型配置
|
|
11
|
+
* node inject.js --key sk-xxx # 注入模型 + 设置 API Key
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
const os = require('os');
|
|
17
|
+
const { execSync } = require('child_process');
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// 解析参数
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
let apiKey = null;
|
|
24
|
+
const args = process.argv.slice(2);
|
|
25
|
+
for (let i = 0; i < args.length; i++) {
|
|
26
|
+
if (args[i] === '--key' && args[i + 1]) {
|
|
27
|
+
apiKey = args[i + 1];
|
|
28
|
+
i++;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ============================================================================
|
|
33
|
+
// 查找 openclaw.json
|
|
34
|
+
// ============================================================================
|
|
35
|
+
|
|
36
|
+
const openclawDir = path.join(os.homedir(), '.openclaw');
|
|
37
|
+
const targetPath = path.join(openclawDir, 'openclaw.json');
|
|
38
|
+
|
|
39
|
+
if (!fs.existsSync(targetPath)) {
|
|
40
|
+
console.error('❌ 未找到 openclaw.json: ' + targetPath);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
console.log('📍 找到配置: ' + targetPath);
|
|
45
|
+
|
|
46
|
+
// ============================================================================
|
|
47
|
+
// 注入模型配置
|
|
48
|
+
// ============================================================================
|
|
49
|
+
|
|
50
|
+
const config = JSON.parse(fs.readFileSync(targetPath, 'utf8'));
|
|
51
|
+
|
|
52
|
+
config.auth = {
|
|
53
|
+
profiles: {
|
|
54
|
+
"minimax:cn": {
|
|
55
|
+
provider: "minimax",
|
|
56
|
+
mode: "api_key"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
config.models = {
|
|
62
|
+
mode: "merge",
|
|
63
|
+
providers: {
|
|
64
|
+
minimax: {
|
|
65
|
+
baseUrl: "https://api.minimaxi.com/anthropic",
|
|
66
|
+
api: "anthropic-messages",
|
|
67
|
+
authHeader: true,
|
|
68
|
+
headers: {
|
|
69
|
+
"Authorization": "Bearer ${env:MINIMAX_API_KEY}"
|
|
70
|
+
},
|
|
71
|
+
models: [
|
|
72
|
+
{
|
|
73
|
+
id: "MiniMax-M2.7",
|
|
74
|
+
name: "MiniMax M2.7",
|
|
75
|
+
reasoning: true,
|
|
76
|
+
input: ["text"],
|
|
77
|
+
cost: {
|
|
78
|
+
input: 0.3,
|
|
79
|
+
output: 1.2,
|
|
80
|
+
cacheRead: 0.06,
|
|
81
|
+
cacheWrite: 0.375
|
|
82
|
+
},
|
|
83
|
+
contextWindow: 204800,
|
|
84
|
+
maxTokens: 131072
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
if (!config.agents) config.agents = {};
|
|
92
|
+
if (!config.agents.defaults) config.agents.defaults = {};
|
|
93
|
+
|
|
94
|
+
config.agents.defaults.model = {
|
|
95
|
+
primary: "minimax/MiniMax-M2.7-highspeed"
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
config.agents.defaults.imageGenerationModel = {
|
|
99
|
+
primary: "minimax/image-01"
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
config.agents.defaults.models = {
|
|
103
|
+
"minimax/MiniMax-M2.7-highspeed": {}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
fs.writeFileSync(targetPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
107
|
+
|
|
108
|
+
console.log('✅ MiniMax 模型配置已注入');
|
|
109
|
+
console.log(' auth.profiles → minimax:cn');
|
|
110
|
+
console.log(' models.providers → minimax (MiniMax-M2.7)');
|
|
111
|
+
console.log(' agents.defaults → minimax/MiniMax-M2.7-highspeed');
|
|
112
|
+
|
|
113
|
+
// ============================================================================
|
|
114
|
+
// 设置 API Key(如果传了 --key)
|
|
115
|
+
// ============================================================================
|
|
116
|
+
|
|
117
|
+
if (apiKey) {
|
|
118
|
+
console.log('');
|
|
119
|
+
console.log('🔑 设置 MINIMAX_API_KEY...');
|
|
120
|
+
|
|
121
|
+
if (os.platform() === 'win32') {
|
|
122
|
+
try {
|
|
123
|
+
execSync('setx MINIMAX_API_KEY "' + apiKey + '"', { stdio: 'pipe' });
|
|
124
|
+
console.log(' ✅ 已写入 Windows 用户环境变量');
|
|
125
|
+
} catch (err) {
|
|
126
|
+
console.log(' ❌ setx 失败: ' + err.message);
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
const shell = process.env.SHELL || '/bin/bash';
|
|
130
|
+
const rcFile = shell.includes('zsh')
|
|
131
|
+
? path.join(os.homedir(), '.zshrc')
|
|
132
|
+
: path.join(os.homedir(), '.bashrc');
|
|
133
|
+
|
|
134
|
+
const exportLine = 'export MINIMAX_API_KEY="' + apiKey + '"';
|
|
135
|
+
let content = '';
|
|
136
|
+
try { content = fs.readFileSync(rcFile, 'utf8'); } catch {}
|
|
137
|
+
|
|
138
|
+
if (content.includes('MINIMAX_API_KEY')) {
|
|
139
|
+
content = content.replace(/^export MINIMAX_API_KEY=.*$/m, exportLine);
|
|
140
|
+
fs.writeFileSync(rcFile, content, 'utf8');
|
|
141
|
+
console.log(' ✅ 已更新: ' + rcFile);
|
|
142
|
+
} else {
|
|
143
|
+
fs.appendFileSync(rcFile, '\n# MiniMax API Key\n' + exportLine + '\n');
|
|
144
|
+
console.log(' ✅ 已追加: ' + rcFile);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// 同时设到当前进程,确保重启的 gateway 能继承
|
|
148
|
+
process.env.MINIMAX_API_KEY = apiKey;
|
|
149
|
+
console.log(' ✅ 当前进程已设置');
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
console.log('');
|
|
153
|
+
console.log('💡 未传入 --key,将使用环境变量 MINIMAX_API_KEY');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ============================================================================
|
|
157
|
+
// 重启 Gateway(不依赖 myclaw)
|
|
158
|
+
// ============================================================================
|
|
159
|
+
|
|
160
|
+
console.log('');
|
|
161
|
+
console.log('🔄 重启 Gateway...');
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
execSync('openclaw gateway stop', { stdio: 'pipe', timeout: 10000 });
|
|
165
|
+
console.log(' Gateway 已停止');
|
|
166
|
+
} catch {
|
|
167
|
+
console.log(' Gateway 未在运行');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
execSync('nohup openclaw gateway > /tmp/openclaw-gateway.log 2>&1 &', {
|
|
172
|
+
stdio: 'ignore',
|
|
173
|
+
shell: true,
|
|
174
|
+
});
|
|
175
|
+
execSync('sleep 2', { stdio: 'ignore' });
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
execSync('openclaw health', { stdio: 'pipe', timeout: 5000 });
|
|
179
|
+
console.log(' ✅ Gateway 启动成功');
|
|
180
|
+
} catch {
|
|
181
|
+
console.log(' ⏳ Gateway 启动中...');
|
|
182
|
+
}
|
|
183
|
+
} catch (err) {
|
|
184
|
+
console.error(' ❌ 启动失败: ' + err.message);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
console.log('');
|