@goodandready/dsh-russian-lang 0.3.25 → 0.3.27

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
@@ -5,7 +5,7 @@
5
5
  <h3>Полная русская локализация, умная типографика и исправление раскладки клавиатуры для DeepSeek Harness</h3>
6
6
 
7
7
  <p align="center">
8
- <a href="https://www.npmjs.com/package/@goodandready/dsh-russian-lang"><img src="https://img.shields.io/badge/npm-v0.3.25-6366f1.svg?style=for-the-badge&labelColor=1e1b4b" alt="npm version"></a>
8
+ <a href="https://www.npmjs.com/package/@goodandready/dsh-russian-lang"><img src="https://img.shields.io/badge/npm-v0.3.27-6366f1.svg?style=for-the-badge&labelColor=1e1b4b" alt="npm version"></a>
9
9
  <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-10b981.svg?style=for-the-badge&color=10b981&labelColor=064e3b" alt="license"></a>
10
10
  <a href="https://github.com/topics/dsh-plugin"><img src="https://img.shields.io/badge/DSH-Plugin-8b5cf6.svg?style=for-the-badge&labelColor=2e1065" alt="DSH Plugin"></a>
11
11
  <a href="https://nodejs.org"><img src="https://img.shields.io/badge/Node-20%2B-f59e0b.svg?style=for-the-badge&labelColor=451a03" alt="Node version"></a>
@@ -14,7 +14,7 @@
14
14
  <p align="center">
15
15
  <img src="https://img.shields.io/badge/DSH-v0.2.0--rc.2%2B-blue.svg?style=for-the-badge&labelColor=1e1b4b" alt="DSH v0.1.7-rc.2+">
16
16
  <img src="https://img.shields.io/badge/Покрытие-100%25-10b981.svg?style=for-the-badge&labelColor=064e3b" alt="Покрытие 100%">
17
- <img src="https://img.shields.io/badge/Ключей_UI-8576-6366f1.svg?style=for-the-badge&labelColor=1e1b4b" alt="8576 ключей">
17
+ <img src="https://img.shields.io/badge/Ключей_UI-8584-6366f1.svg?style=for-the-badge&labelColor=1e1b4b" alt="8584 ключей">
18
18
  <img src="https://img.shields.io/badge/Ручная_вычитка-100%25-0ea5e9.svg?style=for-the-badge&labelColor=082f49" alt="100% ручная вычитка">
19
19
  </p>
20
20
 
@@ -85,7 +85,7 @@ graph LR
85
85
 
86
86
  ## ✨ Полный обзор возможностей
87
87
 
88
- ### 1. 🌐 100% покрытие ядра DSH (59 Пространств имён, 2415 ключей)
88
+ ### 1. 🌐 100% покрытие ядра DSH (58 пространств имён, 2 442 ключа)
89
89
  * **Диалоги и переписка (`conversation`)**: лента сообщений, ветки обсуждений, карточки вызова инструментов, статус генерации и рассуждений (thinking traces).
90
90
  * **Модели и провайдеры (`settings.models`)**: каталог моделей, параметры инференса, управление токенами и ключами API.
91
91
  * **Трейсы рассуждений (`trajectory`)**: детальные шаги, параметры вызовов инструментов, временные метки и визуализация размышлений модели.
@@ -94,9 +94,9 @@ graph LR
94
94
  * **Планировщик и инвентарь (`schedule.catalog`, `settings.pluginInventory`, `settings.plugins`)**: фоновые задания, периодичность, фильтры и каталог установленных плагинов.
95
95
  * **Права доступа и безопасность (`permission.access`, `plan`, `skill`)**: пресеты прав (полный доступ, только чтение, запись в рабочую область), выполнение планов и навыки.
96
96
 
97
- > **О качестве перевода.** Все **8110 ключей интерфейса (2146 ядра + 6589 плагинов) переведены на 100% и вычитаны вручную**. Черновой машинный перевод полностью замещён проверенными формулировками (`draft = 0`). Перевод регулярно валидируется автоматическими линтерами целостности плейсхолдеров, проверкой соблюдения глоссария (`glossary.json`) и детекторами переполнения верстки. Нашли неточность — кнопка «Сообщить о проблеме перевода» в карточке настроек создаёт готовый issue.
97
+ > **О качестве перевода.** Все **8 584 ключа интерфейса (2 442 ядра + 6 142 плагинов) переведены на 100% и вычитаны вручную**. Черновой машинный перевод полностью замещён проверенными формулировками (`draft = 0`). Перевод регулярно валидируется автоматическими линтерами целостности плейсхолдеров, проверкой соблюдения глоссария (`glossary.json`) и детекторами переполнения верстки. Нашли неточность — кнопка «Сообщить о проблеме перевода» в карточке настроек создаёт готовый issue.
98
98
 
99
- ### 2. 🧩 Встроенный перевод 65+ плагинов экосистемы DSH (5695 ключей)
99
+ ### 2. 🧩 Встроенный перевод 65+ плагинов экосистемы DSH (6 142 ключа)
100
100
  Локализация автоматически распространяется на все ключевые плагины экосистемы DeepSeek Harness:
101
101
  * **`dsh-session-control`** — расширенное управление сессиями: закрепление диалогов, архив по периодам, просмотр расшифровок и фильтрация шума;
102
102
  * **`dsh-kanban` и `task-board`** — канбан-доски задач, карточки, чек-листы, дедлайны, критерии готовности (DoD) и шлюз приёмки (Acceptance Gate);
@@ -149,7 +149,7 @@ graph LR
149
149
 
150
150
  ### 7. ⚡ Оптимизации производительности и архитектурная безопасность
151
151
  * **Пакетная обработка MutationObserver**: оптимизированный наблюдатель мутаций интерфейса с адаптивным debounce (16 мс) предотвращает лавинообразные перерисовки и перерасчёт макета (reflow) при интенсивном рендеринге списков и стриминге LLM-токенов.
152
- * **Защита HTTP-маршрутов словарей (405 Method Not Allowed)**: серверные эндпоинты `/dict/core`, `/dict/plugins`, `/dict/all`, `/dict/search` строго защищены и принимают только безопасные методы GET/HEAD.
152
+ * **Защита HTTP-маршрутов словарей (405 Method Not Allowed)**: серверные эндпоинты `/api/dsh-russian-lang/dict/core`, `/api/dsh-russian-lang/dict/plugins`, `/api/dsh-russian-lang/dict/all` строго защищены и принимают только безопасные методы GET/HEAD.
153
153
  * **Клиентский бандл с запасом**: оптимизированная архитектура и компактный бутстрап обеспечивают размер клиентского скрипта 153.7 KiB (запас более 10 KiB до предельного лимита).
154
154
 
155
155
  ### 8. 🔤 Нативная интеграция в ядро
@@ -167,22 +167,31 @@ dsh plugin --profile web add @goodandready/dsh-russian-lang
167
167
 
168
168
  ---
169
169
 
170
- ## ⚙️ Параметры конфигурации (`settings.yaml`)
170
+ ## ⚙️ Параметры конфигурации (`settings.yaml` / профиль Cordis)
171
171
 
172
- Пространство настроек — `russian-lang`. Схема объявлена в [`lib/index.js`](lib/index.js),
173
- все поля необязательные:
172
+ В актуальных версиях DSH (v0.2.0-rc.2+, v0.1.7+) конфигурация плагина управляется штатно через managed-форму в веб-интерфейсе (**Настройки → Плагины → Русская локализация**) либо в профиле/конфиге под идентификатором плагина `dsh-russian-lang` (согласно `cordis.patch.yml`).
173
+
174
+ Для полной обратной совместимости с ранними версиями ядра (DSH <= 0.1.6) плагин также автоматически поддерживает чтение из легаси-пространства `russian-lang`.
175
+
176
+ Схема параметров объявлена в [`lib/index.js`](lib/index.js), все поля необязательные:
174
177
 
175
178
  ```yaml
176
- russian-lang:
179
+ # Актуальный формат (DSH v0.2.0-rc.2+ / v0.1.7+):
180
+ dsh-russian-lang:
177
181
  enabled: true # Русский язык интерфейса
178
182
  typography:
179
183
  enabled: true # Ёлочки, длинные тире, неразрывные пробелы
180
184
  yo: false # Восстанавливать «ё» (по умолчанию выключено)
181
185
  agentPrompt: false # Просить агента отвечать по-русски
182
186
  overrides: {} # Свои значения для любых ключей перевода
187
+
188
+ # Легаси-формат (DSH <= 0.1.6, поддерживается автоматически как fallback):
189
+ # russian-lang:
190
+ # enabled: true
191
+ # ...
183
192
  ```
184
193
 
185
- Проще то же самое — в **Настройки → Плагины → Русская локализация**.
194
+ Удобнее всего настраивать параметры визуально в интерфейсе: **Настройки → Плагины → Русская локализация**.
186
195
 
187
196
  Исправление раскладки (<kbd>Alt+L</kbd>) и браузерный спелчек включаются вместе с
188
197
  русским языком и отдельных ключей не имеют.
package/bin/dsh-i18n.mjs CHANGED
@@ -6,6 +6,10 @@ import { fileURLToPath } from 'node:url'
6
6
  const __dirname = path.dirname(fileURLToPath(import.meta.url))
7
7
  const ROOT = path.resolve(__dirname, '..')
8
8
 
9
+ function escapeRegExp(string) {
10
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
11
+ }
12
+
9
13
  function getPkgVersion() {
10
14
  try {
11
15
  const pkg = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8'))
@@ -55,7 +59,7 @@ function extractKeys(targetDir, defaultNs = 'common') {
55
59
  walk(fullPath)
56
60
  } else if (entry.isFile() && extensions.has(path.extname(entry.name))) {
57
61
  const code = fs.readFileSync(fullPath, 'utf8')
58
- const tMatches = code.matchAll(/\bt\(\s*['"`]([a-zA-Z0-9_.-]+)['"`]\s*\)/g)
62
+ const tMatches = code.matchAll(/\bt\(\s*['"`]([a-zA-Z0-9_.-]+)['"`]\s*[,)]/g)
59
63
  for (const m of tMatches) {
60
64
  result[defaultNs][m[1]] = result[defaultNs][m[1]] || ''
61
65
  }
@@ -88,6 +92,11 @@ function validateDict(filePath, glossaryPath) {
88
92
  return false
89
93
  }
90
94
 
95
+ if (!data || typeof data !== 'object' || Array.isArray(data)) {
96
+ console.error(`Ошибка структуры JSON в ${filePath}: корневой элемент должен быть объектом`)
97
+ return false
98
+ }
99
+
91
100
  let errors = []
92
101
  let warnings = []
93
102
  let totalKeys = 0
@@ -103,7 +112,7 @@ function validateDict(filePath, glossaryPath) {
103
112
  function checkString(ns, key, val) {
104
113
  totalKeys++
105
114
  if (typeof val !== 'string') {
106
- errors.push(`[${ns}:${key}] Значение должно быть строкой, получено: ${typeof val}`)
115
+ errors.push(`[${ns}:${key}] Значение должно быть строкой, получено: ${val === null ? 'null' : Array.isArray(val) ? 'массив' : typeof val}`)
107
116
  return
108
117
  }
109
118
 
@@ -117,13 +126,12 @@ function validateDict(filePath, glossaryPath) {
117
126
  }
118
127
 
119
128
  if (glossary) {
120
- const lower = val.toLowerCase()
121
129
  for (const [term, info] of Object.entries(glossary)) {
122
130
  if (Array.isArray(info.forbidden)) {
123
131
  for (const forbidden of info.forbidden) {
124
- const fLow = forbidden.toLowerCase()
125
- const re = new RegExp(`\\b${fLow}\\b`, 'i')
126
- if (re.test(lower)) {
132
+ const esc = escapeRegExp(forbidden)
133
+ const re = new RegExp(`(?<=[^\\p{L}\\p{N}]|^)${esc}(?=[^\\p{L}\\p{N}]|$)`, 'iu')
134
+ if (re.test(val)) {
127
135
  warnings.push(`[${ns}:${key}] Запрещённый термин по глоссарию "${forbidden}" (рекомендуется: "${info.canonical}")`)
128
136
  }
129
137
  }
@@ -134,10 +142,12 @@ function validateDict(filePath, glossaryPath) {
134
142
 
135
143
  for (const ns of Object.keys(data)) {
136
144
  const section = data[ns]
137
- if (typeof section === 'object' && section !== null) {
138
- for (const [k, v] of Object.entries(section)) {
139
- checkString(ns, k, v)
140
- }
145
+ if (!section || typeof section !== 'object' || Array.isArray(section)) {
146
+ errors.push(`[${ns}] Пространство имён должно быть объектом, получено: ${section === null ? 'null' : Array.isArray(section) ? 'массив' : typeof section}`)
147
+ continue
148
+ }
149
+ for (const [k, v] of Object.entries(section)) {
150
+ checkString(ns, k, v)
141
151
  }
142
152
  }
143
153
 
package/glossary.json ADDED
@@ -0,0 +1,206 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "version": "1.0.0",
4
+ "description": "Канонический глоссарий терминов DeepSeek Harness (DSH) и AI-экосистемы",
5
+ "terms": {
6
+ "workspace": {
7
+ "canonical": "Рабочая область",
8
+ "allowed": [
9
+ "Рабочая область",
10
+ "Воркспейс"
11
+ ],
12
+ "forbidden": [
13
+ "Рабочее место",
14
+ "Рабочий стол",
15
+ "Пространство задач"
16
+ ],
17
+ "description": "Изолированная рабочая директория/проект агента"
18
+ },
19
+ "subagent": {
20
+ "canonical": "Субагент",
21
+ "allowed": [
22
+ "Субагент",
23
+ "Дочерний агент"
24
+ ],
25
+ "forbidden": [
26
+ "Подагент",
27
+ "Младший агент",
28
+ "Вспомогательный агент"
29
+ ],
30
+ "description": "Автономный дочерний агент"
31
+ },
32
+ "prompt": {
33
+ "canonical": "Промпт",
34
+ "allowed": [
35
+ "Промпт",
36
+ "Инструкция",
37
+ "Системный промпт"
38
+ ],
39
+ "forbidden": [
40
+ "Затравка",
41
+ "Побуждение",
42
+ "Внушение"
43
+ ],
44
+ "description": "Инструкция или текстовый ввод для модели"
45
+ },
46
+ "tool": {
47
+ "canonical": "Инструмент",
48
+ "allowed": [
49
+ "Инструмент",
50
+ "Вызов инструмента"
51
+ ],
52
+ "forbidden": [
53
+ "Орудие",
54
+ "Утилита"
55
+ ],
56
+ "description": "Функция или инструмент, вызываемый агентом (tool/tool call)"
57
+ },
58
+ "session": {
59
+ "canonical": "Сессия",
60
+ "allowed": [
61
+ "Сессия",
62
+ "Диалог",
63
+ "Чат"
64
+ ],
65
+ "forbidden": [
66
+ "Заседание",
67
+ "Сеанс связи"
68
+ ],
69
+ "description": "Отдельный поток диалога или сессия работы"
70
+ },
71
+ "skill": {
72
+ "canonical": "Навык",
73
+ "allowed": [
74
+ "Навык",
75
+ "Навыки",
76
+ "Skill"
77
+ ],
78
+ "forbidden": [
79
+ "Умение",
80
+ "Мастерство"
81
+ ],
82
+ "description": "Подключаемый модуль навыков агента"
83
+ },
84
+ "plugin": {
85
+ "canonical": "Плагин",
86
+ "allowed": [
87
+ "Плагин",
88
+ "Плагины"
89
+ ],
90
+ "forbidden": [
91
+ "Встраиваемый модуль"
92
+ ],
93
+ "description": "Плагин Cordis / DSH"
94
+ },
95
+ "provider": {
96
+ "canonical": "Провайдер",
97
+ "allowed": [
98
+ "Провайдер",
99
+ "Провайдеры"
100
+ ],
101
+ "forbidden": [
102
+ "Поставщик",
103
+ "Поставщики"
104
+ ],
105
+ "description": "Провайдер LLM API (OpenAI, DeepSeek, Ollama и др.)"
106
+ },
107
+ "token": {
108
+ "canonical": "Токен",
109
+ "allowed": [
110
+ "Токен",
111
+ "Токены"
112
+ ],
113
+ "forbidden": [
114
+ "Жетон",
115
+ "Жетоны"
116
+ ],
117
+ "description": "Единица расхода контекста LLM"
118
+ },
119
+ "thinking": {
120
+ "canonical": "Размышления",
121
+ "allowed": [
122
+ "Размышления",
123
+ "Рассуждения",
124
+ "Цепочка рассуждений"
125
+ ],
126
+ "forbidden": [
127
+ "Думание",
128
+ "Мышление модели"
129
+ ],
130
+ "description": "Трейс внутренних рассуждений (thinking traces) модели"
131
+ },
132
+ "effort": {
133
+ "canonical": "Уровень рассуждений",
134
+ "allowed": [
135
+ "Уровень рассуждений",
136
+ "Усилие рассуждений",
137
+ "Усилие"
138
+ ],
139
+ "forbidden": [
140
+ "Старание",
141
+ "Напряжение"
142
+ ],
143
+ "description": "Параметр reasoning effort модели"
144
+ },
145
+ "approval": {
146
+ "canonical": "Подтверждение",
147
+ "allowed": [
148
+ "Подтверждение",
149
+ "Одобрение"
150
+ ],
151
+ "forbidden": [
152
+ "Апробация",
153
+ "Санкционирование"
154
+ ],
155
+ "description": "Запрос подтверждения опасного действия пользователем"
156
+ },
157
+ "deliverables": {
158
+ "canonical": "Результаты работы",
159
+ "allowed": [
160
+ "Результаты работы",
161
+ "Файлы результатов",
162
+ "Результаты"
163
+ ],
164
+ "forbidden": [
165
+ "Поставки",
166
+ "Доставляемые элементы"
167
+ ],
168
+ "description": "Созданные агентом итоговые файлы"
169
+ },
170
+ "branch": {
171
+ "canonical": "Ветка",
172
+ "allowed": [
173
+ "Ветка",
174
+ "Ветвление"
175
+ ],
176
+ "forbidden": [
177
+ "Ответвление",
178
+ "Ветвь"
179
+ ],
180
+ "description": "Ветка диалога или Git-ветка"
181
+ },
182
+ "checkpoint": {
183
+ "canonical": "Контрольная точка",
184
+ "allowed": [
185
+ "Контрольная точка",
186
+ "Чекпоинт"
187
+ ],
188
+ "forbidden": [
189
+ "Точка проверки",
190
+ "Контрольный пункт"
191
+ ],
192
+ "description": "Точка сохранения состояния сессии или памяти"
193
+ },
194
+ "command_code": {
195
+ "canonical": "Command Code",
196
+ "allowed": [
197
+ "Command Code"
198
+ ],
199
+ "forbidden": [
200
+ "Код команды",
201
+ "Командный код"
202
+ ],
203
+ "description": "Название провайдера и расширения Command Code (commandcode.ai)"
204
+ }
205
+ }
206
+ }