@aiyiran/myclaw 1.0.61 → 1.0.63
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/find-config.js +121 -0
- package/index.js +18 -1
- package/inject-minimax.js +56 -63
- package/launch.js +154 -0
- package/package.json +1 -1
- package/patch-reset.js +59 -0
- package/skills/minimax-inject/scripts/inject.js +42 -31
- package/wsl2.js +13 -10
package/find-config.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* find-config.js — OpenClaw 配置文件定位 & 读写工具
|
|
3
|
+
*
|
|
4
|
+
* 通用能力:跨平台自动查找 ~/.openclaw/openclaw.json
|
|
5
|
+
* 所有需要读写 openclaw.json 的模块都应该调用这个工具
|
|
6
|
+
*
|
|
7
|
+
* 使用:
|
|
8
|
+
* const { findConfig, readConfig, writeConfig, patchConfig } = require('./find-config');
|
|
9
|
+
*
|
|
10
|
+
* const configPath = findConfig(); // 返回路径或 null
|
|
11
|
+
* const config = readConfig(); // 读取 JSON 对象
|
|
12
|
+
* writeConfig(config); // 写回整个 JSON
|
|
13
|
+
* patchConfig({ session: { reset: { mode: 'idle' } } }); // 深度合并局部字段
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const os = require('os');
|
|
19
|
+
|
|
20
|
+
const CONFIG_FILENAME = 'openclaw.json';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 查找 openclaw.json 的路径
|
|
24
|
+
* 按优先级尝试:
|
|
25
|
+
* 1. ~/.openclaw/openclaw.json(标准路径)
|
|
26
|
+
* 2. 环境变量 OPENCLAW_HOME 指定的目录
|
|
27
|
+
*
|
|
28
|
+
* @returns {string|null} 配置文件路径,未找到返回 null
|
|
29
|
+
*/
|
|
30
|
+
function findConfig() {
|
|
31
|
+
const candidates = [];
|
|
32
|
+
|
|
33
|
+
// 1. 环境变量优先
|
|
34
|
+
if (process.env.OPENCLAW_HOME) {
|
|
35
|
+
candidates.push(path.join(process.env.OPENCLAW_HOME, CONFIG_FILENAME));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 2. 标准路径 ~/.openclaw/
|
|
39
|
+
candidates.push(path.join(os.homedir(), '.openclaw', CONFIG_FILENAME));
|
|
40
|
+
|
|
41
|
+
// 3. Windows WSL 下 /root/.openclaw/
|
|
42
|
+
if (os.platform() === 'linux') {
|
|
43
|
+
candidates.push(path.join('/root', '.openclaw', CONFIG_FILENAME));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
for (const p of candidates) {
|
|
47
|
+
try {
|
|
48
|
+
if (fs.existsSync(p)) {
|
|
49
|
+
return p;
|
|
50
|
+
}
|
|
51
|
+
} catch {}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 读取 openclaw.json 并解析为 JSON 对象
|
|
59
|
+
* @returns {{ config: object, configPath: string }}
|
|
60
|
+
* @throws {Error} 未找到或解析失败
|
|
61
|
+
*/
|
|
62
|
+
function readConfig() {
|
|
63
|
+
const configPath = findConfig();
|
|
64
|
+
if (!configPath) {
|
|
65
|
+
throw new Error('未找到 openclaw.json,请确认 OpenClaw 已安装');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const raw = fs.readFileSync(configPath, 'utf8');
|
|
69
|
+
const config = JSON.parse(raw);
|
|
70
|
+
return { config, configPath };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 写入完整的 config 对象到 openclaw.json
|
|
75
|
+
* @param {object} config - 完整的配置对象
|
|
76
|
+
* @param {string} [configPath] - 可选路径,不传则自动查找
|
|
77
|
+
*/
|
|
78
|
+
function writeConfig(config, configPath) {
|
|
79
|
+
if (!configPath) {
|
|
80
|
+
configPath = findConfig();
|
|
81
|
+
if (!configPath) {
|
|
82
|
+
throw new Error('未找到 openclaw.json,无法写入');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 深度合并 patch 到现有配置(只改指定字段,不影响其他)
|
|
91
|
+
* @param {object} patch - 要合并的局部配置
|
|
92
|
+
* @returns {{ config: object, configPath: string }} 合并后的结果
|
|
93
|
+
*/
|
|
94
|
+
function patchConfig(patch) {
|
|
95
|
+
const { config, configPath } = readConfig();
|
|
96
|
+
deepMerge(config, patch);
|
|
97
|
+
writeConfig(config, configPath);
|
|
98
|
+
return { config, configPath };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* 深度合并 source 到 target(就地修改)
|
|
103
|
+
*/
|
|
104
|
+
function deepMerge(target, source) {
|
|
105
|
+
for (const key of Object.keys(source)) {
|
|
106
|
+
if (
|
|
107
|
+
source[key] !== null &&
|
|
108
|
+
typeof source[key] === 'object' &&
|
|
109
|
+
!Array.isArray(source[key]) &&
|
|
110
|
+
target[key] !== null &&
|
|
111
|
+
typeof target[key] === 'object' &&
|
|
112
|
+
!Array.isArray(target[key])
|
|
113
|
+
) {
|
|
114
|
+
deepMerge(target[key], source[key]);
|
|
115
|
+
} else {
|
|
116
|
+
target[key] = source[key];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
module.exports = { findConfig, readConfig, writeConfig, patchConfig, deepMerge };
|
package/index.js
CHANGED
|
@@ -582,10 +582,11 @@ function runOpen() {
|
|
|
582
582
|
function runPatch() {
|
|
583
583
|
const { patch, status: patchStatus } = require('./patch');
|
|
584
584
|
const { patchSkills } = require('./patch-skill');
|
|
585
|
+
const { patchConfig } = require('./find-config');
|
|
585
586
|
const bar = '----------------------------------------';
|
|
586
587
|
|
|
587
588
|
console.log('');
|
|
588
|
-
console.log('[' + colors.blue + 'MyClaw' + colors.nc + '] ' + colors.blue + 'Patch (UI + Skills)' + colors.nc);
|
|
589
|
+
console.log('[' + colors.blue + 'MyClaw' + colors.nc + '] ' + colors.blue + 'Patch (UI + Skills + Config)' + colors.nc);
|
|
589
590
|
console.log(bar);
|
|
590
591
|
console.log('');
|
|
591
592
|
|
|
@@ -596,6 +597,22 @@ function runPatch() {
|
|
|
596
597
|
console.log('');
|
|
597
598
|
const skillResult = patchSkills();
|
|
598
599
|
|
|
600
|
+
// 3. Config 补丁(修改 openclaw.json 的特定字段)
|
|
601
|
+
console.log('');
|
|
602
|
+
try {
|
|
603
|
+
const { config, configPath } = patchConfig({
|
|
604
|
+
session: {
|
|
605
|
+
reset: {
|
|
606
|
+
mode: "idle",
|
|
607
|
+
idleMinutes: 90720
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
});
|
|
611
|
+
console.log('[myclaw-config] ✅ session.reset → idle (90720 分钟)');
|
|
612
|
+
} catch (err) {
|
|
613
|
+
console.log('[myclaw-config] ⚠️ 配置补丁失败: ' + err.message);
|
|
614
|
+
}
|
|
615
|
+
|
|
599
616
|
if (uiResult.success || skillResult.success) {
|
|
600
617
|
console.log('');
|
|
601
618
|
console.log(bar);
|
package/inject-minimax.js
CHANGED
|
@@ -4,15 +4,15 @@
|
|
|
4
4
|
* inject-minimax.js
|
|
5
5
|
*
|
|
6
6
|
* 将 openclaw.json 中的模型配置清空,注入为唯一的 MiniMax 模型。
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
*
|
|
8
|
+
* 流程:
|
|
9
|
+
* 1. 先执行 openclaw onboard(设置 API Key,会覆盖 JSON)
|
|
10
|
+
* 2. 再写入我们的 JSON 配置(覆盖回来)
|
|
9
11
|
*
|
|
10
12
|
* 入口: myclaw minimax [--key sk-xxx]
|
|
11
13
|
*/
|
|
12
14
|
|
|
13
|
-
const
|
|
14
|
-
const path = require('path');
|
|
15
|
-
const os = require('os');
|
|
15
|
+
const { readConfig, writeConfig } = require('./find-config');
|
|
16
16
|
|
|
17
17
|
function run(cliArgs) {
|
|
18
18
|
// 解析 --key 参数
|
|
@@ -24,23 +24,55 @@ function run(cliArgs) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
console.error('❌
|
|
33
|
-
console.error(' 期望路径: ' + targetPath);
|
|
34
|
-
console.error(' 请先安装 OpenClaw: myclaw install');
|
|
27
|
+
// 查找配置
|
|
28
|
+
let configPath;
|
|
29
|
+
try {
|
|
30
|
+
({ configPath } = readConfig());
|
|
31
|
+
} catch (err) {
|
|
32
|
+
console.error('❌ ' + err.message);
|
|
35
33
|
process.exit(1);
|
|
36
34
|
}
|
|
37
35
|
|
|
38
|
-
console.log('📍 找到配置: ' +
|
|
36
|
+
console.log('📍 找到配置: ' + configPath);
|
|
37
|
+
|
|
38
|
+
// ============================================================
|
|
39
|
+
// 第一步:先执行 onboard(它会覆盖 JSON,所以必须先跑)
|
|
40
|
+
// ============================================================
|
|
41
|
+
|
|
42
|
+
if (apiKey) {
|
|
43
|
+
console.log('');
|
|
44
|
+
console.log('🔑 [Step 1] 执行 openclaw onboard (设置 API Key)...');
|
|
45
|
+
try {
|
|
46
|
+
const { execSync } = require('child_process');
|
|
47
|
+
execSync([
|
|
48
|
+
'openclaw onboard',
|
|
49
|
+
'--non-interactive',
|
|
50
|
+
'--accept-risk',
|
|
51
|
+
'--skip-health',
|
|
52
|
+
'--auth-choice minimax-cn-api',
|
|
53
|
+
'--token "' + apiKey + '"',
|
|
54
|
+
'--minimax-api-key "' + apiKey + '"',
|
|
55
|
+
].join(' '), { stdio: 'inherit' });
|
|
56
|
+
console.log('✅ API Key 已通过 onboard 设置');
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.log('⚠️ onboard 失败 (继续注入 JSON): ' + err.message);
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
console.log('');
|
|
62
|
+
console.log('💡 未传入 --key,跳过 onboard');
|
|
63
|
+
console.log(' 设置方法: myclaw minimax --key sk-xxx');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ============================================================
|
|
67
|
+
// 第二步:写入我们的 JSON 配置(覆盖 onboard 的修改)
|
|
68
|
+
// ============================================================
|
|
39
69
|
|
|
40
|
-
|
|
41
|
-
|
|
70
|
+
console.log('');
|
|
71
|
+
console.log('📝 [Step 2] 注入 MiniMax 模型配置...');
|
|
72
|
+
|
|
73
|
+
// 重新读取(onboard 可能已改过)
|
|
74
|
+
const { config } = readConfig();
|
|
42
75
|
|
|
43
|
-
// 1. auth.profiles → 只保留 minimax
|
|
44
76
|
config.auth = {
|
|
45
77
|
profiles: {
|
|
46
78
|
"minimax:cn": {
|
|
@@ -50,7 +82,6 @@ function run(cliArgs) {
|
|
|
50
82
|
}
|
|
51
83
|
};
|
|
52
84
|
|
|
53
|
-
// 2. models.providers → 只保留 minimax(key 由 onboard 管理)
|
|
54
85
|
config.models = {
|
|
55
86
|
mode: "merge",
|
|
56
87
|
providers: {
|
|
@@ -78,7 +109,6 @@ function run(cliArgs) {
|
|
|
78
109
|
}
|
|
79
110
|
};
|
|
80
111
|
|
|
81
|
-
// 3. agents.defaults → 使用 minimax 模型
|
|
82
112
|
if (!config.agents) config.agents = {};
|
|
83
113
|
if (!config.agents.defaults) config.agents.defaults = {};
|
|
84
114
|
|
|
@@ -94,53 +124,16 @@ function run(cliArgs) {
|
|
|
94
124
|
"minimax/MiniMax-M2.7-highspeed": {}
|
|
95
125
|
};
|
|
96
126
|
|
|
97
|
-
|
|
98
|
-
fs.writeFileSync(targetPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
127
|
+
writeConfig(config, configPath);
|
|
99
128
|
|
|
100
129
|
// 验证写入
|
|
101
|
-
const verify =
|
|
102
|
-
const writtenModelId = verify.models?.providers?.minimax?.models?.[0]?.id || '???';
|
|
103
|
-
const writtenDefault = verify.agents?.defaults?.model?.primary || '???';
|
|
104
|
-
|
|
105
|
-
console.log('✅ MiniMax 模型配置已注入');
|
|
106
|
-
console.log('');
|
|
107
|
-
console.log(' [验证] 写入的 model ID: ' + writtenModelId);
|
|
108
|
-
console.log(' [验证] 写入的 default: ' + writtenDefault);
|
|
109
|
-
console.log(' [验证] 文件路径: ' + targetPath);
|
|
130
|
+
const verify = readConfig();
|
|
131
|
+
const writtenModelId = verify.config.models?.providers?.minimax?.models?.[0]?.id || '???';
|
|
132
|
+
const writtenDefault = verify.config.agents?.defaults?.model?.primary || '???';
|
|
110
133
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
console.log('🔑 执行 openclaw onboard (设置 API Key)...');
|
|
115
|
-
try {
|
|
116
|
-
const { execSync } = require('child_process');
|
|
117
|
-
execSync([
|
|
118
|
-
'openclaw onboard',
|
|
119
|
-
'--non-interactive',
|
|
120
|
-
'--accept-risk',
|
|
121
|
-
'--skip-health',
|
|
122
|
-
'--auth-choice minimax-cn-api',
|
|
123
|
-
'--token "' + apiKey + '"',
|
|
124
|
-
'--minimax-api-key "' + apiKey + '"',
|
|
125
|
-
].join(' '), { stdio: 'inherit' });
|
|
126
|
-
console.log('✅ API Key 已通过 onboard 设置');
|
|
127
|
-
|
|
128
|
-
// 再次验证
|
|
129
|
-
const reVerify = JSON.parse(fs.readFileSync(targetPath, 'utf8'));
|
|
130
|
-
const finalModelId = reVerify.models?.providers?.minimax?.models?.[0]?.id || '???';
|
|
131
|
-
const finalDefault = reVerify.agents?.defaults?.model?.primary || '???';
|
|
132
|
-
|
|
133
|
-
if (finalModelId !== "MiniMax-M2.7-highspeed") {
|
|
134
|
-
console.log('⚠️ [警告] onboard 命令覆盖了你配置的模型 ID: ' + finalModelId);
|
|
135
|
-
}
|
|
136
|
-
} catch (err) {
|
|
137
|
-
console.log('⚠️ onboard 失败: ' + err.message);
|
|
138
|
-
}
|
|
139
|
-
} else {
|
|
140
|
-
console.log('');
|
|
141
|
-
console.log('💡 未传入 --key,跳过 API Key 设置');
|
|
142
|
-
console.log(' 设置方法: myclaw minimax --key sk-xxx');
|
|
143
|
-
}
|
|
134
|
+
console.log('✅ 配置已注入');
|
|
135
|
+
console.log(' [验证] model ID: ' + writtenModelId);
|
|
136
|
+
console.log(' [验证] default: ' + writtenDefault);
|
|
144
137
|
|
|
145
138
|
console.log('');
|
|
146
139
|
}
|
package/launch.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ============================================================================
|
|
5
|
+
* MyClaw Launch - 统一启动流程
|
|
6
|
+
* ============================================================================
|
|
7
|
+
*
|
|
8
|
+
* 使用: myclaw launch
|
|
9
|
+
*
|
|
10
|
+
* 统一的启动链条,被 bat 脚本和 wsl2 安装器共同复用:
|
|
11
|
+
* Step 1: 更新 MyClaw 到最新版
|
|
12
|
+
* Step 2: 执行 Patch(UI + Skills + Config)
|
|
13
|
+
* Step 3: 后台启动 OpenClaw Gateway
|
|
14
|
+
* Step 4: 打开浏览器控制台
|
|
15
|
+
* Step 5: 等待 Gateway 进程(关闭终端 = 停止服务)
|
|
16
|
+
* ============================================================================
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const { execSync, spawn } = require('child_process');
|
|
20
|
+
const os = require('os');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
|
|
23
|
+
const isWindows = os.platform() === 'win32';
|
|
24
|
+
const C = isWindows
|
|
25
|
+
? { r: '', g: '', y: '', b: '', nc: '' }
|
|
26
|
+
: { r: '\x1b[31m', g: '\x1b[32m', y: '\x1b[33m', b: '\x1b[34m', nc: '\x1b[0m' };
|
|
27
|
+
|
|
28
|
+
const BAR = '============================================';
|
|
29
|
+
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// Step 1: 更新 MyClaw
|
|
32
|
+
// ============================================================================
|
|
33
|
+
|
|
34
|
+
function stepUpdate() {
|
|
35
|
+
console.log('[1/4] 更新 MyClaw...');
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
const registry = 'https://registry.npmjs.org';
|
|
39
|
+
const pkg = '@aiyiran/myclaw';
|
|
40
|
+
const currentVersion = require('./package.json').version;
|
|
41
|
+
|
|
42
|
+
const latestVersion = execSync(
|
|
43
|
+
'npm view ' + pkg + ' version --registry ' + registry,
|
|
44
|
+
{ encoding: 'utf8', timeout: 15000 }
|
|
45
|
+
).trim();
|
|
46
|
+
|
|
47
|
+
if (currentVersion === latestVersion) {
|
|
48
|
+
console.log(' ' + C.g + '[OK]' + C.nc + ' 已是最新 v' + currentVersion);
|
|
49
|
+
} else {
|
|
50
|
+
console.log(' v' + currentVersion + ' → v' + latestVersion);
|
|
51
|
+
const tarball = execSync(
|
|
52
|
+
'npm view ' + pkg + ' dist.tarball --registry ' + registry,
|
|
53
|
+
{ encoding: 'utf8', timeout: 15000 }
|
|
54
|
+
).trim();
|
|
55
|
+
execSync('npm install -g ' + tarball, { stdio: 'pipe', timeout: 60000 });
|
|
56
|
+
console.log(' ' + C.g + '[OK]' + C.nc + ' 已升级到 v' + latestVersion);
|
|
57
|
+
}
|
|
58
|
+
} catch (err) {
|
|
59
|
+
console.log(' ' + C.y + '[跳过]' + C.nc + ' 更新失败 (非致命)');
|
|
60
|
+
}
|
|
61
|
+
console.log('');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ============================================================================
|
|
65
|
+
// Step 2: 执行 Patch
|
|
66
|
+
// ============================================================================
|
|
67
|
+
|
|
68
|
+
function stepPatch() {
|
|
69
|
+
console.log('[2/4] Patch...');
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const { patch } = require('./patch');
|
|
73
|
+
const { patchSkills } = require('./patch-skill');
|
|
74
|
+
const { patchConfig } = require('./find-config');
|
|
75
|
+
|
|
76
|
+
patch();
|
|
77
|
+
patchSkills();
|
|
78
|
+
patchConfig({
|
|
79
|
+
session: {
|
|
80
|
+
reset: {
|
|
81
|
+
mode: 'idle',
|
|
82
|
+
idleMinutes: 90720,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
console.log(' ' + C.g + '[OK]' + C.nc);
|
|
88
|
+
} catch (err) {
|
|
89
|
+
console.log(' ' + C.y + '[跳过]' + C.nc + ' ' + err.message);
|
|
90
|
+
}
|
|
91
|
+
console.log('');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ============================================================================
|
|
95
|
+
// Step 3 & 4: 启动 Gateway + 打开浏览器
|
|
96
|
+
// ============================================================================
|
|
97
|
+
|
|
98
|
+
function stepGatewayAndOpen() {
|
|
99
|
+
console.log('[3/4] 启动 Gateway...');
|
|
100
|
+
console.log('');
|
|
101
|
+
console.log(BAR);
|
|
102
|
+
console.log(' Gateway starting...');
|
|
103
|
+
console.log(' 关闭此窗口 = 停止服务');
|
|
104
|
+
console.log(BAR);
|
|
105
|
+
console.log('');
|
|
106
|
+
|
|
107
|
+
// 后台启动 gateway
|
|
108
|
+
const gateway = spawn('openclaw', ['gateway'], {
|
|
109
|
+
stdio: 'inherit',
|
|
110
|
+
detached: false,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// 打开浏览器(不阻塞)
|
|
114
|
+
console.log('[4/4] 打开浏览器...');
|
|
115
|
+
try {
|
|
116
|
+
// 直接调用 runOpen 的逻辑
|
|
117
|
+
execSync('node "' + path.join(__dirname, 'index.js') + '" open', {
|
|
118
|
+
stdio: 'pipe',
|
|
119
|
+
timeout: 10000,
|
|
120
|
+
});
|
|
121
|
+
console.log(' ' + C.g + '[OK]' + C.nc);
|
|
122
|
+
} catch {
|
|
123
|
+
console.log(' ' + C.y + '[跳过]' + C.nc);
|
|
124
|
+
}
|
|
125
|
+
console.log('');
|
|
126
|
+
|
|
127
|
+
// 等待 gateway 进程退出(关闭终端会终止)
|
|
128
|
+
return new Promise((resolve) => {
|
|
129
|
+
gateway.on('close', (code) => {
|
|
130
|
+
console.log('');
|
|
131
|
+
console.log(' Gateway 已退出。');
|
|
132
|
+
resolve(code);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ============================================================================
|
|
138
|
+
// 主入口
|
|
139
|
+
// ============================================================================
|
|
140
|
+
|
|
141
|
+
async function run() {
|
|
142
|
+
const bar = '----------------------------------------';
|
|
143
|
+
|
|
144
|
+
console.log('');
|
|
145
|
+
console.log('[' + C.b + 'MyClaw' + C.nc + '] ' + C.b + '启动流程' + C.nc);
|
|
146
|
+
console.log(bar);
|
|
147
|
+
console.log('');
|
|
148
|
+
|
|
149
|
+
stepUpdate();
|
|
150
|
+
stepPatch();
|
|
151
|
+
await stepGatewayAndOpen();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
module.exports = { run };
|
package/package.json
CHANGED
package/patch-reset.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* patch-reset.js — 修改 openclaw.json 的 session.reset 字段
|
|
3
|
+
*
|
|
4
|
+
* 使用 patchConfig 精准修改,不影响其他配置。
|
|
5
|
+
*
|
|
6
|
+
* 入口: myclaw reset-idle [--minutes N]
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { patchConfig, readConfig } = require('./find-config');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 将 session.reset 设为 idle 模式,默认 90720 分钟(≈63 天)
|
|
13
|
+
* @param {number} [idleMinutes=90720] - idle 超时分钟数
|
|
14
|
+
*/
|
|
15
|
+
function run(cliArgs) {
|
|
16
|
+
// 解析 --minutes 参数
|
|
17
|
+
let idleMinutes = 90720;
|
|
18
|
+
if (cliArgs) {
|
|
19
|
+
for (let i = 0; i < cliArgs.length; i++) {
|
|
20
|
+
if (cliArgs[i] === '--minutes' && cliArgs[i + 1]) {
|
|
21
|
+
idleMinutes = parseInt(cliArgs[i + 1], 10);
|
|
22
|
+
if (isNaN(idleMinutes) || idleMinutes <= 0) {
|
|
23
|
+
console.error('❌ --minutes 必须是正整数');
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
i++;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
console.log('📝 修改 session.reset...');
|
|
32
|
+
console.log(' mode: idle');
|
|
33
|
+
console.log(' idleMinutes: ' + idleMinutes + ' (' + Math.round(idleMinutes / 1440) + ' 天)');
|
|
34
|
+
console.log('');
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const { config, configPath } = patchConfig({
|
|
38
|
+
session: {
|
|
39
|
+
reset: {
|
|
40
|
+
mode: "idle",
|
|
41
|
+
idleMinutes: idleMinutes
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// 验证
|
|
47
|
+
const reset = config.session?.reset;
|
|
48
|
+
console.log('✅ 已修改: ' + configPath);
|
|
49
|
+
console.log(' [验证] session.reset.mode: ' + (reset?.mode || '???'));
|
|
50
|
+
console.log(' [验证] session.reset.idleMinutes: ' + (reset?.idleMinutes || '???'));
|
|
51
|
+
} catch (err) {
|
|
52
|
+
console.error('❌ ' + err.message);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log('');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = { run };
|
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
* 独立运行,不依赖 myclaw CLI。
|
|
7
7
|
* OpenClaw agent 可直接调用此脚本。
|
|
8
8
|
*
|
|
9
|
+
* 流程:
|
|
10
|
+
* 1. 先执行 openclaw onboard(设置 API Key,会覆盖 JSON)
|
|
11
|
+
* 2. 再写入我们的 JSON 配置(覆盖回来)
|
|
12
|
+
*
|
|
9
13
|
* 用法:
|
|
10
14
|
* node inject.js # 只注入模型配置(不设 key)
|
|
11
15
|
* node inject.js --key sk-xxx # 注入模型 + 通过 onboard 设置 key
|
|
@@ -44,9 +48,39 @@ if (!fs.existsSync(targetPath)) {
|
|
|
44
48
|
console.log('📍 找到配置: ' + targetPath);
|
|
45
49
|
|
|
46
50
|
// ============================================================================
|
|
47
|
-
//
|
|
51
|
+
// 第一步:先执行 onboard(它会覆盖 JSON,所以必须先跑)
|
|
52
|
+
// ============================================================================
|
|
53
|
+
|
|
54
|
+
if (apiKey) {
|
|
55
|
+
console.log('');
|
|
56
|
+
console.log('🔑 [Step 1] 执行 openclaw onboard (设置 API Key)...');
|
|
57
|
+
try {
|
|
58
|
+
execSync([
|
|
59
|
+
'openclaw onboard',
|
|
60
|
+
'--non-interactive',
|
|
61
|
+
'--accept-risk',
|
|
62
|
+
'--skip-health',
|
|
63
|
+
'--auth-choice minimax-cn-api',
|
|
64
|
+
'--token "' + apiKey + '"',
|
|
65
|
+
'--minimax-api-key "' + apiKey + '"',
|
|
66
|
+
].join(' '), { stdio: 'inherit' });
|
|
67
|
+
console.log('✅ API Key 已通过 onboard 设置');
|
|
68
|
+
} catch (err) {
|
|
69
|
+
console.log('⚠️ onboard 失败 (继续注入 JSON): ' + err.message);
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
console.log('');
|
|
73
|
+
console.log('💡 未传入 --key,跳过 onboard');
|
|
74
|
+
console.log(' 设置方法: node inject.js --key sk-xxx');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ============================================================================
|
|
78
|
+
// 第二步:写入我们的 JSON 配置(覆盖 onboard 的修改)
|
|
48
79
|
// ============================================================================
|
|
49
80
|
|
|
81
|
+
console.log('');
|
|
82
|
+
console.log('📝 [Step 2] 注入 MiniMax 模型配置...');
|
|
83
|
+
|
|
50
84
|
const config = JSON.parse(fs.readFileSync(targetPath, 'utf8'));
|
|
51
85
|
|
|
52
86
|
config.auth = {
|
|
@@ -102,37 +136,14 @@ config.agents.defaults.models = {
|
|
|
102
136
|
|
|
103
137
|
fs.writeFileSync(targetPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
104
138
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// ============================================================================
|
|
111
|
-
// 通过 openclaw onboard 设置 API Key
|
|
112
|
-
// ============================================================================
|
|
139
|
+
// 验证写入
|
|
140
|
+
const verify = JSON.parse(fs.readFileSync(targetPath, 'utf8'));
|
|
141
|
+
const writtenModelId = verify.models?.providers?.minimax?.models?.[0]?.id || '???';
|
|
142
|
+
const writtenDefault = verify.agents?.defaults?.model?.primary || '???';
|
|
113
143
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
try {
|
|
118
|
-
execSync([
|
|
119
|
-
'openclaw onboard',
|
|
120
|
-
'--non-interactive',
|
|
121
|
-
'--accept-risk',
|
|
122
|
-
'--skip-health',
|
|
123
|
-
'--auth-choice minimax-cn-api',
|
|
124
|
-
'--token "' + apiKey + '"',
|
|
125
|
-
'--minimax-api-key "' + apiKey + '"',
|
|
126
|
-
].join(' '), { stdio: 'inherit' });
|
|
127
|
-
console.log('✅ API Key 已通过 onboard 设置');
|
|
128
|
-
} catch (err) {
|
|
129
|
-
console.log('⚠️ onboard 失败: ' + err.message);
|
|
130
|
-
}
|
|
131
|
-
} else {
|
|
132
|
-
console.log('');
|
|
133
|
-
console.log('💡 未传入 --key,跳过 API Key 设置');
|
|
134
|
-
console.log(' 设置方法: node inject.js --key sk-xxx');
|
|
135
|
-
}
|
|
144
|
+
console.log('✅ 配置已注入');
|
|
145
|
+
console.log(' [验证] model ID: ' + writtenModelId);
|
|
146
|
+
console.log(' [验证] default: ' + writtenDefault);
|
|
136
147
|
|
|
137
148
|
// ============================================================================
|
|
138
149
|
// 重启 Gateway
|
package/wsl2.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*
|
|
14
14
|
* 自动检测安装状态,分两阶段完成:
|
|
15
15
|
* Phase 1: 启用底层 Windows 功能 + 安装 WSL → 需要重启
|
|
16
|
-
* Phase 2: 导入预制 Linux 环境 →
|
|
16
|
+
* Phase 2: 导入预制 Linux 环境 → 自动启动 Gateway
|
|
17
17
|
* ============================================================================
|
|
18
18
|
*/
|
|
19
19
|
|
|
@@ -200,7 +200,7 @@ Write-Host ' MyClaw WSL2 安装 - 阶段 1/2'
|
|
|
200
200
|
Write-Host '========================================'
|
|
201
201
|
Write-Host ''
|
|
202
202
|
|
|
203
|
-
$dir = "$env:LOCALAPPDATA
|
|
203
|
+
$dir = "$env:LOCALAPPDATA\\\\myclaw"
|
|
204
204
|
New-Item -ItemType Directory -Force -Path $dir | Out-Null
|
|
205
205
|
|
|
206
206
|
Write-Host '[1/4] 启用 Windows Subsystem for Linux...'
|
|
@@ -222,7 +222,7 @@ try {
|
|
|
222
222
|
Write-Host ''
|
|
223
223
|
|
|
224
224
|
Write-Host '[3/4] 获取 WSL 安装包...'
|
|
225
|
-
$msi = "$dir
|
|
225
|
+
$msi = "$dir\\\\wsl_full.msi"
|
|
226
226
|
$wslInstalled = $false
|
|
227
227
|
try {
|
|
228
228
|
$ver = wsl --version 2>&1 | Out-String
|
|
@@ -238,7 +238,7 @@ ${askMsi}
|
|
|
238
238
|
Write-Host ''
|
|
239
239
|
Write-Host '[4/4] 安装 WSL...'
|
|
240
240
|
try {
|
|
241
|
-
Start-Process msiexec.exe -ArgumentList "/i
|
|
241
|
+
Start-Process msiexec.exe -ArgumentList "/i \\\`"$msi\\\`" /quiet /norestart" -Wait -NoNewWindow
|
|
242
242
|
Write-Host ' [OK]'
|
|
243
243
|
} catch {
|
|
244
244
|
Write-Host ' [失败] 安装出错'
|
|
@@ -308,7 +308,7 @@ Write-Host ' 导入预制 Linux 环境'
|
|
|
308
308
|
Write-Host '========================================'
|
|
309
309
|
Write-Host ''
|
|
310
310
|
|
|
311
|
-
$dir = "$env:LOCALAPPDATA
|
|
311
|
+
$dir = "$env:LOCALAPPDATA\\\\myclaw"
|
|
312
312
|
New-Item -ItemType Directory -Force -Path $dir | Out-Null
|
|
313
313
|
|
|
314
314
|
Write-Host '[1/3] 设置 WSL2 为默认版本...'
|
|
@@ -317,9 +317,9 @@ Write-Host ' [OK]'
|
|
|
317
317
|
Write-Host ''
|
|
318
318
|
|
|
319
319
|
Write-Host '[2/3] 获取预制 Linux 环境...'
|
|
320
|
-
$tarPath = "$dir
|
|
320
|
+
$tarPath = "$dir\\\\openclaw-rootfs.tar"
|
|
321
321
|
$distroName = 'OpenClaw'
|
|
322
|
-
$installDir = "$dir
|
|
322
|
+
$installDir = "$dir\\\\OpenClaw"
|
|
323
323
|
$installed = $false
|
|
324
324
|
|
|
325
325
|
${askTar}
|
|
@@ -357,12 +357,15 @@ Write-Host ''
|
|
|
357
357
|
Write-Host '========================================'
|
|
358
358
|
if ($installed) {
|
|
359
359
|
Write-Host ' [OK] WSL2 + OpenClaw Linux 安装完成!'
|
|
360
|
+
Write-Host '========================================'
|
|
360
361
|
Write-Host ''
|
|
361
|
-
|
|
362
|
+
|
|
363
|
+
# 统一启动流程:update + patch + gateway + open
|
|
364
|
+
wsl -d $distroName -- myclaw launch
|
|
362
365
|
} else {
|
|
363
366
|
Write-Host ' [失败] 请检查后重试: myclaw wsl2'
|
|
367
|
+
Write-Host '========================================'
|
|
364
368
|
}
|
|
365
|
-
Write-Host '========================================'
|
|
366
369
|
|
|
367
370
|
} catch {
|
|
368
371
|
Write-Host ''
|
|
@@ -380,7 +383,7 @@ Write-Host '========================================'
|
|
|
380
383
|
if (launchElevatedPS(ps)) {
|
|
381
384
|
console.log('[' + C.g + '已启动' + C.nc + '] 请查看新弹出的蓝色窗口');
|
|
382
385
|
console.log('');
|
|
383
|
-
console.log('
|
|
386
|
+
console.log('安装完成后会自动启动 Gateway 并打开浏览器');
|
|
384
387
|
console.log('');
|
|
385
388
|
}
|
|
386
389
|
}
|