Files
deepseek-harness/packages
Tianyi Cui fff2e1f33d workflow: render thrown script values inside the realm's execution window
Codex code-review round 3: the round-2 'contained stack getter' still let a
script escape the vm sync-slice timeout — throw { get stack() { while(true){} } }
put the spin on the HOST catch path, where no timeout applies (verified: a
direct sync-slice spin dies by the timeout; the getter-hidden one hung the
process). Identity-trusting the native getter is also insufficient: V8 stack
formatting reads script-controllable hooks at format time (Error.prepareStackTrace,
a subclass name getter — both empirically confirmed), so ANY host-side
formatting of a realm error can run realm code.

The fix moves rendering into the realm itself: the compiled body (and the meta
literal) is wrapped in a realm-side catch that pre-renders the thrown value to
a string (REALM_THROWN_RENDERER_SOURCE) — a hostile accessor/toString now runs
as ordinary script code, killed by the sync-slice timeout or falling under the
documented post-await spin limitation; host WorkflowErrors pass through for
the CANCELLED mapping. The host catch descriptor-reads the pre-rendered string
(thrownRendering) or falls back to describeThrown, which invokes no getter
whose identity is not the host realm's own native stack getter.

Tests: hostile-table expectations updated for realm-side rendering; new
regressions for the getter-hidden sync spin dying by the vm timeout (engine +
meta paths) and for a hostile thenable rejection that bypasses the realm
wrapper (renders host-side, proxy labelled, traps never run); describeThrown/
thrownRendering unit tables including the realm-error identity-mismatch case.
2026-07-05 20:32:35 +08:00
..
2026-07-05 00:45:39 +08:00

Packages

Harness packages, all under the @deepseek-ai/dsh-* scope. Each package is a Cordis plugin (microkernel-style): it exports either a default Service subclass or a functional plugin, declares its ctx key/events through declaration merging, and exposes extension points through ctx.effect(), ctx.on(), and ctx.waterfall(). Authoring conventions: AGENTS.md (subtree) and the root AGENTS.md § Conventions.

Hierarchy

Packages are grouped by modular role at packages/<group>/<pkg>/. The group directory is a pure container (no package.json of its own); the package name stays @deepseek-ai/dsh-<pkg> regardless of group. Each group README is the canonical per-package map — package roles, ctx keys, and the product-vs-support split live there, next to the code.

Group Role Release expectation
core/ Product API spine: session, system-prompt, tools, agent, and the concrete loop Product — stable surface
llm/ LLM capability family: the abstract service + provider adapters Product — stable surface
bash/ Bash capability family: the executor seam, a local impl, and the model-facing tool Product — stable surface
fs/ Filesystem capability family: the abstract seam, a local impl, and the model-facing file tools Product — stable surface
compact/ Compaction capability family: the abstract seam + a basic backend (tool deferred) Product — stable surface
subagent/ Subagent capability family: the provider-registry seam and the model-facing delegation tool Product — stable surface
workflow/ Workflow capability family: the script-engine seam, the node:vm engine, and the model-facing workflow tool Product — stable surface
web/ Web capability family: the abstract seam, search/fetch provider impls, and the model-facing web tools Product — stable surface
todo/ Todo/planning family: the model-facing todo_write tool (whole-list task tracking on the session log) Product — stable surface
hooks/ Hook bridges + the shared Claude Code / Codex wire-protocol library Product — stable surface
session-persistence/ Persistence capability family: the seam + JSONL/SQLite backends Product — stable surface
ui/ Editor/client integration surfaces (the ACP bridge) + the app packages Product — stable surface
support/ Dev/test/example infrastructure (invariants, replay adapter, subagent mock) Support — lower compatibility expectations
util/ Low-level zero-dependency utilities shared across groups (the Branded<B> primitive) Support — small, stable, harness-dep-free

The split is the point: a package's group says whether it is part of the product API or support/test/example infrastructure, so release and removal decisions do not treat every package as an equal public contract. New packages join an existing group; adding a new top-level group is a deliberate act (extend the group READMEs and this table).

Dependencies

The inter-package dependency graph is generated: docs/module-graph.md (pnpm run gen-module-graph, freshness-gated in CI).

The rule it must obey: extension plugins depend on interfaces, never on the concrete loop. dsh-agent-loop is swappable — UI/hook/tool plugins keep working against the dsh-agent vocabulary if the loop is replaced. The sanctioned exception is a composition/bundle package like dsh-agent-core, whose whole job is to assemble the concrete spine: it depends on dsh-agent-loop (and the other concrete spine plugins) on purpose. The rule constrains plugins that EXTEND the system, not the bundle that COMPOSES it — swapping the loop means shipping a different bundle, not rewiring every extension. A swappable capability splits into interface / implementation / consumer packages (the bash trio is the template — see capability seams).

Each package has its own README.md with purpose, service API, events, extension points, and deliberate non-goals (TODOs).