dsh-plugin-inspector

The Desktop application

← dsh-plugin-inspector docs

The DeepSeek Harness Desktop application is an Electron shell around the same dsh runtime the CLI launches. apps/desktop and apps/desktop-host are private: true and never reach npm, so this page was written from the monorepo at tag dsh-v0.1.7-rc.2, which is a later release than the one HARNESS_REFERENCE names. Where a claim below depends on a version, it says so.

The short answer: third-party plugins can be installed into Desktop, they are installed in exactly the shape this tool analyses, and Desktop composes them through the same loader, the same bundles and the same patch layers as the CLI’s web profile. Nothing here asks for a Desktop-specific mode. What Desktop adds is one composition step outside the loader and — at 0.1.7-rc.2 — two waterfall events the CLI’s 0.1.5-rc.3 catalogue does not declare.

Desktop’s profile is the web profile

apps/desktop/src/project-manager.ts takes its bundle list straight from the shipped template:

const WEB_PROFILE = PROFILE_TEMPLATES.web as ProfileTemplate   // project-manager.ts:32
export function createPluginProfile(projectDir: string): void {
  initProfile(projectDir, WEB_PROFILE.bundles)                 // project-manager.ts:175
}

PROFILE_TEMPLATES.web is ['@deepseek-ai/dsh-base', '@deepseek-ai/dsh-web-app'] (packages/boot/app-boot/src/profile.ts:183 to :184). There is no desktop entry in PROFILE_TEMPLATES and no packages/bundle/desktop. apps/desktop-host/src/index.ts:25 to :29 calls the CLI’s own runProfile with profile: 'desktop' and patchFiles: [], and passes resolvedProfile, which bypasses named-profile initialization — so 'desktop' is a name carried into ProfileContext, not a template lookup. The layer stack it produces is the shared one documented at apps/cli/src/profile-boot.ts:185 to :190: each bundle in dsh.profile.bundles order, then the profile’s own cordis.patch.yml, then $DSH_HOME/cordis.patch.yml, then --patch overlays (none, for Desktop), then the telemetry switch.

So Desktop’s rows are the core rows this tool already knows, for whatever harness version the installed runtime is. CORE_ROWS needs no Desktop-specific entries.

Plugins can be installed, and a new bundle activates itself

A Desktop profile is a pnpm package directory. initProfile writes its package.json, an empty cordis.patch.yml, and a pnpm-workspace.yaml pinning nodeLinker: hoisted — which the harness’s own comment (profile.ts above PROFILE_PNPM_WORKSPACE) says exists so out-of-tree plugins share the installation’s single Cordis instance. apps/desktop-host/src/index.ts:31 to :40 hands runProfile a packageManager whose command is Electron’s own executable under ELECTRON_RUN_AS_NODE, so package operations run inside the application.

Installing a package that declares dsh.bundle.patch activates it with no separate step: reconcileProfilePlugins appends every new bundle dependency to dsh.profile.bundles (packages/boot/app-boot/src/profile-plugins.ts:115, under the JSDoc line “New bundle dependencies activate automatically” at :97). Appended means after @deepseek-ai/dsh-base and @deepseek-ai/dsh-web-app, so a third-party layer patches over every core row those two inserted. That is the exact act Tier A grades.

Desktop also ships a recovery path for when that goes wrong. DesktopProjectManager.disableAllPlugins calls sanitizeProfile, which renames the profile’s cordis.patch.yml aside and rewrites dsh.profile.bundles back to [base, web-app] (apps/desktop/src/project-manager.ts:77, packages/boot/app-boot/src/profile-sanitize.ts:18). It preserves installed packages and it does not touch $DSH_HOME/cordis.patch.yml, which composeProfile applies to every profile and ranks above the per-profile layer.

What Desktop composes outside the loader

apps/desktop-host/src/index.ts mounts four things on the booted context directly, after runProfile resolves:

What Where Reaches
desktop-office index.ts:95, defined in office.ts mounts @deepseek-ai/dsh-tool-workspace-dependencies and @deepseek-ai/dsh-skill-office
update admission installDesktopUpdateTaskControl, update-tasks.ts:34 a connection/request listener that answers 503 while an update holds the admission lock (:36)
quit inspection installDesktopQuitInspection, quit-inspection.ts dispatches workspace/session-activity per live agent (:35)
platform session publisher platform-session.ts:11 ctx.inject(['deepseekAccount']), forwards account sessions over private IPC

None of these is a loader row. They carry no row id, so no patch entry can name them: - id: desktop-office / disabled: true in a third-party layer is inert. Worth noticing that the same two packages are rows under ids workspace-dependencies and skill-office in the sdk-app bundle (packages/bundle/sdk-app/cordis.patch.yml:30 and :36) — the same code is a targetable row in one profile and unreachable-by-id in another. None of the four provides a capability seam.

The two waterfalls Desktop dispatches

At 0.1.7-rc.2 the api-catalog declares 17 waterfall events against the 14 in WATERFALL_EVENTS. Two of the three additions are the ones Desktop uses, and both are decision waterfalls by this tool’s own rule — a short-circuit replaces what the harness would otherwise have done:

The third addition, compaction/summary-error, is an error-recovery chain (api-catalog.ts:3873, declared at :3869) and is not a decision waterfall.

None of the three is in WATERFALL_EVENTS yet, because this tool tracks latest and they arrive in next. src/knowledge.ts explains that choice at HARNESS_REFERENCE. Until 0.1.7 becomes latest, B14 says nothing about a listener on any of them: this page is the warning, and pnpm run sync -- --release 0.1.7-rc.2 prints the gap on demand.

What is not established here