@licity/qclaw-local-connector 1.3.0 → 1.3.1

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/README.md +35 -13
  2. package/index.js +52 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -16,36 +16,50 @@
16
16
 
17
17
  ### 方式一:npm 全局安装(推荐)
18
18
 
19
- **第一步:安装前提**
19
+ **第一步:安装 Node.js**
20
20
 
21
- 需要先安装 Node.js(访问 [nodejs.org](https://nodejs.org) 免费下载,安装完默认自带 npm 命令)。
21
+ 没有 Node.js 的需要先安装它(npm 命令附带在 Node.js 里)。
22
+
23
+ 1. 打开浏览器,访问 [nodejs.org](https://nodejs.org)
24
+ 2. 点击显示"LTS"的大按钮下载安装包(Windows 下载 `.msi` 文件)
25
+ 3. 下载完成后双击运行,一直点"Next"直到安装完成,保持所有默认选项
26
+ 4. 安装完后打开终端(见下一步),输入 `node -v`,能看到版本号说明安装成功
27
+
28
+ **如何打开终端:**
29
+ - **Windows 11/10**:按 `Win + X`,选择"终端"或"PowerShell";或按 `Win + R`,输入 `cmd` 回车
30
+ - **macOS**:按 `Cmd + 空格`,搜索"Terminal"打开
31
+ - **或者**:在文件夹空白处右键,选择"在此处打开终端"/"在终端中打开"
22
32
 
23
33
  **第二步:全局安装连接器**
24
34
 
35
+ 在终端里输入以下命令并回车:
36
+
25
37
  ```bash
26
38
  npm install -g @licity/qclaw-local-connector
27
39
  ```
28
40
 
29
- 看到 `added X packages` 即安装成功。
41
+ 等待安装完成,看到 `added X packages` 字样即成功。安装过程中出现 `WARN` 字样是正常的,不影响使用。
30
42
 
31
43
  **第三步:创建工作目录**
32
44
 
33
- 在电脑上选一个记得住的文件夹作为工作目录,例如在桌面新建一个 `licity` 文件夹。
45
+ 在电脑上选一个记得住的文件夹作为工作目录。例如在桌面新建一个 `licity` 文件夹。
34
46
 
35
- > ⚠️ **重要**:不要在 npm 全局安装目录(`node_modules/@licity/qclaw-local-connector`)里直接运行。请始终在你自己建的工作目录里运行。
47
+ > ⚠️ **重要**:不要在 npm 全局安装目录里直接运行(路径包含 `node_modules/@licity`)。请始终在你自己建的工作目录里运行。
36
48
 
37
- **第四步:创建 `.env` 配置文件**
49
+ **第四步:初次运行,自动生成 `.env` 配置文件**
38
50
 
39
- 在工作目录中创建名为 `.env` 的文本文件(见下方第 4 步的详细说明),填写必要字段。
40
-
41
- **第五步:启动连接器**
42
-
43
- 在工作目录里右键"在此处打开终端",然后执行:
51
+ 在工作目录(例如桌面的 `licity` 文件夹)里右键 在此处打开终端,然后运行:
44
52
 
45
53
  ```bash
46
54
  licity-connector
47
55
  ```
48
56
 
57
+ **如果是第一次运行且当前目录没有 `.env` 文件,连接器会自动在当前目录生成一个 `.env` 模板文件,然后退出并提示你填写。**
58
+
59
+ 用文本编辑器打开自动生成的 `.env` 文件,按第 4 步说明填写必填项,保存后重新运行 `licity-connector` 即可。
60
+
61
+ 不需要手动创建 `.env` 文件 — 第一次运行会帮你生成。
62
+
49
63
  ### 方式二:本地克隆 / 下载后运行
50
64
 
51
65
  进入连接器目录,执行:
@@ -162,9 +176,17 @@ npm install && npm run quickstart
162
176
 
163
177
  ### 第 4 步:第一次启动时补全 `.env`
164
178
 
165
- 在工作目录(你自己建的那个 `licity` 文件夹)里新建一个名为 `.env` 的文本文件(没有任何后缀)。
179
+ **方式一(npm 全局安装)用户:**
180
+
181
+ 不需要手动创建 `.env` 文件。第一次在工作目录运行 `licity-connector` 时,如果目录里没有 `.env`,程序会**自动生成**一份模板并退出,提示你填写。
182
+
183
+ 然后用记事本或任何文本编辑器打开生成的 `.env` 文件,按下面说明填写必填项,保存后重新运行 `licity-connector`。
184
+
185
+ **方式二(本地克隆/下载)用户:**
186
+
187
+ 首次运行 `npm run quickstart` 时,安装助手会自动从 `.env.example` 生成一份 `.env` 模板,直接编辑那个文件即可。
166
188
 
167
- > 如果你用的是"方式二"本地克隆,首次运行 `npm run quickstart` 会自动从 `.env.example` 生成一份 `.env` 模板,直接编辑那个就好。
189
+ ---
168
190
 
169
191
  `.env` 文件的完整示例如下。复制粘贴后,按 **【必填/可选/勿改】** 说明逐行确认:
170
192
 
package/index.js CHANGED
@@ -449,7 +449,53 @@ function extractAgentMedia(result) {
449
449
  return null;
450
450
  }
451
451
 
452
- function parseAgentSuccess(rawStdout) {
452
+ // AI 回复文本中提取本地文件路径,当 agent 没有结构化附件输出时作为兜底
453
+ function extractLocalFileFromReply(replyText) {
454
+ if (!replyText) return null;
455
+
456
+ // 匹配 Windows 绝对路径(含中文路径)和 Unix 绝对路径
457
+ const patterns = [
458
+ // Windows: C:\path\file.ext 或 C:/path/file.ext(包含中文字符和空格)
459
+ /[A-Za-z]:[\\\/][^\s`'",。!?\]]{3,260}\.[a-zA-Z0-9]{1,10}/g,
460
+ // Unix: /Users/path/file.ext
461
+ /(?:\/(?:[^\s`'",。!?\]]+\/)+[^\s`'",。!?\]]+\.[a-zA-Z0-9]{1,10})/g,
462
+ ];
463
+
464
+ const candidates = [];
465
+ for (const pattern of patterns) {
466
+ const matches = replyText.matchAll(pattern);
467
+ for (const m of matches) {
468
+ // 去掉首尾的引号、反引号
469
+ const candidate = m[0].trim().replace(/^[`'"【]|[`'"】,,。!?]$/g, '');
470
+ if (candidate.length > 3) candidates.push(candidate);
471
+ }
472
+ }
473
+
474
+ // 按文件大小筛选:必须存在且 ≤ maxEmbeddedMediaBytes
475
+ for (const filePath of candidates) {
476
+ try {
477
+ if (!fs.existsSync(filePath)) continue;
478
+ const stat = fs.statSync(filePath);
479
+ if (stat.size === 0 || stat.size > maxEmbeddedMediaBytes) continue;
480
+ const fileName = path.basename(filePath);
481
+ const mimeType = guessMimeTypeFromPath(filePath);
482
+ const mediaType = normalizeMediaType(null, mimeType, fileName);
483
+ console.log(`[Task] 检测到本地文件,自动附加: ${fileName} (${Math.round(stat.size / 1024)}KB)`);
484
+ return {
485
+ media_base64: fs.readFileSync(filePath).toString('base64'),
486
+ media_type: mediaType,
487
+ media_mime_type: mimeType,
488
+ media_name: fileName,
489
+ };
490
+ } catch (_) {
491
+ // 忽略单个文件处理错误,继续检查下一个
492
+ }
493
+ }
494
+
495
+ return null;
496
+ }
497
+
498
+
453
499
  const parsed = extractLastJsonObject(rawStdout);
454
500
  if (!parsed) {
455
501
  return null;
@@ -843,6 +889,11 @@ async function handleTask(task) {
843
889
  model: agentResult.raw?.result?.meta?.agentMeta?.model || null,
844
890
  action: 'openclaw_agent_reply',
845
891
  };
892
+ // 如果 agent 没有结构化附件,尝试从回复文本中提取本地文件路径
893
+ if (!agentResult.media && agentResult.reply) {
894
+ const detectedMedia = extractLocalFileFromReply(agentResult.reply);
895
+ if (detectedMedia) agentResult.media = detectedMedia;
896
+ }
846
897
  if (agentResult.media) {
847
898
  taskResult.mediaType = agentResult.media.media_type;
848
899
  taskResult.mediaName = agentResult.media.media_name;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@licity/qclaw-local-connector",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "里世界龙虾本地连接器 — 把 QClaw 或其他第三方本地 Runtime 接入里世界 APP",
5
5
  "main": "index.js",
6
6
  "bin": {