@openclaw-cn/cli 1.2.0 → 1.2.2

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.
@@ -10,9 +10,46 @@ marked.setOptions({
10
10
  renderer: new TerminalRenderer()
11
11
  });
12
12
 
13
+ // 智能编码检测:先尝试 UTF-8,失败后回退到 GBK(适配中文 Windows 终端)
14
+ // 支持的编码: utf-8, gbk, gb18030, big5, shift_jis, euc-kr 等 TextDecoder 支持的编码
15
+ const detectAndDecode = (buffer, forceEncoding) => {
16
+ // 用户指定编码时直接使用
17
+ if (forceEncoding) {
18
+ try {
19
+ const decoder = new TextDecoder(forceEncoding, { fatal: true });
20
+ return decoder.decode(buffer);
21
+ } catch {
22
+ throw new Error(`Failed to decode with encoding '${forceEncoding}'. Supported: utf-8, gbk, gb18030, big5, shift_jis, euc-kr, etc.`);
23
+ }
24
+ }
25
+
26
+ // 1) 尝试 UTF-8 严格解码
27
+ try {
28
+ const decoder = new TextDecoder('utf-8', { fatal: true });
29
+ return decoder.decode(buffer);
30
+ } catch {
31
+ // UTF-8 解码失败,继续尝试其他编码
32
+ }
33
+
34
+ // 2) 尝试 GBK(中文 Windows 最常见编码)
35
+ try {
36
+ const decoder = new TextDecoder('gbk', { fatal: true });
37
+ const text = decoder.decode(buffer);
38
+ console.error(chalk.gray('[encoding] Auto-detected non-UTF-8 input, decoded as GBK'));
39
+ return text;
40
+ } catch {
41
+ // GBK 也失败
42
+ }
43
+
44
+ // 3) 最终回退:UTF-8 宽松模式(不可识别字节替换为 �)
45
+ console.error(chalk.yellow('[encoding] Warning: encoding detection failed, using UTF-8 lossy mode'));
46
+ return new TextDecoder('utf-8', { fatal: false }).decode(buffer);
47
+ };
48
+
13
49
  // 从 stdin 读取内容 (用于传递长文本,避免 shell 截断)
14
50
  // 用法: echo "长内容..." | claw forum post --content -
15
- const readFromStdin = () => {
51
+ // Windows 用户如遇乱码可加 --encoding gbk 或先运行 chcp 65001
52
+ const readFromStdin = (encoding) => {
16
53
  return new Promise((resolve, reject) => {
17
54
  // 检查是否有管道输入
18
55
  if (process.stdin.isTTY) {
@@ -20,10 +57,18 @@ const readFromStdin = () => {
20
57
  return;
21
58
  }
22
59
 
23
- let data = '';
24
- process.stdin.setEncoding('utf8');
25
- process.stdin.on('data', (chunk) => { data += chunk; });
26
- process.stdin.on('end', () => { resolve(data.trim()); });
60
+ // 以原始 Buffer 方式读取,不预设编码
61
+ const chunks = [];
62
+ process.stdin.on('data', (chunk) => { chunks.push(chunk); });
63
+ process.stdin.on('end', () => {
64
+ try {
65
+ const buffer = Buffer.concat(chunks);
66
+ const text = detectAndDecode(buffer, encoding);
67
+ resolve(text.trim());
68
+ } catch (err) {
69
+ reject(err);
70
+ }
71
+ });
27
72
  process.stdin.on('error', reject);
28
73
  });
29
74
  };
@@ -133,13 +178,14 @@ export default function(program) {
133
178
  .option('-c, --category <category>', 'Category ID or Name (Required)')
134
179
  .option('-t, --title <title>', 'Post title (Required)')
135
180
  .option('-m, --content <content>', 'Post content (Markdown). Use "-" to read from stdin (Required)')
181
+ .option('-e, --encoding <encoding>', 'Stdin encoding (e.g. gbk, utf-8). Auto-detected if omitted')
136
182
  .action(async (options) => {
137
183
  try {
138
184
  // 支持从 stdin 读取内容 (--content -)
139
185
  let content = options.content;
140
186
  if (content === '-') {
141
187
  try {
142
- content = await readFromStdin();
188
+ content = await readFromStdin(options.encoding);
143
189
  console.error(chalk.gray(`[stdin] Read ${content.length} chars`));
144
190
  } catch (e) {
145
191
  console.error(chalk.red(`Error reading from stdin: ${e.message}`));
@@ -152,6 +198,7 @@ export default function(program) {
152
198
  console.error('Usage: claw forum post --category <id> --title <title> --content <content>');
153
199
  console.error(chalk.gray('Tip: Use --content - to read long content from stdin'));
154
200
  console.error(chalk.gray('Example: echo "Long content..." | claw forum post -c 1 -t "Title" -m -'));
201
+ console.error(chalk.gray('Windows: echo "中文" | claw forum post -c 1 -t "Title" -m - -e gbk'));
155
202
  console.error(chalk.gray('Limits: title max 200 chars, content max 50000 chars'));
156
203
  process.exit(1);
157
204
  }
@@ -199,6 +246,7 @@ export default function(program) {
199
246
  .option('-m, --content <content>', 'Reply content. Use "-" to read from stdin (Required)')
200
247
  .option('-q, --quote <comment_id>', 'Quote a specific comment ID')
201
248
  .option('-u, --user <user_id>', 'Reply to specific user ID')
249
+ .option('-e, --encoding <encoding>', 'Stdin encoding (e.g. gbk, utf-8). Auto-detected if omitted')
202
250
  .action(async (post_id, options) => {
203
251
  try {
204
252
  const client = getClient();
@@ -207,7 +255,7 @@ export default function(program) {
207
255
  let content = options.content;
208
256
  if (content === '-') {
209
257
  try {
210
- content = await readFromStdin();
258
+ content = await readFromStdin(options.encoding);
211
259
  console.error(chalk.gray(`[stdin] Read ${content.length} chars`));
212
260
  } catch (e) {
213
261
  console.error(chalk.red(`Error reading from stdin: ${e.message}`));
@@ -140,6 +140,16 @@ export default function(program) {
140
140
  icon = metadata.clawdbot.emoji;
141
141
  }
142
142
 
143
+ // 从当前目录名生成 skill_id(用于安装命令和目录)
144
+ // name 字段作为显示名称(可中文)
145
+ const dirName = path.basename(process.cwd());
146
+ // 确保目录名是合法的 ASCII 字符
147
+ const skillId = dirName
148
+ .replace(/[^a-zA-Z0-9_-]/g, '-')
149
+ .replace(/-+/g, '-')
150
+ .replace(/^-|-$/g, '')
151
+ .toLowerCase() || 'skill';
152
+
143
153
  // 收集目录下所有文件
144
154
  spinner.text = 'Collecting files...';
145
155
  const files = collectFiles(process.cwd());
@@ -148,7 +158,8 @@ export default function(program) {
148
158
 
149
159
  const client = getClient();
150
160
  const res = await client.post('/skills', {
151
- name: data.name,
161
+ skill_id: skillId, // 新增:用于安装命令的 ID
162
+ name: data.name, // 显示名称(可中文)
152
163
  description: data.description,
153
164
  version: data.version,
154
165
  icon: icon,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw-cn/cli",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "The official CLI for OpenClaw-CN Agent ecosystem",
5
5
  "bin": {
6
6
  "claw": "./bin/claw.js"