@zqagent/core 0.2.20 → 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 +3 -3
  3. package/README.oss.md +8 -3
  4. package/README.oss.zh-TW.md +3 -3
  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 +5418 -1096
  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 +5299 -1011
  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 -25218
  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 -25201
  232. package/dist/cli/index.js.map +0 -1
  233. package/dist/server/index.cjs +0 -20510
  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 -20493
  238. package/dist/server/index.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/tools/diff.ts","../../src/tools/pathSafety.ts"],"sourcesContent":["import { ToolRegistry } from \"./ToolRegistry.js\";\n\n/**\n * apply_patch + apply_unified_diff\n * 对齐 Python 版 aisuite.toolkits.files.FileToolkit\n */\n\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { resolveEntryWithinRoot, resolveWithinRoot } from \"./pathSafety.js\";\n\n/** apply_patch — Codex 风格补丁 (对齐 Python 版) */\nfunction makeApplyPatch(workspace: string) {\n const root = path.resolve(workspace);\n\n return function apply_patch(args: Record<string, unknown>) {\n const patch = String(args.patch ?? \"\");\n if (!patch.trim()) return { error: \"补丁内容不能为空\" };\n\n // 归一化 CRLF,并去掉尾部空白:否则 `*** End Patch\\n` 会因最后一项是空串\n // 而被误判为「补丁必须以 *** End Patch 结尾」。\n const lines = patch\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n .trimEnd()\n .split(\"\\n\");\n if (!lines[0]?.trim().startsWith(\"*** Begin Patch\")) {\n return { error: \"补丁必须以 '*** Begin Patch' 开头\" };\n }\n if (!lines[lines.length - 1]?.trim().startsWith(\"*** End Patch\")) {\n return { error: \"补丁必须以 '*** End Patch' 结尾\" };\n }\n\n const changedFiles: string[] = [];\n const addedFiles: string[] = [];\n const deletedFiles: string[] = [];\n let fileCount = 0;\n\n let i = 1;\n while (i < lines.length - 1) {\n const line = lines[i].trim();\n if (!line) { i++; continue; }\n\n if (line.startsWith(\"*** Add File: \")) {\n const filePath = line.slice(\"*** Add File: \".length).trim();\n const resolved = resolveWithinRoot(root, filePath);\n if (!resolved) {\n return { error: `路径在工作区之外: ${filePath}` };\n }\n const target = resolved.real;\n i++;\n const contentLines: string[] = [];\n while (i < lines.length - 1 && !lines[i].trimStart().startsWith(\"*** \")) {\n const current = lines[i];\n if (!current.startsWith(\"+\")) {\n return { error: `无效的 add-file 补丁行: ${current}` };\n }\n contentLines.push(current.slice(1));\n i++;\n }\n if (fs.existsSync(target)) {\n return { error: `文件已存在: ${filePath}` };\n }\n fs.mkdirSync(path.dirname(target), { recursive: true });\n fs.writeFileSync(target, contentLines.join(\"\\n\") + \"\\n\", \"utf-8\");\n const rel = path.relative(resolved.root, target);\n changedFiles.push(rel);\n addedFiles.push(rel);\n fileCount++;\n continue;\n }\n\n if (line.startsWith(\"*** Delete File: \")) {\n const filePath = line.slice(\"*** Delete File: \".length).trim();\n // 删除作用于条目本身:父目录取 realpath,最后一段不解析\n const entry = resolveEntryWithinRoot(root, filePath);\n if (!entry) {\n return { error: `路径在工作区之外: ${filePath}` };\n }\n const target = entry.real;\n if (!fs.existsSync(target)) {\n return { error: `文件不存在: ${filePath}` };\n }\n fs.unlinkSync(target);\n deletedFiles.push(path.relative(entry.root, target));\n fileCount++;\n i++;\n continue;\n }\n\n if (line.startsWith(\"*** Update File: \")) {\n const filePath = line.slice(\"*** Update File: \".length).trim();\n const resolved = resolveWithinRoot(root, filePath);\n if (!resolved) {\n return { error: `路径在工作区之外: ${filePath}` };\n }\n const target = resolved.real;\n i++;\n let moveTo: string | null = null;\n if (i < lines.length - 1 && lines[i].trimStart().startsWith(\"*** Move to: \")) {\n moveTo = lines[i].trim().slice(\"*** Move to: \".length).trim();\n i++;\n }\n\n const chunkLines: string[][] = [];\n let currentChunk: string[] = [];\n while (i < lines.length - 1 && !lines[i].trimStart().startsWith(\"*** \")) {\n const ln = lines[i];\n if (ln.trimStart().startsWith(\"@@\")) {\n if (currentChunk.length) {\n chunkLines.push(currentChunk);\n currentChunk = [];\n }\n } else if (ln && \" +-\".includes(ln[0]!)) {\n currentChunk.push(ln);\n }\n i++;\n }\n if (currentChunk.length) chunkLines.push(currentChunk);\n if (!chunkLines.length) {\n return { error: `补丁更新没有 hunks: ${filePath}` };\n }\n\n // Read original file\n if (!fs.existsSync(target)) {\n return { error: `文件不存在: ${filePath}` };\n }\n const oldLines = fs.readFileSync(target, \"utf-8\").split(\"\\n\");\n // Apply hunks\n const newLines = applyPatchHunks(oldLines, chunkLines, filePath);\n\n let finalResolved = resolved;\n if (moveTo) {\n const moved = resolveWithinRoot(root, moveTo);\n if (!moved) {\n return { error: `路径在工作区之外: ${moveTo}` };\n }\n finalResolved = moved;\n }\n const finalTarget = finalResolved.real;\n if (moveTo && fs.existsSync(finalTarget) && finalTarget !== target) {\n return { error: `文件已存在: ${moveTo}` };\n }\n fs.mkdirSync(path.dirname(finalTarget), { recursive: true });\n fs.writeFileSync(finalTarget, newLines.join(\"\\n\"), \"utf-8\");\n if (moveTo && finalTarget !== target) {\n // 删除源条目本身:父目录取 realpath,最后一段不解析(符号链接删链接)\n const entry = resolveEntryWithinRoot(root, filePath);\n if (!entry) {\n return { error: `路径在工作区之外: ${filePath}` };\n }\n fs.unlinkSync(entry.real);\n deletedFiles.push(path.relative(resolved.root, target));\n }\n changedFiles.push(path.relative(finalResolved.root, finalTarget));\n fileCount++;\n continue;\n }\n\n return { error: `未知的补丁操作: ${line}` };\n }\n\n if (fileCount === 0) {\n return { error: \"补丁不包含任何文件操作\" };\n }\n\n return { changed_files: changedFiles, added_files: addedFiles, deleted_files: deletedFiles, file_count: fileCount };\n };\n}\n\n/** 应用补丁 hunks 到文件行 */\nfunction applyPatchHunks(oldLines: string[], chunks: string[][], path: string): string[] {\n let newLines = [...oldLines];\n let cursor = 0;\n\n for (const chunk of chunks) {\n const oldBlock = chunk.filter((l) => l[0] === \" \" || l[0] === \"-\").map((l) => l.slice(1));\n const newBlock = chunk.filter((l) => l[0] === \" \" || l[0] === \"+\").map((l) => l.slice(1));\n\n if (!oldBlock.length) {\n throw new Error(`补丁 hunk 必须包含上下文或删除行: ${path}`);\n }\n\n // Find match for old block\n const matchStart = findBlockMatch(newLines, oldBlock, cursor);\n if (matchStart === -1) {\n throw new Error(`补丁上下文不匹配: ${path}`);\n }\n\n const matchEnd = matchStart + oldBlock.length;\n newLines.splice(matchStart, oldBlock.length, ...newBlock);\n cursor = matchStart + newBlock.length;\n }\n\n return newLines;\n}\n\n/** 在行数组中查找块匹配 */\nfunction findBlockMatch(lines: string[], block: string[], start: number): number {\n for (let i = start; i <= lines.length - block.length; i++) {\n if (lines.slice(i, i + block.length).every((l, j) => l === block[j]!)) {\n return i;\n }\n }\n return -1;\n}\n\n// ==================== Unified Diff ====================\n\n/** apply_unified_diff — 标准 unified diff (对齐 Python 版) */\nfunction makeApplyUnifiedDiff(workspace: string) {\n const root = path.resolve(workspace);\n\n return function apply_unified_diff(args: Record<string, unknown>) {\n const diff = String(args.diff ?? \"\").replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n if (!diff.trim()) return { error: \"diff 内容不能为空\" };\n\n const patches = parseUnifiedDiff(diff);\n if (!patches.length) return { error: \"未找到 unified diff 文件补丁\" };\n\n const changedFiles: string[] = [];\n const addedFiles: string[] = [];\n const deletedFiles: string[] = [];\n let hunkCount = 0;\n\n for (const patch of patches) {\n const oldIsDevNull = patch.oldPath === \"/dev/null\";\n const newIsDevNull = patch.newPath === \"/dev/null\";\n const targetPath = newIsDevNull ? patch.oldPath : patch.newPath;\n const resolved = resolveWithinRoot(root, targetPath);\n if (!resolved) {\n return { error: `路径在工作区之外: ${targetPath}` };\n }\n const target = resolved.real;\n\n const oldLines = oldIsDevNull ? [] : (fs.existsSync(target) ? fs.readFileSync(target, \"utf-8\").split(\"\\n\") : []);\n const newLines = applyDiffHunks(oldLines, patch.hunks, targetPath);\n hunkCount += patch.hunks.length;\n\n if (newIsDevNull) {\n if (fs.existsSync(target)) {\n if (!fs.statSync(target).isFile()) {\n return { error: `路径不是文件: ${targetPath}` };\n }\n // 删除源条目本身:父目录取 realpath,最后一段不解析\n const entry = resolveEntryWithinRoot(root, targetPath);\n if (!entry) {\n return { error: `路径在工作区之外: ${targetPath}` };\n }\n fs.unlinkSync(entry.real);\n }\n deletedFiles.push(path.relative(resolved.root, target));\n continue;\n }\n\n fs.mkdirSync(path.dirname(target), { recursive: true });\n fs.writeFileSync(target, newLines.join(\"\\n\"), \"utf-8\");\n const rel = path.relative(resolved.root, target);\n changedFiles.push(rel);\n if (oldIsDevNull) addedFiles.push(rel);\n }\n\n return {\n changed_files: changedFiles,\n added_files: addedFiles,\n deleted_files: deletedFiles,\n file_count: patches.length,\n hunk_count: hunkCount,\n };\n };\n}\n\ninterface DiffHunk {\n oldStart: number;\n oldCount: number;\n newStart: number;\n newCount: number;\n lines: string[];\n}\n\ninterface FilePatch {\n oldPath: string;\n newPath: string;\n hunks: DiffHunk[];\n}\n\nfunction parseUnifiedDiff(diff: string): FilePatch[] {\n const lines = diff.split(\"\\n\");\n const patches: FilePatch[] = [];\n let i = 0;\n\n while (i < lines.length) {\n if (!lines[i]!.startsWith(\"--- \")) { i++; continue; }\n\n const oldPath = parseDiffFileLine(lines[i]!, \"---\");\n i++;\n if (i >= lines.length || !lines[i]!.startsWith(\"+++ \")) {\n throw new Error(\"Unified diff 缺少 +++ 文件头\");\n }\n const newPath = parseDiffFileLine(lines[i]!, \"+++\");\n i++;\n\n const hunks: DiffHunk[] = [];\n while (i < lines.length) {\n const current = lines[i]!;\n if (current.startsWith(\"--- \")) break;\n if (!current.startsWith(\"@@ \")) { i++; continue; }\n\n const [oldStart, oldCount, newStart, newCount] = parseHunkHeader(current);\n i++;\n const hunkLines: string[] = [];\n while (i < lines.length) {\n const ln = lines[i]!;\n if (ln.startsWith(\"@@ \") || ln.startsWith(\"--- \")) break;\n if (ln.startsWith(\"\\\\ No newline\")) { i++; continue; }\n if (ln && \" +-\".includes(ln[0]!)) {\n hunkLines.push(ln);\n i++;\n } else {\n break;\n }\n }\n hunks.push({ oldStart, oldCount, newStart, newCount, lines: hunkLines });\n }\n if (hunks.length) {\n patches.push({ oldPath, newPath, hunks });\n }\n }\n\n return patches;\n}\n\nfunction parseDiffFileLine(line: string, marker: string): string {\n let value = line.slice(marker.length).trim();\n if (value.includes(\"\\t\")) value = value.split(\"\\t\")[0]!;\n if (value.startsWith(\"a/\") || value.startsWith(\"b/\")) value = value.slice(2);\n return value;\n}\n\nfunction parseHunkHeader(line: string): [number, number, number, number] {\n const parts = line.split(\" \");\n if (parts.length < 3 || !parts[1]!.startsWith(\"-\") || !parts[2]!.startsWith(\"+\")) {\n throw new Error(`无效的 hunk header: ${line}`);\n }\n const [oldStart, oldCount] = parseRange(parts[1]!.slice(1));\n const [newStart, newCount] = parseRange(parts[2]!.slice(1));\n return [oldStart, oldCount, newStart, newCount];\n}\n\nfunction parseRange(value: string): [number, number] {\n if (!value.includes(\",\")) return [parseInt(value), 1];\n const [start, count] = value.split(\",\");\n return [parseInt(start!), parseInt(count!)];\n}\n\nfunction applyDiffHunks(oldLines: string[], hunks: DiffHunk[], filePath: string): string[] {\n const newLines: string[] = [];\n let cursor = 0;\n\n for (const hunk of hunks) {\n const start = Math.max(hunk.oldStart - 1, 0);\n if (start < cursor) {\n throw new Error(`Overlapping hunks: ${filePath}`);\n }\n newLines.push(...oldLines.slice(cursor, start));\n cursor = start;\n\n for (const line of hunk.lines) {\n const prefix = line[0]!;\n const content = line.slice(1);\n if (prefix === \" \") {\n if (cursor >= oldLines.length || oldLines[cursor] !== content) {\n throw new Error(`Diff context 不匹配: ${filePath}`);\n }\n newLines.push(oldLines[cursor]!);\n cursor++;\n } else if (prefix === \"-\") {\n if (cursor >= oldLines.length || oldLines[cursor] !== content) {\n throw new Error(`Diff removal 不匹配: ${filePath}`);\n }\n cursor++;\n } else if (prefix === \"+\") {\n newLines.push(content);\n }\n }\n }\n newLines.push(...oldLines.slice(cursor));\n return newLines;\n}\n\n/** 注册 diff 工具 */\nexport function registerDiffTools(registry: ToolRegistry, workspace: string): void {\n const applyPatchFunc = makeApplyPatch(workspace);\n registry.register(\n (args) => applyPatchFunc(args),\n { category: \"filesystem\", riskLevel: \"medium\", capabilities: [\"edit_file\"], requiresApproval: true },\n {\n type: \"function\",\n function: {\n name: \"apply_patch\",\n description: \"应用 Codex 风格的补丁信封(使用 *** Begin Patch / *** End Patch 段落)。支持 Add File、Delete File、Update File 操作。\",\n parameters: {\n type: \"object\",\n properties: {\n patch: { type: \"string\", description: \"补丁内容 (必须包含 *** Begin Patch 和 *** End Patch)\" },\n },\n required: [\"patch\"],\n },\n },\n },\n );\n\n const applyUnifiedDiffFunc = makeApplyUnifiedDiff(workspace);\n registry.register(\n (args) => applyUnifiedDiffFunc(args),\n { category: \"filesystem\", riskLevel: \"medium\", capabilities: [\"edit_file\"], requiresApproval: true },\n {\n type: \"function\",\n function: {\n name: \"apply_unified_diff\",\n description: \"应用标准 unified diff 补丁。支持 --- / +++ 文件头和 @@ hunk headers。\",\n parameters: {\n type: \"object\",\n properties: {\n diff: { type: \"string\", description: \"unified diff 格式的补丁内容\" },\n },\n required: [\"diff\"],\n },\n },\n },\n );\n}\n","/**\n * 路径安全辅助函数\n *\n * 判断目标路径是否真正位于工作区根目录之内。\n *\n * 仅做字符串比较(path.relative)无法防御符号链接逃逸:\n * 工作区内若存在指向外部的 symlink,`workspace/link/secret.txt`\n * 的字符串前缀合法,但实际读写发生在链接目标(工作区外)。\n *\n * 因此这里用 fs.realpathSync 解析符号链接后再与根目录的 realpath\n * 比较。目标尚不存在(如 write_file 新建文件)时,向上回溯到最近\n * 已存在的祖先目录解析,再拼回剩余路径段。\n *\n * 校验通过时把解析后的真实路径一并返回:调用方必须用它(而非原始\n * 相对路径)做实际 fs 操作,否则「校验后、操作前」路径组件被替换为\n * 指向外部的 symlink 仍会逃逸(TOCTOU)。\n */\nimport * as fs from \"fs\";\nimport * as path from \"path\";\n\n/**\n * 判断 `path.relative(root, target)` 的结果是否落在 root 之内。\n *\n * 逃逸必然恰好是 `..` 或以 `..` + 分隔符开头,不能用 `startsWith(\"..\")`:\n * 工作区里名为 `..foo` 的合法条目会被误判为逃逸而拒绝。\n * 跨盘符时(Windows)path.relative 返回绝对路径,一并拒绝。\n */\nfunction isInsideRelative(rel: string): boolean {\n return (\n !path.isAbsolute(rel) && rel !== \"..\" && !rel.startsWith(`..${path.sep}`)\n );\n}\n\n/** 是否为文件系统根(\"/\"、\"C:\\\\\") */\nfunction isFilesystemRoot(p: string): boolean {\n return path.parse(p).root === p;\n}\n\n/** 校验通过的路径:root 为工作区根的真实路径,real 为目标的真实路径 */\nexport interface ResolvedPath {\n root: string;\n real: string;\n}\n\n/**\n * 校验 target(相对 workspace 的路径)是否位于 workspace 内,并返回\n * 解析符号链接后的真实路径;不在工作区内时返回 null。\n *\n * - 解析符号链接:路径中任何 symlink 组件都会先 realpath 再校验;\n * broken symlink(存在但无法解析)一律拒绝。\n * - 目标不存在时(写新文件):回溯到最近存在的祖先做 realpath,\n * 再拼接剩余段,仍能捕获祖先链中的 symlink 逃逸。\n * - 工作区根若就是文件系统根(`WORKSPACE=/`):此时任何绝对路径都在\n * 其内,等同没有沙箱,直接判为越界。\n */\nexport function resolveWithinRoot(\n workspace: string,\n target: string,\n): ResolvedPath | null {\n const abs = path.resolve(workspace, target);\n\n let rootReal: string;\n try {\n rootReal = fs.realpathSync(workspace);\n } catch {\n // 根目录不存在(如权限引擎尚未初始化工作区):\n // 没有实际目录结构即无 symlink 逃逸面,退化为纯字符串路径比较。\n const rootAbs = path.resolve(workspace);\n if (!isInsideRelative(path.relative(rootAbs, abs))) return null;\n return { root: rootAbs, real: abs };\n }\n if (isFilesystemRoot(rootReal)) return null;\n\n let real: string;\n try {\n real = fs.realpathSync(abs);\n } catch {\n // abs 不存在:向上回溯找最近存在的祖先\n let probe = abs;\n const tail: string[] = [];\n for (;;) {\n // 组件存在(含 broken symlink)但 realpath 失败 → 无法解析,拒绝\n const exists = fs.existsSync(probe) || fs.lstatSync(probe, { throwIfNoEntry: false }) !== undefined;\n if (exists) {\n try {\n real = path.join(fs.realpathSync(probe), ...tail);\n break;\n } catch {\n return null;\n }\n }\n tail.unshift(path.basename(probe));\n const parent = path.dirname(probe);\n if (parent === probe) return null; // 已到文件系统根\n probe = parent;\n }\n }\n\n if (!isInsideRelative(path.relative(rootReal, real))) return null;\n return { root: rootReal, real };\n}\n\n/**\n * 判断 target 是否安全地位于 workspace 内(不需要真实路径时用这个)。\n *\n * 注意:删除类操作不应据此改用 realpath 去 unlink —— 那会删掉符号链接\n * 指向的目标而非链接本身;这类操作请用 resolveEntryWithinRoot。\n */\nexport function isWithinRoot(workspace: string, target: string): boolean {\n return resolveWithinRoot(workspace, target) !== null;\n}\n\n/**\n * 解析「目录项本身」的路径:父目录取 realpath,最后一段保持原样。\n *\n * 供 unlink / rename 等作用于条目自身的操作用:父目录不可被 symlink\n * 替换,而最后一段若是符号链接,被操作的是链接本身,不会被跟随。\n */\nexport function resolveEntryWithinRoot(\n workspace: string,\n target: string,\n): ResolvedPath | null {\n const abs = path.resolve(workspace, target);\n const parent = resolveWithinRoot(workspace, path.dirname(abs));\n if (!parent) return null;\n return { root: parent.root, real: path.join(parent.real, path.basename(abs)) };\n}\n"],"mappings":"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","names":["fs","path","path"]}
1
+ {"version":3,"sources":["../../src/tools/diff.ts","../../src/tools/pathSafety.ts"],"sourcesContent":["import { ToolRegistry } from \"./ToolRegistry.js\";\n\n/**\n * apply_patch + apply_unified_diff\n * 对齐 Python 版 aisuite.toolkits.files.FileToolkit\n */\n\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { resolveEntryWithinRoot, resolveWithinRoot } from \"./pathSafety.js\";\nimport type { ConflictGuard } from \"./conflictGuard.js\";\n\n/** apply_patch — Codex 风格补丁 (对齐 Python 版) */\nfunction makeApplyPatch(workspace: string, guard?: ConflictGuard) {\n const root = path.resolve(workspace);\n\n return function apply_patch(args: Record<string, unknown>) {\n const patch = String(args.patch ?? \"\");\n if (!patch.trim()) return { error: \"补丁内容不能为空\" };\n\n // 归一化 CRLF,并去掉尾部空白:否则 `*** End Patch\\n` 会因最后一项是空串\n // 而被误判为「补丁必须以 *** End Patch 结尾」。\n const lines = patch\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n .trimEnd()\n .split(\"\\n\");\n if (!lines[0]?.trim().startsWith(\"*** Begin Patch\")) {\n return { error: \"补丁必须以 '*** Begin Patch' 开头\" };\n }\n if (!lines[lines.length - 1]?.trim().startsWith(\"*** End Patch\")) {\n return { error: \"补丁必须以 '*** End Patch' 结尾\" };\n }\n\n const changedFiles: string[] = [];\n const addedFiles: string[] = [];\n const deletedFiles: string[] = [];\n let fileCount = 0;\n\n let i = 1;\n while (i < lines.length - 1) {\n const line = lines[i].trim();\n if (!line) { i++; continue; }\n\n if (line.startsWith(\"*** Add File: \")) {\n const filePath = line.slice(\"*** Add File: \".length).trim();\n const resolved = resolveWithinRoot(root, filePath);\n if (!resolved) {\n return { error: `路径在工作区之外: ${filePath}` };\n }\n const target = resolved.real;\n i++;\n const contentLines: string[] = [];\n while (i < lines.length - 1 && !lines[i].trimStart().startsWith(\"*** \")) {\n const current = lines[i];\n if (!current.startsWith(\"+\")) {\n return { error: `无效的 add-file 补丁行: ${current}` };\n }\n contentLines.push(current.slice(1));\n i++;\n }\n if (fs.existsSync(target)) {\n return { error: `文件已存在: ${filePath}` };\n }\n fs.mkdirSync(path.dirname(target), { recursive: true });\n fs.writeFileSync(target, contentLines.join(\"\\n\") + \"\\n\", \"utf-8\");\n const rel = path.relative(resolved.root, target);\n changedFiles.push(rel);\n addedFiles.push(rel);\n fileCount++;\n continue;\n }\n\n if (line.startsWith(\"*** Delete File: \")) {\n const filePath = line.slice(\"*** Delete File: \".length).trim();\n // 删除作用于条目本身:父目录取 realpath,最后一段不解析\n const entry = resolveEntryWithinRoot(root, filePath);\n if (!entry) {\n return { error: `路径在工作区之外: ${filePath}` };\n }\n const target = entry.real;\n if (!fs.existsSync(target)) {\n return { error: `文件不存在: ${filePath}` };\n }\n // 删除同样是破坏性操作:本会话读过之后被别人改过 → 先让人确认\n const delConflict = guard?.checkWrite(target, filePath);\n if (delConflict) return { error: delConflict.message };\n fs.unlinkSync(target);\n deletedFiles.push(path.relative(entry.root, target));\n fileCount++;\n i++;\n continue;\n }\n\n if (line.startsWith(\"*** Update File: \")) {\n const filePath = line.slice(\"*** Update File: \".length).trim();\n const resolved = resolveWithinRoot(root, filePath);\n if (!resolved) {\n return { error: `路径在工作区之外: ${filePath}` };\n }\n const target = resolved.real;\n i++;\n let moveTo: string | null = null;\n if (i < lines.length - 1 && lines[i].trimStart().startsWith(\"*** Move to: \")) {\n moveTo = lines[i].trim().slice(\"*** Move to: \".length).trim();\n i++;\n }\n\n const chunkLines: string[][] = [];\n let currentChunk: string[] = [];\n while (i < lines.length - 1 && !lines[i].trimStart().startsWith(\"*** \")) {\n const ln = lines[i];\n if (ln.trimStart().startsWith(\"@@\")) {\n if (currentChunk.length) {\n chunkLines.push(currentChunk);\n currentChunk = [];\n }\n } else if (ln && \" +-\".includes(ln[0]!)) {\n currentChunk.push(ln);\n }\n i++;\n }\n if (currentChunk.length) chunkLines.push(currentChunk);\n if (!chunkLines.length) {\n return { error: `补丁更新没有 hunks: ${filePath}` };\n }\n\n // Read original file\n if (!fs.existsSync(target)) {\n return { error: `文件不存在: ${filePath}` };\n }\n const oldLines = fs.readFileSync(target, \"utf-8\").split(\"\\n\");\n // 补丁是「基于读到的版本」生成的:先确认这个版本没被别人改过\n const conflict = guard?.checkWrite(target, filePath);\n if (conflict) return { error: conflict.message };\n // Apply hunks\n const newLines = applyPatchHunks(oldLines, chunkLines, filePath);\n\n let finalResolved = resolved;\n if (moveTo) {\n const moved = resolveWithinRoot(root, moveTo);\n if (!moved) {\n return { error: `路径在工作区之外: ${moveTo}` };\n }\n finalResolved = moved;\n }\n const finalTarget = finalResolved.real;\n if (moveTo && fs.existsSync(finalTarget) && finalTarget !== target) {\n return { error: `文件已存在: ${moveTo}` };\n }\n fs.mkdirSync(path.dirname(finalTarget), { recursive: true });\n fs.writeFileSync(finalTarget, newLines.join(\"\\n\"), \"utf-8\");\n guard?.noteWrite(finalTarget, newLines.join(\"\\n\"));\n if (moveTo && finalTarget !== target) {\n // 删除源条目本身:父目录取 realpath,最后一段不解析(符号链接删链接)\n const entry = resolveEntryWithinRoot(root, filePath);\n if (!entry) {\n return { error: `路径在工作区之外: ${filePath}` };\n }\n fs.unlinkSync(entry.real);\n deletedFiles.push(path.relative(resolved.root, target));\n }\n changedFiles.push(path.relative(finalResolved.root, finalTarget));\n fileCount++;\n continue;\n }\n\n return { error: `未知的补丁操作: ${line}` };\n }\n\n if (fileCount === 0) {\n return { error: \"补丁不包含任何文件操作\" };\n }\n\n return { changed_files: changedFiles, added_files: addedFiles, deleted_files: deletedFiles, file_count: fileCount };\n };\n}\n\n/** 应用补丁 hunks 到文件行 */\nfunction applyPatchHunks(oldLines: string[], chunks: string[][], path: string): string[] {\n let newLines = [...oldLines];\n let cursor = 0;\n\n for (const chunk of chunks) {\n const oldBlock = chunk.filter((l) => l[0] === \" \" || l[0] === \"-\").map((l) => l.slice(1));\n const newBlock = chunk.filter((l) => l[0] === \" \" || l[0] === \"+\").map((l) => l.slice(1));\n\n if (!oldBlock.length) {\n throw new Error(`补丁 hunk 必须包含上下文或删除行: ${path}`);\n }\n\n // Find match for old block\n const matchStart = findBlockMatch(newLines, oldBlock, cursor);\n if (matchStart === -1) {\n throw new Error(`补丁上下文不匹配: ${path}`);\n }\n\n const matchEnd = matchStart + oldBlock.length;\n newLines.splice(matchStart, oldBlock.length, ...newBlock);\n cursor = matchStart + newBlock.length;\n }\n\n return newLines;\n}\n\n/** 在行数组中查找块匹配 */\nfunction findBlockMatch(lines: string[], block: string[], start: number): number {\n for (let i = start; i <= lines.length - block.length; i++) {\n if (lines.slice(i, i + block.length).every((l, j) => l === block[j]!)) {\n return i;\n }\n }\n return -1;\n}\n\n// ==================== Unified Diff ====================\n\n/** apply_unified_diff — 标准 unified diff (对齐 Python 版) */\nfunction makeApplyUnifiedDiff(workspace: string, guard?: ConflictGuard) {\n const root = path.resolve(workspace);\n\n return function apply_unified_diff(args: Record<string, unknown>) {\n const diff = String(args.diff ?? \"\").replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n if (!diff.trim()) return { error: \"diff 内容不能为空\" };\n\n const patches = parseUnifiedDiff(diff);\n if (!patches.length) return { error: \"未找到 unified diff 文件补丁\" };\n\n const changedFiles: string[] = [];\n const addedFiles: string[] = [];\n const deletedFiles: string[] = [];\n let hunkCount = 0;\n\n for (const patch of patches) {\n const oldIsDevNull = patch.oldPath === \"/dev/null\";\n const newIsDevNull = patch.newPath === \"/dev/null\";\n const targetPath = newIsDevNull ? patch.oldPath : patch.newPath;\n const resolved = resolveWithinRoot(root, targetPath);\n if (!resolved) {\n return { error: `路径在工作区之外: ${targetPath}` };\n }\n const target = resolved.real;\n\n const oldLines = oldIsDevNull ? [] : (fs.existsSync(target) ? fs.readFileSync(target, \"utf-8\").split(\"\\n\") : []);\n // diff 基于某个版本生成:不校验就应用会把别人的改动覆盖掉\n if (!oldIsDevNull) {\n const conflict = guard?.checkWrite(target, targetPath);\n if (conflict) return { error: conflict.message };\n }\n const newLines = applyDiffHunks(oldLines, patch.hunks, targetPath);\n hunkCount += patch.hunks.length;\n\n if (newIsDevNull) {\n if (fs.existsSync(target)) {\n if (!fs.statSync(target).isFile()) {\n return { error: `路径不是文件: ${targetPath}` };\n }\n // 删除源条目本身:父目录取 realpath,最后一段不解析\n const entry = resolveEntryWithinRoot(root, targetPath);\n if (!entry) {\n return { error: `路径在工作区之外: ${targetPath}` };\n }\n fs.unlinkSync(entry.real);\n }\n deletedFiles.push(path.relative(resolved.root, target));\n continue;\n }\n\n fs.mkdirSync(path.dirname(target), { recursive: true });\n const written = newLines.join(\"\\n\");\n fs.writeFileSync(target, written, \"utf-8\");\n guard?.noteWrite(target, written);\n const rel = path.relative(resolved.root, target);\n changedFiles.push(rel);\n if (oldIsDevNull) addedFiles.push(rel);\n }\n\n return {\n changed_files: changedFiles,\n added_files: addedFiles,\n deleted_files: deletedFiles,\n file_count: patches.length,\n hunk_count: hunkCount,\n };\n };\n}\n\ninterface DiffHunk {\n oldStart: number;\n oldCount: number;\n newStart: number;\n newCount: number;\n lines: string[];\n}\n\ninterface FilePatch {\n oldPath: string;\n newPath: string;\n hunks: DiffHunk[];\n}\n\nfunction parseUnifiedDiff(diff: string): FilePatch[] {\n const lines = diff.split(\"\\n\");\n const patches: FilePatch[] = [];\n let i = 0;\n\n while (i < lines.length) {\n if (!lines[i]!.startsWith(\"--- \")) { i++; continue; }\n\n const oldPath = parseDiffFileLine(lines[i]!, \"---\");\n i++;\n if (i >= lines.length || !lines[i]!.startsWith(\"+++ \")) {\n throw new Error(\"Unified diff 缺少 +++ 文件头\");\n }\n const newPath = parseDiffFileLine(lines[i]!, \"+++\");\n i++;\n\n const hunks: DiffHunk[] = [];\n while (i < lines.length) {\n const current = lines[i]!;\n if (current.startsWith(\"--- \")) break;\n if (!current.startsWith(\"@@ \")) { i++; continue; }\n\n const [oldStart, oldCount, newStart, newCount] = parseHunkHeader(current);\n i++;\n const hunkLines: string[] = [];\n while (i < lines.length) {\n const ln = lines[i]!;\n if (ln.startsWith(\"@@ \") || ln.startsWith(\"--- \")) break;\n if (ln.startsWith(\"\\\\ No newline\")) { i++; continue; }\n if (ln && \" +-\".includes(ln[0]!)) {\n hunkLines.push(ln);\n i++;\n } else {\n break;\n }\n }\n hunks.push({ oldStart, oldCount, newStart, newCount, lines: hunkLines });\n }\n if (hunks.length) {\n patches.push({ oldPath, newPath, hunks });\n }\n }\n\n return patches;\n}\n\nfunction parseDiffFileLine(line: string, marker: string): string {\n let value = line.slice(marker.length).trim();\n if (value.includes(\"\\t\")) value = value.split(\"\\t\")[0]!;\n if (value.startsWith(\"a/\") || value.startsWith(\"b/\")) value = value.slice(2);\n return value;\n}\n\nfunction parseHunkHeader(line: string): [number, number, number, number] {\n const parts = line.split(\" \");\n if (parts.length < 3 || !parts[1]!.startsWith(\"-\") || !parts[2]!.startsWith(\"+\")) {\n throw new Error(`无效的 hunk header: ${line}`);\n }\n const [oldStart, oldCount] = parseRange(parts[1]!.slice(1));\n const [newStart, newCount] = parseRange(parts[2]!.slice(1));\n return [oldStart, oldCount, newStart, newCount];\n}\n\nfunction parseRange(value: string): [number, number] {\n if (!value.includes(\",\")) return [parseInt(value), 1];\n const [start, count] = value.split(\",\");\n return [parseInt(start!), parseInt(count!)];\n}\n\nfunction applyDiffHunks(oldLines: string[], hunks: DiffHunk[], filePath: string): string[] {\n const newLines: string[] = [];\n let cursor = 0;\n\n for (const hunk of hunks) {\n const start = Math.max(hunk.oldStart - 1, 0);\n if (start < cursor) {\n throw new Error(`Overlapping hunks: ${filePath}`);\n }\n newLines.push(...oldLines.slice(cursor, start));\n cursor = start;\n\n for (const line of hunk.lines) {\n const prefix = line[0]!;\n const content = line.slice(1);\n if (prefix === \" \") {\n if (cursor >= oldLines.length || oldLines[cursor] !== content) {\n throw new Error(`Diff context 不匹配: ${filePath}`);\n }\n newLines.push(oldLines[cursor]!);\n cursor++;\n } else if (prefix === \"-\") {\n if (cursor >= oldLines.length || oldLines[cursor] !== content) {\n throw new Error(`Diff removal 不匹配: ${filePath}`);\n }\n cursor++;\n } else if (prefix === \"+\") {\n newLines.push(content);\n }\n }\n }\n newLines.push(...oldLines.slice(cursor));\n return newLines;\n}\n\n/** 注册 diff 工具 */\nexport function registerDiffTools(\n registry: ToolRegistry,\n workspace: string,\n guard?: ConflictGuard,\n): void {\n const applyPatchFunc = makeApplyPatch(workspace, guard);\n registry.register(\n (args) => applyPatchFunc(args),\n { category: \"filesystem\", riskLevel: \"medium\", capabilities: [\"edit_file\"], requiresApproval: true },\n {\n type: \"function\",\n function: {\n name: \"apply_patch\",\n description: \"应用 Codex 风格的补丁信封(使用 *** Begin Patch / *** End Patch 段落)。支持 Add File、Delete File、Update File 操作。\",\n parameters: {\n type: \"object\",\n properties: {\n patch: { type: \"string\", description: \"补丁内容 (必须包含 *** Begin Patch 和 *** End Patch)\" },\n },\n required: [\"patch\"],\n },\n },\n },\n );\n\n const applyUnifiedDiffFunc = makeApplyUnifiedDiff(workspace, guard);\n registry.register(\n (args) => applyUnifiedDiffFunc(args),\n { category: \"filesystem\", riskLevel: \"medium\", capabilities: [\"edit_file\"], requiresApproval: true },\n {\n type: \"function\",\n function: {\n name: \"apply_unified_diff\",\n description: \"应用标准 unified diff 补丁。支持 --- / +++ 文件头和 @@ hunk headers。\",\n parameters: {\n type: \"object\",\n properties: {\n diff: { type: \"string\", description: \"unified diff 格式的补丁内容\" },\n },\n required: [\"diff\"],\n },\n },\n },\n );\n}\n","/**\n * 路径安全辅助函数\n *\n * 判断目标路径是否真正位于工作区根目录之内。\n *\n * 仅做字符串比较(path.relative)无法防御符号链接逃逸:\n * 工作区内若存在指向外部的 symlink,`workspace/link/secret.txt`\n * 的字符串前缀合法,但实际读写发生在链接目标(工作区外)。\n *\n * 因此这里用 fs.realpathSync 解析符号链接后再与根目录的 realpath\n * 比较。目标尚不存在(如 write_file 新建文件)时,向上回溯到最近\n * 已存在的祖先目录解析,再拼回剩余路径段。\n *\n * 校验通过时把解析后的真实路径一并返回:调用方必须用它(而非原始\n * 相对路径)做实际 fs 操作,否则「校验后、操作前」路径组件被替换为\n * 指向外部的 symlink 仍会逃逸(TOCTOU)。\n */\nimport * as fs from \"fs\";\nimport * as path from \"path\";\n\n/**\n * 判断 `path.relative(root, target)` 的结果是否落在 root 之内。\n *\n * 逃逸必然恰好是 `..` 或以 `..` + 分隔符开头,不能用 `startsWith(\"..\")`:\n * 工作区里名为 `..foo` 的合法条目会被误判为逃逸而拒绝。\n * 跨盘符时(Windows)path.relative 返回绝对路径,一并拒绝。\n *\n * 导出供自行做 `path.relative` 校验的调用方复用(如目录浏览新建目录、\n * git 面板的 repo / path 参数),避免各处重复写 `startsWith(\"..\")`。\n */\nexport function isInsideRelative(rel: string): boolean {\n return (\n !path.isAbsolute(rel) && rel !== \"..\" && !rel.startsWith(`..${path.sep}`)\n );\n}\n\n/** 是否为文件系统根(\"/\"、\"C:\\\\\") */\nfunction isFilesystemRoot(p: string): boolean {\n return path.parse(p).root === p;\n}\n\n/** 校验通过的路径:root 为工作区根的真实路径,real 为目标的真实路径 */\nexport interface ResolvedPath {\n root: string;\n real: string;\n}\n\n/**\n * 校验 target(相对 workspace 的路径)是否位于 workspace 内,并返回\n * 解析符号链接后的真实路径;不在工作区内时返回 null。\n *\n * - 解析符号链接:路径中任何 symlink 组件都会先 realpath 再校验;\n * broken symlink(存在但无法解析)一律拒绝。\n * - 目标不存在时(写新文件):回溯到最近存在的祖先做 realpath,\n * 再拼接剩余段,仍能捕获祖先链中的 symlink 逃逸。\n * - 工作区根若就是文件系统根(`WORKSPACE=/`):此时任何绝对路径都在\n * 其内,等同没有沙箱,直接判为越界。\n */\nexport function resolveWithinRoot(\n workspace: string,\n target: string,\n): ResolvedPath | null {\n const abs = path.resolve(workspace, target);\n\n let rootReal: string;\n try {\n rootReal = fs.realpathSync(workspace);\n } catch {\n // 根目录不存在(如权限引擎尚未初始化工作区):\n // 没有实际目录结构即无 symlink 逃逸面,退化为纯字符串路径比较。\n const rootAbs = path.resolve(workspace);\n if (!isInsideRelative(path.relative(rootAbs, abs))) return null;\n return { root: rootAbs, real: abs };\n }\n if (isFilesystemRoot(rootReal)) return null;\n\n let real: string;\n try {\n real = fs.realpathSync(abs);\n } catch {\n // abs 不存在:向上回溯找最近存在的祖先\n let probe = abs;\n const tail: string[] = [];\n for (;;) {\n // 组件存在(含 broken symlink)但 realpath 失败 → 无法解析,拒绝\n const exists = fs.existsSync(probe) || fs.lstatSync(probe, { throwIfNoEntry: false }) !== undefined;\n if (exists) {\n try {\n real = path.join(fs.realpathSync(probe), ...tail);\n break;\n } catch {\n return null;\n }\n }\n tail.unshift(path.basename(probe));\n const parent = path.dirname(probe);\n if (parent === probe) return null; // 已到文件系统根\n probe = parent;\n }\n }\n\n if (!isInsideRelative(path.relative(rootReal, real))) return null;\n return { root: rootReal, real };\n}\n\n/**\n * 判断 target 是否安全地位于 workspace 内(不需要真实路径时用这个)。\n *\n * 注意:删除类操作不应据此改用 realpath 去 unlink —— 那会删掉符号链接\n * 指向的目标而非链接本身;这类操作请用 resolveEntryWithinRoot。\n */\nexport function isWithinRoot(workspace: string, target: string): boolean {\n return resolveWithinRoot(workspace, target) !== null;\n}\n\n/**\n * 解析「目录项本身」的路径:父目录取 realpath,最后一段保持原样。\n *\n * 供 unlink / rename 等作用于条目自身的操作用:父目录不可被 symlink\n * 替换,而最后一段若是符号链接,被操作的是链接本身,不会被跟随。\n */\nexport function resolveEntryWithinRoot(\n workspace: string,\n target: string,\n): ResolvedPath | null {\n const abs = path.resolve(workspace, target);\n const parent = resolveWithinRoot(workspace, path.dirname(abs));\n if (!parent) return null;\n return { root: parent.root, real: path.join(parent.real, path.basename(abs)) };\n}\n"],"mappings":"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","names":["fs","path","path"]}
@@ -1,4 +1,6 @@
1
- import { T as ToolRegistry } from '../ToolRegistry-C3pTFiaJ.cjs';
1
+ import { T as ToolRegistry } from '../ToolRegistry-DouDvn9E.cjs';
2
+ import '../types-BYyXWWPW.cjs';
3
+ import '@zqagent/shared/model-capabilities';
2
4
 
3
5
  /**
4
6
  * request_directory — 请求文件夹访问权限
@@ -1,4 +1,6 @@
1
- import { T as ToolRegistry } from '../ToolRegistry-C3pTFiaJ.js';
1
+ import { T as ToolRegistry } from '../ToolRegistry-Cy0fQxrb.js';
2
+ import '../types-BYyXWWPW.js';
3
+ import '@zqagent/shared/model-capabilities';
2
4
 
3
5
  /**
4
6
  * request_directory — 请求文件夹访问权限