feat(home-paths): add dshCachePath
This commit is contained in:
1 parent
40606d1558
commit
e4e0e78dd2
8 files changed
+43
-6
No files matched your search
+2
-2
@@ -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 .agents/notes/implemented/architecture/2026-07-24-single-harness-home-resolver.md
|
||||
2026-07-24-single-harness-home-resolver.md: 02578674b4547bae54b2edce99c6c4ef53748588
|
||||
2026-07-24-single-harness-home-resolver.zh.md: 5764be3f85901196cd2a2db77d1fc3838668163f
|
||||
2026-07-24-single-harness-home-resolver.md: c4a0023797c5946f979cfc7b895512e362ac956b
|
||||
2026-07-24-single-harness-home-resolver.zh.md: 0bda1e8405b788ce2939b47a9ca3199ef21fc81c
|
||||
@@ -23,6 +23,8 @@ explicit configured path > $DSH_HOME > ~/.dsh
|
||||
|
||||
An empty or whitespace-only `$DSH_HOME` is treated as unset; otherwise `resolve('')` would silently place the home at the current working directory. The harness keeps all user data under one root; there is no XDG config/data/cache split. `dshHomePath(...segments)` joins deployment-owned children onto that root, and `dsh-app-boot` exposes it to Loader `!!js` config expressions before mounting entries, so shipped compositions derive `sessions` and `storages` without copying the resolver. `dshHomeDisplay()` names a resolved root symbolically for user-facing paths — `~/.dsh` for the default home, `$DSH_HOME` for any configured home — so the user-global `AGENTS.md` label never leaks an absolute machine path. It replaces agent-instructions's bespoke default-vs-`$DSH_HOME` check.
|
||||
|
||||
`dshCachePath(...segments)` derives cache paths through `dshHomePath('cache', ...segments)`, keeping cache placement under the same home policy. It resolves paths without creating directories; callers own directory creation.
|
||||
|
||||
`@deepseek-ai/dsh-home` is deleted. Home-owning providers and boot packages import `resolveDshHome` from `dsh-home-paths`; composition bundles contain only the resolved configuration rows.
|
||||
|
||||
`dsh-telemetry` and its separate home policy are absent under the [SDK project toolchain removal](../../archived/simplification/2026-08-11-remove-sdk-project-toolchain.md), leaving this resolver as the sole home policy.
|
||||
|
||||
@@ -23,6 +23,8 @@ explicit configured path > $DSH_HOME > ~/.dsh
|
||||
|
||||
空或仅含空白的 `$DSH_HOME` 被当作未设置处理;否则,`resolve('')` 会悄悄把 home 落在当前工作目录。harness 把所有用户数据都放在同一个根目录下;不存在 XDG 的 config/data/cache 拆分。`dshHomePath(...segments)` 将部署负责的子路径拼接到该根目录下,`dsh-app-boot` 在挂载条目前向 Loader `!!js` 配置表达式暴露它,因此出厂组合无需复制解析器即可派生 `sessions` 和 `storages`。`dshHomeDisplay()` 为面向用户的路径以符号形式命名已解析的根目录——默认 home 显示为 `~/.dsh`,任何已配置的 home 显示为 `$DSH_HOME`——这样用户全局的 `AGENTS.md` 标签就绝不会泄露机器上的绝对路径。它取代了 agent-instructions 中自定义的「默认值 vs `$DSH_HOME`」判断。
|
||||
|
||||
`dshCachePath(...segments)` 通过 `dshHomePath('cache', ...segments)` 派生缓存路径,使缓存位置遵循同一套 home 策略。它只解析路径,不创建目录;目录创建由调用方负责。
|
||||
|
||||
`@deepseek-ai/dsh-home` 被删除。拥有 home 配置的提供方与 boot 包从 `dsh-home-paths` 导入 `resolveDshHome`;组合包只包含解析后的配置行。
|
||||
|
||||
`dsh-telemetry` 及其独立 home 策略已随 [SDK 项目工具链移除](../../archived/simplification/2026-08-11-remove-sdk-project-toolchain.md)一并消失,因此该解析器是唯一的 home 策略。
|
||||
|
||||
@@ -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/util/home-paths/README.md
|
||||
README.md: 2ce9810bd29bdb00f5eb2e09d886f31e2ca3b176
|
||||
README.zh.md: 0bd46c223992c37be01876597aa239cfc8eb768d
|
||||
README.md: 0fb09c3a9d2deede5d23e9d720e23a3e534bbf81
|
||||
README.zh.md: f02f49f799d28904241c2ca4550e5c42e03c5186
|
||||
@@ -29,14 +29,17 @@ Use these helpers wherever a package must agree with the rest of the harness abo
|
||||
### Resolving the home
|
||||
|
||||
```ts
|
||||
import { resolveDshHome, dshHomePath } from '@deepseek-ai/dsh-home-paths'
|
||||
import { resolveDshHome, dshHomePath, dshCachePath } from '@deepseek-ai/dsh-home-paths'
|
||||
|
||||
const home = resolveDshHome() // configured path, else $DSH_HOME, else ~/.dsh
|
||||
const settings = dshHomePath('settings') // join one child onto the resolved home
|
||||
const cache = dshCachePath('models') // $DSH_HOME/cache/models, default ~/.dsh/cache/models
|
||||
```
|
||||
|
||||
An explicit configured path has the highest precedence, then `$DSH_HOME`, then the default `~/.dsh`. An empty or whitespace-only `$DSH_HOME` is treated as unset, so a blank override never resolves the home to the current working directory.
|
||||
|
||||
`dshCachePath(...segments)` derives paths from the resolved home's `cache` directory. With no segments it returns the cache directory itself. It returns an absolute path without creating directories.
|
||||
|
||||
### Displaying a home
|
||||
|
||||
For user-facing paths, render the root symbolically rather than as a machine path: the default home displays as `~/.dsh` and any configured home displays as `$DSH_HOME`. The display form never leaks an absolute machine path.
|
||||
|
||||
@@ -29,14 +29,17 @@ kind: "package-library"
|
||||
### 解析主目录
|
||||
|
||||
```ts
|
||||
import { resolveDshHome, dshHomePath } from '@deepseek-ai/dsh-home-paths'
|
||||
import { resolveDshHome, dshHomePath, dshCachePath } from '@deepseek-ai/dsh-home-paths'
|
||||
|
||||
const home = resolveDshHome() // configured path, else $DSH_HOME, else ~/.dsh
|
||||
const settings = dshHomePath('settings') // join one child onto the resolved home
|
||||
const cache = dshCachePath('models') // $DSH_HOME/cache/models, default ~/.dsh/cache/models
|
||||
```
|
||||
|
||||
显式配置的路径优先级最高,然后是 `$DSH_HOME`,最后是默认的 `~/.dsh`。空或仅含空白的 `$DSH_HOME` 视为未设置,因此空白的覆盖值绝不会把主目录解析到当前工作目录。
|
||||
|
||||
`dshCachePath(...segments)` 从解析出的主目录下的 `cache` 目录派生路径。不传路径段时返回缓存目录本身。它返回绝对路径,不会创建目录。
|
||||
|
||||
### 展示主目录
|
||||
|
||||
面向用户的路径请以符号形式渲染根目录,而不是机器路径:默认主目录显示为 `~/.dsh`,任何已配置的主目录显示为 `$DSH_HOME`。展示形式绝不会泄露机器的绝对路径。
|
||||
|
||||
@@ -99,6 +99,15 @@ export function dshHomePath(...segments: string[]): string {
|
||||
return join(resolveDshHome(), ...segments)
|
||||
}
|
||||
|
||||
/**
|
||||
* Join path segments onto the resolved Harness home's `cache` directory without creating it.
|
||||
* @param segments - path segments appended to the cache directory; an empty list returns the cache directory itself.
|
||||
* @returns the normalized absolute cache path.
|
||||
*/
|
||||
export function dshCachePath(...segments: string[]): string {
|
||||
return dshHomePath('cache', ...segments)
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe a resolved harness home symbolically for user-facing display.
|
||||
*
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
DSH_HOME_DIR_NAME,
|
||||
canonicalizeWatchPath,
|
||||
defaultDshHome,
|
||||
dshCachePath,
|
||||
dshHomeDisplay,
|
||||
dshHomePath,
|
||||
expandHomePath,
|
||||
@@ -56,6 +57,22 @@ describe('dsh path helpers', () => {
|
||||
expect(dshHomeDisplay('/some/other/root')).toBe('$DSH_HOME')
|
||||
})
|
||||
|
||||
it.each([
|
||||
[undefined, join(homedir(), '.dsh')],
|
||||
['', join(homedir(), '.dsh')],
|
||||
[' ', join(homedir(), '.dsh')],
|
||||
['~/env-dsh', join(homedir(), 'env-dsh')],
|
||||
['./relative-dsh', resolve('./relative-dsh')],
|
||||
] as const)('resolves cache paths with DSH_HOME=%j', (home, expectedHome) => {
|
||||
vi.stubEnv('DSH_HOME', home)
|
||||
try {
|
||||
expect(dshCachePath()).toBe(join(expectedHome, 'cache'))
|
||||
expect(dshCachePath('models', 'index.json')).toBe(join(expectedHome, 'cache', 'models', 'index.json'))
|
||||
} finally {
|
||||
vi.unstubAllEnvs()
|
||||
}
|
||||
})
|
||||
|
||||
it('canonicalizes a watcher ancestor while preserving a missing suffix', async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), 'dsh-watch-path-'))
|
||||
const target = join(root, 'target')
|
||||
@@ -63,6 +80,7 @@ describe('dsh path helpers', () => {
|
||||
try {
|
||||
await mkdir(target)
|
||||
await symlink(target, alias, process.platform === 'win32' ? 'junction' : 'dir')
|
||||
await expect(canonicalizeWatchPath(alias)).resolves.toBe(await realpath(target))
|
||||
await expect(canonicalizeWatchPath(join(alias, 'later', 'config.yml'))).resolves.toBe(
|
||||
join(await realpath(target), 'later', 'config.yml'),
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user