@dcrays/dcgchat-test 0.2.12 → 0.2.14

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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/src/bot.ts +150 -4
  3. package/src/skill.ts +8 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dcrays/dcgchat-test",
3
- "version": "0.2.12",
3
+ "version": "0.2.14",
4
4
  "type": "module",
5
5
  "description": "OpenClaw channel plugin for 书灵墨宝 (WebSocket)",
6
6
  "main": "index.ts",
package/src/bot.ts CHANGED
@@ -152,6 +152,125 @@ function createFileExtractor() {
152
152
  return { getNewFiles }
153
153
  }
154
154
 
155
+ /**
156
+ * 从文本中提取 /mobook 目录下的文件
157
+ * @param {string} text
158
+ * @returns {string[]}
159
+ */
160
+ const EXT_LIST = [
161
+ // 文档类
162
+ 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf', 'txt', 'rtf', 'odt',
163
+
164
+ // 数据/开发
165
+ 'json', 'xml', 'csv', 'yaml', 'yml',
166
+
167
+ // 前端/文本
168
+ 'html', 'htm', 'md', 'markdown', 'css', 'js', 'ts',
169
+
170
+ // 图片
171
+ 'png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp', 'svg', 'ico', 'tiff',
172
+
173
+ // 音频
174
+ 'mp3', 'wav', 'ogg', 'aac', 'flac', 'm4a',
175
+
176
+ // 视频
177
+ 'mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'webm',
178
+
179
+ // 压缩包
180
+ 'zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz',
181
+
182
+ // 可执行/程序
183
+ 'exe', 'dmg', 'pkg', 'apk', 'ipa',
184
+
185
+ // 其他常见
186
+ 'log', 'dat', 'bin'
187
+ ];
188
+
189
+ function extractMobookFiles(text = '') {
190
+ if (typeof text !== 'string' || !text.trim()) return [];
191
+
192
+ const result = new Set();
193
+
194
+ // ✅ 扩展名
195
+ const EXT = `(${EXT_LIST.join('|')})`;
196
+
197
+ // ✅ 文件名字符(增强:支持中文、符号)
198
+ const FILE_NAME = `[\\w\\u4e00-\\u9fa5::《》()()\\-\\s]+?`;
199
+
200
+ try {
201
+ // 1️⃣ `xxx.xxx`
202
+ const backtickReg = new RegExp(`\`([^\\\`]+?\\.${EXT})\``, 'gi');
203
+ (text.match(backtickReg) || []).forEach(item => {
204
+ const name = item.replace(/`/g, '').trim();
205
+ if (isValidFileName(name)) {
206
+ result.add(`/mobook/${name}`);
207
+ }
208
+ });
209
+
210
+ // 2️⃣ /mobook/xxx.xxx
211
+ const fullPathReg = new RegExp(`/mobook/${FILE_NAME}\\.${EXT}`, 'gi');
212
+ (text.match(fullPathReg) || []).forEach(p => {
213
+ result.add(normalizePath(p));
214
+ });
215
+
216
+ // 3️⃣ mobook下的 xxx.xxx
217
+ const inlineReg = new RegExp(`mobook下的\\s*(${FILE_NAME}\\.${EXT})`, 'gi');
218
+ (text.match(inlineReg) || []).forEach(item => {
219
+ const match = item.match(new RegExp(`${FILE_NAME}\\.${EXT}`, 'i'));
220
+ if (match && isValidFileName(match[0])) {
221
+ result.add(`/mobook/${match[0].trim()}`);
222
+ }
223
+ });
224
+
225
+ // 🆕 4️⃣ **xxx.xxx**
226
+ const boldReg = new RegExp(`\\*\\*(${FILE_NAME}\\.${EXT})\\*\\*`, 'gi');
227
+ (text.match(boldReg) || []).forEach(item => {
228
+ const name = item.replace(/\*\*/g, '').trim();
229
+ if (isValidFileName(name)) {
230
+ result.add(`/mobook/${name}`);
231
+ }
232
+ });
233
+
234
+ // 🆕 5️⃣ xxx.xxx (123字节)
235
+ const looseReg = new RegExp(`(${FILE_NAME}\\.${EXT})\\s*\\(`, 'gi');
236
+ (text.match(looseReg) || []).forEach(item => {
237
+ const name = item.replace(/\s*\(.+$/, '').trim();
238
+ if (isValidFileName(name)) {
239
+ result.add(`/mobook/${name}`);
240
+ }
241
+ });
242
+
243
+ } catch (e) {
244
+ console.warn('extractMobookFiles error:', e);
245
+ }
246
+
247
+ return [...result];
248
+ }
249
+
250
+ /**
251
+ * 校验文件名是否合法(避免脏数据)
252
+ */
253
+ function isValidFileName(name: string) {
254
+ if (!name) return false;
255
+
256
+ // 过滤异常字符
257
+ if (/[\/\\<>:"|?*]/.test(name)) return false;
258
+
259
+ // 长度限制(防止异常长字符串)
260
+ if (name.length > 200) return false;
261
+
262
+ return true;
263
+ }
264
+
265
+ /**
266
+ * 规范路径(去重用)
267
+ */
268
+ function normalizePath(path: string) {
269
+ return path
270
+ .replace(/\/+/g, '/') // 多斜杠 → 单斜杠
271
+ .replace(/\/$/, ''); // 去掉结尾 /
272
+ }
273
+
155
274
  /**
156
275
  * 处理一条用户消息,调用 Agent 并返回回复
157
276
  */
@@ -197,7 +316,7 @@ export async function handleDcgchatMessage(params: {
197
316
 
198
317
  const route = core.channel.routing.resolveAgentRoute({
199
318
  cfg,
200
- channel: "dcgchat-test",
319
+ channel: "dcgchat",
201
320
  accountId: account.accountId,
202
321
  peer: { kind: "direct", id: userId },
203
322
  });
@@ -234,13 +353,13 @@ export async function handleDcgchatMessage(params: {
234
353
  ChatType: "direct",
235
354
  SenderName: userId,
236
355
  SenderId: userId,
237
- Provider: "dcgchat-test" as const,
238
- Surface: "dcgchat-test" as const,
356
+ Provider: "dcgchat" as const,
357
+ Surface: "dcgchat" as const,
239
358
  MessageSid: msg.content.message_id,
240
359
  Timestamp: Date.now(),
241
360
  WasMentioned: true,
242
361
  CommandAuthorized: true,
243
- OriginatingChannel: "dcgchat-test" as const,
362
+ OriginatingChannel: "dcgchat" as const,
244
363
  OriginatingTo: `user:${userId}`,
245
364
  ...mediaPayload,
246
365
  });
@@ -369,6 +488,33 @@ export async function handleDcgchatMessage(params: {
369
488
  }
370
489
  log(`dcgchat[${accountId}][deliver]: sent ${completeFiles.length} media file(s) through channel adapter`);
371
490
  }
491
+ const mobookFiles = extractMobookFiles(completeText)
492
+ if (mobookFiles.length > 0) {
493
+ for (let i = 0; i < mobookFiles.length; i++) {
494
+ let url = mobookFiles[i] as string
495
+ const key = getMediaKey(url);
496
+ if (sentMediaKeys.has(key)) {
497
+ log(`dcgchat[${accountId}]: mobookFiles already sent, skipping: ${url}`);
498
+ continue;
499
+ }
500
+ if (!fs.existsSync(url)) {
501
+ url = path.join(getWorkspaceDir(), url)
502
+ if (!fs.existsSync(url)) {
503
+ log(`dcgchat[${accountId}]: mobookFiles file not found, skipping: ${url}`);
504
+ continue;
505
+ }
506
+ }
507
+ sentMediaKeys.add(key);
508
+ await sendDcgchatMedia({
509
+ cfg,
510
+ accountId,
511
+ log,
512
+ mediaUrl: url,
513
+ text: "",
514
+ });
515
+ }
516
+ log(`dcgchat[${accountId}][deliver]: sent ${mobookFiles.length} media file(s) through channel adapter`);
517
+ }
372
518
  log(`dcgchat[${accountId}]: dispatch complete, sending final state`);
373
519
  params.onChunk({
374
520
  messageType: "openclaw_bot_chat",
package/src/skill.ts CHANGED
@@ -67,7 +67,14 @@ export async function installSkill(params: ISkillParams, msgContent: Record<stri
67
67
  }
68
68
 
69
69
  try {
70
- const entryPath = entry.path;
70
+ const flags = entry.props?.flags ?? 0;
71
+ const isUtf8 = (flags & 0x800) !== 0;
72
+ let entryPath: string;
73
+ if (!isUtf8 && entry.props?.pathBuffer) {
74
+ entryPath = new TextDecoder('gbk').decode(entry.props.pathBuffer);
75
+ } else {
76
+ entryPath = entry.path;
77
+ }
71
78
  const pathParts = entryPath.split("/");
72
79
 
73
80
  // 检测根目录