Files
deepseek-harness/packages/client/test-runtime
ZiyaZhang 00390ae851 feat(web): open a produced file from the conversation
Serve one file at a time out of a Session's workspace under /f on the web
transport, and point the conversation's existing file-open affordance at it.
Clicking a write/edit/read row's path now opens that file in a browser tab —
including from a LAN client, where the Host's system opener is fenced to
loopback and answered nothing.

- /f/<sessionId>/<segments> in client-connection, behind the same
  browser-trust fence as /api; realpath confinement, streamed reads,
  GET/HEAD only, nosniff + no-store.
- Script-capable documents carry CSP sandbox: model-authored markup must not
  be same-origin with /api, where events.mux is a readable GET stream.
- ApiProxy.workspaceRootOf answers where a Session's files live without
  resuming an agent; the client program cannot reach the core services.
- The /f URL shape lives in dsh-host-apiproxy/api so both ends share one
  encoding (client bundles may not value-import another plugin).
2026-07-31 12:07:43 -07:00
..

@deepseek-ai/dsh-client-test-runtime

English | 中文

jsdom slot test runtime for client feature specs: a real Cordis Context, the production SlotsService and web-react renderer, assembled around typed session/workspace doubles. Feature suites exercise declaration, registration, scope, store, inject, rendering, updates, and disposal without hand-building the machinery per suite — and without a second implementation of any production logic.

The doubles implement the same outward faces features receive through ctx (TestSessions implements ISessions, TestWorkspaces implements IWorkspaces; each fixture session is a FixtureSession implements SessionFace), so a production face change breaks the bench at compile time instead of silently drifting. Provide-bundle materialization runs the production SessionProvideChannel — the one implementation shared with SessionsService. Fixtures feed plain data: list rows, conversation snapshots (immer-patched via updateSnapshot), projection values, and ISession-typed behavior stubs that fail loud when a spec calls an unstubbed verb. The typed provide() constrains fakes for declared service names to Partial of that service's outward face.

Local DOM snapshots: declare(children) registers an auto frame whose per-key <div data-slot> wrappers are snapshot roots; renderSlot(key, owner) returns the slot-local view (container, scoped Testing Library queries, in-place update(owner)); a registered snapshot serializer folds CSS-module class hashes (_frame_a1b2c3frame) to keep .snap files structural and collapses <svg> internals to a data-content fingerprint. Suites needing a custom page frame use root.declare(children, Frame) instead; mount(plugin) runs a real fiber with fail-loud service prechecks, and dispose() tears down views, feature fibers, minted scopes, and persisted store state on one axis.

Not part of the product plugin graph (no dshClient); feature packages depend on it in devDependencies only.

Model Experience

None, as this package is browser-side test infrastructure; nothing here reaches a model request.

KV Cache effect

None; this package neither assembles nor sends a provider request.

Known Limitations and Deferred Work

  • Consumed through repository source aliases only. Specs resolve the package through tsconfig paths to src; the built lib/ artifact re-exports @deepseek-ai/dsh-client-runtime/client, whose bundle is a browser loader script with no Node ESM exports, so lib/index.js is not importable under plain Node. Acceptable while every consumer is an in-repo Vitest suite; a Node-compatible runtime entry is deferred until an out-of-repo consumer exists.
  • Conversation snapshots are fixture data, not replayed history. updateSnapshot writes the snapshot store directly; the wire-to-snapshot computation stays covered by the runtime package's own tests and the replay e2e. A fixture can therefore express states the production projection would never produce.