@deepseek-ai/dsh-fs 0.1.6-alpha.2 → 0.1.7-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 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: e36e400d53cc581eb19733c9b3ccd890f34932a2
6
- README.zh.md: 3efc2106a9200ee84ab1a859a19fdb5b1631f056
5
+ README.md: 549da2a42a70c0ac06bf50870076fceb400cbf78
6
+ README.zh.md: c9b91913554c66f727289130d6d50c522ba60d91
package/README.md CHANGED
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
9
9
 
10
10
  ## Summary
11
11
 
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` or `fs-sandbox` for host execution. Model-facing filesystem tools are provided separately by `dsh-tool-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, watch targets, 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` or `fs-sandbox` for host execution. Model-facing filesystem tools are provided separately by `dsh-tool-fs`.
13
13
 
14
14
  ## Table of Contents
15
15
 
@@ -33,7 +33,9 @@ Pick [`fs-local`](../fs-local/README.md) for ordinary host files or [`fs-sandbox
33
33
 
34
34
  ### What the service lets you do
35
35
 
36
- Through `ctx.fs` you can resolve any path to a stable target identity, read a whole text file or stream it in chunks, read raw bytes up to an explicit cap, list one directory level, atomically create or replace a file, and apply a literal text edit atomically. The version guard on both mutations is optional: omit it for unconditional create-or-overwrite, or supply it to fail when the file changed since you last observed it. Every operation returns data or a typed `FsError` carrying a stable code such as `FS_NOT_FOUND`, `FS_STALE_VERSION`, or `FS_AMBIGUOUS_EDIT`, so callers branch on the code, never on message text.
36
+ Through `ctx.fs` you can resolve any path to a stable target identity, read a whole text file or stream it in chunks, read raw bytes up to an explicit cap, list one directory level, atomically create or replace a file, and apply a literal text edit atomically. The version guard on both mutations is optional: omit it for unconditional create-or-overwrite, or supply it to fail when the file changed since you last observed it. Read, listing, and mutation failures are typed `FsError`s with stable codes such as `FS_NOT_FOUND`, `FS_STALE_VERSION`, or `FS_AMBIGUOUS_EDIT`, so callers branch on the code, never on message text.
37
+
38
+ `watch(target, changed, signal)` reports invalidations for one file or a directory's direct entries. It resolves once observation is ready with an asynchronous close function that the caller must await. The signal cancels initialization; unsupported providers reject without polling.
37
39
 
38
40
  -----
39
41
 
@@ -49,7 +51,7 @@ This section explains the design decisions behind the contract and points at the
49
51
 
50
52
  The contract is built on one separation and three commitments:
51
53
 
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.
54
+ - **Contract over mechanism.** The service names what a storage layer can do — resolve, stat, read, list, watch, write, edit — and never how it stores bytes. Backends own target identity, execution-world coordinates, decoding, binary rejection, and atomicity.
53
55
  - **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
56
  - **`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
57
  - **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.
@@ -72,7 +74,7 @@ The package declares three events so the emitter (`dsh-tool-fs`) and the policy
72
74
  ### Invariants
73
75
 
74
76
  - `targetKey` and `version` are branded opaque ids: consumers must not parse or interpret them; only `displayPath` is for model/UI output.
75
- - Failures are typed `FsError`s with stable codes, never ad-hoc message strings.
77
+ - Read, listing, and mutation failures are typed `FsError`s with stable codes, never ad-hoc message strings; watch initialization may reject with an ordinary exception.
76
78
  - The seam arms no I/O deadline; cancellation is an optional per-primitive `AbortSignal`.
77
79
 
78
80
  </details>
@@ -110,7 +112,7 @@ No direct invalidation; the named consumer owns any request-prefix changes.
110
112
  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
113
 
112
114
  - **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
- - **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)).
115
+ - **No delete, rename, or copy** — `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
116
  - **No I/O deadline** — the seam arms no timeout; cancellation is a best-effort optional `AbortSignal` per primitive ([fs family stance](../README.md)).
115
117
  - **Resolve-then-operate costs a remote backend two round-trips per tool call** — folding or caching resolution is left to such a backend.
116
118
 
package/README.zh.md CHANGED
@@ -9,7 +9,7 @@ kind: "package-reference"
9
9
 
10
10
  ## 概述
11
11
 
12
- 应用需要在宿主、受限或远程执行环境中使用一致的文件系统操作时,选择 `dsh-fs`。消费方可以解析稳定的文件身份、在受支持时映射共享宿主文件、执行有界的文本与字节读取、列出目录,并原子地写入文本及执行字面量编辑。版本防护是可选的,因此后端无需策略强制也能工作;调用方可以提供防护,在文件变化后拒绝变更。在宿主执行时选择 `fs-local` 或 `fs-sandbox`。面向模型的文件系统工具由 `dsh-tool-fs` 单独提供。
12
+ 应用需要在宿主、受限或远程执行环境中使用一致的文件系统操作时,选择 `dsh-fs`。消费方可以解析稳定的文件身份、在受支持时映射共享宿主文件、执行有界的文本与字节读取、列出目录、监听目标,并原子地写入文本及执行字面量编辑。版本防护是可选的,因此后端无需策略强制也能工作;调用方可以提供防护,在文件变化后拒绝变更。在宿主执行时选择 `fs-local` 或 `fs-sandbox`。面向模型的文件系统工具由 `dsh-tool-fs` 单独提供。
13
13
 
14
14
  ## 目录
15
15
 
@@ -33,7 +33,9 @@ kind: "package-reference"
33
33
 
34
34
  ### 服务能做什么
35
35
 
36
- 通过 `ctx.fs`,你可以把任意路径解析为稳定的目标身份、完整读取或分片流式读取文本文件、按显式上限读取原始字节、列出一层目录、原子地创建或替换文件,并原子地应用字面量文本编辑。两个变更操作上的版本防护都是可选的:省略它即无条件创建或覆盖,提供它则在文件自上次观察以来发生变化时失败。每个操作要么返回数据,要么抛出携带稳定错误码(如 `FS_NOT_FOUND`、`FS_STALE_VERSION`、`FS_AMBIGUOUS_EDIT`)的类型化 `FsError`,调用方依据错误码分支,绝不解析消息文本。
36
+ 通过 `ctx.fs`,你可以把任意路径解析为稳定的目标身份、完整读取或分片流式读取文本文件、按显式上限读取原始字节、列出一层目录、原子地创建或替换文件,并原子地应用字面量文本编辑。两个变更操作上的版本防护都是可选的:省略它即无条件创建或覆盖,提供它则在文件自上次观察以来发生变化时失败。读取、列出与变更操作的失败使用携带稳定错误码(如 `FS_NOT_FOUND`、`FS_STALE_VERSION`、`FS_AMBIGUOUS_EDIT`)的类型化 `FsError`,调用方依据错误码分支,绝不解析消息文本。
37
+
38
+ `watch(target, changed, signal)` 报告单个文件或目录直接子项的失效通知。观察就绪后,它返回调用方必须等待完成的异步关闭函数。signal 取消初始化;不支持监听的提供方直接拒绝,不使用轮询。
37
39
 
38
40
  -----
39
41
 
@@ -49,7 +51,7 @@ kind: "package-reference"
49
51
 
50
52
  该约定建立在一个分离与三项承诺之上:
51
53
 
52
- - **约定高于机制。** 服务只命名存储层能做什么——解析、stat、读取、列出、写入、编辑——绝不规定如何存储字节。后端拥有目标身份、执行世界坐标、解码、二进制拒绝与原子性。
54
+ - **约定高于机制。** 服务只命名存储层能做什么——解析、stat、读取、列出、监听、写入、编辑——绝不规定如何存储字节。后端拥有目标身份、执行世界坐标、解码、二进制拒绝与原子性。
53
55
  - **策略不放在基类上。** 已观察状态、编辑前读取与版本防护的变更是插件(`dsh-fs-observation-policy`)的职责,通过提供可选防护来添加——因此沙箱化或远程后端不会继承任何面向模型的观察策略。
54
56
  - **`editText` 留在 seam 上。** 版本校验、字面量匹配与原子重写共享同一个临界区,错误归因与一方胜出/一方陈旧的并发语义因此保持正确;远程后端也可以将其实现为原生比较并编辑操作。
55
57
  - **界限制在此 seam 上。** `readBytes` 要求 `maxBytes`,并以 `FS_TOO_LARGE` 失败而不是截断,因此任何后端都不会无界缓冲文件。`readByteRange` 则以窗口为界:后端最多传输所请求的 `length` 字节(外加为到达 `offset` 而跳过的前缀),因此由调用方对 `length` 的上限承担防护。
@@ -72,7 +74,7 @@ kind: "package-reference"
72
74
  ### 不变式
73
75
 
74
76
  - `targetKey` 与 `version` 是带品牌的不透明 id:消费方不得解析或解释它们;只有 `displayPath` 用于模型/UI 输出。
75
- - 失败是携带稳定错误码的类型化 `FsError`,绝不是临时拼写的消息字符串。
77
+ - 读取、列出与变更操作的失败是携带稳定错误码的类型化 `FsError`,绝不是临时拼写的消息字符串;监听初始化可以用普通异常拒绝。
76
78
  - 该 seam 不设 I/O deadline;取消是每个原语上可选的 `AbortSignal`。
77
79
 
78
80
  </details>
@@ -110,7 +112,7 @@ kind: "package-reference"
110
112
  这些限制说明该约定何时不合适,或何时需要特别的运维注意。它们是当前包约束,不是通用文件系统对比或任务积压。
111
113
 
112
114
  - **变更操作约定只支持文本**:文本读取和两个变更操作都以 `FS_NOT_TEXT` 拒绝二进制/非 UTF-8 内容;`readBytes` 与 `readByteRange` 是原始字节原语,二进制安全的变更操作仍延期。
113
- - **只有十三个原语**:没有删除、重命名、复制或监视;`listDir` 只列出一层,递归、glob、分页与搜索不在范围内(见[目录列出笔记](../../../.agents/notes/archived/architecture/2026-07-03-filesystem-directory-listing-seam.md))。
115
+ - **没有删除、重命名或复制**:`listDir` 只列出一层,递归、glob、分页与搜索不在范围内(见[目录列出笔记](../../../.agents/notes/archived/architecture/2026-07-03-filesystem-directory-listing-seam.md))。
114
116
  - **没有 I/O deadline**:该 seam 不启动超时;取消只是每个原语上尽力而为的可选 `AbortSignal`(见[fs 能力族立场](../README.zh.md))。
115
117
  - **先解析后操作使远程后端每次工具调用需要两次往返**:折叠或缓存解析由这种后端自行决定。
116
118
 
package/lib/index.js CHANGED
@@ -60,6 +60,18 @@ var FileSystem = class extends Service {
60
60
  super(ctx, "fs");
61
61
  }
62
62
  /**
63
+ * Observe one file or a directory's direct entries in this provider's execution world.
64
+ * @param target - resolved file or directory, including an absent path to observe for creation.
65
+ * @param changed - invalidation callback; errors can be reported during or after initialization.
66
+ * @param signal - cancels watcher initialization; the caller closes an initialized watcher.
67
+ * @returns a promise resolving once observation is active, with an asynchronous close function.
68
+ * @throws when the provider does not support watching or cannot initialize the watcher.
69
+ */
70
+ watch(target, changed, signal) {
71
+ signal.throwIfAborted();
72
+ return Promise.reject(new FsError("Filesystem watching is not supported by this provider.", "FS_IO_ERROR"));
73
+ }
74
+ /**
63
75
  * The sandbox mode this backend enforces on mutations BY DEFAULT, or
64
76
  * `undefined` when it does not confine at all — the capability fact the tool
65
77
  * layer reads to advertise the escalation fields honestly (mirrors
@@ -60,6 +60,15 @@ declare module '@deepseek-ai/cordis' {
60
60
  */
61
61
  export declare abstract class FileSystem extends Service {
62
62
  constructor(ctx: Context);
63
+ /**
64
+ * Observe one file or a directory's direct entries in this provider's execution world.
65
+ * @param target - resolved file or directory, including an absent path to observe for creation.
66
+ * @param changed - invalidation callback; errors can be reported during or after initialization.
67
+ * @param signal - cancels watcher initialization; the caller closes an initialized watcher.
68
+ * @returns a promise resolving once observation is active, with an asynchronous close function.
69
+ * @throws when the provider does not support watching or cannot initialize the watcher.
70
+ */
71
+ watch(target: FsTarget, changed: (error?: Error) => void, signal: AbortSignal): Promise<() => Promise<void>>;
63
72
  /**
64
73
  * The sandbox mode this backend enforces on mutations BY DEFAULT, or
65
74
  * `undefined` when it does not confine at all — the capability fact the tool
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.6-alpha.2",
4
+ "version": "0.1.7-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-invariants": "^0.1.6-alpha.2",
36
- "@deepseek-ai/dsh-llm": "^0.1.6-alpha.2",
37
- "@deepseek-ai/dsh-sandbox": "^0.1.6-alpha.2",
38
- "@deepseek-ai/cordis": "^4.0.2",
39
- "@deepseek-ai/dsh-brand": "^0.1.6-alpha.2"
35
+ "@deepseek-ai/dsh-brand": "^0.1.7-alpha.1",
36
+ "@deepseek-ai/dsh-invariants": "^0.1.7-alpha.1",
37
+ "@deepseek-ai/dsh-llm": "^0.1.7-alpha.1",
38
+ "@deepseek-ai/dsh-sandbox": "^0.1.7-alpha.1",
39
+ "@deepseek-ai/cordis": "^4.0.3"
40
40
  },
41
41
  "devDependencies": {
42
- "@deepseek-ai/dsh-brand": "^0.1.6-alpha.2",
43
- "@deepseek-ai/dsh-invariants": "^0.1.6-alpha.2",
44
- "@deepseek-ai/dsh-llm": "^0.1.6-alpha.2",
45
- "@deepseek-ai/dsh-sandbox": "^0.1.6-alpha.2",
46
- "@deepseek-ai/cordis": "^4.0.2"
42
+ "@deepseek-ai/dsh-brand": "^0.1.7-alpha.1",
43
+ "@deepseek-ai/dsh-invariants": "^0.1.7-alpha.1",
44
+ "@deepseek-ai/dsh-llm": "^0.1.7-alpha.1",
45
+ "@deepseek-ai/dsh-sandbox": "^0.1.7-alpha.1",
46
+ "@deepseek-ai/cordis": "^4.0.3"
47
47
  }
48
48
  }