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):

### 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.

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
With the hub plugin installed, ask your agent to install it by name β it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-plugin-md-outline from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.