Machine-produced by `pnpm run rescope-vendor --apply` plus the regeneration it prints: `pnpm install` for the lockfile, `pnpm run gen-third-party-notices`, `verify-translation-pairing --write` for the touched bilingual pairs, `gen-doc-graphs`, and one typert snapshot whose ids embed character offsets. `pnpm run rescope-vendor --check` verifies the result. Renames nine vendored packages (cordis, cosmokit, schemastery and the six @cordisjs plugins) and every reference that resolves them: manifest names and dependency keys, module specifiers including declare-module merges, cordis.yml plugin names, tsconfig paths, every Markdown fence, and `docs/` prose. Directory names, upstream versions, and dependency ranges are unchanged, so vendor/README.md still reads as an upstream snapshot; its manifest table gains an upstream-name column so THIRD_PARTY_NOTICES keeps MIT attribution pointed at each fork's origin. The tutorial tier follows the rename end to end: its yaml fences named plugins the Loader can no longer resolve, its `ts ignore-check` fences disagreed with the compiled fences beside them, and its prose quoted both. The contracts that told readers to keep upstream names — the root convention and the vendoring cookbook's tree comment and manifest invariant — now say to rescope instead. Two rules read `@deepseek-ai/` as "another workspace plugin": the client bundle purity gate now names the vendored libraries a browser bundle inlines, and the files where a bare `cordis` is an agent-preset id keep that product data.
dsh-credentials
English | 中文
Credential Service Definition (ctx.credentials). One doctrine, three consequences:
Configuration carries references to secrets, never the secrets. A settings section or cordis.yml entry says apiKeyEnv: DEEPSEEK_API_KEY; the value behind that reference lives with a credential provider. So the settings document stays safe to sync and to render in a configuration UI, describe() can answer "is this configured, where from, can I write it" without ever holding a value, and rotating a secret touches no configuration file.
Consumers resolve per operation. resolve(ref) is called at the start of each operation (the LLM adapters resolve once per model request) and never cached across operations — that read is what makes a changed credential reach the very next request without restarting any plugin.
An empty stored value is absent. Everywhere: resolve skips it, describe reports it unconfigured. A blank can never masquerade as a configured secret.
Surface
import type { Context } from '@deepseek-ai/cordis'
import { credentialRef } from '@deepseek-ai/dsh-credentials'
declare const ctx: Context
const ref = credentialRef('DEEPSEEK_API_KEY') // POSIX shell identifier, branded
const hit = await ctx.credentials.resolve(ref) // { value, source } | undefined
const info = await ctx.credentials.describe(ref) // { configured, source?, writable } — never the value
await ctx.credentials.set(ref, 'sk-…') // rejects while a read-only source shadows the ref
await ctx.credentials.unset(ref) // no-op when absent; same shadowing rule
credentials/updated (ref) fires after a committed change to a provider-managed source — a set, an unset, or an external edit observed in storage. Ambient process-environment changes are not observable and never emit. Consumers do not need the event (they re-resolve per operation); it exists for configuration UIs refreshing a "configured" badge.
The shadowing rule on set/unset is deliberate fail-loud: when a read-only source (the live process environment, in the local provider) currently supplies the reference, a write would appear to succeed while resolution keeps returning the shadowing value — the seam rejects instead, and describe().writable lets a UI render the reference read-only up front.
Providers
dsh-credentials-local layers the inherited process environment over its managed $DSH_HOME/.credentials.yaml document, with the launcher's project and user .env layers as fallbacks. The seam shape leaves room for keyring-, helper-command-, and KMS-backed providers; a remote settings provider never needs to carry secrets.
Model Experience
Indirectly, through the consuming LLM adapters: a resolved value authorizes their provider requests, and the adapter owns every model-visible surface.
KV Cache effect
No direct invalidation; credentials never enter a request prefix.
Known Limitations and Deferred Work
- No enumeration — the seam answers questions about references it is given; configuration surfaces learn the references from settings schemas, so a
list()has no current consumer. - References are environment-variable-shaped — one flat POSIX-identifier namespace until a provider needs richer addressing.
- Process-environment changes are invisible — no event can fire for them; a UI only re-reads
describe()on its own navigation.