@goodandready/dsh-russian-lang 0.3.0 → 0.3.3
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 +20 -5
- package/README.ru.md +20 -5
- package/bin/dsh-i18n.mjs +247 -0
- package/lib/client.js +2932 -2360
- package/lib/index.js +89 -15
- package/lib/locales/core.json +1 -1
- package/lib/locales/plugins/03-dshmarket.json +1 -1
- package/lib/locales/plugins/17-dsh-context.json +1 -1
- package/lib/locales/plugins/26-config-manager.json +1 -1
- package/lib/locales/plugins/29-config-manager-recovery.json +1 -1
- package/lib/locales/plugins/32-vision-bridge.json +1 -1
- package/lib/locales/plugins/33-messenger-gateway.json +1 -1
- package/lib/locales/plugins/34-key-rotation.json +1 -1
- package/lib/locales/plugins/35-gitea.json +1 -1
- package/lib/locales/plugins/36-cost-meter.json +1 -1
- package/lib/locales/plugins/37-time-machine.json +1 -1
- package/lib/locales/plugins/40-clinebot.json +1 -1
- package/lib/locales/plugins/41-lanmode.json +1 -1
- package/lib/locales/plugins/42-plugin-console.json +1 -1
- package/lib/locales/plugins/48-task-tracker.json +1 -1
- package/lib/locales/plugins/49-dsml-guard.json +1 -1
- package/lib/locales/plugins/54-workshop-market.json +1 -1
- package/lib/locales/plugins/56-cron.json +1 -1
- package/lib/locales/plugins/58-grok-xsearch.json +1 -1
- package/lib/locales/plugins/59-goal.json +1 -1
- package/lib/locales/plugins/60-model-sync.json +1 -1
- package/lib/locales/plugins/61-issue-reporter.json +1 -1
- package/lib/locales/plugins/62-model-search.json +1 -1
- package/lib/locales/plugins/63-agent-orchestrator.json +1 -1
- package/lib/locales/plugins/65-subscriptions.json +1 -1
- package/lib/locales/plugins/67-voice.json +1 -1
- package/lib/locales/plugins/68-image-gen.json +1 -1
- package/lib/locales/plugins/70-hypotheses.json +1 -1
- package/lib/locales/plugins/72-server-monitor.json +1 -1
- package/lib/locales/plugins/73-agentrouter.json +1 -1
- package/lib/locales/plugins/77-github-ops.json +1 -0
- package/lib/locales/plugins/78-web-gateway.json +1 -0
- package/lib/locales/plugins/79-approval-gate.json +1 -0
- package/lib/locales/plugins/80-ip-pool.json +1 -0
- package/lib/locales/plugins/81-ego-browser.json +1 -0
- package/lib/locales/plugins/82-effort-slider.json +1 -0
- package/lib/locales/zh-ru.json +1 -1
- package/lib/locales.js +50 -12
- package/lib/pure.js +306 -14
- package/lib/translator.js +55 -0
- package/package.json +7 -2
package/lib/index.js
CHANGED
|
@@ -1,15 +1,42 @@
|
|
|
1
|
+
import crypto from 'node:crypto'
|
|
1
2
|
import { registerPluginUpdater } from './plugin-updater.js'
|
|
2
3
|
import { registerTranslator } from './translator.js'
|
|
3
|
-
import { getCoreDictionaries, getPluginDictionaries, getZhRuMap } from './locales.js'
|
|
4
|
+
import { getCoreDictionaries, getPluginDictionaries, getPluginDictionariesByNames, getAllDictionaries, getZhRuMap } from './locales.js'
|
|
4
5
|
// dsh-russian-lang — серверная половина.
|
|
5
6
|
//
|
|
6
7
|
// Словари и переключатель живут в браузере (lib/client.js). Хосту переводить
|
|
7
8
|
// нечего, но у выбора языка есть сохраняемая настройка: регистрируем её схему
|
|
8
|
-
// в собственном namespace, чтобы запись переживала браузеры и машины
|
|
9
|
+
// в собственном namespace, чтобы запись переживала браузеры и машины череж
|
|
9
10
|
// штатный механизм настроек DSH.
|
|
10
11
|
import z from '@deepseek-ai/schemastery'
|
|
11
12
|
import { SYSTEM_PROMPT_PRESETS } from './pure.js'
|
|
12
13
|
|
|
14
|
+
|
|
15
|
+
const sendJsonWithEtag = (request, response, obj, maxAge = 300) => {
|
|
16
|
+
const body = Buffer.from(JSON.stringify(obj), 'utf-8')
|
|
17
|
+
const etag = '"' + crypto.createHash('md5').update(body).digest('hex') + '"'
|
|
18
|
+
const ifNoneMatch = request?.headers?.['if-none-match']
|
|
19
|
+
if (ifNoneMatch && (ifNoneMatch === etag || ifNoneMatch === '*' || ifNoneMatch === `W/${etag}`)) {
|
|
20
|
+
response.writeHead(304, {
|
|
21
|
+
'etag': etag,
|
|
22
|
+
'cache-control': `public, max-age=${maxAge}, must-revalidate`,
|
|
23
|
+
})
|
|
24
|
+
response.end()
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
response.writeHead(200, {
|
|
28
|
+
'content-type': 'application/json; charset=utf-8',
|
|
29
|
+
'etag': etag,
|
|
30
|
+
'cache-control': `public, max-age=${maxAge}, must-revalidate`,
|
|
31
|
+
'content-length': body.length,
|
|
32
|
+
})
|
|
33
|
+
if (request?.method === 'HEAD') {
|
|
34
|
+
response.end()
|
|
35
|
+
} else {
|
|
36
|
+
response.end(body)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
13
40
|
export const name = '@goodandready/dsh-russian-lang'
|
|
14
41
|
|
|
15
42
|
const RussianLangSettingsSchema = z.object({
|
|
@@ -36,7 +63,7 @@ export function apply(ctx) {
|
|
|
36
63
|
})
|
|
37
64
|
|
|
38
65
|
// #68: русский системный промпт агента (опционально). Регистрируем секцию
|
|
39
|
-
// промпта, которая
|
|
66
|
+
// промпта, которая задёт стиль ответов по-русски, когда включён флаг
|
|
40
67
|
// russian-lang.agentPrompt. Секция — официальная точка расширения ядра.
|
|
41
68
|
ctx.inject(['settings', 'systemPrompt'], (settingsCtx, prompt) => {
|
|
42
69
|
const NS = 'russian-lang'
|
|
@@ -57,7 +84,7 @@ export function apply(ctx) {
|
|
|
57
84
|
sync()
|
|
58
85
|
})
|
|
59
86
|
|
|
60
|
-
// Web endpoints: One-click plugin updater, modular plugin dictionary serving, & translator gateway
|
|
87
|
+
// Web endpoints: One-click plugin updater, modular lazy-plugin dictionary serving, & translator gateway
|
|
61
88
|
if (typeof ctx.inject === 'function') {
|
|
62
89
|
ctx.inject(['webServer'], (wctx) => {
|
|
63
90
|
try {
|
|
@@ -73,33 +100,80 @@ export function apply(ctx) {
|
|
|
73
100
|
let ws = null
|
|
74
101
|
try { ws = wctx?.webServer } catch (_) { ws = null }
|
|
75
102
|
|
|
76
|
-
|
|
103
|
+
const unregsDict = []
|
|
77
104
|
if (ws && typeof ws.register === 'function') {
|
|
78
|
-
|
|
105
|
+
// 1. Core dictionary only (fast-boot, ~135 KB)
|
|
106
|
+
unregsDict.push(ws.register({
|
|
79
107
|
kind: 'exact',
|
|
80
|
-
path: '/api/dsh-russian-lang/dict/
|
|
108
|
+
path: '/api/dsh-russian-lang/dict/core',
|
|
81
109
|
handler: async (request, response) => {
|
|
82
110
|
try {
|
|
111
|
+
if (request.method !== 'GET' && request.method !== 'HEAD') {
|
|
112
|
+
response.writeHead(405, { allow: 'GET, HEAD', 'content-type': 'application/json; charset=utf-8' })
|
|
113
|
+
response.end(JSON.stringify({ error: 'Method not allowed' }))
|
|
114
|
+
return
|
|
115
|
+
}
|
|
83
116
|
const core = getCoreDictionaries()
|
|
84
|
-
const plugins = getPluginDictionaries()
|
|
85
117
|
const zhRu = getZhRuMap()
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
})
|
|
90
|
-
|
|
118
|
+
sendJsonWithEtag(request, response, { core, zhRu })
|
|
119
|
+
} catch (err) {
|
|
120
|
+
response.writeHead(500, { 'content-type': 'application/json; charset=utf-8' })
|
|
121
|
+
response.end(JSON.stringify({ error: String(err) }))
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
}))
|
|
125
|
+
|
|
126
|
+
// 2. On-demand plugins dictionary serving (query: ?names=p1,p2...)
|
|
127
|
+
unregsDict.push(ws.register({
|
|
128
|
+
kind: 'prefix',
|
|
129
|
+
path: '/api/dsh-russian-lang/dict/plugins',
|
|
130
|
+
handler: async (request, response) => {
|
|
131
|
+
try {
|
|
132
|
+
if (request.method !== 'GET' && request.method !== 'HEAD') {
|
|
133
|
+
response.writeHead(405, { allow: 'GET, HEAD', 'content-type': 'application/json; charset=utf-8' })
|
|
134
|
+
response.end(JSON.stringify({ error: 'Method not allowed' }))
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
const url = new URL(request.url, 'http://localhost')
|
|
138
|
+
const namesParam = url.searchParams.get('names') || url.searchParams.get('list') || ''
|
|
139
|
+
const names = namesParam ? namesParam.split(',').map((s) => s.trim()).filter(Boolean) : null
|
|
140
|
+
const plugins = getPluginDictionariesByNames(names)
|
|
141
|
+
sendJsonWithEtag(request, response, { plugins })
|
|
142
|
+
} catch (err) {
|
|
143
|
+
response.writeHead(500, { 'content-type': 'application/json; charset=utf-8' })
|
|
144
|
+
response.end(JSON.stringify({ error: String(err) }))
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
}))
|
|
148
|
+
|
|
149
|
+
// 3. Backward compatibility all-dictionaries endpoint
|
|
150
|
+
unregsDict.push(ws.register({
|
|
151
|
+
kind: 'exact',
|
|
152
|
+
path: '/api/dsh-russian-lang/dict/all',
|
|
153
|
+
handler: async (request, response) => {
|
|
154
|
+
try {
|
|
155
|
+
if (request.method !== 'GET' && request.method !== 'HEAD') {
|
|
156
|
+
response.writeHead(405, { allow: 'GET, HEAD', 'content-type': 'application/json; charset=utf-8' })
|
|
157
|
+
response.end(JSON.stringify({ error: 'Method not allowed' }))
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
const all = getAllDictionaries()
|
|
161
|
+
const zhRu = getZhRuMap()
|
|
162
|
+
sendJsonWithEtag(request, response, Object.assign({}, all, { core: getCoreDictionaries(), plugins: getPluginDictionaries(), zhRu }))
|
|
91
163
|
} catch (err) {
|
|
92
164
|
response.writeHead(500, { 'content-type': 'application/json; charset=utf-8' })
|
|
93
165
|
response.end(JSON.stringify({ error: String(err) }))
|
|
94
166
|
}
|
|
95
167
|
},
|
|
96
|
-
})
|
|
168
|
+
}))
|
|
97
169
|
}
|
|
98
170
|
|
|
99
171
|
return () => {
|
|
100
172
|
if (typeof unregUpdater === 'function') unregUpdater()
|
|
101
173
|
if (typeof unregTranslator === 'function') unregTranslator()
|
|
102
|
-
|
|
174
|
+
for (const u of unregsDict) {
|
|
175
|
+
if (typeof u === 'function') u()
|
|
176
|
+
}
|
|
103
177
|
}
|
|
104
178
|
}
|
|
105
179
|
if (typeof wctx.effect === 'function') wctx.effect(mount, 'russian-lang: web routes')
|