@ran-sh/dsh-crew 1.5.1 → 1.6.1
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/.claude-plugin/plugin.json +1 -1
- package/lib/client.js +2 -905
- package/official-web-bridge/lib/client.js +1 -71
- package/package.json +1 -1
- package/src/client/collapsible-sections.mjs +5 -7
- package/src/client/index.tsx +3 -357
- package/src/client/quick-entry.tsx +1 -1
- package/src/client/quick-panel.tsx +3 -38
- package/src/client/surface-detection.mjs +1 -1
- package/src/hub/index.mjs +1 -76
- package/src/i18n.mjs +1 -1
- package/src/install/install-legacy.mjs +728 -739
- package/src/policy-legacy.mjs +1 -51
- package/src/provider-inventory.mjs +1 -3
- package/src/runtime-controls.mjs +1 -7
- package/src/runtime-identity.mjs +1 -1
- package/src/server.mjs +1 -2
- package/src/image-output.mjs +0 -71
- package/src/multimodal.mjs +0 -686
- package/src/vision-route.mjs +0 -138
|
@@ -4,7 +4,7 @@ import { PanelHeader, PanelStyles } from './panel-chrome';
|
|
|
4
4
|
// DSH Crew QUICK CONTROLS panel for the official 3080 surface.
|
|
5
5
|
//
|
|
6
6
|
// Narrow by design: only the user-facing master switch, flash/pro model
|
|
7
|
-
// priority lists
|
|
7
|
+
// priority lists — all other operations belong
|
|
8
8
|
// to the native 3210 full control plane. Talks only to the quick endpoints
|
|
9
9
|
// (/_dsh/dsh-crew/quick-config, /quick-status). Runtime maintenance stays on 3210.
|
|
10
10
|
|
|
@@ -17,17 +17,9 @@ type QuickConfig = {
|
|
|
17
17
|
subagents_enabled?: boolean;
|
|
18
18
|
flash_model_priority?: ModelEntry[];
|
|
19
19
|
pro_model_priority?: ModelEntry[];
|
|
20
|
-
vision_enabled?: boolean;
|
|
21
|
-
imagegen_enabled?: boolean;
|
|
22
|
-
vision_provider?: string;
|
|
23
|
-
imagegen_provider?: string;
|
|
24
20
|
};
|
|
25
21
|
|
|
26
22
|
const RESTART_KEYS = new Set([
|
|
27
|
-
'vision_enabled',
|
|
28
|
-
'imagegen_enabled',
|
|
29
|
-
'vision_provider',
|
|
30
|
-
'imagegen_provider',
|
|
31
23
|
]);
|
|
32
24
|
|
|
33
25
|
const T = {
|
|
@@ -48,10 +40,7 @@ const T = {
|
|
|
48
40
|
flash: 'Worker / Flash',
|
|
49
41
|
pro: 'Reviewer / Pro',
|
|
50
42
|
addModel: '+ 添加模型',
|
|
51
|
-
|
|
52
|
-
vision: '视觉',
|
|
53
|
-
imagegen: '生图',
|
|
54
|
-
provider: 'Provider',
|
|
43
|
+
provider: 'Provider',
|
|
55
44
|
applyRestart: '应用并重启 Crew',
|
|
56
45
|
savedNeedsRestart: '配置已保存 · 需要重启 Crew 才会生效',
|
|
57
46
|
saved: '已保存',
|
|
@@ -76,9 +65,6 @@ const T = {
|
|
|
76
65
|
flash: 'Worker / Flash',
|
|
77
66
|
pro: 'Reviewer / Pro',
|
|
78
67
|
addModel: '+ Add model',
|
|
79
|
-
multimodal: 'Multimodal',
|
|
80
|
-
vision: 'Vision',
|
|
81
|
-
imagegen: 'Imagegen',
|
|
82
68
|
provider: 'Provider',
|
|
83
69
|
applyRestart: 'Apply & restart Crew',
|
|
84
70
|
savedNeedsRestart: 'Saved · restart Crew to take effect',
|
|
@@ -167,15 +153,11 @@ export function QuickPanel({ ctx }: { ctx: any }) {
|
|
|
167
153
|
} finally { setBusy(false); }
|
|
168
154
|
}, [t]);
|
|
169
155
|
|
|
170
|
-
const toggle = (key: 'subagents_enabled'
|
|
156
|
+
const toggle = (key: 'subagents_enabled', value: boolean) => {
|
|
171
157
|
setConfig((c) => ({ ...(c ?? {}), [key]: value }));
|
|
172
158
|
void patch({ [key]: value } as QuickConfig);
|
|
173
159
|
};
|
|
174
160
|
|
|
175
|
-
const setProvider = (key: 'vision_provider' | 'imagegen_provider', value: string) => {
|
|
176
|
-
setConfig((c) => ({ ...(c ?? {}), [key]: value }));
|
|
177
|
-
void patch({ [key]: value } as QuickConfig);
|
|
178
|
-
};
|
|
179
161
|
|
|
180
162
|
const moveModel = (listKey: 'flash_model_priority' | 'pro_model_priority', index: number, dir: -1 | 1) => {
|
|
181
163
|
const list = [...((config?.[listKey] as ModelEntry[] | undefined) ?? [])];
|
|
@@ -268,23 +250,6 @@ export function QuickPanel({ ctx }: { ctx: any }) {
|
|
|
268
250
|
</div>
|
|
269
251
|
{modelList('flash_model_priority', t.flash)}
|
|
270
252
|
{modelList('pro_model_priority', t.pro)}
|
|
271
|
-
<details className="crew-quick-group">
|
|
272
|
-
<summary><strong>{t.multimodal}</strong><span className="crew-quick-count">{t.vision} / {t.imagegen}</span></summary>
|
|
273
|
-
<div className="crew-quick-content">
|
|
274
|
-
<div className="crew-quick-media">
|
|
275
|
-
<label><input type="checkbox" disabled={busy} checked={config.vision_enabled === true}
|
|
276
|
-
onChange={(e) => toggle('vision_enabled', e.target.checked)} /> {t.vision}</label>
|
|
277
|
-
<input className="crew-quick-input" aria-label={`${t.vision} Provider`} placeholder={t.provider} disabled={busy} defaultValue={config.vision_provider ?? ''} key={`vision-${config.vision_provider ?? ''}`}
|
|
278
|
-
onBlur={(e) => setProvider('vision_provider', e.target.value)} />
|
|
279
|
-
</div>
|
|
280
|
-
<div className="crew-quick-media">
|
|
281
|
-
<label><input type="checkbox" disabled={busy} checked={config.imagegen_enabled === true}
|
|
282
|
-
onChange={(e) => toggle('imagegen_enabled', e.target.checked)} /> {t.imagegen}</label>
|
|
283
|
-
<input className="crew-quick-input" aria-label={`${t.imagegen} Provider`} placeholder={t.provider} disabled={busy} defaultValue={config.imagegen_provider ?? ''}
|
|
284
|
-
onBlur={(e) => setProvider('imagegen_provider', e.target.value)} />
|
|
285
|
-
</div>
|
|
286
|
-
</div>
|
|
287
|
-
</details>
|
|
288
253
|
{restartPending && (
|
|
289
254
|
<div className="crew-quick-row">
|
|
290
255
|
<a className="crew-quick-btn primary" href={FULL} target="_blank" rel="noopener noreferrer">{t.openFull}</a>
|
|
@@ -26,7 +26,7 @@ export function classifyCrewSurface({ bridgeStatus, runtime } = {}) {
|
|
|
26
26
|
/**
|
|
27
27
|
* Surface capability model. The NATIVE 3210 Crew harness is the single full
|
|
28
28
|
* control plane; the OFFICIAL 3080 surface is a narrow quick-controls panel
|
|
29
|
-
* (total switch
|
|
29
|
+
* (total switch and the flash/pro model priority lists) plus a
|
|
30
30
|
* deep link back to 3210. Unknown surfaces get diagnostics only — never write
|
|
31
31
|
* authority. This replaces the old binary full-vs-minimal assumption.
|
|
32
32
|
*/
|
package/src/hub/index.mjs
CHANGED
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
normalizeGlobalConfig,
|
|
13
13
|
chooseDefaultTier,
|
|
14
14
|
normalizeWorkerProviderMode,
|
|
15
|
-
getMultimodalRegistrationPlan,
|
|
16
15
|
canDispatchRole,
|
|
17
16
|
resolveModelPolicy,
|
|
18
17
|
resolveRoleTierHint,
|
|
@@ -112,10 +111,6 @@ export const QUICK_CONFIG_KEYS = Object.freeze([
|
|
|
112
111
|
'subagents_enabled',
|
|
113
112
|
'flash_model_priority',
|
|
114
113
|
'pro_model_priority',
|
|
115
|
-
'vision_enabled',
|
|
116
|
-
'imagegen_enabled',
|
|
117
|
-
'vision_provider',
|
|
118
|
-
'imagegen_provider',
|
|
119
114
|
]);
|
|
120
115
|
const LEGACY_TIER_MODELS = { flash: 'deepseek-v4-flash', pro: 'deepseek-v4-pro' };
|
|
121
116
|
// Local copy (the hub must not import jobs.mjs, which pulls the DSH SDK into
|
|
@@ -1366,39 +1361,6 @@ export async function apply(ctx) {
|
|
|
1366
1361
|
while (credentialPurgePlans.size > 32) credentialPurgePlans.delete(credentialPurgePlans.keys().next().value);
|
|
1367
1362
|
};
|
|
1368
1363
|
|
|
1369
|
-
// Multimodal bridge: register describe_image / generate_image for the DS
|
|
1370
|
-
// model. Config is read per call so settings-page edits apply live; the
|
|
1371
|
-
// capability switches (vision_enabled / imagegen_enabled) decide which tools
|
|
1372
|
-
// are registered at plugin boot, so toggling them takes effect on restart.
|
|
1373
|
-
try {
|
|
1374
|
-
const { createMultimodalTools } = await import('../multimodal.mjs');
|
|
1375
|
-
const { readGlobalConfig } = await import('../install/install.mjs');
|
|
1376
|
-
const plan = getMultimodalRegistrationPlan(normalizeGlobalConfig(readGlobalConfig()));
|
|
1377
|
-
for (const tool of createMultimodalTools(() => readGlobalConfig())) {
|
|
1378
|
-
if (!plan.tools[tool.name]) {
|
|
1379
|
-
ctx.logger?.info?.(`dsh-crew: ${tool.name} not registered (disabled by capability switch)`);
|
|
1380
|
-
continue;
|
|
1381
|
-
}
|
|
1382
|
-
disposers.push(ctx.effect(() => ctx.tools.register(tool), `dsh-crew: ${tool.name} tool`));
|
|
1383
|
-
}
|
|
1384
|
-
} catch (err) {
|
|
1385
|
-
ctx.logger?.warn?.(`dsh-crew: multimodal tools unavailable: ${err?.message ?? err}`);
|
|
1386
|
-
}
|
|
1387
|
-
|
|
1388
|
-
// Vision route: image paste on the text-only DS models (admission adapter +
|
|
1389
|
-
// pre-step transcription). Installed only while Crew Vision is enabled.
|
|
1390
|
-
try {
|
|
1391
|
-
const { installVisionRoute } = await import('../vision-route.mjs');
|
|
1392
|
-
const { readGlobalConfig } = await import('../install/install.mjs');
|
|
1393
|
-
if (getMultimodalRegistrationPlan(normalizeGlobalConfig(readGlobalConfig())).visionRoute) {
|
|
1394
|
-
disposers.push(installVisionRoute(ctx, () => readGlobalConfig()));
|
|
1395
|
-
} else {
|
|
1396
|
-
ctx.logger?.info?.('dsh-crew: vision route not installed (Crew Vision disabled by capability switch)');
|
|
1397
|
-
}
|
|
1398
|
-
} catch (err) {
|
|
1399
|
-
ctx.logger?.warn?.(`dsh-crew: vision route unavailable: ${err?.message ?? err}`);
|
|
1400
|
-
}
|
|
1401
|
-
|
|
1402
1364
|
ctx.inject(['webServer'], (webCtx) => {
|
|
1403
1365
|
const webServer = webCtx.webServer;
|
|
1404
1366
|
const disposers = [];
|
|
@@ -2676,43 +2638,6 @@ export async function apply(ctx) {
|
|
|
2676
2638
|
},
|
|
2677
2639
|
}));
|
|
2678
2640
|
|
|
2679
|
-
disposers.push(webServer.register({
|
|
2680
|
-
kind: 'exact', path: `${ROUTE_BASE}/vision-models`,
|
|
2681
|
-
handler: async (req, res) => {
|
|
2682
|
-
if (!isLoopbackRequest(req)) return sendJson(res, 403, { ok: false, error: 'loopback only' });
|
|
2683
|
-
try {
|
|
2684
|
-
const url = new URL(req.url, 'http://localhost');
|
|
2685
|
-
const provider = url.searchParams.get('provider');
|
|
2686
|
-
const force = url.searchParams.get('refresh') === '1';
|
|
2687
|
-
const lang = url.searchParams.get('lang');
|
|
2688
|
-
adoptLang(lang);
|
|
2689
|
-
const { listVisionModels } = await import('../multimodal.mjs');
|
|
2690
|
-
const { readGlobalConfig } = await import('../install/install.mjs');
|
|
2691
|
-
return sendJson(res, 200, { ok: true, models: await listVisionModels(provider, force, () => readGlobalConfig(), lang) });
|
|
2692
|
-
} catch (err) {
|
|
2693
|
-
return sendJson(res, 500, { ok: false, error: err?.message ?? String(err) });
|
|
2694
|
-
}
|
|
2695
|
-
},
|
|
2696
|
-
}));
|
|
2697
|
-
|
|
2698
|
-
disposers.push(webServer.register({
|
|
2699
|
-
kind: 'exact', path: `${ROUTE_BASE}/provider-test`,
|
|
2700
|
-
handler: async (req, res) => {
|
|
2701
|
-
if (!isLoopbackRequest(req)) return sendJson(res, 403, { ok: false, error: 'loopback only' });
|
|
2702
|
-
if (req.method !== 'POST') return sendJson(res, 405, { ok: false, error: 'POST only' });
|
|
2703
|
-
try {
|
|
2704
|
-
// The entry comes from the panel form so unsaved edits can be probed.
|
|
2705
|
-
const entry = await readBody(req);
|
|
2706
|
-
adoptLang(entry?.lang);
|
|
2707
|
-
const { testProvider } = await import('../multimodal.mjs');
|
|
2708
|
-
const result = await testProvider(entry, entry?.lang);
|
|
2709
|
-
return sendJson(res, 200, { ok: true, result });
|
|
2710
|
-
} catch (err) {
|
|
2711
|
-
return sendJson(res, 500, { ok: false, error: err?.message ?? String(err) });
|
|
2712
|
-
}
|
|
2713
|
-
},
|
|
2714
|
-
}));
|
|
2715
|
-
|
|
2716
2641
|
disposers.push(webServer.register({
|
|
2717
2642
|
kind: 'exact', path: `${ROUTE_BASE}/install/status`,
|
|
2718
2643
|
handler: async (req, res) => {
|
|
@@ -2761,7 +2686,7 @@ export async function apply(ctx) {
|
|
|
2761
2686
|
return () => { for (const d of disposers.reverse()) d(); };
|
|
2762
2687
|
});
|
|
2763
2688
|
|
|
2764
|
-
ctx.logger?.info?.('dsh-crew hub mounted (jobs API + installer endpoints
|
|
2689
|
+
ctx.logger?.info?.('dsh-crew hub mounted (jobs API + installer endpoints)');
|
|
2765
2690
|
return async () => {
|
|
2766
2691
|
for (const d of disposers.reverse()) { try { d(); } catch {} }
|
|
2767
2692
|
await hub.dispose();
|
package/src/i18n.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Server-side locale for strings that reach the user: connectivity-test
|
|
2
|
-
// reports, model-list labels
|
|
2
|
+
// reports, model-list labels and error messages.
|
|
3
3
|
//
|
|
4
4
|
// The panel owns the authoritative locale (DSH's setting may be absent, in
|
|
5
5
|
// which case the browser decides), so it passes `lang` with every request and
|