@deepseek-ai/dsh-fs 0.1.2-rc.1 → 0.1.5-alpha.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.
- package/README.i18n.yaml +2 -2
- package/README.md +4 -4
- package/README.zh.md +4 -4
- package/lib/types/index.d.ts +17 -0
- package/package.json +11 -11
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/fs/fs/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: baad80c13fa5cbdfebc4e1a367d0726f728cffdb
|
|
6
|
+
README.zh.md: a6598c9b532ebe0349c5ad9af9c56eab75f4c756
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
|
|
|
9
9
|
|
|
10
10
|
## Summary
|
|
11
11
|
|
|
12
|
-
`dsh-fs`
|
|
12
|
+
Use `dsh-fs` when an application needs consistent filesystem operations across host, confined, or remote execution environments. It lets consumers resolve stable file identities, map shared host files where supported, perform bounded text and byte reads, list directories, and apply atomic text writes and literal edits. Version guards are optional, so a backend works without policy enforcement; callers can supply a guard to reject a mutation after the file changes. Choose `fs-local`, `fs-sandbox`, or `fs-e2b` for the required execution environment. Model-facing filesystem tools are provided separately by `dsh-tool-fs`.
|
|
13
13
|
|
|
14
14
|
## Table of Contents
|
|
15
15
|
|
|
@@ -52,7 +52,7 @@ The contract is built on one separation and three commitments:
|
|
|
52
52
|
- **Contract over mechanism.** The service names what a storage layer can do — resolve, stat, read, list, write, edit — and never how it stores bytes. Backends own target identity, execution-world coordinates, decoding, binary rejection, and atomicity.
|
|
53
53
|
- **Policy stays off the base class.** Observed-state, read-before-edit, and version-guarded mutations are a plugin's job (`dsh-fs-observation-policy`), added by supplying the optional guard — so a sandboxed or remote backend inherits no model-facing observation policy.
|
|
54
54
|
- **`editText` stays on the seam.** Version check, literal match, and atomic rewrite share one critical section, so error attribution and one-wins/one-stale concurrency stay correct; a remote backend may implement it as a native compare-and-edit.
|
|
55
|
-
- **Bounds live at this seam.** `readBytes` requires `maxBytes` and fails with `FS_TOO_LARGE` rather than truncating, so no backend ever buffers an unbounded file.
|
|
55
|
+
- **Bounds live at this seam.** `readBytes` requires `maxBytes` and fails with `FS_TOO_LARGE` rather than truncating, so no backend ever buffers an unbounded file. `readByteRange` is bounded by its window instead: a backend transfers at most the requested `length` beyond the prefix it skips, so the caller's cap on `length` is the guard.
|
|
56
56
|
|
|
57
57
|
### Source map
|
|
58
58
|
|
|
@@ -63,7 +63,7 @@ The contract is built on one separation and three commitments:
|
|
|
63
63
|
|
|
64
64
|
### How a call flows
|
|
65
65
|
|
|
66
|
-
Every ordinary operation starts with `resolve(path, { cwd })`, which produces a stable `FsTarget` (an opaque `targetKey` plus a `displayPath` for model/UI output); the same file reached through different paths yields the same key. `processPathFromHostPath(hostPath)` separately maps an absolute host file into this execution world when the backend shares or explicitly maps it, and otherwise returns `undefined`. Reads then go `stat` → `readText`/`streamText`/`readBytes`, listings go `listDir`, and mutations go through one per-target critical section: the optional guard is checked, the new content is applied, and the result is published atomically.
|
|
66
|
+
Every ordinary operation starts with `resolve(path, { cwd })`, which produces a stable `FsTarget` (an opaque `targetKey` plus a `displayPath` for model/UI output); the same file reached through different paths yields the same key. `processPathFromHostPath(hostPath)` separately maps an absolute host file into this execution world when the backend shares or explicitly maps it, and otherwise returns `undefined`. Reads then go `stat` → `readText`/`streamText`/`readBytes`/`readByteRange`, listings go `listDir`, and mutations go through one per-target critical section: the optional guard is checked, the new content is applied, and the result is published atomically.
|
|
67
67
|
|
|
68
68
|
### The `fs/*` policy events
|
|
69
69
|
|
|
@@ -109,7 +109,7 @@ No direct invalidation; the named consumer owns any request-prefix changes.
|
|
|
109
109
|
|
|
110
110
|
These limits define when the contract is a poor fit or needs special operational care. They are current package constraints, not a general filesystem comparison or a task backlog.
|
|
111
111
|
|
|
112
|
-
- **Text-only mutations by contract** — text reads and both mutations reject binary or non-UTF-8 content with `FS_NOT_TEXT`; `readBytes`
|
|
112
|
+
- **Text-only mutations by contract** — text reads and both mutations reject binary or non-UTF-8 content with `FS_NOT_TEXT`; `readBytes` and `readByteRange` are the raw-byte primitives, and binary-safe mutations remain deferred.
|
|
113
113
|
- **Thirteen primitives only** — no delete, rename, copy, or watch; `listDir` lists a single level, with recursion, globbing, pagination, and search out of scope ([directory-listing note](../../../.agents/notes/archived/architecture/2026-07-03-filesystem-directory-listing-seam.md)).
|
|
114
114
|
- **No I/O deadline** — the seam arms no timeout; cancellation is a best-effort optional `AbortSignal` per primitive ([fs family stance](../README.md)).
|
|
115
115
|
- **Resolve-then-operate costs a remote backend two round-trips per tool call** — folding or caching resolution is left to such a backend.
|
package/README.zh.md
CHANGED
|
@@ -9,7 +9,7 @@ kind: "package-reference"
|
|
|
9
9
|
|
|
10
10
|
## 概述
|
|
11
11
|
|
|
12
|
-
`dsh-fs
|
|
12
|
+
应用需要在宿主、受限或远程执行环境中使用一致的文件系统操作时,选择 `dsh-fs`。消费方可以解析稳定的文件身份、在受支持时映射共享宿主文件、执行有界的文本与字节读取、列出目录,并原子地写入文本及执行字面量编辑。版本防护是可选的,因此后端无需策略强制也能工作;调用方可以提供防护,在文件变化后拒绝变更。根据所需执行环境选择 `fs-local`、`fs-sandbox` 或 `fs-e2b`。面向模型的文件系统工具由 `dsh-tool-fs` 单独提供。
|
|
13
13
|
|
|
14
14
|
## 目录
|
|
15
15
|
|
|
@@ -52,7 +52,7 @@ kind: "package-reference"
|
|
|
52
52
|
- **约定高于机制。** 服务只命名存储层能做什么——解析、stat、读取、列出、写入、编辑——绝不规定如何存储字节。后端拥有目标身份、执行世界坐标、解码、二进制拒绝与原子性。
|
|
53
53
|
- **策略不放在基类上。** 已观察状态、编辑前读取与版本防护的变更是插件(`dsh-fs-observation-policy`)的职责,通过提供可选防护来添加——因此沙箱化或远程后端不会继承任何面向模型的观察策略。
|
|
54
54
|
- **`editText` 留在 seam 上。** 版本校验、字面量匹配与原子重写共享同一个临界区,错误归因与一方胜出/一方陈旧的并发语义因此保持正确;远程后端也可以将其实现为原生比较并编辑操作。
|
|
55
|
-
- **界限制在此 seam 上。** `readBytes` 要求 `maxBytes`,并以 `FS_TOO_LARGE`
|
|
55
|
+
- **界限制在此 seam 上。** `readBytes` 要求 `maxBytes`,并以 `FS_TOO_LARGE` 失败而不是截断,因此任何后端都不会无界缓冲文件。`readByteRange` 则以窗口为界:后端最多传输所请求的 `length` 字节(外加为到达 `offset` 而跳过的前缀),因此由调用方对 `length` 的上限承担防护。
|
|
56
56
|
|
|
57
57
|
### 源码地图
|
|
58
58
|
|
|
@@ -63,7 +63,7 @@ kind: "package-reference"
|
|
|
63
63
|
|
|
64
64
|
### 调用流程
|
|
65
65
|
|
|
66
|
-
每个普通操作都以 `resolve(path, { cwd })` 开始,它产生稳定的 `FsTarget`(不透明 `targetKey` 加用于模型/UI 输出的 `displayPath`);经不同路径到达同一文件会产生相同 key。`processPathFromHostPath(hostPath)` 在后端共享或显式映射宿主文件时,单独把绝对宿主文件映射进此执行世界,否则返回 `undefined`。读取随后执行 `stat` → `readText`/`streamText`/`readBytes`,列出执行 `listDir`,变更则经过每个目标一个临界区:先检查可选防护,应用新内容,再原子发布结果。
|
|
66
|
+
每个普通操作都以 `resolve(path, { cwd })` 开始,它产生稳定的 `FsTarget`(不透明 `targetKey` 加用于模型/UI 输出的 `displayPath`);经不同路径到达同一文件会产生相同 key。`processPathFromHostPath(hostPath)` 在后端共享或显式映射宿主文件时,单独把绝对宿主文件映射进此执行世界,否则返回 `undefined`。读取随后执行 `stat` → `readText`/`streamText`/`readBytes`/`readByteRange`,列出执行 `listDir`,变更则经过每个目标一个临界区:先检查可选防护,应用新内容,再原子发布结果。
|
|
67
67
|
|
|
68
68
|
### `fs/*` 策略事件
|
|
69
69
|
|
|
@@ -109,7 +109,7 @@ kind: "package-reference"
|
|
|
109
109
|
|
|
110
110
|
这些限制说明该约定何时不合适,或何时需要特别的运维注意。它们是当前包约束,不是通用文件系统对比或任务积压。
|
|
111
111
|
|
|
112
|
-
- **变更操作约定只支持文本**:文本读取和两个变更操作都以 `FS_NOT_TEXT` 拒绝二进制/非 UTF-8 内容;`readBytes`
|
|
112
|
+
- **变更操作约定只支持文本**:文本读取和两个变更操作都以 `FS_NOT_TEXT` 拒绝二进制/非 UTF-8 内容;`readBytes` 与 `readByteRange` 是原始字节原语,二进制安全的变更操作仍延期。
|
|
113
113
|
- **只有十三个原语**:没有删除、重命名、复制或监视;`listDir` 只列出一层,递归、glob、分页与搜索不在范围内(见[目录列出笔记](../../../.agents/notes/archived/architecture/2026-07-03-filesystem-directory-listing-seam.md))。
|
|
114
114
|
- **没有 I/O deadline**:该 seam 不启动超时;取消只是每个原语上尽力而为的可选 `AbortSignal`(见[fs 能力族立场](../README.zh.md))。
|
|
115
115
|
- **先解析后操作使远程后端每次工具调用需要两次往返**:折叠或缓存解析由这种后端自行决定。
|
package/lib/types/index.d.ts
CHANGED
|
@@ -172,6 +172,23 @@ export declare abstract class FileSystem extends Service {
|
|
|
172
172
|
* @returns the full raw content, at most `maxBytes` long.
|
|
173
173
|
*/
|
|
174
174
|
abstract readBytes(target: FsTarget, signal: AbortSignal | undefined, maxBytes: number): Promise<Uint8Array>;
|
|
175
|
+
/**
|
|
176
|
+
* Read one byte window of the regular file as raw bytes with no decoding or
|
|
177
|
+
* binary rejection: the bytes at `[offset, offset + length)`, shorter when
|
|
178
|
+
* the file ends inside the window and empty when `offset` lies at or past
|
|
179
|
+
* its end. The window is the bound here, not the file: a backend transfers
|
|
180
|
+
* at most `length` bytes of content beyond the prefix it skips to reach
|
|
181
|
+
* `offset` and never buffers the whole file, so the caller's cap on `length`
|
|
182
|
+
* is the guard against unbounded buffering.
|
|
183
|
+
* @param target - the resolved target to read.
|
|
184
|
+
* @param range - `offset`, the 0-based first byte, and `length`, the largest byte count; both non-negative integers.
|
|
185
|
+
* @param signal - aborts the read.
|
|
186
|
+
* @returns the window's bytes, at most `length` long.
|
|
187
|
+
*/
|
|
188
|
+
abstract readByteRange(target: FsTarget, range: {
|
|
189
|
+
offset: number;
|
|
190
|
+
length: number;
|
|
191
|
+
}, signal?: AbortSignal): Promise<Uint8Array>;
|
|
175
192
|
/**
|
|
176
193
|
* List direct children of a directory in stable name order. Returns resolved
|
|
177
194
|
* child targets plus cheap metadata only; never reads file contents.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-fs",
|
|
3
3
|
"description": "Abstract filesystem capability seam (ctx.fs) for the DeepSeek Harness — vocabulary types, the FileSystem service (text IO + optional version-guarded atomic mutations), and the fs/* policy event vocabulary",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.5-alpha.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -32,17 +32,17 @@
|
|
|
32
32
|
],
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@deepseek-ai/dsh-brand": "^0.1.
|
|
36
|
-
"@deepseek-ai/dsh-
|
|
37
|
-
"@deepseek-ai/dsh-
|
|
38
|
-
"@deepseek-ai/
|
|
39
|
-
"@deepseek-ai/
|
|
35
|
+
"@deepseek-ai/dsh-brand": "^0.1.5-alpha.1",
|
|
36
|
+
"@deepseek-ai/dsh-llm": "^0.1.5-alpha.1",
|
|
37
|
+
"@deepseek-ai/dsh-sandbox": "^0.1.5-alpha.1",
|
|
38
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
39
|
+
"@deepseek-ai/dsh-invariants": "^0.1.5-alpha.1"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@deepseek-ai/dsh-
|
|
43
|
-
"@deepseek-ai/dsh-
|
|
44
|
-
"@deepseek-ai/dsh-llm": "^0.1.
|
|
45
|
-
"@deepseek-ai/
|
|
46
|
-
"@deepseek-ai/
|
|
42
|
+
"@deepseek-ai/dsh-invariants": "^0.1.5-alpha.1",
|
|
43
|
+
"@deepseek-ai/dsh-brand": "^0.1.5-alpha.1",
|
|
44
|
+
"@deepseek-ai/dsh-llm": "^0.1.5-alpha.1",
|
|
45
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
46
|
+
"@deepseek-ai/dsh-sandbox": "^0.1.5-alpha.1"
|
|
47
47
|
}
|
|
48
48
|
}
|