Files
deepseek-harness/docs/core-data-structures/filesystem.md
T

146 lines
4.8 KiB
Markdown

# Filesystem
The filesystem execution seam is split across three packages: interface ([dsh-fs](../../packages/fs/fs), `ctx.fs`), implementation ([dsh-fs-local](../../packages/fs/fs-local), local disk), and consumer ([dsh-tool-fs](../../packages/fs/tool-fs), the model-facing `read`/`write`/`edit` tools). Filesystem access is an optional capability, not part of the agent-loop spine, so its vocabulary lives here rather than in [core.md](core.md). A sandboxed, remote, virtual, or project-scoped backend can implement the same `FileSystem` service without changing the tool schemas.
Source: [`packages/fs/fs/src/types.ts`](../../packages/fs/fs/src/types.ts) and [`packages/fs/fs/src/index.ts`](../../packages/fs/fs/src/index.ts)
## Execution context and target identity
The filesystem seam needs just enough execution context to derive the observed-file owner. `ToolExecution` satisfies this shape, so `dsh-tool-fs` passes its execution object through without making `dsh-fs` import the tool, agent, or session packages.
```ts type-equiv
interface FsExecContext {
agent?: {
session?: object
}
}
```
Every operation resolves a user-supplied path to an opaque backend target first. Consumers may display `displayPath`, but must not parse `targetKey` or assume it is a local absolute path.
```ts type-equiv
interface FsTarget {
inputPath: string
targetKey: string
displayPath: string
}
```
The backend also owns file-version tokens. `ctx.fs` stores them for stale checks; consumers do not interpret them.
```ts type-equiv
type FsVersion = string
```
## Reads and editable views
A text read is bounded by line window, byte cap, and backend limits. The returned view records whether the owner saw the whole file or only a partial page; only a `full` view authorizes later write/edit.
```ts type-equiv
interface FsReadRequest {
offset: number
limit: number
}
```
```ts type-equiv
interface FsTextLine {
number: number
text: string
}
```
```ts type-equiv
type FsView = 'full' | 'partial'
```
```ts type-equiv
interface FsReadOutcome {
offset: number
limit: number
lines: FsTextLine[]
totalLines: number
truncatedByBytes?: true
version: FsVersion
view: FsView
}
```
## Write and edit guards
The base `FileSystem` service converts recorded state into an `FsExpectation` before calling the backend. `observed` carries the stale guard, `partial` means the owner saw a non-editable view, and `unobserved` allows create-if-absent but rejects blind overwrite.
```ts type-equiv
type FsExpectation =
| { kind: 'observed'; version: FsVersion }
| { kind: 'partial'; version: FsVersion }
| { kind: 'unobserved' }
```
```ts type-equiv
interface FsWriteOutcome {
operation: 'create' | 'update'
version: FsVersion
}
```
Literal edit is a backend operation, not a `read` plus `write` composed in the tool wrapper. That keeps matching, line-ending handling, stale checks, and atomic replacement inside the filesystem seam.
```ts type-equiv
interface FsEditRequest {
oldString: string
newString: string
replaceAll: boolean
}
```
```ts type-equiv
interface FsEditOutcome {
replacements: number
replaceAll: boolean
version: FsVersion
}
```
## Observed-file state
Observed state is keyed inside the service by owner object and `FsTarget.targetKey`. The owner is normally `exec.agent.session`, but `dsh-fs` treats it as opaque and never reads its fields. A successful read/write/edit refreshes this state for that owner.
```ts type-equiv
type FsStateSource = 'read' | 'write' | 'edit'
```
```ts type-equiv
interface FileState {
targetKey: string
displayPath: string
version: FsVersion
view: FsView
updatedAt: number
source: FsStateSource
}
```
## Error taxonomy
Filesystem failures use stable `FsErrorCode` strings carried by `FsError` (`HarnessError`). The tool registry preserves `{ name, code }` on error results, so retry, permission, and UI layers can branch without parsing text.
```ts type-equiv
type FsErrorCode =
| 'FS_NOT_FOUND'
| 'FS_NOT_TEXT'
| 'FS_NOT_REGULAR_FILE'
| 'FS_STALE_VERSION'
| 'FS_NOT_OBSERVED'
| 'FS_PARTIAL_OBSERVATION'
| 'FS_AMBIGUOUS_EDIT'
| 'FS_EDIT_NOT_FOUND'
| 'FS_ABORTED'
```
`FS_NOT_OBSERVED` means no usable prior observation exists. `FS_PARTIAL_OBSERVATION` means the owner saw only a partial read. `FS_STALE_VERSION` means there was a prior full observation, but the backend version no longer matches.
## The service
`FileSystem` (`ctx.fs`, abstract) owns the shared orchestration: `resolve`, `readPage`, `createOrReplace`, and `applyEdit` are backend primitives; public `read`, `write`, and `edit` derive/record owner state and enforce the read-before-write/edit policy before delegating to the backend. The generated wiring catalog shows the exact service signatures on [events-and-services.md](../cordis-catalog/events-and-services.md#ctxfs--filesystem-abstract-seam).