@deepseek-ai/dsh-api-workspace-files 0.1.7-rc.1 → 0.1.7-rc.2

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
@@ -1,6 +1,67 @@
1
- # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
2
- # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
- # after editing either side, bring the other along and re-record with:
1
+ # Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
2
+ # section, a hash of its English and Chinese blocks outside code blocks and generated regions.
3
+ # After editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/api/workspace-files/README.md
5
- README.md: 0345887e58975b9ef2764144ded20a4f25e8f04d
6
- README.zh.md: 572b83ec37696ee32ba9c3e1e0babdf696afe903
5
+ /:
6
+ en: f83c75aa73ae21dd
7
+ zh: e8873aafd23a8038
8
+ /deepseek-ai-dsh-api-workspace-files:
9
+ en: d2885c72d12d9924
10
+ zh: e111f03d02383229
11
+ /deepseek-ai-dsh-api-workspace-files/summary:
12
+ en: 27c562441286bdbf
13
+ zh: 205dfac32c96873b
14
+ /deepseek-ai-dsh-api-workspace-files/table-of-contents:
15
+ en: d152484eb41ac6b4
16
+ zh: 09388d293f9be9cb
17
+ /deepseek-ai-dsh-api-workspace-files/use-this-package:
18
+ en: 874054ed5e950973
19
+ zh: e8b55d62939c4c2f
20
+ /deepseek-ai-dsh-api-workspace-files/use-this-package/addressing-and-paths:
21
+ en: b9565cfa7a1da451
22
+ zh: fc4078a58322fc7f
23
+ /deepseek-ai-dsh-api-workspace-files/use-this-package/pages:
24
+ en: 9cd68b8be3390c80
25
+ zh: 26049ce447f00452
26
+ /deepseek-ai-dsh-api-workspace-files/use-this-package/binary-reads:
27
+ en: 93ca9e832fbfd632
28
+ zh: 69412adba259c6f8
29
+ /deepseek-ai-dsh-api-workspace-files/use-this-package/file-read-and-directory-checks:
30
+ en: aa85c7754557a22f
31
+ zh: c576d06749fbe0a5
32
+ /deepseek-ai-dsh-api-workspace-files/use-this-package/the-change-feed:
33
+ en: 8bd2d820a512d461
34
+ zh: 0614ddd842ae7526
35
+ /deepseek-ai-dsh-api-workspace-files/use-this-package/configuration:
36
+ en: e606e8b22ac6e0d0
37
+ zh: 13a7214448036d7b
38
+ /deepseek-ai-dsh-api-workspace-files/use-this-package/failures:
39
+ en: c53d597c8f255e69
40
+ zh: 1e00318f9a34f3bb
41
+ /deepseek-ai-dsh-api-workspace-files/use-this-package/client-file-resources:
42
+ en: 9b4bf7a30016f856
43
+ zh: 30127a6ada65e715
44
+ /deepseek-ai-dsh-api-workspace-files/understand-the-implementation:
45
+ en: 42b15ac6321706aa
46
+ zh: ce1d25bffb6948cd
47
+ /deepseek-ai-dsh-api-workspace-files/understand-the-implementation/design-concept:
48
+ en: c3a8852c33dcc0e9
49
+ zh: d24fd47da7faaa29
50
+ /deepseek-ai-dsh-api-workspace-files/understand-the-implementation/source-map:
51
+ en: 2394243d582bb452
52
+ zh: 763e56ca827efa0d
53
+ /deepseek-ai-dsh-api-workspace-files/further-exploration:
54
+ en: 71f00fb919d12181
55
+ zh: 1e3819cd90dfca31
56
+ /deepseek-ai-dsh-api-workspace-files/model-experience:
57
+ en: 37b4264c8301323f
58
+ zh: 74ea89b3383ff7da
59
+ /deepseek-ai-dsh-api-workspace-files/model-experience/kv-cache-effect:
60
+ en: ca75c51c89c2c9b0
61
+ zh: 03126f3b1aac5859
62
+ /deepseek-ai-dsh-api-workspace-files/known-limitations-and-deferred-work:
63
+ en: ee05e55f5d16f253
64
+ zh: 0c937eeac8fa3f08
65
+ /deepseek-ai-dsh-api-workspace-files/known-limitations-and-deferred-work/dev-note:
66
+ en: e67f633dc6fe7773
67
+ zh: e88aeb617ffb74ea
package/README.md CHANGED
@@ -51,7 +51,7 @@ Pass the required options object as `{}` for a complete file under `maxFileBytes
51
51
 
52
52
  ### File-read and directory checks
53
53
 
54
- File reads and directory listing first use `lstat` to reject a missing path, a final symlink, or the wrong file kind. File operations then resolve and read through the composed filesystem without an additional workspace-containment check. Directory listing and watching require the resolved directory to remain inside the workspace root. The configured page, window, complete-file, and listing caps still apply. Text pages additionally reject invalid UTF-8 and NUL bytes; byte reads do not decode content. An empty read or listing path is a `gateway/bad-request`.
54
+ Every operation first uses `lstat` to reject a missing path or the wrong file kind; the file-reading operations also refuse a final symlink, even one pointing back inside the workspace. `list` instead follows a final link — a directory symlink on any platform, including a Windows junction — and requires it to resolve to a directory inside the workspace root, so a linked directory lists like its target; `changes` confines the watched directory the same way. File operations then resolve and read through the composed filesystem without an additional workspace-containment check. The configured page, window, complete-file, and listing caps still apply. Text pages additionally reject invalid UTF-8 and NUL bytes; byte reads do not decode content. An empty read or listing path is a `gateway/bad-request`.
55
55
 
56
56
  ### The change feed
57
57
 
package/README.zh.md CHANGED
@@ -51,7 +51,7 @@ kind: "package-reference"
51
51
 
52
52
  ### 文件读取与目录检查
53
53
 
54
- 文件读取和目录列举先通过 `lstat` 拒绝不存在的路径、末端符号链接或错误的文件类型。文件操作随后通过组合文件系统解析和读取,不做额外的工作区包含检查。目录列举和监听要求解析后的目录仍位于工作区内。配置的分页、窗口、完整文件和目录列举上限仍然适用。文本页还拒绝无效 UTF-8 与 NUL 字节;字节读取不解码内容。读取或列举的空路径是 `gateway/bad-request`。
54
+ 每项操作都先通过 `lstat` 拒绝不存在的路径或错误的文件类型;读取文件的操作还拒绝末端符号链接,包括指回工作区内的链接。`list` 改为跟随末端链接——任何平台上的目录符号链接,包括 Windows 目录联接——要求它解析为工作区内的目录,因此被链接的目录与其目标一样可列举;`changes` 也以同样方式把被监听的目录限制在工作区内。文件操作随后通过组合文件系统解析和读取,不做额外的工作区包含检查。配置的分页、窗口、完整文件和目录列举上限仍然适用。文本页还拒绝无效 UTF-8 与 NUL 字节;字节读取不解码内容。读取或列举的空路径是 `gateway/bad-request`。
55
55
 
56
56
  ### 变更流
57
57
 
package/lib/index.js CHANGED
@@ -493,11 +493,17 @@ let WorkspaceFiles = (() => {
493
493
  */
494
494
  async list(workspaceFileScope, path, signal) {
495
495
  const { root, workspaceRoot, entry } = await this.inspect(workspaceFileScope, path, signal);
496
- if (entry.type !== "directory") throw new RemoteError("workspace-file/not-directory", `"${path}" is a ${entry.type}`, {
496
+ if (entry.type !== "directory" && entry.type !== "symlink") throw new RemoteError("workspace-file/not-directory", `"${path}" is a ${entry.type}`, {
497
497
  path,
498
498
  kind: entry.type
499
499
  });
500
500
  const target = await this.confine(root, workspaceRoot, path, signal);
501
+ if (entry.type === "symlink") {
502
+ if ((await this.ctx.fs.stat(target, signal))?.type !== "directory") throw new RemoteError("workspace-file/not-directory", `"${path}" does not resolve to a directory`, {
503
+ path,
504
+ kind: "symlink"
505
+ });
506
+ }
501
507
  const children = await this.ctx.fs.listDir(target, signal);
502
508
  return {
503
509
  path: workspacePathOf(this.ctx.fs.fileUrl(root), this.ctx.fs.fileUrl(target)),
@@ -161,7 +161,7 @@ export const TYPERT = {
161
161
  typeSymbol: '@deepseek-ai/dsh-api-workspace-files/types#WorkspaceFileWatchFrame',
162
162
  create: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_changes_result$schema,
163
163
  },
164
- sourceLocation: {"file":"packages/api/workspace-files/src/index.ts","line":331,"column":3},
164
+ sourceLocation: {"file":"packages/api/workspace-files/src/index.ts","line":340,"column":3},
165
165
  },
166
166
  {
167
167
  id: '@deepseek-ai/dsh-api-workspace-files#workspaceFiles/list',
@@ -158,7 +158,7 @@ export const TYPERT_REMOTE = {
158
158
  typeSymbol: '@deepseek-ai/dsh-api-workspace-files/types#WorkspaceFileWatchFrame',
159
159
  create: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_changes_result$schema,
160
160
  },
161
- sourceLocation: {"file":"packages/api/workspace-files/src/index.ts","line":331,"column":3},
161
+ sourceLocation: {"file":"packages/api/workspace-files/src/index.ts","line":340,"column":3},
162
162
  },
163
163
  {
164
164
  id: '@deepseek-ai/dsh-api-workspace-files#workspaceFiles/list',
@@ -261,10 +261,19 @@ let WorkspaceFiles = (() => {
261
261
  */
262
262
  async list(workspaceFileScope, path, signal) {
263
263
  const { root, workspaceRoot, entry } = await this.inspect(workspaceFileScope, path, signal);
264
- if (entry.type !== 'directory') {
264
+ // A final link — a Windows junction or a symlink — is listed through the
265
+ // directory it resolves to, matching the child type `listDir` reports for
266
+ // that entry; `read` keeps its own no-follow gate on the final component.
267
+ if (entry.type !== 'directory' && entry.type !== 'symlink') {
265
268
  throw new RemoteError('workspace-file/not-directory', `"${path}" is a ${entry.type}`, { path, kind: entry.type });
266
269
  }
267
270
  const target = await this.confine(root, workspaceRoot, path, signal);
271
+ if (entry.type === 'symlink') {
272
+ const info = await this.ctx.fs.stat(target, signal);
273
+ if (info?.type !== 'directory') {
274
+ throw new RemoteError('workspace-file/not-directory', `"${path}" does not resolve to a directory`, { path, kind: 'symlink' });
275
+ }
276
+ }
268
277
  const children = await this.ctx.fs.listDir(target, signal);
269
278
  return {
270
279
  path: workspacePathOf(this.ctx.fs.fileUrl(root), this.ctx.fs.fileUrl(target)),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-api-workspace-files",
3
3
  "description": "Workspace file service and Client resource provider: bounded reads, directory listing, and live metadata over the workspaceFiles Remote namespace",
4
- "version": "0.1.7-rc.1",
4
+ "version": "0.1.7-rc.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -49,25 +49,25 @@
49
49
  "license": "MIT",
50
50
  "dependencies": {
51
51
  "zod": "^4.4.3",
52
- "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.1",
53
52
  "@deepseek-ai/schemastery": "~3.18.4",
54
- "@deepseek-ai/dsh-deque": "0.1.7-rc.1"
53
+ "@deepseek-ai/dsh-deque": "0.1.7-rc.2",
54
+ "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2"
55
55
  },
56
56
  "peerDependencies": {
57
57
  "@deepseek-ai/cordis": "~4.0.4"
58
58
  },
59
59
  "devDependencies": {
60
- "@deepseek-ai/dsh-api-gateway": "0.1.7-rc.1",
61
- "@deepseek-ai/dsh-client-connection": "0.1.7-rc.1",
62
60
  "@deepseek-ai/cordis": "~4.0.4",
63
- "@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.1",
64
- "@deepseek-ai/dsh-client-resources": "0.1.7-rc.1",
65
- "@deepseek-ai/dsh-fs": "0.1.7-rc.1",
66
- "@deepseek-ai/dsh-remote-mock": "0.1.7-rc.1",
67
- "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.1",
68
- "@deepseek-ai/dsh-session": "0.1.7-rc.1",
69
- "@deepseek-ai/dsh-session-persistence": "0.1.7-rc.1",
70
- "@deepseek-ai/dsh-util-workspace-path": "0.1.7-rc.1"
61
+ "@deepseek-ai/dsh-client-resources": "0.1.7-rc.2",
62
+ "@deepseek-ai/dsh-api-gateway": "0.1.7-rc.2",
63
+ "@deepseek-ai/dsh-fs": "0.1.7-rc.2",
64
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.2",
65
+ "@deepseek-ai/dsh-client-connection": "0.1.7-rc.2",
66
+ "@deepseek-ai/dsh-remote-mock": "0.1.7-rc.2",
67
+ "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2",
68
+ "@deepseek-ai/dsh-session": "0.1.7-rc.2",
69
+ "@deepseek-ai/dsh-session-persistence": "0.1.7-rc.2",
70
+ "@deepseek-ai/dsh-util-workspace-path": "0.1.7-rc.2"
71
71
  },
72
72
  "files": [
73
73
  "lib/index.js",