fix(fs): quote a listed name only when it would misreport the listing

The review made every name a JSON string with `<`, `>`, and `&` escaped. The
hazards behind that are real and each is now covered: a control character
splits one entry across lines, `</` closes the envelope, and a regular file
named `x@` reads as a socket named `x` under the non-regular marker.

Quote those, and only those. `list` is the tool an agent reaches for first
and its output sits in every transcript, so `"archive"/` on every ordinary
line is a permanent cost for a case that almost never occurs. A name is now
emitted verbatim unless it matches a control character, a leading quote, a
backslash, `</`, or a trailing `@`, and is otherwise a JSON string with `</`
neutralized — the delimiter treatment `dsh-workspace-context` already applies
to instruction text, extended to an interpolated path as its
`instruction-frame-paths` TODO asks.
This commit is contained in:
NI0317
2026-07-28 13:16:24 +08:00
parent 717852423f
commit 451c21a5b6
10 changed files with 61 additions and 35 deletions

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-07-27-directory-listing-tool.md
2026-07-27-directory-listing-tool.md: a23cdb0090f1a88b783d9717aa3f0434b6c2782e
2026-07-27-directory-listing-tool.zh.md: bab0138a79ae770ae7e841392b879940e8ac2dc4
2026-07-27-directory-listing-tool.md: fd8e8fb22d0b75a4d457e800296fa3ce2c2b5bd5
2026-07-27-directory-listing-tool.zh.md: 7d4e797878858ea1ca09f1eea6c6a3953c9abae6

View File

@@ -62,7 +62,7 @@ Three presentation rules carry the decision:
- **Directories sort first, then files, then non-regular children, each alphabetically** before paging, so every offset traverses one stable order and the first page keeps navigable structure.
- **The canonical value and Native result carry one recoverable page** of at most `listMaxEntries` (default 200, configurable). The footer states the complete size and composition and gives `offset=<next>` until the final page, so omitted sibling names remain reachable.
- **Filesystem text cannot forge presentation structure.** The path and entry names render as JSON strings with envelope-significant characters escaped; directory `/` and non-regular `@` markers sit outside the quoted name, so a regular filename ending in `@` remains distinguishable.
- **Filesystem text cannot forge presentation structure.** A name is emitted verbatim unless it would make the listing lie — a control character splitting one entry across lines, `</` closing the envelope, a trailing `@` colliding with the non-regular marker — and is then a JSON string with `</` neutralized. Quoting only when needed keeps the tool an agent reaches for first legible in every transcript, while leaving the format unambiguous.
`list` emits no `fs/observed`. Seeing a filename is not reading a file, and a listing must never satisfy the read-before-write gate that `@deepseek-ai/dsh-fs-policy` enforces. It declares `isConcurrencySafe`, because it mutates nothing at all.

View File

@@ -62,7 +62,7 @@ instead of taken in modification-time order. Full sorted result stored at: …)
- **先目录、再文件、最后非常规子项,各组内按字母序**,然后再分页,使每个 offset 都遍历同一稳定顺序,且第一页保留可导航的结构。
- **规范值和 Native 结果携带一个可继续取回的页面**,最多包含 `listMaxEntries` 个条目(默认 200可配置。footer 会说明完整规模与构成,并在最后一页之前给出 `offset=<next>`,因此被省略的同级名称仍可取回。
- **文件系统文本无法伪造展示结构。** 路径和条目名渲染为 JSON 字符串,并转义对包络有意义的字符;目录 `/` 与非常规子项 `@` 标记位于带引号名称之外,因此以 `@` 结尾的常规文件名仍可区分
- **文件系统文本无法伪造展示结构。** 条目名默认原样输出;只有当它会让列出结果失真时才转为 JSON 字符串并中和 `</`——控制字符会把一个条目拆成两行、`</` 会关闭包络、结尾 `@` 会与非常规标记撞车。只在必要时加引号,既让这个 agent 最先使用的工具在每份 transcript文本记录里保持可读又让格式无歧义
`list` 不发出 `fs/observed`。看到文件名不等于读过文件,列出绝不能满足 `@deepseek-ai/dsh-fs-policy` 施加的编辑前读取门禁。它声明 `isConcurrencySafe`,因为它完全不做任何变更。