@zqagent/core 0.2.16 → 0.3.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.
Files changed (238) hide show
  1. package/README.md +1 -1
  2. package/README.oss.en.md +15 -2
  3. package/README.oss.md +18 -2
  4. package/README.oss.zh-TW.md +13 -2
  5. package/dist/McpClient-CEQBUPuC.d.cts +145 -0
  6. package/dist/McpClient-CEQBUPuC.d.ts +145 -0
  7. package/dist/{ToolRegistry-C3pTFiaJ.d.cts → ToolRegistry-Cy0fQxrb.d.ts} +2 -111
  8. package/dist/{ToolRegistry-C3pTFiaJ.d.ts → ToolRegistry-DouDvn9E.d.cts} +2 -111
  9. package/dist/{explore-RtZtb-V6.d.ts → TurnEngine-BPKhWuSI.d.cts} +108 -73
  10. package/dist/{explore-BgRhj6SP.d.cts → TurnEngine-DtGEuVLT.d.ts} +108 -73
  11. package/dist/conflictGuard-BBOOIxxK.d.cts +42 -0
  12. package/dist/conflictGuard-BBOOIxxK.d.ts +42 -0
  13. package/dist/index.cjs +5477 -1140
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.cts +577 -195
  16. package/dist/index.d.ts +577 -195
  17. package/dist/index.js +5305 -1002
  18. package/dist/index.js.map +1 -1
  19. package/dist/internal/crypto/secrets.cjs +25 -0
  20. package/dist/internal/crypto/secrets.cjs.map +1 -0
  21. package/dist/internal/crypto/secrets.d.cts +2 -0
  22. package/dist/internal/crypto/secrets.d.ts +2 -0
  23. package/dist/internal/crypto/secrets.js +3 -0
  24. package/dist/internal/crypto/secrets.js.map +1 -0
  25. package/dist/internal/engine/FileLogHook.cjs +179 -0
  26. package/dist/internal/engine/FileLogHook.cjs.map +1 -0
  27. package/dist/internal/engine/FileLogHook.d.cts +67 -0
  28. package/dist/internal/engine/FileLogHook.d.ts +67 -0
  29. package/dist/internal/engine/FileLogHook.js +144 -0
  30. package/dist/internal/engine/FileLogHook.js.map +1 -0
  31. package/dist/internal/engine/approvalView.cjs +25 -0
  32. package/dist/internal/engine/approvalView.cjs.map +1 -0
  33. package/dist/internal/engine/approvalView.d.cts +1 -0
  34. package/dist/internal/engine/approvalView.d.ts +1 -0
  35. package/dist/internal/engine/approvalView.js +3 -0
  36. package/dist/internal/engine/approvalView.js.map +1 -0
  37. package/dist/internal/engine/limits.cjs +59 -0
  38. package/dist/internal/engine/limits.cjs.map +1 -0
  39. package/dist/internal/engine/limits.d.cts +32 -0
  40. package/dist/internal/engine/limits.d.ts +32 -0
  41. package/dist/internal/engine/limits.js +31 -0
  42. package/dist/internal/engine/limits.js.map +1 -0
  43. package/dist/internal/engine/sessionNaming.cjs +47 -0
  44. package/dist/internal/engine/sessionNaming.cjs.map +1 -0
  45. package/dist/internal/engine/sessionNaming.d.cts +25 -0
  46. package/dist/internal/engine/sessionNaming.d.ts +25 -0
  47. package/dist/internal/engine/sessionNaming.js +20 -0
  48. package/dist/internal/engine/sessionNaming.js.map +1 -0
  49. package/dist/internal/llmConfig.cjs +561 -0
  50. package/dist/internal/llmConfig.cjs.map +1 -0
  51. package/dist/internal/llmConfig.d.cts +75 -0
  52. package/dist/internal/llmConfig.d.ts +75 -0
  53. package/dist/internal/llmConfig.js +535 -0
  54. package/dist/internal/llmConfig.js.map +1 -0
  55. package/dist/internal/mcp/builtin/index.cjs +685 -0
  56. package/dist/internal/mcp/builtin/index.cjs.map +1 -0
  57. package/dist/internal/mcp/builtin/index.d.cts +21 -0
  58. package/dist/internal/mcp/builtin/index.d.ts +21 -0
  59. package/dist/internal/mcp/builtin/index.js +652 -0
  60. package/dist/internal/mcp/builtin/index.js.map +1 -0
  61. package/dist/internal/mcp/config.cjs +278 -0
  62. package/dist/internal/mcp/config.cjs.map +1 -0
  63. package/dist/internal/mcp/config.d.cts +61 -0
  64. package/dist/internal/mcp/config.d.ts +61 -0
  65. package/dist/internal/mcp/config.js +235 -0
  66. package/dist/internal/mcp/config.js.map +1 -0
  67. package/dist/internal/mcp/presets.cjs +184 -0
  68. package/dist/internal/mcp/presets.cjs.map +1 -0
  69. package/dist/internal/mcp/presets.d.cts +39 -0
  70. package/dist/internal/mcp/presets.d.ts +39 -0
  71. package/dist/internal/mcp/presets.js +158 -0
  72. package/dist/internal/mcp/presets.js.map +1 -0
  73. package/dist/internal/node-name.cjs +45 -0
  74. package/dist/internal/node-name.cjs.map +1 -0
  75. package/dist/internal/node-name.d.cts +3 -0
  76. package/dist/internal/node-name.d.ts +3 -0
  77. package/dist/internal/node-name.js +10 -0
  78. package/dist/internal/node-name.js.map +1 -0
  79. package/dist/internal/paths.cjs +63 -0
  80. package/dist/internal/paths.cjs.map +1 -0
  81. package/dist/internal/paths.d.cts +17 -0
  82. package/dist/internal/paths.d.ts +17 -0
  83. package/dist/internal/paths.js +25 -0
  84. package/dist/internal/paths.js.map +1 -0
  85. package/dist/internal/providers/diagnostics.cjs +288 -0
  86. package/dist/internal/providers/diagnostics.cjs.map +1 -0
  87. package/dist/internal/providers/diagnostics.d.cts +103 -0
  88. package/dist/internal/providers/diagnostics.d.ts +103 -0
  89. package/dist/internal/providers/diagnostics.js +250 -0
  90. package/dist/internal/providers/diagnostics.js.map +1 -0
  91. package/dist/internal/providers/models.cjs +699 -0
  92. package/dist/internal/providers/models.cjs.map +1 -0
  93. package/dist/internal/providers/models.d.cts +136 -0
  94. package/dist/internal/providers/models.d.ts +136 -0
  95. package/dist/internal/providers/models.js +654 -0
  96. package/dist/internal/providers/models.js.map +1 -0
  97. package/dist/internal/terminal.cjs +161 -0
  98. package/dist/internal/terminal.cjs.map +1 -0
  99. package/dist/internal/terminal.d.cts +58 -0
  100. package/dist/internal/terminal.d.ts +58 -0
  101. package/dist/internal/terminal.js +128 -0
  102. package/dist/internal/terminal.js.map +1 -0
  103. package/dist/internal/tools/execAsync.cjs +187 -0
  104. package/dist/internal/tools/execAsync.cjs.map +1 -0
  105. package/dist/internal/tools/execAsync.d.cts +30 -0
  106. package/dist/internal/tools/execAsync.d.ts +30 -0
  107. package/dist/internal/tools/execAsync.js +162 -0
  108. package/dist/internal/tools/execAsync.js.map +1 -0
  109. package/dist/internal/tools/git.cjs +935 -0
  110. package/dist/internal/tools/git.cjs.map +1 -0
  111. package/dist/internal/tools/git.d.cts +206 -0
  112. package/dist/internal/tools/git.d.ts +206 -0
  113. package/dist/internal/tools/git.js +883 -0
  114. package/dist/internal/tools/git.js.map +1 -0
  115. package/dist/internal/tools/pathSafety.cjs +99 -0
  116. package/dist/internal/tools/pathSafety.cjs.map +1 -0
  117. package/dist/internal/tools/pathSafety.d.cts +44 -0
  118. package/dist/internal/tools/pathSafety.d.ts +44 -0
  119. package/dist/internal/tools/pathSafety.js +61 -0
  120. package/dist/internal/tools/pathSafety.js.map +1 -0
  121. package/dist/internal/tools/plan.cjs +146 -0
  122. package/dist/internal/tools/plan.cjs.map +1 -0
  123. package/dist/internal/tools/plan.d.cts +48 -0
  124. package/dist/internal/tools/plan.d.ts +48 -0
  125. package/dist/internal/tools/plan.js +117 -0
  126. package/dist/internal/tools/plan.js.map +1 -0
  127. package/dist/internal/tools/ripgrep.cjs +118 -0
  128. package/dist/internal/tools/ripgrep.cjs.map +1 -0
  129. package/dist/internal/tools/ripgrep.d.cts +6 -0
  130. package/dist/internal/tools/ripgrep.d.ts +6 -0
  131. package/dist/internal/tools/ripgrep.js +89 -0
  132. package/dist/internal/tools/ripgrep.js.map +1 -0
  133. package/dist/internal/tools/sandbox.cjs +253 -0
  134. package/dist/internal/tools/sandbox.cjs.map +1 -0
  135. package/dist/internal/tools/sandbox.d.cts +67 -0
  136. package/dist/internal/tools/sandbox.d.ts +67 -0
  137. package/dist/internal/tools/sandbox.js +213 -0
  138. package/dist/internal/tools/sandbox.js.map +1 -0
  139. package/dist/internal/tools/shell.cjs +771 -0
  140. package/dist/internal/tools/shell.cjs.map +1 -0
  141. package/dist/internal/tools/shell.d.cts +47 -0
  142. package/dist/internal/tools/shell.d.ts +47 -0
  143. package/dist/internal/tools/shell.js +731 -0
  144. package/dist/internal/tools/shell.js.map +1 -0
  145. package/dist/internal/tools/shellRuntime.cjs +220 -0
  146. package/dist/internal/tools/shellRuntime.cjs.map +1 -0
  147. package/dist/internal/tools/shellRuntime.d.cts +67 -0
  148. package/dist/internal/tools/shellRuntime.d.ts +67 -0
  149. package/dist/internal/tools/shellRuntime.js +181 -0
  150. package/dist/internal/tools/shellRuntime.js.map +1 -0
  151. package/dist/internal/update/controller.cjs +1035 -0
  152. package/dist/internal/update/controller.cjs.map +1 -0
  153. package/dist/internal/update/controller.d.cts +150 -0
  154. package/dist/internal/update/controller.d.ts +150 -0
  155. package/dist/internal/update/controller.js +991 -0
  156. package/dist/internal/update/controller.js.map +1 -0
  157. package/dist/internal/update/platform.cjs +234 -0
  158. package/dist/internal/update/platform.cjs.map +1 -0
  159. package/dist/internal/update/platform.d.cts +77 -0
  160. package/dist/internal/update/platform.d.ts +77 -0
  161. package/dist/internal/update/platform.js +184 -0
  162. package/dist/internal/update/platform.js.map +1 -0
  163. package/dist/tools/ask.d.cts +3 -1
  164. package/dist/tools/ask.d.ts +3 -1
  165. package/dist/tools/diff.cjs +17 -6
  166. package/dist/tools/diff.cjs.map +1 -1
  167. package/dist/tools/diff.d.cts +5 -2
  168. package/dist/tools/diff.d.ts +5 -2
  169. package/dist/tools/diff.js +17 -6
  170. package/dist/tools/diff.js.map +1 -1
  171. package/dist/tools/directories.d.cts +3 -1
  172. package/dist/tools/directories.d.ts +3 -1
  173. package/dist/tools/explore.cjs +1778 -204
  174. package/dist/tools/explore.cjs.map +1 -1
  175. package/dist/tools/explore.d.cts +82 -2
  176. package/dist/tools/explore.d.ts +82 -2
  177. package/dist/tools/explore.js +1780 -204
  178. package/dist/tools/explore.js.map +1 -1
  179. package/dist/tools/files.cjs +56 -21
  180. package/dist/tools/files.cjs.map +1 -1
  181. package/dist/tools/files.d.cts +6 -3
  182. package/dist/tools/files.d.ts +6 -3
  183. package/dist/tools/files.js +56 -21
  184. package/dist/tools/files.js.map +1 -1
  185. package/dist/tools/git.cjs +34 -25
  186. package/dist/tools/git.cjs.map +1 -1
  187. package/dist/tools/git.d.cts +4 -204
  188. package/dist/tools/git.d.ts +4 -204
  189. package/dist/tools/git.js +34 -25
  190. package/dist/tools/git.js.map +1 -1
  191. package/dist/tools/media.cjs +280 -3
  192. package/dist/tools/media.cjs.map +1 -1
  193. package/dist/tools/media.d.cts +3 -1
  194. package/dist/tools/media.d.ts +3 -1
  195. package/dist/tools/media.js +278 -1
  196. package/dist/tools/media.js.map +1 -1
  197. package/dist/tools/plan.cjs +62 -0
  198. package/dist/tools/plan.cjs.map +1 -1
  199. package/dist/tools/plan.d.cts +4 -17
  200. package/dist/tools/plan.d.ts +4 -17
  201. package/dist/tools/plan.js +59 -0
  202. package/dist/tools/plan.js.map +1 -1
  203. package/dist/tools/search.cjs +3 -0
  204. package/dist/tools/search.cjs.map +1 -1
  205. package/dist/tools/search.d.cts +3 -1
  206. package/dist/tools/search.d.ts +3 -1
  207. package/dist/tools/search.js +3 -0
  208. package/dist/tools/search.js.map +1 -1
  209. package/dist/tools/shell.cjs +76 -11
  210. package/dist/tools/shell.cjs.map +1 -1
  211. package/dist/tools/shell.d.cts +5 -39
  212. package/dist/tools/shell.d.ts +5 -39
  213. package/dist/tools/shell.js +75 -11
  214. package/dist/tools/shell.js.map +1 -1
  215. package/dist/tools/todo.d.cts +3 -1
  216. package/dist/tools/todo.d.ts +3 -1
  217. package/dist/tools/web.cjs +279 -5
  218. package/dist/tools/web.cjs.map +1 -1
  219. package/dist/tools/web.d.cts +3 -1
  220. package/dist/tools/web.d.ts +3 -1
  221. package/dist/tools/web.js +275 -3
  222. package/dist/tools/web.js.map +1 -1
  223. package/dist/types-BYyXWWPW.d.cts +237 -0
  224. package/dist/types-BYyXWWPW.d.ts +237 -0
  225. package/package.json +26 -37
  226. package/bin/zqagent +0 -2
  227. package/dist/cli/index.cjs +0 -24507
  228. package/dist/cli/index.cjs.map +0 -1
  229. package/dist/cli/index.d.cts +0 -2
  230. package/dist/cli/index.d.ts +0 -2
  231. package/dist/cli/index.js +0 -24490
  232. package/dist/cli/index.js.map +0 -1
  233. package/dist/server/index.cjs +0 -19824
  234. package/dist/server/index.cjs.map +0 -1
  235. package/dist/server/index.d.cts +0 -2
  236. package/dist/server/index.d.ts +0 -2
  237. package/dist/server/index.js +0 -19807
  238. package/dist/server/index.js.map +0 -1
@@ -0,0 +1,652 @@
1
+ // src/mcp/builtin/index.ts
2
+ import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
3
+
4
+ // src/mcp/builtin/ocr.ts
5
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
6
+ import {
7
+ CallToolRequestSchema,
8
+ ListToolsRequestSchema
9
+ } from "@modelcontextprotocol/sdk/types.js";
10
+
11
+ // src/mcp/builtin/ocrEngine.ts
12
+ import fs from "fs";
13
+ import os from "os";
14
+ import path2 from "path";
15
+ import { execFile } from "child_process";
16
+ import OpenAI from "openai";
17
+
18
+ // src/tools/shellRuntime.ts
19
+ import * as path from "path";
20
+ var WINDOWS_SUFFIXES = [".exe", ".cmd", ".bat", ".com", ""];
21
+ function pathApi(platform) {
22
+ return platform === "win32" ? path.win32 : path.posix;
23
+ }
24
+ function joinPath(platform, ...parts) {
25
+ return pathApi(platform).join(...parts);
26
+ }
27
+ function findExecutable(name, ctx) {
28
+ if (name.includes("/") || name.includes("\\")) {
29
+ return ctx.fileExists(name) ? name : null;
30
+ }
31
+ const suffixes = ctx.platform === "win32" ? WINDOWS_SUFFIXES : [""];
32
+ const delimiter = ctx.platform === "win32" ? ";" : ":";
33
+ const dirs = (ctx.env.PATH ?? "").split(delimiter).filter((d) => d.length > 0);
34
+ for (const dir of dirs) {
35
+ for (const suffix of suffixes) {
36
+ const candidate = joinPath(ctx.platform, dir, name + suffix);
37
+ if (ctx.fileExists(candidate)) return candidate;
38
+ }
39
+ }
40
+ return null;
41
+ }
42
+
43
+ // src/mcp/builtin/ocrEngine.ts
44
+ var DEFAULT_MAX_PAGES = 5;
45
+ var MAX_MAX_PAGES = 50;
46
+ var DEFAULT_DPI = 150;
47
+ var MAX_DPI = 400;
48
+ var CMD_TIMEOUT_MS = 12e4;
49
+ var COMPILE_TIMEOUT_MS = 18e4;
50
+ var MAX_BUFFER = 32 * 1024 * 1024;
51
+ var VISION_SOURCE = `import Foundation
52
+ import Vision
53
+ import AppKit
54
+ import PDFKit
55
+ import CoreGraphics
56
+
57
+ struct PageResult: Codable { let page: Int; let text: String }
58
+ struct Output: Codable { let pages: [PageResult] }
59
+
60
+ func recognize(_ image: CGImage) -> String {
61
+ func run(_ langs: [String]?) throws -> [VNRecognizedTextObservation] {
62
+ let request = VNRecognizeTextRequest()
63
+ request.recognitionLevel = .accurate
64
+ request.usesLanguageCorrection = true
65
+ if let langs = langs { request.recognitionLanguages = langs }
66
+ let handler = VNImageRequestHandler(cgImage: image, options: [:])
67
+ try handler.perform([request])
68
+ return request.results ?? []
69
+ }
70
+ let observations = (try? run(["zh-Hans", "zh-Hant", "en-US"])) ?? (try? run(nil)) ?? []
71
+ let lines = observations.compactMap { $0.topCandidates(1).first?.string }
72
+ return lines.joined(separator: "\\n")
73
+ }
74
+
75
+ func imageFromFile(_ p: String) -> CGImage? {
76
+ guard let src = CGImageSourceCreateWithURL(URL(fileURLWithPath: p) as CFURL, nil) else { return nil }
77
+ return CGImageSourceCreateImageAtIndex(src, 0, nil)
78
+ }
79
+
80
+ let args = CommandLine.arguments
81
+ guard args.count >= 2 else {
82
+ FileHandle.standardError.write("usage: ocr-vision <file> [maxPages] [dpi]\\n".data(using: .utf8)!)
83
+ exit(2)
84
+ }
85
+ let file = args[1]
86
+ let maxPages = args.count > 2 ? (Int(args[2]) ?? 5) : 5
87
+ let dpi = args.count > 3 ? (Int(args[3]) ?? 150) : 150
88
+
89
+ var pages: [PageResult] = []
90
+ if file.lowercased().hasSuffix(".pdf"), let doc = PDFDocument(url: URL(fileURLWithPath: file)) {
91
+ let count = min(doc.pageCount, max(1, maxPages))
92
+ let scale = CGFloat(dpi) / 72.0
93
+ for i in 0..<count {
94
+ guard let page = doc.page(at: i) else { continue }
95
+ let bounds = page.bounds(for: .mediaBox)
96
+ let w = Int(bounds.width * scale)
97
+ let h = Int(bounds.height * scale)
98
+ guard w > 0, h > 0 else { continue }
99
+ guard let ctx = CGContext(
100
+ data: nil, width: w, height: h, bitsPerComponent: 8, bytesPerRow: 0,
101
+ space: CGColorSpaceCreateDeviceRGB(),
102
+ bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue
103
+ ) else { continue }
104
+ ctx.setFillColor(CGColor(red: 1, green: 1, blue: 1, alpha: 1))
105
+ ctx.fill(CGRect(x: 0, y: 0, width: w, height: h))
106
+ ctx.scaleBy(x: scale, y: scale)
107
+ page.draw(with: .mediaBox, to: ctx)
108
+ guard let image = ctx.makeImage() else { continue }
109
+ pages.append(PageResult(page: i + 1, text: recognize(image)))
110
+ }
111
+ } else if let image = imageFromFile(file) {
112
+ pages.append(PageResult(page: 1, text: recognize(image)))
113
+ } else {
114
+ FileHandle.standardError.write("unsupported or unreadable image: \\(file)\\n".data(using: .utf8)!)
115
+ exit(3)
116
+ }
117
+
118
+ let encoder = JSONEncoder()
119
+ encoder.outputFormatting = [.withoutEscapingSlashes]
120
+ if let data = try? encoder.encode(Output(pages: pages)) {
121
+ FileHandle.standardOutput.write(data)
122
+ } else {
123
+ exit(4)
124
+ }
125
+ `;
126
+ function defaultRun(command, args, opts = {}) {
127
+ return new Promise((resolve, reject) => {
128
+ execFile(
129
+ command,
130
+ args,
131
+ {
132
+ timeout: opts.timeoutMs ?? CMD_TIMEOUT_MS,
133
+ cwd: opts.cwd,
134
+ maxBuffer: MAX_BUFFER,
135
+ encoding: "utf8"
136
+ },
137
+ (err, stdout, stderr) => {
138
+ if (err) {
139
+ const e = err;
140
+ e.message = `${path2.basename(command)} \u6267\u884C\u5931\u8D25: ${e.message}${stderr ? `
141
+ ${stderr.trim()}` : ""}`;
142
+ reject(e);
143
+ } else {
144
+ resolve({ stdout, stderr });
145
+ }
146
+ }
147
+ );
148
+ });
149
+ }
150
+ function makeRuntime(ctx) {
151
+ const overrides = ctx.ocr ?? {};
152
+ const platform = overrides.platform ?? process.platform;
153
+ const env = overrides.env ?? ctx.env ?? process.env;
154
+ const workspace = ctx.workspace ?? env.WORKSPACE ?? process.cwd();
155
+ const fileExists = overrides.fileExists ?? ((p) => {
156
+ try {
157
+ return fs.statSync(p).isFile();
158
+ } catch {
159
+ return false;
160
+ }
161
+ });
162
+ const which = overrides.which ?? ((name) => findExecutable(name, { platform, env, fileExists }));
163
+ return {
164
+ platform,
165
+ env,
166
+ workspace,
167
+ llm: ctx.llm,
168
+ overrides,
169
+ which,
170
+ run: overrides.run ?? defaultRun,
171
+ fileExists
172
+ };
173
+ }
174
+ function clampInt(value, fallback, min, max) {
175
+ const n = typeof value === "number" ? value : Number(value);
176
+ if (!Number.isFinite(n)) return fallback;
177
+ return Math.min(max, Math.max(min, Math.trunc(n)));
178
+ }
179
+ function isPdfFile(file) {
180
+ if (file.toLowerCase().endsWith(".pdf")) return true;
181
+ try {
182
+ const fd = fs.openSync(file, "r");
183
+ try {
184
+ const buf = Buffer.alloc(5);
185
+ const read = fs.readSync(fd, buf, 0, 5, 0);
186
+ return read >= 5 && buf.toString("latin1") === "%PDF-";
187
+ } finally {
188
+ fs.closeSync(fd);
189
+ }
190
+ } catch {
191
+ return false;
192
+ }
193
+ }
194
+ function detectMime(file) {
195
+ try {
196
+ const fd = fs.openSync(file, "r");
197
+ try {
198
+ const buf = Buffer.alloc(12);
199
+ fs.readSync(fd, buf, 0, 12, 0);
200
+ if (buf[0] === 137 && buf[1] === 80) return "image/png";
201
+ if (buf[0] === 255 && buf[1] === 216) return "image/jpeg";
202
+ if (buf.toString("latin1", 0, 4) === "RIFF") return "image/webp";
203
+ if (buf.toString("latin1", 0, 4) === "GIF8") return "image/gif";
204
+ } finally {
205
+ fs.closeSync(fd);
206
+ }
207
+ } catch {
208
+ }
209
+ const ext = path2.extname(file).toLowerCase();
210
+ if (ext === ".jpg" || ext === ".jpeg") return "image/jpeg";
211
+ if (ext === ".webp") return "image/webp";
212
+ if (ext === ".gif") return "image/gif";
213
+ return "image/png";
214
+ }
215
+ function toDataUrl(file) {
216
+ return `data:${detectMime(file)};base64,${fs.readFileSync(file).toString("base64")}`;
217
+ }
218
+ function dataUrlToBuffer(value) {
219
+ const m = /^data:([^;,]+);base64,([\s\S]*)$/.exec(value.trim());
220
+ const mime = m?.[1] ?? "image/png";
221
+ const b64 = m?.[2] ?? value.trim();
222
+ const ext = mime === "image/jpeg" ? ".jpg" : mime === "image/webp" ? ".webp" : mime === "image/gif" ? ".gif" : mime === "application/pdf" ? ".pdf" : ".png";
223
+ return { buffer: Buffer.from(b64, "base64"), ext };
224
+ }
225
+ function naturalCompare(a, b) {
226
+ return a.localeCompare(b, void 0, { numeric: true });
227
+ }
228
+ async function downloadToFile(url, dest, runtime) {
229
+ const fetchImpl = runtime.overrides.fetchImpl ?? globalThis.fetch;
230
+ if (!fetchImpl) throw new Error("\u5F53\u524D\u8FD0\u884C\u65F6\u4E0D\u652F\u6301 fetch\uFF0C\u65E0\u6CD5\u4E0B\u8F7D imageUrl");
231
+ const res = await fetchImpl(url);
232
+ if (!res.ok) throw new Error(`\u4E0B\u8F7D\u56FE\u7247\u5931\u8D25\uFF1AHTTP ${res.status}`);
233
+ fs.writeFileSync(dest, Buffer.from(await res.arrayBuffer()));
234
+ }
235
+ async function materializeInput(input, runtime) {
236
+ const root = runtime.overrides.tmpDir ?? os.tmpdir();
237
+ const tmpDir = fs.mkdtempSync(path2.join(root, "zqagent-ocr-"));
238
+ const cleanup = () => {
239
+ try {
240
+ fs.rmSync(tmpDir, { recursive: true, force: true });
241
+ } catch {
242
+ }
243
+ };
244
+ try {
245
+ if (typeof input.imagePath === "string" && input.imagePath.trim()) {
246
+ const file = path2.isAbsolute(input.imagePath) ? input.imagePath : path2.resolve(runtime.workspace, input.imagePath);
247
+ if (!runtime.fileExists(file) && !fs.existsSync(file))
248
+ throw new Error(`\u56FE\u7247\u4E0D\u5B58\u5728\uFF1A${file}`);
249
+ return { file, isPdf: isPdfFile(file), tmpDir, cleanup };
250
+ }
251
+ if (typeof input.imageBase64 === "string" && input.imageBase64.trim()) {
252
+ const { buffer, ext } = dataUrlToBuffer(input.imageBase64);
253
+ const file = path2.join(tmpDir, `input${ext}`);
254
+ fs.writeFileSync(file, buffer);
255
+ return { file, isPdf: isPdfFile(file), tmpDir, cleanup };
256
+ }
257
+ if (typeof input.imageUrl === "string" && input.imageUrl.trim()) {
258
+ const url = input.imageUrl.trim();
259
+ const ext = path2.extname(new URL(url).pathname).toLowerCase() || ".png";
260
+ const file = path2.join(tmpDir, `input${ext}`);
261
+ await downloadToFile(url, file, runtime);
262
+ return { file, isPdf: isPdfFile(file), tmpDir, cleanup };
263
+ }
264
+ throw new Error("\u7F3A\u5C11\u8F93\u5165\uFF1A\u8BF7\u63D0\u4F9B imagePath / imageBase64 / imageUrl \u4E4B\u4E00");
265
+ } catch (err) {
266
+ cleanup();
267
+ throw err;
268
+ }
269
+ }
270
+ async function pdfToImages(file, tmpDir, input, runtime) {
271
+ const pdftoppm = runtime.which("pdftoppm");
272
+ if (!pdftoppm) {
273
+ throw new Error(
274
+ "PDF \u9700\u8981 poppler \u7684 pdftoppm\uFF08macOS \u53EF\u4F7F\u7528\u5185\u7F6E Vision \u5F15\u64CE\uFF0C\u65E0\u9700\u8BE5\u4F9D\u8D56\uFF09"
275
+ );
276
+ }
277
+ const pagesDir = path2.join(tmpDir, "pages");
278
+ fs.mkdirSync(pagesDir, { recursive: true });
279
+ const maxPages = clampInt(
280
+ input.maxPages,
281
+ DEFAULT_MAX_PAGES,
282
+ 1,
283
+ MAX_MAX_PAGES
284
+ );
285
+ const dpi = clampInt(input.dpi, DEFAULT_DPI, 36, MAX_DPI);
286
+ await runtime.run(
287
+ pdftoppm,
288
+ [
289
+ "-r",
290
+ String(dpi),
291
+ "-png",
292
+ "-f",
293
+ "1",
294
+ "-l",
295
+ String(maxPages),
296
+ file,
297
+ path2.join(pagesDir, "page")
298
+ ],
299
+ { timeoutMs: CMD_TIMEOUT_MS }
300
+ );
301
+ const images = fs.readdirSync(pagesDir).filter((f) => /^page.*\.png$/i.test(f)).sort(naturalCompare).map((f) => path2.join(pagesDir, f));
302
+ if (images.length === 0) throw new Error("PDF \u8F6C\u56FE\u7247\u5931\u8D25\uFF08\u672A\u751F\u6210\u9875\u9762\uFF09");
303
+ return images;
304
+ }
305
+ var visionBuilds = /* @__PURE__ */ new Map();
306
+ function conciseError(err) {
307
+ const lines = err.message.split("\n").map((l) => l.trim()).filter((l) => /error:|fatal error:/i.test(l));
308
+ const pick = lines.length > 0 ? lines[lines.length - 1] : err.message;
309
+ return pick.slice(0, 500);
310
+ }
311
+ async function ensureVisionBinary(runtime) {
312
+ if (runtime.platform !== "darwin")
313
+ return { binary: null, error: "\u4EC5 macOS \u53EF\u7528" };
314
+ const swiftc = runtime.which("swiftc");
315
+ if (!swiftc)
316
+ return {
317
+ binary: null,
318
+ error: "\u672A\u627E\u5230 swiftc\uFF08\u9700\u8981 Xcode Command Line Tools\uFF09"
319
+ };
320
+ const dir = path2.join(runtime.workspace, ".agent", "bin");
321
+ const srcPath = path2.join(dir, "ocr-vision.swift");
322
+ const binPath = path2.join(dir, "ocr-vision");
323
+ const cacheKey = binPath;
324
+ const cached = visionBuilds.get(cacheKey);
325
+ if (cached) return cached;
326
+ const build = (async () => {
327
+ try {
328
+ fs.mkdirSync(dir, { recursive: true });
329
+ let changed = true;
330
+ try {
331
+ changed = fs.readFileSync(srcPath, "utf8") !== VISION_SOURCE;
332
+ } catch {
333
+ changed = true;
334
+ }
335
+ if (changed) fs.writeFileSync(srcPath, VISION_SOURCE, "utf8");
336
+ if (changed || !runtime.fileExists(binPath)) {
337
+ await runtime.run(swiftc, ["-O", "-o", binPath, srcPath], {
338
+ timeoutMs: COMPILE_TIMEOUT_MS
339
+ });
340
+ }
341
+ return runtime.fileExists(binPath) ? { binary: binPath } : { binary: null, error: "Vision \u7F16\u8BD1\u672A\u751F\u6210\u53EF\u6267\u884C\u6587\u4EF6" };
342
+ } catch (err) {
343
+ return { binary: null, error: `Vision \u7F16\u8BD1\u5931\u8D25: ${conciseError(err)}` };
344
+ }
345
+ })();
346
+ visionBuilds.set(cacheKey, build);
347
+ return build;
348
+ }
349
+ async function runVision(binary, file, input, runtime) {
350
+ const maxPages = clampInt(
351
+ input.maxPages,
352
+ DEFAULT_MAX_PAGES,
353
+ 1,
354
+ MAX_MAX_PAGES
355
+ );
356
+ const dpi = clampInt(input.dpi, DEFAULT_DPI, 36, MAX_DPI);
357
+ const { stdout } = await runtime.run(
358
+ binary,
359
+ [file, String(maxPages), String(dpi)],
360
+ { timeoutMs: CMD_TIMEOUT_MS }
361
+ );
362
+ const parsed = JSON.parse(stdout);
363
+ const pages = Array.isArray(parsed.pages) ? parsed.pages : [];
364
+ if (pages.length === 0) throw new Error("Vision \u672A\u8FD4\u56DE\u8BC6\u522B\u7ED3\u679C");
365
+ return pages.map((p) => ({
366
+ page: Number(p.page) || 1,
367
+ text: typeof p.text === "string" ? p.text : ""
368
+ }));
369
+ }
370
+ async function runTesseract(file, isPdf, input, runtime, tmpDir) {
371
+ const tesseract = runtime.which("tesseract");
372
+ if (!tesseract) throw new Error("\u672A\u627E\u5230 tesseract");
373
+ const lang = input.lang ?? runtime.env.OCR_LANG ?? "chi_sim+eng";
374
+ const images = isPdf ? await pdfToImages(file, tmpDir, input, runtime) : [file];
375
+ const pages = [];
376
+ for (let i = 0; i < images.length; i += 1) {
377
+ const { stdout } = await runtime.run(
378
+ tesseract,
379
+ [images[i], "stdout", "-l", lang, "--psm", "3"],
380
+ { timeoutMs: CMD_TIMEOUT_MS }
381
+ );
382
+ pages.push({ page: i + 1, text: stdout.trim() });
383
+ }
384
+ return pages;
385
+ }
386
+ function resolveLlmConfig(runtime) {
387
+ const llm = runtime.llm;
388
+ const apiKey = llm?.apiKey ?? runtime.env.OPENAI_API_KEY ?? runtime.env.OCR_API_KEY ?? "";
389
+ const model = llm?.model ?? runtime.env.OCR_MODEL ?? runtime.env.OPENAI_MODEL ?? "";
390
+ const baseURL = llm?.baseURL ?? runtime.env.OPENAI_BASE_URL ?? runtime.env.OCR_BASE_URL;
391
+ if (!apiKey || !model) return null;
392
+ return { apiKey, model, baseURL };
393
+ }
394
+ async function defaultLlmComplete(req) {
395
+ const client = new OpenAI({
396
+ apiKey: req.apiKey ?? "",
397
+ ...req.baseURL ? { baseURL: req.baseURL } : {}
398
+ });
399
+ const res = await client.chat.completions.create({
400
+ model: req.model,
401
+ messages: [
402
+ {
403
+ role: "user",
404
+ content: [
405
+ { type: "text", text: req.prompt },
406
+ { type: "image_url", image_url: { url: req.imageDataUrl } }
407
+ ]
408
+ }
409
+ ]
410
+ });
411
+ return res.choices?.[0]?.message?.content ?? "";
412
+ }
413
+ async function runLlm(file, isPdf, input, runtime, tmpDir) {
414
+ const cfg = resolveLlmConfig(runtime);
415
+ if (!cfg) {
416
+ throw new Error("\u672A\u914D\u7F6E\u591A\u6A21\u6001\u6A21\u578B\uFF08\u7F3A\u5C11 API key \u6216 model\uFF09");
417
+ }
418
+ const images = isPdf ? await pdfToImages(file, tmpDir, input, runtime) : [file];
419
+ const prompt = "\u8BF7\u9010\u5B57\u63D0\u53D6\u8FD9\u5F20\u56FE\u7247\u4E2D\u7684\u5168\u90E8\u6587\u5B57\uFF0C\u4FDD\u6301\u539F\u6709\u6362\u884C\u4E0E\u987A\u5E8F\u3002\u53EA\u8F93\u51FA\u6587\u5B57\uFF0C\u4E0D\u8981\u89E3\u91CA\u3002";
420
+ const complete = runtime.overrides.llmComplete ?? defaultLlmComplete;
421
+ const pages = [];
422
+ for (let i = 0; i < images.length; i += 1) {
423
+ const text = await complete({
424
+ model: cfg.model,
425
+ prompt,
426
+ imageDataUrl: toDataUrl(images[i]),
427
+ baseURL: cfg.baseURL,
428
+ apiKey: cfg.apiKey
429
+ });
430
+ pages.push({ page: i + 1, text: text.trim() });
431
+ }
432
+ return pages;
433
+ }
434
+ function joinPages(pages) {
435
+ if (pages.length === 1) return pages[0].text;
436
+ return pages.map((p) => `--- page ${p.page} ---
437
+ ${p.text}`).join("\n\n");
438
+ }
439
+ function howToFix(platform) {
440
+ if (platform === "darwin")
441
+ return [
442
+ "macOS \u53EF\u4EFB\u9009\u5176\u4E00\uFF1A",
443
+ "1) \u5B89\u88C5 Xcode Command Line Tools \u4EE5\u542F\u7528\u5185\u7F6E Vision\uFF1Axcode-select --install",
444
+ "2) \u5B89\u88C5 tesseract \u4E0E poppler\uFF1Abrew install tesseract tesseract-lang poppler",
445
+ "3) \u7528 /connect \u914D\u7F6E\u652F\u6301\u56FE\u7247\u8F93\u5165\u7684\u591A\u6A21\u6001\u6A21\u578B\u540E\u91CD\u8BD5"
446
+ ].join("\n");
447
+ if (platform === "win32")
448
+ return [
449
+ "Windows \u53EF\u4EFB\u9009\u5176\u4E00\uFF1A",
450
+ "1) \u5B89\u88C5 tesseract\uFF1Awinget install UB-Mannheim.TesseractOCR",
451
+ "2) \u5B89\u88C5 poppler\uFF08PDF \u9700\u8981\uFF09\u5E76\u52A0\u5165 PATH",
452
+ "3) \u7528 /connect \u914D\u7F6E\u652F\u6301\u56FE\u7247\u8F93\u5165\u7684\u591A\u6A21\u6001\u6A21\u578B\u540E\u91CD\u8BD5"
453
+ ].join("\n");
454
+ return [
455
+ "Linux \u53EF\u4EFB\u9009\u5176\u4E00\uFF1A",
456
+ "1) apt-get install -y tesseract-ocr tesseract-ocr-chi-sim poppler-utils",
457
+ "2) \u7528 /connect \u914D\u7F6E\u652F\u6301\u56FE\u7247\u8F93\u5165\u7684\u591A\u6A21\u6001\u6A21\u578B\u540E\u91CD\u8BD5"
458
+ ].join("\n");
459
+ }
460
+ function engineOrder(runtime) {
461
+ const forced = (runtime.env.OCR_ENGINE ?? "").toLowerCase();
462
+ if (forced === "vision" || forced === "tesseract" || forced === "llm")
463
+ return [forced];
464
+ return ["vision", "tesseract", "llm"];
465
+ }
466
+ async function recognizeOcr(input, ctx = {}) {
467
+ const runtime = makeRuntime(ctx);
468
+ let materialized;
469
+ try {
470
+ materialized = await materializeInput(input, runtime);
471
+ } catch (err) {
472
+ return {
473
+ ok: false,
474
+ error: err.message,
475
+ how_to_fix: howToFix(runtime.platform),
476
+ attempts: []
477
+ };
478
+ }
479
+ const attempts = [];
480
+ try {
481
+ for (const engine of engineOrder(runtime)) {
482
+ try {
483
+ let pages;
484
+ if (engine === "vision") {
485
+ const build = await ensureVisionBinary(runtime);
486
+ if (!build.binary) {
487
+ attempts.push({ engine, error: build.error ?? "\u4E0D\u53EF\u7528" });
488
+ continue;
489
+ }
490
+ pages = await runVision(
491
+ build.binary,
492
+ materialized.file,
493
+ input,
494
+ runtime
495
+ );
496
+ } else if (engine === "tesseract") {
497
+ pages = await runTesseract(
498
+ materialized.file,
499
+ materialized.isPdf,
500
+ input,
501
+ runtime,
502
+ materialized.tmpDir
503
+ );
504
+ } else {
505
+ pages = await runLlm(
506
+ materialized.file,
507
+ materialized.isPdf,
508
+ input,
509
+ runtime,
510
+ materialized.tmpDir
511
+ );
512
+ }
513
+ if (pages.length === 0) throw new Error("\u672A\u8BC6\u522B\u5230\u4EFB\u4F55\u9875\u9762");
514
+ return {
515
+ ok: true,
516
+ text: joinPages(pages),
517
+ engine,
518
+ pages
519
+ };
520
+ } catch (err) {
521
+ attempts.push({ engine, error: err.message });
522
+ }
523
+ }
524
+ return {
525
+ ok: false,
526
+ error: attempts.length > 0 ? `\u6CA1\u6709\u53EF\u7528\u7684 OCR \u5F15\u64CE: ${attempts.map((a) => `${a.engine}: ${a.error}`).join("; ")}` : "\u6CA1\u6709\u53EF\u7528\u7684 OCR \u5F15\u64CE",
527
+ how_to_fix: howToFix(runtime.platform),
528
+ attempts
529
+ };
530
+ } finally {
531
+ materialized.cleanup();
532
+ }
533
+ }
534
+
535
+ // src/mcp/builtin/ocr.ts
536
+ var TOOL_NAME = "recognize";
537
+ var TOOL_DESCRIPTION = [
538
+ "\u4ECE\u56FE\u7247\u3001\u626B\u63CF\u4EF6\u6216 PDF \u4E2D\u63D0\u53D6\u6587\u5B57\uFF08OCR\uFF09\u3002",
539
+ "\u4F18\u5148\u4F20 imagePath\uFF08\u5DE5\u4F5C\u533A\u5185\u7684\u6587\u4EF6\u8DEF\u5F84\uFF09\uFF0C\u4E5F\u652F\u6301 imageBase64\uFF08\u53EF\u5E26 data URL \u524D\u7F00\uFF09\u6216 imageUrl\u3002",
540
+ "\u4F20\u5165 PDF \u4F1A\u9010\u9875\u8BC6\u522B\uFF08maxPages \u9ED8\u8BA4 5\uFF0Cdpi \u9ED8\u8BA4 150\uFF09\u3002",
541
+ "\u8BC6\u522B\u5F15\u64CE\u81EA\u52A8\u9009\u62E9\uFF1AmacOS Vision / tesseract+pdftoppm / \u5DF2\u914D\u7F6E\u7684\u591A\u6A21\u6001\u6A21\u578B\u3002"
542
+ ].join("\n");
543
+ var INPUT_SCHEMA = {
544
+ type: "object",
545
+ properties: {
546
+ imagePath: {
547
+ type: "string",
548
+ description: "\u672C\u5730\u56FE\u7247\u6216 PDF \u8DEF\u5F84\uFF08\u76F8\u5BF9\u8DEF\u5F84\u6309\u5DE5\u4F5C\u533A\u89E3\u6790\uFF09"
549
+ },
550
+ imageBase64: {
551
+ type: "string",
552
+ description: "\u56FE\u7247\u7684 base64 \u7F16\u7801\uFF08\u53EF\u5E26 data URL \u524D\u7F00\uFF09"
553
+ },
554
+ imageUrl: {
555
+ type: "string",
556
+ description: "\u8FDC\u7A0B\u56FE\u7247\u6216 PDF \u7684 URL"
557
+ },
558
+ maxPages: {
559
+ type: "number",
560
+ description: "PDF \u6700\u591A\u8BC6\u522B\u9875\u6570\uFF08\u9ED8\u8BA4 5\uFF0C\u4E0A\u9650 50\uFF09"
561
+ },
562
+ dpi: {
563
+ type: "number",
564
+ description: "PDF \u6E32\u67D3 DPI\uFF08\u9ED8\u8BA4 150\uFF0C\u4E0A\u9650 400\uFF09"
565
+ },
566
+ lang: {
567
+ type: "string",
568
+ description: "tesseract \u8BED\u8A00\u5305\uFF08\u9ED8\u8BA4 chi_sim+eng\uFF09"
569
+ }
570
+ }
571
+ };
572
+ function createOcrServer(ctx = {}) {
573
+ const server = new Server(
574
+ { name: "zqagent-ocr", version: "0.1.0" },
575
+ { capabilities: { tools: {} } }
576
+ );
577
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
578
+ tools: [
579
+ {
580
+ name: TOOL_NAME,
581
+ description: TOOL_DESCRIPTION,
582
+ inputSchema: INPUT_SCHEMA
583
+ }
584
+ ]
585
+ }));
586
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
587
+ if (request.params.name !== TOOL_NAME) {
588
+ return {
589
+ content: [
590
+ {
591
+ type: "text",
592
+ text: JSON.stringify({
593
+ error: `\u672A\u77E5\u5DE5\u5177 "${request.params.name}"\uFF0C\u53EF\u7528\u5DE5\u5177\uFF1A${TOOL_NAME}`
594
+ })
595
+ }
596
+ ],
597
+ isError: true
598
+ };
599
+ }
600
+ const args = request.params.arguments ?? {};
601
+ const result = await recognizeOcr(args, ctx);
602
+ if (!result.ok) {
603
+ return {
604
+ content: [
605
+ {
606
+ type: "text",
607
+ text: JSON.stringify(
608
+ {
609
+ error: result.error,
610
+ how_to_fix: result.how_to_fix,
611
+ attempts: result.attempts
612
+ },
613
+ null,
614
+ 2
615
+ )
616
+ }
617
+ ],
618
+ isError: true
619
+ };
620
+ }
621
+ return {
622
+ content: [{ type: "text", text: result.text }]
623
+ };
624
+ });
625
+ return server;
626
+ }
627
+
628
+ // src/mcp/builtin/index.ts
629
+ var FACTORIES = {
630
+ ocr: createOcrServer
631
+ };
632
+ function listBuiltinServers() {
633
+ return Object.keys(FACTORIES);
634
+ }
635
+ async function createBuiltinTransport(config, ctx) {
636
+ const id = config.builtin ?? config.name;
637
+ const factory = FACTORIES[id];
638
+ if (!factory) {
639
+ throw new Error(
640
+ `\u672A\u77E5\u7684\u5185\u7F6E MCP server "${id}"\uFF08\u53EF\u7528: ${listBuiltinServers().join(", ")}\uFF09`
641
+ );
642
+ }
643
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
644
+ const server = factory(ctx);
645
+ await server.connect(serverTransport);
646
+ return clientTransport;
647
+ }
648
+ export {
649
+ createBuiltinTransport,
650
+ listBuiltinServers
651
+ };
652
+ //# sourceMappingURL=index.js.map