# πŸ‹ Whale Catch Β· dsh-whale-catch > **Zero registration.** Every file this session produced swims into the basket on its own. English | [δΈ­ζ–‡](README.md) A right-sidebar plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH): it collects the files a session produced or changed into one basket, so you can preview them, bundle them into a zip, or archive them in one click. [![CI](https://github.com/Rosynb666/dsh-whale-catch/actions/workflows/ci.yml/badge.svg)](https://github.com/Rosynb666/dsh-whale-catch/actions/workflows/ci.yml) [![Release](https://github.com/Rosynb666/dsh-whale-catch/actions/workflows/release.yml/badge.svg)](https://github.com/Rosynb666/dsh-whale-catch/actions/workflows/release.yml) ![license](https://img.shields.io/badge/license-MIT-blue) ![DSH](https://img.shields.io/badge/DSH-%E2%89%A5%200.2.0--rc.2-4c8bf5) ![node](https://img.shields.io/badge/node-%E2%89%A5%2022.19-3c873a) ![deps](https://img.shields.io/badge/runtime%20deps-1%20(schemastery)-blue) ![build](https://img.shields.io/badge/build%20step-none-brightgreen) --- ## Why Working with DSH, "where did that file go?" is routine: - The built-in deliverables card only covers the **current turn** β€” scroll a few screens and it is gone. - Files written by `python build_doc.py` inside `bash` are neither a file-tool edit nor a `present` call, so neither mechanism sees them. - Sending a dozen deliverables somewhere means digging through the workspace and hoping nothing was missed. Whale Catch does exactly three things: **collect automatically**, **show in one place**, **zip / archive in one click**. ## How it differs from the built-in deliverables It does not reinvent the wheel: both `deliverables/presented` and `workspace/changes` are consumed as-is. It fills the gaps they leave. | | Built-in deliverables card | Whale Catch | |---|---|---| | Sources | `present` files + git / file-tool edits | the same two, **plus a directory-scan fallback** (bash, python, build scripts) | | Scope | one turn, shown at turn end | the whole session, across turns | | Actions | open source file | preview / zip / archive / copy path | | After a Host restart | change summaries live in memory and are lost | rebuilt from mtime (descriptions are lost, see limitations) | | Needs the agent to cooperate | yes, the model must call `present` | **no** | ## Install Requires DSH `>= 0.2.0-rc.2` and Node `^22.19 || >=24` (the Desktop runtime already satisfies both). ```sh # from GitHub (once the repo is published) dsh plugin --profile desktop add github:Rosynb666/dsh-whale-catch # from npm (once published) dsh plugin --profile desktop add dsh-whale-catch # local development dsh plugin --profile desktop add /absolute/path/to/dsh-whale-catch ``` Reload the page (⌘R), click `+` in the right sidebar and pick **β€œOpen Whale Catch”**. ```sh dsh plugin --profile desktop remove dsh-whale-catch ``` ## UI ```text β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ πŸ‹ Catch 12 files Β· 3.4 MB [Refresh] β”‚ β”‚ [All 12] [πŸ“„ Docs 7] [πŸ“Š Sheets 3] [πŸ–Ό 2] β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β˜‘ πŸ“„ lab-report.docx β”‚ β”‚ First lab Β· report.docx [Open] ⧉ β”‚ β”‚ 1.2 MB Β· 3 min ago Β· Delivered β”‚ β”‚ ☐ πŸ“Š training-plan.xlsx β”‚ β”‚ ☐ πŸ–Ό render-evidence.pdf β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ 2 selected [Archive] [Zip] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` - **Select** β†’ zip only the selected files; nothing selected means β€œzip everything”. - **Archive** β†’ copies into the archive directory, preserving relative paths, never overwriting (adds ` (2)`). - **Open** β†’ opens the original file in a new tab (images / PDF / text inline, Office downloads). - **⧉** β†’ copy the absolute path. ## How zero-registration works Three sources merged by absolute path: | Source | From | Covers | |---|---|---| | `presented` | `deliverables/presented` session event | files the model explicitly delivered, with description and turn | | `changed` | `workspace/changes` + `ctx.workspaceChanges.summary()` | git snapshots and file-tool edits | | `scanned` | a workspace scan (`mtime >= session creation`) | anything written by bash / python / build scripts | The scan is bounded: current cwd only, no symlinks, `node_modules` / `.git` / dot-directories skipped, with depth / count / size caps. See [docs/architecture.md](docs/architecture.md). ## Configuration Override in your own profile patch layer β€” do **not** edit the bundled `cordis.patch.yml`: ```yaml - id: dsh-whale-catch config: archiveDir: ~/Documents/whale-catch # ~ expands; default: $DSH_HOME/whale-catch/archive ignore: [dist, build, .venv] maxFiles: 800 maxDepth: 6 maxFileBytes: 67108864 lookbackMinutes: 720 ``` Hot reload picks it up; no restart needed. ## Security model These routes live on the loopback Host, so the threat model is *a third-party page in your browser*, not other local processes: - **Path allowlist** β€” `/file`, `/zip`, `/archive` only accept paths already in the basket; there is no arbitrary file read, and `../` is rejected at the allowlist. - **Same-origin fence** β€” a mismatched `Origin` or `Sec-Fetch-Site: cross-site` gets 403. - **Writes must be `application/json`** β€” cross-site forms cannot send it, and declaring it triggers a preflight that this route rejects with 415. - **Zip / archive hardening** β€” entry names drop `..` and leading slashes; archive writes verify the target stays under the archive root. - **Hard caps** β€” 64 MB per file, 512 MB per zip, 800 files, 1 MB request body. ## Known limitations - Current session **working directory** only (except absolute paths declared via `present`). - After a Host restart, `present` descriptions and turn numbers are gone; files reappear via mtime. - Files whose mtime predates the session are skipped. - The archive directory lives under `$DSH_HOME`; it does not sync to a cloud drive. - Preview relies on the browser: PDF / images / text inline, docx / xlsx download. ## Development ```sh npm install npm test # 35 tests: scan / merge / zip format / HTTP fence / client registration / plugin load npm run check # contract self-check (package shape, patch, client.inject, meta, icon, deps) npm run verify # both ``` No build step: `lib/index.js` is the Host half, `lib/client.js` is the browser half handed verbatim to `__ModuleLoader__`. The only runtime dependency is `@deepseek-ai/schemastery` (a pure validation library), declared as a real dependency on purpose: profiles pin `autoInstallPeers: false`, so a peer would never be installed in a clean profile and the Host half would fail to load. Architecture: [docs/architecture.md](docs/architecture.md) Β· Release checklist: [docs/publish.md](docs/publish.md) ## License [MIT](LICENSE)