reactive-resume
reactive-resume
A one-of-a-kind resume builder that keeps your privacy in mind. Completely secure, customizable, portable, open-source and free forever. Try it out today!
PROJECT TOPICS
PROJECT README
Unified provider authentication, model catalog, and selection routing for DeepSeek Harness.
@fhxgs/dsh-model-hub delivers a single, full-featured model management layer for DeepSeek Harness (DSH). It packages both a Node.js Host plugin and a lazy-loaded browser Client. Everything this plugin owns — provider lifecycle, sign-in attempts, the model catalog, and session selection — travels over its own secure, loopback-only /model-hub RPC channel. Everything the harness already owns keeps using the official /api: settings reads and writes, credential description and storage, endpoint discovery, and the host model list behind the global default. The plugin joins the harness rather than tunnelling around it.
Installing this plugin replaces the default fragmented model settings with a unified experience: one settings section, one composer picker, and one /model command.
| Feature | Description |
|---|---|
| Provider Sign-in | Complete OAuth / device-code authentication flow directly in the browser with real-time attempt tracking, prompt dialogs, and a 30-minute host timeout. Credentials pass straight into secure storage and are never exposed in logs or state snapshots. |
| Provider Lifecycle | Clean management actions (activate, deactivate, logout, useRecord) guarded by impact confirmation dialogs. No generic settings overrides. |
| Provider Customization | Edit API keys (stored safely via credentials.set), base URLs, protocols, display names, and per-route model mappings. Includes endpoint discovery and custom provider creation. |
| Rich Model Catalog | Extends the native llm.models schema to retain inputModalities, contextWindow, and defaultMaxTokens. Features revision-keyed caching, an 8-request concurrency gate, and per-model error isolation. |
| Curation Policy | Flexible visibility rules (all or explicit include allowlists) applied synchronously across both settings and the composer picker. |
| Session Selection & Routing | In-memory session model selection with { prepend: true } hook priority. Subagents follow a 3-tier routing strategy evaluated at agent/created. Blocks unroutable message sends upfront. |
| Thinking Effort Control | Dynamic slider automatically calibrated to each model's supported reasoning levels (e.g., xhigh/max for gpt-5.6-sol, hidden for non-reasoning models). |
| Fast Mode | Metadata-driven toggle for models declaring accelerated service tiers (e.g., gpt-5.6-sol priority tier). |
| Built-in Providers | Out-of-the-box support for qwen-code (RFC 8628 device-code login via chat.qwen.ai) and codex (OpenAI Codex: authorization code + PKCE loopback login with 7 GPT-5.x models). |
| Bilingual Interface | Native Simplified Chinese and English UI following the harness shell's language preferences. |
| Loopback Security | Every /model-hub endpoint is bound strictly to authority: 'loopback' with strict Zod payload validation and sanitized error responses. |
[!NOTE]
dsh pluginruns pnpm under the hood (spawnSync('pnpm')), so pnpm must be available in yourPATH. If needed, enable it via corepack:corepack enable pnpm
Add the plugin to your target profile:
dsh plugin --profile web add @fhxgs/dsh-model-hub
Restart the profile after installation (profile composition changes do not hot-reload).
The plugin automatically registers its patch configuration (cordis.patch.yml), enabling @deepseek-ai/dsh-authorization and disabling the default ui-settings-models and ui-model-selection components. No manual configuration editing is required.
To uninstall:
dsh plugin --profile web remove @fhxgs/dsh-model-hub
Uninstalling cleanly restores the official default model settings and picker.
dsh plugin add runs pnpm, and pnpm resolves peer dependencies against the profile directory alone. The harness installs none of its own packages there: the Host half's @deepseek-ai/* imports and the browser half's platform modules are both answered at runtime by the running shell's module table. Those eighteen peers are therefore declared optional — their ranges say which harness this build was written against, not what a package manager should go and fetch — so a cold profile install no longer reports them missing.
Two peers stay required, because they are the two an environment could genuinely be without and the warning is worth keeping as a signal:
Issues with peer dependencies found
✕ missing peer @earendil-works/pi-ai
✕ missing peer react
That warning is expected on a cold install and the plugin loads normally — the host runtime supplies @earendil-works/pi-ai, and the web shell seeds react into the frozen module table before any plugin factory runs. A warning naming anything else is worth reading.
/model.The plugin manages its configuration under the model-hub settings namespace:
model-hub:
picker:
mode: include # 'all' | 'include' (default: all models visible)
include: # Active when mode is 'include'
- { provider: kimi-coding, model: k3 }
fastMode: # Routes whose accelerated service tier is switched on
- { provider: codex, model: gpt-5.6-sol }
preferredEffort: high # Optional default reasoning effort level
subagent: inherit # 'inherit' | { provider, model, reasoningEffort? }
{ picker: { include: [], fastMode: [] }, subagent: 'inherit' }.agent-default-model namespace. The plugin reads this value but only modifies it when explicitly confirmed by the user.model-hub-providers to prevent catalog cache invalidation during policy updates.Captured from a cold-installed isolated profile on DSH 0.1.1-rc.2, dark theme.
| Composer picker (Simple) | Providers | Catalog |
|---|---|---|
![]() |
![]() |
![]() |
Both Host and Client components reside in a single npm package:
/model-hub RPC channel, settings schemas, built-in provider adapters, and session selection hooks./model modal.src/
├── index.ts # Host entrypoint: RPC channel, settings namespace, lifecycle setup
├── rpc/ # Single-layer wire envelope, router, and 7 standard error codes
├── auth/ # Authorization attempt bridge and two-axis auth.state projection
├── provider/ # Adapter bindings and lifecycle operations (activate/deactivate/logout/useRecord)
├── provider/native/ # Self-served providers (OAuth flows for qwen-code and codex)
├── catalog/ # Super-set model catalog, curation policy filter, and LRU cache
├── selection/ # Session model selection, effort resolver, and subagent routing rules
├── settings/ # Settings schema definitions
└── client/ # Browser UI components (Settings cards, Composer picker, Attempt modal)
Build outputs are published to lib/index.js, lib/invariant.js, lib/client.js, lib/types/**, and cordis.patch.yml.
[!IMPORTANT] The
./clientexport is Loader-only.lib/client.jsis not a module anything imports. Its body is a singlewindow.__ModuleLoader__.load({ ... })call, and the harness shell serves the file to the browser rather than resolving it —import()from Node andrequire()from a bundler both throw, whatever extension the file carries. The export is declared so the shell can address the file by name; it is not a public API surface, and nothing outside the DSH browser runtime can consume it. This is also whypublintreports exactly one finding against this package (it suggests renaming the file to.cjs), and why that finding is documented and declined rather than silenced: the rename would quiet the warning without making the export usable. The reasoning is recorded in full inscripts/verify-manifest.mjs, and the exemption is matched against the report's exact wording, so a different finding still fails the gate.
corepack pnpm install
corepack pnpm run build # Generates lib/types (tsc) and runtime bundles (tsdown)
corepack pnpm run verify # Five gates: bundle purity, patch keys, sourcemap link, published paths, manifest
corepack pnpm run test # Runs vitest test suite
corepack pnpm run smoke:p0 # Cold-installs tarball into an isolated test profile
prepack runs verify before npm pack or npm publish to prevent broken or dirty artifacts; prepublishOnly additionally rebuilds from a cleaned lib/ and runs the full test suite, so a publish cannot ship a stale bundle.smoke:p0) uses an isolated temporary directory (DSH_HOME=$(mktemp -d)) and never touches your local ~/.dsh.scripts/gate-p1.md and scripts/gate-p3.md.scripts/release-checklist.md.Those three documents live in
scripts/, which is deliberately kept out of the published tarball, so the links above are absolute: they resolve from the npm page as well as from a checkout.
| Requirement | Supported Range |
|---|---|
| Node.js | ^22.19 \|\| >=24 |
| DeepSeek Harness | 0.1.1-rc.2 |
@deepseek-ai/* peer dependencies |
^0.1.1-rc.2 |
@deepseek-ai/cordis |
^4.0.1 |
@earendil-works/pi-ai |
~0.82.1 (peer dependency supplied by host runtime) |
| React | ^18.2.0 (peer dependency) |
/model-hub endpoints return HTTP 403 when accessed outside loopback. Non-loopback pages display a read-only badge; model changes must be performed on the host machine.http://localhost:1455/auth/callback), so only one such sign-in can run on a machine at a time; a port already held ends the attempt immediately with the code LOOPBACK_PORT_IN_USE rather than waiting, and there is no device-code fallback for this route. The receiver binds both loopback families where the machine has both — if ::1 cannot be bound the sign-in continues on 127.0.0.1 alone, recorded as LOOPBACK_IPV6_UNAVAILABLE.picked ▸ request header ▸ global default), which this plugin deliberately never writes. Two consequences follow. Switching to a model that takes images does not make the image already in the composer sendable — Core still judges it against the model its own chain names, and the refusal quotes that model rather than the one just chosen. And where the global default names a provider no adapter serves, Core refuses every message of a session that has not yet completed a request — text as well as images — whatever is selected here; repoint or clear the global default to lift it.request/header event that only a completed request writes. Until that first request, nothing reading the durable record sees the choice — Core's own admission chain included — and a restart drops the session back to the global default.session.selectModel remains reachable from ACP and SDK clients even with the official Models UI disabled, and it writes a tier of Core's chain that outranks the request header and has no clearing path while that session's agent lives. A session switched that way admits messages against Core's choice from then on, and selections made here no longer converge with it, however many requests the session completes.MIT © 2026 FHGS
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: model-catalog、oauth。