@aiyiran/myclaw 1.0.4 → 1.0.6

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/README.md ADDED
@@ -0,0 +1,126 @@
1
+ # MyClaw - 学生友好的 OpenClaw 工具
2
+
3
+ 一个简化 OpenClaw 日常操作的命令行工具,专为教学环境设计。
4
+
5
+ ## 跨平台要求 ⚠️
6
+
7
+ ```
8
+ ╔══════════════════════════════════════════════════════════════════════╗
9
+ ║ 跨平台兼容性说明 ║
10
+ ╠══════════════════════════════════════════════════════════════════════╣
11
+ ║ ║
12
+ ║ 支持系统: ║
13
+ ║ ✅ macOS - 完全支持,包括颜色和 Emoji ║
14
+ ║ ✅ Linux - 完全支持,包括颜色和 Emoji ║
15
+ ║ ✅ Windows 10/11 - 基本支持,推荐使用 Windows Terminal ║
16
+ ║ ⚠️ Windows 7/8 - 支持,但 Emoji 可能显示为方块 ║
17
+ ║ ║
18
+ ║ Windows 用户建议: ║
19
+ ║ • 安装 Windows Terminal (Microsoft Store 免费下载) ║
20
+ ║ • 或使用 PowerShell 7+ (https://aka.ms/powershell) ║
21
+ ║ ║
22
+ ║ 颜色说明: ║
23
+ ║ • macOS/Linux: 正常显示 ANSI 颜色 ║
24
+ ║ • Windows: 自动禁用颜色输出,避免乱码 ║
25
+ ║ ║
26
+ ╚══════════════════════════════════════════════════════════════════════╝
27
+ ```
28
+
29
+ ## 安装
30
+
31
+ ```bash
32
+ # 方式一: 直接运行
33
+ node myclaw/index.js <command>
34
+
35
+ # 方式二: 添加到 PATH (macOS/Linux)
36
+ ln -s /path/to/myclaw/index.js /usr/local/bin/myclaw
37
+ chmod +x /usr/local/bin/myclaw
38
+
39
+ # 方式三: Windows PowerShell
40
+ # 将 myclaw/index.js 路径添加到系统 PATH
41
+ ```
42
+
43
+ ## 使用方法
44
+
45
+ ### 查看状态
46
+ ```bash
47
+ myclaw status
48
+ ```
49
+ 简化版的 OpenClaw 状态面板,一眼看清 Gateway、Agents、Sessions 状态。
50
+
51
+ ### 创建新 Agent
52
+ ```bash
53
+ myclaw new <agent名称>
54
+ ```
55
+ 快速创建一个新的 OpenClaw Agent,自动完成:
56
+ - 创建 workspace 目录
57
+ - 配置 agent 文件
58
+ - 发送出生消息
59
+
60
+ 示例:
61
+ ```bash
62
+ myclaw new helper # 创建名为 helper 的 Agent
63
+ myclaw new testbot # 创建名为 testbot 的 Agent
64
+ ```
65
+
66
+ ### 安装 OpenClaw
67
+ ```bash
68
+ myclaw install
69
+ ```
70
+ 自动检测操作系统并执行对应的安装命令。
71
+
72
+ ### 帮助
73
+ ```bash
74
+ myclaw help
75
+ ```
76
+
77
+ ## 文件结构
78
+
79
+ ```
80
+ myclaw/
81
+ ├── index.js # 主入口,命令解析和输出
82
+ ├── create_agent.js # Agent 创建逻辑模块
83
+ └── README.md # 本文件
84
+ ```
85
+
86
+ ### 模块说明
87
+
88
+ | 文件 | 职责 |
89
+ |------|------|
90
+ | `index.js` | 主入口,解析命令、颜色输出、调用模块 |
91
+ | `create_agent.js` | Agent 创建的完整逻辑,可独立使用 |
92
+
93
+ ## 开发说明
94
+
95
+ ### 代码规范
96
+
97
+ 1. **跨平台兼容性** - 必须考虑 Windows 用户体验
98
+ - 使用 `os.platform()` 检测系统
99
+ - Windows 下禁用 ANSI 颜色输出
100
+ - 避免使用只在 Unix 系统有效的命令
101
+
102
+ 2. **错误处理**
103
+ - 所有 `execSync` 调用必须使用 `try-catch`
104
+ - 失败时提供清晰的错误信息和解决方案
105
+
106
+ 3. **模块化**
107
+ - 业务逻辑放入独立模块
108
+ - 主入口只做命令解析和输出
109
+
110
+ ### 测试清单
111
+
112
+ 发布前请在以下环境测试:
113
+ - [ ] macOS (Terminal)
114
+ - [ ] Linux (bash)
115
+ - [ ] Windows 10/11 (PowerShell)
116
+ - [ ] Windows 10/11 (CMD)
117
+ - [ ] Windows Terminal (如果可用)
118
+
119
+ ## 依赖
120
+
121
+ - Node.js 14+
122
+ - OpenClaw CLI (用于实际命令执行)
123
+
124
+ ## 许可证
125
+
126
+ 内部教学工具
@@ -0,0 +1,272 @@
1
+ /**
2
+ * ============================================================================
3
+ * MyClaw - Create Agent 模块
4
+ * ============================================================================
5
+ *
6
+ * 创建 OpenClaw Agent 的完整逻辑
7
+ *
8
+ * 功能:
9
+ * - 标准化 agent ID
10
+ * - 检查重复
11
+ * - 创建工作空间目录和默认文件
12
+ * - 更新 OpenClaw 配置文件
13
+ * - 发送出生消息
14
+ *
15
+ * ============================================================================
16
+ */
17
+
18
+ const { execSync } = require('child_process');
19
+ const fs = require('fs');
20
+ const path = require('path');
21
+ const os = require('os');
22
+
23
+ // ============================================================================
24
+ // 路径工具
25
+ // ============================================================================
26
+
27
+ function normalizePath(p) {
28
+ return p.replace(/\\/g, '/');
29
+ }
30
+
31
+ function ensureDir(dirPath) {
32
+ if (!fs.existsSync(dirPath)) {
33
+ fs.mkdirSync(dirPath, { recursive: true });
34
+ }
35
+ }
36
+
37
+ function writeIfAbsent(filePath, content) {
38
+ if (!fs.existsSync(filePath)) {
39
+ fs.writeFileSync(filePath, content, 'utf8');
40
+ }
41
+ }
42
+
43
+ // ============================================================================
44
+ // 工具函数
45
+ // ============================================================================
46
+
47
+ function fail(msg, code = 1) {
48
+ console.error('[错误] ' + msg);
49
+ process.exit(code);
50
+ }
51
+
52
+ /**
53
+ * 标准化 agent ID
54
+ * - 转小写
55
+ * - 非法字符替换为连字符
56
+ * - 去除多余连字符
57
+ */
58
+ function normalizeAgentId(raw) {
59
+ let value = raw.trim().toLowerCase();
60
+ value = value.replace(/[^a-z0-9-]/g, '-');
61
+ value = value.replace(/-{2,}/g, '-').replace(/^-|-$/g, '');
62
+ return value;
63
+ }
64
+
65
+ /**
66
+ * 验证 agent ID
67
+ */
68
+ function validateAgentId(agentId) {
69
+ if (!agentId) {
70
+ fail('Agent 名称标准化后为空,请检查输入。');
71
+ }
72
+ if (agentId.length > 64) {
73
+ fail('Agent ID 太长,请保持在 64 个字符以内。');
74
+ }
75
+ if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(agentId)) {
76
+ fail('Agent ID 只能包含小写字母、数字和连字符(不能以连字符开头或结尾)。');
77
+ }
78
+ }
79
+
80
+ /**
81
+ * 生成北京时间出生消息
82
+ */
83
+ function buildBirthMessage() {
84
+ const nowUtc = new Date();
85
+ const nowBj = new Date(nowUtc.getTime() + 8 * 60 * 60 * 1000);
86
+ const y = nowBj.getUTCFullYear();
87
+ const m = nowBj.getUTCMonth() + 1;
88
+ const d = nowBj.getUTCDate();
89
+ const h = String(nowBj.getUTCHours()).padStart(2, '0');
90
+ const min = String(nowBj.getUTCMinutes()).padStart(2, '0');
91
+ const ts = `${y}年${m}月${d}日${h}:${min}`;
92
+ return (
93
+ `你好,你的生日是北京时间${ts},请记录这个信息。\n` +
94
+ '欢迎你来到这个世界,我是你的造物主,我们是伙伴,我叫做孙依然,' +
95
+ '你可以叫我依然,请多多指教,共同成长。'
96
+ );
97
+ }
98
+
99
+ /**
100
+ * 默认工作空间文件内容
101
+ */
102
+ function defaultWorkspaceFiles(agentId) {
103
+ return {
104
+ 'AGENTS.md': (
105
+ `# AGENTS.md - ${agentId}\n\n` +
106
+ `This workspace belongs to the \`${agentId}\` agent.\n\n` +
107
+ '## Startup\n' +
108
+ '- Read `SOUL.md`\n' +
109
+ '- Read `USER.md`\n' +
110
+ '- Read recent memory if available\n\n' +
111
+ '## Rules\n' +
112
+ '- Be helpful, careful, and concise.\n' +
113
+ '- Prefer using the existing workspace and defaults.\n' +
114
+ '- Ask before destructive or external actions.\n'
115
+ ),
116
+ 'SOUL.md': (
117
+ `# SOUL.md\n\n` +
118
+ `You are \`${agentId}\`.\n\n` +
119
+ 'Be useful, calm, direct, and trustworthy.\n' +
120
+ 'Use the default OpenClaw behavior unless the user asks for something special.\n'
121
+ ),
122
+ 'USER.md': (
123
+ '# USER.md\n\n' +
124
+ '- Name: 孙依然\n' +
125
+ '- What to call them: 依然\n' +
126
+ '- Timezone: Asia/Shanghai\n\n' +
127
+ 'Build understanding gradually and respectfully.\n'
128
+ ),
129
+ 'IDENTITY.md': (
130
+ '# IDENTITY.md\n\n' +
131
+ `- Name: ${agentId}\n` +
132
+ '- Role: OpenClaw agent\n' +
133
+ '- Vibe: practical, reliable, clear\n'
134
+ ),
135
+ 'HEARTBEAT.md': (
136
+ '# HEARTBEAT.md\n\n' +
137
+ '# Keep empty unless periodic checks are needed.\n'
138
+ ),
139
+ 'BOOTSTRAP.md': (
140
+ `# BOOTSTRAP.md\n\n` +
141
+ `You are a newly created OpenClaw agent named \`${agentId}\`.\n\n` +
142
+ 'On first runs, learn your workspace files and begin helping.\n'
143
+ ),
144
+ };
145
+ }
146
+
147
+ // ============================================================================
148
+ // 主函数
149
+ // ============================================================================
150
+
151
+ /**
152
+ * 创建新的 OpenClaw Agent
153
+ *
154
+ * @param {string} rawName - 原始名称
155
+ * @returns {object} 创建结果
156
+ */
157
+ function createAgent(rawName) {
158
+ // 标准化 & 验证名称
159
+ const agentId = normalizeAgentId(rawName);
160
+ validateAgentId(agentId);
161
+
162
+ // 确定 OpenClaw 配置目录
163
+ const homeDir = os.homedir();
164
+ const openclawDir = path.join(homeDir, '.openclaw');
165
+ const configPath = path.join(openclawDir, 'openclaw.json');
166
+ const agentsDir = path.join(openclawDir, 'agents');
167
+ const workspaceDir = path.join(openclawDir, 'workspace-' + agentId);
168
+ const agentDir = path.join(agentsDir, agentId, 'agent');
169
+
170
+ // 检查配置是否存在
171
+ if (!fs.existsSync(configPath)) {
172
+ fail('配置文件不存在: ' + normalizePath(configPath) + '\n请先运行 openclaw onboard 完成初始化。');
173
+ }
174
+
175
+ // 加载配置
176
+ let configData;
177
+ try {
178
+ const raw = fs.readFileSync(configPath, 'utf8');
179
+ configData = JSON.parse(raw);
180
+ } catch (err) {
181
+ fail('配置文件读取失败: ' + err.message);
182
+ }
183
+
184
+ // 确保 agents 结构存在
185
+ if (!configData.agents) {
186
+ configData.agents = {};
187
+ }
188
+ if (!Array.isArray(configData.agents.list)) {
189
+ configData.agents.list = [];
190
+ }
191
+
192
+ // 检查重复 ID
193
+ const existingIds = new Set(
194
+ configData.agents.list
195
+ .filter(e => e && typeof e === 'object')
196
+ .map(e => e.id)
197
+ );
198
+ if (existingIds.has(agentId)) {
199
+ fail('Agent "' + agentId + '" 已存在,请使用其他名称。');
200
+ }
201
+
202
+ // 检查目录冲突
203
+ if (fs.existsSync(workspaceDir) || fs.existsSync(agentDir)) {
204
+ fail(
205
+ '工作空间或 Agent 目录已存在,请检查是否已有同名 Agent。\n' +
206
+ 'workspace=' + normalizePath(workspaceDir) + '\n' +
207
+ 'agentDir=' + normalizePath(agentDir)
208
+ );
209
+ }
210
+
211
+ // 创建目录结构
212
+ ensureDir(workspaceDir);
213
+ ensureDir(agentDir);
214
+ ensureDir(path.join(agentsDir, agentId, 'sessions'));
215
+
216
+ // 创建默认工作空间文件
217
+ const files = defaultWorkspaceFiles(agentId);
218
+ for (const [filename, content] of Object.entries(files)) {
219
+ writeIfAbsent(path.join(workspaceDir, filename), content);
220
+ }
221
+
222
+ // 备份配置
223
+ const backupPath = configPath + '.bak.agent-birth.' +
224
+ new Date().toISOString().replace(/[:.]/g, '-').slice(0, 26) + 'Z';
225
+ fs.copyFileSync(configPath, backupPath);
226
+
227
+ // 添加 Agent 条目
228
+ configData.agents.list.push({
229
+ id: agentId,
230
+ name: agentId,
231
+ workspace: workspaceDir,
232
+ agentDir: agentDir,
233
+ });
234
+
235
+ // 写入配置
236
+ try {
237
+ fs.writeFileSync(configPath, JSON.stringify(configData, null, 2) + '\n', 'utf8');
238
+ } catch (err) {
239
+ fail('配置文件写入失败: ' + err.message + '\n备份文件: ' + normalizePath(backupPath));
240
+ }
241
+
242
+ // 发送出生消息
243
+ const birthMessage = buildBirthMessage();
244
+ let firstMessageSent = false;
245
+ let firstMessageError = null;
246
+
247
+ try {
248
+ execSync(
249
+ 'openclaw agent --agent ' + agentId + ' --message ' + JSON.stringify(birthMessage) + ' --json 2>&1',
250
+ { encoding: 'utf8', timeout: 30000 }
251
+ );
252
+ firstMessageSent = true;
253
+ } catch (err) {
254
+ firstMessageSent = false;
255
+ firstMessageError = err.message;
256
+ }
257
+
258
+ // 返回结果
259
+ return {
260
+ ok: true,
261
+ agentId: agentId,
262
+ sessionKey: 'agent:' + agentId + ':main',
263
+ workspace: normalizePath(workspaceDir),
264
+ agentDir: normalizePath(agentDir),
265
+ configBackup: normalizePath(backupPath),
266
+ birthMessage: birthMessage,
267
+ firstMessageSent: firstMessageSent,
268
+ firstMessageError: firstMessageError,
269
+ };
270
+ }
271
+
272
+ module.exports = { createAgent, normalizeAgentId, validateAgentId };
package/index.js CHANGED
@@ -1,87 +1,132 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ /**
4
+ * ============================================================================
5
+ * MyClaw - 学生友好的 OpenClaw 工具
6
+ * ============================================================================
7
+ *
8
+ * 跨平台要求 / Cross-Platform Requirements:
9
+ * ----------------------------------------
10
+ * 本脚本支持 macOS、Linux 和 Windows。
11
+ *
12
+ * Windows 支持说明:
13
+ * - Windows 10+ (Build 1053+) 原生支持 ANSI 颜色代码
14
+ * - Windows 7/8/10 旧版本: 颜色代码会被 stripped,避免乱码
15
+ * - 推荐 Windows 用户使用 Windows Terminal 或 PowerShell 7+ 获得最佳体验
16
+ * - Emoji 符号在 Windows 命令行可能显示为方块,属正常现象
17
+ *
18
+ * 测试环境:
19
+ * - macOS: ✅ 完全支持
20
+ * - Linux: ✅ 完全支持
21
+ * - Windows 10/11 (PowerShell/CMD): ✅ 基本支持
22
+ *
23
+ * ============================================================================
24
+ */
25
+
3
26
  const { execSync } = require('child_process');
4
27
  const os = require('os');
28
+ const { createAgent } = require('./create_agent');
5
29
 
6
30
  const args = process.argv.slice(2);
7
31
  const command = args[0];
8
32
 
33
+ // ============================================================================
34
+ // 跨平台检测
35
+ // ============================================================================
36
+
9
37
  function detectPlatform() {
10
38
  const platform = os.platform();
11
39
  if (platform === 'win32') return 'windows';
12
- if (platform === 'darwin' || platform === 'linux') return 'mac'; // mac/linux 都用 bash
40
+ if (platform === 'darwin' || platform === 'linux') return 'mac';
13
41
  return 'unknown';
14
42
  }
15
43
 
44
+ const isWindows = detectPlatform() === 'windows';
45
+
46
+ // ============================================================================
47
+ // 跨平台颜色输出
48
+ // ============================================================================
49
+
50
+ function makeColors() {
51
+ if (isWindows) {
52
+ return { red: '', green: '', yellow: '', blue: '', nc: '' };
53
+ }
54
+ return {
55
+ red: '\x1b[31m',
56
+ green: '\x1b[32m',
57
+ yellow: '\x1b[33m',
58
+ blue: '\x1b[34m',
59
+ nc: '\x1b[0m'
60
+ };
61
+ }
62
+
63
+ const colors = makeColors();
64
+
65
+ // ============================================================================
66
+ // 安装命令
67
+ // ============================================================================
68
+
16
69
  function runInstall() {
17
70
  const platform = detectPlatform();
18
71
 
19
72
  if (platform === 'windows') {
20
- console.log('🪟 检测到 Windows 系统,正在安装...');
73
+ console.log('[Windows] 检测到 Windows 系统,正在安装...');
21
74
  const cmd = 'powershell -c "irm https://openclaw.ai/install.ps1 | iex"';
22
- console.log(`> ${cmd}`);
75
+ console.log('> ' + cmd);
23
76
  try {
24
77
  execSync(cmd, { stdio: 'inherit' });
25
78
  } catch (err) {
26
- console.error(' 安装失败:', err.message);
79
+ console.error('[错误] 安装失败:', err.message);
27
80
  process.exit(1);
28
81
  }
29
82
  } else if (platform === 'mac') {
30
- console.log('🍎 检测到 macOS/Linux 系统,正在安装...');
83
+ console.log('[macOS/Linux] 检测到系统,正在安装...');
31
84
  const cmd = 'curl -fsSL https://openclaw.ai/install.sh | bash';
32
- console.log(`> ${cmd}`);
85
+ console.log('> ' + cmd);
33
86
  try {
34
87
  execSync(cmd, { stdio: 'inherit' });
35
88
  } catch (err) {
36
- console.error(' 安装失败:', err.message);
89
+ console.error('[错误] 安装失败:', err.message);
37
90
  process.exit(1);
38
91
  }
39
92
  } else {
40
- console.error(' 不支持的操作系统:', os.platform());
93
+ console.error('[错误] 不支持的操作系统:', os.platform());
41
94
  process.exit(1);
42
95
  }
43
96
  }
44
97
 
45
- // 颜色输出
46
- const colors = {
47
- red: '\x1b[31m',
48
- green: '\x1b[32m',
49
- yellow: '\x1b[33m',
50
- blue: '\x1b[34m',
51
- nc: '\x1b[0m' // No Color
52
- };
98
+ // ============================================================================
99
+ // 状态命令
100
+ // ============================================================================
53
101
 
54
102
  function runStatus() {
103
+ const bar = '----------------------------------------';
104
+
55
105
  console.log('');
56
- console.log(colors.blue + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' + colors.nc);
57
- console.log(colors.blue + ' 🦞 MyClaw 状态面板' + colors.nc);
58
- console.log(colors.blue + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' + colors.nc);
106
+ console.log('[' + colors.blue + 'MyClaw' + colors.nc + '] ' + colors.blue + '状态面板' + colors.nc);
107
+ console.log(bar);
59
108
  console.log('');
60
-
109
+
61
110
  // Gateway 状态
62
- console.log(colors.yellow + 'Gateway' + colors.nc);
111
+ console.log('[Gateway]');
63
112
  try {
64
113
  execSync('openclaw health', { stdio: 'pipe' });
65
- console.log(' 状态: ' + colors.green + ' 运行中' + colors.nc);
114
+ console.log(' 状态: ' + colors.green + '[OK] 运行中' + colors.nc);
66
115
  try {
67
116
  const statusOutput = execSync('openclaw status 2>/dev/null', { encoding: 'utf8' });
68
117
  const dashboardMatch = statusOutput.match(/Dashboard[^\n]*?(http:\/\/[^\s]+)/);
69
- if (dashboardMatch) {
70
- console.log(' 控制台: ' + dashboardMatch[1]);
71
- } else {
72
- console.log(' 控制台: http://127.0.0.1:18789');
73
- }
118
+ console.log(' 控制台: ' + (dashboardMatch ? dashboardMatch[1] : 'http://127.0.0.1:18789'));
74
119
  } catch {
75
120
  console.log(' 控制台: http://127.0.0.1:18789');
76
121
  }
77
122
  } catch (err) {
78
- console.log(' 状态: ' + colors.red + ' 未运行' + colors.nc);
79
- console.log(' 启动: ' + colors.yellow + 'openclaw gateway' + colors.nc);
123
+ console.log(' 状态: ' + colors.red + '[ERROR] 未运行' + colors.nc);
124
+ console.log(' 启动命令: ' + colors.yellow + 'openclaw gateway' + colors.nc);
80
125
  }
81
126
  console.log('');
82
-
127
+
83
128
  // Session 数量
84
- console.log(colors.yellow + 'Sessions' + colors.nc);
129
+ console.log('[Sessions]');
85
130
  try {
86
131
  const sessionsOutput = execSync('openclaw sessions list 2>/dev/null', { encoding: 'utf8' });
87
132
  const sessionCount = (sessionsOutput.match(/agent:/g) || []).length;
@@ -90,9 +135,9 @@ function runStatus() {
90
135
  console.log(' 活跃会话: ' + colors.red + '0' + colors.nc + ' 个');
91
136
  }
92
137
  console.log('');
93
-
138
+
94
139
  // Agent 数量
95
- console.log(colors.yellow + 'Agents' + colors.nc);
140
+ console.log('[Agents]');
96
141
  try {
97
142
  const agentsOutput = execSync('openclaw agents list 2>/dev/null', { encoding: 'utf8' });
98
143
  const agentCount = (agentsOutput.match(/agent:/g) || []).length;
@@ -101,9 +146,9 @@ function runStatus() {
101
146
  console.log(' 已注册 Agent: ' + colors.red + '0' + colors.nc + ' 个');
102
147
  }
103
148
  console.log('');
104
-
149
+
105
150
  // 最近活动
106
- console.log(colors.yellow + '最近活动' + colors.nc);
151
+ console.log('[最近活动]');
107
152
  try {
108
153
  const sessionsOutput = execSync('openclaw sessions list 2>/dev/null', { encoding: 'utf8' });
109
154
  const lines = sessionsOutput.split('\n').filter(line =>
@@ -121,18 +166,22 @@ function runStatus() {
121
166
  console.log(' 无最近活动');
122
167
  }
123
168
  console.log('');
124
-
125
- console.log(colors.blue + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' + colors.nc);
169
+
170
+ console.log(bar);
126
171
  console.log('提示: 运行 ' + colors.yellow + 'openclaw status' + colors.nc + ' 查看完整状态');
127
172
  console.log(' 运行 ' + colors.yellow + 'myclaw help' + colors.nc + ' 查看所有命令');
128
173
  console.log('');
129
174
  }
130
175
 
176
+ // ============================================================================
177
+ // 创建新 Agent
178
+ // ============================================================================
179
+
131
180
  function runNew() {
132
- const agentName = args[1];
181
+ const rawName = args[1];
133
182
 
134
- if (!agentName) {
135
- console.error('\x1b[31m❌ 请提供 Agent 名称\x1b[0m');
183
+ if (!rawName) {
184
+ console.error('[' + colors.red + '错误' + colors.nc + '] 请提供 Agent 名称');
136
185
  console.log('');
137
186
  console.log('用法: myclaw new <agent名称>');
138
187
  console.log('');
@@ -142,93 +191,143 @@ function runNew() {
142
191
  process.exit(1);
143
192
  }
144
193
 
145
- // 验证名称格式
146
- if (!/^[a-z0-9-]+$/.test(agentName)) {
147
- console.error('\x1b[31m❌ Agent 名称只能包含小写字母、数字和连字符(-)\x1b[0m');
148
- console.log('');
149
- console.log('示例:');
150
- console.log(' myclaw new helper');
151
- console.log(' myclaw new my-bot');
152
- process.exit(1);
153
- }
154
-
194
+ const bar = '----------------------------------------';
195
+
155
196
  console.log('');
156
- console.log(colors.blue + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' + colors.nc);
157
- console.log(colors.blue + ' 🦞 创建新 Agent: ' + agentName + colors.nc);
158
- console.log(colors.blue + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' + colors.nc);
197
+ console.log('[' + colors.blue + 'MyClaw' + colors.nc + '] ' + colors.blue + '创建新 Agent' + colors.nc);
198
+ console.log(bar);
199
+ console.log('');
200
+ console.log('[创建中] 正在创建 Agent...');
159
201
  console.log('');
160
202
 
161
- // 检查是否已存在
162
- try {
163
- const agentsOutput = execSync('openclaw agents list 2>/dev/null', { encoding: 'utf8' });
164
- if (agentsOutput.includes(`agent:${agentName}:`)) {
165
- console.error('\x1b[31m❌ Agent "' + agentName + '" 已存在\x1b[0m');
166
- process.exit(1);
167
- }
168
- } catch (e) {
169
- // 继续创建
170
- }
171
-
172
- // 查找 yiran-agent-birth 脚本
173
- const birthScript = '/Users/yiran/.openclaw/workspace/skills/yiran-agent-birth/scripts/create_agent.py';
174
-
175
- console.log(colors.yellow + '▸ 正在创建 Agent...' + colors.nc);
176
-
177
203
  try {
178
- const result = execSync(`python3 "${birthScript}" ${agentName}`, { encoding: 'utf8' });
179
- const jsonResult = JSON.parse(result);
204
+ const result = createAgent(rawName);
180
205
 
206
+ console.log('[' + colors.green + '成功' + colors.nc + '] Agent 创建成功!');
181
207
  console.log('');
182
- console.log(colors.green + '✓ Agent 创建成功!' + colors.nc);
183
- console.log('');
184
- console.log(' 名称: ' + agentName);
185
- console.log(' Session: ' + jsonResult.sessionKey);
186
- console.log(' Workspace: ' + jsonResult.workspace);
208
+ console.log(' 名称: ' + result.agentId);
209
+ console.log(' Session: ' + result.sessionKey);
210
+ console.log(' Workspace: ' + result.workspace);
211
+ console.log(' 备份: ' + result.configBackup);
187
212
  console.log('');
188
213
 
189
- if (jsonResult.firstMessageSent) {
190
- console.log(colors.green + '✓ 出生消息已发送' + colors.nc);
214
+ if (result.firstMessageSent) {
215
+ console.log('[' + colors.green + 'OK' + colors.nc + '] 出生消息已发送');
191
216
  } else {
192
- console.log(colors.yellow + '⚠ 出生消息发送失败,可手动重试' + colors.nc);
217
+ console.log('[' + colors.yellow + '警告' + colors.nc + '] 出生消息发送失败');
218
+ if (result.firstMessageError) {
219
+ console.log(' 错误: ' + result.firstMessageError);
220
+ }
221
+ console.log(' 手动重试: ' + colors.yellow + 'openclaw agent --agent ' + result.agentId + ' --message "你好"' + colors.nc);
193
222
  }
194
223
 
195
224
  console.log('');
196
- console.log(colors.blue + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' + colors.nc);
197
- console.log('下一步: 运行 ' + colors.yellow + `openclaw agent --agent ${agentName} --message "你好"` + colors.nc + ' 与它对话');
225
+ console.log(bar);
226
+ console.log('下一步: 运行 ' + colors.yellow + 'openclaw agent --agent ' + result.agentId + ' --message "你好"' + colors.nc + ' 与它对话');
198
227
  console.log('');
199
228
 
200
229
  } catch (err) {
201
- console.error('\x1b[31m❌ 创建失败: ' + err.message + '\x1b[0m');
230
+ // create_agent.js 已经有错误信息输出
231
+ console.log('');
232
+ console.log('[' + colors.red + '失败' + colors.nc + '] Agent 创建失败');
202
233
  console.log('');
203
- console.log('常见问题:');
204
- console.log(' - Agent 名称已存在');
205
- console.log(' - 权限不足');
206
- console.log(' - OpenClaw 未运行');
207
234
  process.exit(1);
208
235
  }
209
236
  }
210
237
 
238
+ // ============================================================================
239
+ // 安装/修复 WSL2
240
+ // ============================================================================
241
+
242
+ function runWsl2() {
243
+ if (!isWindows) {
244
+ console.error('[' + colors.red + '提示' + colors.nc + '] 本命令主要用于 Windows 系统。在 Mac/Linux 下不需要安装 WSL2。');
245
+ process.exit(0);
246
+ }
247
+
248
+ const bar = '----------------------------------------';
249
+ console.log('');
250
+ console.log('[' + colors.blue + 'MyClaw' + colors.nc + '] ' + colors.blue + '修复/安装 Windows WSL2 环境' + colors.nc);
251
+ console.log(bar);
252
+ console.log('');
253
+ console.log('即将申请管理员权限以启用 Windows WSL2 和 虚拟机平台功能...');
254
+ console.log('这使用的是兼容性最好的"手动打补丁"底层方法,用来解决直接安装失败的问题。');
255
+ console.log('[' + colors.yellow + '注意' + colors.nc + '] 请在稍后弹出的 UAC 授权窗口中选【是】。');
256
+ console.log('');
257
+
258
+ const psCommand = `
259
+ Write-Host "============================";
260
+ Write-Host " MyClaw - WSL2 环境底座修复";
261
+ Write-Host "============================";
262
+ Write-Host "";
263
+ Write-Host "步骤 1/3: 正在启用 Windows Subsystem for Linux...";
264
+ dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart;
265
+ Write-Host "";
266
+ Write-Host "步骤 2/3: 正在启用 虚拟机平台...";
267
+ dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart;
268
+ Write-Host "";
269
+ Write-Host "步骤 3/3: 尝试设置 WSL2 为默认版本...";
270
+ try { wsl --set-default-version 2 2>$null } catch {}
271
+ Write-Host "";
272
+ Write-Host "============================";
273
+ Write-Host " 操作执行完毕!";
274
+ Write-Host " 注意:必须 [重新启动电脑] 才能生效!";
275
+ Write-Host "============================";
276
+ Write-Host " -> 若重启后运行 wsl 提示需要内核更新,";
277
+ Write-Host " -> 请浏览器访问下载并安装: https://aka.ms/wsl2kernel";
278
+ Write-Host " -> 最后去 Microsoft Store 搜索 Ubuntu 并安装即可。";
279
+ Write-Host "";
280
+ Write-Host "按任意键退出当前窗口...";
281
+ $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown");
282
+ `;
283
+
284
+ // 为了跨 PowerShell 调用避免引号转移错乱,转为 Base64 执行 (UTF-16LE 编码)
285
+ const b64Cmd = Buffer.from(psCommand, 'utf16le').toString('base64');
286
+
287
+ try {
288
+ execSync(`powershell -Command "Start-Process powershell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -EncodedCommand ${b64Cmd}' -Verb RunAs"`, { stdio: 'inherit' });
289
+ console.log('[' + colors.green + '成功' + colors.nc + '] 修复命令已下发,请查看新弹出的蓝色 PowerShell 窗口。');
290
+ console.log('');
291
+ console.log('执行完后记得 ' + colors.yellow + '重启电脑' + colors.nc + ' 哦!');
292
+ console.log('');
293
+ } catch (err) {
294
+ console.error('[' + colors.red + '错误' + colors.nc + '] 执行提权脚本失败:', err.message);
295
+ console.log('建议右键点击终端,选择【以管理员身份运行】再重试。');
296
+ }
297
+ }
298
+
299
+ // ============================================================================
300
+ // 帮助信息
301
+ // ============================================================================
302
+
211
303
  function showHelp() {
212
- console.log(`
213
- myclaw - OpenClaw CLI 工具
214
-
215
- 用法:
216
- myclaw <command>
217
-
218
- 命令:
219
- install 安装 OpenClaw 服务
220
- status 简化版状态查看(学生友好)
221
- new 创建新的 Agent(学生练习用)
222
- help 显示帮助信息
223
-
224
- 示例:
225
- myclaw install # 安装 OpenClaw
226
- myclaw status # 查看状态
227
- myclaw new helper # 创建名为 helper 的 Agent
228
- `);
304
+ console.log('');
305
+ console.log('MyClaw - 学生友好的 OpenClaw 工具');
306
+ console.log('----------------------------------------');
307
+ console.log('');
308
+ console.log('用法:');
309
+ console.log(' myclaw <command>');
310
+ console.log('');
311
+ console.log('命令:');
312
+ console.log(' install 安装 OpenClaw 服务');
313
+ console.log(' status 简化版状态查看(学生友好)');
314
+ console.log(' new 创建新的 Agent(学生练习用)');
315
+ console.log(' wsl2 修复 Windows 下 WSL2 安装失败的问题 (仅限 Windows)');
316
+ console.log(' help 显示帮助信息');
317
+ console.log('');
318
+ console.log('示例:');
319
+ console.log(' myclaw install # 安装 OpenClaw');
320
+ console.log(' myclaw status # 查看状态');
321
+ console.log(' myclaw new helper # 创建名为 helper 的 Agent');
322
+ console.log('');
323
+ console.log('跨平台: macOS / Linux / Windows (PowerShell/CMD)');
324
+ console.log('');
229
325
  }
230
326
 
327
+ // ============================================================================
231
328
  // 主逻辑
329
+ // ============================================================================
330
+
232
331
  if (!command || command === 'help' || command === '--help' || command === '-h') {
233
332
  showHelp();
234
333
  } else if (command === 'install') {
@@ -237,8 +336,10 @@ if (!command || command === 'help' || command === '--help' || command === '-h')
237
336
  runStatus();
238
337
  } else if (command === 'new') {
239
338
  runNew();
339
+ } else if (command === 'wsl2') {
340
+ runWsl2();
240
341
  } else {
241
- console.error('\x1b[31m❌ 未知命令: ' + command + '\x1b[0m');
342
+ console.error('[' + colors.red + '错误' + colors.nc + '] 未知命令: ' + command);
242
343
  showHelp();
243
344
  process.exit(1);
244
- }
345
+ }
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@aiyiran/myclaw",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
7
- "myclaw": "index.js"
7
+ "myclaw": "index.js",
8
+ "mc": "index.js"
8
9
  },
9
10
  "scripts": {
10
11
  "test": "echo \"Error: no test specified\" && exit 1"
package/publish.sh ADDED
@@ -0,0 +1,30 @@
1
+ #!/bin/bash
2
+ set -e # 遇到错误即停止
3
+
4
+ echo "📦 准备发布新版本..."
5
+
6
+ # 1. 添加所有变动
7
+ git add .
8
+
9
+ # 2. 检查是否有未提交的代码,如果有则先提交
10
+ if ! git diff-index --quiet HEAD; then
11
+ echo "📝 发现有修改的内容,正在自动提交..."
12
+ git commit -m "chore: auto update before publish"
13
+ else
14
+ echo "✅ 工作区很干净,不需要额外提交代码。"
15
+ fi
16
+
17
+ # 3. 自动更新最小版本号 (npm version patch 会自动再做一个改 package.json 的 commit 并且打上 Tag)
18
+ echo "📈 增加 Patch 版本号..."
19
+ npm version patch
20
+
21
+ # 4. 推送代码和 Tag 到 GitHub
22
+ echo "☁️ 推送代码和版本 Tag 到 GitHub..."
23
+ git push origin main
24
+ git push origin --tags
25
+
26
+ # 5. 发布到 npm
27
+ echo "🚀 发布到 npm 仓库..."
28
+ npm publish
29
+
30
+ echo "🎉 发布流执行完成!"