dsh-bots 0.2.12 → 0.2.14
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/lib/client.js +150 -3
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -272,7 +272,12 @@
|
|
|
272
272
|
const StateDot = NATIVE.StateDot ?? null;
|
|
273
273
|
// ---- CSS: own stable class names, values mirrored from the shell ----
|
|
274
274
|
const CSS = `
|
|
275
|
-
|
|
275
|
+
/* The native regionArea bleeds right by --dsh-sidebar-inline-padding
|
|
276
|
+
(margin-right: -12px, ui-sidebar.js) for its own scroll model; our rows
|
|
277
|
+
don't follow that bleed, so pull the nav back inside the padded column —
|
|
278
|
+
verified in the live page: removing the parent's margin-right reads
|
|
279
|
+
"normal", this counter-margin is the same geometry from our side. */
|
|
280
|
+
.dbs-nav{flex:1;min-height:0;display:flex;flex-direction:column;gap:2px;font-family:var(--dsw-font-family,inherit);margin-right:var(--dsh-sidebar-inline-padding,12px)}
|
|
276
281
|
.dbs-navGroup{display:flex;flex-direction:column;min-height:0}
|
|
277
282
|
.dbs-navGroup[data-open="true"]{flex:1 1 auto}
|
|
278
283
|
.dbs-navGroup[data-open="false"]{flex:none}
|
|
@@ -323,6 +328,7 @@
|
|
|
323
328
|
.dbs-fileChip{display:inline-flex;align-items:center;gap:5px;padding:3px 10px;border-radius:999px;background:var(--dsw-alias-interactive-bg-hover);font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary);cursor:pointer;max-width:100%;user-select:none}
|
|
324
329
|
.dbs-fileChip:hover{color:var(--dsw-alias-label-primary)}
|
|
325
330
|
.dbs-fileChipName{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
331
|
+
.dbs-setLabel{font-size:12px;line-height:16px;color:var(--dsw-alias-label-tertiary);margin:8px 0 4px}
|
|
326
332
|
.dbs-chatbar{flex:none;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-bottom:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08))}
|
|
327
333
|
.dbs-chatbarName{font-size:14px;line-height:20px;font-weight:600;color:var(--dsw-alias-label-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
|
|
328
334
|
.dbs-scrollBody{scrollbar-gutter:stable;flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden auto}
|
|
@@ -458,6 +464,16 @@
|
|
|
458
464
|
'chat.stop.noop': '当前没有进行中的生成',
|
|
459
465
|
'media.openFailed': '打开失败,文件可能已移动或被删除',
|
|
460
466
|
'chat.members.manage': '管理成员',
|
|
467
|
+
'chat.settings': '设置',
|
|
468
|
+
'chat.settings.title': '会话设置',
|
|
469
|
+
'chat.settings.name': '名称',
|
|
470
|
+
'chat.settings.desc': '简介',
|
|
471
|
+
'chat.settings.workspace': '工作区隔离',
|
|
472
|
+
'chat.settings.root': '工作区根目录',
|
|
473
|
+
'chat.settings.rootPh': '留空 = 不启用',
|
|
474
|
+
'chat.settings.paths': '额外可写路径(逗号分隔)',
|
|
475
|
+
'chat.settings.pathsPh': '/tmp/xxx, /Users/you/shared',
|
|
476
|
+
'chat.settings.hint': '写入被沙盒限制在工作区(含额外路径)内,读取不受限;同 slug 的 Bot 共享同一目录。',
|
|
461
477
|
'modal.members.title': '管理群成员',
|
|
462
478
|
'modal.members.hint': '勾选的 Bot 为群成员;保存后立即生效(可随时再改)。',
|
|
463
479
|
'action.delete': '删除',
|
|
@@ -560,6 +576,16 @@
|
|
|
560
576
|
'chat.stop.noop': 'No generation in progress',
|
|
561
577
|
'media.openFailed': 'Open failed — the file may have moved or been deleted',
|
|
562
578
|
'chat.members.manage': 'Manage members',
|
|
579
|
+
'chat.settings': 'Settings',
|
|
580
|
+
'chat.settings.title': 'Session settings',
|
|
581
|
+
'chat.settings.name': 'Name',
|
|
582
|
+
'chat.settings.desc': 'Description',
|
|
583
|
+
'chat.settings.workspace': 'Workspace jail',
|
|
584
|
+
'chat.settings.root': 'Workspace root',
|
|
585
|
+
'chat.settings.rootPh': 'Empty = disabled',
|
|
586
|
+
'chat.settings.paths': 'Extra writable paths (comma-separated)',
|
|
587
|
+
'chat.settings.pathsPh': '/tmp/xxx, /Users/you/shared',
|
|
588
|
+
'chat.settings.hint': 'Writes are sandboxed to the workspace (plus extra paths); reads stay unrestricted. Bots sharing a slug share one directory.',
|
|
563
589
|
'modal.members.title': 'Manage group members',
|
|
564
590
|
'modal.members.hint': 'Checked bots are members; changes apply immediately on save (editable again anytime).',
|
|
565
591
|
'action.delete': 'Delete',
|
|
@@ -762,6 +788,7 @@
|
|
|
762
788
|
confirmDelete: null,
|
|
763
789
|
/** Manage-members dialog: group agentId | null (system modal). */
|
|
764
790
|
manageMembers: null,
|
|
791
|
+
settingsAgentId: null,
|
|
765
792
|
/** Bumped on a language switch so module-scope `t` output re-renders. */
|
|
766
793
|
localeRev: 0,
|
|
767
794
|
};
|
|
@@ -1380,6 +1407,13 @@
|
|
|
1380
1407
|
return null;
|
|
1381
1408
|
return e('div', { className: 'dbs-mediaRefs' }, imgs.map((r) => e(MediaImage, { key: r, path: r })), files.map((r) => e(FileChip, { key: r, path: r })));
|
|
1382
1409
|
}
|
|
1410
|
+
/**
|
|
1411
|
+
* Settings glyph — three sliders, drawn inline (the primitives package
|
|
1412
|
+
* exposes no verified gear export; same policy as SendUpIcon).
|
|
1413
|
+
*/
|
|
1414
|
+
function SettingsGlyph() {
|
|
1415
|
+
return e('svg', { viewBox: '0 0 16 16', width: '16', height: '16', 'aria-hidden': true }, e('g', { stroke: 'currentColor', strokeWidth: 1.5, strokeLinecap: 'round' }, e('line', { x1: 2, y1: 4, x2: 14, y2: 4 }), e('line', { x1: 2, y1: 8, x2: 14, y2: 8 }), e('line', { x1: 2, y1: 12, x2: 14, y2: 12 })), e('g', { fill: 'currentColor' }, e('circle', { cx: 10, cy: 4, r: 2 }), e('circle', { cx: 5.5, cy: 8, r: 2 }), e('circle', { cx: 11.5, cy: 12, r: 2 })));
|
|
1416
|
+
}
|
|
1383
1417
|
function ToolCard(p) {
|
|
1384
1418
|
const [open, setOpen] = React.useState(false);
|
|
1385
1419
|
const en = p.entry;
|
|
@@ -1695,12 +1729,16 @@
|
|
|
1695
1729
|
variant: 'ghost', size: 'sm', title: t('action.close'), 'aria-label': t('action.close'),
|
|
1696
1730
|
icon: Ico('IconCloseOutline16', { size: 16 }),
|
|
1697
1731
|
onClick: () => patch({ chatAgentId: null }),
|
|
1698
|
-
}), agent !== null ? e(Avatar, { agent, size: 24 }) : null, e('span', { className: 'dbs-chatbarName' }, agent?.name ?? t('chat.loading')), e('span', { className: 'dbs-meta' }, isGroup ? t('chat.group', { n: memberNames.length }) : t('chat.single')), isGroup
|
|
1732
|
+
}), agent !== null ? e(Avatar, { agent, size: 24 }) : null, e('span', { className: 'dbs-chatbarName' }, agent?.name ?? t('chat.loading')), e('span', { className: 'dbs-meta' }, isGroup ? t('chat.group', { n: memberNames.length }) : t('chat.single')), e('span', { style: { flex: 1 } }), isGroup
|
|
1699
1733
|
? e(Button, {
|
|
1700
1734
|
variant: 'ghost', size: 'sm', title: t('chat.members.manage'), 'aria-label': t('chat.members.manage'),
|
|
1701
1735
|
onClick: () => patch({ manageMembers: p.agentId }),
|
|
1702
1736
|
}, t('chat.members.manage'))
|
|
1703
|
-
: null, e('
|
|
1737
|
+
: null, e('button', {
|
|
1738
|
+
className: 'dbs-railBtn', type: 'button',
|
|
1739
|
+
title: t('chat.settings'), 'aria-label': t('chat.settings'),
|
|
1740
|
+
onClick: () => patch({ settingsAgentId: p.agentId }),
|
|
1741
|
+
}, e(SettingsGlyph, null))), error !== null
|
|
1704
1742
|
? e('div', { className: 'dbs-error', onClick: () => setError(null) }, error)
|
|
1705
1743
|
: null, e('div', { className: 'dbs-scrollArea' }, e('div', { className: 'dbs-scrollBody', ref: scrollRef, onScroll: onScrollBody }, e('div', { className: 'dbs-scroll' }, e('div', { className: 'dbs-column' }, entries === null
|
|
1706
1744
|
? e('div', { className: 'dbs-skeleton' }, e('div', { className: 'dbs-skelRow', style: { width: '42%' } }), e('div', { className: 'dbs-skelRow', style: { width: '76%' } }), e('div', { className: 'dbs-skelRow', style: { width: '58%' } }))
|
|
@@ -2161,6 +2199,113 @@
|
|
|
2161
2199
|
onClick: () => void submit(),
|
|
2162
2200
|
}, working ? t('action.saving') : t('action.save')))));
|
|
2163
2201
|
}
|
|
2202
|
+
/**
|
|
2203
|
+
* Per-session settings: name (+ description) for every chat; singles
|
|
2204
|
+
* additionally get the §14 workspace-jail editor (root + extra writable
|
|
2205
|
+
* paths). updateAgent merges only the name/description/title/avatar
|
|
2206
|
+
* fields engine-side, so saving cannot clobber the rest of a profile;
|
|
2207
|
+
* an empty root removes the jail (workspaceRoot: null).
|
|
2208
|
+
*/
|
|
2209
|
+
function AgentSettingsModal() {
|
|
2210
|
+
const s = useStore();
|
|
2211
|
+
const agent = agentById(s.settingsAgentId);
|
|
2212
|
+
const isGroup = agent?.isGroup === true;
|
|
2213
|
+
const [name, setName] = React.useState('');
|
|
2214
|
+
const [desc, setDesc] = React.useState('');
|
|
2215
|
+
const [root, setRoot] = React.useState('');
|
|
2216
|
+
const [paths, setPaths] = React.useState('');
|
|
2217
|
+
const [wsLoaded, setWsLoaded] = React.useState(false);
|
|
2218
|
+
const [working, setWorking] = React.useState(false);
|
|
2219
|
+
const [err, setErr] = React.useState(null);
|
|
2220
|
+
React.useEffect(() => {
|
|
2221
|
+
if (agent === null || agent === undefined)
|
|
2222
|
+
return;
|
|
2223
|
+
setName(String(agent.name ?? ''));
|
|
2224
|
+
setDesc(String(agent.description ?? ''));
|
|
2225
|
+
if (agent.isGroup === true) {
|
|
2226
|
+
setWsLoaded(true);
|
|
2227
|
+
return;
|
|
2228
|
+
}
|
|
2229
|
+
let alive = true;
|
|
2230
|
+
botsCall('workspaceGet', { agentId: agent.id })
|
|
2231
|
+
.then((c) => {
|
|
2232
|
+
if (alive === false)
|
|
2233
|
+
return;
|
|
2234
|
+
setRoot(c.workspaceRoot ?? '');
|
|
2235
|
+
setPaths((c.allowPaths ?? []).join(', '));
|
|
2236
|
+
setWsLoaded(true);
|
|
2237
|
+
})
|
|
2238
|
+
.catch(() => { if (alive)
|
|
2239
|
+
setWsLoaded(true); });
|
|
2240
|
+
return () => { alive = false; };
|
|
2241
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2242
|
+
}, [s.settingsAgentId]);
|
|
2243
|
+
if (agent === null || agent === undefined)
|
|
2244
|
+
return null;
|
|
2245
|
+
const valid = name.trim() !== '';
|
|
2246
|
+
async function save() {
|
|
2247
|
+
if (working || valid === false)
|
|
2248
|
+
return;
|
|
2249
|
+
setWorking(true);
|
|
2250
|
+
setErr(null);
|
|
2251
|
+
try {
|
|
2252
|
+
await botsCall('update', { id: agent.id, profile: { name: name.trim(), description: desc.trim() } });
|
|
2253
|
+
if (agent.isGroup !== true && wsLoaded === true) {
|
|
2254
|
+
const list = paths.split(/[,,]/).map((x) => x.trim()).filter((x) => x !== '');
|
|
2255
|
+
await botsCall('workspaceSet', {
|
|
2256
|
+
agentId: agent.id,
|
|
2257
|
+
workspaceRoot: root.trim() === '' ? null : root.trim(),
|
|
2258
|
+
allowPaths: list,
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2261
|
+
patch({ settingsAgentId: null });
|
|
2262
|
+
await refreshAgents();
|
|
2263
|
+
return;
|
|
2264
|
+
}
|
|
2265
|
+
catch (e2) {
|
|
2266
|
+
setErr(String(e2?.message ?? e2));
|
|
2267
|
+
}
|
|
2268
|
+
setWorking(false);
|
|
2269
|
+
}
|
|
2270
|
+
return e('div', {
|
|
2271
|
+
className: 'dbs-modalBackdrop',
|
|
2272
|
+
onClick: () => { if (working === false)
|
|
2273
|
+
patch({ settingsAgentId: null }); },
|
|
2274
|
+
}, e('div', {
|
|
2275
|
+
className: 'dbs-modalCard', role: 'dialog', 'aria-modal': true,
|
|
2276
|
+
'aria-label': t('chat.settings.title'),
|
|
2277
|
+
onClick: (ev) => { ev.stopPropagation(); },
|
|
2278
|
+
}, e('div', { className: 'dbs-modalTitleRow' }, e('span', { className: 'dbs-modalTitle' }, t('chat.settings.title')), e(Button, {
|
|
2279
|
+
variant: 'ghost', size: 'sm', title: t('action.close'), 'aria-label': t('action.close'),
|
|
2280
|
+
disabled: working,
|
|
2281
|
+
icon: Ico('IconCloseOutline16', { size: 16 }),
|
|
2282
|
+
onClick: () => patch({ settingsAgentId: null }),
|
|
2283
|
+
})), e('div', { className: 'dbs-modalBody' }, e('div', { className: 'dbs-setLabel' }, t('chat.settings.name')), e(Input, {
|
|
2284
|
+
value: name, autoFocus: true, disabled: working,
|
|
2285
|
+
onChange: (ev) => setName(ev.target.value),
|
|
2286
|
+
}), isGroup === false
|
|
2287
|
+
? e('div', null, e('div', { className: 'dbs-setLabel' }, t('chat.settings.desc')), e(Input, {
|
|
2288
|
+
value: desc, disabled: working,
|
|
2289
|
+
onChange: (ev) => setDesc(ev.target.value),
|
|
2290
|
+
}), e('div', { className: 'dbs-setLabel', style: { marginTop: 12, fontWeight: 600 } }, t('chat.settings.workspace')), e('div', { className: 'dbs-setLabel' }, t('chat.settings.root')), e(Input, {
|
|
2291
|
+
value: root, disabled: working || wsLoaded === false,
|
|
2292
|
+
placeholder: t('chat.settings.rootPh'),
|
|
2293
|
+
onChange: (ev) => setRoot(ev.target.value),
|
|
2294
|
+
}), e('div', { className: 'dbs-setLabel' }, t('chat.settings.paths')), e(Input, {
|
|
2295
|
+
value: paths, disabled: working || wsLoaded === false,
|
|
2296
|
+
placeholder: t('chat.settings.pathsPh'),
|
|
2297
|
+
onChange: (ev) => setPaths(ev.target.value),
|
|
2298
|
+
}), e('div', { className: 'dbs-meta', style: { marginTop: 8 } }, t('chat.settings.hint')))
|
|
2299
|
+
: null, err !== null
|
|
2300
|
+
? e('div', { className: 'dbs-error', onClick: () => { setErr(null); } }, err)
|
|
2301
|
+
: null), e('div', { className: 'dbs-modalFooter' }, e(Button, {
|
|
2302
|
+
variant: 'ghost', size: 'sm', disabled: working,
|
|
2303
|
+
onClick: () => patch({ settingsAgentId: null }),
|
|
2304
|
+
}, t('action.cancel')), e(Button, {
|
|
2305
|
+
variant: 'primary', size: 'sm', disabled: valid === false || working,
|
|
2306
|
+
onClick: () => void save(),
|
|
2307
|
+
}, working === true ? t('action.saving') : t('action.save')))));
|
|
2308
|
+
}
|
|
2164
2309
|
/** Delete confirmation modal: same system-dialog chrome as CreateModal. */
|
|
2165
2310
|
function ConfirmDeleteModal() {
|
|
2166
2311
|
const s = useStore();
|
|
@@ -2239,6 +2384,8 @@
|
|
|
2239
2384
|
layers.push(e(CreateModal, { key: 'create' }));
|
|
2240
2385
|
if (s.manageMembers !== null)
|
|
2241
2386
|
layers.push(e(ManageMembersModal, { key: 'manage-members' }));
|
|
2387
|
+
if (s.settingsAgentId !== null)
|
|
2388
|
+
layers.push(e(AgentSettingsModal, { key: 'agent-settings' }));
|
|
2242
2389
|
if (s.confirmDelete !== null)
|
|
2243
2390
|
layers.push(e(ConfirmDeleteModal, { key: 'confirm-delete' }));
|
|
2244
2391
|
return layers.length === 0 ? null : e('div', null, layers);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-bots",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.14",
|
|
4
4
|
"description": "Multi-bot workbench for DeepSeek Harness: bridges the sdk-bots orchestration gateway (group chats, single bots) into the dsh web shell with official-styled UI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|