feat(desktop): DSH Electron desktop shell — harness internals visualized

Minimal Electron shell over the DSH JSON-RPC runtime — a first-look at
what a ChatGPT.app-style host on top of the DeepSeek Harness looks
like, with the harness's normally-invisible internals (trace timeline,
context surface, subagent tree, compaction, plugin registry, rubrics)
brought forward as first-class UI surfaces so plugin authors and
researchers can see what the agent is actually doing.

Runs against three keyless-to-live profiles (stdio-echo works on
master out of the box; daemon-echo / daemon-vibe-echo activate once
the daemon-demo lands; stdio-deepseek and daemon-vibe hit the real
DeepSeek API when you supply a key). HARNESS_DEV auto-resolves to the
in-repo runtime when this shell ships under examples/desktop/, so a
fresh clone launches without config; env DSH_DEV_ROOT overrides for
custom layouts, and a sibling deepseek-harness-dev/ checkout is the
original dev workflow.

Cold-clone gate (P0 fixes for first-time-clone usability):
- HARNESS_DEV: 3-candidate resolver (env → walk-up in-repo marker →
  sibling), unit-tested via mock fs so ordering is locked without
  needing either real layout on disk.
- config yml leaves rewritten at assemble time so the sibling-clone
  paths (../../deepseek-harness-dev/examples/echo-agent/…) become
  the in-repo paths (../../echo-agent/…) in the released tree —
  source yml stays usable for local dev, released tree ships a
  working shape.
- pnpm-workspace.yaml allowBuilds.electron = true (was placeholder).
- missing-key card in stdio-deepseek offers a one-click switch to
  stdio-echo (the keyless profile that works on master) rather than
  daemon-echo (blocked on the not-yet-shipped daemon-demo).
- assemble-oss-release.sh rewrites the source-side breadcrumb name
  'dsh-desktop-demo' → 'dsh-desktop' for the released package.json.

FOUC guard on the onboarding gate (41fc5df carried) keeps the
first-launch splash from flashing before the runtime probe finishes.

Test suite (1634 tests in source, 3990 in the runtime repo) covers
resolver ordering, renderer classifiers, trace timeline shape,
compaction diff rendering, rubric parity, and the missing-key
onboarding paths.
This commit is contained in:
ZiyaZhang
2026-07-18 12:59:34 -07:00
parent 67053d1cf6
commit e8f5c0b51b
378 changed files with 104431 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

View File

@@ -0,0 +1,81 @@
# default-profile-real probe (2026-07-18)
Isolated real-machine verification for `fix/default-profile-real` (default
profile → stdio-deepseek + missing-key guided-switch card).
## Isolation (mandatory)
`--user-data-dir=/tmp/dsh-probe-default-real/user-data` (Electron caches +
Local Storage) AND `DSH_DESKTOP_HOME=/tmp/dsh-probe-default-real/dsh-home`
(shell overlay + config.json + `.onboarded` sentinel). Team-lead flagged
that a prior probe wrote through to the user's real `~/.dsh-desktop/user-
overlay.cordis.yml` because DSH_DESKTOP_HOME wasn't isolated; this probe
respects both.
Driver: `/tmp/dsh-probe-default-real/run.sh {with-key|no-key} [port]`.
## Scenarios
### 01 · no-key boot (`01-no-key-boot.png`)
Boots stdio-deepseek with DEEPSEEK_API_KEY unset. Confirms:
- Bottom-right chip: `stdio-deepseek · deepseek-v4-flash` (NEW DEFAULT
correctly landed — was `daemon-echo · mock-echo` before this change)
- Composer model chip: `deepseek-v4-flash` (matches profile default)
- Status bar: `crashed` (expected — the deepseek runtime dies during
plugin load because this dev-clone snapshot has a `workspaceContext`
schema drift; NOT the api-key error we designed against)
- Banner: **generic "Runtime warning"** — the raw message reaching
the classifier is `runtime not writable` (from
`transport.js:53 write() throws when stdin isn't writable`), which
correctly falls through to the generic bucket. My missing-api-key
regex would ONLY match if the deepseek plugin actually got to throw
its api-key error, which requires the config schema to pass first.
### 02 · guided-switch card (synthetic inject, `02-guided-card-injected.png`)
Fires `showRuntimeErrorBanner('llm-deepseek: an API key is required
(Config.apiKey or $DEEPSEEK_API_KEY)')` via the __dshRenderer test seam
so we can see the classifier + banner logic end-to-end without needing
the real llm-deepseek error to surface. Confirms:
- Banner title: **"! DEEPSEEK_API_KEY needed for real-model profile"**
- Hint: full two-option copy (set env in .env/shell, or try keyless demo)
- Switch button: **"Switch to keyless demo (daemon-echo)"** (ghost small,
under hint, wired to `window.dsh.startRuntime('daemon-echo')`)
- Layout: amber-tinted banner sits above the welcome cards, NO red wall,
full-width row (respects density spec)
### 03 · with-key boot (`03-with-key-boot.png`)
Boots stdio-deepseek with the dev-clone `.env` key loaded. Same shape as
#01 in this environment because the config schema drift dies before the
key check — the WITH-key scenario would surface `status=ready` +
`no banner` only after the dev clone is bumped past the `workspaceContext`
requirement. Documenting for reproducibility.
## Known limits (dev-clone drift)
`deepseek-harness-dev` currently requires `workspaceContext` in the
agent-spine-demo entry (packages/examples/agent-spine-demo/src/index.ts:94).
The demo repo's `config/deepseek-jsonrpc.yml` predates that requirement, so
the runtime dies at config validation before either the key check or the
actual daemon handshake. This is orthogonal to the default-profile change
and does NOT block:
- The default profile stdio-deepseek IS observably active (screenshots
and CDP eval of `#profile.value` confirm)
- The guided-switch card renders correctly when the api-key error DOES
reach the classifier (screenshot #02 proves this via the test seam)
- The static test suite (`test/default-profile-real.test.js` +
`test/renderer-runtime-banner-classify.test.js`) locks every step of
the wire path (currentProfileName, cfg.profile persistence, stderr
accumulator, classification bucket, banner switch button)
## Follow-up
- **Dev-clone bump**: separate ticket. When `agent-spine-demo` becomes
optional or the yml gains `workspaceContext`, re-run this probe in
full to see the api-key error surface organically. Current 1554 test
suite locks the code paths that would fire when it does.
- **README quick-start** — team-lead owns this batch, keeping just the
minimum quote-of-fact edits to README in this commit (default is
stdio-deepseek, keyless demo callout).