dsh-a2a

Harness Compatibility

Agent2Agent (A2A) v1.0.1 dual-end plugin for DeepSeek Harness.

English · 中文

@hanphone/dsh-a2a is built against a sibling DeepSeek Harness checkout rather than against published packages, so every harness release is an opportunity for the plugin’s build layout, manifest contract, or runtime API assumptions to drift. This reference is the maintenance procedure for that drift plus the record of what actually broke and how it was fixed. Architecture is in architecture.md.

When to run this procedure

Compatibility surfaces

Surface Where it lives What a harness change can do
Dependency versions peerDependencies in package.json Host ships a newer @deepseek-ai/cordis/schemastery; a DSH peer range stops covering the runtime and the preflight refuses the plugin
Build layout references in tsconfig.json and tsconfig.client.json A referenced harness package splits, renames, or stops being a composite project; tsc -b fails before any source is read
Mount and manifest contract cordis.patch.yml, dsh.bundle.patch, dsh.client.inject, scripts/build-client.mjs The - insert: patch form, client injection list, or window.__ModuleLoader__.load({ id, factory }) browser contract changes
Runtime APIs ctx.a2a, ctx.slots.inject('settings.section', …), storage KvTable, commands, preset/skill/subagent data A consumed service signature or data structure moves

The four surfaces are ordered by how cheaply they can be checked: dependency versions and build layout fail loudly and early; runtime APIs are covered by the consumer typecheck and tests.

Procedure

1. Identify the harness version

The harness has no changelog; the version is the root package.json version and the release tags are dsh-v<semver>.

cd ../deepseek-harness
grep -m1 '"version"' package.json
git status -sb && git log --oneline -3
git fetch origin --tags --prune
git ls-remote --tags origin | grep -v '\^{}' | awk -F/ '{print $NF}' | sort -V | tail -10

git ls-remote reports the upstream state regardless of what this checkout has fetched; a local tag list alone can be several release lines behind.

2. Refresh the harness build the plugin consumes

Harness lib/ output is gitignored and survives a version switch, so a stale artifact plane can make the plugin typecheck against the previous version. A version switch can also leave manifest-less package directories behind, which the host workspace glob still picks up and tries to bundle.

pnpm install --frozen-lockfile
pnpm run clean            # drop stale build output and manifest-less package residue
pnpm run build            # or a targeted tsc -b for the referenced packages

3. Diff the coupling surfaces

cd ../deepseek-harness
git diff <from> <to> -- vendor/cordis vendor/schemastery | head -40
git diff <from> <to> -- packages/client/ui-settings packages/storage packages/interaction | head -40
git diff <from> <to> -- tsconfig.base.json tsconfig.base.client.json tsconfig.client.json tsconfig.host.json

4. Verify against the new checkout

cd ../dsh-a2a
pnpm typecheck   # host + client + mirror check (tsconfig.types.json)
pnpm test        # vitest run — unit + composition + real persistence
pnpm build       # tsc + tsdown + scripts/build-client.mjs
pnpm test:e2e    # hermetic two-instance A2A smoke against the built artifact

pnpm test alone is not enough evidence for a compatibility change: it runs stub host services and cannot see durable-codec or manifest/mount drift. The mirror check and the e2e smoke are the layers that can; see testing.md.

If the clean rebuild no-ops because lib/ was deleted while the TypeScript build cache survived, clear node_modules/.cache/dsh-a2a/ first: tsc -b trusts a stale tsbuildinfo and tsdown then cannot find its entry points.

5. Adapt metadata only when the code is already compatible

Prefer metadata fixes (project reference paths, peer ranges, version bump) over source changes. If source must change, add or adjust a behavior test in the same change.

6. Verify the DSH peer preflight

DSH 0.1.7 and later evaluate a plugin’s @deepseek-ai/dsh and @deepseek-ai/dsh-* peers against the running version before importing it. Prereleases participate in range matching, and workspace:^/~/* refer to the running version. A refusal carries the incompatible-version code with the unsatisfied ranges; the plugin manager rejects registry installs before pnpm runs.

The important detail for this plugin: the preflight ignores @deepseek-ai/cordis and @deepseek-ai/schemastery. Only @deepseek-ai/dsh-commands and @deepseek-ai/dsh-storage-domain participate. Keep those two ranges truthful for every tested harness version. The other two are not evaluated, but their declared ranges must still admit the host’s vendored copy — including an exact prerelease when the host line vendors one (for example ~4.0.2 || 4.0.5-alpha.1).

To bypass a genuine mismatch, grant an exact exemption rather than widening the range dishonestly:

dsh plugin allow-version <pkg@version> --dsh-version <runtime> --accept-risk
dsh plugin version-exemptions
dsh plugin revoke-version <pkg@version> --dsh-version <runtime>

7. Record, commit, pack, publish

Bump package.json version, commit the adaptation with the harness version in the message, and produce the tarball:

pnpm pack --pack-destination <dir>

Compatibility record

dsh-a2a Harness verified against Changes required Evidence
0.4.0 0.2.1-rc.2 A2A wire conformance: SendMessage {task} envelope, JSON-RPC SSE frames + event ids, ListTasks totalSize, A2A-Version validation, push methods return -32003; per-address rate limiting; running-task continuation rejection; artifact append semantics; outbound stream replay/Last-Event-ID; returnImmediately/historyLength; remove unused outbound handoff session pnpm typecheck (host + client + mirror check) clean; pnpm test 159/159; pnpm build produced lib/index.js+lib/client.js; pnpm test:e2e passed inbound + outbound round trip against two real 0.2.1-rc.2 instances
0.3.8 0.2.1-rc.2 CLI fix: /a2a inbound create and outbound create consumed an extra leading token; the inbound description is now joined from the remaining words; command-parser tests added pnpm typecheck (host + client + mirror check) clean; pnpm test 121/121; pnpm build produced lib/index.js+lib/client.js; pnpm test:e2e passed inbound + outbound round trip against two real 0.2.1-rc.2 instances
0.3.7 0.2.1-rc.2 source fix: inbound message source.kind plugin → producer-owned a2a; test-layer additions (mirror check, real-persistence suite, e2e smoke); standardDecoratorPlugin in vitest.config.ts pnpm typecheck (host + client + mirror check) clean; pnpm test 114/114; pnpm build produced lib/index.js+lib/client.js; pnpm test:e2e passed inbound + outbound round trip against two real 0.2.1-rc.2 instances
0.3.6 0.2.1-rc.2 none — peer ranges, zod pin, build layout, and manifest contract already compatible; version bump and record only clean-cache pnpm typecheck host+client zero errors; pnpm test 110/110; full pnpm build produced lib/index.js+lib/client.js+lib/types
0.3.5 0.2.1-alpha.2 peer ranges widened to the 0.2 line; zod pinned to the harness’s zod line; tests-scoped tsconfig for Vite 8 path resolution pnpm typecheck host+client clean; pnpm test 110/110; full pnpm build produced lib/index.js+lib/client.js+lib/types; dsh web boots and serves
0.3.4 0.1.7-rc.2 tsconfig.client.json reference fix; peer ranges made truthful typecheck host+client clean; vitest run 110/110; full pnpm build succeeded
0.3.3 0.1.5-rc.2 none — code and metadata already compatible consumer pnpm typecheck clean

0.4.0 details

A protocol-conformance and hardening release. SendMessage now returns the spec oneof (result.task / result.message); streamed events are JSON-RPC result/error envelopes with SSE event ids; artifact chunks carry append semantics; ListTasks includes totalSize; A2A-Version is validated and returned; push-configuration methods return PUSH_NOTIFICATION_NOT_SUPPORTED (-32003). Rate limiting keys by client address, continuation of a running task is rejected rather than silently dropped, and the outbound client honors Last-Event-ID on stream reconnect. returnImmediately, historyLength, and text-only acceptedOutputModes are now implemented. The unused outbound hand-off session composition was removed.

0.3.8 details

A CLI bug-fix release. /a2a inbound create and /a2a outbound create destructured the command tail as [action, id, ...args] but read the name/URL from args[0], so the first real argument was discarded and a placeholder was needed. The create branches now read the name/URL from id, the inbound description is joined from the remaining words (so it can contain spaces), and tests/unit/commands.spec.ts covers the parsing. The manual’s command table and troubleshooting page no longer describe a placeholder.

0.3.7 details

A bug-fix release, not a harness adaptation. Two changes:

  1. Inbound (no reply) fix. The session executor sent the agent a message with source: { kind: 'plugin', plugin: 'a2a' }; the JSONL v4 codec refuses kind: 'plugin', the write failed in the handle’s background flush, and the agent loop contained the error, so every inbound task settled COMPLETED with (no reply). The source is now the producer-owned { kind: 'a2a' }.
  2. Test layers that would have caught it. tests/types/mirrors.typecheck.ts (compile-time source contract), tests/integration/persistence.spec.ts (real JSONL v4 codec + agent loop), and scripts/e2e-a2a.mjs (two real instances + mock LLM, inbound and outbound). vitest.config.ts gained the harness standardDecoratorPlugin so tests can import harness source. See testing.md.

Gate: pnpm test:all — typecheck (host + client + mirror check), 114 tests, build, and the hermetic e2e smoke, all against the 0.2.1-rc.2 checkout.

0.3.6 details

The harness moved from 0.2.1-alpha.2 to 0.2.1-rc.2 (990 commits). No adaptation was needed; only the version bump and this record changed.

  1. peerDependencies still cover the new host. vendor/cordis moved 4.0.5-alpha.1 → 4.0.5 and vendor/schemastery 3.18.5-alpha.1 → 3.18.5, both now stable and inside the existing ~4.0.2 and 3.* ranges. @deepseek-ai/dsh-commands and @deepseek-ai/dsh-storage-domain keep >=0.1.3 <0.3, which covers the 0.2 line the preflight evaluates. The two exact prerelease alternatives stay: they keep the plugin truthful for a host still on the alpha line.
  2. dependencies.zod stays pinned to ~4.4.3; the harness root still resolves zod@4.4.3, so the two-copy exactOptionalPropertyTypes failure does not return.
  3. Build layout is unchanged. tsconfig.base.json only gained paths aliases (plugin-market, cua, remote-access, and others this plugin does not consume); tsconfig.base.client.json and the referenced packages’ tsconfig leaves are unchanged, so the project references and the ui-settings/tsconfig.client.json leaf reference still resolve.
  4. The manifest contract is unchanged: DshClientManifest.inject, DshBundleManifest.patch, and the - insert: patch form have zero diff across alpha.2..rc.2.

Post-release, a real dsh web round trip exposed the inbound (no reply) bug above: the 110-test stub suite could not see it, and the typecheck/build steps of this procedure could not either. 0.3.7 fixes it and adds the mirror check, the real-persistence suite, and the e2e smoke (see the 0.3.7 record).

0.3.5 details

Plugin source was unchanged; three metadata/build-layout fixes were needed.

  1. peerDependencies widened to cover the 0.2 line. @deepseek-ai/dsh-commands and @deepseek-ai/dsh-storage-domain went from ">=0.1.3 <0.2" to ">=0.1.3 <0.3", which covers 0.2.1-alpha.2 because prereleases participate in range matching. @deepseek-ai/cordis gained the 4.0.5-alpha.1 alternative and @deepseek-ai/schemastery the 3.18.5-alpha.1 alternative: the 0.2.1-alpha host vendors those prereleases, which the stable ~4.0.2/3.* ranges do not admit.
  2. dependencies.zod pinned from ^4.4.3 to ~4.4.3. The harness resolves zod 4.4.3; a fresh install of ^4.4.3 floats to 4.6.5, and the two zod copies make @deepseek-ai/schemastery’s Config types mutually incompatible under exactOptionalPropertyTypes. The pin keeps the plugin on the harness’s zod line.
  3. tests/tsconfig.json extends the build config so Vite 8’s native resolve.tsconfigPaths applies the harness paths map to spec files. The build config’s include is src; the composition suite imports @deepseek-ai/cordis as a value directly from tests/, so without a tests-scoped config the paths map did not reach it and resolution fell through to a node_modules that holds no harness packages.

Two build-environment details back these fixes. pnpm 11+ reads workspace settings from pnpm-workspace.yaml, not .npmrc, so autoInstallPeers: false and verifyDepsBeforeRun: false live there; the harness peers have no registry version inside their truthful ranges, so any dependency reify (including the pre-script check) fails and must stay disabled. pnpm run clean in the harness is also a prerequisite, not an optional step (see the stale-residue entry below).

0.3.4 details

Two metadata fixes were needed; plugin source was unchanged.

  1. tsconfig.client.json referenced the ui-settings package directory. In 0.1.7 that directory’s tsconfig.json became a solution file (files: []) over tsconfig.host.json and tsconfig.client.json, so the reference has to name ../deepseek-harness/packages/client/ui-settings/tsconfig.client.json. Referencing the solution directory fails with TS6306.
  2. peerDependencies moved from @deepseek-ai/cordis: "4.0.2" to "~4.0.2" (the 0.1.7 host ships 4.0.4) and from "*" to ">=0.1.3 <0.2" for @deepseek-ai/dsh-commands and @deepseek-ai/dsh-storage-domain. The truthful range covers every harness version this plugin has been tested against and satisfies the 0.1.7 preflight without an exemption.

0.3.3 details

Across the 0.1.3 → 0.1.5 range vendor/cordis (4.0.2) and vendor/schemastery (3.18.2) were unchanged, and the packages this plugin consumes only received version bumps and README rewrites. Consumer typecheck against the harness source graph passed with zero errors, so no change shipped.

Breakages and fixes

Publishing

Two registries with different rules:

Known limitations