6.2 KiB
6.2 KiB
@deepseek-ai/dsh-fs-local
English | 中文
ctx.fs 提供方 seam(@deepseek-ai/dsh-fs)的本地文件系统实现。它使用宿主文件系统支持八个 FileSystem 原语;将其作为插件加载会填充 ctx.fs。
import { LocalFileSystem } from '@deepseek-ai/dsh-fs-local'
await ctx.plugin(LocalFileSystem, { cwd: process.cwd() })
// ctx.fs uses the local backend; load @deepseek-ai/dsh-fs-policy for the
// freshness policy gate and @deepseek-ai/dsh-tool-fs to expose read/write/edit.
行为
resolve(path, opts?):相对path在调用方提供opts.cwd时以该值为基准解析(面向模型的工具会传入调用 agent(智能体)的会话 cwd;见每会话 cwd Agent Note),否则以config.cwd为基准(默认process.cwd());绝对path会忽略两者。opts.signal会在本地解析前后检查,远程同级后端则可以用它中止往返。targetKey是文件的realpath,因此经符号链接到达同一文件的两个输入路径会共享一个身份,写入/编辑落在链接目标上,同时保留链接。尚不存在的路径在父目录存在时使用 realpath 后的父目录加 basename;只有父目录无法解析时才回退到绝对路径。displayPath是绝对但未经解析的路径。stat/lstat:返回目标元数据;目标不存在时返回undefined。stat为已解析目标报告FsInfo(version是由 bigintdev:ino:size:mtimeNs:ctimeNs派生的不透明 token,type为file/directory/other,size以字节计);路径形态的lstat不跟随最后一个符号链接,报告FsPathInfo,因此可以返回symlink。两者都会在异步元数据探测前后检查取消,因此飞行中的中止会报告FS_ABORTED,而非陈旧的不存在结果。readText/streamText:只支持 UTF-8。readText读取整个文件;streamText按分片流式读取(跨分片解码),因此超大文件无需整体保存在内存中。两者都会拒绝无效 UTF-8、包含 NUL 字节的二进制样本(FS_NOT_TEXT)以及非普通文件目标。read工具(@deepseek-ai/dsh-tool-fs)按大小决定调用哪个方法,并拥有行窗口逻辑。listDir:按稳定的name.localeCompare()顺序列出一层目录。每个条目携带子项 basename、类型、解析后的子目标(displayPath位于所列目录下,targetKey是 realpath 身份)和低成本 stat 元数据(version,普通文件另有size)。它绝不会打开或解码文件内容。缺失目标报告FS_NOT_FOUND,文件/特殊文件目标报告FS_NOT_DIRECTORY,已中止调用报告FS_ABORTED,权限失败报告FS_PERMISSION_DENIED,其他列出或子项元数据 I/O 失败报告FS_IO_ERROR。损坏/消失的子项以无元数据的other返回,但解析子项时出现权限/I/O 失败会让整个列表以结构化FsError失败。writeText:原子写入。它会向排他打开的临时文件(wx、0o600)写入;该文件位于目标旁随机命名的私有暂存目录(0o700)内。完成写入和 fsync 后,以 rename 覆盖目标。现有文件的 mode 会保留,新文件默认为0o600;Windows 上的新文件继承目标目录的 DACL,而替换会在写入前把目标 DACL 复制到空临时文件,并通过ReplaceFileW发布,使原访问政策得以保留(见 Windows DACL 保留 Agent Note)。expected防护是可选的:省略时无条件创建或覆盖;createIfAbsent创建缺失目标并拒绝现有目标(FS_NOT_OBSERVED);replaceIfVersion只在观察到的版本上替换(目标缺失或版本不匹配均为FS_STALE_VERSION)。editText:在同一原语之上依次执行原子的字面量读取、修改和写入,并通过变更锁按目标串行化。expected防护是可选的:提供时,会在字面量匹配之前校验版本(陈旧编辑报告FS_STALE_VERSION,绝不会针对较新内容报告FS_EDIT_NOT_FOUND/FS_AMBIGUOUS_EDIT);省略时,无条件编辑当前内容。无论哪种情况,目标缺失都报告FS_STALE_VERSION。匹配时规范化为 LF,随后恢复文件主要的 CRLF/LF 风格;空oldString/ 零匹配报告FS_EDIT_NOT_FOUND,未设置replace_all的多个匹配则报告FS_AMBIGUOUS_EDIT。
包根 SDK 接口包含默认/具名 LocalFileSystem 类和 Config。原始 I/O 位于 src/fsio.ts(不依赖 Cordis,单独进行单元测试);src/index.ts 是轻量服务接线。
模型体验
通过 dsh-tool-fs 间接产生影响;该消费方把本提供方带行窗口的 UTF-8 内容、变更确认和精确提供方消息渲染为有上限且保留的结果,而版本、原子写入机制和目录元数据保持内部可见。
KV Cache 影响
不会直接使缓存失效;具名消费方负责请求前缀的任何变化。
已知限制与延期工作
config.cwd不是沙箱:它是解析默认值,而非约束;绝对路径和..可以逃逸。请使用更严格的ctx.fs后端或tools/executewaterfall(瀑布式事件)上的权限插件实施约束(见能力 seam Agent Note)。- 覆盖会把整个旧文件读入内存:只用于 UI diff;在大小阈值之上限制这次预读取的工作延期处理(
TODO(overwrite-diff-bound))。 - 版本 token 是
mtimeMs:size:如果外部变更在文件系统时间戳粒度内保持两者不变,就能绕过陈旧防护。 editText会把整个文件及编辑后的副本保存在内存中:只有读取路径支持流式处理。- 二进制检测不对称:读取只对前 8192 字节执行 NUL 采样,编辑则扫描整个 buffer,因此 NUL 出现在后部的文件可以读取,但编辑会被拒绝。
- 每目标变更锁仅限进程内:其他进程中的写入方只会被可选版本防护发现,绝不会被串行化。