@aiyiran/myclaw 1.0.25 → 1.0.27

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.
@@ -0,0 +1,67 @@
1
+ #!/bin/bash
2
+
3
+ # ============================================
4
+ # 脚本配置
5
+ # ============================================
6
+ URL="${1:-http://127.0.0.1:18789}" # 要导航的网页(默认本地控制台)
7
+ CHECK_INTERVAL=5 # 每隔 5 秒检查一次 Chrome
8
+ MAX_WAIT=600 # 最多等待 10 分钟(可调整)
9
+
10
+ # ============================================
11
+ # 检测操作系统
12
+ # ============================================
13
+ OS=$(uname -s)
14
+ case "$OS" in
15
+ Darwin*) OS_TYPE="Mac" ;;
16
+ Linux*) OS_TYPE="Linux" ;;
17
+ CYGWIN*|MINGW*|MSYS*) OS_TYPE="Windows" ;;
18
+ *) echo "Unsupported OS: $OS"; exit 1 ;;
19
+ esac
20
+
21
+ # ============================================
22
+ # 设置 Chrome 默认路径
23
+ # ============================================
24
+ case "$OS_TYPE" in
25
+ Mac) CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" ;;
26
+ Linux) CHROME="$(which google-chrome || which chromium-browser || echo "")" ;;
27
+ Windows) CHROME="/mnt/c/Program Files/Google/Chrome/Application/chrome.exe" ;;
28
+ esac
29
+
30
+ # ============================================
31
+ # 检测 Chrome 是否存在
32
+ # ============================================
33
+ if [ -z "$CHROME" ] || [ ! -f "$CHROME" ]; then
34
+ echo "Chrome not found on your system!"
35
+
36
+ # 打开官方下载页面
37
+ case "$OS_TYPE" in
38
+ Mac) open "https://www.google.com/chrome/" ;;
39
+ Linux) xdg-open "https://www.google.com/linux/chrome/" >/dev/null 2>&1 || echo "Please download Chrome from https://www.google.com/linux/chrome/" ;;
40
+ Windows) powershell.exe -Command "Start-Process 'https://www.google.com/chrome/'" ;;
41
+ esac
42
+
43
+ echo "Please install Chrome. Waiting for installation..."
44
+
45
+ # 开始轮询等待用户安装
46
+ ELAPSED=0
47
+ while [ ! -f "$CHROME" ]; do
48
+ sleep $CHECK_INTERVAL
49
+ ELAPSED=$((ELAPSED + CHECK_INTERVAL))
50
+ if [ $ELAPSED -ge $MAX_WAIT ]; then
51
+ echo "Timed out waiting for Chrome. Please install manually and rerun this script."
52
+ exit 1
53
+ fi
54
+ done
55
+ echo "Chrome installation detected!"
56
+ fi
57
+
58
+ # ============================================
59
+ # 打开目标 URL
60
+ # ============================================
61
+ echo "Opening URL: $URL ..."
62
+ case "$OS_TYPE" in
63
+ Mac|Linux) "$CHROME" "$URL" ;;
64
+ Windows) powershell.exe -Command "Start-Process '$CHROME' '$URL'" ;;
65
+ esac
66
+
67
+ echo "Done!"
@@ -0,0 +1,295 @@
1
+ /**
2
+ * ============================================================================
3
+ * MyClaw UI Inject — 浏览器端注入脚本
4
+ * ============================================================================
5
+ *
6
+ * 功能:
7
+ * 1. 页面顶部 fixed 显示 myclaw 版本号
8
+ * 2. 在聊天工具栏新增讯飞语音输入按钮
9
+ * - 光标处插入文字
10
+ * - 持续录入,手动停止
11
+ * - 讯飞 60 秒断开后自动重连
12
+ *
13
+ * 依赖:voice-input.js(讯飞 VoiceInput SDK,需先于本脚本加载)
14
+ * ============================================================================
15
+ */
16
+ (function () {
17
+ "use strict";
18
+
19
+ var MYCLAW_VERSION = "__MYCLAW_VERSION__";
20
+
21
+ // ═══ 状态 ═══
22
+ var voice = null; // VoiceInput 实例
23
+ var recording = false; // 用户层面的录音状态(独立于 SDK 的 status)
24
+ var pendingText = ""; // 当前这轮识别的文字(实时更新)
25
+ var committedText = ""; // 已经提交到 textarea 的文字(上一轮累积)
26
+ var cursorOffset = 0; // 录音开始时光标在 textarea 中的位置
27
+ var injected = false;
28
+
29
+ // ═══ 1. 顶部版本号横条 ═══
30
+ function createVersionBar() {
31
+ if (document.querySelector("#myclaw-version-bar")) return;
32
+
33
+ var bar = document.createElement("div");
34
+ bar.id = "myclaw-version-bar";
35
+ bar.style.cssText = [
36
+ "position: fixed",
37
+ "top: 0",
38
+ "left: 0",
39
+ "right: 0",
40
+ "height: 28px",
41
+ "line-height: 28px",
42
+ "background: linear-gradient(90deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%)",
43
+ "color: #e94560",
44
+ "font-size: 12px",
45
+ "font-family: monospace",
46
+ "text-align: center",
47
+ "z-index: 99999",
48
+ "box-shadow: 0 1px 4px rgba(0,0,0,0.3)",
49
+ "user-select: none",
50
+ "letter-spacing: 0.5px",
51
+ ].join(";");
52
+ bar.textContent = "\uD83D\uDC3E MyClaw v" + MYCLAW_VERSION;
53
+
54
+ document.body.prepend(bar);
55
+ document.body.style.paddingTop = "28px";
56
+ }
57
+
58
+ // ═══ 2. textarea 工具 ═══
59
+
60
+ /**
61
+ * 在 textarea 的指定位置写入文字,并触发 Lit 响应式更新
62
+ * @param {string} fullText - 完整的 textarea 内容
63
+ */
64
+ function setTextareaValue(fullText) {
65
+ var ta = document.querySelector(".agent-chat__input textarea");
66
+ if (!ta) return;
67
+
68
+ var setter = Object.getOwnPropertyDescriptor(
69
+ HTMLTextAreaElement.prototype, "value"
70
+ ).set;
71
+ setter.call(ta, fullText);
72
+ ta.dispatchEvent(new Event("input", { bubbles: true }));
73
+ }
74
+
75
+ /**
76
+ * 获取 textarea 当前值
77
+ */
78
+ function getTextareaValue() {
79
+ var ta = document.querySelector(".agent-chat__input textarea");
80
+ return ta ? ta.value : "";
81
+ }
82
+
83
+ /**
84
+ * 获取 textarea 当前光标位置
85
+ */
86
+ function getCursorPosition() {
87
+ var ta = document.querySelector(".agent-chat__input textarea");
88
+ return ta ? ta.selectionStart : 0;
89
+ }
90
+
91
+ /**
92
+ * 在光标位置插入识别的文字
93
+ * 原理:保留光标前的原文 + 已提交文字 + 当前识别文字 + 光标后的原文
94
+ */
95
+ function updateTextAtCursor(recognizedText) {
96
+ var ta = document.querySelector(".agent-chat__input textarea");
97
+ if (!ta) return;
98
+
99
+ // 录音开始时的位置前面的文字(不变)
100
+ var before = committedText.substring(0, cursorOffset);
101
+ // 录音开始时位置后面的文字(不变)
102
+ var originalAfter = committedText.substring(cursorOffset);
103
+
104
+ // 在光标位置插入已识别的文字
105
+ var newValue = before + recognizedText + originalAfter;
106
+ setTextareaValue(newValue);
107
+
108
+ // 把光标放到识别文字的末尾
109
+ var newCursorPos = before.length + recognizedText.length;
110
+ try {
111
+ ta.setSelectionRange(newCursorPos, newCursorPos);
112
+ } catch (e) {}
113
+ }
114
+
115
+ // ═══ 3. 语音按钮 ═══
116
+
117
+ function createVoiceButton() {
118
+ var btn = document.createElement("button");
119
+ btn.id = "myclaw-voice-btn";
120
+ btn.className = "agent-chat__input-btn";
121
+ btn.title = "\u8baf\u98de\u8bed\u97f3";
122
+ btn.setAttribute("aria-label", "\u8baf\u98de\u8bed\u97f3\u8f93\u5165");
123
+ btn.innerHTML = [
124
+ '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18"',
125
+ ' viewBox="0 0 24 24" fill="none" stroke="currentColor"',
126
+ ' stroke-width="2" stroke-linecap="round" stroke-linejoin="round">',
127
+ ' <path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"/>',
128
+ ' <path d="M19 10v2a7 7 0 0 1-14 0v-2"/>',
129
+ ' <line x1="12" x2="12" y1="19" y2="22"/>',
130
+ ' <circle cx="12" cy="22" r="1" fill="currentColor" stroke="none"/>',
131
+ '</svg>',
132
+ ].join("");
133
+
134
+ btn.addEventListener("click", function () {
135
+ if (recording) {
136
+ stopVoice();
137
+ } else {
138
+ startVoice();
139
+ }
140
+ });
141
+
142
+ return btn;
143
+ }
144
+
145
+ function updateButtonUI() {
146
+ var btn = document.querySelector("#myclaw-voice-btn");
147
+ if (!btn) return;
148
+
149
+ if (recording) {
150
+ btn.classList.add("agent-chat__input-btn--recording");
151
+ btn.title = "\u505c\u6b62\u8bed\u97f3";
152
+ } else {
153
+ btn.classList.remove("agent-chat__input-btn--recording");
154
+ btn.title = "\u8baf\u98de\u8bed\u97f3";
155
+ }
156
+ }
157
+
158
+ // ═══ 4. 录音控制 ═══
159
+
160
+ function initVoice() {
161
+ if (typeof window.VoiceInput === "undefined") {
162
+ console.error("[myclaw-inject] VoiceInput SDK \u672a\u52a0\u8f7d");
163
+ return;
164
+ }
165
+
166
+ voice = new window.VoiceInput({
167
+ onResult: function (text) {
168
+ // 讯飞实时返回识别文字,替换到光标位置
169
+ pendingText = text;
170
+ updateTextAtCursor(pendingText);
171
+ console.log("[myclaw-voice] \u8bc6\u522b\u4e2d:", text);
172
+ },
173
+ onStatusChange: function (oldStatus, newStatus) {
174
+ console.log("[myclaw-voice] \u72b6\u6001:", oldStatus, "->", newStatus);
175
+
176
+ if (newStatus === "idle" && recording) {
177
+ // 讯飞 60 秒断开,但用户没有点停止 → 自动重连
178
+ // 把当前识别的文字提交,并更新光标位置
179
+ committedText = getTextareaValue();
180
+ cursorOffset = getCursorPosition();
181
+ pendingText = "";
182
+
183
+ console.log("[myclaw-voice] \u81ea\u52a8\u91cd\u8fde...");
184
+ setTimeout(function () {
185
+ if (recording && voice) {
186
+ voice.start();
187
+ }
188
+ }, 300);
189
+ }
190
+ },
191
+ onError: function (err) {
192
+ console.error("[myclaw-voice] \u9519\u8bef:", err);
193
+ // 权限错误是永久性的,不重试,直接停止
194
+ var errStr = String(err).toLowerCase();
195
+ if (errStr.indexOf("permission") !== -1 || errStr.indexOf("not allowed") !== -1) {
196
+ console.error("[myclaw-voice] ⛔ 麦克风权限被拒绝,停止录音");
197
+ recording = false;
198
+ updateButtonUI();
199
+ return;
200
+ }
201
+ // 其他错误(如 WebSocket)尝试重连
202
+ if (recording) {
203
+ setTimeout(function () {
204
+ if (recording && voice) {
205
+ console.log("[myclaw-voice] \u9519\u8bef\u540e\u91cd\u8fde...");
206
+ voice.start();
207
+ }
208
+ }, 1000);
209
+ }
210
+ },
211
+ });
212
+
213
+ console.log("[myclaw-inject] \u2705 \u8baf\u98de\u8bed\u97f3 SDK \u5df2\u521d\u59cb\u5316");
214
+ }
215
+
216
+ function startVoice() {
217
+ if (!voice) {
218
+ initVoice();
219
+ if (!voice) return;
220
+ }
221
+
222
+ // 记录当前 textarea 状态和光标位置
223
+ committedText = getTextareaValue();
224
+ cursorOffset = getCursorPosition();
225
+ pendingText = "";
226
+
227
+ recording = true;
228
+ updateButtonUI();
229
+ voice.start();
230
+
231
+ console.log("[myclaw-voice] \u5f00\u59cb\u5f55\u97f3\uff0c\u5149\u6807\u4f4d\u7f6e:", cursorOffset);
232
+ }
233
+
234
+ function stopVoice() {
235
+ recording = false;
236
+ updateButtonUI();
237
+
238
+ if (voice) {
239
+ voice.stop();
240
+ }
241
+
242
+ // 最终提交文字
243
+ committedText = getTextareaValue();
244
+ pendingText = "";
245
+
246
+ console.log("[myclaw-voice] \u505c\u6b62\u5f55\u97f3");
247
+ }
248
+
249
+ // ═══ 5. DOM 注入 ═══
250
+
251
+ function injectButton() {
252
+ var toolbar = document.querySelector(".agent-chat__toolbar-left");
253
+ if (!toolbar || document.querySelector("#myclaw-voice-btn")) return;
254
+
255
+ var btn = createVoiceButton();
256
+
257
+ // 插入到 token 计数之前,或追加到末尾
258
+ var tokenCount = toolbar.querySelector(".agent-chat__token-count");
259
+ if (tokenCount) {
260
+ toolbar.insertBefore(btn, tokenCount);
261
+ } else {
262
+ toolbar.appendChild(btn);
263
+ }
264
+
265
+ injected = true;
266
+ console.log("[myclaw-inject] \u2705 \u8bed\u97f3\u6309\u94ae\u5df2\u6ce8\u5165");
267
+ }
268
+
269
+ // ═══ 启动 ═══
270
+ function init() {
271
+ createVersionBar();
272
+
273
+ // 初始化 VoiceInput SDK
274
+ initVoice();
275
+
276
+ // 持续监听 DOM 变化,确保按钮始终在
277
+ new MutationObserver(function () {
278
+ if (!document.querySelector("#myclaw-voice-btn")) {
279
+ injected = false;
280
+ }
281
+ if (!injected) {
282
+ injectButton();
283
+ }
284
+ }).observe(document.documentElement, { childList: true, subtree: true });
285
+
286
+ // 尝试立即注入
287
+ injectButton();
288
+ }
289
+
290
+ if (document.readyState === "loading") {
291
+ document.addEventListener("DOMContentLoaded", init);
292
+ } else {
293
+ init();
294
+ }
295
+ })();
package/index.js CHANGED
@@ -284,6 +284,229 @@ pause
284
284
  }
285
285
  }
286
286
 
287
+ // ============================================================================
288
+ // Open 命令 - 打开浏览器
289
+ // ============================================================================
290
+
291
+ function runOpen() {
292
+ const fs = require('fs');
293
+ const { exec } = require('child_process');
294
+ const url = args[1] || 'http://127.0.0.1:18789';
295
+ const platform = os.platform();
296
+ const bar = '----------------------------------------';
297
+
298
+ console.log('');
299
+ console.log('[' + colors.blue + 'MyClaw' + colors.nc + '] ' + colors.blue + '打开浏览器' + colors.nc);
300
+ console.log(bar);
301
+ console.log('');
302
+
303
+ // 定义各平台 Chrome 路径
304
+ let chromePaths = [];
305
+ if (platform === 'darwin') {
306
+ chromePaths = [
307
+ '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
308
+ ];
309
+ } else if (platform === 'linux') {
310
+ // 检测是否在 WSL2 环境下
311
+ let isWSL = false;
312
+ try {
313
+ const releaseInfo = fs.readFileSync('/proc/version', 'utf8');
314
+ if (/microsoft|wsl/i.test(releaseInfo)) isWSL = true;
315
+ } catch {}
316
+
317
+ if (isWSL) {
318
+ // WSL2 环境下优先使用 Windows 端的 Chrome
319
+ chromePaths = [
320
+ '/mnt/c/Program Files/Google/Chrome/Application/chrome.exe',
321
+ '/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe',
322
+ ];
323
+ } else {
324
+ chromePaths = [
325
+ '/usr/bin/google-chrome',
326
+ '/usr/bin/google-chrome-stable',
327
+ '/usr/bin/chromium-browser',
328
+ '/usr/bin/chromium',
329
+ ];
330
+ }
331
+ } else if (platform === 'win32') {
332
+ chromePaths = [
333
+ path.join(process.env.PROGRAMFILES || 'C:\\Program Files', 'Google', 'Chrome', 'Application', 'chrome.exe'),
334
+ path.join(process.env['PROGRAMFILES(X86)'] || 'C:\\Program Files (x86)', 'Google', 'Chrome', 'Application', 'chrome.exe'),
335
+ path.join(os.homedir(), 'AppData', 'Local', 'Google', 'Chrome', 'Application', 'chrome.exe'),
336
+ ];
337
+ }
338
+
339
+ // 查找 Chrome
340
+ let chromePath = null;
341
+ for (const p of chromePaths) {
342
+ try {
343
+ if (fs.existsSync(p)) {
344
+ chromePath = p;
345
+ break;
346
+ }
347
+ } catch {}
348
+ }
349
+
350
+ // 如果没有找到 Chrome
351
+ if (!chromePath) {
352
+ console.log('[' + colors.yellow + '提示' + colors.nc + '] 未检测到 Chrome 浏览器');
353
+ console.log('');
354
+ console.log('正在打开 Chrome 下载页面...');
355
+ console.log('');
356
+
357
+ const downloadUrl = 'https://www.google.com/chrome/';
358
+ try {
359
+ if (platform === 'darwin') {
360
+ execSync('open "' + downloadUrl + '"', { stdio: 'ignore' });
361
+ } else if (platform === 'win32') {
362
+ execSync('start "" "' + downloadUrl + '"', { stdio: 'ignore', shell: true });
363
+ } else {
364
+ // Linux / WSL2
365
+ try {
366
+ execSync('xdg-open "' + downloadUrl + '"', { stdio: 'ignore' });
367
+ } catch {
368
+ // WSL2 fallback
369
+ try {
370
+ execSync('powershell.exe -Command "Start-Process \'' + downloadUrl + '\'"', { stdio: 'ignore' });
371
+ } catch {
372
+ console.log('请手动下载 Chrome: ' + colors.yellow + downloadUrl + colors.nc);
373
+ }
374
+ }
375
+ }
376
+ } catch {}
377
+
378
+ console.log('安装 Chrome 后重新运行: ' + colors.yellow + 'myclaw open' + colors.nc);
379
+ console.log('');
380
+ console.log(bar);
381
+ console.log('');
382
+ return;
383
+ }
384
+
385
+ // 打开 URL
386
+ console.log('[Chrome] ' + colors.green + '已检测到' + colors.nc);
387
+ console.log(' 路径: ' + chromePath);
388
+ console.log('');
389
+ console.log('[打开] ' + url);
390
+
391
+ try {
392
+ if (platform === 'darwin') {
393
+ // macOS: 使用 open 命令打开 Chrome
394
+ exec('open -a "Google Chrome" "' + url + '"');
395
+ } else if (platform === 'win32') {
396
+ exec('"' + chromePath + '" "' + url + '"');
397
+ } else {
398
+ // Linux / WSL2
399
+ let isWSL = false;
400
+ try {
401
+ const releaseInfo = fs.readFileSync('/proc/version', 'utf8');
402
+ if (/microsoft|wsl/i.test(releaseInfo)) isWSL = true;
403
+ } catch {}
404
+
405
+ if (isWSL) {
406
+ // WSL2: Chrome 路径中有空格,需要特殊处理
407
+ exec('"' + chromePath + '" "' + url + '"');
408
+ } else {
409
+ exec('"' + chromePath + '" "' + url + '"');
410
+ }
411
+ }
412
+ console.log('');
413
+ console.log('[' + colors.green + '成功' + colors.nc + '] 浏览器已启动');
414
+ } catch (err) {
415
+ console.error('[' + colors.red + '错误' + colors.nc + '] 打开浏览器失败: ' + err.message);
416
+ }
417
+
418
+ console.log('');
419
+ console.log(bar);
420
+ console.log('');
421
+ }
422
+
423
+ // ============================================================================
424
+ // Patch / Unpatch / Restart
425
+ // ============================================================================
426
+
427
+ function runPatch() {
428
+ const { patch, status: patchStatus } = require('./patch');
429
+ const bar = '----------------------------------------';
430
+
431
+ console.log('');
432
+ console.log('[' + colors.blue + 'MyClaw' + colors.nc + '] ' + colors.blue + 'UI 注入' + colors.nc);
433
+ console.log(bar);
434
+ console.log('');
435
+
436
+ const result = patch();
437
+
438
+ if (result.success) {
439
+ console.log('');
440
+ console.log(bar);
441
+ console.log('下一步: 运行 ' + colors.yellow + 'myclaw restart' + colors.nc + ' 重启 Gateway 使注入生效');
442
+ console.log('');
443
+ }
444
+ }
445
+
446
+ function runUnpatch() {
447
+ const { unpatch } = require('./patch');
448
+ const bar = '----------------------------------------';
449
+
450
+ console.log('');
451
+ console.log('[' + colors.blue + 'MyClaw' + colors.nc + '] ' + colors.blue + 'UI 回滚' + colors.nc);
452
+ console.log(bar);
453
+ console.log('');
454
+
455
+ unpatch();
456
+
457
+ console.log('');
458
+ console.log(bar);
459
+ console.log('下一步: 运行 ' + colors.yellow + 'myclaw restart' + colors.nc + ' 重启 Gateway');
460
+ console.log('');
461
+ }
462
+
463
+ function runRestart() {
464
+ const bar = '----------------------------------------';
465
+
466
+ console.log('');
467
+ console.log('[' + colors.blue + 'MyClaw' + colors.nc + '] ' + colors.blue + '重启 Gateway' + colors.nc);
468
+ console.log(bar);
469
+ console.log('');
470
+
471
+ try {
472
+ console.log('[停止] 正在停止 Gateway...');
473
+ try {
474
+ execSync('openclaw gateway stop', { stdio: 'pipe', timeout: 10000 });
475
+ console.log('[停止] ' + colors.green + 'Gateway 已停止' + colors.nc);
476
+ } catch {
477
+ console.log('[停止] Gateway 未在运行或已停止');
478
+ }
479
+
480
+ console.log('');
481
+ console.log('[启动] 正在启动 Gateway...');
482
+ // 使用 nohup + 后台启动,避免阻塞当前进程
483
+ execSync('nohup openclaw gateway > /tmp/openclaw-gateway.log 2>&1 &', {
484
+ stdio: 'ignore',
485
+ shell: true,
486
+ });
487
+
488
+ // 等待 2 秒让 Gateway 启动
489
+ execSync('sleep 2', { stdio: 'ignore' });
490
+
491
+ // 检查是否启动成功
492
+ try {
493
+ execSync('openclaw health', { stdio: 'pipe', timeout: 5000 });
494
+ console.log('[启动] ' + colors.green + 'Gateway 启动成功!' + colors.nc);
495
+ console.log('');
496
+ console.log('控制台: ' + colors.yellow + 'http://127.0.0.1:18789' + colors.nc);
497
+ } catch {
498
+ console.log('[启动] ' + colors.yellow + 'Gateway 正在启动中...' + colors.nc);
499
+ console.log('日志: ' + colors.yellow + 'tail -f /tmp/openclaw-gateway.log' + colors.nc);
500
+ }
501
+ } catch (err) {
502
+ console.error('[' + colors.red + '错误' + colors.nc + '] 重启失败: ' + err.message);
503
+ }
504
+
505
+ console.log('');
506
+ console.log(bar);
507
+ console.log('');
508
+ }
509
+
287
510
  // ============================================================================
288
511
  // 帮助信息
289
512
  // ============================================================================
@@ -300,16 +523,22 @@ function showHelp() {
300
523
  console.log(' install 安装 OpenClaw 服务');
301
524
  console.log(' status 简化版状态查看(学生友好)');
302
525
  console.log(' new 创建新的 Agent(学生练习用)');
526
+ console.log(' open 打开浏览器控制台(默认 http://127.0.0.1:18789)');
303
527
  console.log(' wsl2 WSL2 一键安装/修复 (仅限 Windows)');
304
528
  console.log(' bat 在桌面生成一键启动脚本 (仅限 Windows)');
529
+ console.log(' patch 注入 MyClaw UI 扩展到 WebChat');
530
+ console.log(' unpatch 回滚 UI 注入(恢复原版)');
531
+ console.log(' restart 重启 OpenClaw Gateway');
305
532
  console.log(' help 显示帮助信息');
306
533
  console.log('');
307
534
  console.log('示例:');
308
- console.log(' myclaw install # 安装 OpenClaw');
309
- console.log(' myclaw status # 查看状态');
310
- console.log(' myclaw new helper # 创建名为 helper 的 Agent');
311
- console.log(' myclaw wsl2 # Windows 下一键安装 WSL2');
312
- console.log(' myclaw bat # 生成桌面一键启动脚本');
535
+ console.log(' myclaw install # 安装 OpenClaw');
536
+ console.log(' myclaw status # 查看状态');
537
+ console.log(' myclaw new helper # 创建名为 helper 的 Agent');
538
+ console.log(' myclaw open # 打开默认控制台');
539
+ console.log(' myclaw open http://... # 打开指定 URL');
540
+ console.log(' myclaw patch # 注入 UI 扩展');
541
+ console.log(' myclaw restart # 重启 Gateway');
313
542
  console.log('');
314
543
  console.log('跨平台: macOS / Linux / Windows (PowerShell/CMD)');
315
544
  console.log('');
@@ -329,10 +558,18 @@ if (!command || command === 'help' || command === '--help' || command === '-h')
329
558
  runStatus();
330
559
  } else if (command === 'new') {
331
560
  runNew();
561
+ } else if (command === 'open') {
562
+ runOpen();
332
563
  } else if (command === 'wsl2') {
333
564
  runWsl2();
334
565
  } else if (command === 'bat') {
335
566
  runBat();
567
+ } else if (command === 'patch') {
568
+ runPatch();
569
+ } else if (command === 'unpatch') {
570
+ runUnpatch();
571
+ } else if (command === 'restart') {
572
+ runRestart();
336
573
  } else {
337
574
  console.error('[' + colors.red + '错误' + colors.nc + '] 未知命令: ' + command);
338
575
  showHelp();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiyiran/myclaw",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -8,7 +8,8 @@
8
8
  "mc": "index.js"
9
9
  },
10
10
  "scripts": {
11
- "test": "echo \"Error: no test specified\" && exit 1"
11
+ "test": "echo \"Error: no test specified\" && exit 1",
12
+ "postinstall": "node -e \"try{require('./patch').patch()}catch(e){console.log('[myclaw] patch skipped:',e.message)}\""
12
13
  },
13
14
  "keywords": [],
14
15
  "author": "",