@deepseek-ai/dsh-settings-file 0.1.1-rc.2 → 0.1.2-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +126 -21
- package/README.zh.md +129 -24
- package/lib/index.js +2 -1
- package/package.json +13 -12
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/settings/settings-file/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 348441aa5cdce219dcf87abdd1c8ba9f9ce74599
|
|
6
|
+
README.zh.md: 809cda2ad8066ffeb210ecf5cfa6163f7228e7ab
|
package/README.md
CHANGED
|
@@ -1,37 +1,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "The file-backed settings provider for users and maintainers choosing, configuring, or debugging the YAML/JSON settings document and its hot reload."
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# @deepseek-ai/dsh-settings-file
|
|
2
7
|
|
|
3
8
|
English | [中文](README.zh.md)
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
`dsh-settings-file` keeps every namespace's user settings in one YAML or JSON document, by default `settings.yaml` under the harness home: users can edit the document directly — changes take effect live — or write through the service, which merges concurrent edits safely. YAML writes preserve comments, anchors, and formatting on every untouched node, and a section owned by a plugin that is not loaded is never dropped. Boot fails loud on an invalid document; a live reload that fails keeps the last good sections and warns rather than taking the process down.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Use this package](#use-this-package)
|
|
17
|
+
- [Understand the implementation](#understand-the-implementation)
|
|
18
|
+
- [Further Exploration](#further-exploration)
|
|
19
|
+
- [Model Experience](#model-experience)
|
|
20
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
21
|
+
- [Dev Note](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## Use this package
|
|
27
|
+
|
|
28
|
+
Mount this provider when a composition wants one user-editable settings document. The common path is explicit: mount the provider, register namespaces through `ctx.settings`, and let users edit the document or a configuration UI write through the service.
|
|
29
|
+
|
|
30
|
+
### When to choose it
|
|
31
|
+
|
|
32
|
+
Choose it as the default user-settings store: one human-readable document that users can open in any editor, with changes taking effect without a restart. Choose it when comments and formatting in that document matter, because writes preserve them. A non-file store, such as a remote settings backend, is not shipped here; that would need another provider.
|
|
33
|
+
|
|
34
|
+
### Minimal configuration
|
|
6
35
|
|
|
7
|
-
|
|
36
|
+
```yaml
|
|
37
|
+
- name: '@deepseek-ai/dsh-settings-file'
|
|
38
|
+
config:
|
|
39
|
+
path: /absolute/path/to/settings.yaml
|
|
40
|
+
```
|
|
8
41
|
|
|
9
|
-
| Field |
|
|
42
|
+
| Field | Default | Meaning |
|
|
10
43
|
|---|---|---|
|
|
11
|
-
| `path` | Settings document path; extension picks the format (`.yaml
|
|
12
|
-
| `dshHome` | Harness home used when `path` is omitted |
|
|
13
|
-
| `watch` | Watch the document and hot-publish external edits |
|
|
14
|
-
| `debounceMs` | Watcher write-settle window in milliseconds |
|
|
44
|
+
| `path` | `<harness home>/settings.yaml` | Settings document path; the extension picks the format (`.yaml`, `.yml`, or `.json`) |
|
|
45
|
+
| `dshHome` | `$DSH_HOME` or `~/.dsh` | Harness home used when `path` is omitted |
|
|
46
|
+
| `watch` | `true` | Watch the document and hot-publish external edits |
|
|
47
|
+
| `debounceMs` | `100` | Watcher write-settle window, in milliseconds |
|
|
48
|
+
|
|
49
|
+
The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-settings-file) is the exhaustive source for every accepted field and its JSDoc.
|
|
50
|
+
|
|
51
|
+
### Editing the document
|
|
52
|
+
|
|
53
|
+
The document is a YAML or JSON mapping of namespace to user section. Users can edit it directly: any change takes effect automatically, and deleting the file resets every namespace to defaults and `base`. A document that exists but is invalid fails plugin load at boot — the provider never silently ignores or overwrites it. Once live, an unreadable or unparsable edit warns and keeps the last good sections, so a hand-edit mistake cannot take the process down.
|
|
54
|
+
|
|
55
|
+
### Writing through the service
|
|
56
|
+
|
|
57
|
+
Writes through `ctx.settings` never lose concurrent changes: an external edit still in flight, a change the watcher missed, or another process's write is merged into the document before the write lands. YAML edits are leaf-level diffs: only changed values are set and only removed keys deleted, so comments, anchors, and formatting survive on every untouched node and on the key of every changed pair; a changed array or other non-map value replaces wholesale. JSON documents re-serialize without comments. If the on-disk document turned invalid, the write fails loud instead of overwriting the user's manual edit.
|
|
58
|
+
|
|
59
|
+
The lock has a 2-second acquisition deadline with exponential backoff; a contender that times out leaves the existing lock in place, because lock age cannot distinguish a crashed owner from a paused live writer — orphan lock recovery is an operator action. The document is created `0600` under an owner-only `0700` directory and replaced atomically through a random-suffix temp sibling that never follows a planted symlink.
|
|
60
|
+
|
|
61
|
+
### Failures and recovery
|
|
62
|
+
|
|
63
|
+
- An unsupported extension fails at load — the format comes from the extension (`.yaml`, `.yml`, `.json`).
|
|
64
|
+
- A missing document is an empty store; deleting the file returns to that state.
|
|
65
|
+
- An invalid on-disk document at runtime blocks nothing but keeps the last good sections; a write refuses to overwrite it.
|
|
66
|
+
- `prepareDocument()` materializes an absent document as an empty owner-only file before a native editor opens it.
|
|
67
|
+
|
|
68
|
+
-----
|
|
69
|
+
|
|
70
|
+
<a id="understand-the-implementation"></a>
|
|
71
|
+
## Understand the implementation
|
|
15
72
|
|
|
16
|
-
|
|
73
|
+
<details>
|
|
74
|
+
<summary>Implementation internals — click to expand</summary>
|
|
17
75
|
|
|
18
|
-
|
|
76
|
+
This section explains the design decisions behind the provider and points at the code that realizes them; the observable behavior is fully covered in [Use this package](#use-this-package).
|
|
19
77
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
- **
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
78
|
+
### Design philosophy
|
|
79
|
+
|
|
80
|
+
- **One explicit defaulting step.** `resolveSpec(config)` resolves the filename, format, watch flag, and debounce window in one step, so programmatic construction that bypasses Schemastery normalization gets the same defaults.
|
|
81
|
+
- **Boot fails loud, reload keeps last good.** An existing-but-invalid document fails plugin load; once live, an unreadable or unparsable edit warns and keeps the last good sections.
|
|
82
|
+
- **Every write is a read-modify-write.** A persist first reconciles from disk and publishes any difference into the seam, then renders against that fresh text, so a write can never resurrect a stale document or drop an unobserved sibling section.
|
|
83
|
+
- **Writes hold a cross-process writer lock.** The read-render-rename cycle runs under a `wx`-created `<file>.lock` sibling with exponential backoff and a 2-second acquisition deadline; readers never take the lock because the rename commit is atomic.
|
|
84
|
+
- **YAML edits are leaf-level diffs.** Only changed values are set and only removed keys deleted, preserving comments, anchors, and formatting on untouched nodes.
|
|
25
85
|
- **Reloads and writes share one operation chain.** Watcher refreshes and persists from every namespace queue run one at a time in queue order; each render sees the text the previous operation committed.
|
|
26
|
-
- **
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
86
|
+
- **Self-write suppression by content.** The provider caches the last good text; a watcher event whose content equals the cache — its own write included — is a no-op.
|
|
87
|
+
|
|
88
|
+
### Source map
|
|
89
|
+
|
|
90
|
+
| File | Role |
|
|
91
|
+
|---|---|
|
|
92
|
+
| [`src/index.ts`](src/index.ts) | Provider: spec resolution, load/parse, read-modify-write under the writer lock, watcher lifecycle, YAML/JSON rendering |
|
|
93
|
+
| [`src/invariant.ts`](src/invariant.ts) | Invariant companion (no runtime invariant; file round-trip, watcher timing, and atomic-write behavior are proven by package tests, and the in-process commit relation is owned by `dsh-settings`) |
|
|
94
|
+
|
|
95
|
+
### Document lifecycle
|
|
96
|
+
|
|
97
|
+
The base service init loads and publishes the document before the service becomes injectable; the provider then starts the watcher and reconciles once at ready to close the startup gap in which a change written between the initial read and the watcher becoming active never fires an event. Every watcher event and every persist queues onto one exclusive operation chain. `reconcileFromDisk` compares on-disk text against the cache, publishes any difference (including absence as the empty document), and throws only on a parse failure so each caller picks its policy — a reload warns and keeps the last good document, a write fails loud. Disposal marks the provider closed, closes the watcher, and waits out every queued or in-flight operation so nothing publishes after teardown.
|
|
98
|
+
|
|
99
|
+
### Render paths
|
|
100
|
+
|
|
101
|
+
YAML renders by parsing the cached text into a mutable comment-preserving tree and patching one namespace with leaf-level edits; JSON renders by replacing one namespace key and re-serializing with two-space indentation. Before Chokidar opens the target, the provider realpaths its deepest existing ancestor and restores any missing suffix, so Windows cannot mix an 8.3 alias with long-form event paths inside libuv.
|
|
102
|
+
|
|
103
|
+
</details>
|
|
104
|
+
|
|
105
|
+
-----
|
|
106
|
+
|
|
107
|
+
<a id="further-exploration"></a>
|
|
108
|
+
## Further Exploration
|
|
31
109
|
|
|
110
|
+
Read these pages when the provider-level contract is not enough. They move from the seam contract to the atomic-write primitive and the exhaustive configuration surface.
|
|
111
|
+
|
|
112
|
+
- [User-settings service](../settings/README.md) — namespace registration, layered resolution, writes, and the events this provider feeds.
|
|
113
|
+
- [Settings subsystem reference](../../../docs/subsystems/settings.md) — namespaces, resolution order, descriptors, and change commits.
|
|
114
|
+
- [Settings package map](../README.md) — the two packages of the user-settings capability.
|
|
115
|
+
- [Atomic write](../../util/atomic-write/README.md) — the writer lock and atomic replacement every write uses.
|
|
116
|
+
- [Home paths](../../util/home-paths/README.md) — `$DSH_HOME` resolution and canonical watch paths.
|
|
117
|
+
- [Generated configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-settings-file) — every accepted config field and its source declaration.
|
|
118
|
+
|
|
119
|
+
-----
|
|
120
|
+
|
|
121
|
+
<a id="model-experience"></a>
|
|
32
122
|
## Model Experience
|
|
33
123
|
|
|
34
|
-
Indirectly, through consumers of `ctx.settings
|
|
124
|
+
Indirectly, through the consumers of `ctx.settings`, which own any model-facing behavior fed by a stored value; the file provider only stores and publishes namespace sections and registers nothing model-facing itself.
|
|
35
125
|
|
|
36
126
|
#### KV Cache effect
|
|
37
127
|
|
|
@@ -39,7 +129,22 @@ No direct invalidation; the consuming plugin owns any request-prefix changes.
|
|
|
39
129
|
|
|
40
130
|
## Known Limitations and Deferred Work
|
|
41
131
|
|
|
132
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
These limits define when the provider is a poor fit or needs special operational care. They are current package constraints, not a task backlog.
|
|
136
|
+
|
|
42
137
|
- **Same-namespace conflicts stay last-write-wins** — the writer lock and read-modify-write keep concurrent writers from dropping each other's namespaces, but two writers editing one namespace still resolve to the later write; there is no per-value merge or revision check.
|
|
43
138
|
- **A missed watcher event stays unseen until the next signal** — reads never re-stat the file, so a change the watcher fails to report is only folded in by the next event, the next write, or a restart.
|
|
44
|
-
- **Comment preservation is YAML-only and map-shaped** — JSON documents re-serialize without comments
|
|
139
|
+
- **Comment preservation is YAML-only and map-shaped** — JSON documents re-serialize without comments, and comments inside a changed array, or attached inline to a changed scalar value, go with the value they described.
|
|
45
140
|
- **No value indirection** — sections hold literal values; `${env:VAR}`-style references for secrets are a deferred seam-level feature.
|
|
141
|
+
|
|
142
|
+
<a id="dev-note"></a>
|
|
143
|
+
### Dev Note
|
|
144
|
+
|
|
145
|
+
<details>
|
|
146
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
147
|
+
|
|
148
|
+
This Dev Note is working context for maintainers: deferred directions that are not decided. It is explicitly non-authoritative — shipped behavior, limits, and accepted rationale live in the sections above and the package code. Deferred directions: `${env:VAR}`-style value indirection is a seam-level feature — it belongs with the settings service contract when it lands, not with this provider. Orphan lock recovery remains an operator action by design, because lock age cannot distinguish a crashed owner from a paused live writer.
|
|
149
|
+
|
|
150
|
+
</details>
|
package/README.zh.md
CHANGED
|
@@ -1,45 +1,150 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "面向用户与维护者的文件型设置提供方:选择、配置或排查 YAML/JSON 设置文档及其热重载。"
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# @deepseek-ai/dsh-settings-file
|
|
2
7
|
|
|
3
8
|
[English](README.md) | 中文
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
`dsh-settings-file` 把所有 namespace 的用户设置保存在一个 YAML 或 JSON 文档中,默认是 harness home 下的 `settings.yaml`:用户可以直接编辑文档——变更实时生效——也可以经服务写入,后者会安全合并并发编辑。YAML 写入保留每个未触碰节点上的注释、锚点与排版,未加载插件所拥有的分节也绝不会被丢弃。启动时非法文档直接报错;运行中失败的热重载保留最后可用分节并告警,而不是拖垮进程。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [使用本包](#use-this-package)
|
|
17
|
+
- [理解实现](#understand-the-implementation)
|
|
18
|
+
- [进一步探索](#further-exploration)
|
|
19
|
+
- [模型体验](#model-experience)
|
|
20
|
+
- [已知限制与延期工作](#known-limitations-and-deferred-work)
|
|
21
|
+
- [开发备注](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## 使用本包
|
|
27
|
+
|
|
28
|
+
当组合想要一份用户可编辑的设置文档时,挂载此提供方。常用路径是显式的:挂载提供方、经 `ctx.settings` 注册 namespace,然后让用户编辑文档或让配置界面经服务写入。
|
|
29
|
+
|
|
30
|
+
### 何时选择
|
|
31
|
+
|
|
32
|
+
把它当作默认的用户设置存储:一份用户可以在任意编辑器中打开的人类可读文档,变更无需重启即可生效。当文档中的注释与排版很重要时也选它,因为写入会保留它们。非文件存储(例如远程设置后端)不随本包提供;那需要另一个提供方。
|
|
33
|
+
|
|
34
|
+
### 最小配置
|
|
6
35
|
|
|
7
|
-
|
|
36
|
+
```yaml
|
|
37
|
+
- name: '@deepseek-ai/dsh-settings-file'
|
|
38
|
+
config:
|
|
39
|
+
path: /absolute/path/to/settings.yaml
|
|
40
|
+
```
|
|
8
41
|
|
|
9
|
-
| 字段 |
|
|
42
|
+
| 字段 | 默认值 | 含义 |
|
|
10
43
|
|---|---|---|
|
|
11
|
-
| `path` |
|
|
12
|
-
| `dshHome` | `path` 省略时使用的 harness home |
|
|
13
|
-
| `watch` |
|
|
14
|
-
| `debounceMs` | watcher 写入稳定窗口(毫秒) |
|
|
44
|
+
| `path` | `<harness home>/settings.yaml` | 设置文档路径;扩展名决定格式(`.yaml`、`.yml` 或 `.json`) |
|
|
45
|
+
| `dshHome` | `$DSH_HOME` 或 `~/.dsh` | `path` 省略时使用的 harness home |
|
|
46
|
+
| `watch` | `true` | 监听文档并热发布外部编辑 |
|
|
47
|
+
| `debounceMs` | `100` | watcher 写入稳定窗口(毫秒) |
|
|
48
|
+
|
|
49
|
+
生成的[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-settings-file)是每个受支持字段及其 JSDoc 的穷尽式真源。
|
|
50
|
+
|
|
51
|
+
### 编辑文档
|
|
52
|
+
|
|
53
|
+
文档是 namespace 到用户分节的 YAML 或 JSON 映射。用户可以直接编辑:任何变更都会自动生效,删除文件则让所有 namespace 回到默认值与 `base`。存在但非法的文档在启动时使插件加载失败——提供方绝不会静默忽略或覆盖它。运行中不可读或不可解析的编辑只告警并保留最后可用分节,因此手改出错不会拖垮进程。
|
|
54
|
+
|
|
55
|
+
### 经服务写入
|
|
56
|
+
|
|
57
|
+
经 `ctx.settings` 的写入绝不会丢失并发变更:仍在途中的外部编辑、watcher 漏掉的变更或另一个进程的写入,都会在写入落地前并入文档。YAML 编辑是叶子级 diff:只设置变化的值、只删除被移除的键,因此每个未触碰节点以及每个被改键值对的键上的注释、锚点与排版都得以保留;被改的数组或其他非 map 值整体替换。JSON 文档重新序列化,无注释。若磁盘上的文档已变为非法,写入会明确报错,而不是覆盖用户的手工编辑。
|
|
58
|
+
|
|
59
|
+
锁有 2 秒的获取期限,带指数退避;超时的竞争者不会移除现有锁,因为锁龄无法区分崩溃的所有者与被暂停但仍存活的写入方——遗留锁恢复须由操作者执行。文档以 `0600` 权限创建在仅属主可访问的 `0700` 目录下,并通过一个绝不跟随预埋符号链接的随机后缀临时文件原子替换。
|
|
60
|
+
|
|
61
|
+
### 失败与恢复
|
|
62
|
+
|
|
63
|
+
- 不支持的扩展名在加载时报错——格式由扩展名决定(`.yaml`、`.yml`、`.json`)。
|
|
64
|
+
- 文档缺失即空存储;删除文件即回到该状态。
|
|
65
|
+
- 运行中磁盘文档非法不会阻塞任何操作,但保留最后可用分节;写入拒绝覆盖它。
|
|
66
|
+
- `prepareDocument()` 在原生编辑器打开前,把缺失的文档物化为空的仅属主可访问文件。
|
|
67
|
+
|
|
68
|
+
-----
|
|
69
|
+
|
|
70
|
+
<a id="understand-the-implementation"></a>
|
|
71
|
+
## 理解实现
|
|
15
72
|
|
|
16
|
-
|
|
73
|
+
<details>
|
|
74
|
+
<summary>实现细节——点击展开</summary>
|
|
17
75
|
|
|
18
|
-
|
|
76
|
+
本节解释提供方背后的设计决策并指出实现它们的代码位置;可观察行为已在[使用本包](#use-this-package)中完整说明。
|
|
19
77
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
78
|
+
### 设计理念
|
|
79
|
+
|
|
80
|
+
- **一步显式默认化。** `resolveSpec(config)` 在一步内解析文件名、格式、watch 标志与防抖窗口,因此绕过 Schemastery 规范化的程序化构造也得到同样的默认值。
|
|
81
|
+
- **启动明确报错,重载保留最后可用值。** 存在但非法的文档使插件加载失败;运行中不可读或不可解析的编辑只告警并保留最后可用分节。
|
|
82
|
+
- **每次写入都是读-改-写。** persist 先从磁盘对账并把任何差异发布进 seam,再基于这份新鲜文本渲染,因此写入绝不会复活陈旧文档或丢掉未观察到的同级分节。
|
|
83
|
+
- **写入持有跨进程写锁。** 读-渲染-rename 流程在以 `wx` 创建的同级 `<file>.lock` 保护下运行,带指数退避与 2 秒的获取期限;读取方从不取锁,因为 rename 提交是原子的。
|
|
84
|
+
- **YAML 编辑是叶子级 diff。** 只设置变化的值、只删除被移除的键,保留未触碰节点上的注释、锚点与排版。
|
|
25
85
|
- **重载与写入共享一条操作链。** watcher 刷新与来自各 namespace 队列的 persist 按队列顺序逐个执行;每次渲染都基于上一次操作提交后的文本。
|
|
26
|
-
- **watcher 的 ready 信号做一次对账。** 初始加载与 watcher 自身的建立存在竞态,因此其间写入的变更绝不会触发事件;ready 时的对账补上这个启动缺口。
|
|
27
|
-
- **原生 watcher 接收规范化路径。** 在 Chokidar 打开目标之前,提供方会对层级最深的现有祖先路径执行 realpath 解析,再拼回缺失的后缀。文件访问和面向用户的诊断仍使用配置路径,从而避免 Windows 在 libuv 内部混用 8.3 别名与长格式事件路径。
|
|
28
|
-
- **dispose(资源释放)在每种 watch 模式下都保证完全停稳。** 卸载先把提供方标记为已关闭,在 watcher 存在时将其关闭,再等待所有已排队或进行中的文档操作完成,之后不再有任何发布。
|
|
29
86
|
- **按内容抑制自写。** 提供方缓存最后可用文本;watcher 事件内容与缓存相同(含自己的写入)即为 no-op。
|
|
30
|
-
- **Host 配置适配器会收到解析后的路径。** `ctx.settings.documentPath` 是 `resolveSpec()` 得出的绝对文件名,包括自定义 YAML/JSON 路径;`prepareDocument()` 会保留现有文件,或在 Host 打开文档前,以仅属主可访问的权限独占创建缺失的空文件。浏览器只收到可用性标志,绝不重建 `$DSH_HOME`,也绝不提交文件系统目标。
|
|
31
87
|
|
|
88
|
+
### 源码地图
|
|
89
|
+
|
|
90
|
+
| 文件 | 职责 |
|
|
91
|
+
|---|---|
|
|
92
|
+
| [`src/index.ts`](src/index.ts) | 提供方:spec 解析、加载/解析、写锁下的读-改-写、watcher 生命周期、YAML/JSON 渲染 |
|
|
93
|
+
| [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件(无运行时不变式;文件往返、watcher 时序与原子写入行为由包测试证明,进程内提交关系归 `dsh-settings` 所有) |
|
|
94
|
+
|
|
95
|
+
### 文档生命周期
|
|
96
|
+
|
|
97
|
+
基类服务 init 在服务可注入前加载并发布文档;随后提供方启动 watcher,并在 ready 时对账一次,补上「初始读取与 watcher 生效之间写入的变更永不触发事件」的启动缺口。每个 watcher 事件与每次 persist 都排上同一条独占操作链。`reconcileFromDisk` 把磁盘文本与缓存比较,发布任何差异(缺失即空文档),只在解析失败时抛出,让每个调用方自行选择策略——重载告警并保留最后可用文档,写入明确报错。卸载先把提供方标记为已关闭,关闭 watcher,再等待所有已排队或进行中的操作完成,之后不再有任何发布。
|
|
98
|
+
|
|
99
|
+
### 渲染路径
|
|
100
|
+
|
|
101
|
+
YAML 渲染把缓存文本解析成可变的保留注释树,再对一个 namespace 施加叶子级编辑;JSON 渲染替换一个 namespace 键后以两个空格缩进重新序列化。在 Chokidar 打开目标之前,提供方对层级最深的现有祖先路径执行 realpath 解析,再拼回缺失的后缀,从而避免 Windows 在 libuv 内部混用 8.3 别名与长格式事件路径。
|
|
102
|
+
|
|
103
|
+
</details>
|
|
104
|
+
|
|
105
|
+
-----
|
|
106
|
+
|
|
107
|
+
<a id="further-exploration"></a>
|
|
108
|
+
## 进一步探索
|
|
109
|
+
|
|
110
|
+
当提供方级约定不够用时阅读以下页面。它们从 seam 约定逐步进入原子写入原语与穷尽式配置面。
|
|
111
|
+
|
|
112
|
+
- [用户设置服务](../settings/README.zh.md)——namespace 注册、分层解析、写入与本提供方所供的事件。
|
|
113
|
+
- [设置子系统参考](../../../docs/subsystems/settings.zh.md)——namespace、解析顺序、descriptor 与变更提交。
|
|
114
|
+
- [设置包映射](../README.zh.md)——用户设置能力的两个包。
|
|
115
|
+
- [原子写入](../../util/atomic-write/README.zh.md)——每次写入都使用的写锁与原子替换。
|
|
116
|
+
- [主目录路径](../../util/home-paths/README.zh.md)——`$DSH_HOME` 解析与规范化监听路径。
|
|
117
|
+
- [生成配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-settings-file)——每个受支持配置字段及其源声明。
|
|
118
|
+
|
|
119
|
+
-----
|
|
120
|
+
|
|
121
|
+
<a id="model-experience"></a>
|
|
32
122
|
## 模型体验
|
|
33
123
|
|
|
34
|
-
|
|
124
|
+
间接生效:经由 `ctx.settings` 的消费方,它们拥有存储值所喂给的任何模型面行为;本文件提供方只存储并发布 namespace 分节,自身不注册任何模型面内容。
|
|
35
125
|
|
|
36
126
|
#### KV Cache 影响
|
|
37
127
|
|
|
38
128
|
无直接失效;请求前缀的任何变更均由消费方插件负责。
|
|
39
129
|
|
|
40
|
-
##
|
|
130
|
+
## 已知限制与延期工作
|
|
131
|
+
|
|
132
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
这些限制说明本提供方何时不合适或需要特别的运维注意。它们是当前包约束,不是任务积压。
|
|
136
|
+
|
|
137
|
+
- **同 namespace 冲突仍是后写胜出**——写锁加读-改-写让并发写入者不会丢掉彼此的 namespace,但两个写入者编辑同一个 namespace 时仍以较后的写入为准;没有按值合并,也没有修订检查。
|
|
138
|
+
- **漏掉的 watcher 事件在下一个信号前保持不可见**——读取从不重新 stat 文件,因此 watcher 漏报的变更只会在下一个事件、下一次写入或重启时被并入。
|
|
139
|
+
- **注释保留仅限 YAML 且仅限 map 形状**——JSON 文档重新序列化,无注释,且被改数组内部的注释(或行内附着在被改标量值上的注释)随其所描述的值一同被换掉。
|
|
140
|
+
- **无值间接引用**——分节存字面值;面向密钥的 `${env:VAR}` 式引用是暂缓实现的 seam 层功能。
|
|
141
|
+
|
|
142
|
+
<a id="dev-note"></a>
|
|
143
|
+
### 开发备注
|
|
144
|
+
|
|
145
|
+
<details>
|
|
146
|
+
<summary>维护者的工作上下文——点击展开</summary>
|
|
147
|
+
|
|
148
|
+
本开发备注是维护者的工作上下文:尚未决定的暂缓方向。它明确非权威——已发布的行为、限制与已接受的理由见上文各节与包代码。暂缓方向:`${env:VAR}` 式值间接引用是 seam 层功能——落地时应归属设置服务约定,而非本提供方。遗留锁恢复按设计仍是操作者动作,因为锁龄无法区分崩溃的所有者与被暂停但仍存活的写入方。
|
|
41
149
|
|
|
42
|
-
|
|
43
|
-
- **漏掉的 watcher 事件在下一个信号前保持不可见** — 读取从不重新 stat 文件,因此 watcher 漏报的变更只会在下一个事件、下一次写入或重启时被并入。
|
|
44
|
-
- **注释保留仅限 YAML 且仅限 map 形状** — JSON 文档重新序列化,无注释(JSON 本身没有),且被改数组内部的注释(或行内附着在被改标量值上的注释)随其所描述的值一同被换掉。
|
|
45
|
-
- **无值间接引用** — 分节存字面值;面向密钥的 `${env:VAR}` 式引用是暂缓实现的 seam 层功能。
|
|
150
|
+
</details>
|
package/lib/index.js
CHANGED
|
@@ -6,7 +6,8 @@ import { dirname, extname, join, resolve } from "node:path";
|
|
|
6
6
|
import { Document, parseDocument } from "yaml";
|
|
7
7
|
import { withFileLock, writeFileAtomic } from "@deepseek-ai/dsh-atomic-write";
|
|
8
8
|
import { canonicalizeWatchPath, resolveDshHome } from "@deepseek-ai/dsh-home-paths";
|
|
9
|
-
import { SettingsProvider
|
|
9
|
+
import { SettingsProvider } from "@deepseek-ai/dsh-settings";
|
|
10
|
+
import { deepEqualJson } from "@deepseek-ai/dsh-util-values";
|
|
10
11
|
//#region lib/types/index.js
|
|
11
12
|
/**
|
|
12
13
|
* File-backed settings provider. One YAML or JSON document under the user's
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-settings-file",
|
|
3
3
|
"description": "File-backed settings provider (settings.yaml) for the DeepSeek Harness",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.2-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -32,22 +32,23 @@
|
|
|
32
32
|
],
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@deepseek-ai/
|
|
36
|
-
"@deepseek-ai/dsh-
|
|
37
|
-
"@deepseek-ai/dsh-home-paths": "^0.1.
|
|
38
|
-
"@deepseek-ai/dsh-
|
|
39
|
-
"@deepseek-ai/
|
|
35
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
36
|
+
"@deepseek-ai/dsh-atomic-write": "^0.1.2-alpha.2",
|
|
37
|
+
"@deepseek-ai/dsh-home-paths": "^0.1.2-alpha.2",
|
|
38
|
+
"@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2",
|
|
39
|
+
"@deepseek-ai/dsh-settings": "^0.1.2-alpha.2"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"chokidar": "^4.0.3",
|
|
43
43
|
"yaml": "^2.9.0",
|
|
44
|
-
"@deepseek-ai/
|
|
44
|
+
"@deepseek-ai/dsh-util-values": "^0.1.2-alpha.2",
|
|
45
|
+
"@deepseek-ai/schemastery": "^3.18.2"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
|
-
"@deepseek-ai/dsh-
|
|
48
|
-
"@deepseek-ai/
|
|
49
|
-
"@deepseek-ai/dsh-home-paths": "^0.1.
|
|
50
|
-
"@deepseek-ai/dsh-
|
|
51
|
-
"@deepseek-ai/
|
|
48
|
+
"@deepseek-ai/dsh-atomic-write": "^0.1.2-alpha.2",
|
|
49
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
50
|
+
"@deepseek-ai/dsh-home-paths": "^0.1.2-alpha.2",
|
|
51
|
+
"@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2",
|
|
52
|
+
"@deepseek-ai/dsh-settings": "^0.1.2-alpha.2"
|
|
52
53
|
}
|
|
53
54
|
}
|