deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:pixellover1433/dsh-better-sidebar-lite
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
![]()
A right-side tabbed sidebar for DeepSeek Harness (dsh) web: explorer (workspace file tree) and git (changes & commits) tabs, built on an extensible tab registry.
Status: development build in this workspace — NOT installed into any running dsh deployment. Installing is a documented, deliberate step (see Installing below).
dsh plugin add dsh-better-sidebar-lite@v0.0.3-beta.1 --profile web
(⚠️ v0.0.1-beta. compatible with deepseek-harness below v0.1.0-rc.7 only) (⚠️ v0.0.2-beta. and above only compatible with deepseek-harness from version v0.1.0-rc.7)
![]()
Two halves of one cordis plugin:
/better-sidebar with authority: loopback and serves nine endpoints: explorer/list, explorer/stamp (auto-refresh change stamps), git/status, git/log, git/stage, git/unstage, git/commit-detail (full message + changed files of one commit), git/commit (stage + commit), and git/discard (restore/clean). Filesystem access uses node:fs/promises; git runs via a spawn wrapper with fixed arguments, optional stdin for commit messages, timeout and abort support — no shell interpolation.details column (declared by ui-layout AppFrame; priority -1 shadows ui-conversation's DetailsPanel) that renders the sidebar with a tab bar. Because the dock is a real grid column, the conversation shrinks beside it — it never overlaps the main UI. The dock tab set comes from ctx.betterSidebar.tabs, a registry any plugin can contribute to.Data flow (one round trip):
Tab panel -> ctx.betterSidebar.rpc.call(endpoint, payload, { signal })
-> ctx.connection.rpc.call(channel, ...) (browser)
-> host dispatch -> ExplorerService / GitService -> fs / git
-> SidebarResult<T> in the RPC value slot (ADR-002)
ctx.betterSidebar ({ rpc, tabs, explorer }), the dock (the frame's right details column: open/close via ctx.layout, native drag resize, AppFrame's column border), the tab registry, the explorer and git tabs, inline-SVG icons, and en/zh locales.Decisions are recorded in docs/adr/ (architecture, transport & error model, tab registry & dock, explorer & git scope). Design docs live in docs/design/. The dsh API facts everything builds on are in docs/architecture-brief.md.
Explorer and git are pure browser chrome: nothing here reaches a model request. The tabs render host filesystem and git state, fetched over the loopback RPC channel.
Zero — no prompts, tool schemas, or model context are assembled or sent.
None; this package neither assembles nor sends a provider request.
Not installed here; when the owner authorizes, the steps are:
name, inject: [connection], Config, and apply(ctx, config). The client-connection plugin (which provides ctx.connection) must load first../client entry in the web bundle client plugin set (the dsh web loader module table). The plugin requires connection, slots, locale, and layout services and the details slot (declared by ui-layout AppFrame). The dock is session-scoped like dsh's native details column: it shows while a conversation is current.authority: loopback — non-loopback browsers are refused by the connection layer before the handler runs. The host also validates every payload path (absolute, existing, directory, inside allowedRoots when configured).The plugin has two configuration surfaces:
1. User settings (Settings > Plugins > Plugin configuration) — live-editable, no restart. When the ui-settings seam is composed, the plugin registers a dsh-better-sidebar settings namespace:
| Field | Default | Meaning |
|---|---|---|
explorerPollMs |
8000 |
Explorer fallback stamp-poll cadence (ms). |
explorerDebounceMs |
600 |
Explorer session-dirty debounce (ms). |
gitPollMs |
8000 |
Git fallback status-poll cadence (ms). |
gitDebounceMs |
600 |
Git session-dirty debounce (ms). |
gitTimeoutMs |
15000 |
Per git command timeout (ms). |
The tabs re-read these live, so editing them takes effect immediately (the explorer/git poll and debounce intervals are recreated, and the git timeout is read per command). The git timeout replaces the legacy cordis gitTimeoutMs below when the settings seam is present; the cordis value remains the fallback when it is not.
2. Cordis config (cordis.yml) — read at load, restart to change:
| Field | Type | Default | Meaning |
|---|---|---|---|
allowedRoots |
string[] | [] |
Absolute roots the plugin may read; empty = any absolute directory the host process can read. Entries must be absolute (validated at load). |
gitTimeoutMs |
number | 15000 |
Per git command timeout (clamped 100-120000). Used only when the settings seam is absent. |
maxEntriesPerListing |
number | 2000 |
Per-directory listing cap; excess is truncated with a flag. |
maxLogEntries |
number | 100 |
git log -n cap / page size clamp. |
maxStatusEntries |
number | 20000 |
git status entry cap. |
untrackedFiles |
all or normal | all |
Porcelain untracked mode; normal collapses all-untracked dirs into dir/ entries. |
hidePatterns |
string[] | ['.git','node_modules'] |
Basenames filtered from listings (no reveal toggle in v1). |
gitExecutable |
string | git |
Test/override seam. |
Settings-card exposure (dsh ≥ v0.1.0-rc.7). Since rc.7 dsh lets plugins register their own settings cards: the Host serves every registered settings namespace (no
api-proxyallowlist, noregisterConfigurableProvidersself-exposure needed), and the Settings → Plugins → Plugin configuration tab dispatches one card per served namespace. The host half registers thedsh-better-sidebarnamespace and the browser half registers a card keyeddsh-better-sidebar— the join key — so the two pair up automatically.
Any client plugin can contribute a tab:
import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'
import type { TabDef } from 'dsh-better-sidebar-lite/client'
export function apply(ctx: ClientContext): void {
ctx.effect(() => {
const dispose = ctx.betterSidebar.tabs.register({
id: 'my-tab',
order: 30, // sorts after explorer(10), git(20)
label: () => 'My tab', // locale-aware via a function
icon: <MyIcon />, // inline SVG
badge: () => undefined, // optional live badge
renderPanel: () => <MyPanel />, // renders inside the dock
})
return dispose
}, 'my-plugin: tab')
}
Requirements: a stable unique id (duplicates throw TabRegisterError), registration inside ctx.effect (unload disposes), and panel components that read dsh session/workspace data through useDock() (the context the dock provides around every panel) or through props captured by the factory.
Built-in tabs are the reference implementation: explorer (id explorer, order 10) and git (id git, order 20), registered in the plugin own apply through the same public API.
Domain errors travel inside the RPC value slot as SidebarResult<T> (ADR-002 — dsh RpcError is a closed union; a plugin code in the error slot would break the browser response parser). The transport error slot is used only by the connection layer itself.
| Code | Meaning |
|---|---|
not-found |
Path does not exist |
permission-denied |
fs read denied (EACCES/EPERM) |
not-directory |
Expected a directory |
symlink-loop |
ELOOP during stat |
path-too-long |
Payload path over the 4096-char guard |
invalid-root |
Root validation failure (relative path, ...) |
outside-allowed-root |
Root outside configured allowedRoots |
not-a-repo |
Path is not inside a git work tree |
git-missing |
git binary not found on PATH |
git-failed |
git exited with an error (stderr tail capped) |
timeout |
git command exceeded gitTimeoutMs |
cancelled |
Caller aborted the request |
param-invalid |
Payload failed the contract guard |
internal |
Unexpected host failure / transport down (host unavailable) |
Prerequisite — sibling dsh checkout. This repo consumes the DeepSeek
Harness checkout as a read-only sibling: clone deepseek-harness into the
same parent directory as this repo (i.e. ../deepseek-harness next to this
repo). No absolute paths are stored anywhere; every reference is relative.
parent/
├── deepseek-harness # sibling checkout (read-only, packages prebuilt)
└── dsh-better-sidebar-lite # this repo
pnpm install # toolchain (react 18.3.1, vitest 4, typescript 6, oxlint) + link: deps
pnpm typecheck # tsc -p host + client against the dsh checkout built types
pnpm typecheck:tests
pnpm test # vitest projects: host (node) + client (jsdom)
pnpm build # tsc emits lib/{host,client,contract}; CSS mirrored into lib/client
pnpm lint # oxlint
The test suite needs a real git on PATH (git-service tests script a real repo under a temp dir). The dsh checkout is wired in three ways, all relative: tsconfig.base.json paths (built .d.ts for tsc), tsconfig.vitest.json + vitest.config.ts aliases (dsh source for vitest — never the built module-loader bundles), and @deepseek-ai/schemastery in devDependencies as link:../deepseek-harness/vendor/schemastery (the one host-side runtime import; pnpm install creates the junction in node_modules/@deepseek-ai/). The client tests force a single React instance (see the comments in vitest.config.ts).
explorer/stamp, ADR-004), so agent-written and external tree changes appear without manual refresh. On filesystems with coarse (1s) timestamp granularity, two rapid changes to the same directory may be merged until the next change; the manual refresh button remains the backstop. The explorer has no hidden-file reveal toggle, no multi-select, no virtualization.details column, so dsh's built-in tool-details viewer (click a tool call to inspect its input/output) is replaced by the sidebar. The details track only opens for a current NON-blank session on a wide-enough viewport (AppFrame gates both) — when it is closed the dock floats at the right edge instead of vanishing, and docks back in-flow once the column opens. Collapse shrinks it to a 56px tab rail (click a tab or the expand chevron to restore; Ctrl/Cmd+Shift+B toggles); without any current session the dock does not mount (dsh's native details behavior).CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: dsh-plugin-pack。