refactor: apply repository naming contract

Apply the accepted pre-release package, service, type, directory, and role renames as one repository-wide change.
This commit is contained in:
Tianyi Cui
2026-08-13 00:54:38 +08:00
parent 101df7cf58
commit a2d0f7f411
3281 changed files with 21730 additions and 21592 deletions
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/credentials/credentials-local/README.md
README.md: 462618b990f8d07e9b855248db1e149b3c673964
README.zh.md: c3aa2fc942a2e6b73ef9e51a6d3079f11abc1dde
README.md: 63895d34fe8396d55c1d6ef29b3e3d9a9dc17264
README.zh.md: 3c60fb7bbf06a0ae9ec905f36a5c543c2fb6af1b
@@ -15,7 +15,7 @@ The launching environment wins because a per-run override (`DEEPSEEK_API_KEY=…
Everything below it loses to the managed store, so a key written by the Models page takes effect immediately even when an older key sits in a `.env`. Those two layers still resolve when nothing is stored, and `describe()` names them `project-env` or `user-env` with `writable: true` — storing a key replaces them as the effective source.
Under the product CLI, resolution reads the launcher's frozen [environment snapshot](../../util/environment/README.md) rather than `process.env`: only the snapshot can say whether a value came from the launching shell or from a file. A composition the product CLI did not boot has the inherited environment as its only layer, which keeps embedders on the semantics they already had.
Under the product CLI, resolution reads the launcher's frozen [environment snapshot](../../util/launch-environment/README.md) rather than `process.env`: only the snapshot can say whether a value came from the launching shell or from a file. A composition the product CLI did not boot has the inherited environment as its only layer, which keeps embedders on the semantics they already had.
## Config
@@ -15,7 +15,7 @@
它之下的所有来源优先级都低于受管存储,因此 Models 页写入的密钥会立即生效,即使某个 `.env` 里还留着更旧的密钥。没有存储任何东西时这两层仍会参与解析,`describe()` 会把来源报告为 `project-env``user-env``writable: true`——存入一个密钥就会取代它们成为生效来源。
在产品 CLI(命令行界面)下,解析读取的是启动器冻结的[环境快照](../../util/environment/README.md)而不是 `process.env`:只有快照才说得清某个值来自启动 shell 还是来自某个文件。并非由产品 CLI 启动的组合只有继承环境这一层,这让嵌入方保持它们原有的语义。
在产品 CLI(命令行界面)下,解析读取的是启动器冻结的[环境快照](../../util/launch-environment/README.md)而不是 `process.env`:只有快照才说得清某个值来自启动 shell 还是来自某个文件。并非由产品 CLI 启动的组合只有继承环境这一层,这让嵌入方保持它们原有的语义。
## 配置
@@ -34,9 +34,9 @@
"peerDependencies": {
"@deepseek-ai/dsh-atomic-write": "workspace:^",
"@deepseek-ai/dsh-credentials": "workspace:^",
"@deepseek-ai/dsh-environment": "workspace:^",
"@deepseek-ai/dsh-launch-environment": "workspace:^",
"@deepseek-ai/dsh-invariants": "workspace:^",
"@deepseek-ai/dsh-paths": "workspace:^",
"@deepseek-ai/dsh-home-paths": "workspace:^",
"@deepseek-ai/cordis": "workspace:^"
},
"dependencies": {
@@ -47,9 +47,9 @@
"devDependencies": {
"@deepseek-ai/dsh-atomic-write": "workspace:^",
"@deepseek-ai/dsh-credentials": "workspace:^",
"@deepseek-ai/dsh-environment": "workspace:^",
"@deepseek-ai/dsh-launch-environment": "workspace:^",
"@deepseek-ai/dsh-invariants": "workspace:^",
"@deepseek-ai/dsh-paths": "workspace:^",
"@deepseek-ai/dsh-home-paths": "workspace:^",
"@deepseek-ai/cordis": "workspace:^"
}
}
@@ -42,11 +42,11 @@ import { mkdir, readFile, stat } from 'node:fs/promises'
import { dirname, join, resolve } from 'node:path'
import { Document, parseDocument, type YAMLError } from 'yaml'
import { withFileLock, writeFileAtomic } from '@deepseek-ai/dsh-atomic-write'
import { canonicalizeWatchPath, resolveDshHome } from '@deepseek-ai/dsh-paths'
import { environmentOf } from '@deepseek-ai/dsh-environment'
import { Credentials, credentialRef } from '@deepseek-ai/dsh-credentials'
import { canonicalizeWatchPath, resolveDshHome } from '@deepseek-ai/dsh-home-paths'
import { launchEnvironmentOf } from '@deepseek-ai/dsh-launch-environment'
import { CredentialProvider, credentialRef } from '@deepseek-ai/dsh-credentials'
import type { CredentialInfo, CredentialRef, ResolvedCredential } from '@deepseek-ai/dsh-credentials'
import type { EnvironmentEntry } from '@deepseek-ai/dsh-environment'
import type { LaunchEnvironmentEntry } from '@deepseek-ai/dsh-launch-environment'
/** Basename of the credentials document inside the harness home. */
export const CREDENTIALS_FILENAME = '.credentials.yaml'
@@ -204,9 +204,9 @@ function renderDocument(text: string | undefined, ref: CredentialRef, value: str
}
/** File-backed credentials provider (`$DSH_HOME/.credentials.yaml`). */
export class CredentialsLocal extends Credentials {
export class LocalCredentialProvider extends CredentialProvider {
/* jscpd:ignore-start -- deliberate config-surface and lifecycle symmetry with
settings-local (prefer symmetry for parallel values); extracting the shared
settings-file (prefer symmetry for parallel values); extracting the shared
shape would couple the two providers' teardown semantics across packages. */
static Config: z<Config> = z.object({
path: z.string(),
@@ -248,7 +248,7 @@ export class CredentialsLocal extends Credentials {
/** The inherited-environment value for a reference, or `undefined` when empty or unset. */
private inherited(ref: CredentialRef): string | undefined {
const entry = environmentOf(this.ctx).getFrom(ref, ['process'])
const entry = launchEnvironmentOf(this.ctx).getFrom(ref, ['process'])
return entry !== undefined && entry.value.length > 0 ? entry.value : undefined
}
@@ -257,8 +257,8 @@ export class CredentialsLocal extends Credentials {
* it. The invoking project ranks over the user's home file, matching the
* environment layering: the more specific location wins.
*/
private dotenvFallback(ref: CredentialRef): EnvironmentEntry | undefined {
const entry = environmentOf(this.ctx).getFrom(ref, ['project-env', 'user-env'])
private dotenvFallback(ref: CredentialRef): LaunchEnvironmentEntry | undefined {
const entry = launchEnvironmentOf(this.ctx).getFrom(ref, ['project-env', 'user-env'])
return entry !== undefined && entry.value.length > 0 ? entry : undefined
}
@@ -271,7 +271,7 @@ export class CredentialsLocal extends Credentials {
}
await this.loadInitial()
if (!this.spec.watch) return
/* jscpd:ignore-start -- same watcher discipline as settings-local by design:
/* jscpd:ignore-start -- same watcher discipline as settings-file by design:
the serialized-refresh and quiesce-on-dispose shape is the reviewed
lifecycle contract, not accidental repetition. */
const watcher = chokidarWatch(await canonicalizeWatchPath(this.spec.filename), {
@@ -342,7 +342,7 @@ export class CredentialsLocal extends Credentials {
}
/* jscpd:ignore-start -- the operation-chain and reload lifecycle is the same
reviewed contract as settings-local, deliberately mirrored (prefer symmetry
reviewed contract as settings-file, deliberately mirrored (prefer symmetry
for parallel values); the two providers own different documents and
failure policies, so extracting a shared helper would couple their teardown
semantics across packages for a handful of lines. */
@@ -434,7 +434,7 @@ export class CredentialsLocal extends Credentials {
this.text = text
}
/* jscpd:ignore-start -- same deliberate mirror of settings-local's reload and
/* jscpd:ignore-start -- same deliberate mirror of settings-file's reload and
reconcile policy: warn-and-keep on a reload, throw on a write, invariant
failures propagate. */
/**
@@ -493,4 +493,4 @@ export class CredentialsLocal extends Credentials {
}
}
export default CredentialsLocal
export default LocalCredentialProvider
@@ -4,7 +4,7 @@ import { mkdtemp, rm } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { credentialRef } from '@deepseek-ai/dsh-credentials'
import { CredentialsLocal } from '../src/index.ts'
import { LocalCredentialProvider } from '../src/index.ts'
// The atomic write is the gated asynchronous hold point inside a queued
// write; gating it makes the dispose-versus-queued-write race fully
@@ -42,7 +42,7 @@ describe('write-drain teardown', () => {
const dir = await mkdtemp(join(tmpdir(), 'dsh-credentials-drain-'))
cleanups.push(() => rm(dir, { recursive: true, force: true }))
const ctx = new Context()
const fiber = ctx.plugin(CredentialsLocal, { path: join(dir, '.credentials.yaml'), watch: false })
const fiber = ctx.plugin(LocalCredentialProvider, { path: join(dir, '.credentials.yaml'), watch: false })
await fiber
const service = ctx.credentials
@@ -4,9 +4,9 @@ import { mkdir, mkdtemp, readFile, rm, stat, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join, resolve } from 'node:path'
import { credentialRef } from '@deepseek-ai/dsh-credentials'
import { createEnvironmentSnapshot, DSH_ENVIRONMENT_KEY } from '@deepseek-ai/dsh-environment'
import { createLaunchEnvironmentSnapshot, DSH_LAUNCH_ENVIRONMENT_KEY } from '@deepseek-ai/dsh-launch-environment'
import type { CredentialRef } from '@deepseek-ai/dsh-credentials'
import { CredentialsLocal, resolveSpec } from '../src/index.ts'
import { LocalCredentialProvider, resolveSpec } from '../src/index.ts'
/** Credential documents are seeded owner-only, exactly as the provider creates them. */
function writeCredentials(file: string, text: string): Promise<void> {
@@ -29,9 +29,9 @@ async function tempDir(): Promise<string> {
return dir
}
async function boot(config: ConstructorParameters<typeof CredentialsLocal>[1]): Promise<Context> {
async function boot(config: ConstructorParameters<typeof LocalCredentialProvider>[1]): Promise<Context> {
const ctx = new Context()
const fiber = ctx.plugin(CredentialsLocal, config)
const fiber = ctx.plugin(LocalCredentialProvider, config)
cleanups.push(async () => {
await fiber.dispose()
})
@@ -102,7 +102,7 @@ describe('layering and reads', () => {
const path = join(dir, 'occupied')
await mkdir(path)
const ctx = new Context()
await expect(ctx.plugin(CredentialsLocal, { path, watch: false })).rejects.toThrow()
await expect(ctx.plugin(LocalCredentialProvider, { path, watch: false })).rejects.toThrow()
})
})
@@ -111,11 +111,11 @@ describe('layer ladder', () => {
// invoking directory's .env supplies no credential at all.
async function bootLayered(
path: string,
layers: Parameters<typeof createEnvironmentSnapshot>[0],
layers: Parameters<typeof createLaunchEnvironmentSnapshot>[0],
): Promise<Context> {
const ctx = new Context()
ctx.provide(DSH_ENVIRONMENT_KEY, createEnvironmentSnapshot(layers))
const fiber = ctx.plugin(CredentialsLocal, { path, watch: false })
ctx.provide(DSH_LAUNCH_ENVIRONMENT_KEY, createLaunchEnvironmentSnapshot(layers))
const fiber = ctx.plugin(LocalCredentialProvider, { path, watch: false })
cleanups.push(async () => { await fiber.dispose() })
await fiber
return ctx
@@ -175,7 +175,7 @@ describe('layer ladder', () => {
const ctx = new Context()
// Before the contents are read at all: serving secrets out of a
// world-readable file would make the 0600 the provider writes meaningless.
await expect(ctx.plugin(CredentialsLocal, { path, watch: false }))
await expect(ctx.plugin(LocalCredentialProvider, { path, watch: false }))
.rejects.toThrow(/readable beyond its owner \(mode 644\)/)
})
@@ -187,14 +187,14 @@ describe('layer ladder', () => {
// reached at all is a misconfiguration: the parent is a file, so the
// check fails with ENOTDIR rather than concluding "no credentials yet".
const ctx = new Context()
await expect(ctx.plugin(CredentialsLocal, { path: join(notADirectory, '.credentials.yaml'), watch: false }))
await expect(ctx.plugin(LocalCredentialProvider, { path: join(notADirectory, '.credentials.yaml'), watch: false }))
.rejects.toThrow(/ENOTDIR/)
})
it('propagates a permission check rejected before the OS lookup', async () => {
const dir = await tempDir()
const ctx = new Context()
await expect(ctx.plugin(CredentialsLocal, { path: join(dir, '.credentials\0.yaml'), watch: false }))
await expect(ctx.plugin(LocalCredentialProvider, { path: join(dir, '.credentials\0.yaml'), watch: false }))
.rejects.toMatchObject({ code: 'ERR_INVALID_ARG_VALUE' })
})
@@ -206,7 +206,7 @@ describe('layer ladder', () => {
// rather than silently serve nothing.
await mkdir(path, { mode: 0o700 })
const ctx = new Context()
await expect(ctx.plugin(CredentialsLocal, { path, watch: false })).rejects.toThrow(/EISDIR/)
await expect(ctx.plugin(LocalCredentialProvider, { path, watch: false })).rejects.toThrow(/EISDIR/)
})
it('lets only the inherited environment shadow the store, read-only', async () => {
@@ -240,7 +240,7 @@ describe('document validation', () => {
const path = join(dir, '.credentials.yaml')
await writeCredentials(path, text)
const ctx = new Context()
await expect(ctx.plugin(CredentialsLocal, { path, watch: false })).rejects.toThrow(message)
await expect(ctx.plugin(LocalCredentialProvider, { path, watch: false })).rejects.toThrow(message)
})
it('never puts a credential value in a diagnostic', async () => {
@@ -253,7 +253,7 @@ describe('document validation', () => {
await writeCredentials(path, `DSH_CRED_TEST: "${secret}\n`)
let failure: unknown
try {
await new Context().plugin(CredentialsLocal, { path, watch: false })
await new Context().plugin(LocalCredentialProvider, { path, watch: false })
} catch (error) {
failure = error
}
@@ -386,7 +386,7 @@ describe('document writes', () => {
it('refuses writes after disposal', async () => {
const dir = await tempDir()
const ctx = new Context()
const fiber = ctx.plugin(CredentialsLocal, { path: join(dir, '.credentials.yaml'), watch: false })
const fiber = ctx.plugin(LocalCredentialProvider, { path: join(dir, '.credentials.yaml'), watch: false })
await fiber
// Capture the handle first: disposal also removes the ctx.credentials service.
const service = ctx.credentials
@@ -8,7 +8,7 @@ import { mkdtemp, readFile, rm, stat, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { credentialRef } from '@deepseek-ai/dsh-credentials'
import { CredentialsLocal } from '../src/index.ts'
import { LocalCredentialProvider } from '../src/index.ts'
/** Credential documents are seeded owner-only, exactly as the provider creates them. */
function writeCredentials(file: string, text: string): Promise<void> {
@@ -31,9 +31,9 @@ async function tempDir(): Promise<string> {
return dir
}
async function boot(config: ConstructorParameters<typeof CredentialsLocal>[1]): Promise<Context> {
async function boot(config: ConstructorParameters<typeof LocalCredentialProvider>[1]): Promise<Context> {
const ctx = new Context()
const fiber = ctx.plugin(CredentialsLocal, config)
const fiber = ctx.plugin(LocalCredentialProvider, config)
cleanups.push(async () => { await fiber.dispose() })
await fiber
return ctx
@@ -4,7 +4,7 @@ import { chmod, mkdtemp, rm, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { credentialRef } from '@deepseek-ai/dsh-credentials'
import { CredentialsLocal } from '../src/index.ts'
import { LocalCredentialProvider } from '../src/index.ts'
const fsHarness = vi.hoisted(() => ({
nextReadError: undefined as NodeJS.ErrnoException | undefined,
@@ -78,9 +78,9 @@ async function tempDir(): Promise<string> {
return dir
}
async function boot(config: ConstructorParameters<typeof CredentialsLocal>[1]): Promise<Context> {
async function boot(config: ConstructorParameters<typeof LocalCredentialProvider>[1]): Promise<Context> {
const ctx = new Context()
const fiber = ctx.plugin(CredentialsLocal, config)
const fiber = ctx.plugin(LocalCredentialProvider, config)
cleanups.push(async () => {
await fiber.dispose()
})
@@ -174,7 +174,7 @@ describe('watcher pipeline', () => {
const path = join(dir, '.credentials.yaml')
await writeCredentials(path, 'DSH_CRED_PIPE: initial\n')
const ctx = new Context()
const fiber = ctx.plugin(CredentialsLocal, { path, debounceMs: 5 })
const fiber = ctx.plugin(LocalCredentialProvider, { path, debounceMs: 5 })
await fiber
let disposed = false
let postDisposeCommits = 0
@@ -21,16 +21,16 @@
"path": "../../util/atomic-write"
},
{
"path": "../../util/environment"
"path": "../../util/launch-environment"
},
{
"path": "../../util/paths"
"path": "../../util/home-paths"
},
{
"path": "../credentials"
},
{
"path": "../../support/invariants"
"path": "../../runtime-diagnostics/invariants"
}
]
}
@@ -37,17 +37,17 @@ export interface ResolvedCredential {
/** Source and writability facts for one reference, safe for configuration UIs — never the value. */
export interface CredentialInfo {
/** Whether {@link Credentials.resolve} would currently return a value. */
/** Whether {@link CredentialProvider.resolve} would currently return a value. */
configured: boolean
/** Source layer currently supplying the value; absent while unconfigured. */
source?: string
/** Whether {@link Credentials.set} would currently succeed for this reference. */
/** Whether {@link CredentialProvider.set} would currently succeed for this reference. */
writable: boolean
}
declare module '@deepseek-ai/cordis' {
interface Context {
credentials: Credentials
credentials: CredentialProvider
}
}
@@ -57,7 +57,7 @@ declare module '@deepseek-ai/cordis' {
* value is absent everywhere — `resolve` skips it, `describe` reports it
* unconfigured — so a blank never masquerades as a configured secret.
*/
export abstract class Credentials extends Service {
export abstract class CredentialProvider extends Service {
constructor(ctx: Context) {
super(ctx, 'credentials')
}
@@ -142,4 +142,4 @@ export abstract class Credentials extends Service {
}
}
export default Credentials
export default CredentialProvider
@@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest'
import { Context } from '@deepseek-ai/cordis'
import InvariantService from '@deepseek-ai/dsh-invariants'
import InvariantRegistry from '@deepseek-ai/dsh-invariants'
import { credentialRef } from '../src/index.ts'
import * as CredentialsInvariant from '../src/invariant.ts'
import { MemoryCredentials } from './memory.ts'
@@ -10,7 +10,7 @@ const REF = credentialRef('DEEPSEEK_API_KEY')
describe('credentials invariant companion', () => {
it('accepts a committed change emitted by a live service', async () => {
const ctx = new Context()
await ctx.plugin(InvariantService)
await ctx.plugin(InvariantRegistry)
await ctx.plugin(CredentialsInvariant)
await ctx.plugin(MemoryCredentials)
@@ -19,7 +19,7 @@ describe('credentials invariant companion', () => {
it('fails an update event emitted without a live service', async () => {
const ctx = new Context()
await ctx.plugin(InvariantService)
await ctx.plugin(InvariantRegistry)
await ctx.plugin(CredentialsInvariant)
expect(() => { ctx.emit('credentials/updated', REF) }).toThrow(/invariant violated by "@deepseek-ai\/dsh-credentials"/)
@@ -27,7 +27,7 @@ describe('credentials invariant companion', () => {
it('reserves the package name against duplicate registration', async () => {
const ctx = new Context()
await ctx.plugin(InvariantService)
await ctx.plugin(InvariantRegistry)
await ctx.plugin(CredentialsInvariant)
expect(() => {
@@ -1,12 +1,12 @@
import type { Context } from '@deepseek-ai/cordis'
import { Credentials } from '../src/index.ts'
import { CredentialProvider } from '../src/index.ts'
import type { CredentialInfo, CredentialRef, ResolvedCredential } from '../src/index.ts'
/**
* In-memory credentials provider for interface and consumer tests: one
* always-writable `memory` source seeded from plugin config.
*/
export class MemoryCredentials extends Credentials {
export class MemoryCredentials extends CredentialProvider {
private readonly store = new Map<string, string>()
constructor(ctx: Context, seed: Record<string, string> = {}) {
@@ -18,7 +18,7 @@
"path": "../../util/brand"
},
{
"path": "../../support/invariants"
"path": "../../runtime-diagnostics/invariants"
}
]
}