Back to catalog

modestoma /

dsh-webfile

Verified

S3 & FTP file tools for DeepSeek Harness: 8 agent tools (list, stat, mkdir, delete, move, copy, download, upload) — approval-gated mutations, transfer jobs with progress & cancel.

0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
READMESource: main@69f29901

dsh-webfile

English | 中文

S3 & FTP file tools for DeepSeek Harness: 8 agent tools (list, stat, mkdir, delete, move, copy, download, upload) — approval-gated mutations, transfer jobs with progress & cancel.

Let your agent browse and manage files on S3 (including MinIO and compatible object stores) and FTP/FTPS directly in conversation:

  • Read-only pass-through: webfile_list / webfile_stat never require approval;
  • Per-call approval for mutations: the other 6 tools ask the user before every call — a rejection means zero side effects;
  • Transfers run as background jobs: download/upload stream progress into the Jobs panel and can be cancelled at any time;
  • Credentials by reference only: secret values never enter config or the session log; rotations take effect on the next call.

Install

dsh plugin --profile <name> add dsh-webfile

The package declares dsh.bundle, so installing auto-mounts it into the profile's layer stack — no manual rows needed. To upgrade:

dsh plugin --profile <name> update

Configuration

Override the plugin config by id in the profile's cordis.patch.yml ($DSH_HOME/profiles/<name>/cordis.patch.yml):

- id: dsh-webfile
  config:
    connections:
      prod-logs:
        protocol: s3
        endpoint: https://oss.example.com   # omit for AWS public cloud
        region: cn-north-1
        bucket: prod-logs
        pathStyle: true                     # required for MinIO
        accessKeyRef: OSS_ACCESS_KEY        # credential reference name, see below
        secretKeyRef: OSS_SECRET_KEY
      legacy-ftp:
        protocol: ftp
        host: ftp.example.com
        port: 21
        userRef: FTP_USER
        passwordRef: FTP_PASSWORD
        tls: explicit                       # none | explicit | implicit
    maxTransferBytes: 2147483648            # per-file transfer cap, default 2 GiB
    multipartThresholdBytes: 67108864       # S3 multipart threshold, default 64 MiB

Connection fields

Field Protocol Notes
protocol both s3 or ftp (required)
endpoint s3 Custom endpoint (MinIO etc.); omit for AWS public cloud
region s3 Region (required)
bucket s3 Default bucket
pathStyle s3 Path-style addressing; MinIO needs true
accessKeyRef / secretKeyRef / sessionTokenRef s3 Credential reference names, see below
host ftp Server address (required)
port ftp Default 21; 990 for implicit FTPS
userRef / passwordRef ftp Credential reference names; omit for anonymous login
tls ftp none / explicit / implicit (required)
passive ftp Default true; only passive mode is supported

Patch semantics

  • Target by id: patch rows without an id are skipped with a warning;
  • Whole-value replace: config shallow-replaces the entire value; omitted fields fall back to schema defaults;
  • Do not re-mount: never insert another row with the same name in the user layer — configure through id overrides only;
  • Disable: - id: dsh-webfile / disabled: true turns the plugin off for that profile;
  • Hot reload: long-lived surfaces watch this file — saving replays the patch transactionally via HMR, no restart needed; a parse failure fails loud and keeps the last good tree.

Credentials

The config only holds credential reference names (environment-variable names, POSIX identifiers). Secret values live in $DSH_HOME/.credentials.yaml:

OSS_ACCESS_KEY: AKIAxxxxxxxx
OSS_SECRET_KEY: xxxxxxxxxxxx
FTP_USER: logbot
FTP_PASSWORD: xxxxxxxx
  • Four-layer precedence: process environment > credentials file > project .env > user .env; the process environment is read-only and shadows same-named file entries;
  • Hot publish: the file is watched (100 ms debounce) — an external edit takes effect on the next tool call, zero-restart rotation;
  • Format: strictly a reference: string value map (not dotenv syntax); values must be non-empty; file permissions must be 0600;
  • Secret values never enter the config surface or the session log.

Tools

Tool Parameters Approval Background job
webfile_list connection · remotePath · maxEntries (default 200, cap 1000) · nextToken none no
webfile_stat connection · remotePath none no
webfile_mkdir connection · remotePath required no
webfile_delete connection · remotePath · recursive (default false) required no
webfile_move connection · sourcePath · targetPath · overwrite (default false) required no
webfile_copy connection · sourcePath · targetPath · overwrite (default false) required no
webfile_download connection · remotePath · localPath (optional; defaults to mirroring under the workspace root) required yes
webfile_upload connection · localPath · remotePath · overwrite (default false) required yes

Semantics

  • S3 has no real directories: directories are key-prefix aggregations; mkdir writes a zero-byte key/ marker; stat synthesizes a directory for prefixes that have children but no object of their own.
  • List pagination: truncated results return truncated: true plus a nextToken (S3 ContinuationToken passthrough) — pass it back to continue; FTP has no server-side continuation, so retry with a larger maxEntries.
  • Overwrite protection: overwrite defaults to false; an existing target raises WEBBUF_EXISTS with a hint to enable it.
  • Recursion protection: delete refuses non-empty directories with WEBBUF_DIR_NOT_EMPTY; recursive: true deletes the whole subtree.
  • Transfer cap: maxTransferBytes (default 2 GiB) is checked before the operation starts; oversized transfers raise WEBBUF_TOO_LARGE with zero remote side effects.
  • S3 large uploads: at or above multipartThresholdBytes (default 64 MiB) uploads use multipart with monotonic progress.
  • Cancellation: killing a transfer job aborts the stream, removes the local half-file, and settles the job as killed.
  • S3 directory move/copy: per-object copy (+delete) — large directories are slow and an interruption can leave a half-moved state, which the tool description and approval reason state explicitly.
  • FTP symlinks: surfaced as type=link; recursive delete removes the link itself and never follows it; copy refuses symlinks outright.

Web transfer card

In the Web GUI, every download / upload opens a transfer card in the chat flow (webfile-transfer conversation node): direction, label, a live status dot (animated while transferring), elapsed time, source/target paths, and the terminal result. Data comes in two layers:

  • Durable layer: the host half records webfile/transfer-start / webfile/transfer-end session events around each transfer, which place the card in the message flow and let it replay the terminal state even after the registry drops the job.
  • Live layer: the client renderer reads the job's live status, timestamps, and terminal detail from the jobsBySession mirror, falling back to the durable events once the registry drops it.

The card ships through the dsh.client declaration (package.jsondsh.client + exports["./client"]); pnpm build emits lib/client.js. It only appears when the composing profile includes this package and the Web server has restarted and the page refreshed (the client plugin table is scanned at boot). Outside a Web composition it costs nothing: events are still recorded and the model-facing Jobs panel is unchanged.

Security notes

  • Per-call authorization: every mutation asks independently — no session-wide exemptions; allowed-once is the only grant.
  • Fail closed: with no approval channel (e.g. pure headless without an answerer) or with session policy approval/policy: never, mutation tools are always denied — never silently allowed.
  • Session log: tool arguments (connection id, remotePath, …) enter the session log with the call — mind paths that are sensitive; secret values never do.
  • S3 CopyObject cannot be aborted: server-side copies, once issued, cannot be cancelled — relevant for large directory move/copy.
  • Downloads land through ctx.fs into the workspace, governed by the DSH file sandbox policy.

Error codes

Code Meaning
WEBBUF_UNKNOWN_CONNECTION Connection id not configured (message lists the available ids)
WEBBUF_CREDENTIAL_MISSING A declared credential reference has no value (message names the variable)
WEBBUF_NOT_FOUND Path does not exist
WEBBUF_EXISTS Target exists and overwrite: false
WEBBUF_DIR_NOT_EMPTY Non-empty directory and recursive: false
WEBBUF_PATH_TRAVERSAL Path contains .. or is absolute
WEBBUF_TOO_LARGE Exceeds maxTransferBytes
WEBBUF_PROTOCOL_ERROR Protocol-level error (e.g. FTP refusing to follow a symlink)

Compatibility

  • Node: ^22.19.0 || >=24.0.0 (aligned with DeepSeek Harness).
  • S3: any object store implementing ListObjectsV2 / HeadObject / GetObject / PutObject / DeleteObject(s) / CopyObject / multipart (AWS, MinIO, and S3-compatible services).
  • FTP/FTPS: MLSD-capable servers yield the fullest listings (precise timestamps); older LIST-only servers work but lack time fields and infer directory types from permissions; both explicit and implicit TLS are supported.
  • One short-lived connection per operation in v1 (no pooling) — extremely high-frequency workloads are a later milestone.

Development

The committed manifest and lockfile use registry packages so local development and CI resolve the same dependency graph:

pnpm install
pnpm check   # build + lint + tests

For cross-repository development, use pnpm link <package-dir>... to replace selected packages in node_modules without editing package.json or pnpm-lock.yaml.

Commit convention: <type>(<scope>): <summary>. The lefthook commit-msg hook enforces local commits after pnpm exec lefthook install; CI applies the same rule to pull request titles.

Releasing: fully automated via semantic-release — every merge to main analyzes the conventional commit history, bumps the version (fix → patch, feat → minor, e.g. 0.1.1 → 0.2.0), publishes to npm, pushes a version tag, and files a GitHub Release whose notes are generated from the commits. The source manifest intentionally remains at 0.0.0; the Git tag is the version record.

The first publish needs a granular automation token in the NPM_TOKEN GitHub Actions secret. Once the package exists, configure npm Trusted Publishing for modestoma/dsh-webfile and workflow ci.yml, then delete the secret and its workflow environment entry. Later publishes use short-lived OIDC credentials and carry npm provenance attestations.

License

MIT © 2026 modesto

/ 5

No ratings yet

Community comments

No comments yet. Be the first to write one.