# dsh-workspace-combiner
Built for full-stack developers — bundle a frontend repo, a backend repo, and a docs
anchor into one AI session. Absolute paths injected, sandbox writable roots auto-synced,
API changes edited on both sides in the same conversation.
中文 · English
---
A [Cordis](https://github.com/cordiverse/cordis) dual-face plugin for DSH (DeepSeek
Harness) that turns a set of repositories into a coordinated **multi-workspace joint
development** context.
The current plugin manifest targets the DSH `0.2.0-rc.2` seam APIs and declares a peer
range (`>=0.2.0-rc.1 <0.3.0`) rather than exact versions, so later release candidates in
the same line load without a republish. `pnpm smoke:dsh-compat` guards that claim. Host
DSH services are not bundled into this plugin.
The plugin registers a **Workspace Combiner** tab in the left sidebar. Each *workspace*
bundles a primary directory (the "workspace anchor" — where docs and non-code assets
live) plus an ordered list of *code-project* directories (for example a backend repo and
a frontend repo). When you start a new session, the plugin injects the absolute paths of
all active directories into the system prompt and syncs the writable ones into the
[`dsh-write-protect`](https://github.com/azazo1/dsh-write-protect) whitelist.
To keep that injected context from exploding, the plugin applies a **four-layer
context-control** model:
1. **Directory layer** — per-directory access (`readwrite` / `readonly` / `disabled`),
primary anchoring, drag ordering.
2. **Config layer** — `anchor` / `single` workspace mode plus optional group tags.
3. **Load-mode layer** — `full` / `summary` / `tree` controlling how much file detail is
injected.
4. **Command layer** — `@`-command dynamic scope.
Layers 1-4 ship today; see [Changelog](./CHANGELOG.md) · [中文](./CHANGELOG.zh.md).
---
## Features
- **Workspaces** — create / rename / delete / switch named workspaces; each owns a
primary directory plus ordered code-project directories with per-directory access.
- **Workspace readiness report** — a compact status in the header summarizes directory
validity, detected frontend/backend projects, writable roots, Git changes, paired
endpoints, project commands, context budget, and attached sessions. Open it for
blocking issues and actionable suggestions.
- **Start-task wizard** — describe a feature, API change, bug fix, code review,
cross-repository refactor, or custom task. Only complete Exact/Normalized endpoint pairs narrow
the directory scope; inferred or one-sided matches retain the safe full scope. Run/Test/Build/
Impact checks are editable and show command coverage. The confirmation step adds a per-project
execution plan, then checks missing directories, dirty repositories, read-only projects, and
verification gaps before session creation.
- **TaskMode workflows** — all six task modes share one registry with explicit scope, context
preset, required data blocks, endpoint-impact behavior, verification, write permissions, and
final-output rules. Review is read-only and API change always checks both endpoint sides.
- **Native monorepo detection** — recognizes pnpm/npm/yarn/bun workspaces, Turbo, Nx, Lerna,
Maven modules, and Gradle multi-project builds; loads the root once while preserving package
boundaries in the session prompt.
- **New-workspace wizard** — pick a name + base path; the host creates the primary folder
and scans Java / Vue / React / Python / Go projects for multi-select, automatic grouping,
commands derived from real project scripts, and a scope-aware loading default.
- **Three ways to add a directory** — select from native DSH workspaces, open the host
directory picker, or paste an absolute path.
- **Session-scoped on-demand context** — standards, commands, and feature indexes live under
`~/.dsh/dsh-workspace-combiner/sessions//`, so concurrent sessions cannot overwrite one another and disposed sessions are cleaned automatically.
- **Task context capsules** — task sessions keep only entrypoints, configuration, tests, current changes, matched endpoints, and a recommended reading order resident; the complete file tree becomes session-scoped on-demand context.
- **Directory tri-state access** — `readwrite` (sandbox-writable), `readonly` (visible but
not writable), `disabled` (excluded from the prompt). The primary directory is always
`readwrite`.
- **Workspace mode** — `anchor` (primary = docs anchor) vs `single` (primary = core
business code).
- **Directory grouping** — optional group tags (docs / backend / frontend / reference /
other) rendered as sub-headers.
- **Snapshots** — save / restore / delete a workspace's directory configuration; restore
re-syncs the sandbox immediately.
- **File index + load modes** — gitignore-aware bounded file-tree scan with an mtime
cache; a per-workspace load mode controls injected detail.
- **Code/API index** — extracts HTTP endpoints and links the server registration site to the
client call site as `file:line` across TS/JS/TSX/JSX/Vue and Java/Kotlin/Go/Python/Ruby/C#.
Every row exposes an Exact / Normalized / Inferred / One-sided confidence badge; hover it
to inspect sources, evidence, and index time.
- **Symbol-level code skeletons** — reuse the same source scan to index functions, classes,
interfaces, types, enums, and common components together with compact declaration signatures.
Task capsules keep only matched skeletons resident; the complete list remains session-scoped
and on-demand, so the model can inspect parameters and type boundaries before reading a file.
- **Minimal dependency neighborhood** — deterministically resolves local imports and keeps only
one-hop dependencies/dependents around task evidence resident. The complete graph remains
on-demand, preventing a single relevant file from triggering a whole-module read.
- **Precise test mapping** — links source files to tests through direct imports or conservative
naming conventions. Task capsules recommend only relevant tests, while the complete map remains
on-demand so verification starts narrow before expanding to a full suite.
- **Explainable endpoint correlation** — deterministic-first, normalized matching, heuristic
fallback, and visible evidence. `/api/user/detail` and `/user/detail` can join after one
optional `/api` or `/api/vN` normalization; Spring class and method routes are composed;
named endpoint references are explicitly marked inferred. Dynamic/generated routes still
need source-code verification.
- **Endpoints touched by these changes** — a deterministic reverse lookup from the git
working tree, through the file→endpoint map built during the same scan, to the endpoints
those files declare or call, with the counterpart file on the other side.
- **Per-project command handbook** — `run` / `test` / `build` per directory, edited inline and
injected with **absolute paths** so the model knows which command to run where. Prefilled
from the detected project type only where the command is certain.
- **Context monitor (estimates)** — a budget modal with per-directory file counts and estimated
tokens, so you can tune the load mode and watch context shrink. Fixed overhead is derived as
`whole-block render − each block`, so the figures add up to what is actually injected.
- **Real token usage (measured)** — the same modal shows provider-reported usage: uncached
input / cache read / cache write / output, **cache hit rate**, an occupancy bar against the
context window, and the **plugin's share** of the latest request.
- **@-command dynamic scope** — a prompt section teaches the model to resolve `@`-prefixed
tokens as explicitly referenced paths across all workspace roots (`@dir/`, `@file`,
`@"path with spaces"`), pulling files into scope on demand.
- **Sandbox sync** — read-write directories are pushed into
`dsh-write-protect` `writablePaths` (written to the desktop profile's `cordis.patch.yml`, applied
via live patch reload); the bottom legend shows how many directories are actually in the allowlist.
- **Git status per directory** — each row shows its branch, amber with `*N` when there are
uncommitted or untracked changes, grey when clean, plus `↑N` when ahead of the upstream.
Directories that are not repositories show nothing.
- **Directory notes** — attach a free-form note to any directory, edited inline; it travels
with the directory configuration.
- **Project-directory annotations** — the primary row is badged `Docs only` and the others
`Code`, so the anchor-vs-source distinction is visible at a glance (hover for an explanation).
- **Live injected-prompt preview** — expand a read-only block that renders exactly what will be
injected for the current configuration, and copy it.
- **Context budget** — an editable per-workspace token budget with a donut summary, 2x2 stat
cards, and a per-directory **column chart**; the panel warns past 80% and past 100%.
- **Context presets + global budget gate** — new workspaces default to Balanced, with Economy,
Deep analysis, and Custom modes. Presets coordinate load mode and file-index, feature-index,
standards, and command budgets; when the global cap is tight, the task, directory list, explicit
`@` references, and standards are preserved first, while every truncation is explained.
- **Unified diagnostics center** — check directories, sandbox roots, required DSH services,
linked-session freshness, index caches, token variance, project commands, oversized directories,
and configuration versions in one place. Safe repairs are one click, and copied reports redact
usernames and secrets.
- **Fixed-height panel with local scrolling** — the panel fills the sidebar and only its lists
scroll, so the header and the New-session button never leave the screen.
- **Compact entry cards + modals** — advanced config, coding standards, prompt preview and the
context budget are left-column entry cards that open modals, so they no longer occupy permanent
panel height.
- **Keyboard** — `Cmd/Ctrl+N` opens Start task, `Cmd/Ctrl+K` opens the command palette, and `Esc` closes dialogs; the
palette covers switching workspaces, adding directories, refreshing stats and changing modes.
---
## Architecture
~~~text
dsh-workspace-combiner/
├── package.json # dsh field: bundle.patch + client.inject
├── cordis.patch.yml # registration patch
├── tsconfig.json # typecheck
├── tsdown.config.ts # dual-entry build: host + client
└── src/
├── invariant.ts # shared constants (plugin id / API paths / prompt order)
├── core/types.ts # shared types (WorkspaceRef / Workspace / StoreShape / ...)
├── prompt.ts # multi-workspace prompt + file-index rendering
├── store.ts # host persistence (~/.dsh/dsh-workspace-combiner.json)
├── sandbox-sync.ts # dsh-write-protect writable-root sync
├── routes.ts # /api/dsh-workspace-combiner routes (loopback-only)
├── host/
│ ├── index.ts # host entry: prompt section + session/created + routes
│ ├── projectDetector.ts # scan a directory for project type
│ ├── fileIndex.ts # gitignore-aware bounded file-tree scanner + mtime cache
│ ├── gitStatus.ts # branch / dirty / untracked / ahead per directory
│ └── contextStats.ts # token estimator + per-directory context stats
└── client/
├── index.ts # client entry: sidebar icon + main-column panel
├── types.ts # client-local mirrored types
├── locales.ts # zh/en dictionary + tt() helper
├── api.ts # client -> host fetch API
└── panel/
├── WorkspaceCombinerPanel.tsx # panel body + icon
├── controller.ts # state management
├── NewWorkspaceWizard.tsx # create-workspace wizard
├── typeBadge.tsx # project-type badge
├── naming.ts # name sanitize / dedupe
└── styles.ts # injected