# dsh-pdf

[中文](README.md) | English

PDF toolbox for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness): extract text, metadata, and page ranges from PDF files. Local parsing via [PDF.js](https://mozilla.github.io/pdf.js/) (pdfjs-dist) — no API key, no network.

## Features

- `pdf_read` tool: per-page text extraction with page markers.
- Page selection: `"1-3,5"` or `"all"` — read large documents in chunks.
- Document metadata (title) and total page count.
- Bounded by design: byte cap on the file, page cap per parse, character cap per call — truncation is explicit and tells the model how to continue.
- Reads through the harness filesystem seam (`ctx.fs`), so the deployment's permission and sandbox policy applies.

## Install

### From GitHub

```sh
dsh plugin --profile web add "github:sunshine-lang/dsh-pdf"
```

Then restart `dsh --profile web`. `lib/` is prebuilt and committed, so no build permission is needed.

### From npm (once published)

```sh
dsh plugin --profile web add dsh-pdf
```

### From a local checkout (development)

```sh
dsh plugin --profile web add ./dsh-pdf
```

> Note: pnpm installs the dependencies of a `link:`-style local dependency only if you add them to the profile yourself. A registry/GitHub install handles them automatically:
>
> ```sh
> dsh plugin --profile web add @deepseek-ai/dsh-tools @deepseek-ai/cordis @deepseek-ai/schemastery pdfjs-dist
> ```

## Use

Start the Web UI and ask the model, for example:

> Read the first 3 pages of `paper.pdf` and summarize them.
>
> What does page 7 of `contract.pdf` say?

The model calls `pdf_read` with `path` (required) and optionally `pages` (`"1-3,5"` or `"all"`). Large outputs stop at a page boundary with a note; the model continues with a page range.

## Configuration

Override any key through `cordis.patch.yml` or the profile's patch layer:

```yaml
- patch:
    - id: dsh-pdf
      config:
        maxFileBytes: 52428800
        maxPages: 200
        maxCharsPerCall: 20000
```

| Key | Default | Meaning |
| --- | --- | --- |
| `maxFileBytes` | `20971520` (20 MiB) | Inclusive byte cap on the whole PDF; larger files fail with a loud error. |
| `maxPages` | `500` | Maximum pages parsed in one call; larger documents truncate with a notice. |
| `maxCharsPerCall` | `12000` | Maximum characters returned by one call; the result truncates at a page boundary. |

Invalid configuration fails the load with an actionable error.

## Development

```sh
npm install        # or pnpm install
npm run build      # tsc → lib/
```

Rebuild from a DeepSeek Harness checkout (for type resolution against the workspace source) uses `tsconfig.local.json` instead: `tsc -p tsconfig.local.json`.

Tests: `tests/fixtures/sample.pdf` is generated by `make-test-pdf.mjs` (dependency-free); `w3-dummy.pdf` is the W3C dummy test file. Integration test: `node --import tsx/esm test-integration.ts` from a harness checkout.

## More plugins by this author

All DeepSeek Harness plugins by this author, in one place: [dsh-plugins](https://github.com/sunshine-lang/dsh-plugins)

## License

MIT.
