@goodandready/dsh-dsml-artifact-guard 0.2.8 → 0.2.9
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/CHANGELOG.md +7 -0
- package/lib/client.js +32 -37
- package/lib/index.js +27 -24
- package/package.json +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [0.2.9] - 2026-10-07
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **Settings Card Locale Snapshot Extraction**: safely extract active locale string from `LocaleSnapshot` object (`snap?.active`) returned by `ctx.locale.getLocale()` / `getSnapshot()`, eliminating fatal `TypeError: rawLang.startsWith is not a function` during settings card mount (#50, #57).
|
|
14
|
+
- **Russian Language Registration & Ownership**: removed embedded `ru` dictionary from the plugin bundle to prevent `(namespace, 'ru')` duplicate registration collisions in core; delegate Russian translations to `dsh-russian-lang` via `props.t` and `ctx.locale.bind(NS)` (#58).
|
|
15
|
+
- **Volatile Per-Field Settings Schema**: marked configuration fields volatile individually, enabling DSH to discover and generate settings form controls (#52).
|
|
16
|
+
|
|
10
17
|
## [0.2.8] - 2026-09-26
|
|
11
18
|
|
|
12
19
|
### Added
|
package/lib/client.js
CHANGED
|
@@ -91,38 +91,6 @@ window.__ModuleLoader__.load({
|
|
|
91
91
|
saveError: '保存失败: {msg}',
|
|
92
92
|
};
|
|
93
93
|
|
|
94
|
-
const ru = {
|
|
95
|
-
title: 'Защита от артефактов DSML',
|
|
96
|
-
sub: 'Фильтрация утекших замыкающих тегов протокола DSML из потоков моделей DeepSeek',
|
|
97
|
-
version: 'Версия',
|
|
98
|
-
updateChecking: 'Проверка обновлений…',
|
|
99
|
-
updateAvailable: 'Доступно обновление: v{v}',
|
|
100
|
-
upToDate: 'Установлена последняя версия',
|
|
101
|
-
updateNow: 'Обновить сейчас',
|
|
102
|
-
updating: 'Обновление…',
|
|
103
|
-
updateSuccess: 'Обновлено до v{v}. Перезапустите службу DSH для применения изменений.',
|
|
104
|
-
updateFailed: 'Ошибка обновления: {msg}',
|
|
105
|
-
checkUpdateFailed: 'Не удалось проверить обновления',
|
|
106
|
-
mode: 'Режим работы',
|
|
107
|
-
modeSanitize: 'Санация (вырезать утекшие замыкающие теги)',
|
|
108
|
-
modeAudit: 'Аудит (только логировать предупреждения в журнал)',
|
|
109
|
-
modeDisabled: 'Отключено (пропускать все потоки без изменений)',
|
|
110
|
-
modelPattern: 'Шаблон модели (RegExp)',
|
|
111
|
-
modelPatternHint: 'Регулярное выражение без учёта регистра для ID модели (по умолчанию: deepseek).',
|
|
112
|
-
providers: 'Целевые провайдеры (опционально)',
|
|
113
|
-
providersPlaceholder: 'все провайдеры (через запятую, напр. commandcode, deepseek-official)',
|
|
114
|
-
providersHint: 'Список ID провайдеров через запятую. Оставьте пустым для защиты всех провайдеров.',
|
|
115
|
-
legacyDetected: 'Обнаружены устаревшие параметры providerId / modelId (действуют как дополнительное правило).',
|
|
116
|
-
legacyClear: 'Очистить устаревшие поля',
|
|
117
|
-
providerId: 'Целевой провайдер (устаревшее)',
|
|
118
|
-
modelId: 'Целевая модель (устаревшее)',
|
|
119
|
-
disabledNotice: '⚠️ Защита отключена. Замыкающие теги DSML будут попадать в интерфейс чата.',
|
|
120
|
-
statusUnavailable: 'Служба настроек недоступна.',
|
|
121
|
-
saving: 'Сохранение…',
|
|
122
|
-
ready: 'Сохранить настройки',
|
|
123
|
-
saved: 'Настройки сохранены',
|
|
124
|
-
saveError: 'Ошибка сохранения: {msg}',
|
|
125
|
-
};
|
|
126
94
|
|
|
127
95
|
const DEFAULTS = {
|
|
128
96
|
mode: 'sanitize',
|
|
@@ -164,11 +132,38 @@ window.__ModuleLoader__.load({
|
|
|
164
132
|
}
|
|
165
133
|
const scope = scopeRef.current;
|
|
166
134
|
|
|
167
|
-
const rawLang = ((
|
|
168
|
-
|
|
169
|
-
|
|
135
|
+
const rawLang = (() => {
|
|
136
|
+
try {
|
|
137
|
+
const snap = typeof _ctx?.locale?.getLocale === 'function'
|
|
138
|
+
? _ctx.locale.getLocale()
|
|
139
|
+
: (typeof _ctx?.locale?.getSnapshot === 'function' ? _ctx.locale.getSnapshot() : null);
|
|
140
|
+
if (typeof snap?.active === 'string' && snap.active) return snap.active;
|
|
141
|
+
if (typeof snap === 'string' && snap) return snap;
|
|
142
|
+
} catch (err) {
|
|
143
|
+
/* Fallback if locale service getter fails */
|
|
144
|
+
}
|
|
145
|
+
if (typeof navigator !== 'undefined' && typeof navigator.language === 'string' && navigator.language) {
|
|
146
|
+
return navigator.language;
|
|
147
|
+
}
|
|
148
|
+
return 'en';
|
|
149
|
+
})();
|
|
150
|
+
const currentLang = rawLang.startsWith('zh') ? 'zh' : 'en';
|
|
151
|
+
const dict = currentLang === 'zh' ? zh : en;
|
|
152
|
+
|
|
153
|
+
const tBound = React.useMemo(() => {
|
|
154
|
+
if (typeof t === 'function') return t;
|
|
155
|
+
if (typeof _ctx?.locale?.bind === 'function') {
|
|
156
|
+
try {
|
|
157
|
+
return _ctx.locale.bind(NS);
|
|
158
|
+
} catch (err) {
|
|
159
|
+
/* Locale bind fallback */
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
}, [t, _ctx]);
|
|
164
|
+
|
|
170
165
|
const tt = (k, params) => {
|
|
171
|
-
let str = (typeof
|
|
166
|
+
let str = (typeof tBound === 'function' ? tBound(k) : null) || dict[k] || en[k] || k;
|
|
172
167
|
if (params && typeof params === 'object') {
|
|
173
168
|
for (const [pk, pv] of Object.entries(params)) {
|
|
174
169
|
str = str.replace(new RegExp('\\{' + pk + '\\}', 'g'), String(pv));
|
|
@@ -675,7 +670,7 @@ window.__ModuleLoader__.load({
|
|
|
675
670
|
if (typeof ctx.locale?.register === 'function') {
|
|
676
671
|
const registerLocale = () => {
|
|
677
672
|
try {
|
|
678
|
-
return ctx.locale.register(NS, { en, zh
|
|
673
|
+
return ctx.locale.register(NS, { en, zh });
|
|
679
674
|
} catch (err) {
|
|
680
675
|
/* Locale namespace already registered or unavailable */
|
|
681
676
|
}
|
package/lib/index.js
CHANGED
|
@@ -9,17 +9,24 @@ const KEEP = 96;
|
|
|
9
9
|
export const name = '@goodandready/dsh-dsml-artifact-guard';
|
|
10
10
|
export const inject = ['llm', 'settings', 'webServer'];
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
// DSH builds a namespace's settings form from the PER-FIELD volatile markers of the
|
|
13
|
+
// entry schema. Wrapping the object in .volatile() produced none of them, so no form was
|
|
14
|
+
// ever generated. Mark each user-editable field instead.
|
|
15
|
+
export const Config = Schema.object({
|
|
16
|
+
mode: Schema.string().default('sanitize').volatile().description('How to handle detected artifact markup'),
|
|
17
|
+
modelPattern: Schema.string().default('deepseek').volatile().description('Model name substring this plugin guards'),
|
|
18
|
+
providers: Schema.array(Schema.string()).default([]).volatile().description('Restrict guarding to these providers; empty means all'),
|
|
19
|
+
providerId: Schema.string().volatile().description('Legacy exact provider id match'),
|
|
20
|
+
modelId: Schema.string().volatile().description('Legacy exact model id match'),
|
|
18
21
|
});
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
// Unwrap Volatile boxes before any caller reads a value.
|
|
24
|
+
export function plainConfig(value) {
|
|
25
|
+
if (value === null || typeof value !== 'object') return value;
|
|
26
|
+
if (Array.isArray(value)) return value.map(plainConfig);
|
|
27
|
+
if (typeof value.get === 'function') return plainConfig(value.get());
|
|
28
|
+
return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, plainConfig(v)]));
|
|
29
|
+
}
|
|
23
30
|
|
|
24
31
|
export function matchesScope(o, c) {
|
|
25
32
|
if (!c || c.mode === 'disabled') return false;
|
|
@@ -139,25 +146,21 @@ export async function* sanitizeDsmlArtifacts(s, { mode = 'sanitize', onArtifact
|
|
|
139
146
|
|
|
140
147
|
export function unwrapConfig(conf) {
|
|
141
148
|
if (!conf) return {};
|
|
142
|
-
|
|
149
|
+
// A Volatile reference (any field is now volatile) resolves through .get().
|
|
150
|
+
const readRef = (val) => {
|
|
143
151
|
try {
|
|
144
|
-
const
|
|
145
|
-
return
|
|
146
|
-
} catch
|
|
147
|
-
/* Volatile getter failed */
|
|
152
|
+
const inner = typeof val?.get === 'function' ? val.get() : val;
|
|
153
|
+
return inner && typeof inner === 'object' ? inner : {};
|
|
154
|
+
} catch {
|
|
148
155
|
return {};
|
|
149
156
|
}
|
|
150
|
-
}
|
|
157
|
+
};
|
|
158
|
+
if (typeof conf.get === 'function') return readRef(conf);
|
|
151
159
|
try {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
return (res && typeof res === 'object') ? res : {};
|
|
158
|
-
} catch (err) {
|
|
159
|
-
/* Config validation fallback to object */
|
|
160
|
-
return (conf && typeof conf === 'object') ? conf : {};
|
|
160
|
+
// Config() returns volatile boxes now, so unwrap them; a plain input stays plain.
|
|
161
|
+
return plainConfig(Config(conf));
|
|
162
|
+
} catch {
|
|
163
|
+
return plainConfig(conf) && typeof plainConfig(conf) === 'object' ? plainConfig(conf) : {};
|
|
161
164
|
}
|
|
162
165
|
}
|
|
163
166
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-dsml-artifact-guard",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "Sanitizes leaked DeepSeek DSML closing tags from model text streams",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -33,12 +33,15 @@
|
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
36
|
-
"@deepseek-ai/schemastery": "^3.18.
|
|
36
|
+
"@deepseek-ai/schemastery": "^3.18.4"
|
|
37
37
|
},
|
|
38
38
|
"exports": {
|
|
39
39
|
".": "./lib/index.js",
|
|
40
40
|
"./client": "./lib/client.js",
|
|
41
41
|
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
42
42
|
"./package.json": "./package.json"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@deepseek-ai/schemastery": "^3.18.4"
|
|
43
46
|
}
|
|
44
47
|
}
|