Bundle
dsh-npm-runner
DeepSeek Harness plugin: discovers the npm/pnpm/yarn/bun scripts of the current workspace (never descending into node_modules) and runs any of them in the background from a compact control in the composer area or the session header.
- Source
- nobu121
- License
- MIT
- Updated
- Updated 14 hours ago
Readme
# dsh-npm-runner
[](https://github.com/nobu121/dsh-npm-runner/actions/workflows/ci.yml)
[](https://www.npmjs.com/package/dsh-npm-runner)
A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) plugin that finds the npm scripts of the current workspace and runs any of them in the background.
- **Finds the scripts without walking `node_modules`** — the workspace root manifest, plus the packages its `workspaces` field declares or its immediate subdirectories.
- **One collapsible group per package**, like VS Code's NPM Scripts view, with the folded shape remembered per workspace.
- **Runs in the background**, with live output, elapsed time, and a **Stop** that reaps the whole process tree.
- **Uses each package's own package manager** (`pnpm`, `yarn`, `bun` or `npm`, from the lockfiles present) in each package's own directory.
- **Shows nothing when there is nothing to show.**
## Requirements
DSH `0.1.5-rc.1` or newer, and Node.js 20 or newer.
## Install
```sh
dsh plugin --profile web add -w dsh-npm-runner
```
`-w` is not optional: the profile directory is a pnpm workspace root, and pnpm refuses an `add` there without it.
To track the repository instead of a release:
```sh
dsh plugin --profile web add -w github:nobu121/dsh-npm-runner
```
Update or remove:
```sh
dsh plugin --profile web update -w dsh-npm-runner
dsh plugin --profile web remove dsh-npm-runner
```
**Restart DSH afterwards** — a newly added bundle is picked up at profile boot, not by a page refresh.
Working on the plugin itself? `dsh plugin --profile web add -w .` from the checkout links the working tree instead of taking a snapshot.
## Usage
| Session state | Where it appears |
| --- | --- |
| New session | Right-aligned on the workspace/mode row. |
| Conversation | In the header's action row, next to DSH's own background-task list. |
The control appears only when the current workspace has at least one script. Clicking it opens the script list:
- **One collapsible group per package**, labelled with the directory its scripts run in and a script count. With several packages there are also **Collapse all** / **Expand all**.
- **One row per script**, showing the name and the command it expands to. Clicking starts it in the background and expands its live output.
- **A running script** shows a status dot and elapsed time, with **Stop** to reap it. A dot on the trigger means something is running, so the state stays visible with the list closed.
- **The list is per workspace**: every run of the current workspace, including ones started from another conversation, and nothing from another project.
- **Clear finished**, on the **Background runs** header, drops completed, failed and stopped runs and leaves live ones alone.
## DSH background jobs
Runs are also registered with DSH's own background-job registry, so they join the job list and the agent can read them with `job_list` / `job_output` / `job_kill`.
Stopping a run from the panel marks it as accounted for, so DSH does not inject a *background job finished* notice into the session for a stop you asked for — a run that ends on its own still notifies. Set `registerJobs: false` to keep runs private to the plugin's own list.
## Configuration
Optional, on the plugin row in the profile's `cordis.patch.yml`:
```yaml
- id: npm-runner
name: 'dsh-npm-runner'
config:
maxPackages: 60 # packages reported per scan
maxJobs: 12 # retained runs; the oldest finished one is evicted first
maxRunning: 6 # concurrently live runs
bufferBytes: 65536 # retained output per run, in bytes
registerJobs: true # also register runs with DSH's background-job registry
jobScope: session # 'session' keeps a run inside its own conversation; 'global' shares it machine-wide
```
## Security
These routes start processes, so three limits apply: every request passes the same trust fence DSH's own gateway applies (loopback or a trusted `Host`, no cross-site, a matching `Origin`); the workspace comes from the Session rather than from the request; and a request cannot name a command — the client sends a directory and a script *name*, and the host re-reads that directory's own `package.json` and rebuilds `<packageManager> run <name>` itself. Runs start in the DSH host process, on the machine DSH runs on.
## Limitations
- **Clearing does not touch DSH's own job list.** DSH's background-task count keeps a finished entry until DSH restarts; its registry exposes no delete.
- **DSH's job list is not workspace-aware.** With the default `jobScope: 'session'`, a run does not appear there in another conversation, even one in the same workspace. The plugin's own list is the surface that matches by workspace.
- **The scanner never walks above the session's workspace**, and nothing is shown while no session is selected.
## Development
```sh
npm test # hermetic: scanner, runner, job bridge, host routes, client bundle
npm run test:e2e # really runs npm: the fixtures, the run lifecycle and the tree kill
```
`examples/` holds a second package of runnable fixtures — a long-lived service, a streamer, a high-volume writer, a process tree, a failure and a working-directory probe. It is not published, and `npm run test:e2e` drives all of it through the plugin's own registry.
## License
MIT
Install
dsh plugin --profile web add github:nobu121/dsh-npm-runner
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-npm-runner from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.