Merge master into worktree-windows-runtime

This commit is contained in:
Tianyi Cui
2026-07-21 23:39:14 +08:00
936 changed files with 36271 additions and 10361 deletions

View File

@@ -5,14 +5,13 @@ Zero-dependency primitives shared across the other groups. A package lands here
| Package | Role |
|---|---|
| `brand/` | The type-only `Branded<B>` nominal-typing primitive (no runtime code, no harness deps) |
| `home/` | Canonical `DSH_HOME` resolution from explicit config, environment, or `~/.dsh` (no harness deps) |
| `paths/` | Shared filesystem path constants and helpers for harness user data |
| `paths/` | Canonical single-root `DSH_HOME` resolution plus shared filesystem path constants and helpers for harness user data (no harness deps) |
| `timeout/` | The timing/classification half of a timeout — `clampTimeout`/`deadline`/`timeoutOf`/`TimeoutReason` (pure functions, no harness deps); termination stays in each capability |
| `retention/` | Bounded model-facing output — `ItemRetainer`/`TextRetainer` + neutral notice helpers (pure, no harness deps); business semantics stay in each tool |
`dsh-brand` is the canonical case: it owns ONLY the `Branded<B>` helper, so a capability package can brand the ids it owns (`dsh-tasks`'s `TaskId`, `dsh-session`'s `SessionId`, …) by depending on `dsh-brand` alone, without pulling in an unrelated package just to reach `Branded`.
`dsh-home` gives every package the same configurable Harness home without assigning that cross-cutting fact to bash, skills, or a composition bundle. It resolves an explicit value before `$DSH_HOME`, falls back to `~/.dsh`, and returns an absolute path without caching, creating, or mutating anything.
`dsh-paths` gives every package the same configurable Harness home without assigning that cross-cutting fact to bash, skills, telemetry, or a composition bundle. It resolves an explicit value before `$DSH_HOME`, falls back to `~/.dsh`, and returns an absolute path without caching, creating, or mutating anything. The harness keeps all user data under one root.
`dsh-timeout` follows the same shape for the timeout family: `dsh-bash` and `dsh-web-fetch-local` each fuse a caller's cancellation with a deadline and later classify "timed out" vs "cancelled" by depending on `dsh-timeout` alone. It deliberately owns only the timing/classification half — the *termination* (SIGKILL a process group, tear down a fetch socket) stays in each capability, because no shared layer can own every capability's kill (see [the timeout-library Agent Note](../../.agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.md)).

View File

@@ -11,20 +11,27 @@
"types": "./lib/types/index.d.ts",
"default": "./lib/index.js"
},
"./invariant": {
"types": "./lib/types/invariant.d.ts",
"default": "./lib/invariant.js"
},
"./src/*": "./src/*",
"./package.json": "./package.json"
},
"files": [
"lib/index.js",
"lib/invariant.js",
"lib/types/**/*.d.ts",
"lib/types/**/*.d.ts.map",
"src"
],
"license": "BSD-3-Clause",
"peerDependencies": {
"@deepseek-ai/dsh-invariants": "^0.0.1",
"cordis": "^4.0.0-rc.7"
},
"devDependencies": {
"@deepseek-ai/dsh-invariants": "workspace:^",
"cordis": "^4.0.0-rc.7"
}
}

View File

@@ -0,0 +1,30 @@
/**
* Package-owned invariant companion for `@deepseek-ai/dsh-brand`.
* @module @deepseek-ai/dsh-brand/invariant
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
const PACKAGE_NAME = '@deepseek-ai/dsh-brand'
/** Cordis companion plugin name. */
export const name = 'brand-invariant'
/** Service required before the companion can reserve package ownership. */
export const inject = ['invariants']
/**
* No runtime invariant: this pure utility owns no event stream or mutable runtime data; its value
* algebra is enforced by unit tests.
*/
const install: InvariantInstaller = () => {}
/**
* Register this package's invariant companion.
* @param ctx - Cordis context carrying the invariant service.
* @returns the installed registration's disposer after setup succeeds.
*/
export const apply = (ctx: Context): Promise<() => void> =>
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
/* jscpd:ignore-end */

View File

@@ -7,5 +7,9 @@
"include": [
"src"
],
"references": []
"references": [
{
"path": "../../support/invariants"
}
]
}

View File

@@ -1,21 +0,0 @@
# @deepseek-ai/dsh-home
`@deepseek-ai/dsh-home` is the single owner of DeepSeek Harness home-directory resolution. `resolveDshHome(configured?)` returns an absolute path using this precedence:
1. The explicit `configured` path.
2. The `DSH_HOME` environment variable.
3. The `.dsh` directory under the current user's home directory.
The resolver reads its inputs at call time. It does not cache a result, create the directory, or mutate `process.env`; consumers keep ownership of their own configuration fields and pass the configured value when resolving the shared home.
## Model Experience
Indirectly, through `dsh-tool-bash`, which exposes the resolved path to model bash as `DSH_HOME` without adding a prompt section.
#### KV Cache effect
No direct invalidation; the named consumer owns any request-prefix changes.
## Known Limitations and Deferred Work
- **Resolution only** — the resolver makes a path absolute but does not create it, check access, or canonicalize symlinks; each consumer owns those filesystem decisions.

View File

@@ -1,30 +0,0 @@
{
"name": "@deepseek-ai/dsh-home",
"description": "Canonical DeepSeek Harness home-directory resolver",
"version": "0.0.1",
"private": true,
"type": "module",
"main": "lib/index.js",
"types": "lib/types/index.d.ts",
"exports": {
".": {
"types": "./lib/types/index.d.ts",
"default": "./lib/index.js"
},
"./src/*": "./src/*",
"./package.json": "./package.json"
},
"files": [
"lib/index.js",
"lib/types/**/*.d.ts",
"lib/types/**/*.d.ts.map",
"src"
],
"license": "BSD-3-Clause",
"peerDependencies": {
"cordis": "^4.0.0-rc.6"
},
"devDependencies": {
"cordis": "^4.0.0-rc.6"
}
}

View File

@@ -1,23 +0,0 @@
/**
* Canonical DeepSeek Harness home-directory resolution.
*
* @module @deepseek-ai/dsh-home
*/
import { homedir } from 'node:os'
import { join, resolve } from 'node:path'
const DEFAULT_DSH_HOME_DIRNAME = '.dsh'
/** Environment variable that overrides the default Harness home directory. */
export const DSH_HOME_ENV = 'DSH_HOME' as const
/**
* Resolve the DeepSeek Harness home directory without caching or mutating the environment.
*
* @param configured - Optional configured path, which takes precedence over the environment.
* @returns The absolute configured path, `$DSH_HOME`, or `~/.dsh`, in that order.
*/
export function resolveDshHome(configured?: string): string {
return resolve(configured ?? process.env[DSH_HOME_ENV] ?? join(homedir(), DEFAULT_DSH_HOME_DIRNAME))
}

View File

@@ -1,26 +0,0 @@
import { homedir } from 'node:os'
import { join, resolve } from 'node:path'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { DSH_HOME_ENV, resolveDshHome } from '@deepseek-ai/dsh-home'
afterEach(() => vi.unstubAllEnvs())
describe('resolveDshHome', () => {
it('prefers an explicit configured path and resolves it absolutely', () => {
vi.stubEnv(DSH_HOME_ENV, './environment-home')
expect(resolveDshHome('./configured-home')).toBe(resolve('./configured-home'))
})
it('uses DSH_HOME when no configured path is supplied', () => {
vi.stubEnv(DSH_HOME_ENV, './environment-home')
expect(resolveDshHome()).toBe(resolve('./environment-home'))
})
it('defaults to the .dsh directory under the user home', () => {
vi.stubEnv(DSH_HOME_ENV, undefined)
expect(resolveDshHome()).toBe(join(homedir(), '.dsh'))
})
})

View File

@@ -1,9 +0,0 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "lib/types"
},
"include": ["src"],
"references": []
}

View File

@@ -4,6 +4,10 @@ Shared filesystem path helpers for DeepSeek Harness user data.
## DSH home
`resolveDshHome()` resolves the single-root DeepSeek Harness home. Precedence, highest first: an explicit configured path, `$DSH_HOME`, then `~/.dsh`. The harness keeps all user data under one root.
`dshHomeDisplay()` names an active root symbolically for user-facing paths: `~/.dsh` for the default home, `$DSH_HOME` for any configured home. It never leaks an absolute machine path.
`DSH_HOME_DIR_NAME` owns the default user-data directory name: `.dsh`.
`defaultDshHome()` returns the default DeepSeek Harness home by joining the operating-system home directory with `.dsh`, using Node's platform path rules.

View File

@@ -11,20 +11,27 @@
"types": "./lib/types/index.d.ts",
"default": "./lib/index.js"
},
"./invariant": {
"types": "./lib/types/invariant.d.ts",
"default": "./lib/invariant.js"
},
"./src/*": "./src/*",
"./package.json": "./package.json"
},
"files": [
"lib/index.js",
"lib/invariant.js",
"lib/types/**/*.d.ts",
"lib/types/**/*.d.ts.map",
"src"
],
"license": "BSD-3-Clause",
"peerDependencies": {
"@deepseek-ai/dsh-invariants": "^0.0.1",
"cordis": "^4.0.0-rc.6"
},
"devDependencies": {
"@deepseek-ai/dsh-invariants": "workspace:^",
"cordis": "^4.0.0-rc.6"
}
}

View File

@@ -36,12 +36,30 @@ export function expandHomePath(path: string): string {
}
/**
* Resolve an explicitly configured, environment-selected, or default DSH home.
* Resolve the single-root DeepSeek Harness home.
*
* Precedence, highest first: an explicit configured path, `$DSH_HOME`, then
* `~/.dsh`. The harness keeps all user data under one root. An empty or
* whitespace-only `$DSH_HOME` is treated as unset, so a blank override never
* resolves the home to the current working directory.
* @param configured - explicit harness-home override, which has highest precedence.
* @param env - environment mapping used to read `DSH_HOME`.
* @returns the normalized absolute harness home path.
*/
export function resolveDshHome(configured?: string, env: Record<string, string | undefined> = process.env): string {
const selected = configured ?? env[DSH_HOME_ENV] ?? defaultDshHome()
const fromEnv = env[DSH_HOME_ENV]
const selected = configured ?? (fromEnv !== undefined && fromEnv.trim().length > 0 ? fromEnv : defaultDshHome())
return resolve(expandHomePath(selected))
}
/**
* Describe a resolved harness home symbolically for user-facing display.
*
* It never returns an absolute machine path: the default home is labelled
* `~/.dsh`, and any configured home is labelled `$DSH_HOME`.
* @param resolvedHome - the absolute path returned by {@link resolveDshHome}.
* @returns `~/.dsh` for the default home, otherwise `$DSH_HOME`.
*/
export function dshHomeDisplay(resolvedHome: string): string {
return resolvedHome === resolve(defaultDshHome()) ? DEFAULT_DSH_HOME_DISPLAY : `$${DSH_HOME_ENV}`
}

View File

@@ -0,0 +1,30 @@
/**
* Package-owned invariant companion for `@deepseek-ai/dsh-paths`.
* @module @deepseek-ai/dsh-paths/invariant
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
const PACKAGE_NAME = '@deepseek-ai/dsh-paths'
/** Cordis companion plugin name. */
export const name = 'paths-invariant'
/** Service required before the companion can reserve package ownership. */
export const inject = ['invariants']
/**
* No runtime invariant: this pure utility owns no event stream or mutable runtime data; its value
* algebra is enforced by unit tests.
*/
const install: InvariantInstaller = () => {}
/**
* Register this package's invariant companion.
* @param ctx - Cordis context carrying the invariant service.
* @returns the installed registration's disposer after setup succeeds.
*/
export const apply = (ctx: Context): Promise<() => void> =>
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
/* jscpd:ignore-end */

View File

@@ -5,6 +5,7 @@ import {
DEFAULT_DSH_HOME_DISPLAY,
DSH_HOME_DIR_NAME,
defaultDshHome,
dshHomeDisplay,
expandHomePath,
resolveDshHome,
} from '@deepseek-ai/dsh-paths'
@@ -24,11 +25,21 @@ describe('dsh path helpers', () => {
expect(expandHomePath('~other/.dsh')).toBe('~other/.dsh')
})
it('resolves explicit DSH home before environment and default locations', () => {
it('resolves explicit path before DSH_HOME and the default', () => {
const envHome = join(homedir(), 'env-dsh')
expect(resolveDshHome(undefined, { DSH_HOME: '~/env-dsh' })).toBe(envHome)
expect(resolveDshHome('/tmp/explicit-dsh', { DSH_HOME: '~/env-dsh' })).toBe(resolve('/tmp/explicit-dsh'))
expect(resolveDshHome(undefined, { DSH_HOME: '~/env-dsh' })).toBe(envHome)
expect(resolveDshHome(undefined, {})).toBe(defaultDshHome())
})
it('treats an empty or whitespace-only DSH_HOME as unset', () => {
expect(resolveDshHome(undefined, { DSH_HOME: '' })).toBe(defaultDshHome())
expect(resolveDshHome(undefined, { DSH_HOME: ' ' })).toBe(defaultDshHome())
})
it('labels a resolved home by whether it is the default root', () => {
expect(dshHomeDisplay(resolve(defaultDshHome()))).toBe('~/.dsh')
expect(dshHomeDisplay('/some/other/root')).toBe('$DSH_HOME')
})
})

View File

@@ -7,5 +7,9 @@
"include": [
"src"
],
"references": []
"references": [
{
"path": "../../support/invariants"
}
]
}

View File

@@ -11,20 +11,27 @@
"types": "./lib/types/index.d.ts",
"default": "./lib/index.js"
},
"./invariant": {
"types": "./lib/types/invariant.d.ts",
"default": "./lib/invariant.js"
},
"./src/*": "./src/*",
"./package.json": "./package.json"
},
"files": [
"lib/index.js",
"lib/invariant.js",
"lib/types/**/*.d.ts",
"lib/types/**/*.d.ts.map",
"src"
],
"license": "BSD-3-Clause",
"peerDependencies": {
"@deepseek-ai/dsh-invariants": "^0.0.1",
"cordis": "^4.0.0-rc.6"
},
"devDependencies": {
"@deepseek-ai/dsh-invariants": "workspace:^",
"cordis": "^4.0.0-rc.6"
}
}

View File

@@ -0,0 +1,30 @@
/**
* Package-owned invariant companion for `@deepseek-ai/dsh-retention`.
* @module @deepseek-ai/dsh-retention/invariant
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
const PACKAGE_NAME = '@deepseek-ai/dsh-retention'
/** Cordis companion plugin name. */
export const name = 'retention-invariant'
/** Service required before the companion can reserve package ownership. */
export const inject = ['invariants']
/**
* No runtime invariant: this pure utility owns no event stream or mutable runtime data; its value
* algebra is enforced by unit tests.
*/
const install: InvariantInstaller = () => {}
/**
* Register this package's invariant companion.
* @param ctx - Cordis context carrying the invariant service.
* @returns the installed registration's disposer after setup succeeds.
*/
export const apply = (ctx: Context): Promise<() => void> =>
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
/* jscpd:ignore-end */

View File

@@ -7,5 +7,9 @@
"include": [
"src"
],
"references": []
"references": [
{
"path": "../../support/invariants"
}
]
}

View File

@@ -11,20 +11,27 @@
"types": "./lib/types/index.d.ts",
"default": "./lib/index.js"
},
"./invariant": {
"types": "./lib/types/invariant.d.ts",
"default": "./lib/invariant.js"
},
"./src/*": "./src/*",
"./package.json": "./package.json"
},
"files": [
"lib/index.js",
"lib/invariant.js",
"lib/types/**/*.d.ts",
"lib/types/**/*.d.ts.map",
"src"
],
"license": "BSD-3-Clause",
"peerDependencies": {
"@deepseek-ai/dsh-invariants": "^0.0.1",
"cordis": "^4.0.0-rc.7"
},
"devDependencies": {
"@deepseek-ai/dsh-invariants": "workspace:^",
"cordis": "^4.0.0-rc.7"
}
}

View File

@@ -0,0 +1,30 @@
/**
* Package-owned invariant companion for `@deepseek-ai/dsh-timeout`.
* @module @deepseek-ai/dsh-timeout/invariant
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
const PACKAGE_NAME = '@deepseek-ai/dsh-timeout'
/** Cordis companion plugin name. */
export const name = 'timeout-invariant'
/** Service required before the companion can reserve package ownership. */
export const inject = ['invariants']
/**
* No runtime invariant: this pure utility owns no event stream or mutable runtime data; its value
* algebra is enforced by unit tests.
*/
const install: InvariantInstaller = () => {}
/**
* Register this package's invariant companion.
* @param ctx - Cordis context carrying the invariant service.
* @returns the installed registration's disposer after setup succeeds.
*/
export const apply = (ctx: Context): Promise<() => void> =>
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
/* jscpd:ignore-end */

View File

@@ -7,5 +7,9 @@
"include": [
"src"
],
"references": []
"references": [
{
"path": "../../support/invariants"
}
]
}