dsh-switchman 1.3.1 → 1.6.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.de.md +56 -34
- package/README.es.md +53 -31
- package/README.fr.md +52 -30
- package/README.it.md +47 -25
- package/README.ja.md +54 -32
- package/README.ko.md +55 -33
- package/README.md +53 -31
- package/README.pt.md +47 -25
- package/README.ru.md +52 -30
- package/README.zh-TW.md +52 -30
- package/README.zh.md +46 -24
- package/client.js +2344 -40
- package/cordis.patch.yml +24 -8
- package/host/config.js +31 -0
- package/host/context-watch.js +424 -84
- package/host/dispatch.js +107 -6
- package/host/handover-state.js +38 -0
- package/host/lang.js +211 -36
- package/host/lib/dsh-home.js +18 -0
- package/host/routes.js +143 -8
- package/host/subagent-model.js +147 -0
- package/host/subagents.js +160 -0
- package/host/teams.js +583 -0
- package/host/ui-locale.js +35 -0
- package/host/vision.js +367 -0
- package/index.js +40 -8
- package/package.json +1 -1
- package/skills/db-query/package.json +1 -1
- package/skills/db-query/scripts/lib/cli.js +23 -23
- package/skills/db-query/scripts/lib/config.js +78 -61
- package/skills/db-query/scripts/lib/mysql-readonly.js +167 -158
- package/skills/db-query/scripts/lib/output.js +56 -55
- package/skills/db-query/scripts/lib/redis-readonly.js +116 -111
- package/skills/db-query/scripts/mysql-query.js +46 -42
- package/skills/db-query/scripts/redis-query.js +32 -29
- package/skills/db-query/scripts/setup.sh +16 -16
package/client.js
CHANGED
|
@@ -4,19 +4,26 @@
|
|
|
4
4
|
* bundle per package; sibling files cannot be synchronously required).
|
|
5
5
|
*
|
|
6
6
|
* Surfaces, all reading the shared "dsh-switchman" locale namespace (zh/en):
|
|
7
|
-
* - Phase 0: the team-autonomy badge in `conversation.session.header.actions
|
|
8
|
-
*
|
|
7
|
+
* - Phase 0: the team-autonomy badge in `conversation.session.header.actions`,
|
|
8
|
+
* extended with the current session's actual model (provider/model@effort)
|
|
9
|
+
* for subagent sessions (live projection face, shared-snapshot fallback).
|
|
9
10
|
* - Phase 1: a `settings.section` page with a "Language" card:
|
|
10
11
|
* conversation / code-comment / document language preferences.
|
|
11
12
|
* - Phase 2: a "Dispatch pools & ranking" card on the same page: six lane
|
|
12
13
|
* pools and a capability ranking edited against the live model catalog
|
|
13
14
|
* (served by the Host route family), plus the enforcement mode. Every
|
|
14
|
-
* field shares one staged draft and one atomic fenced save.
|
|
15
|
+
* field shares one staged draft and one atomic fenced save. Selected
|
|
16
|
+
* routes outside the session's DSH-authorized child models (Host
|
|
17
|
+
* /authorized route) carry a ⚠ badge plus a one-line hint.
|
|
15
18
|
* - Phase 3: a "Context watermark" card on the same page: tiered token
|
|
16
19
|
* thresholds (soft/hard/force), the per-read budget, hard-tier behavior,
|
|
17
20
|
* automatic handover, and the subagent context cap — number inputs with
|
|
18
21
|
* per-field minimum plus soft<hard<force order validation, folded into
|
|
19
22
|
* the same staged draft and one atomic save.
|
|
23
|
+
* - Phase 4: an "Agent teams" card on the same page: the teams-mode master
|
|
24
|
+
* switch, the whitelist-sync sub-switch (teams mode only), and the
|
|
25
|
+
* whitelist sync status line. The ⚠ unauthorized badges and hint render
|
|
26
|
+
* only in teams mode (plain subagent dispatch names no routes).
|
|
20
27
|
*/
|
|
21
28
|
|
|
22
29
|
window.__ModuleLoader__.load({
|
|
@@ -46,10 +53,55 @@ window.__ModuleLoader__.load({
|
|
|
46
53
|
{ value: 'ko', label: '한국어' },
|
|
47
54
|
{ value: 'es', label: 'Español' },
|
|
48
55
|
{ value: 'fr', label: 'Français' },
|
|
56
|
+
{ value: 'it', label: 'Italiano' },
|
|
57
|
+
{ value: 'pt', label: 'Português' },
|
|
49
58
|
{ value: 'de', label: 'Deutsch' },
|
|
50
59
|
{ value: 'ru', label: 'Русский' },
|
|
51
60
|
];
|
|
52
61
|
|
|
62
|
+
/** Interface-language choices for this plugin's own UI: "auto"
|
|
63
|
+
* follows the DSH app language; any other value forces the plugin
|
|
64
|
+
* UI into that locale (extra locales resolve from the inline
|
|
65
|
+
* EXTRA_UI_DICTS table, falling back to English). Labels are
|
|
66
|
+
* endonyms, identical in every UI language. */
|
|
67
|
+
const UI_LOCALE_OPTIONS = [
|
|
68
|
+
{ value: 'auto', label: 'Auto' },
|
|
69
|
+
{ value: 'en', label: 'English' },
|
|
70
|
+
{ value: 'zh', label: '简体中文' },
|
|
71
|
+
{ value: 'zh-TW', label: '繁體中文' },
|
|
72
|
+
{ value: 'ja', label: '日本語' },
|
|
73
|
+
{ value: 'ko', label: '한국어' },
|
|
74
|
+
{ value: 'de', label: 'Deutsch' },
|
|
75
|
+
{ value: 'es', label: 'Español' },
|
|
76
|
+
{ value: 'fr', label: 'Français' },
|
|
77
|
+
{ value: 'it', label: 'Italiano' },
|
|
78
|
+
{ value: 'pt', label: 'Português' },
|
|
79
|
+
{ value: 'ru', label: 'Русский' },
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
/** Repaint signal for the manual interface-locale override: t()
|
|
83
|
+
* reads an apply()-scope closure variable, so every component that
|
|
84
|
+
* renders plugin strings subscribes to this tiny store to
|
|
85
|
+
* re-render when the override changes (the DSH locale store only
|
|
86
|
+
* fires on app-language changes). Snapshot is a monotonic version
|
|
87
|
+
* counter; notify never lets one bad listener block the rest. */
|
|
88
|
+
const uiLocaleListeners = new Set();
|
|
89
|
+
let uiLocaleVersion = 0;
|
|
90
|
+
const subscribeUiLocale = (listener) => {
|
|
91
|
+
uiLocaleListeners.add(listener);
|
|
92
|
+
return () => uiLocaleListeners.delete(listener);
|
|
93
|
+
};
|
|
94
|
+
const notifyUiLocale = () => {
|
|
95
|
+
uiLocaleVersion += 1;
|
|
96
|
+
for (const listener of uiLocaleListeners) {
|
|
97
|
+
try {
|
|
98
|
+
listener();
|
|
99
|
+
} catch {
|
|
100
|
+
/* one bad listener never blocks the rest */
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
53
105
|
/** Sentinel select value standing for a hand-typed language. */
|
|
54
106
|
const CUSTOM = '__custom__';
|
|
55
107
|
|
|
@@ -138,6 +190,7 @@ window.__ModuleLoader__.load({
|
|
|
138
190
|
|
|
139
191
|
/** Every settings field this page edits, in mutate order. */
|
|
140
192
|
const ALL_FIELDS = [
|
|
193
|
+
'uiLocale',
|
|
141
194
|
...LANG_FIELDS,
|
|
142
195
|
...POOL_FIELDS.map(({ field }) => field),
|
|
143
196
|
...POOL_FIELDS.map(({ manualField }) => manualField),
|
|
@@ -148,6 +201,8 @@ window.__ModuleLoader__.load({
|
|
|
148
201
|
'wmDenyMode',
|
|
149
202
|
'wmAutoHandover',
|
|
150
203
|
'wmSubagentCap',
|
|
204
|
+
'teamsMode',
|
|
205
|
+
'syncWhitelist',
|
|
151
206
|
];
|
|
152
207
|
|
|
153
208
|
/** Stable identity of one provider/model route. */
|
|
@@ -171,11 +226,12 @@ window.__ModuleLoader__.load({
|
|
|
171
226
|
: route;
|
|
172
227
|
}
|
|
173
228
|
|
|
174
|
-
/**
|
|
175
|
-
*
|
|
229
|
+
/** Reasoning-effort fallback tiers (used when wire metadata is
|
|
230
|
+
* unavailable for a model); the real list follows wire
|
|
231
|
+
* reasoning.efforts. */
|
|
176
232
|
const EFFORTS = ['low', 'medium', 'high'];
|
|
177
233
|
|
|
178
|
-
/**
|
|
234
|
+
/** One well-formed effort entry ({provider, model, effort}), or null. */
|
|
179
235
|
function sanitizeEffortEntry(entry) {
|
|
180
236
|
const route = sanitizeRoute(entry);
|
|
181
237
|
if (route === null) return null;
|
|
@@ -230,6 +286,15 @@ window.__ModuleLoader__.load({
|
|
|
230
286
|
const bool = (field, def) =>
|
|
231
287
|
typeof value?.[field] === 'boolean' ? value[field] : def;
|
|
232
288
|
return {
|
|
289
|
+
// Interface-locale enum (a missing/invalid host snapshot
|
|
290
|
+
// always presents as "auto"), then the scope enum (same
|
|
291
|
+
// fallback to "global"). Both sit first to mirror save()'s
|
|
292
|
+
// desired object; equality itself is canonical()-based, so
|
|
293
|
+
// key order is not load-bearing.
|
|
294
|
+
uiLocale: UI_LOCALE_OPTIONS.some((option) => option.value === value?.uiLocale)
|
|
295
|
+
? value.uiLocale
|
|
296
|
+
: 'auto',
|
|
297
|
+
langScope: value?.langScope === 'project' ? 'project' : 'global',
|
|
233
298
|
langConversation: string('langConversation'),
|
|
234
299
|
langComments: string('langComments'),
|
|
235
300
|
langDocs: string('langDocs'),
|
|
@@ -260,6 +325,8 @@ window.__ModuleLoader__.load({
|
|
|
260
325
|
wmDenyMode: value?.wmDenyMode === 'deny' ? 'deny' : 'cap',
|
|
261
326
|
wmAutoHandover: bool('wmAutoHandover', true),
|
|
262
327
|
wmSubagentCap: bool('wmSubagentCap', true),
|
|
328
|
+
teamsMode: bool('teamsMode', false),
|
|
329
|
+
syncWhitelist: bool('syncWhitelist', false),
|
|
263
330
|
};
|
|
264
331
|
}
|
|
265
332
|
|
|
@@ -270,9 +337,11 @@ window.__ModuleLoader__.load({
|
|
|
270
337
|
* numbers — never their input-string forms). */
|
|
271
338
|
function canonical(values) {
|
|
272
339
|
return JSON.stringify({
|
|
340
|
+
langScope: values.langScope,
|
|
273
341
|
langConversation: values.langConversation,
|
|
274
342
|
langComments: values.langComments,
|
|
275
343
|
langDocs: values.langDocs,
|
|
344
|
+
uiLocale: values.uiLocale,
|
|
276
345
|
...Object.fromEntries(
|
|
277
346
|
POOL_FIELDS.map(({ field, manualField }) => [
|
|
278
347
|
field,
|
|
@@ -306,6 +375,8 @@ window.__ModuleLoader__.load({
|
|
|
306
375
|
wmDenyMode: values.wmDenyMode,
|
|
307
376
|
wmAutoHandover: values.wmAutoHandover,
|
|
308
377
|
wmSubagentCap: values.wmSubagentCap,
|
|
378
|
+
teamsMode: values.teamsMode,
|
|
379
|
+
syncWhitelist: values.syncWhitelist,
|
|
309
380
|
});
|
|
310
381
|
}
|
|
311
382
|
|
|
@@ -343,9 +414,26 @@ window.__ModuleLoader__.load({
|
|
|
343
414
|
return index;
|
|
344
415
|
}
|
|
345
416
|
|
|
417
|
+
/** Parse the /authorized answer (the session's DSH-authorized child
|
|
418
|
+
* models) into { enabled, keys } — null when unknown: a failed
|
|
419
|
+
* fetch, an unreadable service (both fields null), or a malformed
|
|
420
|
+
* shape all degrade to "no badges, no hint". A readable-but-empty
|
|
421
|
+
* whitelist yields keys = empty Set (every selected route drifts). */
|
|
422
|
+
function parseAuthorized(value) {
|
|
423
|
+
if (value === null || typeof value !== 'object') return null;
|
|
424
|
+
if (value.enabled !== true && value.enabled !== false) return null;
|
|
425
|
+
if (!Array.isArray(value.routes)) return null;
|
|
426
|
+
const keys = new Set();
|
|
427
|
+
for (const route of value.routes) {
|
|
428
|
+
const clean = sanitizeRoute(route);
|
|
429
|
+
if (clean !== null) keys.add(routeKey(clean));
|
|
430
|
+
}
|
|
431
|
+
return { enabled: value.enabled, keys };
|
|
432
|
+
}
|
|
433
|
+
|
|
346
434
|
/** Checkbox rows for one pool: every live catalog model, checked or
|
|
347
|
-
*
|
|
348
|
-
*
|
|
435
|
+
* not, plus this pool's saved routes that left the catalog (still
|
|
436
|
+
* removable — mirrors the shipped model-selection page). */
|
|
349
437
|
function poolRows(pool, catalogIndex) {
|
|
350
438
|
const selected = new Set(pool.map(routeKey));
|
|
351
439
|
const rows = [];
|
|
@@ -412,11 +500,30 @@ window.__ModuleLoader__.load({
|
|
|
412
500
|
badge: '自主团队',
|
|
413
501
|
badgeTip:
|
|
414
502
|
'dsh-switchman:四个内置预设(standard / ptc / minimal / cordis)已注入自主智能体团队调度规程',
|
|
503
|
+
handoverActive: '交接进行中',
|
|
504
|
+
handoverPhaseBackup: '备份会话',
|
|
505
|
+
handoverPhaseCompacting: '压缩上下文',
|
|
506
|
+
handoverPhaseContinuation: '唤醒续接',
|
|
507
|
+
handoverActiveTip:
|
|
508
|
+
'Switchman 正在后台交接:fork 备份会话并压缩上下文,完成后自动继续任务;期间会话静止属正常现象。',
|
|
509
|
+
visionHintNeedsPool:
|
|
510
|
+
'当前模型不支持读图:请在 dsh-switchman 设置中配置「视觉池」模型,之后用 /vision 发送图片。',
|
|
511
|
+
visionHintUseVision:
|
|
512
|
+
'当前模型不支持读图:图片请用 /vision 发送(将自动派发视觉池读取)。',
|
|
513
|
+
visionAutoConverted:
|
|
514
|
+
'图片直发被拒:已自动改用 /vision 重发(由视觉池读取)。',
|
|
415
515
|
settingsTitle: 'dsh-switchman',
|
|
516
|
+
panelLabel: 'Switchman 调度中心',
|
|
416
517
|
settingsDescription: '配置 dsh-switchman 的各项偏好。',
|
|
417
518
|
langSectionTitle: '语言偏好',
|
|
418
519
|
langSectionDescription:
|
|
419
520
|
'控制智能体的对话、代码注释与文档撰写语言。',
|
|
521
|
+
langScopeLabel: '语言作用域',
|
|
522
|
+
langScopeHelp: '选择这三项语言偏好的存放位置。',
|
|
523
|
+
langScopeGlobal: '全局(本 profile)',
|
|
524
|
+
langScopeProject: '按项目(.switchman/lang.json)',
|
|
525
|
+
langProjectNote:
|
|
526
|
+
'按项目模式:各项目读取自身的 .switchman/lang.json;首次询问的答案会写入该文件,文件不存在时每个会话都会询问。以下三项仅在全局模式生效。',
|
|
420
527
|
langConversationLabel: '对话语言',
|
|
421
528
|
langConversationHelp:
|
|
422
529
|
'智能体回复与讨论使用的语言;未设置时会在首次使用时询问一次并记住。',
|
|
@@ -478,6 +585,9 @@ window.__ModuleLoader__.load({
|
|
|
478
585
|
catalogEmpty: '当前没有模型提供方公布模型。',
|
|
479
586
|
catalogUnavailableGroup: '已保存但当前不可用',
|
|
480
587
|
catalogUnavailable: '当前不可用',
|
|
588
|
+
unauthorizedBadge: '未在 DSH 设置的子智能体模型选择授权列表中',
|
|
589
|
+
unauthorizedHint:
|
|
590
|
+
'标有 ⚠ 的模型未在 DSH 设置 → 子智能体 → 模型选择 中授权,Agent 显式指定它们会被拒绝;去 DSH 设置授权,或让 Agent 走隐式派发。',
|
|
481
591
|
rankTitle: '能力排序',
|
|
482
592
|
rankDescription:
|
|
483
593
|
'序号即能力序(最强在前),可为每项锚定 S/A/B/C 档。列表为六池选中 ∪ 已有排序;任意编辑都会固化当前显示顺序。',
|
|
@@ -524,16 +634,53 @@ window.__ModuleLoader__.load({
|
|
|
524
634
|
wmSubagentFollowForce: '跟随 force 档(0)',
|
|
525
635
|
wmCommands:
|
|
526
636
|
'命令:/ctx-pause 暂停水位干预 · /ctx-resume 恢复干预 · /ctx-handover 立即备份并交接压缩。',
|
|
637
|
+
teamsSectionTitle: '智能体团队',
|
|
638
|
+
teamsSectionDescription:
|
|
639
|
+
'切换派发形态:关闭为纯 subagent 派发(DSH 出厂保守团队策略接管);开启后注入自主团队规程并启用 Agent Teams。',
|
|
640
|
+
teamsModeLabel: '智能体团队模式',
|
|
641
|
+
teamsModeHelp:
|
|
642
|
+
'开启后注入团队规程(默认委派 + 分级验证 + 任务板纪律),并自动启用 DSH 的 Agent Teams bundle;派发池的 ⚠ 授权徽标仅在开启时显示。',
|
|
643
|
+
syncWhitelistLabel: '同步子智能体模型白名单',
|
|
644
|
+
syncWhitelistHelp:
|
|
645
|
+
'独立开关(不依赖智能体团队模式):把六池选中模型的并集整体写入 DSH「设置 → 子智能体 → 模型选择」的授权列表;dsh-switchman 成为唯一事实源。',
|
|
646
|
+
whitelistSyncOk: '已同步 {count} 条({time})。',
|
|
647
|
+
whitelistSyncError: '同步失败:{error}',
|
|
648
|
+
whitelistSyncPending: '等待同步…',
|
|
649
|
+
whitelistSyncNote: '白名单变更仅对之后新建的会话生效。',
|
|
650
|
+
uiSectionTitle: '界面',
|
|
651
|
+
uiSectionDescription: '本插件自身界面(徽标、面板、本设置页)的显示语言。',
|
|
652
|
+
uiLocaleLabel: '界面语言',
|
|
653
|
+
uiLocaleHelp: '「自动」跟随 DeepSeek Harness 应用语言;选择具体语言后,本插件界面将固定为该语言。',
|
|
654
|
+
uiLocaleAuto: '自动(跟随 DSH)',
|
|
527
655
|
},
|
|
528
656
|
en: {
|
|
529
657
|
badge: 'Team autonomy',
|
|
530
658
|
badgeTip:
|
|
531
659
|
'dsh-switchman: the four built-in presets (standard / ptc / minimal / cordis) carry the autonomous Agent Teams doctrine',
|
|
660
|
+
handoverActive: 'Handover in progress',
|
|
661
|
+
handoverPhaseBackup: 'forking backup',
|
|
662
|
+
handoverPhaseCompacting: 'compacting context',
|
|
663
|
+
handoverPhaseContinuation: 'waking continuation',
|
|
664
|
+
handoverActiveTip:
|
|
665
|
+
'Switchman is handing over in the background: forking a backup session and compacting context; the task continues automatically when done. A still session during this window is expected.',
|
|
666
|
+
visionHintNeedsPool:
|
|
667
|
+
'This model cannot read images: add vision-pool models in the dsh-switchman settings, then send images with /vision.',
|
|
668
|
+
visionHintUseVision:
|
|
669
|
+
'This model cannot read images: send them with /vision (routed to the vision pool automatically).',
|
|
670
|
+
visionAutoConverted:
|
|
671
|
+
'Image send was refused: automatically resubmitting via /vision (read by the vision pool).',
|
|
532
672
|
settingsTitle: 'dsh-switchman',
|
|
673
|
+
panelLabel: 'Switchman',
|
|
533
674
|
settingsDescription: 'Configure dsh-switchman preferences.',
|
|
534
675
|
langSectionTitle: 'Language',
|
|
535
676
|
langSectionDescription:
|
|
536
677
|
'Controls the language of agent replies, code comments, and authored documents.',
|
|
678
|
+
langScopeLabel: 'Language scope',
|
|
679
|
+
langScopeHelp: 'Where these language preferences are stored.',
|
|
680
|
+
langScopeGlobal: 'Global (this profile)',
|
|
681
|
+
langScopeProject: 'Per project (.switchman/lang.json)',
|
|
682
|
+
langProjectNote:
|
|
683
|
+
'Per-project mode: every project reads its own .switchman/lang.json; first-use answers are saved there, and sessions ask until it exists. The three fields below apply only in global mode.',
|
|
537
684
|
langConversationLabel: 'Conversation language',
|
|
538
685
|
langConversationHelp:
|
|
539
686
|
'The language agents reply and discuss in; when unset, you are asked once on first use and the choice is remembered.',
|
|
@@ -596,6 +743,9 @@ window.__ModuleLoader__.load({
|
|
|
596
743
|
catalogEmpty: 'No model provider currently advertises a model.',
|
|
597
744
|
catalogUnavailableGroup: 'Saved but currently unavailable',
|
|
598
745
|
catalogUnavailable: 'currently unavailable',
|
|
746
|
+
unauthorizedBadge: 'not authorized for explicit child dispatch in DSH Settings (subagents: model selection)',
|
|
747
|
+
unauthorizedHint:
|
|
748
|
+
'Models marked ⚠ are not authorized in DSH Settings → Subagents → model selection; agents naming them explicitly will be denied — authorize them in DSH Settings, or let agents dispatch implicitly.',
|
|
599
749
|
rankTitle: 'Capability ranking',
|
|
600
750
|
rankDescription:
|
|
601
751
|
'Numbered strongest first; each entry may anchor an S/A/B/C tier. The list is pool selections ∪ the saved ranking; any edit persists the displayed order.',
|
|
@@ -642,6 +792,1269 @@ window.__ModuleLoader__.load({
|
|
|
642
792
|
wmSubagentFollowForce: 'Follow the force tier (0)',
|
|
643
793
|
wmCommands:
|
|
644
794
|
'Commands: /ctx-pause suspends watermark actions · /ctx-resume resumes them · /ctx-handover backs up and hands over now.',
|
|
795
|
+
teamsSectionTitle: 'Agent teams',
|
|
796
|
+
teamsSectionDescription:
|
|
797
|
+
"Switch the dispatch shape: off is plain subagent dispatch (DSH's factory conservative team policy takes over); on injects the autonomous team doctrine and enables Agent Teams.",
|
|
798
|
+
teamsModeLabel: 'Agent teams mode',
|
|
799
|
+
teamsModeHelp:
|
|
800
|
+
'When on, the team doctrine (delegate by default + tiered verification + task-board discipline) is injected and the DSH Agent Teams bundle is enabled; the dispatch pools ⚠ authorization badges show only in this mode.',
|
|
801
|
+
syncWhitelistLabel: 'Sync the subagent model whitelist',
|
|
802
|
+
syncWhitelistHelp:
|
|
803
|
+
'Independent switch (does not require agent teams mode): writes the union of the six pools over the DSH "Settings → Subagents → model selection" authorization list; dsh-switchman becomes the single source of truth.',
|
|
804
|
+
whitelistSyncOk: 'Synced {count} entries ({time}).',
|
|
805
|
+
whitelistSyncError: 'Sync failed: {error}',
|
|
806
|
+
whitelistSyncPending: 'Waiting to sync…',
|
|
807
|
+
whitelistSyncNote: 'Whitelist changes only affect sessions created afterwards.',
|
|
808
|
+
uiSectionTitle: 'Interface',
|
|
809
|
+
uiSectionDescription: "Display language for this plugin's own UI (badge, panel, this settings page).",
|
|
810
|
+
uiLocaleLabel: 'Interface language',
|
|
811
|
+
uiLocaleHelp: "Auto follows the DeepSeek Harness app language; picking a language forces this plugin's UI into it.",
|
|
812
|
+
uiLocaleAuto: 'Auto (follow DSH)',
|
|
813
|
+
},
|
|
814
|
+
};
|
|
815
|
+
|
|
816
|
+
/** Inline dictionaries for the extra interface locales (every
|
|
817
|
+
* UI_LOCALE_OPTIONS tag beyond zh/en). Inlined on purpose: the
|
|
818
|
+
* harness loads plugin client bundles as classic scripts, where
|
|
819
|
+
* ESM-only syntax (module meta context, dynamic module
|
|
820
|
+
* loading) is a parse-time SyntaxError there, and
|
|
821
|
+
* the plugin asset route serves only client*.js chunks — so an
|
|
822
|
+
* on-demand module fetch could never work. Key set mirrors the
|
|
823
|
+
* DICTS en table (verified by script at generation time). Keep in
|
|
824
|
+
* sync with UI_LOCALE_OPTIONS and the host ENUM_FIELDS. */
|
|
825
|
+
const EXTRA_UI_DICTS = {
|
|
826
|
+
'zh-TW': {
|
|
827
|
+
badge: '自主團隊',
|
|
828
|
+
badgeTip: 'dsh-switchman:四個內建預設(standard / ptc / minimal / cordis)已注入自主智能體團隊調度規程',
|
|
829
|
+
handoverActive: '交接進行中',
|
|
830
|
+
handoverPhaseBackup: '備份會話',
|
|
831
|
+
handoverPhaseCompacting: '壓縮上下文',
|
|
832
|
+
handoverPhaseContinuation: '喚醒續接',
|
|
833
|
+
handoverActiveTip: 'Switchman 正在背景交接:fork 備份會話並壓縮上下文,完成後自動繼續任務;期間會話靜止屬正常現象。',
|
|
834
|
+
visionHintNeedsPool: '目前模型不支援讀圖:請在 dsh-switchman 設定中配置多模態池模型,之後用 /vision 傳送圖片。',
|
|
835
|
+
visionHintUseVision: '目前模型不支援讀圖:圖片請用 /vision 傳送(將自動派發多模態池讀取)。',
|
|
836
|
+
visionAutoConverted: '圖片直傳被拒:已自動改用 /vision 重送(由多模態池讀取)。',
|
|
837
|
+
settingsTitle: 'dsh-switchman',
|
|
838
|
+
panelLabel: 'Switchman 調度中心',
|
|
839
|
+
settingsDescription: '設定 dsh-switchman 的各項偏好。',
|
|
840
|
+
langSectionTitle: '語言偏好',
|
|
841
|
+
langSectionDescription: '控制智能體的對話、程式碼註解與文件撰寫語言。',
|
|
842
|
+
langScopeLabel: '語言作用範圍',
|
|
843
|
+
langScopeHelp: '選擇這三項語言偏好的存放位置。',
|
|
844
|
+
langScopeGlobal: '全域(本 profile)',
|
|
845
|
+
langScopeProject: '按專案(.switchman/lang.json)',
|
|
846
|
+
langProjectNote: '按專案模式:各專案讀取自身的 .switchman/lang.json;首次詢問的答案會寫入該檔案,檔案不存在時每個會話都會詢問。以下三項僅在全域模式生效。',
|
|
847
|
+
langConversationLabel: '對話語言',
|
|
848
|
+
langConversationHelp: '智能體回覆與討論使用的語言;未設定時會在首次使用時詢問一次並記住。',
|
|
849
|
+
langCommentsLabel: '程式碼註解語言',
|
|
850
|
+
langCommentsHelp: '智能體撰寫程式碼註解使用的語言。',
|
|
851
|
+
langDocsLabel: '文件語言',
|
|
852
|
+
langDocsHelp: '智能體撰寫文件使用的語言。',
|
|
853
|
+
followConversation: '跟隨對話語言',
|
|
854
|
+
notSetAsk: '未設定(首次使用時詢問)',
|
|
855
|
+
customLanguage: '自訂…',
|
|
856
|
+
customLanguagePlaceholder: '語言名稱或 BCP 標籤',
|
|
857
|
+
customLanguageRequired: '請輸入自訂語言(1–48 個字元)。',
|
|
858
|
+
currentValue: '目前:{value}',
|
|
859
|
+
currentValueUnset: '目前:未設定',
|
|
860
|
+
suggestedValue: '建議:{value}',
|
|
861
|
+
save: '儲存',
|
|
862
|
+
saving: '儲存中…',
|
|
863
|
+
discard: '放棄修改',
|
|
864
|
+
saveFailed: '本部署沒有接受這些值,已保留供你修改。',
|
|
865
|
+
saveConflict: '設定已在其他位置更新。請放棄修改後重試。',
|
|
866
|
+
formLoading: '正在載入設定…',
|
|
867
|
+
formUnavailable: '該外掛目前未載入,暫時無法設定。',
|
|
868
|
+
formReadOnly: '本部署的設定為唯讀。',
|
|
869
|
+
dispatchSectionTitle: '派發池與模型排序',
|
|
870
|
+
dispatchSectionDescription: '按任務複雜度把模型分組進六個派發池,並維護能力排序;僅影響 dsh-switchman 的委派調度。',
|
|
871
|
+
dispatchProgress: '已設定 {pools}/6 池 · 已排名 {ranked} 項 · 模式 {mode}',
|
|
872
|
+
poolEconomyTitle: '輕量池 · economy',
|
|
873
|
+
poolEconomyDesc: '輕量批次與低複雜度任務',
|
|
874
|
+
poolMechanicalTitle: '機械池 · mechanical',
|
|
875
|
+
poolMechanicalDesc: '機械改寫與模板化操作',
|
|
876
|
+
poolMainTitle: '主力池 · main',
|
|
877
|
+
poolMainDesc: '常規編碼與日常任務',
|
|
878
|
+
poolHardTitle: '高難池 · hard',
|
|
879
|
+
poolHardDesc: '高難推理與大規模重構',
|
|
880
|
+
poolVisionTitle: '多模態池 · vision',
|
|
881
|
+
poolVisionDesc: '影像等多模態輸入任務',
|
|
882
|
+
poolReviewTitle: '複審池 · review',
|
|
883
|
+
poolReviewDesc: '唯讀複審與獨立驗證',
|
|
884
|
+
poolSelectAll: '全選',
|
|
885
|
+
poolClear: '清空',
|
|
886
|
+
poolEmpty: '暫無候選模型',
|
|
887
|
+
poolManualLabel: '手動序',
|
|
888
|
+
poolManualHelp: '開啟後按清單順序派發(首個即首選);未開啟按能力排序自動排。',
|
|
889
|
+
poolManualSelected: '已選 · 派發優先序',
|
|
890
|
+
poolManualAddable: '可新增',
|
|
891
|
+
poolMoveUp: '上移',
|
|
892
|
+
poolMoveDown: '下移',
|
|
893
|
+
poolRemoveOne: '移除',
|
|
894
|
+
poolEffortFollow: '跟隨泳道',
|
|
895
|
+
poolEffortLabel: '思考強度',
|
|
896
|
+
poolEffortHelp: '手動指定該模型的思考強度,派發時優先於泳道預設',
|
|
897
|
+
catalogLoading: '正在載入模型目錄…',
|
|
898
|
+
catalogLoadFailed: '無法載入模型目錄。',
|
|
899
|
+
catalogRetry: '重試',
|
|
900
|
+
catalogPartial: '部分模型提供者暫時無法載入;已儲存的選擇仍可移除。',
|
|
901
|
+
catalogEmpty: '目前沒有模型提供者公布模型。',
|
|
902
|
+
catalogUnavailableGroup: '已儲存但目前不可用',
|
|
903
|
+
catalogUnavailable: '目前不可用',
|
|
904
|
+
unauthorizedBadge: '未在 DSH 設定的子智能體模型選擇授權清單中',
|
|
905
|
+
unauthorizedHint: '標有 ⚠ 的模型未在 DSH 設定 → 子智能體 → 模型選擇 中授權,Agent 明確指定它們會被拒絕;去 DSH 設定授權,或讓 Agent 走隱式派發。',
|
|
906
|
+
rankTitle: '能力排序',
|
|
907
|
+
rankDescription: '序號即能力序(最強在前),可為每項錨定 S/A/B/C 檔。清單為六池選中 ∪ 已有排序;任意編輯都會固化目前顯示順序。',
|
|
908
|
+
rankEmpty: '先在上方池中勾選模型,排序清單會自動出現。',
|
|
909
|
+
rankTier: '檔位',
|
|
910
|
+
rankTierNone: '—',
|
|
911
|
+
rankMoveUp: '上移',
|
|
912
|
+
rankMoveDown: '下移',
|
|
913
|
+
rankRemove: '移出排序',
|
|
914
|
+
enforceLabel: '執行模式',
|
|
915
|
+
enforceOff: '關閉',
|
|
916
|
+
enforceAdvice: '建議',
|
|
917
|
+
enforceEnforce: '強制',
|
|
918
|
+
enforceHelpOff: '不向委派注入任何池子指引。',
|
|
919
|
+
enforceHelpAdvice: '池子指引作為建議注入,模型可自行偏離。',
|
|
920
|
+
enforceHelpEnforce: '池子指引作為硬性約束注入,偏離會被拒絕。',
|
|
921
|
+
wmSectionTitle: '上下文水位',
|
|
922
|
+
wmSectionDescription: '按 token 用量分級收緊行為:建議、限讀與收尾、自動交接。',
|
|
923
|
+
wmSoftLabel: '建議水位(soft)',
|
|
924
|
+
wmSoftHelp: '達到後出現橫幅提示,並建議委派與整理上下文。',
|
|
925
|
+
wmHardLabel: '硬水位(hard)',
|
|
926
|
+
wmHardHelp: '達到後讀取預算收緊,並建議收尾目前工作。',
|
|
927
|
+
wmForceLabel: '強制水位(force)',
|
|
928
|
+
wmForceHelp: '達到後建議備份並移交壓縮(可設為自動)。',
|
|
929
|
+
wmReadBudgetLabel: '單次讀取預算',
|
|
930
|
+
wmReadBudgetHelp: '每次讀取的 token 預算;每輪上限為其兩倍。',
|
|
931
|
+
wmNumberInvalid: '請輸入不小於 {min} 的整數。',
|
|
932
|
+
wmOrderInvalid: '三檔水位需嚴格遞增:soft < hard < force。',
|
|
933
|
+
wmDenyModeLabel: '硬檔行為',
|
|
934
|
+
wmDenyModeCap: '限流放行',
|
|
935
|
+
wmDenyModeDeny: '直接拒絕',
|
|
936
|
+
wmDenyModeHelpCap: '超出讀取預算的呼叫放行,但記錄警示。',
|
|
937
|
+
wmDenyModeHelpDeny: '超出讀取預算的呼叫直接拒絕。',
|
|
938
|
+
wmAutoHandoverLabel: '自動交接',
|
|
939
|
+
wmAutoHandoverHelp: '達到強制水位時自動備份並移交壓縮,無需手動確認。',
|
|
940
|
+
wmSubagentTitle: '子智能體',
|
|
941
|
+
wmSubagentCapLabel: '子智能體上下文上限',
|
|
942
|
+
wmSubagentCapHelp: '開啟後子智能體可用下方獨立強制閾值;關閉則完全跟隨上方三檔水位。',
|
|
943
|
+
wmSubagentForceLabel: '子智能體強制閾值',
|
|
944
|
+
wmSubagentForceHelp: '僅覆蓋子智能體的 force 檔(soft/hard 與主會話共用);0 = 跟隨上方強制水位。',
|
|
945
|
+
wmSubagentFollowForce: '跟隨 force 檔(0)',
|
|
946
|
+
wmCommands: '命令:/ctx-pause 暫停水位干預 · /ctx-resume 恢復干預 · /ctx-handover 立即備份並交接壓縮。',
|
|
947
|
+
teamsSectionTitle: '智能體團隊',
|
|
948
|
+
teamsSectionDescription: '切換派發形態:關閉為純 subagent 派發(DSH 出廠保守團隊策略接管);開啟後注入自主團隊規程並啟用 Agent Teams。',
|
|
949
|
+
teamsModeLabel: '智能體團隊模式',
|
|
950
|
+
teamsModeHelp: '開啟後注入團隊規程(預設委派 + 分級驗證 + 任務板紀律),並自動啟用 DSH 的 Agent Teams bundle;派發池的 ⚠ 授權徽標僅在開啟時顯示。',
|
|
951
|
+
syncWhitelistLabel: '同步子智能體模型白名單',
|
|
952
|
+
syncWhitelistHelp: '獨立開關(不依賴智能體團隊模式):把六池選中模型的聯集整體寫入 DSH「設定 → 子智能體 → 模型選擇」的授權清單;dsh-switchman 成為唯一事實來源。',
|
|
953
|
+
whitelistSyncOk: '已同步 {count} 條({time})。',
|
|
954
|
+
whitelistSyncError: '同步失敗:{error}',
|
|
955
|
+
whitelistSyncPending: '等待同步…',
|
|
956
|
+
whitelistSyncNote: '白名單變更僅對之後新建的會話生效。',
|
|
957
|
+
uiSectionTitle: '介面',
|
|
958
|
+
uiSectionDescription: '本外掛自身 UI(徽章、面板、此設定頁)的顯示語言。',
|
|
959
|
+
uiLocaleLabel: '介面語言',
|
|
960
|
+
uiLocaleHelp: '「自動」跟隨 DeepSeek Harness 應用程式語言;指定語言後,本外掛的 UI 固定使用該語言。',
|
|
961
|
+
uiLocaleAuto: '自動(跟隨 DSH)',
|
|
962
|
+
},
|
|
963
|
+
ja: {
|
|
964
|
+
badge: '自律チーム',
|
|
965
|
+
badgeTip: 'dsh-switchman:内蔵の 4 プリセット(standard / ptc / minimal / cordis)には自律エージェントチームのディスパッチ規律が注入済み',
|
|
966
|
+
handoverActive: 'ハンドオーバー進行中',
|
|
967
|
+
handoverPhaseBackup: 'バックアップ作成中',
|
|
968
|
+
handoverPhaseCompacting: 'コンテキスト圧縮中',
|
|
969
|
+
handoverPhaseContinuation: '継続セッション起動中',
|
|
970
|
+
handoverActiveTip: 'Switchman がバックグラウンドでハンドオーバー中です:セッションを fork してバックアップし、コンテキストを圧縮します。完了するとタスクは自動的に再開します。この間セッションが静止するのは正常です。',
|
|
971
|
+
visionHintNeedsPool: 'このモデルは画像を読めません:dsh-switchman の設定でマルチモーダルプールのモデルを追加し、画像は /vision で送信してください。',
|
|
972
|
+
visionHintUseVision: 'このモデルは画像を読めません:画像は /vision で送ってください(自動的にマルチモーダルプールへルーティングされます)。',
|
|
973
|
+
visionAutoConverted: '画像の直接送信は拒否されました:自動的に /vision で再送信します(マルチモーダルプールが読み取ります)。',
|
|
974
|
+
settingsTitle: 'dsh-switchman',
|
|
975
|
+
panelLabel: 'Switchman ディスパッチセンター',
|
|
976
|
+
settingsDescription: 'dsh-switchman の各種設定を行います。',
|
|
977
|
+
langSectionTitle: '言語設定',
|
|
978
|
+
langSectionDescription: 'エージェントの返信・コードコメント・ドキュメントの言語を制御します。',
|
|
979
|
+
langScopeLabel: '言語スコープ',
|
|
980
|
+
langScopeHelp: 'これらの言語設定の保存先です。',
|
|
981
|
+
langScopeGlobal: 'グローバル(このプロファイル)',
|
|
982
|
+
langScopeProject: 'プロジェクト単位(.switchman/lang.json)',
|
|
983
|
+
langProjectNote: 'プロジェクトモード:各プロジェクトは自身の .switchman/lang.json を読み取ります。初回の回答はそこに保存され、ファイルが存在するまで毎セッション尋ねます。下の 3 項目はグローバルモードでのみ有効です。',
|
|
984
|
+
langConversationLabel: '会話言語',
|
|
985
|
+
langConversationHelp: 'エージェントが返信や議論に使う言語です。未設定の場合、最初の使用時に一度だけ尋ねて記憶されます。',
|
|
986
|
+
langCommentsLabel: 'コードコメント言語',
|
|
987
|
+
langCommentsHelp: 'エージェントがコードコメントを書く言語です。',
|
|
988
|
+
langDocsLabel: 'ドキュメント言語',
|
|
989
|
+
langDocsHelp: 'エージェントがドキュメントを書く言語です。',
|
|
990
|
+
followConversation: '会話言語に従う',
|
|
991
|
+
notSetAsk: '未設定(初回使用時に尋ねる)',
|
|
992
|
+
customLanguage: 'カスタム…',
|
|
993
|
+
customLanguagePlaceholder: '言語名または BCP タグ',
|
|
994
|
+
customLanguageRequired: 'カスタム言語を入力してください(1–48 文字)。',
|
|
995
|
+
currentValue: '現在:{value}',
|
|
996
|
+
currentValueUnset: '現在:未設定',
|
|
997
|
+
suggestedValue: '推奨:{value}',
|
|
998
|
+
save: '保存',
|
|
999
|
+
saving: '保存中…',
|
|
1000
|
+
discard: '変更を破棄',
|
|
1001
|
+
saveFailed: 'このデプロイメントはこれらの値を受け付けませんでした。修正できるよう残してあります。',
|
|
1002
|
+
saveConflict: '設定が別の場所で変更されました。下書きを破棄してもう一度お試しください。',
|
|
1003
|
+
formLoading: '設定を読み込み中…',
|
|
1004
|
+
formUnavailable: 'このプラグインは現在ロードされていないため、設定できません。',
|
|
1005
|
+
formReadOnly: 'このデプロイメントの設定は読み取り専用です。',
|
|
1006
|
+
dispatchSectionTitle: 'ディスパッチプールとモデル順位',
|
|
1007
|
+
dispatchSectionDescription: 'タスクの複雑さに応じてモデルを 6 つのディスパッチプールに分け、能力順位を管理します。dsh-switchman の委譲にのみ影響します。',
|
|
1008
|
+
dispatchProgress: '{pools}/6 プール設定 · {ranked} 件ランク済み · モード {mode}',
|
|
1009
|
+
poolEconomyTitle: '軽量 · economy',
|
|
1010
|
+
poolEconomyDesc: '小口のバッチと低複雑度タスク',
|
|
1011
|
+
poolMechanicalTitle: '機械的 · mechanical',
|
|
1012
|
+
poolMechanicalDesc: '機械的な書き換えとテンプレート操作',
|
|
1013
|
+
poolMainTitle: '主力 · main',
|
|
1014
|
+
poolMainDesc: '日常的なコーディングと定常タスク',
|
|
1015
|
+
poolHardTitle: '高難度 · hard',
|
|
1016
|
+
poolHardDesc: '難しい推論と大規模リファクタリング',
|
|
1017
|
+
poolVisionTitle: 'マルチモーダル · vision',
|
|
1018
|
+
poolVisionDesc: '画像などのマルチモーダル作業',
|
|
1019
|
+
poolReviewTitle: 'レビュー · review',
|
|
1020
|
+
poolReviewDesc: '読み取り専用レビューと独立検証',
|
|
1021
|
+
poolSelectAll: 'すべて選択',
|
|
1022
|
+
poolClear: 'クリア',
|
|
1023
|
+
poolEmpty: '候補モデルなし',
|
|
1024
|
+
poolManualLabel: '手動順序',
|
|
1025
|
+
poolManualHelp: 'オンにするとリストの順序でディスパッチします(先頭=第一候補)。オフなら能力順で自動的に並びます。',
|
|
1026
|
+
poolManualSelected: '選択済み · ディスパッチ優先順',
|
|
1027
|
+
poolManualAddable: 'モデルを追加',
|
|
1028
|
+
poolMoveUp: '上へ',
|
|
1029
|
+
poolMoveDown: '下へ',
|
|
1030
|
+
poolRemoveOne: '削除',
|
|
1031
|
+
poolEffortFollow: 'レーンに従う',
|
|
1032
|
+
poolEffortLabel: '思考強度',
|
|
1033
|
+
poolEffortHelp: 'このモデルの思考強度を固定します。ディスパッチ時にレーンのデフォルトより優先されます',
|
|
1034
|
+
catalogLoading: 'モデルカタログを読み込み中…',
|
|
1035
|
+
catalogLoadFailed: 'モデルカタログを読み込めませんでした。',
|
|
1036
|
+
catalogRetry: '再試行',
|
|
1037
|
+
catalogPartial: '一部のモデルプロバイダーを読み込めませんでした。保存済みの選択は引き続き削除できます。',
|
|
1038
|
+
catalogEmpty: '現在モデルを公開しているプロバイダーはありません。',
|
|
1039
|
+
catalogUnavailableGroup: '保存済みだが現在利用不可',
|
|
1040
|
+
catalogUnavailable: '現在利用不可',
|
|
1041
|
+
unauthorizedBadge: 'DSH 設定のサブエージェント・モデル選択の許可リストに含まれていません',
|
|
1042
|
+
unauthorizedHint: '⚠ マークのモデルは DSH 設定 → サブエージェント → モデル選択 で許可されていません。エージェントが明示的に指定すると拒否されます。DSH 設定で許可するか、暗黙のディスパッチを利用してください。',
|
|
1043
|
+
rankTitle: '能力順位',
|
|
1044
|
+
rankDescription: '番号は能力順(最強が先頭)で、各項目に S/A/B/C ティアを設定できます。リストはプール選択 ∪ 保存済み順位です。編集すると表示中の順序がそのまま保存されます。',
|
|
1045
|
+
rankEmpty: '上のプールでモデルを選択すると、順位リストが自動的に表示されます。',
|
|
1046
|
+
rankTier: 'ティア',
|
|
1047
|
+
rankTierNone: '—',
|
|
1048
|
+
rankMoveUp: '上へ',
|
|
1049
|
+
rankMoveDown: '下へ',
|
|
1050
|
+
rankRemove: '順位から削除',
|
|
1051
|
+
enforceLabel: '強制モード',
|
|
1052
|
+
enforceOff: 'オフ',
|
|
1053
|
+
enforceAdvice: 'アドバイス',
|
|
1054
|
+
enforceEnforce: '強制',
|
|
1055
|
+
enforceHelpOff: '委譲にプールのガイダンスを注入しません。',
|
|
1056
|
+
enforceHelpAdvice: 'プールのガイダンスをアドバイスとして注入します。モデルは外れることができます。',
|
|
1057
|
+
enforceHelpEnforce: 'プールのガイダンスを厳格な制約として注入します。外れた場合は拒否されます。',
|
|
1058
|
+
wmSectionTitle: 'コンテキスト水位',
|
|
1059
|
+
wmSectionDescription: 'token 使用量に応じた段階的な引き締め:アドバイス、読み取り制限と締めくくり、自動ハンドオーバー。',
|
|
1060
|
+
wmSoftLabel: 'ソフト水位(soft)',
|
|
1061
|
+
wmSoftHelp: '超えるとバナーが表示され、委譲やコンテキスト整理が推奨されます。',
|
|
1062
|
+
wmHardLabel: 'ハード水位(hard)',
|
|
1063
|
+
wmHardHelp: '超えると読み取り予算が引き締められ、仕事の締めくくりが推奨されます。',
|
|
1064
|
+
wmForceLabel: '強制水位(force)',
|
|
1065
|
+
wmForceHelp: '超えるとバックアップと圧縮へのハンドオーバーが推奨されます(自動化可能)。',
|
|
1066
|
+
wmReadBudgetLabel: '読み取り予算',
|
|
1067
|
+
wmReadBudgetHelp: '1 回の読み取りあたりの token 予算です。各ラウンドの上限はその 2 倍です。',
|
|
1068
|
+
wmNumberInvalid: '{min} 以上の整数を入力してください。',
|
|
1069
|
+
wmOrderInvalid: '3 段階の水位は厳密に昇順にしてください:soft < hard < force。',
|
|
1070
|
+
wmDenyModeLabel: 'ハード段階の動作',
|
|
1071
|
+
wmDenyModeCap: '制限して警告',
|
|
1072
|
+
wmDenyModeDeny: '即時拒否',
|
|
1073
|
+
wmDenyModeHelpCap: '予算超過の呼び出しは通しますが、警告を記録します。',
|
|
1074
|
+
wmDenyModeHelpDeny: '予算超過の呼び出しは即座に拒否します。',
|
|
1075
|
+
wmAutoHandoverLabel: '自動ハンドオーバー',
|
|
1076
|
+
wmAutoHandoverHelp: '強制水位に達したら、確認なしでバックアップして圧縮へハンドオーバーします。',
|
|
1077
|
+
wmSubagentTitle: 'サブエージェント',
|
|
1078
|
+
wmSubagentCapLabel: 'サブエージェントのコンテキスト上限',
|
|
1079
|
+
wmSubagentCapHelp: 'オンにすると、下の専用強制しきい値を使えます。オフなら上の 3 段階の水位に完全に従います。',
|
|
1080
|
+
wmSubagentForceLabel: 'サブエージェント強制しきい値',
|
|
1081
|
+
wmSubagentForceHelp: 'サブエージェントの force 段階のみを上書きします(soft/hard はメインセッションと共通)。0 なら上の強制水位に従います。',
|
|
1082
|
+
wmSubagentFollowForce: 'force 段階に従う(0)',
|
|
1083
|
+
wmCommands: 'コマンド:/ctx-pause で水位アクションを一時停止 · /ctx-resume で再開 · /ctx-handover で今すぐバックアップしてハンドオーバー。',
|
|
1084
|
+
teamsSectionTitle: 'エージェントチーム',
|
|
1085
|
+
teamsSectionDescription: 'ディスパッチ形態の切り替え:オフは通常の subagent ディスパッチ(DSH 出荷時の保守的なチームポリシーが引き継ぎ)。オンにすると自律チーム規律を注入し、Agent Teams を有効にします。',
|
|
1086
|
+
teamsModeLabel: 'エージェントチームモード',
|
|
1087
|
+
teamsModeHelp: 'オンにするとチーム規律(デフォルト委譲 + 段階的検証 + タスクボードの規律)を注入し、DSH の Agent Teams バンドルを有効にします。ディスパッチプールの ⚠ 許可バッジはこのモードでのみ表示されます。',
|
|
1088
|
+
syncWhitelistLabel: 'サブエージェントモデル許可リストの同期',
|
|
1089
|
+
syncWhitelistHelp: '独立したスイッチです(エージェントチームモード不要):6 プールで選択されたモデルの和集合を、DSH の「設定 → サブエージェント → モデル選択」許可リストにまるごと書き込みます。dsh-switchman が唯一の事実源になります。',
|
|
1090
|
+
whitelistSyncOk: '{count} 件を同期しました({time})。',
|
|
1091
|
+
whitelistSyncError: '同期に失敗しました:{error}',
|
|
1092
|
+
whitelistSyncPending: '同期待ち…',
|
|
1093
|
+
whitelistSyncNote: '許可リストの変更は、以降に新しく作成されたセッションにのみ反映されます。',
|
|
1094
|
+
uiSectionTitle: 'インターフェース',
|
|
1095
|
+
uiSectionDescription: 'このプラグイン自身の UI(バッジ、パネル、この設定ページ)の表示言語です。',
|
|
1096
|
+
uiLocaleLabel: 'インターフェース言語',
|
|
1097
|
+
uiLocaleHelp: '「自動」は DeepSeek Harness アプリの言語に従います。言語を選ぶと、このプラグインの UI がその言語に固定されます。',
|
|
1098
|
+
uiLocaleAuto: '自動(DSH に従う)',
|
|
1099
|
+
},
|
|
1100
|
+
ko: {
|
|
1101
|
+
badge: '자율 팀',
|
|
1102
|
+
badgeTip: 'dsh-switchman: 네 가지 내장 프리셋(standard / ptc / minimal / cordis)에 자율 에이전트 팀 디스패치 규율이 주입되어 있습니다',
|
|
1103
|
+
handoverActive: '핸드오버 진행 중',
|
|
1104
|
+
handoverPhaseBackup: '세션 백업 중',
|
|
1105
|
+
handoverPhaseCompacting: '컨텍스트 압축 중',
|
|
1106
|
+
handoverPhaseContinuation: '후속 세션 깨우는 중',
|
|
1107
|
+
handoverActiveTip: 'Switchman이 백그라운드에서 핸드오버 중입니다: 세션을 fork해 백업하고 컨텍스트를 압축하며, 완료되면 작업이 자동으로 이어집니다. 이 동안 세션이 잠시 멈추는 것은 정상입니다.',
|
|
1108
|
+
visionHintNeedsPool: '이 모델은 이미지를 읽을 수 없습니다: dsh-switchman 설정에서 멀티모달 풀 모델을 추가한 뒤, 이미지를 /vision으로 보내 주세요.',
|
|
1109
|
+
visionHintUseVision: '이 모델은 이미지를 읽을 수 없습니다: 이미지는 /vision으로 보내 주세요(자동으로 멀티모달 풀로 라우팅됩니다).',
|
|
1110
|
+
visionAutoConverted: '이미지 직접 전송이 거부되었습니다: 자동으로 /vision으로 다시 보냅니다(멀티모달 풀이 읽습니다).',
|
|
1111
|
+
settingsTitle: 'dsh-switchman',
|
|
1112
|
+
panelLabel: 'Switchman 디스패치 센터',
|
|
1113
|
+
settingsDescription: 'dsh-switchman 기본 설정을 구성합니다.',
|
|
1114
|
+
langSectionTitle: '언어',
|
|
1115
|
+
langSectionDescription: '에이전트 응답, 코드 주석, 작성 문서의 언어를 제어합니다.',
|
|
1116
|
+
langScopeLabel: '언어 범위',
|
|
1117
|
+
langScopeHelp: '이 언어 기본 설정의 저장 위치입니다.',
|
|
1118
|
+
langScopeGlobal: '전역(이 프로필)',
|
|
1119
|
+
langScopeProject: '프로젝트별(.switchman/lang.json)',
|
|
1120
|
+
langProjectNote: '프로젝트 모드: 각 프로젝트는 자신의 .switchman/lang.json을 읽습니다. 최초 응답 내용이 그 파일에 저장되며, 파일이 생길 때까지 매 세션마다 묻습니다. 아래 세 항목은 전역 모드에서만 적용됩니다.',
|
|
1121
|
+
langConversationLabel: '대화 언어',
|
|
1122
|
+
langConversationHelp: '에이전트가 응답과 토론에 사용하는 언어입니다. 설정하지 않으면 처음 사용할 때 한 번만 묻고 기억합니다.',
|
|
1123
|
+
langCommentsLabel: '코드 주석 언어',
|
|
1124
|
+
langCommentsHelp: '에이전트가 코드 주석을 작성하는 언어입니다.',
|
|
1125
|
+
langDocsLabel: '문서 언어',
|
|
1126
|
+
langDocsHelp: '에이전트가 문서를 작성하는 언어입니다.',
|
|
1127
|
+
followConversation: '대화 언어 따르기',
|
|
1128
|
+
notSetAsk: '미설정(처음 사용 시 묻기)',
|
|
1129
|
+
customLanguage: '사용자 지정…',
|
|
1130
|
+
customLanguagePlaceholder: '언어 이름 또는 BCP 태그',
|
|
1131
|
+
customLanguageRequired: '사용자 지정 언어를 입력하세요(1–48자).',
|
|
1132
|
+
currentValue: '현재: {value}',
|
|
1133
|
+
currentValueUnset: '현재: 미설정',
|
|
1134
|
+
suggestedValue: '추천: {value}',
|
|
1135
|
+
save: '저장',
|
|
1136
|
+
saving: '저장 중…',
|
|
1137
|
+
discard: '변경 취소',
|
|
1138
|
+
saveFailed: '이 배포에서 해당 값을 수락하지 않아, 수정할 수 있도록 남겨 두었습니다.',
|
|
1139
|
+
saveConflict: '다른 곳에서 설정이 변경되었습니다. 초안을 버리고 다시 시도하세요.',
|
|
1140
|
+
formLoading: '설정 불러오는 중…',
|
|
1141
|
+
formUnavailable: '이 플러그인이 로드되어 있지 않아 지금은 설정할 수 없습니다.',
|
|
1142
|
+
formReadOnly: '이 배포의 설정은 읽기 전용입니다.',
|
|
1143
|
+
dispatchSectionTitle: '디스패치 풀과 모델 순위',
|
|
1144
|
+
dispatchSectionDescription: '작업 복잡도에 따라 모델을 여섯 개 디스패치 풀로 묶고 능력 순위를 유지합니다. dsh-switchman 위임에만 영향을 줍니다.',
|
|
1145
|
+
dispatchProgress: '{pools}/6개 풀 설정 · {ranked}개 순위 지정 · 모드 {mode}',
|
|
1146
|
+
poolEconomyTitle: '경량 · economy',
|
|
1147
|
+
poolEconomyDesc: '가벼운 일괄 작업과 낮은 복잡도 작업',
|
|
1148
|
+
poolMechanicalTitle: '기계 · mechanical',
|
|
1149
|
+
poolMechanicalDesc: '기계적 재작성과 템플릿 작업',
|
|
1150
|
+
poolMainTitle: '주력 · main',
|
|
1151
|
+
poolMainDesc: '일상적 코딩과 매일 하는 작업',
|
|
1152
|
+
poolHardTitle: '고난도 · hard',
|
|
1153
|
+
poolHardDesc: '어려운 추론과 대규모 리팩터링',
|
|
1154
|
+
poolVisionTitle: '멀티모달 · vision',
|
|
1155
|
+
poolVisionDesc: '이미지 등 멀티모달 작업',
|
|
1156
|
+
poolReviewTitle: '리뷰 · review',
|
|
1157
|
+
poolReviewDesc: '읽기 전용 리뷰와 독립 검증',
|
|
1158
|
+
poolSelectAll: '모두 선택',
|
|
1159
|
+
poolClear: '지우기',
|
|
1160
|
+
poolEmpty: '후보 모델 없음',
|
|
1161
|
+
poolManualLabel: '수동 순서',
|
|
1162
|
+
poolManualHelp: '켜면 목록 순서대로 디스패치합니다(맨 앞이 제1순위). 끄면 능력 순으로 자동 정렬됩니다.',
|
|
1163
|
+
poolManualSelected: '선택됨 · 디스패치 우선순위',
|
|
1164
|
+
poolManualAddable: '모델 추가',
|
|
1165
|
+
poolMoveUp: '위로',
|
|
1166
|
+
poolMoveDown: '아래로',
|
|
1167
|
+
poolRemoveOne: '제거',
|
|
1168
|
+
poolEffortFollow: '레인 따르기',
|
|
1169
|
+
poolEffortLabel: '추론 강도',
|
|
1170
|
+
poolEffortHelp: '이 모델의 추론 강도를 고정합니다. 디스패치 시 레인 기본값보다 우선합니다',
|
|
1171
|
+
catalogLoading: '모델 카탈로그 불러오는 중…',
|
|
1172
|
+
catalogLoadFailed: '모델 카탈로그를 불러올 수 없습니다.',
|
|
1173
|
+
catalogRetry: '다시 시도',
|
|
1174
|
+
catalogPartial: '일부 모델 공급자를 불러오지 못했습니다. 저장된 선택 항목은 여전히 제거할 수 있습니다.',
|
|
1175
|
+
catalogEmpty: '현재 모델을 공개하는 공급자가 없습니다.',
|
|
1176
|
+
catalogUnavailableGroup: '저장되었으나 현재 사용 불가',
|
|
1177
|
+
catalogUnavailable: '현재 사용 불가',
|
|
1178
|
+
unauthorizedBadge: 'DSH 설정의 서브에이전트 모델 선택 허용 목록에 없음',
|
|
1179
|
+
unauthorizedHint: '⚠ 표시가 붙은 모델은 DSH 설정 → 서브에이전트 → 모델 선택에서 허용되지 않았습니다. 에이전트가 명시적으로 지정하면 거부됩니다. DSH 설정에서 허용하거나, 암시적 디스패치를 이용하세요.',
|
|
1180
|
+
rankTitle: '능력 순위',
|
|
1181
|
+
rankDescription: '번호가 능력 순서입니다(가장 강한 것이 앞). 각 항목에 S/A/B/C 티어를 지정할 수 있습니다. 목록은 풀 선택 ∪ 저장된 순위이며, 편집하면 표시된 순서가 그대로 저장됩니다.',
|
|
1182
|
+
rankEmpty: '위 풀에서 모델을 선택하면 순위 목록이 자동으로 나타납니다.',
|
|
1183
|
+
rankTier: '티어',
|
|
1184
|
+
rankTierNone: '—',
|
|
1185
|
+
rankMoveUp: '위로',
|
|
1186
|
+
rankMoveDown: '아래로',
|
|
1187
|
+
rankRemove: '순위에서 제거',
|
|
1188
|
+
enforceLabel: '적용 모드',
|
|
1189
|
+
enforceOff: '끄기',
|
|
1190
|
+
enforceAdvice: '조언',
|
|
1191
|
+
enforceEnforce: '강제',
|
|
1192
|
+
enforceHelpOff: '위임에 풀 지침을 주입하지 않습니다.',
|
|
1193
|
+
enforceHelpAdvice: '풀 지침을 조언으로 주입합니다. 모델이 벗어날 수 있습니다.',
|
|
1194
|
+
enforceHelpEnforce: '풀 지침을 엄격한 제약으로 주입합니다. 벗어나면 거부됩니다.',
|
|
1195
|
+
wmSectionTitle: '컨텍스트 수위',
|
|
1196
|
+
wmSectionDescription: '토큰 사용량에 따른 단계별 강화: 조언, 읽기 제한과 마무리, 자동 핸드오버.',
|
|
1197
|
+
wmSoftLabel: '소프트 수위(soft)',
|
|
1198
|
+
wmSoftHelp: '넘으면 배너가 나타나고 위임이나 컨텍스트 정리를 권장합니다.',
|
|
1199
|
+
wmHardLabel: '하드 수위(hard)',
|
|
1200
|
+
wmHardHelp: '넘으면 읽기 예산이 줄어들고 작업 마무리를 권장합니다.',
|
|
1201
|
+
wmForceLabel: '강제 수위(force)',
|
|
1202
|
+
wmForceHelp: '넘으면 백업 후 압축으로 핸드오버를 권장합니다(자동화 가능).',
|
|
1203
|
+
wmReadBudgetLabel: '읽기 예산',
|
|
1204
|
+
wmReadBudgetHelp: '한 번 읽기당 토큰 예산입니다. 매 라운드 상한은 그 두 배입니다.',
|
|
1205
|
+
wmNumberInvalid: '{min} 이상의 정수를 입력하세요.',
|
|
1206
|
+
wmOrderInvalid: '세 수위는 엄격히 증가해야 합니다: soft < hard < force.',
|
|
1207
|
+
wmDenyModeLabel: '하드 단계 동작',
|
|
1208
|
+
wmDenyModeCap: '제한하고 경고',
|
|
1209
|
+
wmDenyModeDeny: '즉시 거부',
|
|
1210
|
+
wmDenyModeHelpCap: '예산 초과 호출은 통과시키지만 경고를 기록합니다.',
|
|
1211
|
+
wmDenyModeHelpDeny: '예산 초과 호출은 즉시 거부합니다.',
|
|
1212
|
+
wmAutoHandoverLabel: '자동 핸드오버',
|
|
1213
|
+
wmAutoHandoverHelp: '강제 수위에 도달하면 확인 없이 백업하고 압축으로 핸드오버합니다.',
|
|
1214
|
+
wmSubagentTitle: '서브에이전트',
|
|
1215
|
+
wmSubagentCapLabel: '서브에이전트 컨텍스트 상한',
|
|
1216
|
+
wmSubagentCapHelp: '켜면 서브에이전트가 아래 전용 강제 임계값을 사용합니다. 끄면 위 세 수위를 그대로 따릅니다.',
|
|
1217
|
+
wmSubagentForceLabel: '서브에이전트 강제 임계값',
|
|
1218
|
+
wmSubagentForceHelp: '서브에이전트의 force 단계만 덮어씁니다(soft/hard는 메인 세션과 공유). 0이면 위 강제 수위를 따릅니다.',
|
|
1219
|
+
wmSubagentFollowForce: 'force 단계 따르기(0)',
|
|
1220
|
+
wmCommands: '명령: /ctx-pause 수위 개입 일시 중지 · /ctx-resume 재개 · /ctx-handover 지금 백업하고 핸드오버.',
|
|
1221
|
+
teamsSectionTitle: '에이전트 팀',
|
|
1222
|
+
teamsSectionDescription: '디스패치 형태 전환: 끄면 일반 subagent 디스패치입니다(DSH 출고 기본 보수적 팀 정책이 이어받음). 켜면 자율 팀 규율을 주입하고 Agent Teams를 활성화합니다.',
|
|
1223
|
+
teamsModeLabel: '에이전트 팀 모드',
|
|
1224
|
+
teamsModeHelp: '켜면 팀 규율(기본 위임 + 단계별 검증 + 작업판 규율)을 주입하고 DSH의 Agent Teams 번들을 활성화합니다. 디스패치 풀의 ⚠ 허용 배지는 이 모드에서만 표시됩니다.',
|
|
1225
|
+
syncWhitelistLabel: '서브에이전트 모델 허용 목록 동기화',
|
|
1226
|
+
syncWhitelistHelp: '독립 스위치입니다(에이전트 팀 모드 불필요): 여섯 풀에서 선택한 모델의 합집합을 DSH 설정 → 서브에이전트 → 모델 선택 허용 목록에 통째로 씁니다. dsh-switchman이 유일한 사실 원천이 됩니다.',
|
|
1227
|
+
whitelistSyncOk: '{count}건 동기화됨({time}).',
|
|
1228
|
+
whitelistSyncError: '동기화 실패: {error}',
|
|
1229
|
+
whitelistSyncPending: '동기화 대기 중…',
|
|
1230
|
+
whitelistSyncNote: '허용 목록 변경은 이후 새로 만든 세션에만 적용됩니다.',
|
|
1231
|
+
uiSectionTitle: '인터페이스',
|
|
1232
|
+
uiSectionDescription: '이 플러그인 자체 UI(배지, 패널, 이 설정 페이지)의 표시 언어입니다.',
|
|
1233
|
+
uiLocaleLabel: '인터페이스 언어',
|
|
1234
|
+
uiLocaleHelp: '자동은 DeepSeek Harness 앱 언어를 따르고, 언어를 직접 고르면 이 플러그인의 UI가 그 언어로 고정됩니다.',
|
|
1235
|
+
uiLocaleAuto: '자동(DSH 따르기)',
|
|
1236
|
+
},
|
|
1237
|
+
de: {
|
|
1238
|
+
badge: 'Autonomes Team',
|
|
1239
|
+
badgeTip: 'dsh-switchman: Die vier integrierten Presets (standard / ptc / minimal / cordis) tragen die autonome-Agent-Teams-Doktrin',
|
|
1240
|
+
handoverActive: 'Übergabe läuft',
|
|
1241
|
+
handoverPhaseBackup: 'Backup wird erstellt',
|
|
1242
|
+
handoverPhaseCompacting: 'Kontext wird komprimiert',
|
|
1243
|
+
handoverPhaseContinuation: 'Fortsetzung wird geweckt',
|
|
1244
|
+
handoverActiveTip: 'Switchman übergibt gerade im Hintergrund: Eine Backup-Session wird geforkt und der Kontext komprimiert; die Aufgabe läuft danach automatisch weiter. Eine ruhende Session ist in dieser Phase normal.',
|
|
1245
|
+
visionHintNeedsPool: 'Dieses Modell kann keine Bilder lesen: Fügen Sie in den dsh-switchman-Einstellungen Modelle zum Vision-Pool hinzu und senden Sie Bilder dann mit /vision.',
|
|
1246
|
+
visionHintUseVision: 'Dieses Modell kann keine Bilder lesen: Senden Sie Bilder mit /vision (automatisch an den Vision-Pool geleitet).',
|
|
1247
|
+
visionAutoConverted: 'Direkter Bildversand wurde abgelehnt: Er wird automatisch über /vision erneut gesendet (vom Vision-Pool gelesen).',
|
|
1248
|
+
settingsTitle: 'dsh-switchman',
|
|
1249
|
+
panelLabel: 'Switchman',
|
|
1250
|
+
settingsDescription: 'dsh-switchman-Einstellungen konfigurieren.',
|
|
1251
|
+
langSectionTitle: 'Sprache',
|
|
1252
|
+
langSectionDescription: 'Steuert die Sprache von Agent-Antworten, Code-Kommentaren und erstellten Dokumenten.',
|
|
1253
|
+
langScopeLabel: 'Sprach-Geltungsbereich',
|
|
1254
|
+
langScopeHelp: 'Wo diese Spracheinstellungen gespeichert werden.',
|
|
1255
|
+
langScopeGlobal: 'Global (dieses Profil)',
|
|
1256
|
+
langScopeProject: 'Pro Projekt (.switchman/lang.json)',
|
|
1257
|
+
langProjectNote: 'Projektmodus: Jedes Projekt liest seine eigene .switchman/lang.json; Antworten bei der Erstanwendung werden dort gespeichert, und Sessions fragen nach, bis die Datei existiert. Die drei Felder unten gelten nur im globalen Modus.',
|
|
1258
|
+
langConversationLabel: 'Konversationssprache',
|
|
1259
|
+
langConversationHelp: 'Die Sprache, in der Agenten antworten und diskutieren; ohne Festlegung werden Sie bei der ersten Nutzung einmalig gefragt, und die Auswahl wird gemerkt.',
|
|
1260
|
+
langCommentsLabel: 'Sprache für Code-Kommentare',
|
|
1261
|
+
langCommentsHelp: 'Die Sprache, in der Agenten Code-Kommentare schreiben.',
|
|
1262
|
+
langDocsLabel: 'Dokumentsprache',
|
|
1263
|
+
langDocsHelp: 'Die Sprache, in der Agenten Dokumente verfassen.',
|
|
1264
|
+
followConversation: 'Konversationssprache folgen',
|
|
1265
|
+
notSetAsk: 'Nicht gesetzt (bei Erstanwendung fragen)',
|
|
1266
|
+
customLanguage: 'Benutzerdefiniert…',
|
|
1267
|
+
customLanguagePlaceholder: 'Sprachname oder BCP-Tag',
|
|
1268
|
+
customLanguageRequired: 'Geben Sie eine eigene Sprache ein (1–48 Zeichen).',
|
|
1269
|
+
currentValue: 'Aktuell: {value}',
|
|
1270
|
+
currentValueUnset: 'Aktuell: nicht gesetzt',
|
|
1271
|
+
suggestedValue: 'Vorschlag: {value}',
|
|
1272
|
+
save: 'Speichern',
|
|
1273
|
+
saving: 'Speichern…',
|
|
1274
|
+
discard: 'Änderungen verwerfen',
|
|
1275
|
+
saveFailed: 'Diese Werte wurden von der Bereitstellung nicht akzeptiert; sie bleiben zur Korrektur erhalten.',
|
|
1276
|
+
saveConflict: 'Einstellungen wurden andernorts geändert. Verwerfen Sie Ihren Entwurf und versuchen Sie es erneut.',
|
|
1277
|
+
formLoading: 'Einstellungen werden geladen…',
|
|
1278
|
+
formUnavailable: 'Dieses Plugin ist nicht geladen und kann daher gerade nicht konfiguriert werden.',
|
|
1279
|
+
formReadOnly: 'Diese Bereitstellung speichert Einstellungen schreibgeschützt.',
|
|
1280
|
+
dispatchSectionTitle: 'Dispatch-Pools und Modell-Ranking',
|
|
1281
|
+
dispatchSectionDescription: 'Gruppiert Modelle nach Aufgabenkomplexität in sechs Dispatch-Pools und pflegt ein Fähigkeits-Ranking; betrifft nur die Delegation von dsh-switchman.',
|
|
1282
|
+
dispatchProgress: '{pools}/6 Pools gesetzt · {ranked} im Ranking · Modus {mode}',
|
|
1283
|
+
poolEconomyTitle: 'Leicht · economy',
|
|
1284
|
+
poolEconomyDesc: 'Leichte Massen- und geringkomplexe Aufgaben',
|
|
1285
|
+
poolMechanicalTitle: 'Mechanisch · mechanical',
|
|
1286
|
+
poolMechanicalDesc: 'Mechanische Umschreibungen und Vorlagen-Operationen',
|
|
1287
|
+
poolMainTitle: 'Standard · main',
|
|
1288
|
+
poolMainDesc: 'Routiniertes Codieren und Alltagsaufgaben',
|
|
1289
|
+
poolHardTitle: 'Schwer · hard',
|
|
1290
|
+
poolHardDesc: 'Schweres Reasoning und große Refactorings',
|
|
1291
|
+
poolVisionTitle: 'Multimodal · vision',
|
|
1292
|
+
poolVisionDesc: 'Multimodale (Bild-)Arbeit',
|
|
1293
|
+
poolReviewTitle: 'Review · review',
|
|
1294
|
+
poolReviewDesc: 'Nur-Lese-Review und unabhängige Prüfung',
|
|
1295
|
+
poolSelectAll: 'Alle auswählen',
|
|
1296
|
+
poolClear: 'Leeren',
|
|
1297
|
+
poolEmpty: 'Keine Kandidatenmodelle',
|
|
1298
|
+
poolManualLabel: 'Manuelle Reihenfolge',
|
|
1299
|
+
poolManualHelp: 'Ein: Der Versand folgt der gelisteten Reihenfolge (oben = erste Wahl); aus: Lanes werden automatisch nach Fähigkeit sortiert.',
|
|
1300
|
+
poolManualSelected: 'Ausgewählt · Dispatch-Priorität',
|
|
1301
|
+
poolManualAddable: 'Modelle hinzufügen',
|
|
1302
|
+
poolMoveUp: 'Nach oben',
|
|
1303
|
+
poolMoveDown: 'Nach unten',
|
|
1304
|
+
poolRemoveOne: 'Entfernen',
|
|
1305
|
+
poolEffortFollow: 'Lane folgen',
|
|
1306
|
+
poolEffortLabel: 'Aufwand',
|
|
1307
|
+
poolEffortHelp: 'Fixiert den Reasoning-Aufwand dieses Modells; überschreibt beim Dispatch den Lane-Standard',
|
|
1308
|
+
catalogLoading: 'Modellkatalog wird geladen…',
|
|
1309
|
+
catalogLoadFailed: 'Der Modellkatalog konnte nicht geladen werden.',
|
|
1310
|
+
catalogRetry: 'Erneut versuchen',
|
|
1311
|
+
catalogPartial: 'Einige Modell-Provider konnten nicht geladen werden; gespeicherte Auswahl bleibt entfernbar.',
|
|
1312
|
+
catalogEmpty: 'Aktuell bewirbt kein Modell-Provider ein Modell.',
|
|
1313
|
+
catalogUnavailableGroup: 'Gespeichert, aber derzeit nicht verfügbar',
|
|
1314
|
+
catalogUnavailable: 'derzeit nicht verfügbar',
|
|
1315
|
+
unauthorizedBadge: 'für expliziten Subagent-Dispatch in DSH-Einstellungen (Subagents: Modellauswahl) nicht autorisiert',
|
|
1316
|
+
unauthorizedHint: 'Mit ⚠ markierte Modelle sind in DSH-Einstellungen → Subagents → Modellauswahl nicht autorisiert; Agenten, die sie explizit nennen, werden abgelehnt — autorisieren Sie sie in den DSH-Einstellungen oder lassen Sie Agenten implizit delegieren.',
|
|
1317
|
+
rankTitle: 'Fähigkeits-Ranking',
|
|
1318
|
+
rankDescription: 'Nummeriert, stärkstes zuerst; jeder Eintrag kann ein S/A/B/C-Tier verankern. Die Liste ist Pool-Auswahl ∪ gespeichertes Ranking; jede Änderung speichert die angezeigte Reihenfolge.',
|
|
1319
|
+
rankEmpty: 'Wählen Sie oben Modelle in den Pools; die Ranking-Liste erscheint automatisch.',
|
|
1320
|
+
rankTier: 'Tier',
|
|
1321
|
+
rankTierNone: '—',
|
|
1322
|
+
rankMoveUp: 'Nach oben',
|
|
1323
|
+
rankMoveDown: 'Nach unten',
|
|
1324
|
+
rankRemove: 'Aus dem Ranking entfernen',
|
|
1325
|
+
enforceLabel: 'Durchsetzung',
|
|
1326
|
+
enforceOff: 'Aus',
|
|
1327
|
+
enforceAdvice: 'Empfehlung',
|
|
1328
|
+
enforceEnforce: 'Erzwungen',
|
|
1329
|
+
enforceHelpOff: 'Es wird keine Pool-Leitlinie in Delegationen eingespeist.',
|
|
1330
|
+
enforceHelpAdvice: 'Pool-Leitlinien werden als Empfehlung eingespeist; Modelle dürfen abweichen.',
|
|
1331
|
+
enforceHelpEnforce: 'Pool-Leitlinien werden als harte Einschränkung eingespeist; Abweichungen werden abgelehnt.',
|
|
1332
|
+
wmSectionTitle: 'Kontext-Wasserstand',
|
|
1333
|
+
wmSectionDescription: 'Abgestuftes Verhalten nach Token-Nutzung: Empfehlung, gedeckelte Lesevorgänge und Abschluss, automatische Übergabe.',
|
|
1334
|
+
wmSoftLabel: 'Weicher Wasserstand (soft)',
|
|
1335
|
+
wmSoftHelp: 'Danach erscheint ein Banner, und Delegieren bzw. Kontext aufräumen wird empfohlen.',
|
|
1336
|
+
wmHardLabel: 'Harter Wasserstand (hard)',
|
|
1337
|
+
wmHardHelp: 'Danach strafft sich das Lese-Budget, und ein Abschluss wird empfohlen.',
|
|
1338
|
+
wmForceLabel: 'Erzwungener Wasserstand (force)',
|
|
1339
|
+
wmForceHelp: 'Danach Backup erstellen und an die Komprimierung übergeben (automatisch möglich).',
|
|
1340
|
+
wmReadBudgetLabel: 'Lese-Budget',
|
|
1341
|
+
wmReadBudgetHelp: 'Token-Budget pro Lesevorgang; jede Runde ist auf das Doppelte gedeckelt.',
|
|
1342
|
+
wmNumberInvalid: 'Geben Sie eine ganze Zahl von mindestens {min} ein.',
|
|
1343
|
+
wmOrderInvalid: 'Die drei Stufen müssen strikt aufsteigen: soft < hard < force.',
|
|
1344
|
+
wmDenyModeLabel: 'Verhalten der Hard-Stufe',
|
|
1345
|
+
wmDenyModeCap: 'Deckeln und warnen',
|
|
1346
|
+
wmDenyModeDeny: 'Direkt ablehnen',
|
|
1347
|
+
wmDenyModeHelpCap: 'Über-Budget-Aufrufe laufen durch, aber eine Warnung wird protokolliert.',
|
|
1348
|
+
wmDenyModeHelpDeny: 'Über-Budget-Aufrufe werden direkt abgelehnt.',
|
|
1349
|
+
wmAutoHandoverLabel: 'Automatische Übergabe',
|
|
1350
|
+
wmAutoHandoverHelp: 'Beim erzwungenen Wasserstand automatisch sichern und an die Komprimierung übergeben.',
|
|
1351
|
+
wmSubagentTitle: 'Subagents',
|
|
1352
|
+
wmSubagentCapLabel: 'Kontext-Deckel für Subagents',
|
|
1353
|
+
wmSubagentCapHelp: 'Subagents dürfen die eigene erzwungene Schwelle unten nutzen; aus = vollständig den drei Stufen oben folgen.',
|
|
1354
|
+
wmSubagentForceLabel: 'Erzwungene Schwelle für Subagents',
|
|
1355
|
+
wmSubagentForceHelp: 'Überschreibt nur die Force-Stufe der Subagents (soft/hard teilen sich mit der Haupt-Session); 0 folgt dem erzwungenen Wasserstand oben.',
|
|
1356
|
+
wmSubagentFollowForce: 'Der Force-Stufe folgen (0)',
|
|
1357
|
+
wmCommands: 'Befehle: /ctx-pause pausiert Wasserstand-Aktionen · /ctx-resume setzt sie fort · /ctx-handover sichert jetzt und übergibt sofort.',
|
|
1358
|
+
teamsSectionTitle: 'Agent-Teams',
|
|
1359
|
+
teamsSectionDescription: 'Wechselt die Dispatch-Form: Aus ist gewöhnlicher Subagent-Versand (die konservative Werks-Teamrichtlinie von DSH greift); an speist die autonome Team-Doktrin ein und aktiviert Agent Teams.',
|
|
1360
|
+
teamsModeLabel: 'Agent-Teams-Modus',
|
|
1361
|
+
teamsModeHelp: 'Ein: Die Team-Doktrin (standardmäßig delegieren + abgestufte Prüfung + Task-Board-Disziplin) wird eingespeist und das DSH-Agent-Teams-Bundle aktiviert; die ⚠-Autorisierungs-Badges der Dispatch-Pools erscheinen nur in diesem Modus.',
|
|
1362
|
+
syncWhitelistLabel: 'Modell-Whitelist der Subagents synchronisieren',
|
|
1363
|
+
syncWhitelistHelp: 'Unabhängiger Schalter (kein Agent-Teams-Modus nötig): schreibt die Vereinigung der sechs Pools in die Autorisierungsliste von DSH „Einstellungen → Subagents → Modellauswahl“; dsh-switchman wird zur einzigen Quelle der Wahrheit.',
|
|
1364
|
+
whitelistSyncOk: '{count} Einträge synchronisiert ({time}).',
|
|
1365
|
+
whitelistSyncError: 'Synchronisierung fehlgeschlagen: {error}',
|
|
1366
|
+
whitelistSyncPending: 'Warte auf Synchronisierung…',
|
|
1367
|
+
whitelistSyncNote: 'Whitelist-Änderungen wirken sich nur auf später erstellte Sessions aus.',
|
|
1368
|
+
uiSectionTitle: 'Oberfläche',
|
|
1369
|
+
uiSectionDescription: 'Anzeigesprache der eigenen Oberfläche dieses Plugins (Badge, Panel, diese Einstellungsseite).',
|
|
1370
|
+
uiLocaleLabel: 'Sprache der Oberfläche',
|
|
1371
|
+
uiLocaleHelp: 'Auto folgt der App-Sprache von DeepSeek Harness; wählt man eine Sprache, wird die Oberfläche dieses Plugins darauf festgelegt.',
|
|
1372
|
+
uiLocaleAuto: 'Auto (DSH folgen)',
|
|
1373
|
+
},
|
|
1374
|
+
es: {
|
|
1375
|
+
badge: 'Equipo autónomo',
|
|
1376
|
+
badgeTip: 'dsh-switchman: los cuatro preajustes integrados (standard / ptc / minimal / cordis) incorporan la doctrina de equipos de agentes autónomos',
|
|
1377
|
+
handoverActive: 'Traspaso en curso',
|
|
1378
|
+
handoverPhaseBackup: 'creando copia de seguridad',
|
|
1379
|
+
handoverPhaseCompacting: 'compactando contexto',
|
|
1380
|
+
handoverPhaseContinuation: 'despertando continuación',
|
|
1381
|
+
handoverActiveTip: 'Switchman está realizando el traspaso en segundo plano: crea un fork de la sesión de respaldo y compacta el contexto; la tarea continúa automáticamente al terminar. Es normal que la sesión quede quieta durante este intervalo.',
|
|
1382
|
+
visionHintNeedsPool: 'Este modelo no puede leer imágenes: añade modelos del grupo de visión en los ajustes de dsh-switchman y envía las imágenes con /vision.',
|
|
1383
|
+
visionHintUseVision: 'Este modelo no puede leer imágenes: envíalas con /vision (se enrutan automáticamente al grupo de visión).',
|
|
1384
|
+
visionAutoConverted: 'El envío directo de la imagen fue rechazado: se reenvía automáticamente vía /vision (lo lee el grupo de visión).',
|
|
1385
|
+
settingsTitle: 'dsh-switchman',
|
|
1386
|
+
panelLabel: 'Switchman',
|
|
1387
|
+
settingsDescription: 'Configura las preferencias de dsh-switchman.',
|
|
1388
|
+
langSectionTitle: 'Idioma',
|
|
1389
|
+
langSectionDescription: 'Controla el idioma de las respuestas de los agentes, los comentarios de código y los documentos redactados.',
|
|
1390
|
+
langScopeLabel: 'Ámbito del idioma',
|
|
1391
|
+
langScopeHelp: 'Dónde se guardan estas preferencias de idioma.',
|
|
1392
|
+
langScopeGlobal: 'Global (este perfil)',
|
|
1393
|
+
langScopeProject: 'Por proyecto (.switchman/lang.json)',
|
|
1394
|
+
langProjectNote: 'Modo por proyecto: cada proyecto lee su propio .switchman/lang.json; la respuesta del primer uso se guarda allí, y las sesiones preguntan hasta que exista. Los tres campos de abajo solo se aplican en modo global.',
|
|
1395
|
+
langConversationLabel: 'Idioma de conversación',
|
|
1396
|
+
langConversationHelp: 'El idioma en que los agentes responden y debaten; si no se fija, se te pregunta una vez en el primer uso y la elección se recuerda.',
|
|
1397
|
+
langCommentsLabel: 'Idioma de los comentarios',
|
|
1398
|
+
langCommentsHelp: 'El idioma en que los agentes escriben los comentarios de código.',
|
|
1399
|
+
langDocsLabel: 'Idioma de los documentos',
|
|
1400
|
+
langDocsHelp: 'El idioma en que los agentes redactan documentos.',
|
|
1401
|
+
followConversation: 'Seguir el idioma de la conversación',
|
|
1402
|
+
notSetAsk: 'Sin fijar (preguntar en el primer uso)',
|
|
1403
|
+
customLanguage: 'Personalizado…',
|
|
1404
|
+
customLanguagePlaceholder: 'Nombre de idioma o etiqueta BCP',
|
|
1405
|
+
customLanguageRequired: 'Introduce un idioma personalizado (1–48 caracteres).',
|
|
1406
|
+
currentValue: 'Actual: {value}',
|
|
1407
|
+
currentValueUnset: 'Actual: sin fijar',
|
|
1408
|
+
suggestedValue: 'Sugerido: {value}',
|
|
1409
|
+
save: 'Guardar',
|
|
1410
|
+
saving: 'Guardando…',
|
|
1411
|
+
discard: 'Descartar cambios',
|
|
1412
|
+
saveFailed: 'El despliegue no aceptó estos valores; se dejaron para que los corrijas.',
|
|
1413
|
+
saveConflict: 'Los ajustes cambiaron en otro lugar. Descarta tu borrador e inténtalo de nuevo.',
|
|
1414
|
+
formLoading: 'Cargando ajustes…',
|
|
1415
|
+
formUnavailable: 'Este plugin no está cargado, así que no puede configurarse ahora mismo.',
|
|
1416
|
+
formReadOnly: 'Este despliegue guarda los ajustes en modo de solo lectura.',
|
|
1417
|
+
dispatchSectionTitle: 'Grupos de despacho y ranking de modelos',
|
|
1418
|
+
dispatchSectionDescription: 'Agrupa modelos en seis grupos de despacho según la complejidad de la tarea y mantiene un ranking de capacidad; solo afecta a la delegación de dsh-switchman.',
|
|
1419
|
+
dispatchProgress: '{pools}/6 grupos definidos · {ranked} clasificados · modo {mode}',
|
|
1420
|
+
poolEconomyTitle: 'Económico · economy',
|
|
1421
|
+
poolEconomyDesc: 'Tareas por lotes ligeras y de baja complejidad',
|
|
1422
|
+
poolMechanicalTitle: 'Mecánico · mechanical',
|
|
1423
|
+
poolMechanicalDesc: 'Reescrituras mecánicas y operaciones con plantillas',
|
|
1424
|
+
poolMainTitle: 'Principal · main',
|
|
1425
|
+
poolMainDesc: 'Programación rutinaria y tareas cotidianas',
|
|
1426
|
+
poolHardTitle: 'Difícil · hard',
|
|
1427
|
+
poolHardDesc: 'Razonamiento difícil y refactorizaciones a gran escala',
|
|
1428
|
+
poolVisionTitle: 'Visión · vision',
|
|
1429
|
+
poolVisionDesc: 'Trabajo multimodal (imágenes)',
|
|
1430
|
+
poolReviewTitle: 'Revisión · review',
|
|
1431
|
+
poolReviewDesc: 'Revisión de solo lectura y verificación independiente',
|
|
1432
|
+
poolSelectAll: 'Seleccionar todo',
|
|
1433
|
+
poolClear: 'Limpiar',
|
|
1434
|
+
poolEmpty: 'No hay modelos candidatos',
|
|
1435
|
+
poolManualLabel: 'Orden manual',
|
|
1436
|
+
poolManualHelp: 'Activado, el despacho sigue el orden de la lista (el primero es la primera opción); desactivado, los carriles se ordenan automáticamente por capacidad.',
|
|
1437
|
+
poolManualSelected: 'Seleccionados · prioridad de despacho',
|
|
1438
|
+
poolManualAddable: 'Añadir modelos',
|
|
1439
|
+
poolMoveUp: 'Subir',
|
|
1440
|
+
poolMoveDown: 'Bajar',
|
|
1441
|
+
poolRemoveOne: 'Quitar',
|
|
1442
|
+
poolEffortFollow: 'seguir carril',
|
|
1443
|
+
poolEffortLabel: 'esfuerzo',
|
|
1444
|
+
poolEffortHelp: 'Fija el esfuerzo de razonamiento de este modelo; prevalece sobre el valor del carril al despachar',
|
|
1445
|
+
catalogLoading: 'Cargando el catálogo de modelos…',
|
|
1446
|
+
catalogLoadFailed: 'No se pudo cargar el catálogo de modelos.',
|
|
1447
|
+
catalogRetry: 'Reintentar',
|
|
1448
|
+
catalogPartial: 'Algunos proveedores de modelos no se pudieron cargar; las elecciones guardadas siguen pudiendo quitarse.',
|
|
1449
|
+
catalogEmpty: 'Ningún proveedor de modelos ofrece modelos actualmente.',
|
|
1450
|
+
catalogUnavailableGroup: 'Guardados pero no disponibles ahora',
|
|
1451
|
+
catalogUnavailable: 'no disponible actualmente',
|
|
1452
|
+
unauthorizedBadge: 'sin autorización para despacho explícito de subagentes en Ajustes de DSH (subagentes: selección de modelos)',
|
|
1453
|
+
unauthorizedHint: 'Los modelos marcados con ⚠ no están autorizados en Ajustes de DSH → Subagentes → selección de modelos; los agentes que los nombren explícitamente serán rechazados — autorízalos en los Ajustes de DSH o deja que los agentes despachen de forma implícita.',
|
|
1454
|
+
rankTitle: 'Ranking de capacidad',
|
|
1455
|
+
rankDescription: 'Numerados del más fuerte al primero; cada entrada puede anclar un nivel S/A/B/C. La lista es la selección de grupos ∪ el ranking guardado; cualquier edición persiste el orden mostrado.',
|
|
1456
|
+
rankEmpty: 'Selecciona modelos en los grupos de arriba; la lista del ranking aparecerá automáticamente.',
|
|
1457
|
+
rankTier: 'Nivel',
|
|
1458
|
+
rankTierNone: '—',
|
|
1459
|
+
rankMoveUp: 'Subir',
|
|
1460
|
+
rankMoveDown: 'Bajar',
|
|
1461
|
+
rankRemove: 'Quitar del ranking',
|
|
1462
|
+
enforceLabel: 'Aplicación',
|
|
1463
|
+
enforceOff: 'Desactivado',
|
|
1464
|
+
enforceAdvice: 'Consejo',
|
|
1465
|
+
enforceEnforce: 'Obligatorio',
|
|
1466
|
+
enforceHelpOff: 'No se inyecta ninguna guía de grupos en las delegaciones.',
|
|
1467
|
+
enforceHelpAdvice: 'La guía de grupos se inyecta como consejo; los modelos pueden desviarse.',
|
|
1468
|
+
enforceHelpEnforce: 'La guía de grupos se inyecta como restricción estricta; las desviaciones se rechazan.',
|
|
1469
|
+
wmSectionTitle: 'Nivel de contexto',
|
|
1470
|
+
wmSectionDescription: 'Comportamiento por niveles según el uso de tokens: consejos, lecturas limitadas y cierre, traspaso automático.',
|
|
1471
|
+
wmSoftLabel: 'Nivel suave (soft)',
|
|
1472
|
+
wmSoftHelp: 'Al superarlo aparece un aviso y se recomienda delegar o ordenar el contexto.',
|
|
1473
|
+
wmHardLabel: 'Nivel duro (hard)',
|
|
1474
|
+
wmHardHelp: 'Al superarlo se ajusta el presupuesto de lectura y se recomienda cerrar el trabajo.',
|
|
1475
|
+
wmForceLabel: 'Nivel forzado (force)',
|
|
1476
|
+
wmForceHelp: 'Al superarlo, haz copia de seguridad y traspasa a la compactación (puede ser automático).',
|
|
1477
|
+
wmReadBudgetLabel: 'Presupuesto de lectura',
|
|
1478
|
+
wmReadBudgetHelp: 'Presupuesto de tokens por lectura; cada ronda se limita al doble.',
|
|
1479
|
+
wmNumberInvalid: 'Introduce un número entero de {min} o más.',
|
|
1480
|
+
wmOrderInvalid: 'Los tres niveles deben ascender estrictamente: soft < hard < force.',
|
|
1481
|
+
wmDenyModeLabel: 'Comportamiento del nivel duro',
|
|
1482
|
+
wmDenyModeCap: 'Limitar y avisar',
|
|
1483
|
+
wmDenyModeDeny: 'Rechazar directamente',
|
|
1484
|
+
wmDenyModeHelpCap: 'Las llamadas sobre el presupuesto pasan, pero se registra un aviso.',
|
|
1485
|
+
wmDenyModeHelpDeny: 'Las llamadas sobre el presupuesto se rechazan directamente.',
|
|
1486
|
+
wmAutoHandoverLabel: 'Traspaso automático',
|
|
1487
|
+
wmAutoHandoverHelp: 'En el nivel forzado, hace copia de seguridad y traspasa a la compactación automáticamente.',
|
|
1488
|
+
wmSubagentTitle: 'Subagentes',
|
|
1489
|
+
wmSubagentCapLabel: 'Tope de contexto de subagentes',
|
|
1490
|
+
wmSubagentCapHelp: 'Permite que los subagentes usen el umbral forzado propio de abajo; desactivado = seguir por completo los tres niveles de arriba.',
|
|
1491
|
+
wmSubagentForceLabel: 'Umbral forzado de subagentes',
|
|
1492
|
+
wmSubagentForceHelp: 'Solo sobrescribe el nivel forzado de los subagentes (soft/hard se comparten con la sesión principal); 0 sigue el nivel forzado de arriba.',
|
|
1493
|
+
wmSubagentFollowForce: 'Seguir el nivel forzado (0)',
|
|
1494
|
+
wmCommands: 'Comandos: /ctx-pause suspende las acciones del nivel · /ctx-resume las reanuda · /ctx-handover hace copia y traspasa ahora.',
|
|
1495
|
+
teamsSectionTitle: 'Equipos de agentes',
|
|
1496
|
+
teamsSectionDescription: 'Cambia la forma de despacho: desactivado es despacho simple de subagentes (aplica la política conservadora de fábrica de DSH); activado inyecta la doctrina de equipo autónomo y habilita Agent Teams.',
|
|
1497
|
+
teamsModeLabel: 'Modo de equipos de agentes',
|
|
1498
|
+
teamsModeHelp: 'Activado, se inyecta la doctrina de equipo (delegar por defecto + verificación por niveles + disciplina del tablero de tareas) y se habilita el paquete Agent Teams de DSH; las insignias ⚠ de autorización de los grupos de despacho solo se muestran en este modo.',
|
|
1499
|
+
syncWhitelistLabel: 'Sincronizar la lista blanca de modelos de subagentes',
|
|
1500
|
+
syncWhitelistHelp: 'Interruptor independiente (no requiere el modo de equipos): escribe la unión de los seis grupos en la lista de autorización de «Ajustes de DSH → Subagentes → selección de modelos»; dsh-switchman pasa a ser la única fuente de verdad.',
|
|
1501
|
+
whitelistSyncOk: '{count} entradas sincronizadas ({time}).',
|
|
1502
|
+
whitelistSyncError: 'Error de sincronización: {error}',
|
|
1503
|
+
whitelistSyncPending: 'Esperando la sincronización…',
|
|
1504
|
+
whitelistSyncNote: 'Los cambios de la lista blanca solo afectan a las sesiones creadas después.',
|
|
1505
|
+
uiSectionTitle: 'Interfaz',
|
|
1506
|
+
uiSectionDescription: 'Idioma de la interfaz propia de este plugin (insignia, panel, esta página de ajustes).',
|
|
1507
|
+
uiLocaleLabel: 'Idioma de la interfaz',
|
|
1508
|
+
uiLocaleHelp: 'Automático sigue el idioma de la app DeepSeek Harness; al elegir un idioma, la interfaz del plugin se fija en él.',
|
|
1509
|
+
uiLocaleAuto: 'Automático (seguir DSH)',
|
|
1510
|
+
},
|
|
1511
|
+
fr: {
|
|
1512
|
+
badge: 'Équipe autonome',
|
|
1513
|
+
badgeTip: 'dsh-switchman : les quatre préréglages intégrés (standard / ptc / minimal / cordis) embarquent la doctrine d’équipe autonome des Agent Teams',
|
|
1514
|
+
handoverActive: 'Remise en cours',
|
|
1515
|
+
handoverPhaseBackup: 'sauvegarde de la session',
|
|
1516
|
+
handoverPhaseCompacting: 'compactage du contexte',
|
|
1517
|
+
handoverPhaseContinuation: 'réveil de la continuation',
|
|
1518
|
+
handoverActiveTip: 'Switchman effectue la remise en arrière-plan : fork d’une session de sauvegarde et compactage du contexte ; la tâche se poursuit automatiquement une fois terminée. Une session immobile pendant cette fenêtre est normale.',
|
|
1519
|
+
visionHintNeedsPool: 'Ce modèle ne sait pas lire les images : ajoutez des modèles au pool multimodal dans les réglages dsh-switchman, puis envoyez les images avec /vision.',
|
|
1520
|
+
visionHintUseVision: 'Ce modèle ne sait pas lire les images : envoyez-les avec /vision (routage automatique vers le pool multimodal).',
|
|
1521
|
+
visionAutoConverted: 'Envoi d’image refusé : renvoi automatique via /vision (lecture par le pool multimodal).',
|
|
1522
|
+
settingsTitle: 'dsh-switchman',
|
|
1523
|
+
panelLabel: 'Switchman',
|
|
1524
|
+
settingsDescription: 'Configurez les préférences de dsh-switchman.',
|
|
1525
|
+
langSectionTitle: 'Langue',
|
|
1526
|
+
langSectionDescription: 'Détermine la langue des réponses des agents, des commentaires de code et des documents rédigés.',
|
|
1527
|
+
langScopeLabel: 'Portée de la langue',
|
|
1528
|
+
langScopeHelp: 'Là où ces préférences de langue sont conservées.',
|
|
1529
|
+
langScopeGlobal: 'Global (ce profil)',
|
|
1530
|
+
langScopeProject: 'Par projet (.switchman/lang.json)',
|
|
1531
|
+
langProjectNote: 'Mode par projet : chaque projet lit son propre .switchman/lang.json ; les réponses données au premier usage y sont enregistrées, et les sessions posent la question tant qu’il n’existe pas. Les trois champs ci-dessous ne s’appliquent qu’en mode global.',
|
|
1532
|
+
langConversationLabel: 'Langue des conversations',
|
|
1533
|
+
langConversationHelp: 'La langue dans laquelle les agents répondent et discutent ; si elle n’est pas réglée, on vous la demande une fois au premier usage et le choix est retenu.',
|
|
1534
|
+
langCommentsLabel: 'Langue des commentaires de code',
|
|
1535
|
+
langCommentsHelp: 'La langue dans laquelle les agents écrivent les commentaires de code.',
|
|
1536
|
+
langDocsLabel: 'Langue des documents',
|
|
1537
|
+
langDocsHelp: 'La langue dans laquelle les agents rédigent les documents.',
|
|
1538
|
+
followConversation: 'Suivre la langue de la conversation',
|
|
1539
|
+
notSetAsk: 'Non réglée (demander au premier usage)',
|
|
1540
|
+
customLanguage: 'Personnalisée…',
|
|
1541
|
+
customLanguagePlaceholder: 'Nom de langue ou étiquette BCP',
|
|
1542
|
+
customLanguageRequired: 'Saisissez une langue personnalisée (1–48 caractères).',
|
|
1543
|
+
currentValue: 'Actuel : {value}',
|
|
1544
|
+
currentValueUnset: 'Actuel : non réglé',
|
|
1545
|
+
suggestedValue: 'Suggéré : {value}',
|
|
1546
|
+
save: 'Enregistrer',
|
|
1547
|
+
saving: 'Enregistrement…',
|
|
1548
|
+
discard: 'Annuler les modifications',
|
|
1549
|
+
saveFailed: 'Le déploiement n’a pas accepté ces valeurs ; elles ont été laissées à corriger.',
|
|
1550
|
+
saveConflict: 'Les réglages ont changé ailleurs. Abandonnez votre brouillon et réessayez.',
|
|
1551
|
+
formLoading: 'Chargement des réglages…',
|
|
1552
|
+
formUnavailable: 'Ce plugin n’est pas chargé : impossible de le configurer pour le moment.',
|
|
1553
|
+
formReadOnly: 'Ce déploiement stocke les réglages en lecture seule.',
|
|
1554
|
+
dispatchSectionTitle: 'Pools de dispatch et classement des modèles',
|
|
1555
|
+
dispatchSectionDescription: 'Répartit les modèles en six pools de dispatch selon la complexité des tâches et maintient un classement de capacité ; n’affecte que la délégation dsh-switchman.',
|
|
1556
|
+
dispatchProgress: '{pools}/6 pools réglés · {ranked} classés · mode {mode}',
|
|
1557
|
+
poolEconomyTitle: 'Économie',
|
|
1558
|
+
poolEconomyDesc: 'Tâches légères en série et de faible complexité',
|
|
1559
|
+
poolMechanicalTitle: 'Mécanique',
|
|
1560
|
+
poolMechanicalDesc: 'Réécritures mécaniques et opérations sur gabarit',
|
|
1561
|
+
poolMainTitle: 'Principal',
|
|
1562
|
+
poolMainDesc: 'Code au quotidien et tâches courantes',
|
|
1563
|
+
poolHardTitle: 'Difficile',
|
|
1564
|
+
poolHardDesc: 'Raisonnement corsé et refontes à grande échelle',
|
|
1565
|
+
poolVisionTitle: 'Vision',
|
|
1566
|
+
poolVisionDesc: 'Travail multimodal (images)',
|
|
1567
|
+
poolReviewTitle: 'Relecture',
|
|
1568
|
+
poolReviewDesc: 'Relecture en lecture seule et vérification indépendante',
|
|
1569
|
+
poolSelectAll: 'Tout cocher',
|
|
1570
|
+
poolClear: 'Effacer',
|
|
1571
|
+
poolEmpty: 'Aucun modèle candidat',
|
|
1572
|
+
poolManualLabel: 'Ordre manuel',
|
|
1573
|
+
poolManualHelp: 'Activé, le dispatch suit l’ordre affiché (la tête = premier choix) ; désactivé, les couloirs sont ordonnés par capacité automatiquement.',
|
|
1574
|
+
poolManualSelected: 'Sélectionnés · priorité de dispatch',
|
|
1575
|
+
poolManualAddable: 'Ajouter des modèles',
|
|
1576
|
+
poolMoveUp: 'Monter',
|
|
1577
|
+
poolMoveDown: 'Descendre',
|
|
1578
|
+
poolRemoveOne: 'Retirer',
|
|
1579
|
+
poolEffortFollow: 'suivre le couloir',
|
|
1580
|
+
poolEffortLabel: 'effort',
|
|
1581
|
+
poolEffortHelp: 'Épingle l’effort de raisonnement de ce modèle ; il prime le défaut du couloir au dispatch',
|
|
1582
|
+
catalogLoading: 'Chargement du catalogue de modèles…',
|
|
1583
|
+
catalogLoadFailed: 'Le catalogue de modèles n’a pas pu être chargé.',
|
|
1584
|
+
catalogRetry: 'Réessayer',
|
|
1585
|
+
catalogPartial: 'Certains fournisseurs de modèles n’ont pas pu être chargés ; les choix enregistrés restent retirables.',
|
|
1586
|
+
catalogEmpty: 'Aucun fournisseur de modèles n’annonce de modèle pour l’instant.',
|
|
1587
|
+
catalogUnavailableGroup: 'Enregistrés mais actuellement indisponibles',
|
|
1588
|
+
catalogUnavailable: 'actuellement indisponible',
|
|
1589
|
+
unauthorizedBadge: 'non autorisé pour le dispatch enfant explicite dans les réglages DSH (subagents : sélection de modèle)',
|
|
1590
|
+
unauthorizedHint: 'Les modèles marqués ⚠ ne sont pas autorisés dans Réglages DSH → Subagents → sélection de modèle ; les agents qui les nomment explicitement se verront refuser le dispatch — autorisez-les dans les réglages DSH, ou laissez les agents dispatcher implicitement.',
|
|
1591
|
+
rankTitle: 'Classement de capacité',
|
|
1592
|
+
rankDescription: 'Numérotés du plus fort au moins fort ; chaque entrée peut ancrer un tier S/A/B/C. La liste est sélection des pools ∪ classement enregistré ; toute modification rend l’ordre affiché persistant.',
|
|
1593
|
+
rankEmpty: 'Cochez des modèles dans les pools ci-dessus ; la liste de classement apparaît automatiquement.',
|
|
1594
|
+
rankTier: 'Tier',
|
|
1595
|
+
rankTierNone: '—',
|
|
1596
|
+
rankMoveUp: 'Monter',
|
|
1597
|
+
rankMoveDown: 'Descendre',
|
|
1598
|
+
rankRemove: 'Retirer du classement',
|
|
1599
|
+
enforceLabel: 'Exécution',
|
|
1600
|
+
enforceOff: 'Off',
|
|
1601
|
+
enforceAdvice: 'Advice',
|
|
1602
|
+
enforceEnforce: 'Enforce',
|
|
1603
|
+
enforceHelpOff: 'Aucune recommandation de pool n’est injectée dans la délégation.',
|
|
1604
|
+
enforceHelpAdvice: 'Les recommandations de pool sont injectées à titre de conseil (advice) ; les modèles peuvent s’en écarter.',
|
|
1605
|
+
enforceHelpEnforce: 'Les recommandations de pool sont injectées comme contrainte stricte ; tout écart est refusé.',
|
|
1606
|
+
wmSectionTitle: 'Niveau d’eau du contexte',
|
|
1607
|
+
wmSectionDescription: 'Comportement par paliers selon l’usage des tokens : conseil, lectures plafonnées et phase de clôture, remise automatique.',
|
|
1608
|
+
wmSoftLabel: 'Ligne d’eau soft',
|
|
1609
|
+
wmSoftHelp: 'Au-delà, une bannière apparaît et il est conseillé de déléguer ou de ranger le contexte.',
|
|
1610
|
+
wmHardLabel: 'Ligne d’eau hard',
|
|
1611
|
+
wmHardHelp: 'Au-delà, le budget de lecture se resserre et il est conseillé de conclure.',
|
|
1612
|
+
wmForceLabel: 'Ligne d’eau force',
|
|
1613
|
+
wmForceHelp: 'Au-delà, sauvegardez et remettez à la compaction (peut être automatique).',
|
|
1614
|
+
wmReadBudgetLabel: 'Budget de lecture',
|
|
1615
|
+
wmReadBudgetHelp: 'Budget de tokens par lecture ; chaque tour plafonne au double.',
|
|
1616
|
+
wmNumberInvalid: 'Saisissez un nombre entier d’au moins {min}.',
|
|
1617
|
+
wmOrderInvalid: 'Les trois paliers doivent strictement monter : soft < hard < force.',
|
|
1618
|
+
wmDenyModeLabel: 'Comportement au palier hard',
|
|
1619
|
+
wmDenyModeCap: 'Plafonner et avertir',
|
|
1620
|
+
wmDenyModeDeny: 'Refuser d’office',
|
|
1621
|
+
wmDenyModeHelpCap: 'Les appels au-delà du budget passent, mais un avertissement est consigné.',
|
|
1622
|
+
wmDenyModeHelpDeny: 'Les appels au-delà du budget sont refusés d’office.',
|
|
1623
|
+
wmAutoHandoverLabel: 'Remise automatique',
|
|
1624
|
+
wmAutoHandoverHelp: 'À la ligne d’eau force, sauvegarde et remise automatiques à la compaction.',
|
|
1625
|
+
wmSubagentTitle: 'Subagents',
|
|
1626
|
+
wmSubagentCapLabel: 'Plafond de contexte des subagents',
|
|
1627
|
+
wmSubagentCapHelp: 'Laisse les subagents utiliser le seuil force dédié ci-dessous ; désactivé = suivent intégralement les trois paliers ci-dessus.',
|
|
1628
|
+
wmSubagentForceLabel: 'Seuil force des subagents',
|
|
1629
|
+
wmSubagentForceHelp: 'Ne remplace que le palier force des subagents (soft/hard partagés avec la session principale) ; 0 suit la ligne d’eau force ci-dessus.',
|
|
1630
|
+
wmSubagentFollowForce: 'Suivre le palier force (0)',
|
|
1631
|
+
wmCommands: 'Commandes : /ctx-pause suspend les actions de niveau d’eau · /ctx-resume les reprend · /ctx-handover sauvegarde et remet maintenant.',
|
|
1632
|
+
teamsSectionTitle: 'Agent Teams',
|
|
1633
|
+
teamsSectionDescription: 'Change la forme du dispatch : éteint, c’est le dispatch subagent simple (la politique d’équipe prudente d’usine de DSH reprend la main) ; allumé, la doctrine d’équipe autonome est injectée et les Agent Teams sont activés.',
|
|
1634
|
+
teamsModeLabel: 'Mode Agent Teams',
|
|
1635
|
+
teamsModeHelp: 'Activé, la doctrine d’équipe (délégation par défaut + vérification par paliers + discipline du tableau de tâches) est injectée et le bundle DSH Agent Teams est activé ; les badges ⚠ d’autorisation des pools de dispatch n’apparaissent que dans ce mode.',
|
|
1636
|
+
syncWhitelistLabel: 'Synchroniser la liste blanche des modèles de subagents',
|
|
1637
|
+
syncWhitelistHelp: 'Interrupteur indépendant (ne dépend pas du mode Agent Teams) : écrit l’union des six pools dans la liste d’autorisation « Réglages DSH → Subagents → sélection de modèle » ; dsh-switchman devient l’unique source de vérité.',
|
|
1638
|
+
whitelistSyncOk: '{count} entrées synchronisées ({time}).',
|
|
1639
|
+
whitelistSyncError: 'Échec de la synchronisation : {error}',
|
|
1640
|
+
whitelistSyncPending: 'Synchronisation en attente…',
|
|
1641
|
+
whitelistSyncNote: 'Les changements de liste blanche ne s’appliquent qu’aux sessions créées ensuite.',
|
|
1642
|
+
uiSectionTitle: 'Interface',
|
|
1643
|
+
uiSectionDescription: 'Langue d’affichage de l’interface propre du plugin (badge, panneau, cette page de réglages).',
|
|
1644
|
+
uiLocaleLabel: 'Langue de l’interface',
|
|
1645
|
+
uiLocaleHelp: 'Auto suit la langue de l’application DeepSeek Harness ; choisir une langue force l’interface du plugin dans cette langue.',
|
|
1646
|
+
uiLocaleAuto: 'Auto (suivre DSH)',
|
|
1647
|
+
},
|
|
1648
|
+
it: {
|
|
1649
|
+
badge: 'Squadra autonoma',
|
|
1650
|
+
badgeTip: 'dsh-switchman: i quattro preset integrati (standard / ptc / minimal / cordis) portano con sé la dottrina di squadra autonoma degli Agent Teams',
|
|
1651
|
+
handoverActive: 'Handover in corso',
|
|
1652
|
+
handoverPhaseBackup: 'backup della sessione',
|
|
1653
|
+
handoverPhaseCompacting: 'compattazione del contesto',
|
|
1654
|
+
handoverPhaseContinuation: 'risveglio della continuazione',
|
|
1655
|
+
handoverActiveTip: 'Switchman sta facendo l’handover in background: fork di una sessione di backup e compattazione del contesto; finito quello, il task prosegue da solo. Una sessione ferma in questa finestra è normale.',
|
|
1656
|
+
visionHintNeedsPool: 'Questo modello non sa leggere le immagini: aggiungi modelli al pool multimodale nelle impostazioni di dsh-switchman, poi invia le immagini con /vision.',
|
|
1657
|
+
visionHintUseVision: 'Questo modello non sa leggere le immagini: inviale con /vision (instradate automaticamente al pool multimodale).',
|
|
1658
|
+
visionAutoConverted: 'Invio dell’immagine rifiutato: reinvio automatico via /vision (lettura dal pool multimodale).',
|
|
1659
|
+
settingsTitle: 'dsh-switchman',
|
|
1660
|
+
panelLabel: 'Switchman',
|
|
1661
|
+
settingsDescription: 'Configura le preferenze di dsh-switchman.',
|
|
1662
|
+
langSectionTitle: 'Lingua',
|
|
1663
|
+
langSectionDescription: 'Controlla la lingua delle risposte degli agent, dei commenti al codice e dei documenti prodotti.',
|
|
1664
|
+
langScopeLabel: 'Ambito della lingua',
|
|
1665
|
+
langScopeHelp: 'Dove vengono conservate queste preferenze linguistiche.',
|
|
1666
|
+
langScopeGlobal: 'Globale (questo profilo)',
|
|
1667
|
+
langScopeProject: 'Per progetto (.switchman/lang.json)',
|
|
1668
|
+
langProjectNote: 'Modalità per progetto: ogni progetto legge il proprio .switchman/lang.json; le risposte date al primo uso vengono salvate lì, e le sessioni continuano a chiedere finché il file non esiste. I tre campi sottostanti valgono solo in modalità globale.',
|
|
1669
|
+
langConversationLabel: 'Lingua della conversazione',
|
|
1670
|
+
langConversationHelp: 'La lingua in cui gli agent rispondono e discutono; se non è impostata, viene chiesta una volta al primo uso e la scelta viene ricordata.',
|
|
1671
|
+
langCommentsLabel: 'Lingua dei commenti al codice',
|
|
1672
|
+
langCommentsHelp: 'La lingua in cui gli agent scrivono i commenti al codice.',
|
|
1673
|
+
langDocsLabel: 'Lingua dei documenti',
|
|
1674
|
+
langDocsHelp: 'La lingua in cui gli agent redigono i documenti.',
|
|
1675
|
+
followConversation: 'Segui la lingua della conversazione',
|
|
1676
|
+
notSetAsk: 'Non impostata (chiedi al primo uso)',
|
|
1677
|
+
customLanguage: 'Personalizzata…',
|
|
1678
|
+
customLanguagePlaceholder: 'Nome della lingua o tag BCP',
|
|
1679
|
+
customLanguageRequired: 'Inserisci una lingua personalizzata (1–48 caratteri).',
|
|
1680
|
+
currentValue: 'Attuale: {value}',
|
|
1681
|
+
currentValueUnset: 'Attuale: non impostata',
|
|
1682
|
+
suggestedValue: 'Suggerita: {value}',
|
|
1683
|
+
save: 'Salva',
|
|
1684
|
+
saving: 'Salvataggio…',
|
|
1685
|
+
discard: 'Annulla le modifiche',
|
|
1686
|
+
saveFailed: 'Il deployment non ha accettato questi valori; sono stati lasciati a te da correggere.',
|
|
1687
|
+
saveConflict: 'Le impostazioni sono cambiate altrove. Scarta la bozza e riprova.',
|
|
1688
|
+
formLoading: 'Caricamento delle impostazioni…',
|
|
1689
|
+
formUnavailable: 'Questo plugin non è caricato, quindi non è configurabile al momento.',
|
|
1690
|
+
formReadOnly: 'Questo deployment salva le impostazioni in sola lettura.',
|
|
1691
|
+
dispatchSectionTitle: 'Pool di dispatch e classifica dei modelli',
|
|
1692
|
+
dispatchSectionDescription: 'Raggruppa i modelli in sei pool di dispatch per complessità del task e mantiene una classifica di capacità; incide solo sulla delega di dsh-switchman.',
|
|
1693
|
+
dispatchProgress: '{pools}/6 pool impostati · {ranked} classificati · modalità {mode}',
|
|
1694
|
+
poolEconomyTitle: 'Economia',
|
|
1695
|
+
poolEconomyDesc: 'Lavori piccoli in serie e a bassa complessità',
|
|
1696
|
+
poolMechanicalTitle: 'Meccanico',
|
|
1697
|
+
poolMechanicalDesc: 'Riscritture meccaniche e operazioni su schema',
|
|
1698
|
+
poolMainTitle: 'Principale',
|
|
1699
|
+
poolMainDesc: 'Coding di tutti i giorni e attività quotidiane',
|
|
1700
|
+
poolHardTitle: 'Difficile',
|
|
1701
|
+
poolHardDesc: 'Ragionamento complesso e refactoring su larga scala',
|
|
1702
|
+
poolVisionTitle: 'Visione',
|
|
1703
|
+
poolVisionDesc: 'Lavoro multimodale (immagini)',
|
|
1704
|
+
poolReviewTitle: 'Revisione',
|
|
1705
|
+
poolReviewDesc: 'Revisione in sola lettura e verifica indipendente',
|
|
1706
|
+
poolSelectAll: 'Seleziona tutto',
|
|
1707
|
+
poolClear: 'Azzera',
|
|
1708
|
+
poolEmpty: 'Nessun modello candidato',
|
|
1709
|
+
poolManualLabel: 'Ordine manuale',
|
|
1710
|
+
poolManualHelp: 'Attivo, il dispatch segue l’ordine elencato (il primo della lista = prima scelta); spento, le corsie vengono ordinate per capacità automaticamente.',
|
|
1711
|
+
poolManualSelected: 'Selezionati · priorità di dispatch',
|
|
1712
|
+
poolManualAddable: 'Aggiungi modelli',
|
|
1713
|
+
poolMoveUp: 'Sposta su',
|
|
1714
|
+
poolMoveDown: 'Sposta giù',
|
|
1715
|
+
poolRemoveOne: 'Rimuovi',
|
|
1716
|
+
poolEffortFollow: 'segui la corsia',
|
|
1717
|
+
poolEffortLabel: 'effort',
|
|
1718
|
+
poolEffortHelp: 'Fissa il reasoning effort di questo modello; prevale sul default della corsia in fase di dispatch',
|
|
1719
|
+
catalogLoading: 'Caricamento del catalogo modelli…',
|
|
1720
|
+
catalogLoadFailed: 'Impossibile caricare il catalogo dei modelli.',
|
|
1721
|
+
catalogRetry: 'Riprova',
|
|
1722
|
+
catalogPartial: 'Alcuni provider di modelli non sono stati caricati; le scelte salvate restano rimovibili.',
|
|
1723
|
+
catalogEmpty: 'Nessun provider di modelli al momento propone un modello.',
|
|
1724
|
+
catalogUnavailableGroup: 'Salvati ma al momento non disponibili',
|
|
1725
|
+
catalogUnavailable: 'al momento non disponibile',
|
|
1726
|
+
unauthorizedBadge: 'non autorizzato per il dispatch esplicito dei figli nelle impostazioni DSH (subagent: selezione modelli)',
|
|
1727
|
+
unauthorizedHint: 'I modelli contrassegnati ⚠ non sono autorizzati in Impostazioni DSH → Subagent → selezione modelli; gli agent che li nominano esplicitamente vengono negati — autorizzali nelle impostazioni DSH, oppure lascia dispatch implicito agli agent.',
|
|
1728
|
+
rankTitle: 'Classifica di capacità',
|
|
1729
|
+
rankDescription: 'Numerati dal più forte in giù; ogni voce può ancorare una fascia S/A/B/C. L’elenco è selezioni dei pool ∪ classifica salvata; ogni modifica rende persistente l’ordine mostrato.',
|
|
1730
|
+
rankEmpty: 'Seleziona modelli nei pool sopra; la classifica compare da sola.',
|
|
1731
|
+
rankTier: 'Fascia',
|
|
1732
|
+
rankTierNone: '—',
|
|
1733
|
+
rankMoveUp: 'Sposta su',
|
|
1734
|
+
rankMoveDown: 'Sposta giù',
|
|
1735
|
+
rankRemove: 'Rimuovi dalla classifica',
|
|
1736
|
+
enforceLabel: 'Esecuzione',
|
|
1737
|
+
enforceOff: 'Off',
|
|
1738
|
+
enforceAdvice: 'Advice',
|
|
1739
|
+
enforceEnforce: 'Enforce',
|
|
1740
|
+
enforceHelpOff: 'Nessuna raccomandazione di pool viene iniettata nella delega.',
|
|
1741
|
+
enforceHelpAdvice: 'Le raccomandazioni dei pool entrano come consiglio (advice); i modelli possono discostarsene.',
|
|
1742
|
+
enforceHelpEnforce: 'Le raccomandazioni dei pool entrano come vincolo rigido; gli scostamenti vengono rifiutati.',
|
|
1743
|
+
wmSectionTitle: 'Livello dell’acqua del contesto',
|
|
1744
|
+
wmSectionDescription: 'Comportamento a soglie in base ai token usati: consiglio, letture col tetto e chiusura, handover automatico.',
|
|
1745
|
+
wmSoftLabel: 'Soglia soft',
|
|
1746
|
+
wmSoftHelp: 'Superata, compare un banner e conviene delegare o sistemare il contesto.',
|
|
1747
|
+
wmHardLabel: 'Soglia hard',
|
|
1748
|
+
wmHardHelp: 'Superata, il budget di lettura si stringe e conviene chiudere.',
|
|
1749
|
+
wmForceLabel: 'Soglia force',
|
|
1750
|
+
wmForceHelp: 'Superata, backup e handover alla compattazione (può essere automatico).',
|
|
1751
|
+
wmReadBudgetLabel: 'Budget di lettura',
|
|
1752
|
+
wmReadBudgetHelp: 'Budget di token per lettura; ogni turno arriva al massimo al doppio.',
|
|
1753
|
+
wmNumberInvalid: 'Inserisci un numero intero di almeno {min}.',
|
|
1754
|
+
wmOrderInvalid: 'Le tre soglie devono salire rigorosamente: soft < hard < force.',
|
|
1755
|
+
wmDenyModeLabel: 'Comportamento alla soglia hard',
|
|
1756
|
+
wmDenyModeCap: 'Tetto e avviso',
|
|
1757
|
+
wmDenyModeDeny: 'Rifiuto secco',
|
|
1758
|
+
wmDenyModeHelpCap: 'Le chiamate oltre budget passano, ma viene registrato un avviso.',
|
|
1759
|
+
wmDenyModeHelpDeny: 'Le chiamate oltre budget vengono rifiutate sul posto.',
|
|
1760
|
+
wmAutoHandoverLabel: 'Handover automatico',
|
|
1761
|
+
wmAutoHandoverHelp: 'Alla soglia force, backup e handover alla compattazione avvengono da soli.',
|
|
1762
|
+
wmSubagentTitle: 'Subagent',
|
|
1763
|
+
wmSubagentCapLabel: 'Tetto di contesto dei subagent',
|
|
1764
|
+
wmSubagentCapHelp: 'Lascia i subagent usare la soglia force dedicata qui sotto; spento = seguono appieno le tre soglie sopra.',
|
|
1765
|
+
wmSubagentForceLabel: 'Soglia force dei subagent',
|
|
1766
|
+
wmSubagentForceHelp: 'Sostituisce solo la soglia force dei subagent (soft/hard restano condivise con la sessione principale); 0 segue la soglia force sopra.',
|
|
1767
|
+
wmSubagentFollowForce: 'Segui la soglia force (0)',
|
|
1768
|
+
wmCommands: 'Comandi: /ctx-pause sospende le azioni da livello dell’acqua · /ctx-resume le riprende · /ctx-handover fa backup e handover subito.',
|
|
1769
|
+
teamsSectionTitle: 'Agent Teams',
|
|
1770
|
+
teamsSectionDescription: 'Cambia la forma del dispatch: spento è il semplice dispatch via subagent (subentra la politica di squadra prudente di fabbrica di DSH); acceso inietta la dottrina di squadra autonoma e abilita gli Agent Teams.',
|
|
1771
|
+
teamsModeLabel: 'Modalità Agent Teams',
|
|
1772
|
+
teamsModeHelp: 'Accesa, la dottrina di squadra (delega per default + verifica a livelli + disciplina del task board condiviso) viene iniettata e il bundle Agent Teams di DSH viene abilitato; i badge ⚠ di autorizzazione dei pool di dispatch compaiono solo in questa modalità.',
|
|
1773
|
+
syncWhitelistLabel: 'Sincronizza la whitelist dei modelli per i subagent',
|
|
1774
|
+
syncWhitelistHelp: 'Interruttore indipendente (non richiede la modalità Agent Teams): scrive l’unione dei sei pool nella lista di autorizzazione «Impostazioni DSH → Subagent → selezione modelli»; dsh-switchman diventa l’unica fonte di verità.',
|
|
1775
|
+
whitelistSyncOk: 'Sincronizzate {count} voci ({time}).',
|
|
1776
|
+
whitelistSyncError: 'Sincronizzazione fallita: {error}',
|
|
1777
|
+
whitelistSyncPending: 'In attesa di sincronizzare…',
|
|
1778
|
+
whitelistSyncNote: 'Le modifiche alla whitelist valgono solo per le sessioni create dopo.',
|
|
1779
|
+
uiSectionTitle: 'Interfaccia',
|
|
1780
|
+
uiSectionDescription: 'Lingua di visualizzazione dell’interfaccia del plugin stesso (badge, pannello, questa pagina di impostazioni).',
|
|
1781
|
+
uiLocaleLabel: 'Lingua dell’interfaccia',
|
|
1782
|
+
uiLocaleHelp: 'Auto segue la lingua dell’app DeepSeek Harness; scegliere una lingua forza l’interfaccia del plugin in quella lingua.',
|
|
1783
|
+
uiLocaleAuto: 'Auto (segui DSH)',
|
|
1784
|
+
},
|
|
1785
|
+
pt: {
|
|
1786
|
+
badge: 'Equipe autônoma',
|
|
1787
|
+
badgeTip: 'dsh-switchman: os quatro presets embutidos (standard / ptc / minimal / cordis) carregam a doutrina de equipe autônoma do Agent Teams',
|
|
1788
|
+
handoverActive: 'Handover em andamento',
|
|
1789
|
+
handoverPhaseBackup: 'backup da sessão',
|
|
1790
|
+
handoverPhaseCompacting: 'compactação do contexto',
|
|
1791
|
+
handoverPhaseContinuation: 'despertar da continuação',
|
|
1792
|
+
handoverActiveTip: 'O Switchman está fazendo o handover em segundo plano: fork de uma sessão de backup e compactação do contexto; ao terminar, a tarefa continua automaticamente. Uma sessão parada durante essa janela é esperada.',
|
|
1793
|
+
visionHintNeedsPool: 'Este modelo não sabe ler imagens: adicione modelos ao pool multimodal nas configurações do dsh-switchman e depois envie imagens com /vision.',
|
|
1794
|
+
visionHintUseVision: 'Este modelo não sabe ler imagens: envie-as com /vision (roteadas automaticamente para o pool multimodal).',
|
|
1795
|
+
visionAutoConverted: 'Envio da imagem recusado: reenvio automático via /vision (leitura pelo pool multimodal).',
|
|
1796
|
+
settingsTitle: 'dsh-switchman',
|
|
1797
|
+
panelLabel: 'Switchman',
|
|
1798
|
+
settingsDescription: 'Configure as preferências do dsh-switchman.',
|
|
1799
|
+
langSectionTitle: 'Idioma',
|
|
1800
|
+
langSectionDescription: 'Controla o idioma das respostas dos agents, dos comentários de código e dos documentos redigidos.',
|
|
1801
|
+
langScopeLabel: 'Escopo do idioma',
|
|
1802
|
+
langScopeHelp: 'Onde essas preferências de idioma ficam guardadas.',
|
|
1803
|
+
langScopeGlobal: 'Global (este perfil)',
|
|
1804
|
+
langScopeProject: 'Por projeto (.switchman/lang.json)',
|
|
1805
|
+
langProjectNote: 'Modo por projeto: cada projeto lê o próprio .switchman/lang.json; as respostas do primeiro uso são salvas lá, e as sessões perguntam até o arquivo existir. Os três campos abaixo valem apenas no modo global.',
|
|
1806
|
+
langConversationLabel: 'Idioma da conversa',
|
|
1807
|
+
langConversationHelp: 'O idioma em que os agents respondem e discutem; sem valor definido, perguntam uma vez no primeiro uso e a escolha fica guardada.',
|
|
1808
|
+
langCommentsLabel: 'Idioma dos comentários de código',
|
|
1809
|
+
langCommentsHelp: 'O idioma em que os agents escrevem comentários de código.',
|
|
1810
|
+
langDocsLabel: 'Idioma dos documentos',
|
|
1811
|
+
langDocsHelp: 'O idioma em que os agents redigem documentos.',
|
|
1812
|
+
followConversation: 'Seguir o idioma da conversa',
|
|
1813
|
+
notSetAsk: 'Não definido (perguntar no primeiro uso)',
|
|
1814
|
+
customLanguage: 'Personalizado…',
|
|
1815
|
+
customLanguagePlaceholder: 'Nome de idioma ou tag BCP',
|
|
1816
|
+
customLanguageRequired: 'Informe um idioma personalizado (1–48 caracteres).',
|
|
1817
|
+
currentValue: 'Atual: {value}',
|
|
1818
|
+
currentValueUnset: 'Atual: não definido',
|
|
1819
|
+
suggestedValue: 'Sugerido: {value}',
|
|
1820
|
+
save: 'Salvar',
|
|
1821
|
+
saving: 'Salvando…',
|
|
1822
|
+
discard: 'Descartar alterações',
|
|
1823
|
+
saveFailed: 'O deployment não aceitou estes valores; eles ficaram para você corrigir.',
|
|
1824
|
+
saveConflict: 'As configurações mudaram em outro lugar. Descarte o rascunho e tente de novo.',
|
|
1825
|
+
formLoading: 'Carregando configurações…',
|
|
1826
|
+
formUnavailable: 'Este plugin não está carregado, então não pode ser configurado agora.',
|
|
1827
|
+
formReadOnly: 'Este deployment guarda as configurações em modo somente leitura.',
|
|
1828
|
+
dispatchSectionTitle: 'Pools de despacho e ranking de modelos',
|
|
1829
|
+
dispatchSectionDescription: 'Agrupa os modelos em seis pools de despacho por complexidade da tarefa e mantém um ranking de capacidade; afeta apenas o despacho do dsh-switchman.',
|
|
1830
|
+
dispatchProgress: '{pools}/6 pools definidos · {ranked} no ranking · modo {mode}',
|
|
1831
|
+
poolEconomyTitle: 'Economia',
|
|
1832
|
+
poolEconomyDesc: 'Tarefas leves em lote e de baixa complexidade',
|
|
1833
|
+
poolMechanicalTitle: 'Mecânico',
|
|
1834
|
+
poolMechanicalDesc: 'Reescritas mecânicas e operações de molde',
|
|
1835
|
+
poolMainTitle: 'Principal',
|
|
1836
|
+
poolMainDesc: 'Codificação do dia a dia e tarefas correntes',
|
|
1837
|
+
poolHardTitle: 'Difícil',
|
|
1838
|
+
poolHardDesc: 'Raciocínio pesado e refatoração em grande escala',
|
|
1839
|
+
poolVisionTitle: 'Visão',
|
|
1840
|
+
poolVisionDesc: 'Trabalho multimodal (imagens)',
|
|
1841
|
+
poolReviewTitle: 'Revisão',
|
|
1842
|
+
poolReviewDesc: 'Revisão somente leitura e verificação independente',
|
|
1843
|
+
poolSelectAll: 'Marcar todos',
|
|
1844
|
+
poolClear: 'Limpar',
|
|
1845
|
+
poolEmpty: 'Nenhum modelo candidato',
|
|
1846
|
+
poolManualLabel: 'Ordem manual',
|
|
1847
|
+
poolManualHelp: 'Ligado, o despacho segue a ordem listada (o primeiro = primeira escolha); desligado, as faixas são ordenadas por capacidade automaticamente.',
|
|
1848
|
+
poolManualSelected: 'Selecionados · prioridade de despacho',
|
|
1849
|
+
poolManualAddable: 'Adicionar modelos',
|
|
1850
|
+
poolMoveUp: 'Mover para cima',
|
|
1851
|
+
poolMoveDown: 'Mover para baixo',
|
|
1852
|
+
poolRemoveOne: 'Remover',
|
|
1853
|
+
poolEffortFollow: 'seguir a faixa',
|
|
1854
|
+
poolEffortLabel: 'effort',
|
|
1855
|
+
poolEffortHelp: 'Fixa o reasoning effort deste modelo; sobrepõe o padrão da faixa no despacho',
|
|
1856
|
+
catalogLoading: 'Carregando o catálogo de modelos…',
|
|
1857
|
+
catalogLoadFailed: 'Não foi possível carregar o catálogo de modelos.',
|
|
1858
|
+
catalogRetry: 'Tentar de novo',
|
|
1859
|
+
catalogPartial: 'Alguns provedores de modelos não foram carregados; as escolhas salvas continuam removíveis.',
|
|
1860
|
+
catalogEmpty: 'Nenhum provedor de modelos anuncia um modelo no momento.',
|
|
1861
|
+
catalogUnavailableGroup: 'Salvos, mas indisponíveis no momento',
|
|
1862
|
+
catalogUnavailable: 'indisponível no momento',
|
|
1863
|
+
unauthorizedBadge: 'não autorizado para despacho explícito de filhos nas configurações do DSH (subagents: seleção de modelos)',
|
|
1864
|
+
unauthorizedHint: 'Modelos marcados com ⚠ não estão autorizados em Configurações do DSH → Subagents → seleção de modelos; agents que os nomearem explicitamente serão negados — autorize-os nas configurações do DSH, ou deixe os agents despachar implicitamente.',
|
|
1865
|
+
rankTitle: 'Ranking de capacidade',
|
|
1866
|
+
rankDescription: 'Numerados do mais forte para baixo; cada entrada pode ancorar um nível S/A/B/C. A lista é seleção dos pools ∪ ranking salvo; qualquer edição persiste a ordem exibida.',
|
|
1867
|
+
rankEmpty: 'Marque modelos nos pools acima; o ranking aparece sozinho.',
|
|
1868
|
+
rankTier: 'Nível',
|
|
1869
|
+
rankTierNone: '—',
|
|
1870
|
+
rankMoveUp: 'Mover para cima',
|
|
1871
|
+
rankMoveDown: 'Mover para baixo',
|
|
1872
|
+
rankRemove: 'Remover do ranking',
|
|
1873
|
+
enforceLabel: 'Execução',
|
|
1874
|
+
enforceOff: 'Off',
|
|
1875
|
+
enforceAdvice: 'Advice',
|
|
1876
|
+
enforceEnforce: 'Enforce',
|
|
1877
|
+
enforceHelpOff: 'Nenhuma orientação de pool é injetada no despacho.',
|
|
1878
|
+
enforceHelpAdvice: 'A orientação dos pools entra como conselho (advice); os modelos podem desviar.',
|
|
1879
|
+
enforceHelpEnforce: 'A orientação dos pools entra como restrição rígida; desvios são recusados.',
|
|
1880
|
+
wmSectionTitle: 'Nível de água do contexto',
|
|
1881
|
+
wmSectionDescription: 'Comportamento em degraus conforme o uso de tokens: conselho, leituras com teto e encerramento, handover automático.',
|
|
1882
|
+
wmSoftLabel: 'Limiar soft',
|
|
1883
|
+
wmSoftHelp: 'Além dele, aparece um banner e delegar ou arrumar o contexto é recomendado.',
|
|
1884
|
+
wmHardLabel: 'Limiar hard',
|
|
1885
|
+
wmHardHelp: 'Além dele, o orçamento de leitura aperta e convém encerrar.',
|
|
1886
|
+
wmForceLabel: 'Limiar force',
|
|
1887
|
+
wmForceHelp: 'Além dele, backup e handover para a compactação (pode ser automático).',
|
|
1888
|
+
wmReadBudgetLabel: 'Orçamento de leitura',
|
|
1889
|
+
wmReadBudgetHelp: 'Orçamento de tokens por leitura; cada turno se limita ao dobro disso.',
|
|
1890
|
+
wmNumberInvalid: 'Informe um número inteiro de {min} ou mais.',
|
|
1891
|
+
wmOrderInvalid: 'Os três limiares devem subir estritamente: soft < hard < force.',
|
|
1892
|
+
wmDenyModeLabel: 'Comportamento no limiar hard',
|
|
1893
|
+
wmDenyModeCap: 'Limitar e avisar',
|
|
1894
|
+
wmDenyModeDeny: 'Negar na hora',
|
|
1895
|
+
wmDenyModeHelpCap: 'Chamadas acima do orçamento passam, mas um aviso é registrado.',
|
|
1896
|
+
wmDenyModeHelpDeny: 'Chamadas acima do orçamento são negadas na hora.',
|
|
1897
|
+
wmAutoHandoverLabel: 'Handover automático',
|
|
1898
|
+
wmAutoHandoverHelp: 'No limiar force, backup e handover para a compactação acontecem sozinhos.',
|
|
1899
|
+
wmSubagentTitle: 'Subagents',
|
|
1900
|
+
wmSubagentCapLabel: 'Teto de contexto dos subagents',
|
|
1901
|
+
wmSubagentCapHelp: 'Deixa os subagents usar o limiar force dedicado abaixo; desligado = seguem integralmente os três limiares acima.',
|
|
1902
|
+
wmSubagentForceLabel: 'Limiar force dos subagents',
|
|
1903
|
+
wmSubagentForceHelp: 'Sobrepõe apenas o limiar force dos subagents (soft/hard são compartilhados com a sessão principal); 0 segue o limiar force acima.',
|
|
1904
|
+
wmSubagentFollowForce: 'Seguir o limiar force (0)',
|
|
1905
|
+
wmCommands: 'Comandos: /ctx-pause suspende as ações de nível de água · /ctx-resume as retoma · /ctx-handover faz backup e handover agora.',
|
|
1906
|
+
teamsSectionTitle: 'Agent Teams',
|
|
1907
|
+
teamsSectionDescription: 'Muda o formato do despacho: desligado é o despacho simples via subagent (entra a política conservadora de equipe de fábrica do DSH); ligado injeta a doutrina de equipe autônoma e habilita os Agent Teams.',
|
|
1908
|
+
teamsModeLabel: 'Modo Agent Teams',
|
|
1909
|
+
teamsModeHelp: 'Ligado, a doutrina de equipe (delegar por padrão + verificação em níveis + disciplina do quadro de tarefas compartilhado) é injetada e o bundle Agent Teams do DSH fica habilitado; os badges ⚠ de autorização dos pools de despacho aparecem apenas neste modo.',
|
|
1910
|
+
syncWhitelistLabel: 'Sincronizar a whitelist de modelos dos subagents',
|
|
1911
|
+
syncWhitelistHelp: 'Chave independente (não depende do modo Agent Teams): grava a união dos seis pools na lista de autorização “Configurações do DSH → Subagents → seleção de modelos”; o dsh-switchman vira a única fonte da verdade.',
|
|
1912
|
+
whitelistSyncOk: 'Sincronizadas {count} entradas ({time}).',
|
|
1913
|
+
whitelistSyncError: 'Falha na sincronização: {error}',
|
|
1914
|
+
whitelistSyncPending: 'Aguardando sincronizar…',
|
|
1915
|
+
whitelistSyncNote: 'Mudanças na whitelist só valem para sessões criadas depois.',
|
|
1916
|
+
uiSectionTitle: 'Interface',
|
|
1917
|
+
uiSectionDescription: 'Idioma de exibição da interface do próprio plugin (badge, painel, esta página de configurações).',
|
|
1918
|
+
uiLocaleLabel: 'Idioma da interface',
|
|
1919
|
+
uiLocaleHelp: 'Auto segue o idioma do aplicativo DeepSeek Harness; escolher um idioma força a interface do plugin para ele.',
|
|
1920
|
+
uiLocaleAuto: 'Auto (seguir DSH)',
|
|
1921
|
+
},
|
|
1922
|
+
ru: {
|
|
1923
|
+
badge: 'Автономная команда',
|
|
1924
|
+
badgeTip: 'dsh-switchman: четыре встроенных пресета (standard / ptc / minimal / cordis) несут с собой регламент автономной команды Agent Teams',
|
|
1925
|
+
handoverActive: 'Идёт передача',
|
|
1926
|
+
handoverPhaseBackup: 'резервная сессия',
|
|
1927
|
+
handoverPhaseCompacting: 'сжатие контекста',
|
|
1928
|
+
handoverPhaseContinuation: 'пробуждение продолжения',
|
|
1929
|
+
handoverActiveTip: 'Switchman передаёт контекст в фоне: форкает резервную сессию и сжимает контекст; по завершении задача продолжается автоматически. Неподвижная сессия в это окно — это нормально.',
|
|
1930
|
+
visionHintNeedsPool: 'Эта модель не умеет читать изображения: добавьте модели в мультимодальный пул в настройках dsh-switchman и отправляйте картинки через /vision.',
|
|
1931
|
+
visionHintUseVision: 'Эта модель не умеет читать изображения: отправляйте их через /vision (автоматически уйдут в мультимодальный пул).',
|
|
1932
|
+
visionAutoConverted: 'Отправка картинки отклонена: повторная отправка идёт автоматически через /vision (прочитает мультимодальный пул).',
|
|
1933
|
+
settingsTitle: 'dsh-switchman',
|
|
1934
|
+
panelLabel: 'Switchman',
|
|
1935
|
+
settingsDescription: 'Настройка предпочтений dsh-switchman.',
|
|
1936
|
+
langSectionTitle: 'Язык',
|
|
1937
|
+
langSectionDescription: 'Определяет язык ответов агентов, комментариев в коде и создаваемых документов.',
|
|
1938
|
+
langScopeLabel: 'Область действия языка',
|
|
1939
|
+
langScopeHelp: 'Где хранятся эти языковые предпочтения.',
|
|
1940
|
+
langScopeGlobal: 'Глобально (этот профиль)',
|
|
1941
|
+
langScopeProject: 'По проектам (.switchman/lang.json)',
|
|
1942
|
+
langProjectNote: 'Режим по проектам: каждый проект читает свой .switchman/lang.json; ответы при первом использовании сохраняются туда, и сессии спрашивают, пока файл не появится. Три поля ниже действуют только в глобальном режиме.',
|
|
1943
|
+
langConversationLabel: 'Язык беседы',
|
|
1944
|
+
langConversationHelp: 'Язык, на котором агенты отвечают и обсуждают; если не задан, спросят один раз при первом использовании и запомнят выбор.',
|
|
1945
|
+
langCommentsLabel: 'Язык комментариев в коде',
|
|
1946
|
+
langCommentsHelp: 'Язык, на котором агенты пишут комментарии в коде.',
|
|
1947
|
+
langDocsLabel: 'Язык документов',
|
|
1948
|
+
langDocsHelp: 'Язык, на котором агенты составляют документы.',
|
|
1949
|
+
followConversation: 'Следовать языку беседы',
|
|
1950
|
+
notSetAsk: 'Не задан (спросить при первом использовании)',
|
|
1951
|
+
customLanguage: 'Свой язык…',
|
|
1952
|
+
customLanguagePlaceholder: 'Название языка или BCP-тег',
|
|
1953
|
+
customLanguageRequired: 'Введите свой язык (1–48 символов).',
|
|
1954
|
+
currentValue: 'Сейчас: {value}',
|
|
1955
|
+
currentValueUnset: 'Сейчас: не задан',
|
|
1956
|
+
suggestedValue: 'Предложено: {value}',
|
|
1957
|
+
save: 'Сохранить',
|
|
1958
|
+
saving: 'Сохранение…',
|
|
1959
|
+
discard: 'Отменить изменения',
|
|
1960
|
+
saveFailed: 'Развёртывание не приняло эти значения; они оставлены вам на исправление.',
|
|
1961
|
+
saveConflict: 'Настройки изменились в другом месте. Откажитесь от черновика и попробуйте снова.',
|
|
1962
|
+
formLoading: 'Загрузка настроек…',
|
|
1963
|
+
formUnavailable: 'Плагин не загружен, поэтому настроить его сейчас нельзя.',
|
|
1964
|
+
formReadOnly: 'Это развёртывание хранит настройки в режиме только для чтения.',
|
|
1965
|
+
dispatchSectionTitle: 'Пулы диспетчеризации и ранжирование моделей',
|
|
1966
|
+
dispatchSectionDescription: 'Разбивает модели на шесть пулов диспетчеризации по сложности задач и ведёт ранжирование по силе; действует только на делегирование dsh-switchman.',
|
|
1967
|
+
dispatchProgress: '{pools}/6 пулов задано · {ranked} в ранжировании · режим {mode}',
|
|
1968
|
+
poolEconomyTitle: 'Экономия',
|
|
1969
|
+
poolEconomyDesc: 'Мелкие массовые задачи низкой сложности',
|
|
1970
|
+
poolMechanicalTitle: 'Механика',
|
|
1971
|
+
poolMechanicalDesc: 'Механические переработки и шаблонные операции',
|
|
1972
|
+
poolMainTitle: 'Основной',
|
|
1973
|
+
poolMainDesc: 'Повседневный кодинг и рутинные задачи',
|
|
1974
|
+
poolHardTitle: 'Сложный',
|
|
1975
|
+
poolHardDesc: 'Тяжёлые рассуждения и крупные рефакторинги',
|
|
1976
|
+
poolVisionTitle: 'Мультимодальный',
|
|
1977
|
+
poolVisionDesc: 'Мультимодальная работа (изображения)',
|
|
1978
|
+
poolReviewTitle: 'Ревью',
|
|
1979
|
+
poolReviewDesc: 'Ревью только для чтения и независимая проверка',
|
|
1980
|
+
poolSelectAll: 'Выбрать все',
|
|
1981
|
+
poolClear: 'Очистить',
|
|
1982
|
+
poolEmpty: 'Нет моделей-кандидатов',
|
|
1983
|
+
poolManualLabel: 'Ручной порядок',
|
|
1984
|
+
poolManualHelp: 'Включено — диспетчеризация идёт по списку (голова списка = первый выбор); выключено — полосы упорядочиваются по силе автоматически.',
|
|
1985
|
+
poolManualSelected: 'Выбрано · приоритет диспетчеризации',
|
|
1986
|
+
poolManualAddable: 'Добавить модели',
|
|
1987
|
+
poolMoveUp: 'Выше',
|
|
1988
|
+
poolMoveDown: 'Ниже',
|
|
1989
|
+
poolRemoveOne: 'Убрать',
|
|
1990
|
+
poolEffortFollow: 'следовать полосе',
|
|
1991
|
+
poolEffortLabel: 'effort',
|
|
1992
|
+
poolEffortHelp: 'Фиксирует reasoning effort этой модели; при диспетчеризации перекрывает умолчание полосы',
|
|
1993
|
+
catalogLoading: 'Загрузка каталога моделей…',
|
|
1994
|
+
catalogLoadFailed: 'Не удалось загрузить каталог моделей.',
|
|
1995
|
+
catalogRetry: 'Повторить',
|
|
1996
|
+
catalogPartial: 'Часть провайдеров моделей не загрузилась; сохранённый выбор всё ещё можно убрать.',
|
|
1997
|
+
catalogEmpty: 'Ни один провайдер моделей сейчас не объявляет моделей.',
|
|
1998
|
+
catalogUnavailableGroup: 'Сохранённые, но сейчас недоступные',
|
|
1999
|
+
catalogUnavailable: 'сейчас недоступна',
|
|
2000
|
+
unauthorizedBadge: 'не авторизовано для явной диспетчеризации потомков в настройках DSH (субагенты: выбор моделей)',
|
|
2001
|
+
unauthorizedHint: 'Модели с пометкой ⚠ не авторизованы в «Настройки DSH → Субагенты → выбор моделей»; явное их назначение агентом будет отклонено — авторизуйте их в настройках DSH или пусть агенты диспетчеризуют неявно.',
|
|
2002
|
+
rankTitle: 'Ранжирование по силе',
|
|
2003
|
+
rankDescription: 'Нумерация от сильнейшего; каждая запись может привязаться к ступени S/A/B/C. Список — это выбор пулов ∪ сохранённое ранжирование; любое изменение закрепляет показанный порядок.',
|
|
2004
|
+
rankEmpty: 'Отметьте модели в пулах выше — список ранжирования появится сам.',
|
|
2005
|
+
rankTier: 'Ступень',
|
|
2006
|
+
rankTierNone: '—',
|
|
2007
|
+
rankMoveUp: 'Выше',
|
|
2008
|
+
rankMoveDown: 'Ниже',
|
|
2009
|
+
rankRemove: 'Убрать из ранжирования',
|
|
2010
|
+
enforceLabel: 'Режим исполнения',
|
|
2011
|
+
enforceOff: 'Off',
|
|
2012
|
+
enforceAdvice: 'Advice',
|
|
2013
|
+
enforceEnforce: 'Enforce',
|
|
2014
|
+
enforceHelpOff: 'Никакие рекомендации пулов не добавляются в делегирование.',
|
|
2015
|
+
enforceHelpAdvice: 'Рекомендации пулов добавляются как совет (advice); модели могут от них отступать.',
|
|
2016
|
+
enforceHelpEnforce: 'Рекомендации пулов добавляются как жёсткое ограничение; отступления отклоняются.',
|
|
2017
|
+
wmSectionTitle: 'Уровень воды в контексте',
|
|
2018
|
+
wmSectionDescription: 'Ступенчатое поведение по расходу токенов: совет, урезание чтения и подведение итогов, автоматическая передача.',
|
|
2019
|
+
wmSoftLabel: 'Линия soft',
|
|
2020
|
+
wmSoftHelp: 'Выше неё появляется баннер, и советуется делегировать или прибрать контекст.',
|
|
2021
|
+
wmHardLabel: 'Линия hard',
|
|
2022
|
+
wmHardHelp: 'Выше неё бюджет чтения урезается и стоит подвигаться к завершению.',
|
|
2023
|
+
wmForceLabel: 'Линия force',
|
|
2024
|
+
wmForceHelp: 'Выше неё — резервная копия и передача на сжатие (может быть автоматически).',
|
|
2025
|
+
wmReadBudgetLabel: 'Бюджет чтения',
|
|
2026
|
+
wmReadBudgetHelp: 'Бюджет токенов на одно чтение; каждый ход ограничен удвоенным значением.',
|
|
2027
|
+
wmNumberInvalid: 'Введите целое число не меньше {min}.',
|
|
2028
|
+
wmOrderInvalid: 'Три линии должны строго возрастать: soft < hard < force.',
|
|
2029
|
+
wmDenyModeLabel: 'Поведение на линии hard',
|
|
2030
|
+
wmDenyModeCap: 'Урезать и предупредить',
|
|
2031
|
+
wmDenyModeDeny: 'Отклонять сразу',
|
|
2032
|
+
wmDenyModeHelpCap: 'Вызовы сверх бюджета проходят, но предупреждение записывается.',
|
|
2033
|
+
wmDenyModeHelpDeny: 'Вызовы сверх бюджета отклоняются сразу.',
|
|
2034
|
+
wmAutoHandoverLabel: 'Автоматическая передача',
|
|
2035
|
+
wmAutoHandoverHelp: 'На линии force — резервная копия и передача на сжатие автоматически.',
|
|
2036
|
+
wmSubagentTitle: 'Субагенты',
|
|
2037
|
+
wmSubagentCapLabel: 'Потолок контекста субагентов',
|
|
2038
|
+
wmSubagentCapHelp: 'Субагенты используют отдельный порог force ниже; выключено = полностью следуют трём линиям выше.',
|
|
2039
|
+
wmSubagentForceLabel: 'Порог force субагентов',
|
|
2040
|
+
wmSubagentForceHelp: 'Меняет только линию force субагентов (soft/hard общие с главной сессией); 0 — следовать линии force выше.',
|
|
2041
|
+
wmSubagentFollowForce: 'Следовать линии force (0)',
|
|
2042
|
+
wmCommands: 'Команды: /ctx-pause приостанавливает действия по уровню воды · /ctx-resume возобновляет их · /ctx-handover делает резервную копию и передаёт прямо сейчас.',
|
|
2043
|
+
teamsSectionTitle: 'Agent Teams',
|
|
2044
|
+
teamsSectionDescription: 'Переключает форму диспетчеризации: выключено — обычный dispatch через субагентов (вступает консервативная заводская командная политика DSH); включено — внедряется регламент автономной команды и включаются Agent Teams.',
|
|
2045
|
+
teamsModeLabel: 'Режим Agent Teams',
|
|
2046
|
+
teamsModeHelp: 'Включено: внедряется командный регламент (делегирование по умолчанию + многоуровневая проверка + дисциплина общей доски задач) и включается бандл DSH Agent Teams; значки ⚠ авторизации у пулов диспетчеризации показываются только в этом режиме.',
|
|
2047
|
+
syncWhitelistLabel: 'Синхронизировать белый список моделей субагентов',
|
|
2048
|
+
syncWhitelistHelp: 'Независимый переключатель (режим Agent Teams не требуется): записывает объединение шести пулов в список авторизации «Настройки DSH → Субагенты → выбор моделей»; dsh-switchman становится единственным источником истины.',
|
|
2049
|
+
whitelistSyncOk: 'Синхронизировано записей: {count} ({time}).',
|
|
2050
|
+
whitelistSyncError: 'Сбой синхронизации: {error}',
|
|
2051
|
+
whitelistSyncPending: 'Ожидание синхронизации…',
|
|
2052
|
+
whitelistSyncNote: 'Изменения белого списка действуют только на сессии, созданные после.',
|
|
2053
|
+
uiSectionTitle: 'Интерфейс',
|
|
2054
|
+
uiSectionDescription: 'Язык отображения собственного интерфейса плагина (значок, панель, эта страница настроек).',
|
|
2055
|
+
uiLocaleLabel: 'Язык интерфейса',
|
|
2056
|
+
uiLocaleHelp: '«Авто» следует языку приложения DeepSeek Harness; выбор конкретного языка принудительно переводит на него интерфейс плагина.',
|
|
2057
|
+
uiLocaleAuto: 'Авто (следовать DSH)',
|
|
645
2058
|
},
|
|
646
2059
|
};
|
|
647
2060
|
|
|
@@ -649,15 +2062,217 @@ window.__ModuleLoader__.load({
|
|
|
649
2062
|
// Session-header badge (Phase 0, unchanged)
|
|
650
2063
|
// ------------------------------------------------------------------
|
|
651
2064
|
|
|
652
|
-
|
|
2065
|
+
/** Rotating-arc spinner (SVG SMIL animateTransform): the restricted
|
|
2066
|
+
* dynamic-module runtime exposes no CSS insertion here, and SMIL
|
|
2067
|
+
* animates without lifecycle code or a React state loop. */
|
|
2068
|
+
function HandoverSpinner() {
|
|
2069
|
+
return h(
|
|
2070
|
+
'svg',
|
|
2071
|
+
{
|
|
2072
|
+
viewBox: '0 0 16 16',
|
|
2073
|
+
width: 12,
|
|
2074
|
+
height: 12,
|
|
2075
|
+
'aria-hidden': true,
|
|
2076
|
+
style: { flex: 'none' },
|
|
2077
|
+
},
|
|
2078
|
+
h(
|
|
2079
|
+
'circle',
|
|
2080
|
+
{
|
|
2081
|
+
cx: 8,
|
|
2082
|
+
cy: 8,
|
|
2083
|
+
r: 6,
|
|
2084
|
+
fill: 'none',
|
|
2085
|
+
stroke: 'currentColor',
|
|
2086
|
+
strokeWidth: 2,
|
|
2087
|
+
strokeDasharray: '9 19',
|
|
2088
|
+
strokeLinecap: 'round',
|
|
2089
|
+
},
|
|
2090
|
+
h('animateTransform', {
|
|
2091
|
+
attributeName: 'transform',
|
|
2092
|
+
type: 'rotate',
|
|
2093
|
+
from: '0 8 8',
|
|
2094
|
+
to: '360 8 8',
|
|
2095
|
+
dur: '1s',
|
|
2096
|
+
repeatCount: 'indefinite',
|
|
2097
|
+
}),
|
|
2098
|
+
),
|
|
2099
|
+
);
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
function SwitchmanBadge({
|
|
2103
|
+
locale,
|
|
2104
|
+
t,
|
|
2105
|
+
sessionId,
|
|
2106
|
+
useProjection,
|
|
2107
|
+
useSessions,
|
|
2108
|
+
}) {
|
|
2109
|
+
|
|
653
2110
|
// Subscription only: stable snapshot via getLocale() re-renders on switch.
|
|
654
2111
|
React.useSyncExternalStore(
|
|
655
2112
|
(fn) => locale.subscribe(fn),
|
|
656
2113
|
() => locale.getLocale(),
|
|
657
2114
|
);
|
|
2115
|
+
// Re-render when the manual interface-locale override changes.
|
|
2116
|
+
React.useSyncExternalStore(subscribeUiLocale, () => uiLocaleVersion);
|
|
2117
|
+
// Live handover cue: during the fork+compact window the session
|
|
2118
|
+
// GUI has no motion of its own, so the badge polls the Host's
|
|
2119
|
+
// handover-state route (phases recorded from runHandover's first
|
|
2120
|
+
// synchronous line) and flips to an animated status chip. Fast
|
|
2121
|
+
// cadence while in flight, slow otherwise; a failed fetch or an
|
|
2122
|
+
// older Host reads as "no handover" and never blocks the badge.
|
|
2123
|
+
const [handover, setHandover] = React.useState(null);
|
|
2124
|
+
React.useEffect(() => {
|
|
2125
|
+
let stopped = false;
|
|
2126
|
+
let timer = null;
|
|
2127
|
+
const tick = async () => {
|
|
2128
|
+
let live = null;
|
|
2129
|
+
// NOTE: the handover-state route is not session-scoped, so
|
|
2130
|
+
// this reflects ANY in-flight handover (cross-session bleed
|
|
2131
|
+
// with several open sessions) — accepted: cosmetic, and
|
|
2132
|
+
// the desktop GUI renders one session header at a time.
|
|
2133
|
+
try {
|
|
2134
|
+
const reply = await api.get('handover-state');
|
|
2135
|
+
if (reply?.ok && reply.value?.count > 0)
|
|
2136
|
+
live = reply.value.handovers[0] ?? null;
|
|
2137
|
+
} catch {
|
|
2138
|
+
live = null;
|
|
2139
|
+
}
|
|
2140
|
+
if (stopped) return;
|
|
2141
|
+
setHandover(live);
|
|
2142
|
+
timer = setTimeout(tick, live === null ? 10_000 : 3_000);
|
|
2143
|
+
};
|
|
2144
|
+
void tick();
|
|
2145
|
+
return () => {
|
|
2146
|
+
stopped = true;
|
|
2147
|
+
if (timer !== null) clearTimeout(timer);
|
|
2148
|
+
};
|
|
2149
|
+
}, []);
|
|
2150
|
+
// ---- Session model line ----
|
|
2151
|
+
// The slot is session-scoped, so `sessionId` names the open session
|
|
2152
|
+
// and `useProjection` reads its live projection faces (standard kit
|
|
2153
|
+
// members; both degrade to no-ops outside the kit, same guard shape
|
|
2154
|
+
// as the vision dock entry). Switching sessions re-materializes the
|
|
2155
|
+
// standard props, so the face re-binds and the old subscription is
|
|
2156
|
+
// dropped by the hook machinery — no manual lifecycle here.
|
|
2157
|
+
const projectionHook =
|
|
2158
|
+
typeof useProjection === 'function' ? useProjection : () => undefined;
|
|
2159
|
+
const liveSelection = projectionHook('modelSelection');
|
|
2160
|
+
// NEVER touch services this plugin did not declare in inject:
|
|
2161
|
+
// the dynamic-module guard THROWS on `ctx.<undeclared>` access
|
|
2162
|
+
// (ctx.sessions did exactly that and the slot occurrence error
|
|
2163
|
+
// boundary swallowed it — the badge silently vanished this way).
|
|
2164
|
+
// Session facts arrive only through framework-bound kit hooks, and
|
|
2165
|
+
// every selector must return a value-stable primitive.
|
|
2166
|
+
const sessionsHook =
|
|
2167
|
+
typeof useSessions === 'function' ? useSessions : () => undefined;
|
|
2168
|
+
// Durable metadata separates subagent sessions from root ones
|
|
2169
|
+
// (summary `origin`/`parentId`). A root session's model already has
|
|
2170
|
+
// the composer's model selector, so the line stays subagent-only.
|
|
2171
|
+
const subagentKey = sessionsHook((list) => {
|
|
2172
|
+
if (list == null) return 'absent';
|
|
2173
|
+
const summary =
|
|
2174
|
+
sessionId != null ? list.byId?.[sessionId] : undefined;
|
|
2175
|
+
if (summary === undefined) return 'absent';
|
|
2176
|
+
return summary.origin === 'subagent' ||
|
|
2177
|
+
summary.parentId !== undefined
|
|
2178
|
+
? 'subagent'
|
|
2179
|
+
: 'root';
|
|
2180
|
+
});
|
|
2181
|
+
const isSubagent = subagentKey === 'subagent';
|
|
2182
|
+
// Fallback for sessions whose retained face has not carried the
|
|
2183
|
+
// key yet: the manager's shared list snapshot often already holds
|
|
2184
|
+
// explicitly loaded projections (sidebar-visible subagents).
|
|
2185
|
+
const fallbackText = sessionsHook((list) => {
|
|
2186
|
+
if (list == null) return '';
|
|
2187
|
+
const selection =
|
|
2188
|
+
sessionId != null
|
|
2189
|
+
? list.projectionsBySession?.[sessionId]?.values
|
|
2190
|
+
?.modelSelection
|
|
2191
|
+
: undefined;
|
|
2192
|
+
const model = selection?.next ?? selection?.lastUsed;
|
|
2193
|
+
if (model == null) return '';
|
|
2194
|
+
return `${model.provider}/${model.model}${
|
|
2195
|
+
model.reasoningEffort ? `@${model.reasoningEffort}` : ''
|
|
2196
|
+
}`;
|
|
2197
|
+
});
|
|
2198
|
+
const liveModel =
|
|
2199
|
+
liveSelection?.next ?? liveSelection?.lastUsed ?? null;
|
|
2200
|
+
const modelText =
|
|
2201
|
+
liveModel == null
|
|
2202
|
+
? (fallbackText ?? '')
|
|
2203
|
+
: `${liveModel.provider}/${liveModel.model}${
|
|
2204
|
+
liveModel.reasoningEffort
|
|
2205
|
+
? `@${liveModel.reasoningEffort}`
|
|
2206
|
+
: ''
|
|
2207
|
+
}`;
|
|
2208
|
+
const modelChip =
|
|
2209
|
+
isSubagent && modelText !== ''
|
|
2210
|
+
? h(
|
|
2211
|
+
'span',
|
|
2212
|
+
{
|
|
2213
|
+
title: modelText,
|
|
2214
|
+
'data-dsh-switchman': 'session-model',
|
|
2215
|
+
style: {
|
|
2216
|
+
borderRadius: 'var(--dsw-radius-xs)',
|
|
2217
|
+
height: '22px',
|
|
2218
|
+
color: 'var(--dsw-alias-label-tertiary)',
|
|
2219
|
+
whiteSpace: 'nowrap',
|
|
2220
|
+
display: 'inline-flex',
|
|
2221
|
+
alignItems: 'center',
|
|
2222
|
+
gap: '4px',
|
|
2223
|
+
padding: '0 8px',
|
|
2224
|
+
fontSize: '12px',
|
|
2225
|
+
lineHeight: '22px',
|
|
2226
|
+
flex: 'none',
|
|
2227
|
+
},
|
|
2228
|
+
},
|
|
2229
|
+
h('span', { 'aria-hidden': true, style: { flex: 'none' } }, '◇'),
|
|
2230
|
+
h('span', null, modelText),
|
|
2231
|
+
)
|
|
2232
|
+
: null;
|
|
2233
|
+
/** Append the model chip without disturbing the status chip shapes. */
|
|
2234
|
+
const withModelChip = (chip) =>
|
|
2235
|
+
modelChip === null ? chip : h(React.Fragment, null, chip, modelChip);
|
|
2236
|
+
if (handover !== null) {
|
|
2237
|
+
const phaseKey =
|
|
2238
|
+
handover.phase === 'backup'
|
|
2239
|
+
? 'handoverPhaseBackup'
|
|
2240
|
+
: handover.phase === 'continuation'
|
|
2241
|
+
? 'handoverPhaseContinuation'
|
|
2242
|
+
: 'handoverPhaseCompacting';
|
|
2243
|
+
const seconds = Math.max(
|
|
2244
|
+
0,
|
|
2245
|
+
Math.round((Date.now() - (handover.at ?? Date.now())) / 1000),
|
|
2246
|
+
);
|
|
2247
|
+
const status = h(
|
|
2248
|
+
'span',
|
|
2249
|
+
{
|
|
2250
|
+
title: `${t('handoverActiveTip')}(${seconds}s)`,
|
|
2251
|
+
role: 'status',
|
|
2252
|
+
'data-dsh-switchman': 'handover-active',
|
|
2253
|
+
style: {
|
|
2254
|
+
borderRadius: 'var(--dsw-radius-xs)',
|
|
2255
|
+
background: 'var(--dsw-alias-interactive-bg-hover, transparent)',
|
|
2256
|
+
color: 'var(--dsw-alias-state-business-primary, inherit)',
|
|
2257
|
+
height: '22px',
|
|
2258
|
+
whiteSpace: 'nowrap',
|
|
2259
|
+
display: 'inline-flex',
|
|
2260
|
+
alignItems: 'center',
|
|
2261
|
+
gap: '4px',
|
|
2262
|
+
padding: '0 8px',
|
|
2263
|
+
fontSize: '12px',
|
|
2264
|
+
lineHeight: '22px',
|
|
2265
|
+
flex: 'none',
|
|
2266
|
+
},
|
|
2267
|
+
},
|
|
2268
|
+
h(HandoverSpinner, null),
|
|
2269
|
+
h('span', null, `${t('handoverActive')} · ${t(phaseKey)}`),
|
|
2270
|
+
);
|
|
2271
|
+
return withModelChip(status);
|
|
2272
|
+
}
|
|
658
2273
|
const text = t('badge');
|
|
659
2274
|
const tip = t('badgeTip');
|
|
660
|
-
|
|
2275
|
+
const status = h(
|
|
661
2276
|
'span',
|
|
662
2277
|
{
|
|
663
2278
|
title: tip,
|
|
@@ -684,6 +2299,246 @@ window.__ModuleLoader__.load({
|
|
|
684
2299
|
h('span', { 'aria-hidden': true, style: { flex: 'none' } }, '⚡'),
|
|
685
2300
|
h('span', null, text),
|
|
686
2301
|
);
|
|
2302
|
+
return withModelChip(status);
|
|
2303
|
+
}
|
|
2304
|
+
|
|
2305
|
+
/** Composer-dock vision entry. Two jobs:
|
|
2306
|
+
*
|
|
2307
|
+
* 1. Guidance chip — DSH refuses to send pasted images while the
|
|
2308
|
+
* session model has no image input; switchman's unlock is the
|
|
2309
|
+
* /vision command backed by the vision pool. The chip renders
|
|
2310
|
+
* whenever image support is not positively confirmed (probe
|
|
2311
|
+
* false, or null = unresolved — the common live case: the
|
|
2312
|
+
* Host-side model-info resolution often cannot resolve custom
|
|
2313
|
+
* routes), polling the Host route at a slow fixed cadence;
|
|
2314
|
+
* any failure renders nothing.
|
|
2315
|
+
* 2. Reactive auto-conversion (v1) — when a plain send is refused
|
|
2316
|
+
* host-side (session/attachment-invalid), rewrite the draft as
|
|
2317
|
+
* "/vision <original text>" and resubmit once; the claimed
|
|
2318
|
+
* command submit carries the restored draft attachments past
|
|
2319
|
+
* the model gate to the /vision handler. The refusal code is
|
|
2320
|
+
* the authoritative image-gate signal; the probe's
|
|
2321
|
+
* imageCapable only brakes the conversion when it positively
|
|
2322
|
+
* says true. Session-scoped dock entries receive the standard
|
|
2323
|
+
* kit (inputActions, useInput, useSession) automatically;
|
|
2324
|
+
* loop safety = one conversion per promptError object
|
|
2325
|
+
* identity + never converting a draft that already starts
|
|
2326
|
+
* with "/". */
|
|
2327
|
+
function VisionDockEntry({ t, sessionId, inputActions, useInput, useSession }) {
|
|
2328
|
+
const [vision, setVision] = React.useState(null);
|
|
2329
|
+
const [notice, setNotice] = React.useState(false);
|
|
2330
|
+
const handled = React.useRef(null);
|
|
2331
|
+
const latest = React.useRef({ vision: null, draft: '', attachmentIds: [] });
|
|
2332
|
+
React.useEffect(() => {
|
|
2333
|
+
let stopped = false;
|
|
2334
|
+
let timer = null;
|
|
2335
|
+
// The probe must judge the CURRENT conversation's model: pass
|
|
2336
|
+
// the session scope's identity so the Host resolves
|
|
2337
|
+
// imageCapable from that session's model selection (subagent
|
|
2338
|
+
// sessions included); without it the Host falls back to the
|
|
2339
|
+
// root session and mislabels text-only children. Restarting
|
|
2340
|
+
// the loop on `sessionId` re-probes immediately on a switch.
|
|
2341
|
+
const query =
|
|
2342
|
+
typeof sessionId === 'string' && sessionId !== ''
|
|
2343
|
+
? `?session=${encodeURIComponent(sessionId)}`
|
|
2344
|
+
: '';
|
|
2345
|
+
const tick = async () => {
|
|
2346
|
+
let next = null;
|
|
2347
|
+
try {
|
|
2348
|
+
const reply = await api.get(`vision-state${query}`);
|
|
2349
|
+
if (reply?.ok && reply.value && typeof reply.value === 'object')
|
|
2350
|
+
next = {
|
|
2351
|
+
poolConfigured: reply.value.poolConfigured === true,
|
|
2352
|
+
imageCapable: reply.value.imageCapable,
|
|
2353
|
+
};
|
|
2354
|
+
} catch {
|
|
2355
|
+
next = null;
|
|
2356
|
+
}
|
|
2357
|
+
if (stopped) return;
|
|
2358
|
+
setVision(next);
|
|
2359
|
+
timer = setTimeout(tick, 15_000);
|
|
2360
|
+
};
|
|
2361
|
+
void tick();
|
|
2362
|
+
return () => {
|
|
2363
|
+
stopped = true;
|
|
2364
|
+
if (timer !== null) clearTimeout(timer);
|
|
2365
|
+
};
|
|
2366
|
+
}, [sessionId]);
|
|
2367
|
+
// Standard kit props are guaranteed by the session scope, but the
|
|
2368
|
+
// hooks must be called unconditionally — degrade to no-op sources
|
|
2369
|
+
// if a future shell ever mounts this entry outside that scope.
|
|
2370
|
+
const inputHook =
|
|
2371
|
+
typeof useInput === 'function' ? useInput : () => () => ({ draft: '', attachmentIds: [] });
|
|
2372
|
+
const sessionHook =
|
|
2373
|
+
typeof useSession === 'function' ? useSession : () => () => null;
|
|
2374
|
+
const input = inputHook((s) => s) ?? {};
|
|
2375
|
+
const promptError = sessionHook((s) => s.promptError);
|
|
2376
|
+
latest.current = {
|
|
2377
|
+
vision,
|
|
2378
|
+
draft: typeof input.draft === 'string' ? input.draft : '',
|
|
2379
|
+
attachmentIds: Array.isArray(input.attachmentIds) ? input.attachmentIds : [],
|
|
2380
|
+
};
|
|
2381
|
+
React.useEffect(() => {
|
|
2382
|
+
if (promptError == null || promptError === handled.current) return;
|
|
2383
|
+
handled.current = promptError;
|
|
2384
|
+
if (promptError.op !== 'send') return; // stop failures are not ours
|
|
2385
|
+
const code = promptError.error?.code;
|
|
2386
|
+
if (code !== 'session/attachment-invalid' && code !== 'subagent/attachment-invalid') return;
|
|
2387
|
+
// Let InputBar's failure restore of the draft and attachments
|
|
2388
|
+
// land before reading them.
|
|
2389
|
+
const timer = setTimeout(() => {
|
|
2390
|
+
const snap = latest.current;
|
|
2391
|
+
// The refusal code below is the authoritative image-gate
|
|
2392
|
+
// signal; vision.imageCapable is only a secondary brake.
|
|
2393
|
+
// The Host probe legitimately yields null (unknown) when
|
|
2394
|
+
// its model-info resolution fails, so skip ONLY when the
|
|
2395
|
+
// probe positively says the model reads images.
|
|
2396
|
+
if (snap.vision?.imageCapable === true) return;
|
|
2397
|
+
const text = snap.draft.trim();
|
|
2398
|
+
if (text.startsWith('/')) return; // already a command path — never loop
|
|
2399
|
+
if (snap.attachmentIds.length === 0) return;
|
|
2400
|
+
if (typeof inputActions?.setDraft !== 'function' || typeof inputActions?.submit !== 'function')
|
|
2401
|
+
return;
|
|
2402
|
+
inputActions.setDraft(text === '' ? '/vision' : `/vision ${text}`);
|
|
2403
|
+
inputActions.submit();
|
|
2404
|
+
setNotice(true);
|
|
2405
|
+
setTimeout(() => setNotice(false), 6_000);
|
|
2406
|
+
}, 300);
|
|
2407
|
+
return () => clearTimeout(timer);
|
|
2408
|
+
}, [promptError, inputActions]);
|
|
2409
|
+
if (vision === null && !notice) return null;
|
|
2410
|
+
// The dock zone spans the full conversation width while the
|
|
2411
|
+
// composer card is a centered column (max-width contract). The
|
|
2412
|
+
// hero state narrows the whole stack, the active state does
|
|
2413
|
+
// not — so a bare <p> lands hard against the far left once a
|
|
2414
|
+
// conversation starts. Mirror the shell's own QueueDock column
|
|
2415
|
+
// formula (same CSS custom properties) to keep every line's
|
|
2416
|
+
// left edge tracking the input card in both states; fallback
|
|
2417
|
+
// values degrade to the shell defaults if a variable is unset.
|
|
2418
|
+
const dockColumnStyle = {
|
|
2419
|
+
boxSizing: 'border-box',
|
|
2420
|
+
width: 'calc(100% - var(--dsh-composer-side-clearance, 16px) - var(--dsh-composer-side-clearance, 16px))',
|
|
2421
|
+
maxWidth: 'var(--dsh-composer-card-max-width, 780px)',
|
|
2422
|
+
margin: '0 auto',
|
|
2423
|
+
flex: 'none',
|
|
2424
|
+
// Keep the rhythm between the notice and hint lines equal to
|
|
2425
|
+
// the composer stack gap they no longer participate in.
|
|
2426
|
+
display: 'flex',
|
|
2427
|
+
flexDirection: 'column',
|
|
2428
|
+
gap: 'var(--dsh-composer-stack-gap, 6px)',
|
|
2429
|
+
};
|
|
2430
|
+
return h(
|
|
2431
|
+
'div',
|
|
2432
|
+
{
|
|
2433
|
+
'data-dsh-switchman': 'vision-dock-column',
|
|
2434
|
+
style: dockColumnStyle,
|
|
2435
|
+
},
|
|
2436
|
+
notice
|
|
2437
|
+
? h(
|
|
2438
|
+
'p',
|
|
2439
|
+
{
|
|
2440
|
+
'data-dsh-switchman': 'vision-auto-converted',
|
|
2441
|
+
style: {
|
|
2442
|
+
margin: '0',
|
|
2443
|
+
padding: '2px 0',
|
|
2444
|
+
color: 'var(--dsw-alias-label-secondary)',
|
|
2445
|
+
fontSize: '12px',
|
|
2446
|
+
lineHeight: '1.6',
|
|
2447
|
+
},
|
|
2448
|
+
},
|
|
2449
|
+
'↻ ',
|
|
2450
|
+
t('visionAutoConverted'),
|
|
2451
|
+
)
|
|
2452
|
+
: null,
|
|
2453
|
+
// Hint whenever the probe cannot positively confirm image
|
|
2454
|
+
// input — false (confirmed text-only) or null (unresolved,
|
|
2455
|
+
// the common live case): /vision is harmless either way and
|
|
2456
|
+
// this chip is the only composer-surface affordance for it.
|
|
2457
|
+
vision !== null && vision.imageCapable !== true
|
|
2458
|
+
? h(
|
|
2459
|
+
'p',
|
|
2460
|
+
{
|
|
2461
|
+
'data-dsh-switchman': 'vision-hint',
|
|
2462
|
+
style: {
|
|
2463
|
+
margin: '0',
|
|
2464
|
+
padding: '2px 0',
|
|
2465
|
+
color: 'var(--dsw-alias-label-tertiary)',
|
|
2466
|
+
fontSize: '12px',
|
|
2467
|
+
lineHeight: '1.6',
|
|
2468
|
+
},
|
|
2469
|
+
},
|
|
2470
|
+
'⚠ ',
|
|
2471
|
+
t(vision.poolConfigured ? 'visionHintUseVision' : 'visionHintNeedsPool'),
|
|
2472
|
+
)
|
|
2473
|
+
: null,
|
|
2474
|
+
);
|
|
2475
|
+
}
|
|
2476
|
+
|
|
2477
|
+
/** Home-sidebar panel icon (sidebar.panellist contract): the shell
|
|
2478
|
+
* row renderer passes { size, active } and colors the glyph via the
|
|
2479
|
+
* row's currentColor, so only size matters here. 16×16 stroke
|
|
2480
|
+
* glyph — one dispatch stem splitting into two routed lanes.
|
|
2481
|
+
* data-dsh-panel-entry is the documented L2 skins hook (the shell
|
|
2482
|
+
* row itself carries no per-entry marker). */
|
|
2483
|
+
function SwitchmanPanelIcon({ size }) {
|
|
2484
|
+
return h(
|
|
2485
|
+
'svg',
|
|
2486
|
+
{
|
|
2487
|
+
'data-dsh-panel-entry': 'dsh-switchman',
|
|
2488
|
+
viewBox: '0 0 16 16',
|
|
2489
|
+
width: size,
|
|
2490
|
+
height: size,
|
|
2491
|
+
fill: 'none',
|
|
2492
|
+
stroke: 'currentColor',
|
|
2493
|
+
strokeWidth: 1.3,
|
|
2494
|
+
strokeLinecap: 'round',
|
|
2495
|
+
strokeLinejoin: 'round',
|
|
2496
|
+
'aria-hidden': true,
|
|
2497
|
+
},
|
|
2498
|
+
h('path', { d: 'M2 8h4.5' }),
|
|
2499
|
+
h('path', { d: 'M6.5 8 10.5 4H12' }),
|
|
2500
|
+
h('path', { d: 'M6.5 8l4 4H12' }),
|
|
2501
|
+
h('path', { d: 'M12.2 2.2 14 4l-1.8 1.8' }),
|
|
2502
|
+
h('path', { d: 'M12.2 10.2 14 12l-1.8 1.8' }),
|
|
2503
|
+
);
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2506
|
+
/** Central-panel host for the sidebar entry: reuses the settings
|
|
2507
|
+
* page component unchanged (its {t, locale} props arrive as the
|
|
2508
|
+
* register inject() face). The main area hands the page a
|
|
2509
|
+
* definite-height, overflow-clipped frame with no gutter — the
|
|
2510
|
+
* page must own its scrolling (skill-explorer's .view/.tabBody
|
|
2511
|
+
* pattern): height:100% scroll owner outside, reading-width
|
|
2512
|
+
* centered column inside. */
|
|
2513
|
+
function SwitchmanPanelPage(props) {
|
|
2514
|
+
// Re-render when the manual interface-locale override changes
|
|
2515
|
+
// (panel strings go through the injected t wrapper).
|
|
2516
|
+
React.useSyncExternalStore(subscribeUiLocale, () => uiLocaleVersion);
|
|
2517
|
+
return h(
|
|
2518
|
+
'div',
|
|
2519
|
+
{
|
|
2520
|
+
'data-dsh-switchman': 'panel',
|
|
2521
|
+
style: {
|
|
2522
|
+
minWidth: 0,
|
|
2523
|
+
minHeight: 0,
|
|
2524
|
+
height: '100%',
|
|
2525
|
+
overflowY: 'auto',
|
|
2526
|
+
},
|
|
2527
|
+
},
|
|
2528
|
+
h(
|
|
2529
|
+
'div',
|
|
2530
|
+
{
|
|
2531
|
+
style: {
|
|
2532
|
+
minWidth: 0,
|
|
2533
|
+
maxWidth: '860px',
|
|
2534
|
+
margin: '0 auto',
|
|
2535
|
+
padding: '16px 24px',
|
|
2536
|
+
boxSizing: 'border-box',
|
|
2537
|
+
},
|
|
2538
|
+
},
|
|
2539
|
+
h(SwitchmanSettingsPage, props),
|
|
2540
|
+
),
|
|
2541
|
+
);
|
|
687
2542
|
}
|
|
688
2543
|
|
|
689
2544
|
// ------------------------------------------------------------------
|
|
@@ -834,7 +2689,7 @@ window.__ModuleLoader__.load({
|
|
|
834
2689
|
cursor: 'pointer',
|
|
835
2690
|
},
|
|
836
2691
|
poolList: {
|
|
837
|
-
maxHeight: '
|
|
2692
|
+
maxHeight: '320px',
|
|
838
2693
|
overflowY: 'auto',
|
|
839
2694
|
display: 'grid',
|
|
840
2695
|
gap: '2px',
|
|
@@ -867,6 +2722,10 @@ window.__ModuleLoader__.load({
|
|
|
867
2722
|
color: 'var(--dsw-alias-label-tertiary)',
|
|
868
2723
|
flex: 'none',
|
|
869
2724
|
},
|
|
2725
|
+
unauthorizedMark: {
|
|
2726
|
+
color: 'var(--dsw-alias-state-error-primary)',
|
|
2727
|
+
flex: 'none',
|
|
2728
|
+
},
|
|
870
2729
|
rankList: { display: 'grid', gap: '2px', marginTop: '8px' },
|
|
871
2730
|
rankRow: {
|
|
872
2731
|
display: 'grid',
|
|
@@ -885,9 +2744,12 @@ window.__ModuleLoader__.load({
|
|
|
885
2744
|
color: 'var(--dsw-alias-label-primary)',
|
|
886
2745
|
fontSize: '12.5px',
|
|
887
2746
|
lineHeight: 1.6,
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
2747
|
+
// Wrap instead of ellipsize: provider/model pairs must stay
|
|
2748
|
+
// fully readable in the narrow panel (the hover title remains
|
|
2749
|
+
// a convenience, not the only way to read the full route).
|
|
2750
|
+
whiteSpace: 'normal',
|
|
2751
|
+
wordBreak: 'break-word',
|
|
2752
|
+
minWidth: 0,
|
|
891
2753
|
},
|
|
892
2754
|
rankActions: { display: 'flex', gap: '4px', flex: 'none' },
|
|
893
2755
|
effortSelect: {
|
|
@@ -1002,6 +2864,8 @@ window.__ModuleLoader__.load({
|
|
|
1002
2864
|
efforts,
|
|
1003
2865
|
manual,
|
|
1004
2866
|
editable,
|
|
2867
|
+
authorized,
|
|
2868
|
+
teamsMode,
|
|
1005
2869
|
onToggle,
|
|
1006
2870
|
onToggleManual,
|
|
1007
2871
|
onSetEffort,
|
|
@@ -1011,7 +2875,30 @@ window.__ModuleLoader__.load({
|
|
|
1011
2875
|
onClear,
|
|
1012
2876
|
}) {
|
|
1013
2877
|
const hasCandidates = rows.length > 0 || extras.length > 0;
|
|
1014
|
-
/**
|
|
2878
|
+
/** Authorization-drift check: this route is not among the subagent
|
|
2879
|
+
* models DSH authorized for this session (authorized === null =
|
|
2880
|
+
* unknown, no mark). When enabled === false every explicit route
|
|
2881
|
+
* is rejected, so all selected routes count as drift. Team mode
|
|
2882
|
+
* only: plain subagent mode does no explicit route injection, the
|
|
2883
|
+
* badge would be meaningless. */
|
|
2884
|
+
const drift = (route) =>
|
|
2885
|
+
teamsMode === true &&
|
|
2886
|
+
authorized !== null &&
|
|
2887
|
+
(authorized.enabled === false ||
|
|
2888
|
+
!authorized.keys.has(routeKey(route)));
|
|
2889
|
+
/** ⚠ badge for drifted rows (hover/screen-reader text in
|
|
2890
|
+
* unauthorizedBadge). */
|
|
2891
|
+
const unauthorizedBadge = () =>
|
|
2892
|
+
h(
|
|
2893
|
+
'span',
|
|
2894
|
+
{
|
|
2895
|
+
style: STYLE.unauthorizedMark,
|
|
2896
|
+
title: t('unauthorizedBadge'),
|
|
2897
|
+
'aria-label': t('unauthorizedBadge'),
|
|
2898
|
+
},
|
|
2899
|
+
'⚠',
|
|
2900
|
+
);
|
|
2901
|
+
/** Display-name lookup: covers catalog rows and stored off-catalog rows. */
|
|
1015
2902
|
const nameByKey = new Map(
|
|
1016
2903
|
[...rows, ...extras]
|
|
1017
2904
|
.filter((row) => row.header === undefined)
|
|
@@ -1020,11 +2907,12 @@ window.__ModuleLoader__.load({
|
|
|
1020
2907
|
`${row.providerName} · ${row.modelName}`,
|
|
1021
2908
|
]),
|
|
1022
2909
|
);
|
|
1023
|
-
/**
|
|
2910
|
+
/** Effort lookup: a configured entry's key → effort for this pool. */
|
|
1024
2911
|
const effortByKey = new Map(
|
|
1025
2912
|
efforts.map((entry) => [routeKey(entry), entry.effort]),
|
|
1026
2913
|
);
|
|
1027
|
-
/**
|
|
2914
|
+
/** Effort metadata lookup: routeKey → wire reasoning.efforts (default
|
|
2915
|
+
* when absent). */
|
|
1028
2916
|
const effortsMetaByKey = new Map(
|
|
1029
2917
|
[...rows, ...extras]
|
|
1030
2918
|
.filter(
|
|
@@ -1033,9 +2921,10 @@ window.__ModuleLoader__.load({
|
|
|
1033
2921
|
)
|
|
1034
2922
|
.map((row) => [routeKey(row), row.reasoning.efforts]),
|
|
1035
2923
|
);
|
|
1036
|
-
/**
|
|
1037
|
-
*
|
|
1038
|
-
*
|
|
2924
|
+
/** Effort dropdown options for one selected model: prefer the real
|
|
2925
|
+
* efforts from the model's wire metadata; fall back to the EFFORTS
|
|
2926
|
+
* constant when unavailable; append a stored legacy value missing
|
|
2927
|
+
* from the list so the controlled select never misaligns. */
|
|
1039
2928
|
const effortOptions = (route) => {
|
|
1040
2929
|
const key = routeKey(route);
|
|
1041
2930
|
const wireEfforts = effortsMetaByKey.get(key);
|
|
@@ -1058,8 +2947,9 @@ window.__ModuleLoader__.load({
|
|
|
1058
2947
|
...pending,
|
|
1059
2948
|
];
|
|
1060
2949
|
};
|
|
1061
|
-
/**
|
|
1062
|
-
*
|
|
2950
|
+
/** Effort dropdown for one selected model ('' = follow the lane
|
|
2951
|
+
* default); stop propagation so the outer label's checkbox does not
|
|
2952
|
+
* toggle. */
|
|
1063
2953
|
const effortSelect = (route) =>
|
|
1064
2954
|
h(
|
|
1065
2955
|
'select',
|
|
@@ -1078,7 +2968,8 @@ window.__ModuleLoader__.load({
|
|
|
1078
2968
|
h('option', { value: option.id }, option.name),
|
|
1079
2969
|
),
|
|
1080
2970
|
);
|
|
1081
|
-
/**
|
|
2971
|
+
/** Manual-mode "addable" list: unchecked catalog rows only, empty
|
|
2972
|
+
* group headers dropped. */
|
|
1082
2973
|
const addableRows = [];
|
|
1083
2974
|
if (manual) {
|
|
1084
2975
|
let pendingHeader = null;
|
|
@@ -1095,7 +2986,7 @@ window.__ModuleLoader__.load({
|
|
|
1095
2986
|
addableRows.push(row);
|
|
1096
2987
|
}
|
|
1097
2988
|
}
|
|
1098
|
-
/**
|
|
2989
|
+
/** Manual-order switch on the right of the header row. */
|
|
1099
2990
|
const manualToggle = h(
|
|
1100
2991
|
'label',
|
|
1101
2992
|
{ style: STYLE.checkRow, title: t('poolManualHelp') },
|
|
@@ -1134,6 +3025,7 @@ window.__ModuleLoader__.load({
|
|
|
1134
3025
|
},
|
|
1135
3026
|
nameByKey.get(routeKey(route)) ??
|
|
1136
3027
|
`${route.provider} · ${route.model}`,
|
|
3028
|
+
drift(route) ? unauthorizedBadge() : null,
|
|
1137
3029
|
),
|
|
1138
3030
|
effortSelect(route),
|
|
1139
3031
|
h(
|
|
@@ -1299,6 +3191,9 @@ window.__ModuleLoader__.load({
|
|
|
1299
3191
|
`${row.providerName} · ${row.modelName}`,
|
|
1300
3192
|
),
|
|
1301
3193
|
...(row.selected ? [effortSelect(row)] : []),
|
|
3194
|
+
...(row.selected && drift(row)
|
|
3195
|
+
? [unauthorizedBadge()]
|
|
3196
|
+
: []),
|
|
1302
3197
|
),
|
|
1303
3198
|
),
|
|
1304
3199
|
extras.length > 0
|
|
@@ -1335,6 +3230,7 @@ window.__ModuleLoader__.load({
|
|
|
1335
3230
|
{ style: STYLE.unavailableMark },
|
|
1336
3231
|
` · ${t('catalogUnavailable')}`,
|
|
1337
3232
|
),
|
|
3233
|
+
drift(row) ? unauthorizedBadge() : null,
|
|
1338
3234
|
),
|
|
1339
3235
|
),
|
|
1340
3236
|
)
|
|
@@ -1348,14 +3244,19 @@ window.__ModuleLoader__.load({
|
|
|
1348
3244
|
* shipped settings pages' save/conflict model. Pool and ranking
|
|
1349
3245
|
* candidates come from the live model catalog, refreshed whenever the
|
|
1350
3246
|
* Host's adapter set changes. */
|
|
1351
|
-
|
|
3247
|
+
function SwitchmanSettingsPage({ t, locale, setUiLocale }) {
|
|
1352
3248
|
// Re-render on UI-language switches (drives t() and the suggestion).
|
|
1353
3249
|
React.useSyncExternalStore(
|
|
1354
3250
|
(fn) => locale.subscribe(fn),
|
|
1355
3251
|
() => locale.getLocale(),
|
|
1356
3252
|
);
|
|
3253
|
+
// Re-render when the manual interface-locale override changes or a
|
|
3254
|
+
// saved override is restored at startup.
|
|
3255
|
+
React.useSyncExternalStore(subscribeUiLocale, () => uiLocaleVersion);
|
|
1357
3256
|
// Hooks above the availability early-returns keep a stable order.
|
|
1358
3257
|
const headingId = React.useId();
|
|
3258
|
+
const uiHeadingId = React.useId();
|
|
3259
|
+
const uiSelectId = React.useId();
|
|
1359
3260
|
|
|
1360
3261
|
/** Live settings snapshot from the Host route: { status, writable,
|
|
1361
3262
|
* values } — mirrors the configForms snapshot shape the page was
|
|
@@ -1368,6 +3269,10 @@ window.__ModuleLoader__.load({
|
|
|
1368
3269
|
const [saving, setSaving] = React.useState(false);
|
|
1369
3270
|
const [failed, setFailed] = React.useState(false);
|
|
1370
3271
|
const [conflicted, setConflicted] = React.useState(false);
|
|
3272
|
+
/** Last whitelist sync status from the Host config answer: null when
|
|
3273
|
+
* both teams switches are off (the Host omits the field), otherwise
|
|
3274
|
+
* { ok, count, at, error? }. */
|
|
3275
|
+
const [whitelistSync, setWhitelistSync] = React.useState(null);
|
|
1371
3276
|
|
|
1372
3277
|
// Mirror the editable state for async save flows below (setState
|
|
1373
3278
|
// alone is too late inside stale closures).
|
|
@@ -1377,6 +3282,20 @@ window.__ModuleLoader__.load({
|
|
|
1377
3282
|
/** Values this page loaded — the optimistic-concurrency baseline the
|
|
1378
3283
|
* Host route fences writes against. */
|
|
1379
3284
|
const loadedRef = React.useRef(null);
|
|
3285
|
+
/** Unmount guard for the post-save sync-status re-reads. */
|
|
3286
|
+
const syncAlive = React.useRef(true);
|
|
3287
|
+
React.useEffect(() => () => {
|
|
3288
|
+
syncAlive.current = false;
|
|
3289
|
+
}, []);
|
|
3290
|
+
|
|
3291
|
+
/** Re-read the config answer for the whitelist sync status line: the
|
|
3292
|
+
* Host syncs after a successful write, so one immediate and one
|
|
3293
|
+
* delayed read bracket the async window. */
|
|
3294
|
+
const refreshWhitelistSync = React.useCallback(async () => {
|
|
3295
|
+
const response = await api.get('config');
|
|
3296
|
+
if (!syncAlive.current || !response.ok) return;
|
|
3297
|
+
setWhitelistSync(response.value?.whitelistSync ?? null);
|
|
3298
|
+
}, []);
|
|
1380
3299
|
|
|
1381
3300
|
const assignDraft = (next) => {
|
|
1382
3301
|
draftRef.current = next;
|
|
@@ -1392,6 +3311,9 @@ window.__ModuleLoader__.load({
|
|
|
1392
3311
|
if (response.ok && response.value?.values !== undefined) {
|
|
1393
3312
|
loadedRef.current = response.value.values;
|
|
1394
3313
|
setForm({ status: 'ready', writable: true, values: response.value.values });
|
|
3314
|
+
// Whitelist sync status travels beside the values (null
|
|
3315
|
+
// unless both teams switches are on).
|
|
3316
|
+
setWhitelistSync(response.value.whitelistSync ?? null);
|
|
1395
3317
|
} else setForm({ status: 'error', writable: false });
|
|
1396
3318
|
})();
|
|
1397
3319
|
return () => {
|
|
@@ -1432,6 +3354,25 @@ window.__ModuleLoader__.load({
|
|
|
1432
3354
|
}, [loadCatalog]);
|
|
1433
3355
|
const catalogIndex = indexCatalog(catalog.groups);
|
|
1434
3356
|
|
|
3357
|
+
// DSH-side child-model authorization (which routes this session may
|
|
3358
|
+
// name explicitly on subagent/workflow calls): loaded once on mount
|
|
3359
|
+
// beside the catalog. null (failed fetch or unreadable service)
|
|
3360
|
+
// means unknown — no ⚠ badges, no hint.
|
|
3361
|
+
const [authorized, setAuthorized] = React.useState(null);
|
|
3362
|
+
React.useEffect(() => {
|
|
3363
|
+
let alive = true;
|
|
3364
|
+
void (async () => {
|
|
3365
|
+
const response = await api.get('authorized');
|
|
3366
|
+
if (!alive) return;
|
|
3367
|
+
setAuthorized(
|
|
3368
|
+
response.ok ? parseAuthorized(response.value) : null,
|
|
3369
|
+
);
|
|
3370
|
+
})();
|
|
3371
|
+
return () => {
|
|
3372
|
+
alive = false;
|
|
3373
|
+
};
|
|
3374
|
+
}, []);
|
|
3375
|
+
|
|
1435
3376
|
// Numeric watermark editing: one raw-text overlay per field so
|
|
1436
3377
|
// partial input ('', '5', leading zeros) is editable without
|
|
1437
3378
|
// corrupting the draft; parseable integers commit immediately,
|
|
@@ -1467,7 +3408,9 @@ window.__ModuleLoader__.load({
|
|
|
1467
3408
|
!(values.wmSoftTokens < values.wmHardTokens) ||
|
|
1468
3409
|
!(values.wmHardTokens < values.wmForceTokens);
|
|
1469
3410
|
const invalid =
|
|
1470
|
-
(
|
|
3411
|
+
(values.langScope === 'global' &&
|
|
3412
|
+
customActive &&
|
|
3413
|
+
values.langConversation.trim() === '') ||
|
|
1471
3414
|
anyNumberInvalid ||
|
|
1472
3415
|
orderInvalid;
|
|
1473
3416
|
const dirty = !sameValues(current, values);
|
|
@@ -1528,7 +3471,7 @@ window.__ModuleLoader__.load({
|
|
|
1528
3471
|
? pool.filter((route) => routeKey(route) !== key)
|
|
1529
3472
|
: [...pool, { provider: meta.provider, model: meta.model }],
|
|
1530
3473
|
);
|
|
1531
|
-
//
|
|
3474
|
+
// Unchecking a route also drops its pinned effort entry
|
|
1532
3475
|
if (existed) {
|
|
1533
3476
|
const { effortsField } = POOL_FIELDS.find(
|
|
1534
3477
|
(spec) => spec.field === field,
|
|
@@ -1545,7 +3488,7 @@ window.__ModuleLoader__.load({
|
|
|
1545
3488
|
function setAllPool(field, select) {
|
|
1546
3489
|
if (!select) {
|
|
1547
3490
|
edit(field, []);
|
|
1548
|
-
//
|
|
3491
|
+
// Clearing a pool also clears its pinned effort entries
|
|
1549
3492
|
const { effortsField } = POOL_FIELDS.find(
|
|
1550
3493
|
(spec) => spec.field === field,
|
|
1551
3494
|
);
|
|
@@ -1559,7 +3502,8 @@ window.__ModuleLoader__.load({
|
|
|
1559
3502
|
edit(field, [...[...catalogIndex.values()].map(clean), ...extras]);
|
|
1560
3503
|
}
|
|
1561
3504
|
|
|
1562
|
-
/**
|
|
3505
|
+
/** Manual order: swap the route at index with its neighbor
|
|
3506
|
+
* (boundary-guarded). */
|
|
1563
3507
|
function movePoolRoute(field, index, delta) {
|
|
1564
3508
|
const pool = values[field];
|
|
1565
3509
|
const target = index + delta;
|
|
@@ -1572,7 +3516,7 @@ window.__ModuleLoader__.load({
|
|
|
1572
3516
|
})));
|
|
1573
3517
|
}
|
|
1574
3518
|
|
|
1575
|
-
/**
|
|
3519
|
+
/** Manual order: remove the route at index. */
|
|
1576
3520
|
function removePoolRoute(field, index) {
|
|
1577
3521
|
const next = [...values[field]];
|
|
1578
3522
|
const [removed] = next.splice(index, 1);
|
|
@@ -1580,7 +3524,7 @@ window.__ModuleLoader__.load({
|
|
|
1580
3524
|
provider: route.provider,
|
|
1581
3525
|
model: route.model,
|
|
1582
3526
|
})));
|
|
1583
|
-
//
|
|
3527
|
+
// Drop the route's pinned effort entry alongside
|
|
1584
3528
|
const { effortsField } = POOL_FIELDS.find(
|
|
1585
3529
|
(spec) => spec.field === field,
|
|
1586
3530
|
);
|
|
@@ -1592,7 +3536,8 @@ window.__ModuleLoader__.load({
|
|
|
1592
3536
|
);
|
|
1593
3537
|
}
|
|
1594
3538
|
|
|
1595
|
-
/**
|
|
3539
|
+
/** Set/clear a route's pinned effort entry in a pool (effort '' =
|
|
3540
|
+
* remove the entry). */
|
|
1596
3541
|
function setPoolEffort(effortsField, meta, effort) {
|
|
1597
3542
|
const key = routeKey(meta);
|
|
1598
3543
|
const rest = values[effortsField].filter(
|
|
@@ -1653,9 +3598,11 @@ window.__ModuleLoader__.load({
|
|
|
1653
3598
|
if (form.status !== 'ready' || !form.writable || savingRef.current)
|
|
1654
3599
|
return;
|
|
1655
3600
|
const desired = {
|
|
3601
|
+
langScope: values.langScope,
|
|
1656
3602
|
langConversation: values.langConversation.trim(),
|
|
1657
3603
|
langComments: values.langComments,
|
|
1658
3604
|
langDocs: values.langDocs,
|
|
3605
|
+
uiLocale: values.uiLocale,
|
|
1659
3606
|
...Object.fromEntries(
|
|
1660
3607
|
POOL_FIELDS.map(({ field }) => [
|
|
1661
3608
|
field,
|
|
@@ -1689,6 +3636,8 @@ window.__ModuleLoader__.load({
|
|
|
1689
3636
|
wmDenyMode: values.wmDenyMode,
|
|
1690
3637
|
wmAutoHandover: values.wmAutoHandover,
|
|
1691
3638
|
wmSubagentCap: values.wmSubagentCap,
|
|
3639
|
+
teamsMode: values.teamsMode,
|
|
3640
|
+
syncWhitelist: values.syncWhitelist,
|
|
1692
3641
|
};
|
|
1693
3642
|
if (sameValues(current, desired)) {
|
|
1694
3643
|
// Whitespace-only differences: nothing to write, close the draft.
|
|
@@ -1723,6 +3672,17 @@ window.__ModuleLoader__.load({
|
|
|
1723
3672
|
writable: true,
|
|
1724
3673
|
values: response.value.values,
|
|
1725
3674
|
});
|
|
3675
|
+
// The write triggers the whitelist sync Host-side; the answer
|
|
3676
|
+
// may already carry fresh status, and the delayed re-read
|
|
3677
|
+
// covers the async tail.
|
|
3678
|
+
if (response.value?.whitelistSync !== undefined)
|
|
3679
|
+
setWhitelistSync(response.value.whitelistSync);
|
|
3680
|
+
if (desired.syncWhitelist === true) {
|
|
3681
|
+
void refreshWhitelistSync();
|
|
3682
|
+
setTimeout(() => {
|
|
3683
|
+
void refreshWhitelistSync();
|
|
3684
|
+
}, 2000);
|
|
3685
|
+
}
|
|
1726
3686
|
assignDraft(null);
|
|
1727
3687
|
setCustomArmed(false);
|
|
1728
3688
|
clearNumText();
|
|
@@ -1770,6 +3730,9 @@ window.__ModuleLoader__.load({
|
|
|
1770
3730
|
const conversationId = `${headingId}-conversation`;
|
|
1771
3731
|
const commentsId = `${headingId}-comments`;
|
|
1772
3732
|
const docsId = `${headingId}-docs`;
|
|
3733
|
+
const scopeId = `${headingId}-scope`;
|
|
3734
|
+
/** Project scope moves the three slots into per-project files. */
|
|
3735
|
+
const langLocked = values.langScope === 'project';
|
|
1773
3736
|
const suggestion = suggestFromUiLocale(locale.getLocale().active);
|
|
1774
3737
|
|
|
1775
3738
|
/** Status lines under one row's control. */
|
|
@@ -1805,12 +3768,12 @@ window.__ModuleLoader__.load({
|
|
|
1805
3768
|
return lines;
|
|
1806
3769
|
};
|
|
1807
3770
|
|
|
1808
|
-
/** Shared select props (disabled while saving / read-only). */
|
|
1809
|
-
const selectProps = (id, value, onChange) => ({
|
|
3771
|
+
/** Shared select props (disabled while saving / read-only / locked). */
|
|
3772
|
+
const selectProps = (id, value, onChange, locked = false) => ({
|
|
1810
3773
|
id,
|
|
1811
3774
|
value,
|
|
1812
3775
|
onChange: (event) => onChange(event.target.value),
|
|
1813
|
-
disabled: !editable,
|
|
3776
|
+
disabled: !editable || locked,
|
|
1814
3777
|
style: STYLE.control,
|
|
1815
3778
|
});
|
|
1816
3779
|
|
|
@@ -1825,6 +3788,7 @@ window.__ModuleLoader__.load({
|
|
|
1825
3788
|
? CUSTOM
|
|
1826
3789
|
: values.langConversation,
|
|
1827
3790
|
selectConversation,
|
|
3791
|
+
langLocked,
|
|
1828
3792
|
),
|
|
1829
3793
|
...languageOptions(t, { withUnset: 'ask', withCustom: true }),
|
|
1830
3794
|
),
|
|
@@ -1836,7 +3800,7 @@ window.__ModuleLoader__.load({
|
|
|
1836
3800
|
edit('langConversation', event.target.value),
|
|
1837
3801
|
placeholder: t('customLanguagePlaceholder'),
|
|
1838
3802
|
maxLength: LANG_MAX,
|
|
1839
|
-
disabled: !editable,
|
|
3803
|
+
disabled: !editable || langLocked,
|
|
1840
3804
|
'aria-label': t('customLanguage'),
|
|
1841
3805
|
style: STYLE.control,
|
|
1842
3806
|
})
|
|
@@ -1864,9 +3828,30 @@ window.__ModuleLoader__.load({
|
|
|
1864
3828
|
enforce: 'enforceHelpEnforce',
|
|
1865
3829
|
};
|
|
1866
3830
|
const display = rankDisplay(values, catalogIndex);
|
|
3831
|
+
// Teams mode (draft value, consistent with the rest of the page):
|
|
3832
|
+
// gates the ⚠ authorization badges/hint — plain subagent dispatch
|
|
3833
|
+
// names no explicit routes, so drift marks would be noise.
|
|
3834
|
+
const teamsMode = values.teamsMode === true;
|
|
3835
|
+
/** Authorization drift exists when at least one selected pool
|
|
3836
|
+
* route is outside the DSH-authorized child models (or the
|
|
3837
|
+
* whitelist is readable and explicit selection is disabled
|
|
3838
|
+
* while any pool is configured) — drives the section hint.
|
|
3839
|
+
* Teams mode only (see above). */
|
|
3840
|
+
const anyUnauthorized =
|
|
3841
|
+
teamsMode &&
|
|
3842
|
+
authorized !== null &&
|
|
3843
|
+
(authorized.enabled === false
|
|
3844
|
+
? poolsSet > 0
|
|
3845
|
+
: POOL_FIELDS.some(({ field }) =>
|
|
3846
|
+
values[field].some(
|
|
3847
|
+
(route) => !authorized.keys.has(routeKey(route)),
|
|
3848
|
+
),
|
|
3849
|
+
));
|
|
1867
3850
|
|
|
1868
3851
|
// ---- watermark section derived state ----
|
|
1869
3852
|
const wmId = `${headingId}-wm`;
|
|
3853
|
+
// ---- teams section ids ----
|
|
3854
|
+
const teamsId = `${headingId}-teams`;
|
|
1870
3855
|
|
|
1871
3856
|
/** One watermark number input: raw-text overlay over the draft
|
|
1872
3857
|
* value (0 renders as the placeholder for the follow-force row),
|
|
@@ -1955,6 +3940,20 @@ window.__ModuleLoader__.load({
|
|
|
1955
3940
|
)
|
|
1956
3941
|
: null;
|
|
1957
3942
|
|
|
3943
|
+
/** Keys of every route configured across the six pools: the drift
|
|
3944
|
+
* badge is pool-scoped, so rank-only modelRank entries (in no
|
|
3945
|
+
* pool) never carry it. */
|
|
3946
|
+
const poolRouteKeys = new Set(
|
|
3947
|
+
POOL_FIELDS.flatMap(({ field }) => values[field].map(routeKey)),
|
|
3948
|
+
);
|
|
3949
|
+
/** Pool-scoped drift check for rank rows (same semantics as the
|
|
3950
|
+
* PoolCard drift helper, which is not in scope here). Teams mode
|
|
3951
|
+
* only, matching the pool cards. */
|
|
3952
|
+
const rankDrift = (route) =>
|
|
3953
|
+
teamsMode === true &&
|
|
3954
|
+
authorized !== null &&
|
|
3955
|
+
(authorized.enabled === false ||
|
|
3956
|
+
!authorized.keys.has(routeKey(route)));
|
|
1958
3957
|
/** One ranking row: index, label, tier select, move/remove buttons. */
|
|
1959
3958
|
const rankRow = (entry, index) => {
|
|
1960
3959
|
const key = routeKey(entry);
|
|
@@ -1980,6 +3979,17 @@ window.__ModuleLoader__.load({
|
|
|
1980
3979
|
` · ${t('catalogUnavailable')}`,
|
|
1981
3980
|
)
|
|
1982
3981
|
: null,
|
|
3982
|
+
poolRouteKeys.has(key) && rankDrift(entry)
|
|
3983
|
+
? h(
|
|
3984
|
+
'span',
|
|
3985
|
+
{
|
|
3986
|
+
style: STYLE.unauthorizedMark,
|
|
3987
|
+
title: t('unauthorizedBadge'),
|
|
3988
|
+
'aria-label': t('unauthorizedBadge'),
|
|
3989
|
+
},
|
|
3990
|
+
'⚠',
|
|
3991
|
+
)
|
|
3992
|
+
: null,
|
|
1983
3993
|
),
|
|
1984
3994
|
h(
|
|
1985
3995
|
'select',
|
|
@@ -2053,6 +4063,37 @@ window.__ModuleLoader__.load({
|
|
|
2053
4063
|
'div',
|
|
2054
4064
|
{ 'data-dsh-switchman': 'settings', style: STYLE.page },
|
|
2055
4065
|
h('p', { style: STYLE.description }, t('settingsDescription')),
|
|
4066
|
+
h(
|
|
4067
|
+
'section',
|
|
4068
|
+
{ 'aria-labelledby': uiHeadingId, style: STYLE.section },
|
|
4069
|
+
h('h3', { id: uiHeadingId, style: STYLE.heading }, t('uiSectionTitle')),
|
|
4070
|
+
h('p', { style: STYLE.description }, t('uiSectionDescription')),
|
|
4071
|
+
h(
|
|
4072
|
+
'div',
|
|
4073
|
+
{ style: STYLE.rows },
|
|
4074
|
+
h(SettingsRow, {
|
|
4075
|
+
key: 'ui-locale',
|
|
4076
|
+
id: uiSelectId,
|
|
4077
|
+
lines: [],
|
|
4078
|
+
label: t('uiLocaleLabel'),
|
|
4079
|
+
help: t('uiLocaleHelp'),
|
|
4080
|
+
control: h(
|
|
4081
|
+
'select',
|
|
4082
|
+
selectProps(uiSelectId, values.uiLocale ?? 'auto', (value) => {
|
|
4083
|
+
edit('uiLocale', value);
|
|
4084
|
+
setUiLocale?.(value);
|
|
4085
|
+
}),
|
|
4086
|
+
...UI_LOCALE_OPTIONS.map((option) =>
|
|
4087
|
+
h(
|
|
4088
|
+
'option',
|
|
4089
|
+
{ key: option.value, value: option.value },
|
|
4090
|
+
option.value === 'auto' ? t('uiLocaleAuto') : option.label,
|
|
4091
|
+
),
|
|
4092
|
+
),
|
|
4093
|
+
),
|
|
4094
|
+
}),
|
|
4095
|
+
),
|
|
4096
|
+
),
|
|
2056
4097
|
h(
|
|
2057
4098
|
'section',
|
|
2058
4099
|
{ 'aria-labelledby': headingId, style: STYLE.section },
|
|
@@ -2069,6 +4110,34 @@ window.__ModuleLoader__.load({
|
|
|
2069
4110
|
h(
|
|
2070
4111
|
'div',
|
|
2071
4112
|
{ style: STYLE.rows },
|
|
4113
|
+
h(
|
|
4114
|
+
SettingsRow,
|
|
4115
|
+
{
|
|
4116
|
+
key: 'scope',
|
|
4117
|
+
id: scopeId,
|
|
4118
|
+
label: t('langScopeLabel'),
|
|
4119
|
+
help: t('langScopeHelp'),
|
|
4120
|
+
control: h(
|
|
4121
|
+
'select',
|
|
4122
|
+
selectProps(scopeId, values.langScope, (value) =>
|
|
4123
|
+
edit('langScope', value),
|
|
4124
|
+
),
|
|
4125
|
+
h(
|
|
4126
|
+
'option',
|
|
4127
|
+
{ key: 'global', value: 'global' },
|
|
4128
|
+
t('langScopeGlobal'),
|
|
4129
|
+
),
|
|
4130
|
+
h(
|
|
4131
|
+
'option',
|
|
4132
|
+
{ key: 'project', value: 'project' },
|
|
4133
|
+
t('langScopeProject'),
|
|
4134
|
+
),
|
|
4135
|
+
),
|
|
4136
|
+
lines: langLocked
|
|
4137
|
+
? [{ text: t('langProjectNote'), invalid: false }]
|
|
4138
|
+
: [],
|
|
4139
|
+
},
|
|
4140
|
+
),
|
|
2072
4141
|
h(
|
|
2073
4142
|
SettingsRow,
|
|
2074
4143
|
{
|
|
@@ -2093,6 +4162,7 @@ window.__ModuleLoader__.load({
|
|
|
2093
4162
|
commentsId,
|
|
2094
4163
|
values.langComments,
|
|
2095
4164
|
(value) => edit('langComments', value),
|
|
4165
|
+
langLocked,
|
|
2096
4166
|
),
|
|
2097
4167
|
...languageOptions(t, { withUnset: 'follow' }),
|
|
2098
4168
|
),
|
|
@@ -2112,6 +4182,7 @@ window.__ModuleLoader__.load({
|
|
|
2112
4182
|
docsId,
|
|
2113
4183
|
values.langDocs,
|
|
2114
4184
|
(value) => edit('langDocs', value),
|
|
4185
|
+
langLocked,
|
|
2115
4186
|
),
|
|
2116
4187
|
...languageOptions(t, { withUnset: 'follow' }),
|
|
2117
4188
|
),
|
|
@@ -2146,6 +4217,13 @@ window.__ModuleLoader__.load({
|
|
|
2146
4217
|
}),
|
|
2147
4218
|
),
|
|
2148
4219
|
catalogNotice,
|
|
4220
|
+
anyUnauthorized
|
|
4221
|
+
? h(
|
|
4222
|
+
'p',
|
|
4223
|
+
{ key: 'unauthorized', role: 'status', style: STYLE.progress },
|
|
4224
|
+
t('unauthorizedHint'),
|
|
4225
|
+
)
|
|
4226
|
+
: null,
|
|
2149
4227
|
h(
|
|
2150
4228
|
'div',
|
|
2151
4229
|
{ style: STYLE.poolGrid },
|
|
@@ -2164,6 +4242,8 @@ window.__ModuleLoader__.load({
|
|
|
2164
4242
|
efforts: values[effortsField],
|
|
2165
4243
|
manual: values[manualField],
|
|
2166
4244
|
editable,
|
|
4245
|
+
authorized,
|
|
4246
|
+
teamsMode,
|
|
2167
4247
|
onToggle: (meta) => {
|
|
2168
4248
|
togglePool(field, meta);
|
|
2169
4249
|
},
|
|
@@ -2333,6 +4413,102 @@ window.__ModuleLoader__.load({
|
|
|
2333
4413
|
),
|
|
2334
4414
|
h('p', { style: STYLE.progress }, t('wmCommands')),
|
|
2335
4415
|
),
|
|
4416
|
+
h(
|
|
4417
|
+
'section',
|
|
4418
|
+
{
|
|
4419
|
+
'aria-labelledby': teamsId,
|
|
4420
|
+
style: { ...STYLE.section, ...STYLE.sectionDivider },
|
|
4421
|
+
},
|
|
4422
|
+
h(
|
|
4423
|
+
'h3',
|
|
4424
|
+
{ id: teamsId, style: STYLE.heading },
|
|
4425
|
+
t('teamsSectionTitle'),
|
|
4426
|
+
),
|
|
4427
|
+
h(
|
|
4428
|
+
'p',
|
|
4429
|
+
{ style: STYLE.description },
|
|
4430
|
+
t('teamsSectionDescription'),
|
|
4431
|
+
),
|
|
4432
|
+
h(
|
|
4433
|
+
'div',
|
|
4434
|
+
{ style: STYLE.rows },
|
|
4435
|
+
h(SettingsRow, {
|
|
4436
|
+
key: 'teamsMode',
|
|
4437
|
+
id: `${teamsId}-mode`,
|
|
4438
|
+
label: t('teamsModeLabel'),
|
|
4439
|
+
help: t('teamsModeHelp'),
|
|
4440
|
+
control: h('input', {
|
|
4441
|
+
type: 'checkbox',
|
|
4442
|
+
id: `${teamsId}-mode`,
|
|
4443
|
+
checked: values.teamsMode,
|
|
4444
|
+
onChange: () => {
|
|
4445
|
+
edit('teamsMode', !values.teamsMode);
|
|
4446
|
+
},
|
|
4447
|
+
disabled: !editable,
|
|
4448
|
+
style: STYLE.checkbox,
|
|
4449
|
+
}),
|
|
4450
|
+
lines: [],
|
|
4451
|
+
}),
|
|
4452
|
+
h(SettingsRow, {
|
|
4453
|
+
key: 'syncWhitelist',
|
|
4454
|
+
id: `${teamsId}-sync`,
|
|
4455
|
+
label: t('syncWhitelistLabel'),
|
|
4456
|
+
help: t('syncWhitelistHelp'),
|
|
4457
|
+
control: h('input', {
|
|
4458
|
+
type: 'checkbox',
|
|
4459
|
+
id: `${teamsId}-sync`,
|
|
4460
|
+
checked: values.syncWhitelist,
|
|
4461
|
+
onChange: () => {
|
|
4462
|
+
edit('syncWhitelist', !values.syncWhitelist);
|
|
4463
|
+
},
|
|
4464
|
+
disabled: !editable,
|
|
4465
|
+
style: STYLE.checkbox,
|
|
4466
|
+
}),
|
|
4467
|
+
// Status line reads the Host-reported sync state;
|
|
4468
|
+
// visible whenever the (independent) sync switch
|
|
4469
|
+
// is on — the only shape the Host reports for.
|
|
4470
|
+
lines:
|
|
4471
|
+
values.syncWhitelist === true
|
|
4472
|
+
? [
|
|
4473
|
+
whitelistSync == null
|
|
4474
|
+
? {
|
|
4475
|
+
text: t('whitelistSyncPending'),
|
|
4476
|
+
invalid: false,
|
|
4477
|
+
}
|
|
4478
|
+
: whitelistSync.ok === true
|
|
4479
|
+
? {
|
|
4480
|
+
text: t('whitelistSyncOk', {
|
|
4481
|
+
count: whitelistSync.count ?? 0,
|
|
4482
|
+
time:
|
|
4483
|
+
typeof whitelistSync.at ===
|
|
4484
|
+
'number' &&
|
|
4485
|
+
whitelistSync.at > 0
|
|
4486
|
+
? new Date(
|
|
4487
|
+
whitelistSync.at,
|
|
4488
|
+
).toLocaleString()
|
|
4489
|
+
: '—',
|
|
4490
|
+
}),
|
|
4491
|
+
invalid: false,
|
|
4492
|
+
}
|
|
4493
|
+
: {
|
|
4494
|
+
text: t('whitelistSyncError', {
|
|
4495
|
+
error:
|
|
4496
|
+
typeof whitelistSync.error ===
|
|
4497
|
+
'string' &&
|
|
4498
|
+
whitelistSync.error !== ''
|
|
4499
|
+
? whitelistSync.error
|
|
4500
|
+
: 'unknown',
|
|
4501
|
+
}),
|
|
4502
|
+
invalid: true,
|
|
4503
|
+
},
|
|
4504
|
+
]
|
|
4505
|
+
: [],
|
|
4506
|
+
}),
|
|
4507
|
+
),
|
|
4508
|
+
teamsMode
|
|
4509
|
+
? h('p', { style: STYLE.progress }, t('whitelistSyncNote'))
|
|
4510
|
+
: null,
|
|
4511
|
+
),
|
|
2336
4512
|
h(
|
|
2337
4513
|
'div',
|
|
2338
4514
|
{ style: STYLE.footer },
|
|
@@ -2397,7 +4573,82 @@ window.__ModuleLoader__.load({
|
|
|
2397
4573
|
inject: ['slots', 'locale'],
|
|
2398
4574
|
apply(ctx) {
|
|
2399
4575
|
ctx.effect(() => ctx.locale.register(NS, DICTS));
|
|
2400
|
-
const
|
|
4576
|
+
const baseT = ctx.locale.bind(NS);
|
|
4577
|
+
// Manual interface-locale override: "auto" keeps following the
|
|
4578
|
+
// DSH app language (baseT); any other value resolves this
|
|
4579
|
+
// plugin's own strings from DICTS (zh/en) or the inline
|
|
4580
|
+
// EXTRA_UI_DICTS table. Every failure path degrades back to
|
|
4581
|
+
// baseT — never a hard error.
|
|
4582
|
+
let uiLocale = 'auto';
|
|
4583
|
+
const formatUiValue = (text, params) =>
|
|
4584
|
+
typeof params === 'object' && params !== null
|
|
4585
|
+
? text.replace(/\{(\w+)\}/g, (match, name) =>
|
|
4586
|
+
name in params ? String(params[name]) : match,
|
|
4587
|
+
)
|
|
4588
|
+
: text;
|
|
4589
|
+
const warnedUiTags = new Set();
|
|
4590
|
+
const dictForUiLocale = (tag) => {
|
|
4591
|
+
if (tag === 'en' || tag === 'zh') return DICTS[tag];
|
|
4592
|
+
const dict = EXTRA_UI_DICTS[tag];
|
|
4593
|
+
if (dict === undefined && !warnedUiTags.has(tag)) {
|
|
4594
|
+
warnedUiTags.add(tag);
|
|
4595
|
+
console.warn('[dsh-switchman] no inline UI dictionary for locale', tag);
|
|
4596
|
+
}
|
|
4597
|
+
return dict ?? null;
|
|
4598
|
+
};
|
|
4599
|
+
const t = (key, params) => {
|
|
4600
|
+
if (uiLocale !== 'auto') {
|
|
4601
|
+
const text = dictForUiLocale(uiLocale)?.[key];
|
|
4602
|
+
if (typeof text === 'string') return formatUiValue(text, params);
|
|
4603
|
+
}
|
|
4604
|
+
return baseT(key, params);
|
|
4605
|
+
};
|
|
4606
|
+
/** Apply an interface-locale choice immediately (preview
|
|
4607
|
+
* before the settings write lands) and wake every subscribed
|
|
4608
|
+
* component. All dictionaries are inline, so the switch
|
|
4609
|
+
* paints on the next render — no async gap. */
|
|
4610
|
+
const applyUiLocale = (tag) => {
|
|
4611
|
+
if (tag === uiLocale) return;
|
|
4612
|
+
uiLocale = tag;
|
|
4613
|
+
notifyUiLocale();
|
|
4614
|
+
};
|
|
4615
|
+
// Report the active UI locale to the host half (it decides the
|
|
4616
|
+
// question language for the language-preference prompt;
|
|
4617
|
+
// fire-and-forget, silent on failure — the host falls back to
|
|
4618
|
+
// the settings' locale.preference, then to English). One extra
|
|
4619
|
+
// report after 3s covers the startup window where the host
|
|
4620
|
+
// routes become ready after this page.
|
|
4621
|
+
const reportUiLocale = () =>
|
|
4622
|
+
void api.post('ui-locale', {
|
|
4623
|
+
locale:
|
|
4624
|
+
uiLocale !== 'auto'
|
|
4625
|
+
? uiLocale
|
|
4626
|
+
: ctx.locale?.getLocale?.().active ?? '',
|
|
4627
|
+
});
|
|
4628
|
+
reportUiLocale();
|
|
4629
|
+
setTimeout(reportUiLocale, 3000);
|
|
4630
|
+
// Pick up a saved interface-locale override at startup so the
|
|
4631
|
+
// badge and panels already render in it without a settings
|
|
4632
|
+
// visit. Fail-open: any error keeps the DSH app language.
|
|
4633
|
+
void (async () => {
|
|
4634
|
+
try {
|
|
4635
|
+
const reply = await api.get('config');
|
|
4636
|
+
const tag = reply.value?.values?.uiLocale;
|
|
4637
|
+
if (reply.ok && typeof tag === 'string' && tag !== 'auto' && tag !== '') {
|
|
4638
|
+
applyUiLocale(tag);
|
|
4639
|
+
// The override may have landed after the initial
|
|
4640
|
+
// report went out; re-report the effective locale
|
|
4641
|
+
// so the host prompt language matches what the
|
|
4642
|
+
// user actually sees.
|
|
4643
|
+
reportUiLocale();
|
|
4644
|
+
}
|
|
4645
|
+
} catch {
|
|
4646
|
+
/* fail-open: keep the DSH app language */
|
|
4647
|
+
}
|
|
4648
|
+
})();
|
|
4649
|
+
// The session scope hands the badge the standard kit: the open
|
|
4650
|
+
// session's id and its live projection face (the model line),
|
|
4651
|
+
// plus the sessions service for the un-retained fallback.
|
|
2401
4652
|
ctx.slots.inject('conversation.session.header.actions', () =>
|
|
2402
4653
|
ctx.slots.register(
|
|
2403
4654
|
{
|
|
@@ -2405,7 +4656,60 @@ window.__ModuleLoader__.load({
|
|
|
2405
4656
|
id: 'dsh-switchman',
|
|
2406
4657
|
order: -9,
|
|
2407
4658
|
},
|
|
2408
|
-
() =>
|
|
4659
|
+
(kit) =>
|
|
4660
|
+
h(SwitchmanBadge, {
|
|
4661
|
+
...kit,
|
|
4662
|
+
locale: ctx.locale,
|
|
4663
|
+
t,
|
|
4664
|
+
}),
|
|
4665
|
+
),
|
|
4666
|
+
);
|
|
4667
|
+
// Home left-sidebar entry + central panel: the same slot pair
|
|
4668
|
+
// the shipped Skills Center row uses. The shell owns the row
|
|
4669
|
+
// button, click-to-switch, active highlight, and collapsed
|
|
4670
|
+
// tooltip. The sidebar id and the main key must match, and
|
|
4671
|
+
// the inject() face becomes the page component's props
|
|
4672
|
+
// ({t, locale} — SwitchmanPanelPage forwards them verbatim).
|
|
4673
|
+
// order 31 sits directly under the Skills Center row
|
|
4674
|
+
// (skill-explorer 30; plugins 0, schedules 10).
|
|
4675
|
+
ctx.slots.inject('sidebar.panellist', () =>
|
|
4676
|
+
ctx.slots.register(
|
|
4677
|
+
{
|
|
4678
|
+
name: 'sidebar.panellist',
|
|
4679
|
+
id: 'dsh-switchman',
|
|
4680
|
+
order: 31,
|
|
4681
|
+
label: () => t('panelLabel'),
|
|
4682
|
+
locale: NS,
|
|
4683
|
+
},
|
|
4684
|
+
SwitchmanPanelIcon,
|
|
4685
|
+
),
|
|
4686
|
+
);
|
|
4687
|
+
ctx.slots.inject('main', () =>
|
|
4688
|
+
ctx.slots.register(
|
|
4689
|
+
{
|
|
4690
|
+
name: 'main',
|
|
4691
|
+
key: 'dsh-switchman',
|
|
4692
|
+
inject: () => ({ t, locale: ctx.locale, setUiLocale: applyUiLocale }),
|
|
4693
|
+
},
|
|
4694
|
+
SwitchmanPanelPage,
|
|
4695
|
+
),
|
|
4696
|
+
);
|
|
4697
|
+
// Composer-adjacent vision entry (conversation.input.dock: the
|
|
4698
|
+
// full-width list ABOVE the composer card): guidance chip while
|
|
4699
|
+
// the current session's model cannot read images, plus reactive
|
|
4700
|
+
// auto-conversion of refused image sends into /vision submits.
|
|
4701
|
+
// The session scope automatically provides
|
|
4702
|
+
// inputActions/useInput/useSession to the registered
|
|
4703
|
+
// component; the wrapper forwards that standard kit through
|
|
4704
|
+
// alongside the closure-bound t.
|
|
4705
|
+
ctx.slots.inject('conversation.input.dock', () =>
|
|
4706
|
+
ctx.slots.register(
|
|
4707
|
+
{
|
|
4708
|
+
name: 'conversation.input.dock',
|
|
4709
|
+
id: 'dsh-switchman-vision-hint',
|
|
4710
|
+
order: 90,
|
|
4711
|
+
},
|
|
4712
|
+
(kit) => h(VisionDockEntry, { ...kit, t }),
|
|
2409
4713
|
),
|
|
2410
4714
|
);
|
|
2411
4715
|
// Settings page: one settings.section entry. The restricted
|
|
@@ -2420,7 +4724,7 @@ window.__ModuleLoader__.load({
|
|
|
2420
4724
|
order: 50,
|
|
2421
4725
|
label: () => t('settingsTitle'),
|
|
2422
4726
|
},
|
|
2423
|
-
() => h(SwitchmanSettingsPage, { t, locale: ctx.locale }),
|
|
4727
|
+
() => h(SwitchmanSettingsPage, { t, locale: ctx.locale, setUiLocale: applyUiLocale }),
|
|
2424
4728
|
),
|
|
2425
4729
|
);
|
|
2426
4730
|
// The same configuration surface on the bundle's own Plugins
|
|
@@ -2432,7 +4736,7 @@ window.__ModuleLoader__.load({
|
|
|
2432
4736
|
name: 'plugins.bundle.config',
|
|
2433
4737
|
key: 'dsh-switchman',
|
|
2434
4738
|
},
|
|
2435
|
-
() => h(SwitchmanSettingsPage, { t, locale: ctx.locale }),
|
|
4739
|
+
() => h(SwitchmanSettingsPage, { t, locale: ctx.locale, setUiLocale: applyUiLocale }),
|
|
2436
4740
|
),
|
|
2437
4741
|
);
|
|
2438
4742
|
},
|