bowenliang123/dsh-context
bowenliang123/dsh-contextDSH 上下文洞察面板:Context 仪表盘 + /context命令 + Context 浏览器,查看 Context的分类组成、内容详情、演进趋势、压缩/注入事件、统计等一站式 Context 全生命周期管理。
Zhipu coding-plan sign-in, plan quota, and server-side usage for DeepSeek Harness, shipped as an out-of-tree profile bundle. Nothing in the application is patched: the plugin installs into a profile, adds its own Settings page, and registers the coding-plan credential the shipped zai provider routes read.
Settings → 智谱套餐 (Zhipu plan), contributed by this package's browser half. The page is two views behind a glass tab bar — 联网能力 (what this plugin can do) and 套餐账户 (the account it does it for) — because they are separate subjects, and stacking them made one long page out of two. A view mounts the first time it is chosen and stays mounted while hidden, so a running read or a scrolled table survives the trip to the other view; the bar follows the fluid-interface rules (the selection pill travels from where it already is rather than cross-fading, the press is answered on pointer-down, and the view settles in from the value already on screen). The account view is laid out like ZCode's own usage page:
Z.ai international or BigModel mainland) for the individual, Team, and Start plans: the host opens the relay's authorization page, shows the address with a copy button while it waits, and polls until the attempt settles. The page never sees a token.The zhipuPlan Remote namespace behind that page. The application's own Remote assembly only mounts the namespaces it was built with, so this plugin mounts its own contribution at activation (see src/wire/).
GLM models usable after sign-in. The service writes the signed-in deployment's provider route into the shipped llm-pi-ai entry's settings document — the same document the Models page edits — and clears both routes on sign-out: zai-coding-cn reads DSH_ZHIPU_PLAN_KEY, zai reads DSH_ZHIPU_PLAN_KEY_ZAI. The matching deployment's models resolve in the picker; the other deployment's provider stays dormant, and a request to it fails loud about the missing credential rather than reaching the wrong endpoint. The bundle patch stays insert-only: a patch row overriding another bundle's row would outlive this bundle and keep the plugin manager from uninstalling it. Because the routes live in the profile's own patch layer, uninstalling a signed-in account leaves them (and the stored plan key) in place; remove them in Settings → Models if you want the models gone too.
Zhipu-backed web search, page reading, and GitHub documentation (Zhipu MCP), as additional tools. The same coding-plan credential the sign-in stores also powers three capabilities, so there is no second key to enter — and none of them replaces a built-in tool:
zhipu_web_search, mounted globally while the search switch is on (default on), accepts one to four focused queries, runs them concurrently, and merges the sources round-robin (URL-deduped, capped at 40) — the upstream backend hard-caps ten results per query and takes no count parameter. The built-in web_search keeps running on its shipped backend;zhipu_web_fetch, mounted globally while the reader switch is on (default on), reads one page through Zhipu's web reader (markdown, images dropped, 200,000-character clamp, untrusted-content boundary) — the built-in web_fetch is likewise untouched;github_search_doc, github_get_repo_structure, and github_read_file expose Zhipu's zread server, mounted globally while the zread switch is on (default off); minimal-preset agents are masked off whatever additional tools are currently mounted, and no other agent's tool view changes. zhPrompt (default off) selects the Chinese or English tool descriptions and prompt sections.The four switches live on the zhipu-plan row as volatile Config fields: changing one mounts or unmounts the matching tools and their prompt sections (tool:zhipu_web_search, tool:zhipu_web_fetch, tool:github_*) without a restart. They are also editable right on this page, in the 联网能力 view: each row writes one field through the shell's settings Remote with the namespace revision, so no restart and no hand-editing of profile files is needed.
The built-in web row is never rewritten. The Zhipu capabilities are extra tools, not backend swaps: whatever the switches say, web_search / web_fetch keep pointing at the shipped backends. The two Zhipu providers (zhipu-web-search-prime, zhipu-web-reader) are still registered on the web service and re-gate on the switches and the credential, so a row pointed at them by hand keeps working — the host treats a configured-but-unavailable provider as a hard error rather than falling back, which is exactly why the plugin never auto-points the row while a key is missing. Builds of this plugin from before the additional-tools change did point the row automatically; the current build restores such residue to the inherited backends (deepseek-official / http) on startup and unload — via the same configEditor runtime write, never a bundle-patch override — so cordis.patch.yml stays insert-only and an uninstall leaves no pointer behind. Values pointing at providers the plugin did not register are never touched.
The authorization seam (@deepseek-ai/dsh-authorization) is mounted by the installation's own dsh-base since 0.1.7-rc.2; this plugin requires it and verifies against 0.2.0-rc.1. Its patch deliberately does not insert the seam itself — a row dsh-base already declares would come back from this layer as a duplicate entry id and fail the whole tree load.
Resets are granted by the deployment, not bought by a button. Two things happen on their own:
POST /api/v1/coding-plan/reset/opportunity) on the deployment's own terms: at most once every five minutes, and at the instant a refusal named. That request is what makes the deployment consider the account; it is never a control the user presses.Spending one is the only manual step, and it goes through the dialog. The deployment confirms it — the window stays processing until the status reports the new usedAt, so a stale read cannot make a spent reset look available again. This is the same mechanism ZCode uses (packages/ui/src/lib/codingPlanQuotaResetCoordinator.ts, packages/services/src/usage-stats/providers/bigmodelUsageQuotaProvider.ts in that repository).
pnpm run preview writes the page with fixture data to preview/plan-page.html — signed in in both languages, the reset dialog, the waiting and signed-out screens, a window being read, a read that failed, and the all-time window — in both themes, so the layout can be reviewed without installing anything. preview/plan-page-dark.html is the same page against the dark theme; scripts/preview-shots.mjs photographs the scenes into preview/shots/ when a browser is available.
The plugin is listed in the dsh-market catalog. Open Settings → Plugin Market, search for Zhipu (or 智谱), and press Install — the market installs the prebuilt release tarball below, so nothing is built locally. A profile without the market installs it first (dsh plugin --profile <profile> add dshmarket, then restart the host).
Every release carries the same version-free asset name, so this address always resolves to the newest release:
https://github.com/Ayelsh/dsh-zhipu-plan/releases/latest/download/dsh-zhipu-plan.tgz
# Desktop: Settings → Plugins accepts this address in the install field.
# CLI (for a CLI-owned profile such as `dsh web`):
dsh plugin --profile <profile> add https://github.com/Ayelsh/dsh-zhipu-plan/releases/latest/download/dsh-zhipu-plan.tgz
The asset is the packed package: lib/index.js, lib/typert.js, lib/client.js, cordis.patch.yml, package.json, README.md, and the preview page.
dsh plugin --profile <profile> add github:Ayelsh/dsh-zhipu-plan
A source install packs the repository exactly as it is. The build artifacts — lib/index.js, lib/typert.js, lib/client.js — are committed, so the installed package carries them and no build script runs on your machine. Nothing in src/ is compiled at install time; the market still prefers the prebuilt tarball above because a source checkout is slower to download than the release asset.
The Host restarts the affected plugin graph; a full application restart is the reliable way to pick up a newly installed bundle. Then open Settings → 智谱套餐, choose the deployment and plan kind, and sign in.
Install from the tarball, not from this directory. A local folder installed as a dependency becomes a link: to wherever it sits, and both Node and the harness resolve a linked package by its real path. The harness routes bare @deepseek-ai/* requests to the running installation only for importers under $DSH_HOME/profiles, so a linked folder anywhere else — G:\dsh-build\dist\dsh-zhipu-plan, a checkout, a desktop — cannot resolve @deepseek-ai/cordis and fails to load with failed to import. A tarball is unpacked into the profile, which is why it works. Copying the folder into $DSH_HOME/profiles/<profile>/node_modules/ also works, because then it is under the profiles tree, but nothing manages that copy.
To remove it, uninstall the bundle the same way (remove dsh-zhipu-plan), which also drops its patch layer.
pnpm install
pnpm run build # writes lib/index.js, lib/typert.js, lib/client.js
pnpm run verify # build, then the artifact, dictionary, and Remote checks
pnpm run preview # writes preview/plan-page.html and preview/plan-page-dark.html
node scripts/preview-shots.mjs # optional: photographs both pages into preview/shots
pnpm pack # writes dsh-zhipu-plan-<version>.tgz
Three offline smokes cover what the build gates cannot see, and each takes the harness checkout as its first argument (or DSH_HARNESS_ROOT):
node --experimental-strip-types --no-warnings scripts/mcp-smoke.mts # MCP frame order and failures
node --experimental-strip-types --no-warnings scripts/web-providers-smoke.mts # search/reader backends and tools
node --experimental-strip-types --no-warnings scripts/zread-smoke.mts # the three repo tools
node scripts/integration-smoke.mjs # the service against a real Cordis Context, no network
node scripts/render-smoke.mjs # the page shell and the switches in JSDOM
scripts/integration-smoke.mjs builds a real Context with fake host services and drives the switches, agent events, and the teardown path, asserting the additional tools mount and unmount and that the web row is only ever cleaned of this plugin's own residue. scripts/render-smoke.mjs bundles the real components with the harness's own React, mounts them in JSDOM, and drives both views and the switch write path, including a refused write and its revert.
lib/ is committed, because a source install packs only git-tracked files: pnpm run build refreshes it after a source change and prepack rebuilds it before pnpm pack, so a release never packs stale artifacts — commit the rebuilt lib/ with the source change that caused it. The release asset is that tarball renamed to the version-free dsh-zhipu-plan.tgz, which is what keeps the releases/latest/download/dsh-zhipu-plan.tgz address stable across versions.
The build runs esbuild directly rather than the repository's client preset, because this package is built outside that repository; it then checks the artifacts it produced: the browser bundle only requires specifiers the shell's module table answers, every class name the markup uses exists in the injected stylesheet, both dictionaries carry the same keys, and every Remote method the published wire and the service source name exist on both sides. pnpm run verify adds the regression gates: logic-freeze pins the dictionary, logic identifiers, poll timings, and host reset request a presentation-only change must not move, client-smoke materializes the browser bundle against the shell's module table, and the harness loader must accept the published Typert manifest.
| Path | Role |
|---|---|
src/host/ | The zhipuPlan service: relay sign-in, plan-credential resolution, monitor and reset reads. Ported from the in-tree package of the same shape. |
src/wire/ | The generated Typert faces. typert-host.js is the manifest @deepseek-ai/dsh-typert-loader registers from any mounted package exporting ./typert; typert-remote-client.js is the browser contribution this plugin mounts through ctx.remote.$mount. |
src/client/ | The Settings page: the two-view shell, the capability switches, and the plan page. |
lib/ | Committed build output: index.js (host), typert.js (wire face), client.js (browser). Written by pnpm run build; never edited by hand. |
cordis.patch.yml | The bundle layer: this plugin, insert-only. |
scripts/ | The build, the artifact/regression gates, and the offline smokes and preview harness. |
openspec/ | The change that added the Zhipu MCP tools, its specs, and the real-host e2e evidence. |
The repository's Typert generator analyzes a ts.Program over the whole workspace, which an out-of-tree package does not have. These two files are its output for this service, with the package name updated; pnpm run build fails if they and src/host/service.ts ever disagree about which methods are Remote.
The host half imports @deepseek-ai/cordis, @deepseek-ai/dsh-authorization, @deepseek-ai/dsh-credentials, @deepseek-ai/dsh-settings, @deepseek-ai/dsh-typert-protocol, @deepseek-ai/schemastery, and zod. All of them are part of the installed application's own dependency closure, and the profile's module fallback links resolve them to the copies the running process already loaded — so the plugin shares the host's service instances instead of carrying a second copy. The package therefore declares no dependencies; installing it downloads nothing but the tarball.
The browser half resolves react, react/jsx-runtime, and @deepseek-ai/dsh-client-ui-primitives from the shell's module table and inlines everything else.
zcode.z.ai) using that product's client identity. This is a personal local build; the relay's deployment can change without notice, and the addresses are configuration rather than code (Config fields on the zhipu-plan row).DSH_ZHIPU_PLAN_KEY for the BigModel mainland deployment, DSH_ZHIPU_PLAN_KEY_ZAI for the Z.ai international deployment. A zai provider route configured by hand in Settings → Models would store its own key under ZAI_API_KEY and take precedence for that route.DSH_ZHIPU_PLAN_KEY / DSH_ZHIPU_PLAN_KEY_ZAI — and add no new credential reference and no new dependency. Their MCP endpoints sit under bigmodelApiOrigin (https://open.bigmodel.cn); the international deployment currently uses the same mainland origin (a configurable origin is reserved until the z.ai MCP endpoints are verified).web_search_prime caps 10 results per query and accepts no count parameter (the zhipu_web_search tool fans out up to four queries and merges, cap 40); webReader takes its upstream timeout in seconds (fixed at 20) and its body is clamped to 200,000 characters with a truncation flag, wrapped in explicit untrusted-content boundaries because it is external text; responses are often double-JSON-encoded, so both layers are parsed, and a streamed response over 8 MiB fails instead of being parsed. A content-filtered upstream query reports a fixed hint to narrow the query, and a repository Zhipu has not indexed reports the fixed "not indexed" message instead of the raw upstream error.@deepseek-ai/dsh-settings-file (every shipped app bundle does).reset.ts and service.ts were carried over and then extended.This plugin is not authored by, affiliated with, or endorsed by Z.AI / Zhipu or DeepSeek. The relay mints tokens under ZCode's own client identity, so using this plugin may conflict with the Z.ai terms of service and Z.ai may revoke access at any time. Every relay origin is a configuration field so the dependency can be repointed or removed. "Z.ai", "Zhipu", "BigModel", "GLM" and "ZCode" are trademarks of their respective owners, used here only descriptively.