Skip to content
dsh.fish
Bundle

dsh-plugin-md-outline

DeepSeek Harness plugin: outline and lint Markdown document structure (heading tree, level skips, duplicate headings, unclosed code fences).

Source
d-ouyang
stars
2 stars
License
MIT
Updated
Updated 17 hours ago

Readme

# dsh-plugin-md-outline

> πŸ‡¨πŸ‡³ [δΈ­ζ–‡ζ–‡ζ‘£](README.zh-CN.md)  |  πŸ‡ΊπŸ‡Έ **English**

A **minimal but practical** DeepSeek Harness plugin that adds an `md_outline` tool.
It outlines and lints Markdown documents: a nested heading tree plus structural
warnings that are tedious to check by hand and easy to get wrong in long docs
(book drafts, skill sets, specs).

> Topic: **`dsh-plugin`** β€” add this topic to the GitHub repo so the ecosystem
> can discover it (see [Publishing the `dsh-plugin` topic](#publishing-the-dsh-plugin-topic) below).

## What it does

| Check | Why it matters |
|---|---|
| Heading tree (H1–H6, with line numbers) | Navigate and audit long documents at a glance. |
| Heading-level skips (e.g. H1 β†’ H3) | Catches broken document hierarchy. |
| Duplicate heading text | Flags accidental repeats that break anchors/TOC. |
| Missing H1 / multiple H1 | Enforces a single document title. |
| **Unclosed code fences** | The classic long-doc bug β€” a fence left open makes everything after it "code". Headings inside fences are correctly ignored. |

## Preview

Terminal preview from `node examples/run.mjs` (covers all 5 sample docs
β€” clean, level skip, duplicate headings, multiple H1, unclosed fence):

![Preview](docs/screenshot.png)

### What a bad doc looks like β€” `examples/level-skip.md`

The left side is the source as written; the right side is what `md_outline` reports.
The H1 β†’ H3 jump on line 3 is flagged with line number and reason.

![Level-skip comparison](docs/level-skip-compare.png)

To regenerate: `python3 docs/gen_screenshot.py` (writes `docs/screenshot.png`).

## Install

**One-click install** (any machine, any profile):

```sh
dsh plugin add https://github.com/d-ouyang/dsh-plugin-md-outline.git
dsh --profile demo --dump-config | grep -i md-outline   # confirm the layer is present
```

Requires the `dsh` CLI (DeepSeek Harness). This plugin is **plain ESM JavaScript**:
no build step, no `allowBuilds` prompt, installs straight from a git repo.

Local checkout also works:

```sh
dsh plugin --profile demo add /path/to/dsh-plugin-md-outline
```

To remove:

```sh
dsh plugin remove dsh-plugin-md-outline
```

## Usage

In the Web UI (or any surface with tools), just ask the model:

> Outline `~/book/draft.md` and tell me about structural issues.

Or call it directly in Code Mode:

```ts
await tools.md_outline({ path: '~/book/draft.md', mode: 'both' })
await tools.md_outline({ path: '~/skills', mode: 'lint', recursive: true })
await tools.md_outline({ path: '~/notes/spec.md', mode: 'outline', maxDepth: 2 })
```

### Parameters

| Name | Type | Required | Notes |
|---|---|---|---|
| `path` | string | yes | A `.md`/`.markdown`/`.mdx` file, or a directory. |
| `mode` | `'outline' \| 'lint' \| 'both'` | no | Default `both`. |
| `maxDepth` | number (1–6) | no | Limit outline nesting. |
| `recursive` | boolean | no | Scan subdirectories when `path` is a dir (default `true`). |

The canonical return value is structured (`{ files, summary }`) for programmatic
use in Code Mode; the model-facing card shows the human-readable `summary`.

## How it is built (cookbook recap)

This plugin follows the official authoring path:

1. **Tool contract** β€” `docs/user/develop/basic/tool.md` and
   `docs/cookbook/adding-a-tool.md`: `defineTool({ name, description, parameters,
   output, execute })` registered via `ctx.tools.register(...)`.
2. **Bundle packaging** β€” `docs/user/develop/basic/publish.md`: a bundle is an npm
   package with a `dsh.bundle` manifest and a `cordis.patch.yml` layer that inserts
   the plugin row by package name.
3. **No build** β€” written in plain ESM JavaScript so a `github:` install loads
   without running any `prepare` script.

```
dsh-plugin-md-outline/
β”œβ”€β”€ package.json        # dsh.bundle manifest + peer dep on @deepseek-ai/dsh-tools
β”œβ”€β”€ cordis.patch.yml    # the layer applied when a profile adds this bundle
β”œβ”€β”€ index.js            # plugin entry: name / inject / apply -> registers md_outline
β”œβ”€β”€ md-outline-core.js  # pure, dependency-free analysis (unit-tested)
β”œβ”€β”€ test.mjs            # `node test.mjs` validates the core logic
β”œβ”€β”€ examples/           # sample docs + run.mjs (real output shown in docs/USAGE.md)
β”œβ”€β”€ docs/USAGE.md       # πŸ‡¨πŸ‡³ full usage guide with real test results
β”œβ”€β”€ README.md
└── README.zh-CN.md
```

## Develop

```sh
node test.mjs                 # unit-test the pure logic
node examples/run.mjs         # run all sample docs and print real outlines + warnings
node --check index.js        # syntax check the plugin entry
```

See [docs/USAGE.md](docs/USAGE.md) (δΈ­ζ–‡) for the full usage guide and real test output.

The runtime contract depends on `@deepseek-ai/dsh-tools` being present in the dsh
installation (it is β€” the harness itself uses it). Declared as a `peerDependency`,
so it is never fetched from a registry.

## Publishing the `dsh-plugin` topic

The `dsh-plugin` GitHub topic is what makes community plugins discoverable. Add it
in **repo Settings β†’ Topics**, or via the API once the repo exists:

```sh
# after `git push`, set the topic through the GitHub API (needs a token)
curl -X PUT -H "Authorization: Bearer $GITHUB_TOKEN" \
  -H "Accept: application/vnd.github+json" \
  https://api.github.com/repos/d-ouyang/dsh-plugin-md-outline/topics \
  -d '{"names":["dsh-plugin","markdown","deepseek-harness"]}'
```

## License

MIT

Install

dsh plugin --profile web add github:d-ouyang/dsh-plugin-md-outline

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source