dsh-mutipleagent 0.0.0-stage → 0.4.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/CHANGELOG.md +214 -0
- package/CONTRIBUTING.md +49 -0
- package/LICENSE +21 -0
- package/README.en.md +125 -0
- package/README.md +302 -2
- package/SECURITY.md +27 -0
- package/THIRD_PARTY_NOTICES.md +29 -0
- package/assets/agents/MAGPIE-LICENSE +21 -0
- package/assets/agents/README.md +47 -0
- package/assets/agents/antigravity.png +0 -0
- package/assets/agents/claude.png +0 -0
- package/assets/agents/codex.png +0 -0
- package/assets/agents/copilot.svg +1 -0
- package/assets/agents/dsh.svg +1 -0
- package/assets/agents/gemini.png +0 -0
- package/assets/agents/grok.svg +1 -0
- package/assets/agents/hermes.svg +1 -0
- package/assets/agents/kimi.svg +1 -0
- package/assets/agents/omp.svg +7 -0
- package/assets/agents/opencode.svg +1 -0
- package/assets/agents/pi.svg +1 -0
- package/assets/kenney/LICENSE-furniture-kit.txt +23 -0
- package/assets/kenney/LICENSE-mini-characters.txt +28 -0
- package/assets/kenney/characters/Textures/colormap.png +0 -0
- package/assets/kenney/characters/character-female-a.glb +0 -0
- package/assets/kenney/characters/character-female-b.glb +0 -0
- package/assets/kenney/characters/character-female-c.glb +0 -0
- package/assets/kenney/characters/character-female-d.glb +0 -0
- package/assets/kenney/characters/character-female-e.glb +0 -0
- package/assets/kenney/characters/character-female-f.glb +0 -0
- package/assets/kenney/characters/character-male-a.glb +0 -0
- package/assets/kenney/characters/character-male-b.glb +0 -0
- package/assets/kenney/characters/character-male-c.glb +0 -0
- package/assets/kenney/characters/character-male-d.glb +0 -0
- package/assets/kenney/characters/character-male-e.glb +0 -0
- package/assets/kenney/characters/character-male-f.glb +0 -0
- package/assets/kenney/furniture/benchCushion.glb +0 -0
- package/assets/kenney/furniture/bookcaseOpen.glb +0 -0
- package/assets/kenney/furniture/books.glb +0 -0
- package/assets/kenney/furniture/cabinetTelevision.glb +0 -0
- package/assets/kenney/furniture/cardboardBoxClosed.glb +0 -0
- package/assets/kenney/furniture/chairCushion.glb +0 -0
- package/assets/kenney/furniture/chairDesk.glb +0 -0
- package/assets/kenney/furniture/chairModernCushion.glb +0 -0
- package/assets/kenney/furniture/coatRackStanding.glb +0 -0
- package/assets/kenney/furniture/computerKeyboard.glb +0 -0
- package/assets/kenney/furniture/computerMouse.glb +0 -0
- package/assets/kenney/furniture/computerScreen.glb +0 -0
- package/assets/kenney/furniture/desk.glb +0 -0
- package/assets/kenney/furniture/doorway.glb +0 -0
- package/assets/kenney/furniture/kitchenBar.glb +0 -0
- package/assets/kenney/furniture/kitchenCabinet.glb +0 -0
- package/assets/kenney/furniture/kitchenCoffeeMachine.glb +0 -0
- package/assets/kenney/furniture/kitchenFridgeLarge.glb +0 -0
- package/assets/kenney/furniture/kitchenMicrowave.glb +0 -0
- package/assets/kenney/furniture/kitchenSink.glb +0 -0
- package/assets/kenney/furniture/lampRoundFloor.glb +0 -0
- package/assets/kenney/furniture/lampSquareTable.glb +0 -0
- package/assets/kenney/furniture/laptop.glb +0 -0
- package/assets/kenney/furniture/loungeChairRelax.glb +0 -0
- package/assets/kenney/furniture/loungeSofa.glb +0 -0
- package/assets/kenney/furniture/plantSmall1.glb +0 -0
- package/assets/kenney/furniture/plantSmall2.glb +0 -0
- package/assets/kenney/furniture/plantSmall3.glb +0 -0
- package/assets/kenney/furniture/pottedPlant.glb +0 -0
- package/assets/kenney/furniture/radio.glb +0 -0
- package/assets/kenney/furniture/rugRectangle.glb +0 -0
- package/assets/kenney/furniture/rugRound.glb +0 -0
- package/assets/kenney/furniture/sideTable.glb +0 -0
- package/assets/kenney/furniture/speaker.glb +0 -0
- package/assets/kenney/furniture/stoolBar.glb +0 -0
- package/assets/kenney/furniture/table.glb +0 -0
- package/assets/kenney/furniture/tableCoffee.glb +0 -0
- package/assets/kenney/furniture/tableRound.glb +0 -0
- package/assets/kenney/furniture/televisionModern.glb +0 -0
- package/assets/kenney/furniture/toaster.glb +0 -0
- package/assets/kenney/furniture/trashcan.glb +0 -0
- package/assets/kenney/furniture/wallWindow.glb +0 -0
- package/assets/logo.svg +12 -0
- package/assets/scene-icons/arcade.png +0 -0
- package/assets/scene-icons/cafe.png +0 -0
- package/assets/scene-icons/castle.png +0 -0
- package/assets/scene-icons/christmas.png +0 -0
- package/assets/scene-icons/graveyard.png +0 -0
- package/assets/scene-icons/map.png +0 -0
- package/assets/scene-icons/office.png +0 -0
- package/assets/scene-icons/pirate.png +0 -0
- package/assets/scene-icons/station.png +0 -0
- package/assets/scenes/arcade.jpg +0 -0
- package/assets/scenes/cafe.jpg +0 -0
- package/assets/scenes/castle.jpg +0 -0
- package/assets/scenes/christmas.jpg +0 -0
- package/assets/scenes/graveyard.jpg +0 -0
- package/assets/scenes/office.jpg +0 -0
- package/assets/scenes/pirate.jpg +0 -0
- package/assets/scenes/station.jpg +0 -0
- package/client.js +144 -0
- package/cordis.patch.yml +3 -0
- package/harness.cjs +49 -0
- package/package.json +89 -4
- package/public/app.js +1 -0
- package/public/chunks/chunk-MU3LEDFF.js +4305 -0
- package/public/demo-icons/arrow-counterclockwise.svg +4 -0
- package/public/demo-icons/arrow-right.svg +3 -0
- package/public/demo-icons/bell.svg +3 -0
- package/public/demo-icons/box-seam-fill.svg +3 -0
- package/public/demo-icons/chat-left-text-fill.svg +3 -0
- package/public/demo-icons/check-lg.svg +3 -0
- package/public/demo-icons/chevron-down.svg +3 -0
- package/public/demo-icons/cpu-fill.svg +4 -0
- package/public/demo-icons/crosshair.svg +3 -0
- package/public/demo-icons/diagram-3-fill.svg +3 -0
- package/public/demo-icons/file-earmark-code-fill.svg +3 -0
- package/public/demo-icons/fullscreen.svg +3 -0
- package/public/demo-icons/pause-fill.svg +3 -0
- package/public/demo-icons/people-fill.svg +3 -0
- package/public/demo-icons/pie-chart-fill.svg +3 -0
- package/public/demo-icons/play-fill.svg +3 -0
- package/public/demo-icons/search.svg +3 -0
- package/public/demo-icons/shield-check.svg +4 -0
- package/public/demo-icons/stack.svg +4 -0
- package/public/demo-icons/x-lg.svg +3 -0
- package/public/demo.css +225 -0
- package/public/demo.html +67 -0
- package/public/demo.js +7 -0
- package/public/index.html +59 -0
- package/public/style.css +15 -0
- package/public/vendor/office.js +1631 -0
- package/src/codex.js +674 -0
- package/src/demo.js +103 -0
- package/src/harness-watcher.js +584 -0
- package/src/server.js +239 -0
- package/vendor/licenses/BOOTSTRAP-ICONS-LICENSE.txt +21 -0
- package/vendor/licenses/ESBUILD-LICENSE.txt +21 -0
- package/vendor/licenses/MESHOPTIMIZER-LICENSE.txt +22 -0
- package/vendor/licenses/PLAYWRIGHT-LICENSE.txt +202 -0
- package/vendor/licenses/PLAYWRIGHT-NOTICE.txt +5 -0
- package/vendor/licenses/THREE-LICENSE.txt +21 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/assets/logo.svg
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="256" height="256">
|
|
2
|
+
<title>whatsmyagentdoing</title>
|
|
3
|
+
<rect width="32" height="32" rx="9" fill="#ff6a4d"/>
|
|
4
|
+
<rect x="5.5" y="7.5" width="21" height="15" rx="4" fill="#fff"/>
|
|
5
|
+
<path d="M13 22h6l1 3h-8z" fill="#fff"/>
|
|
6
|
+
<rect x="10" y="24.6" width="12" height="2.2" rx="1.1" fill="#fff"/>
|
|
7
|
+
<ellipse cx="12.6" cy="15" rx="2.3" ry="3" fill="#1a1a1a"/>
|
|
8
|
+
<ellipse cx="19.4" cy="15" rx="2.3" ry="3" fill="#1a1a1a"/>
|
|
9
|
+
<circle cx="13.3" cy="13.9" r=".8" fill="#fff"/>
|
|
10
|
+
<circle cx="20.1" cy="13.9" r=".8" fill="#fff"/>
|
|
11
|
+
<circle cx="25.2" cy="7.6" r="3.6" fill="#22a874" stroke="#ff6a4d" stroke-width="1.6"/>
|
|
12
|
+
</svg>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/client.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: 'dsh-mutipleagent',
|
|
3
|
+
factory: require => {
|
|
4
|
+
const { createElement: h, useEffect, useState } = require('react');
|
|
5
|
+
// 面板页面由本插件自己的静态服务提供(不是用户内容),需要同源才能读写本地偏好与同源 API。
|
|
6
|
+
// 其余权限(弹窗、顶层跳转、表单、下载、插件、指针锁定、模态框)保持沙箱默认拒绝。
|
|
7
|
+
const FRAME_SANDBOX = 'allow-scripts allow-same-origin';
|
|
8
|
+
const OFFICE_BASE = '/dsh-mutipleagent/';
|
|
9
|
+
const VIEW_ID = 'dsh-mutipleagent';
|
|
10
|
+
const VIEW_LABEL = '多 Agent 办公室';
|
|
11
|
+
// 会话内视图直接带上当前会话 id:办公室据此锁定 rootId,不再要求用户先选目录和会话。
|
|
12
|
+
// rev 取健康检查里的插件版本:升级后地址随之变化,停留在标签页里的旧 iframe 会自动重载,
|
|
13
|
+
// 不必等用户手动刷新整个 Harness 页面(CSS/脚本更新也能立刻生效)。
|
|
14
|
+
function officeUrl(sessionId, rev) {
|
|
15
|
+
const params = new URLSearchParams({ mode: 'live', source: 'harness' });
|
|
16
|
+
if (sessionId) {
|
|
17
|
+
params.set('rootId', sessionId);
|
|
18
|
+
params.set('embed', '1');
|
|
19
|
+
}
|
|
20
|
+
if (rev) params.set('rev', rev);
|
|
21
|
+
return OFFICE_BASE + '?' + params.toString();
|
|
22
|
+
}
|
|
23
|
+
function OfficeIcon({ size = 18 }) {
|
|
24
|
+
return h(
|
|
25
|
+
'svg',
|
|
26
|
+
{ width: size, height: size, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 1.6, 'aria-hidden': true },
|
|
27
|
+
h('path', { d: 'M3 10V5h6v5H3Zm12 0V5h6v5h-6ZM9 21v-5h6v5H9ZM6 10v3h12v-3m-6 3v3' }),
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
// 面板与会话视图共用同一套连接状态机:先探活,再挂 iframe。
|
|
31
|
+
function OfficeFrame({ sessionId, className }) {
|
|
32
|
+
const [version, setVersion] = useState(0);
|
|
33
|
+
const [error, setError] = useState('');
|
|
34
|
+
const [ready, setReady] = useState(false);
|
|
35
|
+
const [rev, setRev] = useState('');
|
|
36
|
+
const url = officeUrl(sessionId, rev);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
let active = true;
|
|
39
|
+
const controller = new AbortController();
|
|
40
|
+
setError('');
|
|
41
|
+
setReady(false);
|
|
42
|
+
fetch(OFFICE_BASE + 'api/health', { signal: controller.signal })
|
|
43
|
+
.then(response => {
|
|
44
|
+
if (!response.ok) throw Error('办公室暂不可用(HTTP ' + response.status + '),请确认插件已启用后重试。');
|
|
45
|
+
return response.json();
|
|
46
|
+
})
|
|
47
|
+
.then(data => {
|
|
48
|
+
if (!active) return;
|
|
49
|
+
setRev(String(data?.version ?? ''));
|
|
50
|
+
setReady(true);
|
|
51
|
+
})
|
|
52
|
+
.catch(error => {
|
|
53
|
+
if (active && error.name !== 'AbortError') setError(error.message);
|
|
54
|
+
});
|
|
55
|
+
return () => {
|
|
56
|
+
active = false;
|
|
57
|
+
controller.abort();
|
|
58
|
+
};
|
|
59
|
+
}, [version, sessionId]);
|
|
60
|
+
if (error)
|
|
61
|
+
return h(
|
|
62
|
+
'section',
|
|
63
|
+
{ className: 'dsh-office-status', role: 'alert' },
|
|
64
|
+
h('p', null, error),
|
|
65
|
+
h('button', { type: 'button', onClick: () => setVersion(value => value + 1) }, '重新连接'),
|
|
66
|
+
);
|
|
67
|
+
if (!ready) return h('p', { className: 'dsh-office-status', role: 'status' }, '正在连接多 Agent 办公室…');
|
|
68
|
+
return h('iframe', {
|
|
69
|
+
key: url,
|
|
70
|
+
className,
|
|
71
|
+
src: url,
|
|
72
|
+
title: 'DeepSeek Harness 多 Agent 协作办公室',
|
|
73
|
+
sandbox: FRAME_SANDBOX,
|
|
74
|
+
referrerPolicy: 'no-referrer',
|
|
75
|
+
allow: 'clipboard-write',
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function OfficePage() {
|
|
79
|
+
return h(OfficeFrame, { className: 'dsh-office-frame' });
|
|
80
|
+
}
|
|
81
|
+
// 会话内标签:sessionId 由 conversation.view 的 inject(sessionId) 注入,切换会话即换 iframe。
|
|
82
|
+
// 标签页在屏时给 body 打标记,宿主据此收起底部输入框,把整块高度让给办公室画面;离开标签即恢复。
|
|
83
|
+
let officeViewCount = 0;
|
|
84
|
+
function OfficeView({ sessionId }) {
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
officeViewCount += 1;
|
|
87
|
+
document.body.dataset.officeView = 'active';
|
|
88
|
+
return () => {
|
|
89
|
+
officeViewCount = Math.max(0, officeViewCount - 1);
|
|
90
|
+
if (officeViewCount === 0) delete document.body.dataset.officeView;
|
|
91
|
+
};
|
|
92
|
+
}, []);
|
|
93
|
+
return h('div', { className: 'dsh-office-view' }, h(OfficeFrame, { sessionId, className: 'dsh-office-frame' }));
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
inject: ['slots'],
|
|
97
|
+
apply(ctx) {
|
|
98
|
+
ctx.effect(() => {
|
|
99
|
+
const style = document.createElement('style');
|
|
100
|
+
style.textContent =
|
|
101
|
+
'.dsh-office-frame{display:block;width:100%;height:100%;min-height:0;border:0;background:#edf3fc}.dsh-office-view{display:flex;flex:1 1 auto;flex-direction:column;min-height:0;min-width:0;height:100%;width:100%;background:#edf3fc}.dsh-office-view>.dsh-office-frame{flex:1 1 auto;height:auto}body[data-office-view=active] [data-conversation-region=composer]{display:none!important}.dsh-office-status{padding:24px;color:var(--dsw-alias-label-primary);font:inherit}.dsh-office-status button{font:inherit;color:inherit;background:var(--dsw-alias-button-elevated-fill);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:8px 16px;cursor:pointer}.dsh-office-status button:focus-visible{outline:2px solid var(--dsw-focus-ring-color);outline-offset:2px}';
|
|
102
|
+
document.head.appendChild(style);
|
|
103
|
+
return () => style.remove();
|
|
104
|
+
}, 'dsh-mutipleagent: panel styles');
|
|
105
|
+
ctx.effect(
|
|
106
|
+
() => ctx.slots.inject('main', () => ctx.slots.register({ name: 'main', key: 'dsh-mutipleagent' }, OfficePage)),
|
|
107
|
+
'dsh-mutipleagent: main panel',
|
|
108
|
+
);
|
|
109
|
+
// 会话页顶部标签行(对话 / 轨迹 / 上下文 / …):在具体会话里直接可用的入口。
|
|
110
|
+
ctx.effect(
|
|
111
|
+
() =>
|
|
112
|
+
ctx.slots.inject('conversation.view', () =>
|
|
113
|
+
ctx.slots.register(
|
|
114
|
+
{
|
|
115
|
+
name: 'conversation.view',
|
|
116
|
+
id: VIEW_ID,
|
|
117
|
+
order: 30,
|
|
118
|
+
label: () => VIEW_LABEL,
|
|
119
|
+
inject: sessionId => ({ sessionId }),
|
|
120
|
+
},
|
|
121
|
+
OfficeView,
|
|
122
|
+
),
|
|
123
|
+
),
|
|
124
|
+
'dsh-mutipleagent: conversation view',
|
|
125
|
+
);
|
|
126
|
+
ctx.effect(
|
|
127
|
+
() =>
|
|
128
|
+
ctx.slots.inject('sidebar.panellist', () =>
|
|
129
|
+
ctx.slots.register(
|
|
130
|
+
{
|
|
131
|
+
name: 'sidebar.panellist',
|
|
132
|
+
id: 'dsh-mutipleagent',
|
|
133
|
+
order: 30,
|
|
134
|
+
label: '多 Agent 办公室',
|
|
135
|
+
},
|
|
136
|
+
OfficeIcon,
|
|
137
|
+
),
|
|
138
|
+
),
|
|
139
|
+
'dsh-mutipleagent: sidebar entry',
|
|
140
|
+
);
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
},
|
|
144
|
+
});
|
package/cordis.patch.yml
ADDED
package/harness.cjs
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { createOfficeServer } = require('./src/server');
|
|
3
|
+
const { HarnessWatcher } = require('./src/harness-watcher');
|
|
4
|
+
|
|
5
|
+
exports.name = 'dsh-mutipleagent';
|
|
6
|
+
exports.inject = ['webServer', 'connection', 'sessionQuery'];
|
|
7
|
+
|
|
8
|
+
exports.apply = function apply(ctx) {
|
|
9
|
+
ctx.effect(() => {
|
|
10
|
+
const watcher = new HarnessWatcher({ query: ctx.sessionQuery });
|
|
11
|
+
const server = createOfficeServer({
|
|
12
|
+
watcher,
|
|
13
|
+
basePath: '/dsh-mutipleagent',
|
|
14
|
+
defaultDocument: 'demo.html',
|
|
15
|
+
authorize(req) {
|
|
16
|
+
const admission = ctx.connection.admit(req);
|
|
17
|
+
if ('rejection' in admission) return admission.rejection;
|
|
18
|
+
// 此页面展示本机完整团队,只向宿主的 owner 开放。
|
|
19
|
+
return admission.peer.principal.kind === 'owner' ? undefined : 403;
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
let unregister;
|
|
23
|
+
try {
|
|
24
|
+
unregister = ctx.webServer.register({
|
|
25
|
+
kind: 'prefix',
|
|
26
|
+
path: '/dsh-mutipleagent',
|
|
27
|
+
handler(req, res) {
|
|
28
|
+
// 保留目录尾斜线,保证相对资源在 Web 和 Desktop 代理中一致。
|
|
29
|
+
const url = new URL(req.url, 'http://localhost');
|
|
30
|
+
if (url.pathname === '/dsh-mutipleagent') {
|
|
31
|
+
res.writeHead(302, { location: '/dsh-mutipleagent/' + url.search });
|
|
32
|
+
res.end();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
server.emit('request', req, res);
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
watcher.start();
|
|
39
|
+
} catch (error) {
|
|
40
|
+
unregister?.();
|
|
41
|
+
server.closeOffice();
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
return () => {
|
|
45
|
+
unregister();
|
|
46
|
+
server.closeOffice();
|
|
47
|
+
};
|
|
48
|
+
}, 'dsh-mutipleagent: office route and session observer');
|
|
49
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,91 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-mutipleagent",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
6
|
-
|
|
3
|
+
"displayName": "DSH 多 Agent 办公室",
|
|
4
|
+
"version": "0.4.0",
|
|
5
|
+
"description": "DeepSeek Harness 多 Agent 3D 协作办公室插件:在会话页顶部标签行直接打开当前会话的 3D 办公室,观察真实主会话、子 Agent、工具活动与汇报,支持目录/会话切换和跨目录搜索。",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"icon": "./assets/agents/dsh.svg",
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": "^22.19.0 || >=24.0.0",
|
|
10
|
+
"dsh": "^0.2.2-rc.1"
|
|
11
|
+
},
|
|
12
|
+
"main": "harness.cjs",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": "./harness.cjs",
|
|
15
|
+
"./client": "./client.js",
|
|
16
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
17
|
+
"./package.json": "./package.json",
|
|
18
|
+
"./icon": "./assets/agents/dsh.svg"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"harness.cjs",
|
|
22
|
+
"client.js",
|
|
23
|
+
"cordis.patch.yml",
|
|
24
|
+
"src",
|
|
25
|
+
"public",
|
|
26
|
+
"assets",
|
|
27
|
+
"!assets/screenshots",
|
|
28
|
+
"vendor/licenses",
|
|
29
|
+
"LICENSE",
|
|
30
|
+
"README.md",
|
|
31
|
+
"README.en.md",
|
|
32
|
+
"SECURITY.md",
|
|
33
|
+
"CONTRIBUTING.md",
|
|
34
|
+
"CHANGELOG.md",
|
|
35
|
+
"THIRD_PARTY_NOTICES.md"
|
|
36
|
+
],
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/lkuliuying/dsh-mutipleagent.git"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/lkuliuying/dsh-mutipleagent",
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/lkuliuying/dsh-mutipleagent/issues"
|
|
44
|
+
},
|
|
45
|
+
"keywords": [
|
|
46
|
+
"dsh-plugin",
|
|
47
|
+
"deepseek-harness",
|
|
48
|
+
"multi-agent",
|
|
49
|
+
"3d-office"
|
|
50
|
+
],
|
|
51
|
+
"dsh": {
|
|
52
|
+
"bundle": {
|
|
53
|
+
"patch": "./cordis.patch.yml"
|
|
54
|
+
},
|
|
55
|
+
"client": {
|
|
56
|
+
"platform": "web",
|
|
57
|
+
"inject": [
|
|
58
|
+
"@deepseek-ai/dsh-client-ui-layout",
|
|
59
|
+
"@deepseek-ai/dsh-client-ui-chat",
|
|
60
|
+
"@deepseek-ai/dsh-client-ui-conversation",
|
|
61
|
+
"@deepseek-ai/dsh-client-ui-sidebar"
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"scripts": {
|
|
66
|
+
"start": "node src/server.js --open",
|
|
67
|
+
"demo": "node src/server.js --demo --open",
|
|
68
|
+
"build": "node scripts/build.mjs",
|
|
69
|
+
"lint": "eslint .",
|
|
70
|
+
"format": "prettier --write \"**/*.{js,cjs,mjs,yml}\"",
|
|
71
|
+
"format:check": "prettier --check \"**/*.{js,cjs,mjs,yml}\"",
|
|
72
|
+
"check:compat": "node scripts/check-compat.mjs",
|
|
73
|
+
"test": "node --test tests/*.test.js",
|
|
74
|
+
"test:ui": "node tests/browser.cjs",
|
|
75
|
+
"test:plugin:ui": "node tests/plugin-browser.cjs",
|
|
76
|
+
"smoke:host": "node scripts/smoke-host.cjs",
|
|
77
|
+
"release": "node scripts/release.mjs",
|
|
78
|
+
"screenshots": "node scripts/screenshots.mjs",
|
|
79
|
+
"test:coverage": "node --test --experimental-test-coverage --test-coverage-lines=85 --test-coverage-functions=80 --test-coverage-branches=75 tests/*.test.js"
|
|
80
|
+
},
|
|
81
|
+
"devDependencies": {
|
|
82
|
+
"@eslint/js": "^9.39.5",
|
|
83
|
+
"esbuild": "^0.25.12",
|
|
84
|
+
"eslint": "^9.39.4",
|
|
85
|
+
"globals": "^15.15.0",
|
|
86
|
+
"playwright": "^1.62.1",
|
|
87
|
+
"prettier": "^3.9.10",
|
|
88
|
+
"semver": "^7.8.6",
|
|
89
|
+
"three": "^0.186.1"
|
|
90
|
+
}
|
|
91
|
+
}
|
package/public/app.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{s as J,u as a,v as F,w as S,x as v,y as P,z as U}from"./chunks/chunk-MU3LEDFF.js";var e=t=>document.getElementById(t),O={assign:"\u2197",message:"\u2194",wait:"\u25F7",report:"\u2199",complete:"\u2713",error:"!",interrupted:"\u2161",close:"\xD7",approval:"?"},st=new Set(["thinking","tool","typing"]),ct=new Set(["done","error","interrupted","closed"]),r=null,g=null,I=null,u=null,A=0,W=new Set,k=!0,B=null,q="activity",w="",j=!1,K=Date.now(),E="",C="",L="",b="",_=!1,$=null,N=new Map,z=t=>{try{return localStorage.getItem(t)}catch{return null}},G=(t,n)=>{try{localStorage.setItem(t,n)}catch{}},M=t=>t?new Date(t).toLocaleTimeString(F(),{hour12:!1,hour:"2-digit",minute:"2-digit",second:"2-digit"}):"\u2014",c=(t,n,i)=>{let p=document.createElement(t);return n&&(p.className=n),i!=null&&(p.textContent=i),p},h=t=>c("div","empty",t),y=()=>r?.agents.find(t=>t.id===g),dt=t=>c("span","state-dot "+t),x=t=>r?.agents.find(n=>n.id===t)?.name||a("common.agent");function Q(t){e("notice").textContent=t,e("notice").hidden=!t}function T(t){e("connection").classList.toggle("connected",t),e("connection").textContent=t?a("topbar.connected"):a("topbar.reconnecting")}function V(t,n=!1){return c("span","agent-avatar"+(t.id===r.rootId?" lead":""),t.id===r.rootId?"\u25C8":n?"\u25C7":String(r.agents.indexOf(t)).padStart(2,"0"))}function D(t,n=!1){g=t,b="",C="",w="",u&&(u.selectedId=t,n&&u.focus(t)),X(),Z()}function pt(){let t=JSON.stringify(r.roots);if(t===E)return;E=t;let n=e("task-select");n.replaceChildren();for(let i of r.roots){let p=c("option","",i.title.slice(0,80));p.value=i.id,n.append(p)}r.roots.length||n.append(c("option","",a("sidebar.noSessions"))),n.value=r.rootId||""}function X(){if(!r)return;let t=JSON.stringify([g,r.agents.map(o=>[o.id,o.name,o.status,o.parentId,o.relationship])]);if(C===t)return;C=t;let n=e("team-tree");n.replaceChildren(),e("team-count").textContent=r.agents.length;let i=[],p=(o,s)=>{let d=r.agents.find(l=>l.id===o);if(!(!d||i.some(l=>l.s.id===o))){i.push({s:d,depth:s});for(let l of r.agents.filter(f=>f.parentId===o))p(l.id,s+1)}};p(r.rootId,0);for(let o of r.agents)i.some(s=>s.s.id===o.id)||i.push({s:o,depth:0});for(let{s:o,depth:s}of i){let d=c("button","agent-card"+(s?" child":"")+(o.id===g?" selected":""));d.type="button",d.setAttribute("aria-pressed",o.id===g),d.setAttribute("aria-label",a("app.ariaAgentStatus",{name:o.name,status:S(o.status)}));let l=c("div","agent-card-body"),f=c("div","agent-card-name");f.append(c("span","",o.name),dt(o.status)),l.append(f,c("div","agent-card-role",(s>1?"\u21B3 ".repeat(Math.min(3,s-1)):"")+(o.role||(s?a("app.roleSubAgent"):a("app.roleLead")))+" \xB7 "+S(o.status))),d.append(V(o),l),d.onclick=()=>D(o.id,!0),n.append(d)}i.length||n.append(h(a("app.teamEmpty")))}function lt(){let t=r.events.filter(s=>O[s.type]).slice(-40),n=JSON.stringify(t);if(n===L)return;L=n;let i=e("timeline"),p=i.scrollLeft,o=i.scrollWidth-i.clientWidth-p<30;i.replaceChildren(),e("event-count").textContent=t.length?a("main.recentEvents",{count:t.length}):a("main.noEvents");for(let s of t){let d=c("button","event-card "+s.type),l=c("div","event-card-top"),f=c("span","event-type");f.append(c("i","",O[s.type]),document.createTextNode(v(s.type))),l.append(f,c("time","",M(s.at)));let m=s.type==="assign"||s.type==="message"?x(s.sessionId)+" \u2192 "+x(s.targetId):s.type==="wait"?a("app.waitingResult",{name:x(s.sessionId)}):s.preview||x(s.sessionId)+" \xB7 "+v(s.type);d.append(l,c("p","",m)),d.onclick=()=>{D(s.sessionId,!0),s.hasText&&R(s)},d.title=m,i.append(d)}t.length||i.append(h(a("main.timelineEmpty"))),i.scrollLeft=o||k?i.scrollWidth:p}function Y(t){if(!t?.turnStartedAt)return"\u2014";let n=Math.max(0,Math.floor(((ct.has(t.status)?t.endedAt:Date.now())-t.turnStartedAt)/1e3));return n>=3600?a("app.durationHours",{hours:Math.floor(n/3600),minutes:Math.floor(n%3600/60)}):a("app.durationMinutes",{minutes:Math.floor(n/60),seconds:n%60})}function Z(){let t=y();if(!t){e("agent-header").replaceChildren(h(a("details.selectAgent"))),e("agent-metadata").replaceChildren(),e("agent-task").textContent=a("details.noTask"),e("agent-activity").replaceChildren(),e("open-task").disabled=!0,e("report-content").replaceChildren(h(a("details.noReport")));return}let n=JSON.stringify([t.id,t.status,t.model,t.role,t.relationship,t.task,t.events,t.reports,t.reportEventId]);if(n===b)return;b=n;let i=c("div");i.append(c("h3","",t.name),c("p","",t.role||(t.parentId?a("app.roleSplit"):a("app.roleLeadTask")))),e("agent-header").replaceChildren(V(t,!0),i);let p=[["status-pill",a("app.metadataStatus"),S(t.status)],["elapsed",a("app.metadataElapsed"),Y(t)],["",a("app.metadataModel"),t.model||a("common.notRecorded")],["",a("app.metadataRelation"),t.relationship==="conflict"?a("app.relationConflict"):t.parentId?x(t.parentId):a("app.relationMain")]];e("agent-metadata").replaceChildren(...p.map(([d,l,f])=>{let m=c("div","metadata-row");return m.append(c("span","",l),c("span",d,f)),m})),e("agent-task").textContent=t.task||a("app.noTaskLogged"),e("open-task").disabled=!t.taskEventId;let o=e("agent-activity");o.replaceChildren();let s=t.events.filter(d=>d.type!=="task").slice(-16).reverse();for(let d of s){let l=c("div","activity-item");if(l.append(c("time","",M(d.at)+" \xB7 "+v(d.type)),c("p","",d.preview||v(d.type))),d.hasText){let f=c("button","",a("details.viewRecord"));f.onclick=()=>R(d),l.append(f)}o.append(l)}s.length||o.append(h(a("details.noActivity"))),q==="report"&&et(t)}async function tt(t,n){let i=t+":"+n;if(N.has(i))return N.get(i);let p=await fetch("./api/report?"+new URLSearchParams({sessionId:t,eventId:n})),o=await p.json();if(!p.ok)throw new Error(o.error||a("app.readFailed"));return N.set(i,o.text),o.text}async function R(t){e("dialog-title").textContent=(O[t.type]?v(t.type):a("dialog.title"))+" \xB7 "+x(t.sessionId),e("dialog-body").textContent=a("dialog.loading"),e("copy-text").textContent=a("dialog.copy"),e("text-dialog").open||e("text-dialog").showModal();let n=t.id;e("text-dialog").dataset.eventId=n;try{let i=await tt(t.sessionId,t.id);e("text-dialog").dataset.eventId===n&&(e("dialog-body").textContent=i||a("dialog.emptyBody"))}catch(i){e("text-dialog").dataset.eventId===n&&(e("dialog-body").textContent=i.message)}}async function et(t){let n=t.reports||[],i=t.id+":"+n.join(",");if(i===w)return;w=i;let p=e("report-content");if(p.replaceChildren(),!n.length){p.append(h(a("app.reportEmpty")));return}p.append(h(a("app.reportLoading")));let o=await Promise.all(n.slice(-8).reverse().map(async s=>{try{return{id:s,text:await tt(t.id,s)}}catch(d){return{id:s,error:d.message}}}));if(!(y()?.id!==t.id||i!==w)){p.replaceChildren();for(let s of o){let d=c("section","report-block"),l=t.events.find(rt=>rt.id===s.id),f=c("header");f.append(c("span","",(s.id===t.reportEventId?a("app.reportCurrent"):a("app.reportHistory"))+(t.parentId?a("app.reportSub"):a("app.reportLead"))),c("time","",M(l?.at))),d.append(f,c("pre",s.error?"error-text":"",s.error||s.text));let m=c("button","report-open",a("app.reportOpen"));m.onclick=()=>R({id:s.id,sessionId:t.id,type:"report"}),d.append(m),p.append(d)}n.length>8&&p.append(c("p","muted",a("app.reportLimit")))}}function nt(t){q=t;for(let n of["activity","report"]){let i=t===n;e(n+"-tab").classList.toggle("active",i),e(n+"-tab").setAttribute("aria-selected",i),e(n+"-panel").hidden=!i}t==="report"&&y()&&et(y())}async function ut(){if(!u||r.agents.length>A){u?.destroy(),A=Math.max(7,Math.ceil(r.agents.length/2)*2+1),e("scene-status").hidden=!1;try{let t=new J(e("scene"),{count:A,reduced:e("reduced-motion").checked,onSelect:i=>D(i)});u=t,t.setTeam(r.agents,r.rootId),t.selectedId=g;let n=await t.ready;if(u!==t)return;e("scene-status").hidden=!!n,n||(e("scene-status").textContent=a("main.sceneUnavailable"),t.visible=!1)}catch{e("scene-status").hidden=!1,e("scene-status").textContent=a("main.sceneFailed")}}else u.setTeam(r.agents,r.rootId),u.selectedId=g}function ot(t){let n=t.rootId!==B;r=t,n&&(B=r.rootId,g=r.rootId,k=!0,C="",L="",b="",w=""),r.agents.some(o=>o.id===g)||(g=r.rootId),e("mode").textContent=r.mode==="demo"?a("app.demoMode"):a("topbar.readonly"),e("mode").classList.toggle("demo",r.mode==="demo");let i=r.agents.find(o=>o.id===r.rootId);e("project-path").textContent=i?.cwd||"",e("project-path").title=i?.cwd||"",e("task-title").textContent=i?.task||a("main.subtitle"),e("task-title").title=i?.task||"",e("working-count").textContent=r.agents.filter(o=>st.has(o.status)).length,e("done-count").textContent=r.agents.filter(o=>o.status==="done").length,e("waiting-count").textContent=r.agents.filter(o=>o.status==="waiting"||o.status==="waiting_agents").length,Q(r.mode==="demo"?a("app.demoNotice"):r.warnings.join(a("common.listSeparator"))||(r.rootId?"":a("app.noRecentSessions"))),pt(),X(),lt(),Z(),ut();let p=r.agents.some(o=>o.loading);if(!k&&!j&&!p&&u)for(let o of r.events)!W.has(o.id)&&o.at>=K&&u.animateEvent(o);j=p,W=new Set(r.events.map(o=>o.id)),k=!1,G("codex-office-root",r.rootId||"")}function at(t){I?.close(),k=!0,j=!0,K=Date.now();let n=new EventSource("./events"+(t?"?"+new URLSearchParams({rootId:t}):""));I=n,n.onopen=()=>{k=!0,T(!0)},n.onmessage=i=>{I===n&&(T(!0),ot(JSON.parse(i.data)))},n.onerror=()=>{I===n&&T(!1)}}async function it(){try{let t=await fetch("./api/sessions");if(!t.ok)throw new Error(a("app.editFailed"));let n=await t.json(),i=z("codex-office-root"),p=n.roots.find(o=>o.id===i)?.id||n.rootId;at(p)}catch(t){T(!1),Q(a("app.retrying",{message:t.message})),_||($=setTimeout(it,2500))}}e("task-select").onchange=t=>{E="",at(t.target.value)};e("reset-camera").onclick=()=>u?.resetCamera();e("activity-tab").onclick=()=>nt("activity");e("report-tab").onclick=()=>nt("report");e("open-task").onclick=()=>{let t=y();t?.taskEventId&&R({id:t.taskEventId,sessionId:t.taskSessionId||t.id,type:"task"})};e("close-dialog").onclick=()=>e("text-dialog").close();e("copy-text").onclick=async()=>{try{await navigator.clipboard.writeText(e("dialog-body").textContent),e("copy-text").textContent=a("common.copied")}catch{e("copy-text").textContent=a("common.copyFailed")}};var H=z("codex-office-reduced");e("reduced-motion").checked=H==null?matchMedia("(prefers-reduced-motion: reduce)").matches:H==="true";e("reduced-motion").onchange=t=>{G("codex-office-reduced",t.target.checked),u?.setReduced(t.target.checked)};var ft=setInterval(()=>{e("clock").textContent=M(Date.now());let t=document.querySelector(".elapsed");t&&y()&&(t.textContent=Y(y()))},1e3);document.addEventListener("visibilitychange",()=>{u&&(u.visible=!document.hidden&&!u.loadError)});P(()=>{E="",C="",L="",b="",w="",r&&ot(r)});U(document);window.addEventListener("beforeunload",()=>{_=!0,clearInterval(ft),clearTimeout($),I?.close(),u?.destroy()});it();
|