# dsh-workspace-combiner

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