@aiyiran/myclaw 1.0.159 → 1.0.161

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 CHANGED
@@ -1143,6 +1143,7 @@ function showHelp() {
1143
1143
  console.log(' image 注入图像生成模型配置 (基于 vveai)');
1144
1144
  console.log(' token 设置 Gateway Token 为 aiyiran');
1145
1145
  console.log(' websearch 注入 Tavily 搜索插件配置');
1146
+ console.log(' soul 替换默认 workspace 的 SOUL.md 提示词');
1146
1147
  console.log(' restart 重启 OpenClaw Gateway');
1147
1148
  console.log(' help 显示帮助信息');
1148
1149
  console.log('');
@@ -1257,6 +1258,12 @@ if (!command) {
1257
1258
  console.log('🔄 正在重启 Gateway 使配置生效...');
1258
1259
  console.log('');
1259
1260
  runRestart();
1261
+ } else if (command === 'soul') {
1262
+ const soul = require('./inject-workspaceAndSoul');
1263
+ soul.run();
1264
+ console.log('🔄 正在重启 Gateway 使配置生效...');
1265
+ console.log('');
1266
+ runRestart();
1260
1267
  } else {
1261
1268
  console.error('[' + colors.red + '错误' + colors.nc + '] 未知命令: ' + command);
1262
1269
  showHelp();
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * inject-workspaceAndSoul.js
5
+ *
6
+ * 替换 ~/.openclaw/workspace/SOUL.md 的内容为面向小学生的学习伙伴提示词。
7
+ *
8
+ * 入口: myclaw soul
9
+ */
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const os = require('os');
14
+
15
+ const SOUL_CONTENT = `# 角色定义
16
+
17
+ 你是一个面向中国小学生的 AI 学习伙伴。
18
+
19
+ 你的目标不是替学生完成任务,而是帮助他们理解问题、建立思考能力,并在学习中获得成就感。
20
+
21
+ ---
22
+
23
+ # 核心性格
24
+
25
+ - 友善、有耐心、愿意鼓励学生
26
+ - 用简单、清晰、生活化的语言表达
27
+ - 擅长把复杂问题讲简单
28
+ - 不炫技,不使用复杂术语
29
+ - 更像一个会讲解的同学,而不是老师
30
+
31
+ ---
32
+
33
+ # 表达要求
34
+
35
+ - 优先使用短句,避免长段落
36
+ - 一次回答只讲一个重点
37
+ - 用词贴近小学生理解水平
38
+ - 尽量用举例、类比来解释
39
+ - 不使用复杂技术术语(除非必须,并且要解释)
40
+
41
+ ---
42
+
43
+ # 内容长度控制(非常重要)
44
+
45
+ 根据不同任务,控制输出长度:
46
+
47
+ ## 1)日常问答 / 提问解答
48
+ - 必须简短(优先 3~6 句)
49
+ - 只回答关键点,不展开过多内容
50
+
51
+ ## 2)教学引导 / 思路讲解
52
+ - 分步骤说明(最多 3 步)
53
+ - 每一步尽量一句话
54
+
55
+ ## 3)生成作品 / 内容(如代码、网页、作文)
56
+ - 可以详细,但结构必须清晰
57
+ - 必须加简单说明(让学生看得懂)
58
+
59
+ ---
60
+
61
+ # 教学原则(核心)
62
+
63
+ 你必须遵守以下教学原则:
64
+
65
+ ## ❌ 不直接给答案(除非明确要求)
66
+ 优先:
67
+ - 引导学生思考
68
+ - 提出提示(hint)
69
+ - 分解问题
70
+
71
+ ## ✅ 鼓励思考
72
+ 可以使用:
73
+ - "你可以先想一想……"
74
+ - "我们一步一步来"
75
+ - "你觉得这里应该怎么做?"
76
+
77
+ ## ✅ 正向反馈
78
+ - 认可学生的尝试
79
+ - 即使错误,也要鼓励
80
+
81
+ 例如:
82
+ - "这个思路很好,我们再优化一下"
83
+ - "已经很接近了!"
84
+
85
+ ---
86
+
87
+ # 错误处理方式
88
+
89
+ 当学生出错时:
90
+
91
+ 1. 不直接否定
92
+ 2. 指出问题所在(简单说明)
93
+ 3. 给一个小提示,而不是完整答案
94
+
95
+ ---
96
+
97
+ # 禁止行为
98
+
99
+ - ❌ 使用复杂专业术语堆砌
100
+ - ❌ 长篇大论解释
101
+ - ❌ 一次讲多个知识点
102
+ - ❌ 直接给出完整答案(除非用户明确要求)
103
+ - ❌ 打击或否定学生
104
+
105
+ ---
106
+
107
+ # 风格示例
108
+
109
+ ❌ 不推荐:
110
+ "该问题涉及哈希映射与时间复杂度优化……"
111
+
112
+ ✅ 推荐:
113
+ "我们可以用一个'小本子'来记住出现过的数字,这样查起来会更快~"
114
+
115
+ ---
116
+
117
+ # 目标
118
+
119
+ 你的最终目标是:
120
+
121
+ - 让学生听得懂
122
+ - 让学生愿意继续学
123
+ - 让学生自己能做出来
124
+ `;
125
+
126
+ function run() {
127
+ const soulPath = path.join(os.homedir(), '.openclaw', 'workspace', 'SOUL.md');
128
+
129
+ if (!fs.existsSync(soulPath)) {
130
+ console.log('❌ 未找到: ' + soulPath);
131
+ console.log(' 请确认 workspace 目录存在');
132
+ return;
133
+ }
134
+
135
+ fs.writeFileSync(soulPath, SOUL_CONTENT, 'utf8');
136
+ console.log('✅ SOUL.md 已更新: ' + soulPath);
137
+ }
138
+
139
+ module.exports = { run };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiyiran/myclaw",
3
- "version": "1.0.159",
3
+ "version": "1.0.161",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -61,6 +61,11 @@
61
61
  "module": "./inject-minimax",
62
62
  "strategy": "auto",
63
63
  "description": "MiniMax 模型注入"
64
+ },
65
+ {
66
+ "module": "./inject-workspaceAndSoul",
67
+ "strategy": "on",
68
+ "description": "替换默认 workspace 的 SOUL.md 提示词"
64
69
  }
65
70
  ]
66
71
  }
package/restrict.js CHANGED
@@ -2,18 +2,24 @@
2
2
 
3
3
  /**
4
4
  * ============================================================================
5
- * MyClaw WSL2 权限封锁
5
+ * MyClaw WSL2 权限封锁(Windows 侧)
6
6
  * ============================================================================
7
7
  *
8
- * 功能:逐步封锁 WSL2 对 Windows 文件系统的访问权限
8
+ * Windows 一次性完成:
9
+ * 步骤 1: 在 WSL 内创建工作目录 ~/workspace
10
+ * 步骤 2: 编辑 /etc/wsl.conf 禁用 automount(Linux 看不到 Windows 盘符)
11
+ * 步骤 3: 在 Windows 桌面创建快捷方式,指向 \\wsl.localhost\OpenClaw\<workspace>
9
12
  *
10
13
  * 使用方法:
11
14
  * myclaw restrict
15
+ *
16
+ * 前提:OpenClaw WSL2 发行版已安装(myclaw wsl2 完成)
12
17
  * ============================================================================
13
18
  */
14
19
 
15
20
  const { execSync } = require('child_process');
16
21
  const os = require('os');
22
+ const fs = require('fs');
17
23
  const path = require('path');
18
24
 
19
25
  // ============================================================================
@@ -26,7 +32,8 @@ const C = isWindows
26
32
  ? { r: '', g: '', y: '', b: '', nc: '' }
27
33
  : { r: '\x1b[31m', g: '\x1b[32m', y: '\x1b[33m', b: '\x1b[34m', nc: '\x1b[0m' };
28
34
 
29
- const SCRIPT_PATH = path.join(__dirname, 'scripts', 'restrict-wsl-access.sh');
35
+ const DISTRO_NAME = 'OpenClaw';
36
+ const WORKSPACE_DIR = 'workspace'; // WSL 内的 ~/workspace
30
37
 
31
38
  // ============================================================================
32
39
  // 工具函数
@@ -52,28 +59,261 @@ function printError(msg) {
52
59
  console.error(C.r + '[错误]' + C.nc + ' ' + msg);
53
60
  }
54
61
 
55
- // 检查是否在 WSL 环境中
56
- function isWSL() {
62
+ // WSL 中执行命令,返回输出
63
+ function wslExec(cmd) {
57
64
  try {
58
- const version = require('fs').readFileSync('/proc/version', 'utf8');
59
- return /microsoft|wsl/i.test(version);
60
- } catch {
61
- return false;
65
+ return execSync(`wsl -d ${DISTRO_NAME} -- bash -c "${cmd}"`, {
66
+ encoding: 'utf8',
67
+ stdio: ['pipe', 'pipe', 'pipe'],
68
+ }).trim();
69
+ } catch (err) {
70
+ return null;
62
71
  }
63
72
  }
64
73
 
65
- // 在 WSL 中执行脚本
66
- function runInWSL(scriptPath) {
74
+ // 在 WSL 中以 root 执行命令
75
+ function wslExecSudo(cmd) {
67
76
  try {
68
- const cmd = `bash "${scriptPath}"`;
69
- execSync(cmd, { stdio: 'inherit' });
77
+ // OpenClaw 默认用户可能是 root,如果不是则需要 sudo
78
+ execSync(`wsl -d ${DISTRO_NAME} --user root -- bash -c "${cmd}"`, {
79
+ encoding: 'utf8',
80
+ stdio: 'pipe',
81
+ });
70
82
  return true;
71
83
  } catch (err) {
72
- printError('执行失败: ' + err.message);
84
+ // 回退尝试普通用户 + sudo
85
+ try {
86
+ execSync(`wsl -d ${DISTRO_NAME} -- bash -c "sudo ${cmd}"`, {
87
+ encoding: 'utf8',
88
+ stdio: 'pipe',
89
+ });
90
+ return true;
91
+ } catch (err2) {
92
+ printError('WSL 命令执行失败: ' + (err2.stderr || err2.message));
93
+ return false;
94
+ }
95
+ }
96
+ }
97
+
98
+ // ============================================================================
99
+ // 前置检查
100
+ // ============================================================================
101
+
102
+ function checkPrerequisites() {
103
+ if (!isWindows) {
104
+ printError('此命令只能在 Windows 上运行');
105
+ console.log('');
106
+ console.log('Mac/Linux 不需要 WSL2 权限封锁。');
107
+ process.exit(1);
108
+ }
109
+
110
+ // 检查 wsl 命令是否存在
111
+ try {
112
+ execSync('wsl --version', { stdio: 'pipe' });
113
+ } catch {
114
+ printError('未检测到 WSL。请先运行: myclaw wsl2');
115
+ process.exit(1);
116
+ }
117
+
118
+ // 检查 OpenClaw 发行版是否存在
119
+ try {
120
+ const list = execSync('wsl -l -q', { encoding: 'utf16le' }).trim();
121
+ if (!list.includes(DISTRO_NAME)) {
122
+ printError('未找到 ' + DISTRO_NAME + ' 发行版。请先运行: myclaw wsl2');
123
+ process.exit(1);
124
+ }
125
+ } catch {
126
+ printError('无法读取 WSL 发行版列表。请先运行: myclaw wsl2');
127
+ process.exit(1);
128
+ }
129
+
130
+ printSuccess('前置检查通过');
131
+ }
132
+
133
+ // ============================================================================
134
+ // 步骤 1: 在 WSL 内创建工作目录
135
+ // ============================================================================
136
+
137
+ function step1_createWorkspace() {
138
+ printStep('步骤 1/3: 在 WSL 内创建工作目录');
139
+
140
+ // 获取 WSL 用户名
141
+ const wslUser = wslExec('whoami');
142
+ if (!wslUser) {
143
+ printError('无法获取 WSL 用户名');
144
+ return null;
145
+ }
146
+
147
+ printInfo('WSL 用户: ' + wslUser);
148
+
149
+ // 创建工作目录
150
+ const workspacePath = `/home/${wslUser}/${WORKSPACE_DIR}`;
151
+ const result = wslExec(`mkdir -p ${workspacePath} && echo ${workspacePath}`);
152
+
153
+ if (!result) {
154
+ printError('创建工作目录失败');
155
+ return null;
156
+ }
157
+
158
+ printSuccess('工作目录已创建: ' + workspacePath);
159
+ return { wslUser, workspacePath };
160
+ }
161
+
162
+ // ============================================================================
163
+ // 步骤 2: 禁用 automount
164
+ // ============================================================================
165
+
166
+ function step2_disableAutomount(wslUser) {
167
+ printStep('步骤 2/3: 禁用自动挂载 Windows 盘符');
168
+
169
+ // 先备份(如果文件存在)
170
+ wslExecSudo('cp /etc/wsl.conf /etc/wsl.conf.bak 2>/dev/null; true');
171
+
172
+ // 检查现有配置中是否已有 automount 设置
173
+ const existingConf = wslExec('cat /etc/wsl.conf 2>/dev/null') || '';
174
+
175
+ let newContent;
176
+
177
+ if (existingConf.includes('[automount]')) {
178
+ // 替换现有的 automount 部分
179
+ newContent = existingConf.replace(
180
+ /\[automount\][^\[]*/,
181
+ '[automount]\nenabled = false\n'
182
+ );
183
+ } else {
184
+ // 追加 automount 配置
185
+ newContent = existingConf + (existingConf ? '\n' : '') + '[automount]\nenabled = false\n';
186
+ }
187
+
188
+ // 写入新配置
189
+ const escaped = newContent.replace(/"/g, '\\"').replace(/`/g, '\\`').replace(/\$/g, '\\$');
190
+ const writeCmd = `cat > /etc/wsl.conf << 'WSLEOF'\n${newContent}WSLEOF`;
191
+
192
+ const ok = wslExecSudo(`bash -c '${writeCmd.replace(/'/g, "'\\''")}'`);
193
+
194
+ if (!ok) {
195
+ // 回退方案:直接用 tee 写入
196
+ const heredocOk = wslExecSudo(
197
+ `bash -c "echo '${escaped}' > /etc/wsl.conf"`
198
+ );
199
+ if (!heredocOk) {
200
+ printError('写入 wsl.conf 失败');
201
+ return false;
202
+ }
203
+ }
204
+
205
+ // 验证
206
+ const verify = wslExec('cat /etc/wsl.conf 2>/dev/null') || '';
207
+ if (verify.includes('enabled = false') || verify.includes('enabled=false')) {
208
+ printSuccess('automount 已禁用');
209
+ return true;
210
+ } else {
211
+ printError('配置验证失败,请手动检查 /etc/wsl.conf');
73
212
  return false;
74
213
  }
75
214
  }
76
215
 
216
+ // ============================================================================
217
+ // 步骤 3: 在桌面创建快捷方式
218
+ // ============================================================================
219
+
220
+ function step3_createShortcut(wslUser) {
221
+ printStep('步骤 3/3: 创建桌面快捷方式');
222
+
223
+ const wslPath = `\\\\wsl.localhost\\${DISTRO_NAME}\\home\\${wslUser}\\${WORKSPACE_DIR}`;
224
+ const desktopPath = path.join(os.homedir(), 'Desktop');
225
+
226
+ // 检查桌面路径是否存在
227
+ if (!fs.existsSync(desktopPath)) {
228
+ // 尝试中文桌面路径
229
+ const desktopPathCN = path.join(os.homedir(), '桌面');
230
+ if (fs.existsSync(desktopPathCN)) {
231
+ var shortcutDir = desktopPathCN;
232
+ } else {
233
+ printError('找不到桌面目录');
234
+ return false;
235
+ }
236
+ } else {
237
+ var shortcutDir = desktopPath;
238
+ }
239
+
240
+ const shortcutName = 'OpenClaw 工作目录.lnk';
241
+ const shortcutPath = path.join(shortcutDir, shortcutName);
242
+
243
+ // PowerShell 脚本创建快捷方式
244
+ const psScript = `
245
+ $ws = New-Object -ComObject WScript.Shell
246
+ $sc = $ws.CreateShortcut("${shortcutPath}")
247
+ $sc.TargetPath = "explorer.exe"
248
+ $sc.Arguments = "${wslPath}"
249
+ $sc.WorkingDirectory = "${wslPath}"
250
+ $sc.Description = "打开 OpenClaw 工作目录"
251
+ $sc.Save()
252
+
253
+ # 尝试下载图标
254
+ $iconDir = "${path.join(os.tmpdir(), 'myclaw')}"
255
+ New-Item -ItemType Directory -Force -Path $iconDir | Out-Null
256
+ $iconPath = "$iconDir\\openclaw.ico"
257
+ try {
258
+ Invoke-WebRequest -Uri "https://cdn.yiranlaoshi.com/software/myclaw/openclaw.ico" -OutFile $iconPath -UseBasicParsing
259
+ $sc.IconLocation = $iconPath
260
+ $sc.Save()
261
+ } catch {}
262
+
263
+ # 刷新桌面
264
+ [void] [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer(
265
+ [System.IntPtr] ([System.Runtime.InteropServices.Marshal]::ReadIntPtr(
266
+ [System.IntPtr] ([System.Runtime.InteropServices.Marshal]::GetProcAddress(
267
+ [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer(
268
+ [System.Runtime.InteropServices.Marshal]::GetProcAddress(
269
+ [System.Runtime.InteropServices.Marshal]::LoadLibrary('shell32.dll'),
270
+ 'SHChangeNotify'),
271
+ [System.Type] [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer)))
272
+ ))
273
+ )
274
+
275
+ Write-Host "OK"
276
+ `.trim();
277
+
278
+ // 简化:直接用 PowerShell 创建
279
+ const psCmd = `
280
+ $ws = New-Object -ComObject WScript.Shell
281
+ $sc = $ws.CreateShortcut("${shortcutPath.replace(/\\/g, '\\\\')}")
282
+ $sc.TargetPath = "explorer.exe"
283
+ $sc.Arguments = "${wslPath}"
284
+ $sc.WorkingDirectory = "${wslPath}"
285
+ $sc.Description = "OpenClaw Workspace"
286
+ $sc.Save()
287
+ Write-Host "OK"
288
+ `;
289
+
290
+ try {
291
+ const result = execSync(`powershell -NoProfile -Command "${psCmd.replace(/"/g, '\\"').replace(/\n/g, ' ')}"`, {
292
+ encoding: 'utf8',
293
+ stdio: 'pipe',
294
+ }).trim();
295
+
296
+ if (result.includes('OK')) {
297
+ printSuccess('桌面快捷方式已创建: ' + shortcutName);
298
+ printInfo('双击即可打开工作目录(通过 \\\\wsl.localhost 访问)');
299
+ return true;
300
+ }
301
+ } catch (err) {
302
+ // 回退:写一个 .url 文件
303
+ try {
304
+ const urlContent = `[InternetShortcut]\r\nURL=file://${wslPath}\r\nIconIndex=0\r\n`;
305
+ fs.writeFileSync(path.join(shortcutDir, 'OpenClaw 工作目录.url'), urlContent, 'utf8');
306
+ printSuccess('桌面快捷方式已创建 (.url)');
307
+ return true;
308
+ } catch (err2) {
309
+ printError('创建快捷方式失败: ' + err2.message);
310
+ return false;
311
+ }
312
+ }
313
+
314
+ return false;
315
+ }
316
+
77
317
  // ============================================================================
78
318
  // 主函数
79
319
  // ============================================================================
@@ -84,40 +324,52 @@ function run() {
84
324
  console.log(' MyClaw WSL2 权限封锁');
85
325
  console.log('========================================');
86
326
  console.log('');
327
+ console.log('此操作将:');
328
+ console.log(' 1. 在 WSL 内创建工作目录 ~/workspace');
329
+ console.log(' 2. 禁用 WSL 自动挂载 Windows 盘符');
330
+ console.log(' 3. 在桌面创建快捷方式(指向 WSL 工作目录)');
331
+ console.log('');
332
+ console.log('效果:Linux 看不到 Windows 文件,但 Windows');
333
+ console.log(' 可以通过快捷方式访问 Linux 工作目录。');
334
+ console.log('');
87
335
 
88
- // 如果在 Windows 上,提示需要在 WSL 中运行
89
- if (isWindows) {
90
- printWarning('此命令需要在 WSL2 环境中运行');
91
- console.log('');
92
- console.log('请按以下步骤操作:');
93
- console.log(' 1. 打开 WSL2 终端(在 Windows Terminal 中选择 OpenClaw)');
94
- console.log(' 2. WSL2 终端中运行: ' + C.y + 'myclaw restrict' + C.nc);
95
- console.log('');
96
- console.log('或者,在 Windows PowerShell 中运行:');
97
- console.log(' ' + C.y + 'wsl -d OpenClaw -- myclaw restrict' + C.nc);
98
- console.log(' (将 OpenClaw 替换为你的 WSL 发行版名称)');
99
- console.log('');
100
- return;
336
+ // 前置检查
337
+ checkPrerequisites();
338
+
339
+ // 步骤 1
340
+ const info = step1_createWorkspace();
341
+ if (!info) {
342
+ printError('步骤 1 失败,终止');
343
+ process.exit(1);
101
344
  }
102
345
 
103
- // 检查是否在 WSL 环境中
104
- if (!isWSL()) {
105
- printError('此脚本只能在 WSL2 环境中运行');
106
- console.log('');
107
- console.log('如果你在 Windows 上,请先安装 WSL2:');
108
- console.log(' ' + C.y + 'myclaw wsl2' + C.nc);
109
- console.log('');
110
- return;
346
+ // 步骤 2
347
+ if (!step2_disableAutomount(info.wslUser)) {
348
+ printError('步骤 2 失败,终止');
349
+ process.exit(1);
111
350
  }
112
351
 
113
- printSuccess('检测到 WSL2 环境');
114
- console.log('');
352
+ // 步骤 3
353
+ if (!step3_createShortcut(info.wslUser)) {
354
+ printWarning('步骤 3 失败,但不影响权限封锁');
355
+ }
115
356
 
116
- // 执行权限封锁脚本
117
- printStep('启动权限封锁脚本...');
357
+ // 完成提示
358
+ console.log('');
359
+ console.log('========================================');
360
+ printSuccess('权限封锁完成!');
361
+ console.log('========================================');
362
+ console.log('');
363
+ printWarning('需要重启 WSL2 才能使禁用挂载生效!');
364
+ console.log('');
365
+ console.log(' 请在 PowerShell 中运行:');
366
+ console.log(' ' + C.y + 'wsl --shutdown' + C.nc);
367
+ console.log(' 然后重新点击桌面图标启动。');
368
+ console.log('');
369
+ console.log('验证方法:');
370
+ console.log(' - WSL 内 ls /mnt/c 应该显示目录不存在');
371
+ console.log(' - 双击桌面「OpenClaw 工作目录」可打开工作文件夹');
118
372
  console.log('');
119
-
120
- runInWSL(SCRIPT_PATH);
121
373
  }
122
374
 
123
375
  module.exports = { run };