{"_id":"@aiorouter/dsh-shield","_rev":"5-44ad2cb4b7f87fe9f1954cfb26875bc6","name":"@aiorouter/dsh-shield","dist-tags":{"latest":"2.0.2"},"versions":{"1.0.0":{"name":"@aiorouter/dsh-shield","version":"1.0.0","license":"MIT","_id":"@aiorouter/dsh-shield@1.0.0","maintainers":[{"name":"tayachu","email":"tayachu@gmail.com"}],"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-ui-slots","@deepseek-ai/dsh-client-connection"],"platform":"web"}},"dist":{"shasum":"46ee43df540f98ab597ac580916b8e5f31c2804a","tarball":"https://registry.npmjs.org/@aiorouter/dsh-shield/-/dsh-shield-1.0.0.tgz","fileCount":74,"integrity":"sha512-9tSTiwp0uM8EIYATfMbTD6NZSNgYYmzgeAFfSxBGNvKXG6gkBlzcTC2emaVZoU05QdMkOy8Wh+XEVLv57pArdA==","signatures":[{"sig":"MEYCIQC/ifSALPLqbKTqytBWCRr96Wg1WlIHoteS6BWWDHq3zQIhAN7ajeWV+zs4BCCQ4/tt/+TsiowbN3foYPyyP71hFa0E","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":232345},"main":"lib/index.js","type":"module","types":"lib/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./lib/index.d.ts","import":"./lib/index.js"},"./client":{"types":"./lib/client-entry.d.ts","default":"./lib/client.js"},"./package.json":"./package.json"},"gitHead":"1070b850801717f5a370df127fbf24f8a4a04c7e","scripts":{"test":"vitest run","build":"tsc -p tsconfig.json && node build-client.mjs","typecheck":"tsc -p tsconfig.json --noEmit","build:client":"node build-client.mjs"},"_npmUser":{"name":"tayachu","email":"tayachu@gmail.com"},"_npmVersion":"11.19.0","description":"AIOrouter Shield — privacy-restoration policy controls (GW-2 header, GW-1 markers) and Shield status/usage tooling for the DeepSeek Harness (dsh). Plugin-only: reads the public /v1/me/* whitelist, stores no API keys, writes no files.","directories":{},"_nodeVersion":"24.5.0","dependencies":{"@deepseek-ai/cordis":"4.0.1","@deepseek-ai/dsh-tools":"0.1.0-rc.6","@deepseek-ai/schemastery":"3.18.1","@deepseek-ai/dsh-settings":"0.1.0-rc.6","@deepseek-ai/dsh-credentials":"0.1.0-rc.6"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.0.0","typescript":"^5.6.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/dsh-shield_1.0.0_1787166249157_0.3936303647445938","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@aiorouter/dsh-shield","version":"1.0.2","license":"MIT","_id":"@aiorouter/dsh-shield@1.0.2","maintainers":[{"name":"tayachu","email":"tayachu@gmail.com"}],"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-ui-slots","@deepseek-ai/dsh-client-connection"],"platform":"web"}},"dist":{"shasum":"7018f7a55b37fdf568f6148bdc0043a2bcf05b97","tarball":"https://registry.npmjs.org/@aiorouter/dsh-shield/-/dsh-shield-1.0.2.tgz","fileCount":74,"integrity":"sha512-IdycJJ5gfxfyWiDnptDpysBU7QMuFFJekM06KBrVn3iXJZo7OQgcmlVNUxnRpyCxD69UO7oyb7JCp9aONPoSNw==","signatures":[{"sig":"MEYCIQCNja8SL5jv+us07llEPMx3Q7yyES31D9ufuhTLLm1RRQIhAKO+rglIU/bv6kX4wCladE1q1+nNeNbYkUylD0IP1z/y","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":235768},"main":"lib/index.js","type":"module","types":"lib/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./lib/index.d.ts","import":"./lib/index.js"},"./client":{"types":"./lib/client-entry.d.ts","default":"./lib/client.js"},"./package.json":"./package.json"},"gitHead":"e8e52900c1f181fb62fe1ed807f207fca1162177","scripts":{"test":"vitest run","build":"tsc -p tsconfig.json && node build-client.mjs","typecheck":"tsc -p tsconfig.json --noEmit","build:client":"node build-client.mjs"},"_npmUser":{"name":"tayachu","email":"tayachu@gmail.com"},"_npmVersion":"11.19.0","description":"AIOrouter Shield — privacy-restoration policy controls (GW-2 header, GW-1 markers) and Shield status/usage tooling for the DeepSeek Harness (dsh). Plugin-only: reads the public /v1/me/* whitelist, stores no API keys, writes no files.","directories":{},"_nodeVersion":"24.5.0","_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.0.0","typescript":"^5.6.0","@types/node":"^22.0.0","@deepseek-ai/cordis":"4.0.1","@deepseek-ai/dsh-tools":"0.1.0-rc.6","@deepseek-ai/schemastery":"3.18.1","@deepseek-ai/dsh-settings":"0.1.0-rc.6","@deepseek-ai/dsh-credentials":"0.1.0-rc.6","@deepseek-ai/dsh-typert-protocol":"0.1.0-rc.6"},"peerDependencies":{"@deepseek-ai/cordis":"4.0.1","@deepseek-ai/dsh-tools":"0.1.0-rc.6","@deepseek-ai/schemastery":"3.18.1","@deepseek-ai/dsh-settings":"0.1.0-rc.6","@deepseek-ai/dsh-credentials":"0.1.0-rc.6","@deepseek-ai/dsh-typert-protocol":"0.1.0-rc.6"},"_npmOperationalInternal":{"tmp":"tmp/dsh-shield_1.0.2_1787248936754_0.48811500102580974","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@aiorouter/dsh-shield","version":"2.0.0","license":"MIT","_id":"@aiorouter/dsh-shield@2.0.0","maintainers":[{"name":"tayachu","email":"tayachu@gmail.com"}],"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-ui-slots","@deepseek-ai/dsh-client-connection"],"platform":"web"}},"dist":{"shasum":"efcb20ee7f1a2a8fae8aba82f07040f8d533c568","tarball":"https://registry.npmjs.org/@aiorouter/dsh-shield/-/dsh-shield-2.0.0.tgz","fileCount":74,"integrity":"sha512-OUECugvn979K0i3+/mScBbr9kozYPwXgmcDg4KKqbB8fv+JgU7ez+apcvAkSFKZFRdvTibSJh4OSIkXwwNP4/g==","signatures":[{"sig":"MEUCIQCcca4mK4riiQmZXrppYh7QlzR/jxEqqSC0ZjIgvfZfZAIgWaqbpHgXRxa4gIY7Q+qHIPh/uiKzwtTIG+mHRNnEXks=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":223146},"main":"lib/index.js","type":"module","types":"lib/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./lib/index.d.ts","import":"./lib/index.js"},"./client":{"types":"./lib/client-entry.d.ts","default":"./lib/client.js"},"./package.json":"./package.json"},"gitHead":"cb81a790962e7693a188cac3d9c355440bfc2a95","scripts":{"test":"vitest run","build":"tsc -p tsconfig.json && node build-client.mjs","typecheck":"tsc -p tsconfig.json --noEmit","build:client":"node build-client.mjs"},"_npmUser":{"name":"tayachu","email":"tayachu@gmail.com"},"_npmVersion":"11.19.0","description":"AIOrouter Shield — privacy-restoration policy controls (GW-2 header, GW-1 markers) and Shield status/usage tooling for the DeepSeek Harness (dsh). Plugin-only: reads the public /v1/me/* whitelist, stores no API keys, writes no files.","directories":{},"_nodeVersion":"24.5.0","_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.0.0","typescript":"^5.6.0","@types/node":"^22.0.0","@deepseek-ai/cordis":"4.0.1","@deepseek-ai/dsh-tools":"0.1.0-rc.6","@deepseek-ai/schemastery":"3.18.1","@deepseek-ai/dsh-settings":"0.1.0-rc.6","@deepseek-ai/dsh-credentials":"0.1.0-rc.6","@deepseek-ai/dsh-typert-protocol":"0.1.0-rc.6"},"peerDependencies":{"@deepseek-ai/cordis":"4.0.1","@deepseek-ai/dsh-tools":"0.1.0-rc.6","@deepseek-ai/schemastery":"3.18.1","@deepseek-ai/dsh-settings":"0.1.0-rc.6","@deepseek-ai/dsh-credentials":"0.1.0-rc.6","@deepseek-ai/dsh-typert-protocol":"0.1.0-rc.6"},"_npmOperationalInternal":{"tmp":"tmp/dsh-shield_2.0.0_1787269887768_0.8530695626225644","host":"s3://npm-registry-packages-npm-production"}},"2.0.1":{"name":"@aiorouter/dsh-shield","version":"2.0.1","license":"MIT","_id":"@aiorouter/dsh-shield@2.0.1","maintainers":[{"name":"tayachu","email":"tayachu@gmail.com"}],"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-ui-slots","@deepseek-ai/dsh-client-connection"],"platform":"web"}},"dist":{"shasum":"9db7566bee4734758ef63ff3467459a62279b02c","tarball":"https://registry.npmjs.org/@aiorouter/dsh-shield/-/dsh-shield-2.0.1.tgz","fileCount":74,"integrity":"sha512-zATUkQ0Eq0QzZ6u0GTDlUZGzwHUqh9CAwSt54Jho+UY5RZ9LCxsAHlb0wsRFC0w39c7VxfNqwCbUJCi0GtXF7Q==","signatures":[{"sig":"MEUCIEbqmAFPyczDaOzyRPn/SuPv2HCBBc9D9z+K7GWfUh0ZAiEA1ijO9PNFm3ySSqF4wWQwepUDpxQweGrsnqJjZCpfgg0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":226592},"main":"lib/index.js","type":"module","types":"lib/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./lib/index.d.ts","import":"./lib/index.js"},"./client":{"types":"./lib/client-entry.d.ts","default":"./lib/client.js"},"./package.json":"./package.json"},"gitHead":"9fdadaa9dcb99e2fad9a2ea4b7696de37e3293aa","scripts":{"test":"vitest run","build":"tsc -p tsconfig.json && node build-client.mjs","typecheck":"tsc -p tsconfig.json --noEmit","build:client":"node build-client.mjs"},"_npmUser":{"name":"tayachu","email":"tayachu@gmail.com"},"_npmVersion":"11.19.0","description":"AIOrouter Shield — privacy-restoration policy controls (GW-2 header, GW-1 markers) and Shield status/usage tooling for the DeepSeek Harness (dsh). Plugin-only: reads the public /v1/me/* whitelist, stores no API keys, writes no files.","directories":{},"_nodeVersion":"24.5.0","_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.0.0","typescript":"^5.6.0","@types/node":"^22.0.0","@deepseek-ai/cordis":"4.0.1","@deepseek-ai/dsh-tools":"0.1.0-rc.6","@deepseek-ai/schemastery":"3.18.1","@deepseek-ai/dsh-settings":"0.1.0-rc.6","@deepseek-ai/dsh-credentials":"0.1.0-rc.6","@deepseek-ai/dsh-typert-protocol":"0.1.0-rc.6"},"peerDependencies":{"@deepseek-ai/cordis":"4.0.1","@deepseek-ai/dsh-tools":"0.1.0-rc.6","@deepseek-ai/schemastery":"3.18.1","@deepseek-ai/dsh-settings":"0.1.0-rc.6","@deepseek-ai/dsh-credentials":"0.1.0-rc.6","@deepseek-ai/dsh-typert-protocol":"0.1.0-rc.6"},"_npmOperationalInternal":{"tmp":"tmp/dsh-shield_2.0.1_1787429202985_0.1940149502251367","host":"s3://npm-registry-packages-npm-production"}},"2.0.2":{"name":"@aiorouter/dsh-shield","version":"2.0.2","description":"AIOrouter Shield — privacy-restoration policy controls (GW-2 header, GW-1 markers) and Shield status/usage tooling for the DeepSeek Harness (dsh). Plugin-only: reads the public /v1/me/* whitelist, stores no API keys, writes no files.","type":"module","main":"lib/index.js","types":"lib/index.d.ts","exports":{".":{"types":"./lib/index.d.ts","import":"./lib/index.js"},"./client":{"types":"./lib/client-entry.d.ts","default":"./lib/client.js"},"./package.json":"./package.json"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"platform":"web","inject":["@deepseek-ai/dsh-client-ui-slots","@deepseek-ai/dsh-client-connection"]}},"scripts":{"build":"tsc -p tsconfig.json && node build-client.mjs","build:client":"node build-client.mjs","test":"vitest run","typecheck":"tsc -p tsconfig.json --noEmit"},"peerDependencies":{"@deepseek-ai/cordis":"4.0.1","@deepseek-ai/dsh-credentials":"^0.1.1-rc.2","@deepseek-ai/dsh-settings":"^0.1.1-rc.2","@deepseek-ai/dsh-tools":"^0.1.1-rc.2","@deepseek-ai/dsh-typert-protocol":"^0.1.1-rc.2","@deepseek-ai/schemastery":"3.18.1"},"devDependencies":{"@deepseek-ai/cordis":"4.0.1","@deepseek-ai/dsh-credentials":"^0.1.1-rc.2","@deepseek-ai/dsh-settings":"^0.1.1-rc.2","@deepseek-ai/dsh-tools":"^0.1.1-rc.2","@deepseek-ai/dsh-typert-protocol":"^0.1.1-rc.2","@deepseek-ai/schemastery":"3.18.1","@types/node":"^22.0.0","typescript":"^5.6.0","vitest":"^3.0.0"},"engines":{"node":">=20"},"license":"MIT","gitHead":"5dd25645de99418850c2a9076262c263addcf679","_id":"@aiorouter/dsh-shield@2.0.2","_nodeVersion":"24.5.0","_npmVersion":"11.19.0","dist":{"integrity":"sha512-PknFtoSEqvOxeKksp342ghU2lXIIOI2tXVICtGcMhbbQCsqYXukXpaaXCl2qFPz5kCkwNER3HWJCavdlq5jOGw==","shasum":"c0c797c563ab37dd2fefefd6dd98c708f7706ffb","tarball":"https://registry.npmjs.org/@aiorouter/dsh-shield/-/dsh-shield-2.0.2.tgz","fileCount":74,"unpackedSize":227034,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDQaaMdYXza55OgzpnzR5sOKi5HeSULUPiNJqbjsv+PVAIhAKqRwONQYgQ6aS/4ZTSScPF1lzzL6dnPIy/EO2jI86Pg"}]},"_npmUser":{"name":"tayachu","email":"tayachu@gmail.com"},"directories":{},"maintainers":[{"name":"tayachu","email":"tayachu@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-shield_2.0.2_1788232925688_0.7740460135418017"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-19T19:04:08.900Z","modified":"2026-09-01T03:22:06.061Z","1.0.0":"2026-08-19T19:04:09.316Z","1.0.2":"2026-08-20T18:02:16.896Z","2.0.0":"2026-08-20T23:51:27.918Z","2.0.1":"2026-08-22T20:06:43.120Z","2.0.2":"2026-09-01T03:22:05.839Z"},"license":"MIT","description":"AIOrouter Shield — privacy-restoration policy controls (GW-2 header, GW-1 markers) and Shield status/usage tooling for the DeepSeek Harness (dsh). Plugin-only: reads the public /v1/me/* whitelist, stores no API keys, writes no files.","maintainers":[{"name":"tayachu","email":"tayachu@gmail.com"}],"readme":"# @aiorouter/dsh-shield\n\nAIOrouter Shield controls and status tooling for the DeepSeek Harness (dsh) plugin system.\n\n> **Merged (2026-08-31):** Shield is now part of the unified AIOrouter plugin\n> [`@aiorouter/dsh-aiorouter-mas`](https://www.npmjs.com/package/@aiorouter/dsh-aiorouter-mas) —\n> which adds the AIOrouter model route and the multi-agent workflow on top of the same\n> privacy status window. New installs should use `@aiorouter/dsh-aiorouter-mas`;\n> this package remains available for existing setups and receives security fixes.\n\nThis plugin is **public** (npm package). It only touches the public AIOrouter API contract:\naccount health (`GET /v1/me/usage`), session protection summary\n(`GET /v1/me/protection-summary?window=session`), model discovery (`GET /v1/models`),\nand the request header values the gateway already defines. It stores no API keys,\nwrites no files, and never embeds server-side privacy-taxonomy internals.\n\n## Features\n\n- **Dashboard-governed privacy** (V2.0.0) — Restore/Redact/Disable are controlled\n  **exclusively on the AIOrouter Dashboard** (`https://dashboard.aiorouter.ca`,\n  per-key policy + Shield toggle). This plugin no longer writes\n  `x-aiorouter-privacy-policy` / `x-aiorouter-restoration-markers` and no\n  longer registers a settings section — there is intentionally **no policy\n  control surface in dsh** (single control surface, no dual-control drift).\n- **`aiorouter_shield_status` tool** — model-facing account card (balance, effective policy,\n  Shield state, dashboard link) and the per-session protection mapping table (type × count ×\n  disposition), with metadata-only output (no protected values ever rendered). The effective\n  policy shown is the dashboard-governed GW-3 value.\n- **model discovery** — on plugin load, when an API key is configured, fills the provider's\n  model list from the gateway's OpenAI-compatible `/v1/models` (never clobbers\n  user-maintained models; silent if the key is missing or the call fails).\n- **PL-9 floating value-comparison window** — a draggable, minimisable Shield window\n    in the Web UI (all-English UI). It defaults COLLAPSED to a compact **vertical\n    `{icon / counts / Detected}` card** (V1.0.2): three centre-aligned lines\n    (shield icon, the live session detection count, and the label) in a narrow\n    column, so the bottom-right anchor never overlaps the chat composer input.\n    The collapsed card is itself draggable (drag moves it, click expands).\n    Clicking expands the detailed list, which shows (a) the CURRENT\n    Restore/Redact posture (W-5: the dashboard-governed effective policy and\n    Shield state, read-only via the `aiorouterShield/getStatus` remote) and\n    (b) what was replaced vs what the model\n    actually saw (Type × Before (Original) × LLM Saw × Action, four equal-width columns,\n    with a `Detected {N} · Restore {R} · Redact {D} · 10-minute window` summary line).\n    Restored entries show the original value; redacted entries never show it. The\n    window reads the ephemeral `/v1/me/redaction-trace` endpoint through host-side\n    Typert remotes — the API key stays on the host and the payloads are held in pure\n    client memory (never written to disk or localStorage, never sent to the model).\n- **Client wire contract (dsh v0.1.0-rc.6, V2.6.4):** the bundle declares\n        `inject [\"slots\",\"connection\",\"remote\"]` and resolves the namespace face\n        with `ctx.get('remote.aiorouterShield')` — the reflector-STORE lookup\n        that deliberately has NO cordis inject guard (`gateway.client.spec.ts`\n        resolves `ctx.get('remote.probe')` the same way). The two wrong shapes\n        are documented regressions: declaring `remote.aiorouterShield` in\n        `inject` deadlocks boot (the api-gateway installs that dotted child\n        service only while *this entry's own apply* runs `ctx.remote.$mount`,\n        so cordis inject-wait — which has no timeout — leaves the entry PENDING\n        → `1 entry did not activate … (waiting for service:\n        remote.aiorouterShield)`), and accessing it as a plain property without\n        the inject entry throws `cannot get property\n        \"remote.aiorouterShield\" without inject` at apply time. The namespace\n        face and its methods are bound INSIDE `apply`; the window never touches\n        the ctx proxy at render time (React effects / 60s interval / event\n        handlers call only the bound functions), then the bundle mounts a\n        hand-written Typert remote contribution via\n      `ctx.remote.$mount({ package, descriptors })` (direct, zero-parameter,\n      `cancellation: { parameter: 'signal' }`) exposing `getRedactionTrace` and\n      `getStatus`; both resolve to the `RemoteResult` envelope\n      (`{ ok: true, value } | { ok: false, error }`).\n      The contribution's `result` MUST be a `mode: 'strict'` codec — the client\n      api-gateway's `requireStrictCodec` rejects `src-json` with `field \"result\"\n      has no strict codec` and the whole plugin fails to load; the strict schema\n      is a zod-free shape guard (`src/redaction-trace-codec.ts`) so zod never\n      enters the client bundle. `ctx.connection.api.*` is the *fixed* legacy\n      host-apiproxy face (sessions/goals/settings/…) and does **not** project\n      plugin remotes — do not regress to it (V2.6.2 fix for `Cannot read\n      properties of undefined (reading 'getRedactionTrace')`).\n- **Host wire contract (dsh v0.1.0-rc.6, V2.6.5):** the gateway claims the\n  `aiorouterShield/*` endpoints only after TWO host-side steps. (1) A HOST\n  strict contribution is registered via `ctx.typert.register(...)` — the\n  typert-loader auto-registers only packages that export a `./typert`\n  host-face artifact whose codecs are real zod v4 schemas; this package\n  intentionally ships zero runtime deps, and the typert REGISTRY's own\n  validation (`validateInvocation`/`validateCodec`) accepts the same\n  zod-free shape-guard codecs the client uses (`src/typert-contribution.ts`).\n  (2) The remote service is mounted with\n  `ctx.root.plugin(ShieldHostRemote, { pluginCtx })` — `ctx.root` is the\n  common ancestor of every cordis context, so the gateway's receiver\n  resolution (`ctx.get('aiorouterShield')`) always succeeds; business\n  seams come through `pluginCtx` because root-scope static `inject`\n  resolution is not guaranteed. Without BOTH steps the client sees\n  `transport failure for /api/aiorouterShield/getRedactionTrace: HTTP 404`\n  (V2.6.4 regression root cause). Both are guarded — plugin `apply` never\n  rejects, so a dsh web restart cannot regress into a\n  `Failed to load plugins web boot`.\n\n## Installation\n\n```sh\ndsh plugin add @aiorouter/dsh-shield\n```\n\nThen configure the AIOrouter API key in Settings → Models (`AIOROUTER_API_KEY`).\n\n> **V2.0.0 upgrade note:** plugin versions ≤ 1.0.2 wrote\n> `x-aiorouter-privacy-policy` / `x-aiorouter-restoration-markers` into the\n> provider route and registered an **AIOrouter Shield** settings section —\n> both are REMOVED. Restore/Redact/Disable are governed exclusively on the\n> dashboard (`https://dashboard.aiorouter.ca`, per-key). If you upgraded from\n> ≤1.0.2, remove the two stale header lines from your provider\n> (`~/.dsh/profiles/web/settings.yaml` → `llm-pi-ai.providers.aiorouter.headers`)\n> so requests stop carrying the old policy header; the dashboard settings then\n> take effect for dsh traffic too.\n\n> **Peer-only runtime (V1.0.1):** since V1.0.1 the package declares its `@deepseek-ai/*`\n> runtime imports (`cordis`, `dsh-tools`, `dsh-settings`, `dsh-credentials`,\n> `dsh-typert-protocol`, `schemastery`) as **peerDependencies**, provided by\n> the dsh harness. Do **not** add them back to `dependencies`: a nested copy in a profile's\n> `node_modules` shadows the harness junction and breaks Symbol identity\n> (`Cannot read properties of undefined (reading 'prepare')` — a harness-side\n> peer-resolution bug, fixed in the harness during August 2026). Profiles that run\n> pnpm installs must keep `auto-install-peers=false` in their `.npmrc` (installed with the\n> web profile since 2026-08-20).\n\n## Display contract (parity with the gateway)\n\nThe account card and summary table read the public `/v1/me/*` whitelist exactly as the\ngateway serializes it (2026-08-15 audit):\n\n- `effectiveRestorationPolicy` / `policy` arrive as OBJECTS\n  (`{ default_mode, overrides? }`), not preset-name strings. The plugin maps them to the\n  SD-D9 display names (Restore All / Redact Secrets / Redact All / Custom).\n- The table's Action column prefers `policy_result` (restored → Restored, redacted → Masked —\n  emitted only when unanimous) and falls back to the raw DLP action semantics\n  (`pseudonymized` / `depseudonymized` / `blocked` / `flagged` …) when there is no\n  unanimous result.\n\n## Updating (V1.0.2)\n\nNew versions of this plugin are published to the npm registry. The DSH plugin\nmanager (`dsh plugin`) has **no silent auto-update**: after a release, update\nwith the one-command pnpm forwarder (installs the newer version; the DSH\nreconcile step re-activates the bundle automatically):\n\n```bash\ndsh plugin --profile <profile> update @aiorouter/dsh-shield\n# e.g. dsh plugin --profile web update @aiorouter/dsh-shield\n```\n\n- The `aiorouter_shield_status` tool shows a **`📦 Update available: X → Y`**\n  line (checked against the public npm registry metadata at most once per day)\n  when a newer version exists — the update command is printed right there.\n- Model-catalog auto-sync: the aiorouter route's model list refreshes from the\n  gateway's `/v1/models` every `modelRefreshMinutes` (default 360 = 6h,\n  `0` = at boot only). New gateway models appear automatically; user-added\n  models are never removed (append-only union-merge).\n\n## Privacy posture\n\n- Zero-disk: API keys live only in the credentials seam, resolved per call.\n- Zero-PII: the status tool renders counts, type labels, dispositions, and policy names only.\n- Header values are the preset names the gateway accepts, or JSON the gateway validates.\n  Structurally invalid JSON (bad shape, empty `overrides`, no recognized signal) falls back\n  to the preset rather than poisoning the request. **Per-type NAMES in the advanced JSON are\n  validated by the gateway itself** (this package never embeds the type taxonomy): a mistyped\n  name is a loud, explicit HTTP 400 — never a silent privacy change.\n- This package holds no founder/personal identity and no contract pricing.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}