dsh-date-wrapper 0.3.0 → 0.4.0

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.md CHANGED
@@ -4,28 +4,38 @@
4
4
  - [中文 README](./README.zh.md)
5
5
  - [日本語 README](./README.ja.md)
6
6
  - [한국어 README](./README.ko.md)
7
+ - [Français README](./README.fr.md)
8
+ - [Deutsch README](./README.de.md)
9
+ - [Italiano README](./README.it.md)
10
+ - [Русский README](./README.ru.md)
11
+ - [Español README](./README.es.md)
7
12
  - [Installation guide](./INSTALL.md)
8
13
  - [中文安装指南](./INSTALL.zh.md)
9
14
  - [日本語インストールガイド](./INSTALL.ja.md)
10
15
  - [한국어 설치 안내](./INSTALL.ko.md)
16
+ - [Guide d'installation](./INSTALL.fr.md)
17
+ - [Installationsanleitung](./INSTALL.de.md)
18
+ - [Guida all'installazione](./INSTALL.it.md)
19
+ - [Руководство по установке](./INSTALL.ru.md)
20
+ - [Guía de instalación](./INSTALL.es.md)
11
21
  - [Changelog](./CHANGELOG.md)
12
22
  - [日本語 changelog](./CHANGELOG.ja.md)
13
23
  - [한국어 changelog](./CHANGELOG.ko.md)
24
+ - [Français changelog](./CHANGELOG.fr.md)
25
+ - [Deutsch changelog](./CHANGELOG.de.md)
26
+ - [Italiano changelog](./CHANGELOG.it.md)
27
+ - [Русский changelog](./CHANGELOG.ru.md)
28
+ - [Español changelog](./CHANGELOG.es.md)
14
29
 
15
30
  > **▼ DSH version compatibility**
16
31
  >
17
- > | DSH version | Load | Host contract | Client half |
18
- > | --- | --- | --- | --- |
19
- > | 0.1.0-rc.7 ~ 0.1.7.x (0.1.x line) | ✅ artifact ≤ 0.2.0 | `systemPrompt.context({ name, order, text })` | — (host-only plugin) |
20
- > | 0.2.0-rc.1+ (`>=0.2.0-rc.1 <0.2.1-0`) | ✅ artifact ≥ 0.3.0 | same signature; `packages/core/system-prompt` diff vs `dsh-v0.1.7-rc.2` is the version string only | — (host-only plugin) |
21
- >
22
- > One contract covers all lines: the plugin only calls `systemPrompt.context`, whose
23
- > signature and semantics are unchanged from `dsh-v0.1.1-rc.2` through
24
- > `dsh-v0.2.0-rc.1`. It registers no settings namespace, reads no session data and
25
- > makes no RPC call, so the 0.1.1 → 0.1.2 client/session/persistence rewrites and
26
- > the 0.1.7 → 0.2.0-rc.1 host changes do not touch it. Older 0.1.x hosts stay on
27
- > artifact ≤ 0.2.0 (dist-tag `dsh-0.1.7`); the 0.2.0 line is served by artifact
28
- > ≥ 0.3.0.
32
+ > The supported DSH version list is **script-managed, not hand-written** — see the
33
+ > generated block below (single source: `scripts/hosts.mjs`; distributed by
34
+ > `scripts/sync-hosts.mjs` to `package.json` peerDependencies + engines.dsh,
35
+ > `dsh.plugin.json`, and this README in nine languages). The plugin's single host
36
+ > contract is `systemPrompt.context({ name, order, text })`; it registers no
37
+ > settings namespace, reads no session data and makes no RPC call, so host-side
38
+ > client/session/persistence rewrites do not touch it.
29
39
 
30
40
  > A minimal date line: it hangs `Current date: 2026-09-08 Asia/Shanghai Tuesday` (46 characters, ~12 tokens) onto the runtime-context snapshot DSH already sends.
31
41
  > It does **not** load `@deepseek-ai/dsh-time-context`, does **not** add extra session messages, does **not** patch DSH source, and needs no PR.
@@ -33,6 +43,11 @@
33
43
  - [How it works: DSH sessions, JSONL and request assembly](./docs/dsh-session-and-context-mechanics.md) (Chinese)
34
44
  - [HANDOVER.md](./HANDOVER.md) (Chinese)
35
45
 
46
+ <!-- host-compat:begin — generated by scripts/sync-hosts.mjs from scripts/hosts.mjs; DO NOT EDIT -->
47
+ - **Supported DSH hosts:** `0.1.0-rc.2` `0.1.0-rc.3` `0.1.0-rc.6` `0.1.0-rc.7` `0.1.0-rc.8` `0.1.1-rc.1` `0.1.1-rc.2` `0.1.2-rc.1` `0.1.5-rc.1` `0.1.5-rc.2` `0.1.5-rc.3` `0.1.7-rc.1` `0.1.7-rc.2` `0.2.0-rc.1` `0.2.0-rc.2` (15 rc releases across lines 0.1.0 / 0.1.1 / 0.1.2 / 0.1.5 / 0.1.7 / 0.2.0)
48
+ - **Runtime-verified:** `0.1.0-rc.2`, `0.1.0-rc.3`, `0.1.0-rc.6`, `0.1.0-rc.7`, `0.1.0-rc.8`, `0.1.1-rc.1`, `0.1.1-rc.2`, `0.1.2-rc.1`, `0.1.5-rc.1`, `0.1.5-rc.2`, `0.1.5-rc.3`, `0.1.7-rc.1`, `0.1.7-rc.2`, `0.2.0-rc.1`, `0.2.0-rc.2` — evidence in `.compat-results/`
49
+ <!-- host-compat:end -->
50
+
36
51
  ## What this plugin solves
37
52
 
38
53
  DSH's own `@deepseek-ai/dsh-time-context` injects about **280 characters** of metadata on every request:
@@ -61,13 +76,16 @@ Current date: 2026-09-08 Asia/Shanghai Tuesday
61
76
 
62
77
  | Item | Verdict |
63
78
  |------|---------|
64
- | Target DSH versions | 0.1.0-rc.7 → 0.1.7.x (0.1.x line — artifact ≤ 0.2.0) and 0.2.0-rc.1 → 0.2.0.x (0.2.0 line, `engines.dsh: >=0.2.0-rc.1 <0.2.1-0` — artifact ≥ 0.3.0) |
79
+ | Target DSH versions | Script-managed enum — `scripts/hosts.mjs` (15 rc releases across lines 0.1.0 → 0.2.0); runtime-verified list in the generated block at the top |
65
80
  | settings API | **Not applicable**: the plugin registers no settings and exports no schemastery `Config` |
66
81
  | Contract points used | Exactly one — `systemPrompt.context()` |
67
82
  | Conflict with a native feature | Overlaps `@deepseek-ai/dsh-time-context`; **do not use both**. Not installed by default = off by default |
68
83
  | Browser half | **None**: no slot, no DOM, no CSS semantic tokens |
69
84
  | DSH package imports | **Zero**: nothing from `@deepseek-ai/*`, which is stricter than the "runtime detection + dual API fallback" pattern |
70
85
 
86
+ Historical static audit (npm-pack type diff, kept for reference; **version-support
87
+ claims now come from the enum + runtime matrix, not from this table**):
88
+
71
89
  | Contract point | 0.1.0-rc.7 | 0.1.1-rc.2 | 0.1.2-rc.1 | 0.1.3-alpha.2 | 0.1.7-rc.2 | 0.2.0-rc.1 |
72
90
  |---|---|---|---|---|---|---|
73
91
  | `systemPrompt.context(ctx): () => void` | yes | yes (verified on this host) | yes | yes | yes | yes (diff vs 0.1.7-rc.2: version string only) |
@@ -78,7 +96,7 @@ Current date: 2026-09-08 Asia/Shanghai Tuesday
78
96
 
79
97
  > Method: `npm pack @deepseek-ai/dsh-system-prompt@<version>`, unpack, and compare `lib/types/index.d.ts` and `lib/index.js`; the same for `@deepseek-ai/dsh-agent-loop`.
80
98
  > Between `dsh-v0.1.7-rc.2` and `dsh-v0.2.0-rc.1` the `packages/core/system-prompt` diff is a single version line, the 110/115/120 `systemPrompt.context` call sites are unchanged, and the plugin migration guide has no `systemPrompt` entry.
81
- > Only 0.1.1-rc.2 has been verified **at runtime** on this host; runtime smoke on 0.2.0-rc.1 is tracked in `HANDOVER.md` §7.
99
+ > Runtime verification is now **per host rc in the local isolation matrix** (`scripts/test-host-compat.mjs`, evidence in `.compat-results/`); the green list is the generated block at the top of this README. The 0.1.1-rc.2 note in `HANDOVER.md` §7 predates the matrix.
82
100
 
83
101
  ## Why a runtime-context snapshot instead of a message
84
102
 
package/README.ru.md ADDED
@@ -0,0 +1,236 @@
1
+ # dsh-date-wrapper
2
+
3
+ - [English README](./README.md)
4
+ - [中文 README](./README.zh.md)
5
+ - [日本語 README](./README.ja.md)
6
+ - [한국어 README](./README.ko.md)
7
+ - [Français README](./README.fr.md)
8
+ - [Deutsch README](./README.de.md)
9
+ - [Italiano README](./README.it.md)
10
+ - [Русский README](./README.ru.md)
11
+ - [Español README](./README.es.md)
12
+ - [Installation guide](./INSTALL.md)
13
+ - [中文安装指南](./INSTALL.zh.md)
14
+ - [日本語インストールガイド](./INSTALL.ja.md)
15
+ - [한국어 설치 안내](./INSTALL.ko.md)
16
+ - [Guide d'installation](./INSTALL.fr.md)
17
+ - [Installationsanleitung](./INSTALL.de.md)
18
+ - [Guida all'installazione](./INSTALL.it.md)
19
+ - [Руководство по установке](./INSTALL.ru.md)
20
+ - [Guía de instalación](./INSTALL.es.md)
21
+ - [Changelog](./CHANGELOG.md)
22
+ - [日本語 changelog](./CHANGELOG.ja.md)
23
+ - [한국어 changelog](./CHANGELOG.ko.md)
24
+ - [Français changelog](./CHANGELOG.fr.md)
25
+ - [Deutsch changelog](./CHANGELOG.de.md)
26
+ - [Italiano changelog](./CHANGELOG.it.md)
27
+ - [Русский changelog](./CHANGELOG.ru.md)
28
+ - [Español changelog](./CHANGELOG.es.md)
29
+
30
+ > Список поддерживаемых версий DSH **управляется скриптом, а не пишется вручную** — см. сгенерированный блок ниже (единственный источник: `scripts/hosts.mjs`; распространяется `scripts/sync-hosts.mjs` в `package.json` peerDependencies + engines.dsh, `dsh.plugin.json` и этот README на девяти языках). Единственный контракт плагина с хостом — `systemPrompt.context({ name, order, text })`; он не регистрирует namespace настроек, не читает данные сессий и не делает RPC-вызовов — переработки на стороне хоста его не затрагивают.
31
+
32
+ > Минималистичная строка с датой: она подвешивает `Current date: 2026-09-08 Asia/Shanghai Tuesday` (46 символов, ~12 токенов) к снимку контекста времени выполнения, который DSH и так уже отправляет.
33
+ > Она **не** загружает `@deepseek-ai/dsh-time-context`, **не** добавляет лишних сообщений в сессию, **не** патчит исходники DSH и не требует PR.
34
+
35
+ - [Как это работает: сессии DSH, JSONL и сборка запроса](./docs/dsh-session-and-context-mechanics.md) (китайский)
36
+ - [HANDOVER.md](./HANDOVER.md) (китайский)
37
+
38
+ <!-- host-compat:begin — generated by scripts/sync-hosts.mjs from scripts/hosts.mjs; DO NOT EDIT -->
39
+ - **Поддерживаемые хосты DSH:** `0.1.0-rc.2` `0.1.0-rc.3` `0.1.0-rc.6` `0.1.0-rc.7` `0.1.0-rc.8` `0.1.1-rc.1` `0.1.1-rc.2` `0.1.2-rc.1` `0.1.5-rc.1` `0.1.5-rc.2` `0.1.5-rc.3` `0.1.7-rc.1` `0.1.7-rc.2` `0.2.0-rc.1` `0.2.0-rc.2` (15 rc по линиям 0.1.0 / 0.1.1 / 0.1.2 / 0.1.5 / 0.1.7 / 0.2.0)
40
+ - **Проверено на этапе выполнения:** `0.1.0-rc.2`, `0.1.0-rc.3`, `0.1.0-rc.6`, `0.1.0-rc.7`, `0.1.0-rc.8`, `0.1.1-rc.1`, `0.1.1-rc.2`, `0.1.2-rc.1`, `0.1.5-rc.1`, `0.1.5-rc.2`, `0.1.5-rc.3`, `0.1.7-rc.1`, `0.1.7-rc.2`, `0.2.0-rc.1`, `0.2.0-rc.2` — доказательства в `.compat-results/`
41
+ <!-- host-compat:end -->
42
+
43
+ ## Какую задачу решает этот плагин
44
+
45
+ Собственный `@deepseek-ai/dsh-time-context` в DSH внедряет при каждом запросе около **280 символов** метаданных:
46
+
47
+ ```
48
+ Time sampled while preparing turn 3, step 2: 2026-09-08T16:05:36+08:00[Asia/Shanghai]
49
+ Browser time zone for this request: Asia/Shanghai. Interpret otherwise-unqualified dates and times in this zone.
50
+ Elapsed since the preceding model-visible message: 2m 34s.
51
+ ```
52
+
53
+ Этот плагин сжимает ту же информацию в одну строку из **46 символов** и меняет место её назначения — она больше не попадает в поток сообщений:
54
+
55
+ ```
56
+ Current date: 2026-09-08 Asia/Shanghai Tuesday
57
+ ```
58
+
59
+ | Измерение | `dsh-time-context` | `dsh-date-wrapper` |
60
+ |-----------|--------------------|--------------------|
61
+ | Внедряемый текст | ~280 символов | 46 символов (↓84%), ~12 токенов |
62
+ | Место назначения | Одно сообщение на каждый pre-step (`user/message`) | Снимок контекста времени выполнения платформы (`systemPrompt.context`) |
63
+ | Частота | Одно событие на каждый подходящий step | Повторно отправляется со снимком только при изменении текста (0 событий в течение суток) |
64
+ | Зависимость | Сервис `agents` | Сервис `systemPrompt` |
65
+ | Зависимости времени выполнения | — | нет |
66
+
67
+ ## Совместимость версий
68
+
69
+ | Пункт | Вердикт |
70
+ |------|---------|
71
+ | Целевые версии DSH | 0.1.0-rc.7 → 0.1.7.x (линия 0.1.x — артефакт ≤ 0.2.0) и 0.2.0-rc.1 → 0.2.0.x (линия 0.2.0, `engines.dsh: >=0.2.0-rc.1 <0.2.1-0` — артефакт ≥ 0.3.0) |
72
+ | settings API | **Неприменимо**: плагин не регистрирует настройки и не экспортирует schemastery-`Config` |
73
+ | Используемые точки контракта | Ровно одна — `systemPrompt.context()` |
74
+ | Конфликт со встроенной функцией | Пересекается с `@deepseek-ai/dsh-time-context`; **не использовать оба сразу**. Не установлен по умолчанию = выключен по умолчанию |
75
+ | Браузерная половина | **Отсутствует**: ни slot, ни DOM, ни CSS-семантических токенов |
76
+ | Импорты пакетов DSH | **Ноль**: ничего из `@deepseek-ai/*`, что строже паттерна «определение в рантайме + двойной API-фолбэк» |
77
+
78
+ | Точка контракта | 0.1.0-rc.7 | 0.1.1-rc.2 | 0.1.2-rc.1 | 0.1.3-alpha.2 | 0.1.7-rc.2 | 0.2.0-rc.1 |
79
+ |---|---|---|---|---|---|---|
80
+ | `systemPrompt.context(ctx): () => void` | да | да (проверено на этом хосте) | да | да | да | да (diff относительно 0.1.7-rc.2: только строка версии) |
81
+ | `PromptContext = { name, order, text }`, без поля `complete` | да | да | да | да | да | да |
82
+ | `includeRuntimeContext` / `suppressRuntimeContext` | да | да | да | да | да | да |
83
+ | дедупликация по тексту в `project()` agent-loop и `surfaceOp: "append"` | да | да | да | не сравнивалось | да | да |
84
+ | `order: 116` без коллизий (110 / 115 / 120 заняты) | да | да | да | да | да | да |
85
+
86
+ > Метод: `npm pack @deepseek-ai/dsh-system-prompt@<version>`, распаковать и сравнить `lib/types/index.d.ts` и `lib/index.js`; то же для `@deepseek-ai/dsh-agent-loop`.
87
+ > Между `dsh-v0.1.7-rc.2` и `dsh-v0.2.0-rc.1` diff `packages/core/system-prompt` — одна строка версии, точки вызова `systemPrompt.context` на 110/115/120 не тронуты, а в гайде по миграции плагинов нет ни одного упоминания `systemPrompt`.
88
+ > **В рантайме** проверена только 0.1.1-rc.2 на этом хосте; runtime-смоук 0.2.0-rc.1 отслеживается в `HANDOVER.md` §7.
89
+
90
+ ## Почему снимок контекста времени выполнения, а не сообщение
91
+
92
+ Первая попытка копировала `dsh-time-context` и добавляла `user/message` в `agent/pre-step`. Измеренные затраты оказались слишком велики: каждое JSONL-событие весит **339 байт** (на текст приходится лишь 46, потому что `content` и `sections` хранят по копии), и такое событие писалось **каждый ход**.
93
+
94
+ При регистрации контекста времени выполнения вместо этого дата складывается в то сообщение-снимок, которое платформа уже отправляет:
95
+
96
+ - Платформа **дедуплицирует снимки по тексту** (`RuntimeContextProjection.project()` в `dsh-agent-loop`: `if (this.retained?.text === snapshot) return`), поэтому пока дата не меняется, **не пишется ни одного лишнего события**;
97
+ - Снимки **дописывают** новое сообщение (`surfaceOp: 'append'`), а не переписывают существующее, поэтому последовательность запроса только растёт → **префиксный кэш сохраняется**;
98
+ - Наши предельные затраты — те самые 46 байт, и только когда снимок переотправляется из-за изменения текста.
99
+
100
+ Измерено на этом хосте (одна реальная сессия, 10 ходов / 231 шаг):
101
+
102
+ | Пункт | Измерено |
103
+ |------|----------|
104
+ | Снимки контекста времени выполнения платформы | 2 события, по 1133 Б, всего 2,3 КБ |
105
+ | Реальные сообщения пользователя | 10 событий, по 396 Б |
106
+ | Старый подход (одно сообщение на ход) | 10 × 339 Б ≈ 3,4 КБ |
107
+ | Этот подход | 0 лишних событий; ~46 Б складываются в существующий снимок |
108
+
109
+ ## Конфигурация
110
+
111
+ Поставляется в `cordis.patch.yml`; после изменения требуется перезапуск:
112
+
113
+ ```yaml
114
+ - insert:
115
+ - id: date-wrapper
116
+ name: dsh-date-wrapper
117
+ config:
118
+ timeZone: Asia/Shanghai # IANA zone; omit to use the process zone
119
+ ```
120
+
121
+ - Некорректный `timeZone` бросает исключение при старте (**никакого** тихого фолбэка на UTC).
122
+ - Имя зоны в тексте — это разрешённое имя IANA (имя зоны процесса, если `timeZone` не указан).
123
+ - Запись контекста времени выполнения называется `date-wrapper:date` с order `116` (занято: 110 sandbox, 115 approval, 120 subagent).
124
+ - Плагин **не экспортирует schemastery-`Config`**, поэтому его конфигурация не проходит схемную валидацию хоста; всё проверяется вручную в `validateConfig()`. Именно поэтому на странице Settings → Plugins для него нет формы конфигурации.
125
+
126
+ ## Включение/выключение: переключатель — это активация плагина, отдельной панели нет
127
+
128
+ Плагин не содержит **ни** переключателя в панели настроек, **ни** поля конфигурации `enabled`, потому что:
129
+
130
+ - Переключатель функции — это и есть *активность строки плагина*. Неактивна → `apply()` не выполняется → записи контекста времени выполнения не существует → не внедряется ни одного символа.
131
+ - Браузерной половины нет (`dsh.client`), поэтому в UI нет ни одного нашего виджета.
132
+ - Встроенная страница DSH **Settings → Plugins** уже показывает статус каждой записи как `enabled / disabled` (только для чтения).
133
+
134
+ ### Как выключить
135
+
136
+ Переопределите её по `id` в **своём собственном** слое profile patch — `C:\Users\<you>\.dsh\profiles\web\cordis.patch.yml`:
137
+
138
+ ```yaml
139
+ - id: date-wrapper
140
+ disabled: true # disabled; set back to false to restore
141
+ ```
142
+
143
+ - **Горячо, без перезапуска**: файл наблюдается Cordis HMR, и `disabled: true` немедленно уничтожает fiber этой строки.
144
+ - Если строки `date-wrapper` ещё нет (не установлен), этот patch лишь запишет предупреждение `entry "date-wrapper" not found`; старт всё равно пройдёт успешно.
145
+ - ⚠️ Файл должен быть **YAML-массивом верхнего уровня**; если он повреждён, **старт падает** (DSH для пользовательских слоёв patch работает по принципу fail-loud).
146
+
147
+ ### Как удалить полностью
148
+
149
+ ```bash
150
+ dsh plugin --profile web remove dsh-date-wrapper
151
+ ```
152
+
153
+ Удаление идёт через слой bundle и **требует перезапуска** dsh web (bundle-patch не перезагружаются на лету).
154
+
155
+ ## Установка
156
+
157
+ ```bash
158
+ dsh plugin --profile web add github:drscrewdriver/dsh-date-wrapper
159
+ ```
160
+
161
+ Перезапустите dsh web и обновите страницу. Локальные пути, режим link и устранение неполадок: [INSTALL.ru.md](./INSTALL.ru.md).
162
+
163
+ ## Проверка
164
+
165
+ | # | Как | Ожидается |
166
+ |---|-----|----------|
167
+ | A1 | Открыть новую сессию и отправить одно сообщение | В снимке контекста времени выполнения появляется `Current date: YYYY-MM-DD <zone> <weekday>` (показывается как строка внедрённого контекста с источником `system-prompt`) |
168
+ | A2 | Проверить эту строку | ≤50 символов (измерено 46; порог PRD в 30 был смягчён ради запрошенного формата) |
169
+ | A3 | Отключить плагин (profile patch `disabled: true`) | Строка больше не появляется в снимках последующих сессий |
170
+ | A4 | Поискать в журнале сессии | Нет `Time sampled` / `Elapsed since` / `Browser time zone` |
171
+ | A5 | Поставить `timeZone` в `UTC` и перезапустить | Дата следует UTC (на границе зон возможен сдвиг в один день) |
172
+
173
+ ## Примечания по реализации
174
+
175
+ ```
176
+ dsh-date-wrapper/
177
+ ├── package.json # name / type: module / main / exports["."] / dsh.bundle.patch / files
178
+ ├── cordis.patch.yml # one insert row (no patch-level id → lands at the profile root = host plane)
179
+ ├── src/
180
+ │ ├── format.js # pure functions: resolveZone / renderDate / createDateContextText / validateConfig / TEXT_LABEL
181
+ │ └── index.js # apply(ctx, config) → ctx.inject(['systemPrompt'], …) → systemPrompt.context(...)
182
+ └── tests/
183
+ ├── format.test.mjs # 11 cases (zone projection, weekday, format and length, degradation, config validation)
184
+ └── context.test.mjs # 7 cases (registration contract against a fake ctx)
185
+ ```
186
+
187
+ - **Строка на плоскости хоста**: `ctx.inject(['systemPrompt'], …)` открывает дочернюю fiber; если сервиса нет, плагин молча ничего не регистрирует, вместо того чтобы уронить всю загрузку.
188
+ - **Fail-soft провайдер текста**: исключение во время сборки промпта уронило бы **каждый** запрос, поэтому при ошибке рендера возвращается пустая строка (платформа отфильтровывает пустой текст).
189
+ - **Без `complete`**: если его задать, он затрёт весь системный промпт.
190
+ - **Дедупликация — задача платформы**: никакого состояния per-agent не хранится; после полуночи снимок просто несёт новую дату.
191
+ - **Жизненный цикл**: регистрация принадлежит дочерней fiber `ctx.inject` и освобождается при деактивации плагина.
192
+
193
+ ## Разработка: TDD + lint
194
+
195
+ ```bash
196
+ npm install # devDependencies only (eslint / @eslint/js); zero runtime dependencies
197
+
198
+ npm run tdd # watch mode: rerun on src/ or tests/ changes (node --test --watch)
199
+ npm test # one full run: node --test "tests/*.test.mjs"
200
+ node tests/format.test.mjs # run a single file (most reliable under a sandbox: no child process)
201
+
202
+ npm run lint # eslint . (src + tests + eslint.config.mjs)
203
+ npm run lint:fix # auto-fix what can be fixed
204
+ npm run verify # lint + test; run this before committing
205
+ ```
206
+
207
+ ### Красный-зелёный-рефакторинг
208
+
209
+ Тест-кейсы напрямую соответствуют критериям приёмки: сначала пишется падающая проверка, затем её доводят до зелёной.
210
+
211
+ | Шаг | Действие | Команда |
212
+ |------|--------|---------|
213
+ | 1 красный | Добавить в `tests/*.test.mjs` проверку, названную по критерию приёмки, которая проверяет поведение, которого у вас **ещё нет** | `npm run tdd` |
214
+ | 2 зелёный | Написать в `src/` минимальную реализацию, чтобы она прошла, не трогая другие проверки | `npm run tdd` |
215
+ | 3 рефакторинг | Оставаясь в зелёном, переименовывать и выделять чистые функции; вся чистая логика живёт в `src/format.js`, `src/index.js` только регистрирует | `npm run tdd` |
216
+ | 4 шлюз | Перед коммитом прогнать lint + весь набор тестов | `npm run verify` |
217
+
218
+ Сегодня 18 проверок: `format.test.mjs` (11) покрывает чистые функции, `context.test.mjs` (7) проверяет контракт регистрации против фейкового ctx.
219
+
220
+ ### Особенности конфигурации lint
221
+
222
+ - ESLint 10 flat config (`eslint.config.mjs`) с `@eslint/js` recommended в качестве базовой линии.
223
+ - Ужесточённые правила: `eqeqeq`, `prefer-const`, `object-shorthand`, `no-unused-vars` (префикс `_` освобождён).
224
+ - Глобальные объекты Node `crypto` / `console` / `process` объявлены явно, иначе `no-undef` даёт ложные срабатывания.
225
+
226
+ ## Известные ограничения
227
+
228
+ - **Не работает с fixed-prompt-пресетами**: если persona пресета задаёт `includeRuntimeContext: false` (так делают и официальный `minimal`, и локальный `simple-reply`), `assemble()` возвращает `contexts: []`, и запись этого плагина отбрасывается целиком. Такие пресеты специально запрещают последующим listener'ам добавлять что-либо в промпт.
229
+ - **Старые снимки остаются в истории**: при смене даты платформа дописывает новый снимок (старый сохраняется), а новый вступает в силу благодаря собственному объявлению "This snapshot supersedes earlier runtime-context snapshots" — точно так же платформа обрабатывает смены cwd / sandbox / политики одобрения.
230
+ - **Bundle-patch не перезагружаются на лету**: изменение `cordis.patch.yml` или обновление плагина требует перезапуска dsh web (изменение `disabled` в profile patch срабатывает горячо).
231
+ - **`dsh-time-context` не загружается и не фильтруется**: если вы явно смонтируете его в пресете, его подробный текст появится как обычно. Не использовать оба.
232
+ - **Нет runtime-пробы точки контракта**: `systemPrompt.context` вызывается без защиты, поэтому будущее переименование со стороны DSH проявится как ошибка загрузки плагина, а не как тихая деградация (см. `HANDOVER.md` §7).
233
+
234
+ ## Лицензия
235
+
236
+ MIT
package/README.zh.md CHANGED
@@ -4,26 +4,36 @@
4
4
  - [中文 README](./README.zh.md)
5
5
  - [日本語 README](./README.ja.md)
6
6
  - [한국어 README](./README.ko.md)
7
+ - [Français README](./README.fr.md)
8
+ - [Deutsch README](./README.de.md)
9
+ - [Italiano README](./README.it.md)
10
+ - [Русский README](./README.ru.md)
11
+ - [Español README](./README.es.md)
7
12
  - [Installation guide](./INSTALL.md)
8
13
  - [中文安装指南](./INSTALL.zh.md)
9
14
  - [日本語インストールガイド](./INSTALL.ja.md)
10
15
  - [한국어 설치 안내](./INSTALL.ko.md)
16
+ - [Guide d'installation](./INSTALL.fr.md)
17
+ - [Installationsanleitung](./INSTALL.de.md)
18
+ - [Guida all'installazione](./INSTALL.it.md)
19
+ - [Руководство по установке](./INSTALL.ru.md)
20
+ - [Guía de instalación](./INSTALL.es.md)
11
21
  - [Changelog](./CHANGELOG.md)
12
22
  - [日本語 changelog](./CHANGELOG.ja.md)
13
23
  - [한국어 changelog](./CHANGELOG.ko.md)
24
+ - [Français changelog](./CHANGELOG.fr.md)
25
+ - [Deutsch changelog](./CHANGELOG.de.md)
26
+ - [Italiano changelog](./CHANGELOG.it.md)
27
+ - [Русский changelog](./CHANGELOG.ru.md)
28
+ - [Español changelog](./CHANGELOG.es.md)
14
29
 
15
30
  > **▼ DSH 版本适配**
16
31
  >
17
- > | DSH 版本 | 加载 | 宿主契约 | 客户端半 |
18
- > | --- | --- | --- | --- |
19
- > | 0.1.0-rc.7 ~ 0.1.7.x(0.1.x 线) | ✅ 产物 ≤ 0.2.0 | `systemPrompt.context({ name, order, text })` | —(纯宿主插件) |
20
- > | 0.2.0-rc.1+(`>=0.2.0-rc.1 <0.2.1-0`) | ✅ 产物 ≥ 0.3.0 | 同一签名;`packages/core/system-prompt` 相对 `dsh-v0.1.7-rc.2` 的 diff 仅版本号一行 | —(纯宿主插件) |
21
- >
22
- > 一份契约覆盖所有版本线:插件只调用 `systemPrompt.context`,其签名与语义从
23
- > `dsh-v0.1.1-rc.2` 到 `dsh-v0.2.0-rc.1` 未变。它不注册设置命名空间、不读会话
24
- > 数据、不发 RPC,因此 0.1.1 → 0.1.2 的客户端/会话/持久化重写与 0.1.7 →
25
- > 0.2.0-rc.1 的宿主改动都与它无关。旧 0.1.x 宿主请使用产物 ≤ 0.2.0(dist-tag
26
- > `dsh-0.1.7`);0.2.0 线由产物 ≥ 0.3.0 服务。
32
+ > 支持的 DSH 版本清单是**脚本下发、禁止手改**的 —— 见下方自动生成的管理块
33
+ > (单一事实源:`scripts/hosts.mjs`;由 `scripts/sync-hosts.mjs` 下发到
34
+ > `package.json` peerDependencies + engines.dsh、`dsh.plugin.json` 与九语 README)。
35
+ > 插件唯一宿主契约是 `systemPrompt.context({ name, order, text })`:不注册设置
36
+ > 命名空间、不读会话数据、不发 RPC,宿主侧客户端/会话/持久化重写都与它无关。
27
37
 
28
38
  > 精简版时间注入:把 `Current date: 2026-09-08 Asia/Shanghai Tuesday`(46 字符 ≈ 12 token)挂进 DSH 自带的运行上下文快照。
29
39
  > 不加载 `@deepseek-ai/dsh-time-context`,不产生额外会话消息,不改 DSH 源码,不提 PR。
@@ -31,6 +41,11 @@
31
41
  - [机制详解:DSH 会话、JSONL 与请求组装](./docs/dsh-session-and-context-mechanics.md)(中文)
32
42
  - [交接文档 HANDOVER.md](./HANDOVER.md)(中文)
33
43
 
44
+ <!-- host-compat:begin — generated by scripts/sync-hosts.mjs from scripts/hosts.mjs; DO NOT EDIT -->
45
+ - **支持的 DSH 宿主:** `0.1.0-rc.2` `0.1.0-rc.3` `0.1.0-rc.6` `0.1.0-rc.7` `0.1.0-rc.8` `0.1.1-rc.1` `0.1.1-rc.2` `0.1.2-rc.1` `0.1.5-rc.1` `0.1.5-rc.2` `0.1.5-rc.3` `0.1.7-rc.1` `0.1.7-rc.2` `0.2.0-rc.1` `0.2.0-rc.2`(覆盖 0.1.0 / 0.1.1 / 0.1.2 / 0.1.5 / 0.1.7 / 0.2.0 六条线共 15 个 rc)
46
+ - **运行时已验证:** `0.1.0-rc.2`, `0.1.0-rc.3`, `0.1.0-rc.6`, `0.1.0-rc.7`, `0.1.0-rc.8`, `0.1.1-rc.1`, `0.1.1-rc.2`, `0.1.2-rc.1`, `0.1.5-rc.1`, `0.1.5-rc.2`, `0.1.5-rc.3`, `0.1.7-rc.1`, `0.1.7-rc.2`, `0.2.0-rc.1`, `0.2.0-rc.2`(证据见 `.compat-results/`)
47
+ <!-- host-compat:end -->
48
+
34
49
  ## 这个插件解决什么
35
50
 
36
51
  DSH 自带的 `@deepseek-ai/dsh-time-context` 每次请求注入约 **280 字符**的元数据:
@@ -59,13 +74,15 @@ Current date: 2026-09-08 Asia/Shanghai Tuesday
59
74
 
60
75
  | 项 | 结论 |
61
76
  |---|---|
62
- | 目标 DSH 版本 | 0.1.0-rc.7 → 0.1.7.x(0.1.x 线 — 产物 ≤ 0.2.0)与 0.2.0-rc.1 → 0.2.0.x(0.2.0 线,`engines.dsh: >=0.2.0-rc.1 <0.2.1-0` — 产物 ≥ 0.3.0) |
77
+ | 目标 DSH 版本 | 脚本管理枚举 —— `scripts/hosts.mjs`(0.1.0 → 0.2.0 六条线共 15 个 rc);运行时已验证清单见文首自动生成块 |
63
78
  | settings API | **不适用**:本插件不注册 settings,也不导出 schemastery `Config` |
64
79
  | 使用的契约点 | 只有一个 —— `systemPrompt.context()` |
65
80
  | 与原生功能冲突 | `@deepseek-ai/dsh-time-context` 功能重叠,**不要同时使用**。本插件默认不安装 = 默认关闭 |
66
81
  | client 半 | **无**:不涉及 slot / DOM / CSS 语义 token |
67
82
  | DSH 包 import | **零**:不 `import` 任何 `@deepseek-ai/*`,比「运行时检测 + 双 API 回退」更保守 |
68
83
 
84
+ 历史静态审计(npm-pack 类型比对,留档用;**版本支持声明现以枚举 + 运行时矩阵为准,不再以本表为准**):
85
+
69
86
  | 契约点 | 0.1.0-rc.7 | 0.1.1-rc.2 | 0.1.2-rc.1 | 0.1.3-alpha.2 | 0.1.7-rc.2 | 0.2.0-rc.1 |
70
87
  |---|---|---|---|---|---|---|
71
88
  | `systemPrompt.context(ctx): () => void` | ✅ | ✅(本机实装验证) | ✅ | ✅ | ✅ | ✅(相对 0.1.7-rc.2 diff 仅版本号) |
@@ -76,7 +93,7 @@ Current date: 2026-09-08 Asia/Shanghai Tuesday
76
93
 
77
94
  > 验证方式:`npm pack @deepseek-ai/dsh-system-prompt@<版本>` 解包后比对 `lib/types/index.d.ts` 与 `lib/index.js`;`@deepseek-ai/dsh-agent-loop` 同法。
78
95
  > `dsh-v0.1.7-rc.2` 与 `dsh-v0.2.0-rc.1` 之间,`packages/core/system-prompt` 的 diff 仅版本号一行,110/115/120 的 `systemPrompt.context` 调用点原位未动,插件迁移指南无任何 `systemPrompt` 条目。
79
- > **运行时**只在本机 0.1.1-rc.2 上验证过;0.2.0-rc.1 的运行时冒烟记录见 `HANDOVER.md` §7。
96
+ > 运行时验证现按宿主 rc 逐格在**本地隔离矩阵**进行(`scripts/test-host-compat.mjs`,证据在 `.compat-results/`);绿名单即文首自动生成块。`HANDOVER.md` §7 的 0.1.1-rc.2 记录先于矩阵,属历史。
80
97
 
81
98
  ## 为什么用运行上下文快照,而不是消息
82
99
 
package/dsh.plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "dsh-date-wrapper",
3
3
  "name": "dsh-date-wrapper",
4
- "version": "0.3.0",
4
+ "version": "0.4.0",
5
5
  "description": {
6
6
  "en": "Minimal date line for the DeepSeek Harness runtime-context snapshot: a single compact line such as 'Current date: 2026-09-08 Asia/Shanghai Tuesday' (46 chars, ~12 tokens). A cordis host plugin with no DSH source changes.",
7
7
  "zh": "为 DeepSeek Harness 运行时上下文快照提供极简日期行:形如「Current date: 2026-09-08 Asia/Shanghai Tuesday」的单行紧凑输出(46 字符,约 12 token)。纯 cordis 宿主插件,不改动 DSH 源码。"
@@ -13,7 +13,7 @@
13
13
  },
14
14
  "license": "MIT",
15
15
  "engines": {
16
- "dsh": ">=0.2.0-rc.1 <0.2.1-0"
16
+ "dsh": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2"
17
17
  },
18
18
  "components": {
19
19
  "host": "src/index.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-date-wrapper",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Minimal date line for the DeepSeek Harness runtime-context snapshot: 'Current date: 2026-09-08 Asia/Shanghai Tuesday' (46 chars, ~12 tokens) - a cordis host plugin, no dsh source changes, no PR required",
6
6
  "keywords": [
@@ -30,16 +30,11 @@
30
30
  "dsh.plugin.json",
31
31
  "screenshots.json",
32
32
  "README.md",
33
- "README.zh.md",
34
- "README.ja.md",
35
- "README.ko.md",
33
+ "README.*.md",
36
34
  "INSTALL.md",
37
- "INSTALL.zh.md",
38
- "INSTALL.ja.md",
39
- "INSTALL.ko.md",
35
+ "INSTALL.*.md",
40
36
  "CHANGELOG.md",
41
- "CHANGELOG.ja.md",
42
- "CHANGELOG.ko.md",
37
+ "CHANGELOG.*.md",
43
38
  "HANDOVER.md",
44
39
  "LICENSE"
45
40
  ],
@@ -49,14 +44,18 @@
49
44
  }
50
45
  },
51
46
  "publishConfig": {
52
- "tag": "dsh-0.1.7"
47
+ "tag": "latest"
53
48
  },
54
49
  "peerDependencies": {
55
- "@deepseek-ai/cordis": "^4.0.2"
50
+ "@deepseek-ai/cordis": "^4.0.2",
51
+ "@deepseek-ai/dsh-system-prompt": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2"
56
52
  },
57
53
  "peerDependenciesMeta": {
58
54
  "@deepseek-ai/cordis": {
59
55
  "optional": true
56
+ },
57
+ "@deepseek-ai/dsh-system-prompt": {
58
+ "optional": true
60
59
  }
61
60
  },
62
61
  "scripts": {
@@ -72,6 +71,6 @@
72
71
  },
73
72
  "engines": {
74
73
  "node": ">=20",
75
- "dsh": ">=0.2.0-rc.1 <0.2.1-0"
74
+ "dsh": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2"
76
75
  }
77
76
  }