Conflict resolution notes: - package.json/run-gates: both sides' new doc-sync gates kept (master's scoped-events/readme gates + this branch's website-api/website-yaml); js-yaml devDeps deduped (master added them independently). - pnpm-workspace/knip: website AND python/sdk-runtime entries kept. - doc-typecheck/verify-type-equiv: master's condensed headers kept, website glob retained in both scan scopes. - vendor/cordis/src/fiber.ts: master's lifecycle-hardening code taken; this branch's richer FiberState JSDoc reapplied on top. vendor/README.md logs both local modifications (hardening = 6, JSDoc enrichment = 7). - pnpm-lock: regenerated from master's side (pnpm install). Post-merge sync the gates forced (the system working as designed): - verify-website-yaml caught 4 stale plugin names from master's package reorg (dsh-stdio-agent -> dsh-stdio-demo, dsh-acp-agent -> dsh-acp-demo); 8 references fixed across guide/ and develop/. - gen-website-api picked up master's 6 new services automatically (ctx.approval/permission/sandbox/sessionQuery/skills/tasks -> 6 new pages + sidebar); api/index.md hub updated to list them. - AGENTS.md budget ceiling 1370 -> 1400: the website rows (layout line + two command lines) and master's own growth collided with the old ceiling; all three website rows are load-bearing (new top-level dir, new CI command).
4.8 KiB
ctx.fs
FileSystem (abstract seam) — provided by @deepseek-ai/dsh-fs.
Abstract filesystem provider. Targets must preserve identity across aliases; reads expose regular UTF-8 text or typed errors, listings are stable and content-free, and mutations are atomic. Optional guards add stale protection without changing the unguarded provider contract.
ctx.fs.resolve(path, opts?)
abstract resolve(path: string, opts?: { cwd?: string }): Promise<FsTarget>
Resolve a model/plugin-supplied path into a stable FsTarget. May perform I/O (a remote/sandboxed backend may need a round-trip to map a path to a stable identity), hence async even though the local backend only normalizes + realpaths.
path— the path to resolve; relative paths resolve againstopts.cwd.opts—cwdoverrides the backend's default base for relative paths.
Returns the stable target; the same file yields the same targetKey.
ctx.fs.stat(target, signal?)
abstract stat(target: FsTarget, signal?: AbortSignal): Promise<FsInfo | undefined>
Return target metadata, or undefined when the target does not exist.
target— the resolved target to stat.signal— aborts the metadata round-trip.
Returns metadata only, never content; undefined for an absent target.
ctx.fs.readText(target, signal?)
abstract readText(target: FsTarget, signal?: AbortSignal): Promise<string>
Read the whole regular text file as a single decoded string.
target— the resolved target to read.signal— aborts the read.
Returns the full decoded UTF-8 content.
ctx.fs.streamText(target, signal?)
abstract streamText(target: FsTarget, signal?: AbortSignal): Promise<AsyncIterable<string>>
Stream the whole regular text file as decoded text chunks (same text semantics as readText, for large files). The backend owns cross-chunk UTF-8 decoding and binary rejection so the policy layer never touches raw bytes.
target— the resolved target to read.signal— aborts the stream, including between chunks.
Returns the chunk iterable, decoded and validated like readText.
ctx.fs.listDir(target, signal?)
abstract listDir(target: FsTarget, signal?: AbortSignal): Promise<FsDirEntry[]>
List direct children of a directory in stable name order. Returns resolved child targets plus cheap metadata only; never reads file contents.
target— the resolved directory target.signal— aborts the listing.
Returns one entry per direct child, in stable name order.
ctx.fs.writeText(target, content, expected?, signal?)
abstract writeText(target: FsTarget, content: string, expected?: FsWriteIntent, signal?: AbortSignal): Promise<FsWriteOutcome>
Atomically create or replace UTF-8 text. expected guards intent and staleness; omission allows unconditional overwrite.
target— the resolved target to write.content— the full new file content.expected— the write intent guarding the write; omit for unconditional.signal— aborts before the atomic rename takes effect.
Returns the outcome, including the version the write produced.
ctx.fs.editText(target, edit, expected?, signal?)
abstract editText(target: FsTarget, edit: FsEditRequest, expected?: { version: FsVersion }, signal?: AbortSignal): Promise<FsEditOutcome>
Atomically edit literal text. When supplied, the version guard is checked before matching so stale content reports FS_STALE_VERSION; omission edits the current content without a freshness precondition.
target— the resolved target to edit.edit— the literal search/replace request.expected— the version guard; omit for an unconditional edit.signal— aborts before the atomic rename takes effect.
Returns the outcome, including the version the edit produced.