@aiyiran/myclaw 1.0.62 → 1.0.64

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 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
@@ -355,31 +355,14 @@ echo [3/4] Gateway...
355
355
  wsl -d OpenClaw -- pgrep -f "openclaw" >nul 2>&1
356
356
  if not errorlevel 1 goto :gateway_running
357
357
 
358
- REM Gateway not running -> update myclaw first, then start
358
+ REM Gateway not running -> update both sides, then launch
359
359
  echo Starting...
360
360
  echo.
361
- echo [update] checking...
362
- call npm install -g @aiyiran/myclaw@latest --prefer-online >nul 2>&1
363
- echo [update] OK
361
+ echo [update] Windows...
362
+ call myclaw up
364
363
  echo.
365
-
366
- REM ---- Step 4: Patch + Open browser ----
367
- echo [4/5] Patch...
368
- wsl -d OpenClaw -- myclaw patch
369
- echo [OK]
370
-
371
- echo [5/5] Browser...
372
- call myclaw open
373
- echo [OK]
374
- echo.
375
- echo ============================================
376
- echo Gateway starting...
377
- echo Close this window = stop service
378
- echo ============================================
379
- echo.
380
- wsl -d OpenClaw -- openclaw gateway
364
+ wsl -d OpenClaw -- myclaw launch
381
365
  echo.
382
- echo Gateway exited.
383
366
  pause
384
367
  exit /b
385
368
 
@@ -582,10 +565,11 @@ function runOpen() {
582
565
  function runPatch() {
583
566
  const { patch, status: patchStatus } = require('./patch');
584
567
  const { patchSkills } = require('./patch-skill');
568
+ const { patchConfig } = require('./find-config');
585
569
  const bar = '----------------------------------------';
586
570
 
587
571
  console.log('');
588
- console.log('[' + colors.blue + 'MyClaw' + colors.nc + '] ' + colors.blue + 'Patch (UI + Skills)' + colors.nc);
572
+ console.log('[' + colors.blue + 'MyClaw' + colors.nc + '] ' + colors.blue + 'Patch (UI + Skills + Config)' + colors.nc);
589
573
  console.log(bar);
590
574
  console.log('');
591
575
 
@@ -596,6 +580,22 @@ function runPatch() {
596
580
  console.log('');
597
581
  const skillResult = patchSkills();
598
582
 
583
+ // 3. Config 补丁(修改 openclaw.json 的特定字段)
584
+ console.log('');
585
+ try {
586
+ const { config, configPath } = patchConfig({
587
+ session: {
588
+ reset: {
589
+ mode: "idle",
590
+ idleMinutes: 90720
591
+ }
592
+ }
593
+ });
594
+ console.log('[myclaw-config] ✅ session.reset → idle (90720 分钟)');
595
+ } catch (err) {
596
+ console.log('[myclaw-config] ⚠️ 配置补丁失败: ' + err.message);
597
+ }
598
+
599
599
  if (uiResult.success || skillResult.success) {
600
600
  console.log('');
601
601
  console.log(bar);
package/inject-minimax.js CHANGED
@@ -4,7 +4,6 @@
4
4
  * inject-minimax.js
5
5
  *
6
6
  * 将 openclaw.json 中的模型配置清空,注入为唯一的 MiniMax 模型。
7
- * 自动查找 ~/.openclaw/openclaw.json
8
7
  *
9
8
  * 流程:
10
9
  * 1. 先执行 openclaw onboard(设置 API Key,会覆盖 JSON)
@@ -13,9 +12,7 @@
13
12
  * 入口: myclaw minimax [--key sk-xxx]
14
13
  */
15
14
 
16
- const fs = require('fs');
17
- const path = require('path');
18
- const os = require('os');
15
+ const { readConfig, writeConfig } = require('./find-config');
19
16
 
20
17
  function run(cliArgs) {
21
18
  // 解析 --key 参数
@@ -27,18 +24,16 @@ function run(cliArgs) {
27
24
  }
28
25
  }
29
26
 
30
- // 自动查找 openclaw.json
31
- const openclawDir = path.join(os.homedir(), '.openclaw');
32
- const targetPath = path.join(openclawDir, 'openclaw.json');
33
-
34
- if (!fs.existsSync(targetPath)) {
35
- console.error('❌ 未找到 openclaw.json');
36
- console.error(' 期望路径: ' + targetPath);
37
- console.error(' 请先安装 OpenClaw: myclaw install');
27
+ // 查找配置
28
+ let configPath;
29
+ try {
30
+ ({ configPath } = readConfig());
31
+ } catch (err) {
32
+ console.error('❌ ' + err.message);
38
33
  process.exit(1);
39
34
  }
40
35
 
41
- console.log('📍 找到配置: ' + targetPath);
36
+ console.log('📍 找到配置: ' + configPath);
42
37
 
43
38
  // ============================================================
44
39
  // 第一步:先执行 onboard(它会覆盖 JSON,所以必须先跑)
@@ -75,8 +70,8 @@ function run(cliArgs) {
75
70
  console.log('');
76
71
  console.log('📝 [Step 2] 注入 MiniMax 模型配置...');
77
72
 
78
- // 重新读取文件(onboard 可能已经改过了)
79
- const config = JSON.parse(fs.readFileSync(targetPath, 'utf8'));
73
+ // 重新读取(onboard 可能已改过)
74
+ const { config } = readConfig();
80
75
 
81
76
  config.auth = {
82
77
  profiles: {
@@ -129,12 +124,12 @@ function run(cliArgs) {
129
124
  "minimax/MiniMax-M2.7-highspeed": {}
130
125
  };
131
126
 
132
- fs.writeFileSync(targetPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
127
+ writeConfig(config, configPath);
133
128
 
134
129
  // 验证写入
135
- const verify = JSON.parse(fs.readFileSync(targetPath, 'utf8'));
136
- const writtenModelId = verify.models?.providers?.minimax?.models?.[0]?.id || '???';
137
- const writtenDefault = verify.agents?.defaults?.model?.primary || '???';
130
+ const verify = readConfig();
131
+ const writtenModelId = verify.config.models?.providers?.minimax?.models?.[0]?.id || '???';
132
+ const writtenDefault = verify.config.agents?.defaults?.model?.primary || '???';
138
133
 
139
134
  console.log('✅ 配置已注入');
140
135
  console.log(' [验证] model ID: ' + writtenModelId);
package/launch.js ADDED
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * ============================================================================
5
+ * MyClaw Launch - 统一启动流程
6
+ * ============================================================================
7
+ *
8
+ * 使用: myclaw launch
9
+ *
10
+ * 统一的启动链条,被 bat 脚本和 wsl2 安装器共同复用:
11
+ * Step 1: 更新 MyClaw(Linux 侧)
12
+ * Step 2: 执行 Patch(UI + Skills + Config)
13
+ * Step 3: 后台启动 OpenClaw Gateway
14
+ * Step 4: 打开浏览器控制台
15
+ * ============================================================================
16
+ */
17
+
18
+ const { execSync, spawn } = require('child_process');
19
+ const os = require('os');
20
+ const path = require('path');
21
+
22
+ const isWindows = os.platform() === 'win32';
23
+ const C = isWindows
24
+ ? { r: '', g: '', y: '', b: '', nc: '' }
25
+ : { r: '\x1b[31m', g: '\x1b[32m', y: '\x1b[33m', b: '\x1b[34m', nc: '\x1b[0m' };
26
+
27
+ const BAR = '============================================';
28
+
29
+ // ============================================================================
30
+ // Step 1: 更新 MyClaw
31
+ // ============================================================================
32
+
33
+ function stepUpdate() {
34
+ console.log('[1/4] 更新 MyClaw...');
35
+
36
+ try {
37
+ const registry = 'https://registry.npmjs.org';
38
+ const pkg = '@aiyiran/myclaw';
39
+ const currentVersion = require('./package.json').version;
40
+
41
+ const latestVersion = execSync(
42
+ 'npm view ' + pkg + ' version --registry ' + registry,
43
+ { encoding: 'utf8', timeout: 15000 }
44
+ ).trim();
45
+
46
+ if (currentVersion === latestVersion) {
47
+ console.log(' ' + C.g + '[OK]' + C.nc + ' 已是最新 v' + currentVersion);
48
+ } else {
49
+ console.log(' v' + currentVersion + ' → v' + latestVersion);
50
+ const tarball = execSync(
51
+ 'npm view ' + pkg + ' dist.tarball --registry ' + registry,
52
+ { encoding: 'utf8', timeout: 15000 }
53
+ ).trim();
54
+ execSync('npm install -g ' + tarball, { stdio: 'pipe', timeout: 60000 });
55
+ console.log(' ' + C.g + '[OK]' + C.nc + ' 已升级到 v' + latestVersion);
56
+ }
57
+ } catch (err) {
58
+ console.log(' ' + C.y + '[跳过]' + C.nc + ' 更新失败 (非致命)');
59
+ }
60
+ console.log('');
61
+ }
62
+
63
+ // ============================================================================
64
+ // Step 2: 执行 Patch
65
+ // ============================================================================
66
+
67
+ function stepPatch() {
68
+ console.log('[2/4] Patch...');
69
+
70
+ try {
71
+ const { patch } = require('./patch');
72
+ const { patchSkills } = require('./patch-skill');
73
+ const { patchConfig } = require('./find-config');
74
+
75
+ patch();
76
+ patchSkills();
77
+ patchConfig({
78
+ session: {
79
+ reset: {
80
+ mode: 'idle',
81
+ idleMinutes: 90720,
82
+ },
83
+ },
84
+ });
85
+
86
+ console.log(' ' + C.g + '[OK]' + C.nc);
87
+ } catch (err) {
88
+ console.log(' ' + C.y + '[跳过]' + C.nc + ' ' + err.message);
89
+ }
90
+ console.log('');
91
+ }
92
+
93
+ // ============================================================================
94
+ // Step 3 & 4: 启动 Gateway + 打开浏览器
95
+ // ============================================================================
96
+
97
+ function stepGatewayAndOpen() {
98
+ console.log('[3/4] 启动 Gateway...');
99
+ console.log('');
100
+ console.log(BAR);
101
+ console.log(' Gateway starting...');
102
+ console.log(' 关闭此窗口 = 停止服务');
103
+ console.log(BAR);
104
+ console.log('');
105
+
106
+ // 后台启动 gateway
107
+ const gateway = spawn('openclaw', ['gateway'], {
108
+ stdio: 'inherit',
109
+ detached: false,
110
+ });
111
+
112
+ // 打开浏览器(不阻塞)
113
+ console.log('[4/4] 打开浏览器...');
114
+ try {
115
+ execSync('node "' + path.join(__dirname, 'index.js') + '" open', {
116
+ stdio: 'pipe',
117
+ timeout: 10000,
118
+ });
119
+ console.log(' ' + C.g + '[OK]' + C.nc);
120
+ } catch {
121
+ console.log(' ' + C.y + '[跳过]' + C.nc);
122
+ }
123
+ console.log('');
124
+
125
+ // 等待 gateway 进程退出(关闭终端会终止)
126
+ return new Promise((resolve) => {
127
+ gateway.on('close', (code) => {
128
+ console.log('');
129
+ console.log(' Gateway 已退出。');
130
+ resolve(code);
131
+ });
132
+ });
133
+ }
134
+
135
+ // ============================================================================
136
+ // 主入口
137
+ // ============================================================================
138
+
139
+ async function run() {
140
+ const bar = '----------------------------------------';
141
+
142
+ console.log('');
143
+ console.log('[' + C.b + 'MyClaw' + C.nc + '] ' + C.b + '启动流程' + C.nc);
144
+ console.log(bar);
145
+ console.log('');
146
+
147
+ stepUpdate();
148
+ stepPatch();
149
+ await stepGatewayAndOpen();
150
+ }
151
+
152
+ module.exports = { run };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiyiran/myclaw",
3
- "version": "1.0.62",
3
+ "version": "1.0.64",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
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 };
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\\myclaw"
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\\wsl_full.msi"
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 \`"$msi\`" /quiet /norestart" -Wait -NoNewWindow
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\\myclaw"
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\\openclaw-rootfs.tar"
320
+ $tarPath = "$dir\\\\openclaw-rootfs.tar"
321
321
  $distroName = 'OpenClaw'
322
- $installDir = "$dir\\OpenClaw"
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
- Write-Host ' 输入 wsl 即可进入 Linux 环境'
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('安装完成后,输入 ' + C.y + 'wsl' + C.nc + ' 即可进入 Linux');
386
+ console.log('安装完成后会自动启动 Gateway 并打开浏览器');
384
387
  console.log('');
385
388
  }
386
389
  }