@nanmicoder/dsh-agent-teams 0.1.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/LICENSE +21 -0
- package/README.md +72 -0
- package/assets/agent-teams/action-celebrating.png +0 -0
- package/assets/agent-teams/action-reporting.png +0 -0
- package/assets/agent-teams/action-sending.png +0 -0
- package/assets/agent-teams/action-sleeping.png +0 -0
- package/assets/agent-teams/action-thinking.png +0 -0
- package/assets/agent-teams/action-working.png +0 -0
- package/assets/agent-teams/data-analyst.png +0 -0
- package/assets/agent-teams/designer.png +0 -0
- package/assets/agent-teams/docs-coordinator.png +0 -0
- package/assets/agent-teams/engineer.png +0 -0
- package/assets/agent-teams/qa-engineer.png +0 -0
- package/assets/agent-teams/researcher.png +0 -0
- package/assets/agent-teams/security-reviewer.png +0 -0
- package/assets/agent-teams/team-lead.png +0 -0
- package/cordis.patch.yml +21 -0
- package/lib/client/ActivityPanel.js +340 -0
- package/lib/client/AgentTeamsCard.js +74 -0
- package/lib/client/activity-model.js +70 -0
- package/lib/client/agent-teams-card-definition.js +85 -0
- package/lib/client/artwork.js +40 -0
- package/lib/client/index.js +33 -0
- package/lib/client.js +1235 -0
- package/lib/client.js.map +1 -0
- package/lib/event-types.js +12 -0
- package/lib/events.js +60 -0
- package/lib/index.js +172 -0
- package/lib/members.js +168 -0
- package/lib/snapshot.js +155 -0
- package/lib/state.js +461 -0
- package/lib/tools.js +749 -0
- package/lib/types/client/ActivityPanel.d.ts +64 -0
- package/lib/types/client/AgentTeamsCard.d.ts +24 -0
- package/lib/types/client/activity-model.d.ts +31 -0
- package/lib/types/client/agent-teams-card-definition.d.ts +44 -0
- package/lib/types/client/artwork.d.ts +19 -0
- package/lib/types/client/index.d.ts +11 -0
- package/lib/types/event-types.d.ts +103 -0
- package/lib/types/events.d.ts +37 -0
- package/lib/types/index.d.ts +42 -0
- package/lib/types/members.d.ts +86 -0
- package/lib/types/snapshot.d.ts +83 -0
- package/lib/types/state.d.ts +144 -0
- package/lib/types/tools.d.ts +40 -0
- package/lib/types/types.d.ts +73 -0
- package/lib/types.js +11 -0
- package/package.json +108 -0
package/lib/client.js
ADDED
|
@@ -0,0 +1,1235 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "dsh-agent-teams",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
|
+
let react_dom_client = require("react-dom/client");
|
|
9
|
+
let react = require("react");
|
|
10
|
+
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
11
|
+
//#region lib/client/activity-model.js
|
|
12
|
+
/** Pure relationship projections used by the AgentTeams activity panel. */
|
|
13
|
+
/**
|
|
14
|
+
* Whether an expanded activity panel still belongs to the current session.
|
|
15
|
+
*
|
|
16
|
+
* The panel is mounted through a body portal, so React does not remount it
|
|
17
|
+
* when the conversation route changes. Ownership keeps an expanded panel
|
|
18
|
+
* from leaking onto the new-session screen (or another conversation) while
|
|
19
|
+
* its local open state is being reset.
|
|
20
|
+
*/
|
|
21
|
+
function activityPanelExpandedForSession(open, owner, current) {
|
|
22
|
+
return open && owner !== void 0 && owner === current;
|
|
23
|
+
}
|
|
24
|
+
/** Group tasks by their precomputed dependency depth. */
|
|
25
|
+
function taskStages(tasks) {
|
|
26
|
+
const byDepth = /* @__PURE__ */ new Map();
|
|
27
|
+
for (const task of tasks) {
|
|
28
|
+
const depth = Number.isFinite(task.depth) ? Math.max(0, Math.floor(task.depth)) : 0;
|
|
29
|
+
const stage = byDepth.get(depth) ?? [];
|
|
30
|
+
stage.push(task);
|
|
31
|
+
byDepth.set(depth, stage);
|
|
32
|
+
}
|
|
33
|
+
return [...byDepth.entries()].sort(([left], [right]) => left - right).map(([depth, stageTasks]) => ({
|
|
34
|
+
depth,
|
|
35
|
+
tasks: stageTasks.slice().sort((left, right) => left.id.localeCompare(right.id, "en", { numeric: true }))
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Return the complete upstream/downstream chain around one task.
|
|
40
|
+
*
|
|
41
|
+
* Traversal uses both dependency directions and remains cycle-safe, so the UI
|
|
42
|
+
* can highlight every handoff related to the focused task even if malformed
|
|
43
|
+
* durable data contains a cycle.
|
|
44
|
+
*/
|
|
45
|
+
function relatedTaskIds(taskId, tasks) {
|
|
46
|
+
const byId = new Map(tasks.map((task) => [task.id, task]));
|
|
47
|
+
if (!byId.has(taskId)) return /* @__PURE__ */ new Set();
|
|
48
|
+
const dependents = /* @__PURE__ */ new Map();
|
|
49
|
+
for (const task of tasks) for (const dependency of task.dependencies) {
|
|
50
|
+
const targets = dependents.get(dependency) ?? [];
|
|
51
|
+
targets.push(task.id);
|
|
52
|
+
dependents.set(dependency, targets);
|
|
53
|
+
}
|
|
54
|
+
const related = /* @__PURE__ */ new Set();
|
|
55
|
+
const upstreamSeen = /* @__PURE__ */ new Set();
|
|
56
|
+
const downstreamSeen = /* @__PURE__ */ new Set();
|
|
57
|
+
const visitUpstream = (id) => {
|
|
58
|
+
if (upstreamSeen.has(id)) return;
|
|
59
|
+
upstreamSeen.add(id);
|
|
60
|
+
related.add(id);
|
|
61
|
+
for (const dependency of byId.get(id)?.dependencies ?? []) visitUpstream(dependency);
|
|
62
|
+
};
|
|
63
|
+
const visitDownstream = (id) => {
|
|
64
|
+
if (downstreamSeen.has(id)) return;
|
|
65
|
+
downstreamSeen.add(id);
|
|
66
|
+
related.add(id);
|
|
67
|
+
for (const dependent of dependents.get(id) ?? []) visitDownstream(dependent);
|
|
68
|
+
};
|
|
69
|
+
visitUpstream(taskId);
|
|
70
|
+
visitDownstream(taskId);
|
|
71
|
+
return related;
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region lib/client/artwork.js
|
|
75
|
+
/**
|
|
76
|
+
* Shared whale artwork lookup for the activity panel and the conversation
|
|
77
|
+
* card: role keywords map to the packaged role images; the captain always
|
|
78
|
+
* uses the lead whale.
|
|
79
|
+
* @module dsh-agent-teams/client/artwork
|
|
80
|
+
*/
|
|
81
|
+
/** Artwork route prefix served by the plugin host half. */
|
|
82
|
+
const ART_BASE = "/plugins/dsh-agent-teams/assets/";
|
|
83
|
+
/** Whale role artwork per role keyword. */
|
|
84
|
+
const ROLE_ART = [
|
|
85
|
+
[/resear|analys|investig|explor|data|study|研究|分析|数据|调查|探索|调研/, "researcher.png"],
|
|
86
|
+
[/engineer|dev\b|server|backend|\bapi\b|runtime|watcher|contract|工程|后端|服务|接口|开发|代码|编程/, "engineer.png"],
|
|
87
|
+
[/\bqa\b|test|verif|quality|测试|质量/, "qa-engineer.png"],
|
|
88
|
+
[/design|\bui\b|\bux\b|front|theme|accessib|设计|前端|主题/, "designer.png"],
|
|
89
|
+
[/secur|audit|risk|threat|review|安全|审计|审查|风险/, "security-reviewer.png"],
|
|
90
|
+
[/docs|writer|product|spec|coordin|撰写|文案|写作|文档|协调/, "docs-coordinator.png"],
|
|
91
|
+
[/release|\bbuild\b|deploy|\bops\b|\bci\b|ship|发布|构建|部署/, "engineer.png"]
|
|
92
|
+
];
|
|
93
|
+
/** Captain artwork (always the lead whale). */
|
|
94
|
+
const LEAD_ART = `${ART_BASE}team-lead.png`;
|
|
95
|
+
/** Status action artwork per member activity. */
|
|
96
|
+
const ACTION_ART = {
|
|
97
|
+
working: `${ART_BASE}action-working.png`,
|
|
98
|
+
idle: `${ART_BASE}action-sleeping.png`,
|
|
99
|
+
unknown: `${ART_BASE}action-thinking.png`
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Member artwork URL, or null when no role matches (initial-letter fallback).
|
|
103
|
+
* @param name - the member's display name.
|
|
104
|
+
* @param role - the member's role text.
|
|
105
|
+
* @returns the artwork URL, or null when unmatched.
|
|
106
|
+
*/
|
|
107
|
+
function memberArtUrl(name, role) {
|
|
108
|
+
const identity = `${name} ${role}`.toLowerCase();
|
|
109
|
+
for (const [pattern, art] of ROLE_ART) if (pattern.test(identity)) return `${ART_BASE}${art}`;
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
113
|
+
//#region \0dsh-css:/Users/nanmi/workspace/myself_code/dsh-agent-teams/src/client/AgentTeamsCard.module.css.mjs
|
|
114
|
+
const css$1 = "._6Ci0pW_root{box-sizing:border-box;border:1px solid var(--dsw-alias-line-normal);background:var(--dsw-alias-bg-module-platform);border-radius:10px;flex-direction:column;gap:8px;width:100%;min-width:0;padding:10px 12px;display:flex}._6Ci0pW_head{align-items:center;gap:8px;min-width:0;display:flex}._6Ci0pW_leadAvatar{border:1px solid var(--dsw-alias-line-strong);object-fit:cover;background:#0b1d33;border-radius:50%;flex:none;width:24px;height:24px}._6Ci0pW_teamName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:0 auto;font-size:13px;font-weight:600;line-height:20px;overflow:hidden}._6Ci0pW_memberCount{color:var(--dsw-alias-label-tertiary);white-space:nowrap;flex:none;margin-left:auto;font-size:11px;line-height:16px}._6Ci0pW_panelButton{border:1px solid var(--dsw-alias-line-strong);background:var(--dsw-alias-bg-module);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;border-radius:999px;flex:none;padding:2px 8px;font-size:10.5px;font-weight:600;line-height:16px;transition:border-color .12s,color .12s}._6Ci0pW_panelButton:hover{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}._6Ci0pW_panelButton:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}._6Ci0pW_members{flex-wrap:wrap;gap:6px;min-width:0;display:flex}._6Ci0pW_member{border:1px solid var(--dsw-alias-line-normal);background:var(--dsw-alias-bg-module);max-width:160px;color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;border-radius:999px;align-items:center;gap:5px;padding:3px 8px 3px 3px;font-size:11px;font-weight:500;line-height:16px;transition:border-color .12s,background-color .12s;display:inline-flex}._6Ci0pW_member:hover{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-bg-fill-neutral)}._6Ci0pW_member:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}._6Ci0pW_memberArt{border:1px solid var(--dsw-alias-line-strong);object-fit:cover;background:#0b1d33;border-radius:50%;width:20px;height:20px}._6Ci0pW_memberInitial{background:var(--dsw-alias-bg-fill-business);width:20px;height:20px;color:var(--dsw-alias-label-on-fill);border-radius:50%;justify-content:center;align-items:center;font-size:10px;font-weight:600;line-height:20px;display:inline-flex}._6Ci0pW_memberName{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}";
|
|
115
|
+
const tagId$1 = "dsh-agent-teams/AgentTeamsCard.module.css";
|
|
116
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
117
|
+
const tag = document.createElement("style");
|
|
118
|
+
tag.dataset.plugin = "dsh-agent-teams";
|
|
119
|
+
tag.dataset.pluginCss = tagId$1;
|
|
120
|
+
tag.textContent = css$1;
|
|
121
|
+
document.head.appendChild(tag);
|
|
122
|
+
}
|
|
123
|
+
var AgentTeamsCard_module_css_default = {
|
|
124
|
+
"memberArt": "_6Ci0pW_memberArt",
|
|
125
|
+
"memberCount": "_6Ci0pW_memberCount",
|
|
126
|
+
"root": "_6Ci0pW_root",
|
|
127
|
+
"memberInitial": "_6Ci0pW_memberInitial",
|
|
128
|
+
"panelButton": "_6Ci0pW_panelButton",
|
|
129
|
+
"members": "_6Ci0pW_members",
|
|
130
|
+
"teamName": "_6Ci0pW_teamName",
|
|
131
|
+
"head": "_6Ci0pW_head",
|
|
132
|
+
"leadAvatar": "_6Ci0pW_leadAvatar",
|
|
133
|
+
"member": "_6Ci0pW_member",
|
|
134
|
+
"memberName": "_6Ci0pW_memberName"
|
|
135
|
+
};
|
|
136
|
+
//#endregion
|
|
137
|
+
//#region lib/client/AgentTeamsCard.js
|
|
138
|
+
/**
|
|
139
|
+
* AgentTeams conversation card: the lightweight in-conversation summary for
|
|
140
|
+
* one team — the captain's whale avatar and name, the member roster as
|
|
141
|
+
* clickable whale avatars (opening the member's subagent transcript), and
|
|
142
|
+
* an "activity panel" button that re-activates the top-right floater.
|
|
143
|
+
*
|
|
144
|
+
* The floater and this card share the `agent-teams:open-panel` window event
|
|
145
|
+
* so the card can summon the panel even after it was closed (or when an old
|
|
146
|
+
* session is re-opened for review).
|
|
147
|
+
* @module dsh-agent-teams/client/card
|
|
148
|
+
*/
|
|
149
|
+
/** Window event name the floater listens for to open itself. */
|
|
150
|
+
const OPEN_PANEL_EVENT = "agent-teams:open-panel";
|
|
151
|
+
/** Re-activate the top-right activity panel, carrying this team's summary
|
|
152
|
+
* so the panel can show it even when the team no longer exists on disk
|
|
153
|
+
* (historical session review). */
|
|
154
|
+
function openActivityPanel(data) {
|
|
155
|
+
window.dispatchEvent(new CustomEvent(OPEN_PANEL_EVENT, { detail: {
|
|
156
|
+
teamId: data.teamId,
|
|
157
|
+
captainSessionId: data.captainSessionId,
|
|
158
|
+
teamName: data.teamName,
|
|
159
|
+
members: data.members
|
|
160
|
+
} }));
|
|
161
|
+
}
|
|
162
|
+
/** Render one durable team as a compact conversation card. */
|
|
163
|
+
function AgentTeamsCard({ node, openSession, currentSessionId }) {
|
|
164
|
+
const data = node.data;
|
|
165
|
+
const owner = data.captainSessionId || currentSessionId() || "";
|
|
166
|
+
const [snapshot, setSnapshot] = (0, react.useState)();
|
|
167
|
+
(0, react.useEffect)(() => {
|
|
168
|
+
let cancelled = false;
|
|
169
|
+
const tick = async () => {
|
|
170
|
+
for (const url of ["/plugins/dsh-agent-teams/state", "/plugins/dsh-agent-teams/state?archived=1"]) try {
|
|
171
|
+
const response = await fetch(url, { cache: "no-store" });
|
|
172
|
+
if (!response.ok) continue;
|
|
173
|
+
const body = await response.json();
|
|
174
|
+
const found = Array.isArray(body.teams) ? body.teams.find((team) => team.teamId === data.teamId && (owner === "" || team.captainSessionId === owner)) : void 0;
|
|
175
|
+
if (found !== void 0) {
|
|
176
|
+
if (!cancelled) setSnapshot(found);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
} catch {}
|
|
180
|
+
};
|
|
181
|
+
tick();
|
|
182
|
+
const timer = setInterval(() => {
|
|
183
|
+
tick();
|
|
184
|
+
}, 1500);
|
|
185
|
+
return () => {
|
|
186
|
+
cancelled = true;
|
|
187
|
+
clearInterval(timer);
|
|
188
|
+
};
|
|
189
|
+
}, [data.teamId, owner]);
|
|
190
|
+
const resolved = (0, react.useMemo)(() => ({
|
|
191
|
+
...data,
|
|
192
|
+
captainSessionId: snapshot?.captainSessionId ?? owner,
|
|
193
|
+
teamName: snapshot?.name ?? data.teamName,
|
|
194
|
+
members: snapshot?.members.map((member) => ({
|
|
195
|
+
id: member.id,
|
|
196
|
+
name: member.name,
|
|
197
|
+
role: member.role
|
|
198
|
+
})) ?? data.members
|
|
199
|
+
}), [
|
|
200
|
+
data,
|
|
201
|
+
owner,
|
|
202
|
+
snapshot
|
|
203
|
+
]);
|
|
204
|
+
return (0, react_jsx_runtime.jsxs)("section", {
|
|
205
|
+
className: AgentTeamsCard_module_css_default.root,
|
|
206
|
+
"data-agent-teams-card": true,
|
|
207
|
+
"data-team-id": resolved.teamId,
|
|
208
|
+
children: [(0, react_jsx_runtime.jsxs)("header", {
|
|
209
|
+
className: AgentTeamsCard_module_css_default.head,
|
|
210
|
+
children: [
|
|
211
|
+
(0, react_jsx_runtime.jsx)("img", {
|
|
212
|
+
className: AgentTeamsCard_module_css_default.leadAvatar,
|
|
213
|
+
src: LEAD_ART,
|
|
214
|
+
alt: "",
|
|
215
|
+
"aria-hidden": true
|
|
216
|
+
}),
|
|
217
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
218
|
+
className: AgentTeamsCard_module_css_default.teamName,
|
|
219
|
+
title: resolved.teamName,
|
|
220
|
+
children: resolved.teamName
|
|
221
|
+
}),
|
|
222
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
223
|
+
className: AgentTeamsCard_module_css_default.memberCount,
|
|
224
|
+
children: [resolved.members.length, " 名成员"]
|
|
225
|
+
}),
|
|
226
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
227
|
+
type: "button",
|
|
228
|
+
className: AgentTeamsCard_module_css_default.panelButton,
|
|
229
|
+
onClick: () => {
|
|
230
|
+
openActivityPanel(resolved);
|
|
231
|
+
},
|
|
232
|
+
"aria-label": "打开活动面板",
|
|
233
|
+
title: "打开活动面板",
|
|
234
|
+
children: "活动面板"
|
|
235
|
+
})
|
|
236
|
+
]
|
|
237
|
+
}), resolved.members.length > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
238
|
+
className: AgentTeamsCard_module_css_default.members,
|
|
239
|
+
children: resolved.members.map((member) => (0, react_jsx_runtime.jsxs)("button", {
|
|
240
|
+
type: "button",
|
|
241
|
+
className: AgentTeamsCard_module_css_default.member,
|
|
242
|
+
onClick: () => {
|
|
243
|
+
if (member.id !== "") openSession(member.id);
|
|
244
|
+
},
|
|
245
|
+
title: member.role === "" ? member.name : `${member.name} · ${member.role}`,
|
|
246
|
+
children: [memberArtUrl(member.name, member.role) !== null ? (0, react_jsx_runtime.jsx)("img", {
|
|
247
|
+
className: AgentTeamsCard_module_css_default.memberArt,
|
|
248
|
+
src: memberArtUrl(member.name, member.role) ?? "",
|
|
249
|
+
alt: "",
|
|
250
|
+
"aria-hidden": true
|
|
251
|
+
}) : (0, react_jsx_runtime.jsx)("span", {
|
|
252
|
+
className: AgentTeamsCard_module_css_default.memberInitial,
|
|
253
|
+
children: member.name.trim().slice(0, 1).toUpperCase() || "?"
|
|
254
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
255
|
+
className: AgentTeamsCard_module_css_default.memberName,
|
|
256
|
+
children: member.name
|
|
257
|
+
})]
|
|
258
|
+
}, member.id))
|
|
259
|
+
})]
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
//#endregion
|
|
263
|
+
//#region \0dsh-css:/Users/nanmi/workspace/myself_code/dsh-agent-teams/src/client/ActivityPanel.module.css.mjs
|
|
264
|
+
const css = "html{--agent-teams-panel-width:388px;--agent-teams-panel-right:calc(18px + var(--dsh-sidebar-width,0px));--agent-teams-panel-gap:14px;--agent-teams-panel-shift:calc(var(--agent-teams-panel-width) + 18px + var(--agent-teams-panel-gap))}html[data-agent-teams-panel-open] [data-phase=active]{box-sizing:border-box;padding-right:var(--agent-teams-panel-shift)}[data-phase=active]{will-change:padding-right;transition:padding-right .36s cubic-bezier(.22,1,.36,1)}.qZToFW_badge{top:64px;right:var(--agent-teams-panel-right);z-index:2147483000;box-sizing:border-box;border:1px solid var(--dsw-alias-line-normal);background:color-mix(in srgb, var(--dsw-alias-bg-module-platform) 92%, transparent);backdrop-filter:blur(16px);height:34px;box-shadow:0 8px 28px color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;border-radius:999px;align-items:center;gap:7px;padding:0 12px;font-size:12px;font-weight:600;line-height:20px;transition:border-color .15s,transform .12s;display:inline-flex;position:fixed}.qZToFW_badge:hover{border-color:var(--dsw-alias-line-strong);transform:translateY(-1px)}.qZToFW_badge:active{transform:translateY(0)scale(.98)}.qZToFW_badge:focus-visible,.qZToFW_closeButton:focus-visible,.qZToFW_memberRow:focus-visible,.qZToFW_taskNode:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.qZToFW_badgeDot,.qZToFW_panelDot{background:var(--dsw-alias-label-tertiary);border-radius:50%;width:7px;height:7px}.qZToFW_badgeDot[data-busy=true],.qZToFW_panelDot[data-busy=true]{background:var(--dsw-alias-state-business-primary);animation:1.25s ease-in-out infinite qZToFW_agentTeamsPulse}.qZToFW_badgeCount,.qZToFW_memberCount,.qZToFW_teamStats,.qZToFW_stageLabel,.qZToFW_taskId{font-variant-numeric:tabular-nums}.qZToFW_panel{top:64px;right:var(--agent-teams-panel-right);z-index:2147483000;width:min(var(--agent-teams-panel-width), calc(100vw - 24px));box-sizing:border-box;border:1px solid color-mix(in srgb, var(--dsw-alias-line-strong) 58%, transparent);background:color-mix(in srgb, var(--dsw-alias-bg-module-platform) 95%, transparent);backdrop-filter:blur(20px)saturate(1.08);max-height:70dvh;box-shadow:0 12px 32px color-mix(in srgb, var(--dsw-alias-label-primary) 12%, transparent), 0 32px 72px color-mix(in srgb, var(--dsw-alias-label-primary) 16%, transparent);border-radius:16px;flex-direction:column;animation:.18s ease-out qZToFW_agentTeamsPanelIn;display:flex;position:fixed;overflow:hidden}@keyframes qZToFW_agentTeamsPanelIn{0%{opacity:0;transform:translateY(-6px)scale(.99)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes qZToFW_agentTeamsPulse{0%,to{opacity:.42}50%{opacity:1}}.qZToFW_panelHead{border-bottom:1px solid var(--dsw-alias-line-normal);flex:none;justify-content:space-between;align-items:center;min-height:44px;padding:0 14px 0 16px;display:flex}.qZToFW_panelTitle{color:var(--dsw-alias-label-primary);align-items:center;gap:8px;font-size:14px;font-weight:600;line-height:20px;display:inline-flex}.qZToFW_closeButton{width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:7px;justify-content:center;align-items:center;padding:0;transition:background-color .12s,color .12s,transform .12s;display:inline-flex}.qZToFW_closeButton:hover{background:var(--dsw-alias-bg-fill-neutral);color:var(--dsw-alias-label-primary)}.qZToFW_closeButton:active{transform:scale(.94)}.qZToFW_teams{overscroll-behavior:contain;flex-direction:column;min-height:0;display:flex;overflow-y:auto}.qZToFW_team{border-bottom:1px solid var(--dsw-alias-line-normal);flex-direction:column;gap:12px;padding:12px 14px 16px;display:flex}.qZToFW_team:last-child{border-bottom:0}.qZToFW_teamHead{align-items:center;gap:10px;min-width:0;display:flex}.qZToFW_teamName{min-width:0;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:13px;font-weight:600;line-height:18px;overflow:hidden}.qZToFW_teamStats{color:var(--dsw-alias-label-tertiary);white-space:nowrap;flex:none;gap:8px;font-size:10.5px;line-height:16px;display:inline-flex}.qZToFW_sectionHead{justify-content:space-between;align-items:center;gap:8px;min-width:0;display:flex}.qZToFW_sectionTitle{color:var(--dsw-alias-label-secondary);align-items:center;gap:6px;font-size:11px;font-weight:600;line-height:16px;display:inline-flex}.qZToFW_sectionHint{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:10px;line-height:14px;overflow:hidden}.qZToFW_delegationSection{min-width:0}.qZToFW_captainNode{box-sizing:border-box;border:1px solid color-mix(in srgb, var(--dsw-alias-state-business-primary) 32%, var(--dsw-alias-line-normal));background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 7%, var(--dsw-alias-bg-module));border-radius:10px;grid-template-columns:38px minmax(0,1fr) auto;align-items:center;gap:9px;min-height:48px;padding:8px 10px;display:grid}.qZToFW_captainAvatar,.qZToFW_memberAvatar{flex:none;justify-content:center;align-items:center;display:inline-flex;position:relative}.qZToFW_captainAvatar{width:36px;height:36px}.qZToFW_leadAvatar,.qZToFW_memberArt,.qZToFW_memberInitial{box-sizing:border-box;border:1px solid var(--dsw-alias-line-strong);object-fit:cover;background:#0b1d33;border-radius:50%;width:34px;height:34px}.qZToFW_captainInfo,.qZToFW_memberInfo{flex-direction:column;min-width:0;display:flex}.qZToFW_captainInfo{gap:2px}.qZToFW_captainLine,.qZToFW_memberLine{align-items:center;gap:6px;min-width:0;display:flex}.qZToFW_captainName,.qZToFW_memberName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:12.5px;font-weight:600;line-height:18px;overflow:hidden}.qZToFW_captainRole,.qZToFW_memberRole{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:10px;line-height:14px;overflow:hidden}.qZToFW_captainSummary,.qZToFW_memberStatusLine{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-size:10.5px;line-height:15px;overflow:hidden}.qZToFW_captainState,.qZToFW_memberState{color:var(--dsw-alias-label-tertiary);white-space:nowrap;flex:none;align-items:center;gap:5px;font-size:10px;font-weight:500;line-height:15px;display:inline-flex}.qZToFW_captainState[data-busy=true],.qZToFW_memberState[data-activity=working]{color:var(--dsw-alias-state-business-primary)}.qZToFW_delegationTree{flex-direction:column;gap:2px;margin-left:18px;padding:9px 0 0 20px;display:flex;position:relative}.qZToFW_delegationTree:before{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 48%, var(--dsw-alias-line-normal));content:\"\";width:1px;position:absolute;top:0;bottom:22px;left:0}.qZToFW_memberBlock{flex-direction:column;min-width:0;padding:3px 0 7px;display:flex;position:relative}.qZToFW_memberBranch{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 48%, var(--dsw-alias-line-normal));width:20px;height:1px;display:block;position:absolute;top:23px;right:100%}.qZToFW_memberBranch:before{background:var(--dsw-alias-state-business-primary);content:\"\";border-radius:50%;width:5px;height:5px;position:absolute;top:-2px;right:-1px}.qZToFW_memberRow{box-sizing:border-box;width:100%;min-width:0;min-height:44px;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:8px;grid-template-columns:38px minmax(0,1fr) auto;align-items:center;gap:8px;padding:4px 6px;transition:background-color .12s,transform .12s;display:grid}.qZToFW_memberRow:hover,.qZToFW_memberRow[data-activity=working]{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 6%, var(--dsw-alias-bg-module))}.qZToFW_memberRow:active{transform:scale(.995)}.qZToFW_memberAvatar{width:34px;height:34px}.qZToFW_memberAvatar[data-unread=true]:after{border:1px solid var(--dsw-alias-state-business-primary);content:\"\";border-radius:50%;animation:1.5s ease-out infinite qZToFW_agentTeamsRing;position:absolute;inset:-3px}@keyframes qZToFW_agentTeamsRing{0%{opacity:.82;transform:scale(.94)}75%,to{opacity:0;transform:scale(1.18)}}.qZToFW_memberInitial{color:var(--dsw-alias-label-on-fill);justify-content:center;align-items:center;font-size:14px;font-weight:600;line-height:20px;display:inline-flex}.qZToFW_stateArt{box-sizing:border-box;border:2px solid var(--dsw-alias-bg-module-platform);object-fit:cover;background:#0b1d33;border-radius:50%;width:19px;height:19px;position:absolute;bottom:-4px;right:-4px}.qZToFW_stateArt[data-activity=working]{animation:2.4s ease-in-out infinite qZToFW_agentTeamsFloat}.qZToFW_stateArt[data-activity=idle]{animation:4.2s ease-in-out infinite qZToFW_agentTeamsBreathe}.qZToFW_stateArt[data-activity=unknown]{animation:2.8s ease-in-out infinite qZToFW_agentTeamsThink}@keyframes qZToFW_agentTeamsFloat{0%,to{transform:translateY(0)rotate(-4deg)}50%{transform:translateY(-2px)rotate(4deg)}}@keyframes qZToFW_agentTeamsBreathe{0%,to{opacity:.82;transform:scale(1)}50%{opacity:1;transform:scale(1.06)}}@keyframes qZToFW_agentTeamsThink{0%,to{transform:rotate(-7deg)}50%{transform:rotate(7deg)}}.qZToFW_memberState{margin-left:auto}.qZToFW_memberCount{color:var(--dsw-alias-label-tertiary);font-size:10.5px;line-height:16px}.qZToFW_assignmentLine{align-items:center;gap:7px;min-width:0;padding:0 6px 0 52px;display:flex}.qZToFW_assignmentLabel{color:var(--dsw-alias-label-tertiary);flex:none;font-size:9.5px;line-height:14px}.qZToFW_assignmentTasks{flex-wrap:wrap;flex:1;gap:4px;min-width:0;display:flex}.qZToFW_assignmentChip{background:var(--dsw-alias-bg-fill-neutral);min-height:16px;color:var(--dsw-alias-label-secondary);border-radius:4px;align-items:center;padding:0 5px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;font-weight:600;line-height:14px;display:inline-flex}.qZToFW_assignmentChip[data-state=running]{background:var(--dsw-alias-bg-fill-business);color:var(--dsw-alias-label-on-fill)}.qZToFW_assignmentChip[data-state=completed]{background:var(--dsw-alias-bg-fill-success);color:var(--dsw-alias-label-on-fill)}.qZToFW_assignmentChip[data-state=blocked]{background:var(--dsw-alias-bg-fill-warning);color:var(--dsw-alias-label-on-fill)}.qZToFW_assignmentChip[data-state=failed]{background:var(--dsw-alias-bg-fill-danger);color:var(--dsw-alias-label-on-fill)}.qZToFW_assignmentChip[data-state=cancelled]{color:var(--dsw-alias-label-tertiary);text-decoration:line-through}.qZToFW_unreadPill{color:var(--dsw-alias-state-business-primary);white-space:nowrap;flex:none;font-size:9.5px;font-weight:600;line-height:14px}.qZToFW_taskEmpty{color:var(--dsw-alias-label-tertiary);font-size:9.5px;line-height:14px}.qZToFW_dependencySection{border-top:1px solid var(--dsw-alias-line-normal);flex-direction:column;gap:7px;min-width:0;padding-top:10px;display:flex}.qZToFW_stageFlow{scrollbar-width:thin;align-items:stretch;gap:0;min-width:0;padding:1px 1px 5px;display:flex;overflow-x:auto}.qZToFW_stageGroup{flex:1 0 126px;min-width:126px;display:flex;position:relative}.qZToFW_stageConnector{width:22px;height:14px;color:var(--dsw-alias-label-tertiary);flex:none;align-items:center;margin-top:0;display:flex}.qZToFW_stageLine{background:var(--dsw-alias-line-strong);flex:1;height:1px;display:block}.qZToFW_stageColumn{flex-direction:column;flex:1;gap:5px;min-width:0;display:flex}.qZToFW_stageLabel{color:var(--dsw-alias-label-tertiary);justify-content:space-between;align-items:center;gap:6px;padding:0 2px;font-size:9.5px;font-weight:600;line-height:14px;display:flex}.qZToFW_stageLabel span{background:var(--dsw-alias-bg-fill-neutral);border-radius:4px;justify-content:center;align-items:center;min-width:14px;height:14px;font-size:8.5px;display:inline-flex}.qZToFW_stageTasks{flex-direction:column;gap:5px;display:flex}.qZToFW_taskNode{box-sizing:border-box;border:1px solid var(--dsw-alias-line-normal);background:var(--dsw-alias-bg-module);min-width:0;min-height:72px;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;border-radius:8px;flex-direction:column;gap:4px;padding:7px 8px;transition:border-color .14s,opacity .14s,transform .12s,background-color .14s;display:flex}.qZToFW_taskNode:hover,.qZToFW_taskNode[data-focused=true]{border-color:var(--dsw-alias-state-business-primary);background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 6%, var(--dsw-alias-bg-module));transform:translateY(-1px)}.qZToFW_taskNode[data-dimmed=true]{opacity:.34}.qZToFW_taskNode[data-state=completed]{border-color:color-mix(in srgb, var(--dsw-alias-state-success) 48%, var(--dsw-alias-line-normal))}.qZToFW_taskNode[data-state=blocked]{border-color:color-mix(in srgb, var(--dsw-alias-state-warning) 52%, var(--dsw-alias-line-normal))}.qZToFW_taskNode[data-state=failed]{border-color:color-mix(in srgb, var(--dsw-alias-state-danger) 56%, var(--dsw-alias-line-normal))}.qZToFW_taskNodeHead,.qZToFW_taskRoute{justify-content:space-between;align-items:center;gap:5px;min-width:0;display:flex}.qZToFW_taskId{color:var(--dsw-alias-label-tertiary);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9.5px;font-weight:700}.qZToFW_taskBadge{background:var(--dsw-alias-bg-fill-neutral);min-height:14px;color:var(--dsw-alias-label-secondary);border-radius:4px;flex:none;align-items:center;padding:0 4px;font-size:8.5px;font-weight:600;line-height:13px;display:inline-flex}.qZToFW_taskBadge[data-state=running]{background:var(--dsw-alias-bg-fill-business);color:var(--dsw-alias-label-on-fill)}.qZToFW_taskBadge[data-state=completed]{background:var(--dsw-alias-bg-fill-success);color:var(--dsw-alias-label-on-fill)}.qZToFW_taskBadge[data-state=blocked]{background:var(--dsw-alias-bg-fill-warning);color:var(--dsw-alias-label-on-fill)}.qZToFW_taskBadge[data-state=failed]{background:var(--dsw-alias-bg-fill-danger);color:var(--dsw-alias-label-on-fill)}.qZToFW_taskBadge[data-state=cancelled]{color:var(--dsw-alias-label-tertiary);text-decoration:line-through}.qZToFW_taskSubject{min-height:30px;color:var(--dsw-alias-label-primary);-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:10.5px;font-weight:500;line-height:15px;display:-webkit-box;overflow:hidden}.qZToFW_taskRoute{color:var(--dsw-alias-label-tertiary);margin-top:auto;font-size:8.5px;line-height:13px}.qZToFW_taskOwner,.qZToFW_taskDeps{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.qZToFW_taskOwner{max-width:48%;color:var(--dsw-alias-label-secondary);font-weight:600}.qZToFW_taskDeps{text-align:right;flex:1}.qZToFW_taskStart{color:var(--dsw-alias-label-tertiary)}.qZToFW_unclaimed,.qZToFW_inbox{border-top:1px solid var(--dsw-alias-line-normal);flex-direction:column;gap:5px;min-width:0;padding-top:10px;display:flex}.qZToFW_unclaimedTitle{color:var(--dsw-alias-label-secondary);font-size:10.5px;font-weight:600;line-height:15px}.qZToFW_inboxRow{border-radius:6px;grid-template-columns:112px minmax(0,1fr);align-items:center;gap:8px;min-width:0;min-height:24px;padding:2px 5px;display:grid}.qZToFW_inboxRow:hover{background:var(--dsw-alias-bg-module)}.qZToFW_inboxRoute{min-width:0;color:var(--dsw-alias-state-business-primary);text-overflow:ellipsis;white-space:nowrap;align-items:center;gap:3px;font-size:9.5px;font-weight:600;line-height:14px;display:inline-flex;overflow:hidden}.qZToFW_inboxContent{min-width:0;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:10px;line-height:14px;overflow:hidden}.qZToFW_emptyHint{color:var(--dsw-alias-label-tertiary);padding:10px 12px;font-size:11px;line-height:16px}.qZToFW_team[data-historic],.qZToFW_archivedWrap{opacity:.82}.qZToFW_historicPill{background:var(--dsw-alias-bg-fill-neutral);color:var(--dsw-alias-label-tertiary);border-radius:4px;flex:none;margin-left:auto;padding:1px 7px;font-size:9.5px;font-weight:600;line-height:15px}.qZToFW_members{flex-direction:column;gap:3px;display:flex}.qZToFW_archivedWrap:before{color:var(--dsw-alias-label-tertiary);content:\"已结束 · 历史归档\";padding:5px 14px 0;font-size:9.5px;font-weight:600;line-height:14px;display:block}@media (prefers-reduced-motion:reduce){[data-phase=active],.qZToFW_panel,.qZToFW_badge,.qZToFW_badgeDot,.qZToFW_panelDot,.qZToFW_stateArt,.qZToFW_memberAvatar[data-unread=true]:after{transition:none;animation:none}}@media (width<=960px){html{--agent-teams-main-shift:0px}html[data-agent-teams-panel-open] [data-phase=active]{padding-right:0}}@media (width<=640px){html{--agent-teams-panel-right:calc(10px + var(--dsh-sidebar-width,0px))}.qZToFW_panel{width:auto;max-height:calc(100dvh - 68px);top:56px;left:10px}.qZToFW_badge{top:56px}.qZToFW_teamStats span[data-stat=messages]{display:none}.qZToFW_captainNode{grid-template-columns:38px minmax(0,1fr)}.qZToFW_captainState{display:none}.qZToFW_delegationTree{margin-left:12px;padding-left:15px}.qZToFW_memberBranch{width:15px}.qZToFW_assignmentLine{padding-left:45px}}";
|
|
265
|
+
const tagId = "dsh-agent-teams/ActivityPanel.module.css";
|
|
266
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
267
|
+
const tag = document.createElement("style");
|
|
268
|
+
tag.dataset.plugin = "dsh-agent-teams";
|
|
269
|
+
tag.dataset.pluginCss = tagId;
|
|
270
|
+
tag.textContent = css;
|
|
271
|
+
document.head.appendChild(tag);
|
|
272
|
+
}
|
|
273
|
+
var ActivityPanel_module_css_default = {
|
|
274
|
+
"inbox": "qZToFW_inbox",
|
|
275
|
+
"unclaimedTitle": "qZToFW_unclaimedTitle",
|
|
276
|
+
"panelHead": "qZToFW_panelHead",
|
|
277
|
+
"panelDot": "qZToFW_panelDot",
|
|
278
|
+
"agentTeamsBreathe": "qZToFW_agentTeamsBreathe",
|
|
279
|
+
"team": "qZToFW_team",
|
|
280
|
+
"assignmentTasks": "qZToFW_assignmentTasks",
|
|
281
|
+
"archivedWrap": "qZToFW_archivedWrap",
|
|
282
|
+
"stageGroup": "qZToFW_stageGroup",
|
|
283
|
+
"memberAvatar": "qZToFW_memberAvatar",
|
|
284
|
+
"dependencySection": "qZToFW_dependencySection",
|
|
285
|
+
"sectionHint": "qZToFW_sectionHint",
|
|
286
|
+
"memberState": "qZToFW_memberState",
|
|
287
|
+
"taskNodeHead": "qZToFW_taskNodeHead",
|
|
288
|
+
"inboxContent": "qZToFW_inboxContent",
|
|
289
|
+
"captainRole": "qZToFW_captainRole",
|
|
290
|
+
"taskId": "qZToFW_taskId",
|
|
291
|
+
"captainSummary": "qZToFW_captainSummary",
|
|
292
|
+
"badgeCount": "qZToFW_badgeCount",
|
|
293
|
+
"taskSubject": "qZToFW_taskSubject",
|
|
294
|
+
"captainState": "qZToFW_captainState",
|
|
295
|
+
"teamStats": "qZToFW_teamStats",
|
|
296
|
+
"taskRoute": "qZToFW_taskRoute",
|
|
297
|
+
"sectionTitle": "qZToFW_sectionTitle",
|
|
298
|
+
"taskEmpty": "qZToFW_taskEmpty",
|
|
299
|
+
"agentTeamsRing": "qZToFW_agentTeamsRing",
|
|
300
|
+
"stageLine": "qZToFW_stageLine",
|
|
301
|
+
"assignmentLine": "qZToFW_assignmentLine",
|
|
302
|
+
"inboxRow": "qZToFW_inboxRow",
|
|
303
|
+
"emptyHint": "qZToFW_emptyHint",
|
|
304
|
+
"members": "qZToFW_members",
|
|
305
|
+
"captainAvatar": "qZToFW_captainAvatar",
|
|
306
|
+
"stateArt": "qZToFW_stateArt",
|
|
307
|
+
"agentTeamsThink": "qZToFW_agentTeamsThink",
|
|
308
|
+
"memberRow": "qZToFW_memberRow",
|
|
309
|
+
"memberCount": "qZToFW_memberCount",
|
|
310
|
+
"agentTeamsPanelIn": "qZToFW_agentTeamsPanelIn",
|
|
311
|
+
"captainNode": "qZToFW_captainNode",
|
|
312
|
+
"delegationTree": "qZToFW_delegationTree",
|
|
313
|
+
"taskOwner": "qZToFW_taskOwner",
|
|
314
|
+
"memberArt": "qZToFW_memberArt",
|
|
315
|
+
"stageColumn": "qZToFW_stageColumn",
|
|
316
|
+
"taskDeps": "qZToFW_taskDeps",
|
|
317
|
+
"assignmentChip": "qZToFW_assignmentChip",
|
|
318
|
+
"panelTitle": "qZToFW_panelTitle",
|
|
319
|
+
"captainLine": "qZToFW_captainLine",
|
|
320
|
+
"stageTasks": "qZToFW_stageTasks",
|
|
321
|
+
"delegationSection": "qZToFW_delegationSection",
|
|
322
|
+
"teams": "qZToFW_teams",
|
|
323
|
+
"taskStart": "qZToFW_taskStart",
|
|
324
|
+
"badgeDot": "qZToFW_badgeDot",
|
|
325
|
+
"panel": "qZToFW_panel",
|
|
326
|
+
"teamHead": "qZToFW_teamHead",
|
|
327
|
+
"memberBlock": "qZToFW_memberBlock",
|
|
328
|
+
"leadAvatar": "qZToFW_leadAvatar",
|
|
329
|
+
"agentTeamsFloat": "qZToFW_agentTeamsFloat",
|
|
330
|
+
"memberInfo": "qZToFW_memberInfo",
|
|
331
|
+
"memberStatusLine": "qZToFW_memberStatusLine",
|
|
332
|
+
"captainName": "qZToFW_captainName",
|
|
333
|
+
"historicPill": "qZToFW_historicPill",
|
|
334
|
+
"memberLine": "qZToFW_memberLine",
|
|
335
|
+
"stageFlow": "qZToFW_stageFlow",
|
|
336
|
+
"unreadPill": "qZToFW_unreadPill",
|
|
337
|
+
"stageLabel": "qZToFW_stageLabel",
|
|
338
|
+
"inboxRoute": "qZToFW_inboxRoute",
|
|
339
|
+
"stageConnector": "qZToFW_stageConnector",
|
|
340
|
+
"sectionHead": "qZToFW_sectionHead",
|
|
341
|
+
"badge": "qZToFW_badge",
|
|
342
|
+
"teamName": "qZToFW_teamName",
|
|
343
|
+
"memberInitial": "qZToFW_memberInitial",
|
|
344
|
+
"taskNode": "qZToFW_taskNode",
|
|
345
|
+
"closeButton": "qZToFW_closeButton",
|
|
346
|
+
"unclaimed": "qZToFW_unclaimed",
|
|
347
|
+
"memberName": "qZToFW_memberName",
|
|
348
|
+
"captainInfo": "qZToFW_captainInfo",
|
|
349
|
+
"taskBadge": "qZToFW_taskBadge",
|
|
350
|
+
"assignmentLabel": "qZToFW_assignmentLabel",
|
|
351
|
+
"agentTeamsPulse": "qZToFW_agentTeamsPulse",
|
|
352
|
+
"memberRole": "qZToFW_memberRole",
|
|
353
|
+
"memberBranch": "qZToFW_memberBranch"
|
|
354
|
+
};
|
|
355
|
+
//#endregion
|
|
356
|
+
//#region lib/client/ActivityPanel.js
|
|
357
|
+
/**
|
|
358
|
+
* AgentTeams activity panel: the top-right floater monitoring every team.
|
|
359
|
+
*
|
|
360
|
+
* Modeled on the Claude Code desktop SessionActivityPanel: a fixed glass
|
|
361
|
+
* panel at the top-right corner. On wide viewports it cooperatively makes the
|
|
362
|
+
* conversation column yield space; narrow viewports keep overlay mode. It
|
|
363
|
+
* polls the host `/plugins/dsh-agent-teams/state` route for
|
|
364
|
+
* server-side snapshots (durable files + live subagent activity), with a
|
|
365
|
+
* collapsed badge that auto-expands once when activity appears. Archived
|
|
366
|
+
* teams stay available for the owning conversation after live work ends.
|
|
367
|
+
*
|
|
368
|
+
* The floater mounts through a body portal (no top-right slot exists in the
|
|
369
|
+
* web shell); it is not a conversation node — the in-conversation panel was
|
|
370
|
+
* removed in favor of this always-available monitor.
|
|
371
|
+
* @module dsh-agent-teams/client/activity
|
|
372
|
+
*/
|
|
373
|
+
/** Poll cadence for the host snapshot route. */
|
|
374
|
+
const POLL_MS = 1e3;
|
|
375
|
+
/** Grace before the panel collapses once no team remains. */
|
|
376
|
+
const AUTOCLOSE_GRACE_MS = 2e3;
|
|
377
|
+
/**
|
|
378
|
+
* Page-settle window after mount: activity restored on page load only shows
|
|
379
|
+
* the collapsed badge, so the panel never yanks the conversation column
|
|
380
|
+
* right after load. New activity after this window auto-expands as usual.
|
|
381
|
+
*/
|
|
382
|
+
const AUTO_OPEN_SETTLE_MS = 4e3;
|
|
383
|
+
/** Host route serving team snapshots. */
|
|
384
|
+
const STATE_URL = "/plugins/dsh-agent-teams/state";
|
|
385
|
+
/** Root marker shared with the panel CSS while the portal is expanded. */
|
|
386
|
+
const PANEL_OPEN_ATTRIBUTE = "data-agent-teams-panel-open";
|
|
387
|
+
/** Initial-letter fallback for unmatched roles. */
|
|
388
|
+
function memberInitial(name) {
|
|
389
|
+
return name.trim().slice(0, 1).toUpperCase() || "?";
|
|
390
|
+
}
|
|
391
|
+
function stableHash(value) {
|
|
392
|
+
let hash = 0;
|
|
393
|
+
for (let index = 0; index < value.length; index += 1) hash = (hash << 5) - hash + value.charCodeAt(index) | 0;
|
|
394
|
+
return Math.abs(hash);
|
|
395
|
+
}
|
|
396
|
+
const ACCENTS = [
|
|
397
|
+
"var(--dsw-alias-state-business-primary)",
|
|
398
|
+
"var(--dsw-alias-state-success)",
|
|
399
|
+
"var(--dsw-alias-state-danger)",
|
|
400
|
+
"var(--dsw-alias-state-warning)",
|
|
401
|
+
"var(--dsw-alias-label-tertiary)"
|
|
402
|
+
];
|
|
403
|
+
function accentOf(id) {
|
|
404
|
+
return ACCENTS[stableHash(id) % ACCENTS.length] ?? ACCENTS[0];
|
|
405
|
+
}
|
|
406
|
+
/** Badge text follows the raw task status (finer than the 4 visual states):
|
|
407
|
+
* claimed/pending/failed/cancelled keep their own labels and colors. */
|
|
408
|
+
const TASK_STATUS_LABEL = {
|
|
409
|
+
pending: "待领取",
|
|
410
|
+
claimed: "已认领",
|
|
411
|
+
in_progress: "进行中",
|
|
412
|
+
completed: "已完成",
|
|
413
|
+
failed: "失败",
|
|
414
|
+
cancelled: "已取消"
|
|
415
|
+
};
|
|
416
|
+
function taskStatusLabel(status) {
|
|
417
|
+
return TASK_STATUS_LABEL[status] ?? status;
|
|
418
|
+
}
|
|
419
|
+
/** Badge/bar coloring key: visual state, widened for terminal statuses. */
|
|
420
|
+
function taskTone(state, status) {
|
|
421
|
+
if (status === "failed") return "failed";
|
|
422
|
+
if (status === "cancelled") return "cancelled";
|
|
423
|
+
return state;
|
|
424
|
+
}
|
|
425
|
+
/** Collapsed badge: an always-visible corner pill while any team exists. */
|
|
426
|
+
function CollapsedBadge({ count, busy, onClick }) {
|
|
427
|
+
return (0, react_jsx_runtime.jsxs)("button", {
|
|
428
|
+
type: "button",
|
|
429
|
+
className: ActivityPanel_module_css_default.badge,
|
|
430
|
+
"data-busy": busy,
|
|
431
|
+
onClick,
|
|
432
|
+
"aria-label": `AgentTeams 活动,${count} 个团队`,
|
|
433
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
434
|
+
className: ActivityPanel_module_css_default.badgeDot,
|
|
435
|
+
"data-busy": busy,
|
|
436
|
+
"aria-hidden": true
|
|
437
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
438
|
+
className: ActivityPanel_module_css_default.badgeCount,
|
|
439
|
+
children: count
|
|
440
|
+
})]
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
function memberDotState(member, tasks) {
|
|
444
|
+
const owned = tasks.filter((task) => task.assignee === member.name);
|
|
445
|
+
if (member.activity === "working") return "ongoing";
|
|
446
|
+
if (owned.some((task) => task.status === "failed")) return "error";
|
|
447
|
+
if (owned.length > 0 && owned.every((task) => task.status === "completed")) return "done";
|
|
448
|
+
return "warning";
|
|
449
|
+
}
|
|
450
|
+
function memberStateLabel(member, tasks) {
|
|
451
|
+
const owned = tasks.filter((task) => task.assignee === member.name);
|
|
452
|
+
if (member.activity === "working") return "工作中";
|
|
453
|
+
if (owned.some((task) => task.status === "failed")) return "有失败";
|
|
454
|
+
if (owned.some((task) => task.state === "blocked")) return "等待";
|
|
455
|
+
if (owned.length > 0 && owned.every((task) => task.status === "completed")) return "已交付";
|
|
456
|
+
if (owned.length > 0) return "待执行";
|
|
457
|
+
return "待派工";
|
|
458
|
+
}
|
|
459
|
+
function memberStatusText(member, tasks) {
|
|
460
|
+
const owned = tasks.filter((task) => task.assignee === member.name);
|
|
461
|
+
const current = owned.find((task) => task.id === member.currentTask);
|
|
462
|
+
const blocked = owned.find((task) => task.state === "blocked");
|
|
463
|
+
if (member.activity === "working" && current !== void 0) return `正在执行 ${current.id}`;
|
|
464
|
+
if (member.activity === "working") return "正在处理已派任务";
|
|
465
|
+
if (blocked !== void 0) {
|
|
466
|
+
const dependency = tasks.find((task) => blocked.dependencies.includes(task.id) && task.state !== "completed");
|
|
467
|
+
if (dependency !== void 0) return `等待 ${dependency.id} · ${dependency.assignee || "待认领"}`;
|
|
468
|
+
return "等待前置任务";
|
|
469
|
+
}
|
|
470
|
+
if (member.total === 0) return "等待队长派工";
|
|
471
|
+
if (member.done === member.total) return "任务已交付";
|
|
472
|
+
return member.activity === "idle" ? "待继续执行" : "状态未知";
|
|
473
|
+
}
|
|
474
|
+
function dependencyLabel(task, tasks) {
|
|
475
|
+
return task.dependencies.map((id) => {
|
|
476
|
+
const dependency = tasks.find((candidate) => candidate.id === id);
|
|
477
|
+
return dependency?.assignee ? `${id}·${dependency.assignee}` : id;
|
|
478
|
+
}).join("、");
|
|
479
|
+
}
|
|
480
|
+
function TaskNode({ task, tasks, focused, dimmed, pinned, onPin, onPreview }) {
|
|
481
|
+
const tone = taskTone(task.state, task.status);
|
|
482
|
+
return (0, react_jsx_runtime.jsxs)("button", {
|
|
483
|
+
type: "button",
|
|
484
|
+
className: ActivityPanel_module_css_default.taskNode,
|
|
485
|
+
"data-task-id": task.id,
|
|
486
|
+
"data-state": tone,
|
|
487
|
+
"data-focused": focused,
|
|
488
|
+
"data-dimmed": dimmed,
|
|
489
|
+
"aria-pressed": pinned,
|
|
490
|
+
title: `${task.id} · ${task.subject}(点击固定依赖链)`,
|
|
491
|
+
onClick: () => {
|
|
492
|
+
onPin(task.id);
|
|
493
|
+
},
|
|
494
|
+
onMouseEnter: () => {
|
|
495
|
+
onPreview(task.id);
|
|
496
|
+
},
|
|
497
|
+
onMouseLeave: () => {
|
|
498
|
+
onPreview(null);
|
|
499
|
+
},
|
|
500
|
+
onFocus: () => {
|
|
501
|
+
onPreview(task.id);
|
|
502
|
+
},
|
|
503
|
+
onBlur: () => {
|
|
504
|
+
onPreview(null);
|
|
505
|
+
},
|
|
506
|
+
children: [
|
|
507
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
508
|
+
className: ActivityPanel_module_css_default.taskNodeHead,
|
|
509
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
510
|
+
className: ActivityPanel_module_css_default.taskId,
|
|
511
|
+
children: task.id
|
|
512
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
513
|
+
className: ActivityPanel_module_css_default.taskBadge,
|
|
514
|
+
"data-state": tone,
|
|
515
|
+
children: taskStatusLabel(task.status)
|
|
516
|
+
})]
|
|
517
|
+
}),
|
|
518
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
519
|
+
className: ActivityPanel_module_css_default.taskSubject,
|
|
520
|
+
children: task.subject
|
|
521
|
+
}),
|
|
522
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
523
|
+
className: ActivityPanel_module_css_default.taskRoute,
|
|
524
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
525
|
+
className: ActivityPanel_module_css_default.taskOwner,
|
|
526
|
+
children: task.assignee || "待认领"
|
|
527
|
+
}), task.dependencies.length === 0 ? (0, react_jsx_runtime.jsx)("span", {
|
|
528
|
+
className: ActivityPanel_module_css_default.taskStart,
|
|
529
|
+
children: "起点"
|
|
530
|
+
}) : (0, react_jsx_runtime.jsxs)("span", {
|
|
531
|
+
className: ActivityPanel_module_css_default.taskDeps,
|
|
532
|
+
children: ["依赖 ", dependencyLabel(task, tasks)]
|
|
533
|
+
})]
|
|
534
|
+
})
|
|
535
|
+
]
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
function DependencyMap({ tasks }) {
|
|
539
|
+
const [previewTaskId, setPreviewTaskId] = (0, react.useState)(null);
|
|
540
|
+
const [pinnedTaskId, setPinnedTaskId] = (0, react.useState)(null);
|
|
541
|
+
const focusedTaskId = pinnedTaskId ?? previewTaskId;
|
|
542
|
+
const stages = (0, react.useMemo)(() => taskStages(tasks), [tasks]);
|
|
543
|
+
const related = (0, react.useMemo)(() => focusedTaskId === null ? null : relatedTaskIds(focusedTaskId, tasks), [focusedTaskId, tasks]);
|
|
544
|
+
(0, react.useEffect)(() => {
|
|
545
|
+
const onKeyDown = (event) => {
|
|
546
|
+
if (event.key === "Escape") setPinnedTaskId(null);
|
|
547
|
+
};
|
|
548
|
+
window.addEventListener("keydown", onKeyDown);
|
|
549
|
+
return () => {
|
|
550
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
551
|
+
};
|
|
552
|
+
}, []);
|
|
553
|
+
if (tasks.length === 0) return null;
|
|
554
|
+
return (0, react_jsx_runtime.jsxs)("section", {
|
|
555
|
+
className: ActivityPanel_module_css_default.dependencySection,
|
|
556
|
+
"aria-label": "任务依赖链",
|
|
557
|
+
"data-dependency-map": true,
|
|
558
|
+
children: [(0, react_jsx_runtime.jsxs)("header", {
|
|
559
|
+
className: ActivityPanel_module_css_default.sectionHead,
|
|
560
|
+
children: [(0, react_jsx_runtime.jsxs)("span", {
|
|
561
|
+
className: ActivityPanel_module_css_default.sectionTitle,
|
|
562
|
+
children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {}), " 任务依赖"]
|
|
563
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
564
|
+
className: ActivityPanel_module_css_default.sectionHint,
|
|
565
|
+
children: pinnedTaskId === null ? "悬停预览 · 点击固定" : `${pinnedTaskId} 已固定 · Esc 取消`
|
|
566
|
+
})]
|
|
567
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
568
|
+
className: ActivityPanel_module_css_default.stageFlow,
|
|
569
|
+
children: stages.map((stage, index) => (0, react_jsx_runtime.jsxs)("div", {
|
|
570
|
+
className: ActivityPanel_module_css_default.stageGroup,
|
|
571
|
+
"data-depth": stage.depth,
|
|
572
|
+
children: [index > 0 && (0, react_jsx_runtime.jsxs)("span", {
|
|
573
|
+
className: ActivityPanel_module_css_default.stageConnector,
|
|
574
|
+
"aria-hidden": true,
|
|
575
|
+
children: [(0, react_jsx_runtime.jsx)("span", { className: ActivityPanel_module_css_default.stageLine }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, {})]
|
|
576
|
+
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
577
|
+
className: ActivityPanel_module_css_default.stageColumn,
|
|
578
|
+
children: [(0, react_jsx_runtime.jsxs)("span", {
|
|
579
|
+
className: ActivityPanel_module_css_default.stageLabel,
|
|
580
|
+
children: [stage.depth === 0 ? "起点" : `依赖层 ${stage.depth}`, (0, react_jsx_runtime.jsx)("span", { children: stage.tasks.length })]
|
|
581
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
582
|
+
className: ActivityPanel_module_css_default.stageTasks,
|
|
583
|
+
children: stage.tasks.map((task) => (0, react_jsx_runtime.jsx)(TaskNode, {
|
|
584
|
+
task,
|
|
585
|
+
tasks,
|
|
586
|
+
focused: related?.has(task.id) ?? false,
|
|
587
|
+
dimmed: related !== null && !related.has(task.id),
|
|
588
|
+
pinned: pinnedTaskId === task.id,
|
|
589
|
+
onPin: (id) => {
|
|
590
|
+
setPinnedTaskId((current) => current === id ? null : id);
|
|
591
|
+
},
|
|
592
|
+
onPreview: setPreviewTaskId
|
|
593
|
+
}, task.id))
|
|
594
|
+
})]
|
|
595
|
+
})]
|
|
596
|
+
}, stage.depth))
|
|
597
|
+
})]
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
function TeamSection({ team, onNavigate, historic = false }) {
|
|
601
|
+
const busyCount = team.members.filter((member) => member.activity === "working").length;
|
|
602
|
+
const assignedCount = team.tasks.filter((task) => task.assignee !== "").length;
|
|
603
|
+
const completedCount = team.tasks.filter((task) => task.status === "completed").length;
|
|
604
|
+
const allCompleted = team.tasks.length > 0 && completedCount === team.tasks.length;
|
|
605
|
+
const unclaimed = team.tasks.filter((task) => {
|
|
606
|
+
if (task.status === "completed" || task.status === "failed" || task.status === "cancelled") return false;
|
|
607
|
+
if (task.assignee === "") return true;
|
|
608
|
+
return !team.members.some((member) => member.name === task.assignee);
|
|
609
|
+
});
|
|
610
|
+
return (0, react_jsx_runtime.jsxs)("section", {
|
|
611
|
+
className: ActivityPanel_module_css_default.team,
|
|
612
|
+
"data-team-id": team.teamId,
|
|
613
|
+
children: [
|
|
614
|
+
(0, react_jsx_runtime.jsxs)("header", {
|
|
615
|
+
className: ActivityPanel_module_css_default.teamHead,
|
|
616
|
+
children: [
|
|
617
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
618
|
+
className: ActivityPanel_module_css_default.teamName,
|
|
619
|
+
title: team.name,
|
|
620
|
+
children: team.name
|
|
621
|
+
}),
|
|
622
|
+
historic && (0, react_jsx_runtime.jsx)("span", {
|
|
623
|
+
className: ActivityPanel_module_css_default.historicPill,
|
|
624
|
+
children: "已结束"
|
|
625
|
+
}),
|
|
626
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
627
|
+
className: ActivityPanel_module_css_default.teamStats,
|
|
628
|
+
children: [
|
|
629
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
630
|
+
"data-stat": "members",
|
|
631
|
+
children: [team.members.length, " 成员"]
|
|
632
|
+
}),
|
|
633
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
634
|
+
"data-stat": "tasks",
|
|
635
|
+
children: [
|
|
636
|
+
completedCount,
|
|
637
|
+
"/",
|
|
638
|
+
team.tasks.length,
|
|
639
|
+
" 完成"
|
|
640
|
+
]
|
|
641
|
+
}),
|
|
642
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
643
|
+
"data-stat": "messages",
|
|
644
|
+
children: [team.messageCount, " 消息"]
|
|
645
|
+
})
|
|
646
|
+
]
|
|
647
|
+
})
|
|
648
|
+
]
|
|
649
|
+
}),
|
|
650
|
+
(0, react_jsx_runtime.jsxs)("section", {
|
|
651
|
+
className: ActivityPanel_module_css_default.delegationSection,
|
|
652
|
+
"aria-label": "队长派工关系",
|
|
653
|
+
"data-delegation-map": true,
|
|
654
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
655
|
+
className: ActivityPanel_module_css_default.captainNode,
|
|
656
|
+
children: [
|
|
657
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
658
|
+
className: ActivityPanel_module_css_default.captainAvatar,
|
|
659
|
+
children: (0, react_jsx_runtime.jsx)("img", {
|
|
660
|
+
className: ActivityPanel_module_css_default.leadAvatar,
|
|
661
|
+
src: LEAD_ART,
|
|
662
|
+
alt: "",
|
|
663
|
+
"aria-hidden": true
|
|
664
|
+
})
|
|
665
|
+
}),
|
|
666
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
667
|
+
className: ActivityPanel_module_css_default.captainInfo,
|
|
668
|
+
children: [(0, react_jsx_runtime.jsxs)("span", {
|
|
669
|
+
className: ActivityPanel_module_css_default.captainLine,
|
|
670
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
671
|
+
className: ActivityPanel_module_css_default.captainName,
|
|
672
|
+
children: "队长"
|
|
673
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
674
|
+
className: ActivityPanel_module_css_default.captainRole,
|
|
675
|
+
children: "拆解 · 派发 · 汇总"
|
|
676
|
+
})]
|
|
677
|
+
}), (0, react_jsx_runtime.jsxs)("span", {
|
|
678
|
+
className: ActivityPanel_module_css_default.captainSummary,
|
|
679
|
+
children: [
|
|
680
|
+
"已派发 ",
|
|
681
|
+
assignedCount,
|
|
682
|
+
" 项任务给 ",
|
|
683
|
+
team.members.length,
|
|
684
|
+
" 名成员"
|
|
685
|
+
]
|
|
686
|
+
})]
|
|
687
|
+
}),
|
|
688
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
689
|
+
className: ActivityPanel_module_css_default.captainState,
|
|
690
|
+
"data-busy": busyCount > 0,
|
|
691
|
+
children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: busyCount > 0 ? "ongoing" : allCompleted ? "done" : "warning" }), busyCount > 0 ? `${busyCount} 人执行中` : allCompleted ? "已收齐" : "等待回报"]
|
|
692
|
+
})
|
|
693
|
+
]
|
|
694
|
+
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
695
|
+
className: ActivityPanel_module_css_default.delegationTree,
|
|
696
|
+
children: [team.members.length === 0 && (0, react_jsx_runtime.jsx)("span", {
|
|
697
|
+
className: ActivityPanel_module_css_default.emptyHint,
|
|
698
|
+
children: "暂无成员,等待队长组建团队"
|
|
699
|
+
}), team.members.map((member) => {
|
|
700
|
+
const owned = team.tasks.filter((task) => task.assignee === member.name);
|
|
701
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
702
|
+
className: ActivityPanel_module_css_default.memberBlock,
|
|
703
|
+
"data-activity": member.activity,
|
|
704
|
+
children: [
|
|
705
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
706
|
+
className: ActivityPanel_module_css_default.memberBranch,
|
|
707
|
+
"aria-hidden": true,
|
|
708
|
+
children: (0, react_jsx_runtime.jsx)("span", {})
|
|
709
|
+
}),
|
|
710
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
711
|
+
type: "button",
|
|
712
|
+
className: ActivityPanel_module_css_default.memberRow,
|
|
713
|
+
"data-activity": member.activity,
|
|
714
|
+
onClick: () => {
|
|
715
|
+
if (member.id !== "") onNavigate(member.id);
|
|
716
|
+
},
|
|
717
|
+
children: [
|
|
718
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
719
|
+
className: ActivityPanel_module_css_default.memberAvatar,
|
|
720
|
+
"data-unread": member.unread > 0,
|
|
721
|
+
children: [memberArtUrl(member.name, member.role) !== null ? (0, react_jsx_runtime.jsx)("img", {
|
|
722
|
+
className: ActivityPanel_module_css_default.memberArt,
|
|
723
|
+
src: memberArtUrl(member.name, member.role) ?? "",
|
|
724
|
+
alt: "",
|
|
725
|
+
"aria-hidden": true
|
|
726
|
+
}) : (0, react_jsx_runtime.jsx)("span", {
|
|
727
|
+
className: ActivityPanel_module_css_default.memberInitial,
|
|
728
|
+
style: { background: accentOf(member.id) },
|
|
729
|
+
children: memberInitial(member.name)
|
|
730
|
+
}), (0, react_jsx_runtime.jsx)("img", {
|
|
731
|
+
className: ActivityPanel_module_css_default.stateArt,
|
|
732
|
+
"data-activity": member.activity,
|
|
733
|
+
src: ACTION_ART[member.activity],
|
|
734
|
+
alt: "",
|
|
735
|
+
"aria-hidden": true
|
|
736
|
+
})]
|
|
737
|
+
}),
|
|
738
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
739
|
+
className: ActivityPanel_module_css_default.memberInfo,
|
|
740
|
+
children: [(0, react_jsx_runtime.jsxs)("span", {
|
|
741
|
+
className: ActivityPanel_module_css_default.memberLine,
|
|
742
|
+
children: [
|
|
743
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
744
|
+
className: ActivityPanel_module_css_default.memberName,
|
|
745
|
+
children: member.name
|
|
746
|
+
}),
|
|
747
|
+
member.role !== "" && (0, react_jsx_runtime.jsx)("span", {
|
|
748
|
+
className: ActivityPanel_module_css_default.memberRole,
|
|
749
|
+
children: member.role
|
|
750
|
+
}),
|
|
751
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
752
|
+
className: ActivityPanel_module_css_default.memberState,
|
|
753
|
+
"data-activity": member.activity,
|
|
754
|
+
children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: memberDotState(member, team.tasks) }), memberStateLabel(member, team.tasks)]
|
|
755
|
+
})
|
|
756
|
+
]
|
|
757
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
758
|
+
className: ActivityPanel_module_css_default.memberStatusLine,
|
|
759
|
+
children: memberStatusText(member, team.tasks)
|
|
760
|
+
})]
|
|
761
|
+
}),
|
|
762
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
763
|
+
className: ActivityPanel_module_css_default.memberCount,
|
|
764
|
+
children: [
|
|
765
|
+
member.done,
|
|
766
|
+
"/",
|
|
767
|
+
member.total
|
|
768
|
+
]
|
|
769
|
+
})
|
|
770
|
+
]
|
|
771
|
+
}),
|
|
772
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
773
|
+
className: ActivityPanel_module_css_default.assignmentLine,
|
|
774
|
+
children: [
|
|
775
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
776
|
+
className: ActivityPanel_module_css_default.assignmentLabel,
|
|
777
|
+
children: "队长派发"
|
|
778
|
+
}),
|
|
779
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
780
|
+
className: ActivityPanel_module_css_default.assignmentTasks,
|
|
781
|
+
children: owned.length === 0 ? (0, react_jsx_runtime.jsx)("span", {
|
|
782
|
+
className: ActivityPanel_module_css_default.taskEmpty,
|
|
783
|
+
children: "暂无任务"
|
|
784
|
+
}) : owned.map((task) => (0, react_jsx_runtime.jsx)("span", {
|
|
785
|
+
className: ActivityPanel_module_css_default.assignmentChip,
|
|
786
|
+
"data-state": taskTone(task.state, task.status),
|
|
787
|
+
title: task.subject,
|
|
788
|
+
children: task.id
|
|
789
|
+
}, task.id))
|
|
790
|
+
}),
|
|
791
|
+
member.unread > 0 && (0, react_jsx_runtime.jsxs)("span", {
|
|
792
|
+
className: ActivityPanel_module_css_default.unreadPill,
|
|
793
|
+
children: [member.unread, " 条消息"]
|
|
794
|
+
})
|
|
795
|
+
]
|
|
796
|
+
})
|
|
797
|
+
]
|
|
798
|
+
}, member.id);
|
|
799
|
+
})]
|
|
800
|
+
})]
|
|
801
|
+
}),
|
|
802
|
+
(0, react_jsx_runtime.jsx)(DependencyMap, { tasks: team.tasks }),
|
|
803
|
+
unclaimed.length > 0 && (0, react_jsx_runtime.jsxs)("section", {
|
|
804
|
+
className: ActivityPanel_module_css_default.unclaimed,
|
|
805
|
+
"aria-label": "待认领任务",
|
|
806
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
807
|
+
className: ActivityPanel_module_css_default.unclaimedTitle,
|
|
808
|
+
children: "待队长认领或改派"
|
|
809
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
810
|
+
className: ActivityPanel_module_css_default.assignmentTasks,
|
|
811
|
+
children: unclaimed.map((task) => (0, react_jsx_runtime.jsxs)("span", {
|
|
812
|
+
className: ActivityPanel_module_css_default.assignmentChip,
|
|
813
|
+
"data-state": taskTone(task.state, task.status),
|
|
814
|
+
title: task.subject,
|
|
815
|
+
children: [
|
|
816
|
+
task.id,
|
|
817
|
+
" · ",
|
|
818
|
+
task.assignee || "未分配"
|
|
819
|
+
]
|
|
820
|
+
}, task.id))
|
|
821
|
+
})]
|
|
822
|
+
}),
|
|
823
|
+
team.captainInbox.length > 0 && (0, react_jsx_runtime.jsxs)("section", {
|
|
824
|
+
className: ActivityPanel_module_css_default.inbox,
|
|
825
|
+
"aria-label": "成员回报队长",
|
|
826
|
+
children: [(0, react_jsx_runtime.jsxs)("header", {
|
|
827
|
+
className: ActivityPanel_module_css_default.sectionHead,
|
|
828
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
829
|
+
className: ActivityPanel_module_css_default.sectionTitle,
|
|
830
|
+
children: "成员回报"
|
|
831
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
832
|
+
className: ActivityPanel_module_css_default.sectionHint,
|
|
833
|
+
children: "流向队长"
|
|
834
|
+
})]
|
|
835
|
+
}), team.captainInbox.slice(-2).map((message, index) => (0, react_jsx_runtime.jsxs)("div", {
|
|
836
|
+
className: ActivityPanel_module_css_default.inboxRow,
|
|
837
|
+
children: [(0, react_jsx_runtime.jsxs)("span", {
|
|
838
|
+
className: ActivityPanel_module_css_default.inboxRoute,
|
|
839
|
+
children: [
|
|
840
|
+
message.from,
|
|
841
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, {}),
|
|
842
|
+
"队长"
|
|
843
|
+
]
|
|
844
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
845
|
+
className: ActivityPanel_module_css_default.inboxContent,
|
|
846
|
+
title: message.content,
|
|
847
|
+
children: message.content
|
|
848
|
+
})]
|
|
849
|
+
}, index))]
|
|
850
|
+
})
|
|
851
|
+
]
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
/** The top-right activity floater. Teams follow the current session: live
|
|
855
|
+
* snapshots and historic card summaries are only shown while their captain
|
|
856
|
+
* session is the one currently open. */
|
|
857
|
+
function ActivityPanel({ sessionsList, openSession }) {
|
|
858
|
+
const navigateToSession = (id) => {
|
|
859
|
+
setOpen(false);
|
|
860
|
+
setWasActive(false);
|
|
861
|
+
openSession(id);
|
|
862
|
+
};
|
|
863
|
+
const [teams, setTeams] = (0, react.useState)([]);
|
|
864
|
+
const [archivedTeams, setArchivedTeams] = (0, react.useState)([]);
|
|
865
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
866
|
+
const [openOwner, setOpenOwner] = (0, react.useState)();
|
|
867
|
+
const [autoOpened, setAutoOpened] = (0, react.useState)(false);
|
|
868
|
+
const [wasActive, setWasActive] = (0, react.useState)(false);
|
|
869
|
+
const [historic, setHistoric] = (0, react.useState)(/* @__PURE__ */ new Map());
|
|
870
|
+
const current = (0, react.useSyncExternalStore)(sessionsList.subscribe, sessionsList.getSnapshot).current;
|
|
871
|
+
const currentRef = (0, react.useRef)(current);
|
|
872
|
+
(0, react.useEffect)(() => {
|
|
873
|
+
currentRef.current = current;
|
|
874
|
+
}, [current]);
|
|
875
|
+
const mountedAtRef = (0, react.useRef)(performance.now());
|
|
876
|
+
const expanded = activityPanelExpandedForSession(open, openOwner, current);
|
|
877
|
+
(0, react.useLayoutEffect)(() => {
|
|
878
|
+
if (openOwner === void 0 || openOwner === current) return;
|
|
879
|
+
setOpen(false);
|
|
880
|
+
setOpenOwner(void 0);
|
|
881
|
+
setWasActive(false);
|
|
882
|
+
setAutoOpened(false);
|
|
883
|
+
}, [current, openOwner]);
|
|
884
|
+
(0, react.useLayoutEffect)(() => {
|
|
885
|
+
const root = document.documentElement;
|
|
886
|
+
if (expanded) root.setAttribute(PANEL_OPEN_ATTRIBUTE, "");
|
|
887
|
+
else root.removeAttribute(PANEL_OPEN_ATTRIBUTE);
|
|
888
|
+
return () => {
|
|
889
|
+
root.removeAttribute(PANEL_OPEN_ATTRIBUTE);
|
|
890
|
+
};
|
|
891
|
+
}, [expanded]);
|
|
892
|
+
(0, react.useEffect)(() => {
|
|
893
|
+
let cancelled = false;
|
|
894
|
+
let inFlight = false;
|
|
895
|
+
const tick = async () => {
|
|
896
|
+
if (inFlight || cancelled) return;
|
|
897
|
+
inFlight = true;
|
|
898
|
+
try {
|
|
899
|
+
const [liveResponse, archivedResponse] = await Promise.all([fetch(STATE_URL, { cache: "no-store" }), fetch(`${STATE_URL}?archived=1`, { cache: "no-store" })]);
|
|
900
|
+
if (liveResponse.ok) {
|
|
901
|
+
const body = await liveResponse.json();
|
|
902
|
+
if (!cancelled && Array.isArray(body.teams)) setTeams(body.teams);
|
|
903
|
+
}
|
|
904
|
+
if (archivedResponse.ok) {
|
|
905
|
+
const body = await archivedResponse.json();
|
|
906
|
+
if (!cancelled && Array.isArray(body.teams)) setArchivedTeams(body.teams);
|
|
907
|
+
}
|
|
908
|
+
} catch {} finally {
|
|
909
|
+
inFlight = false;
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
tick();
|
|
913
|
+
const timer = setInterval(() => {
|
|
914
|
+
tick();
|
|
915
|
+
}, POLL_MS);
|
|
916
|
+
return () => {
|
|
917
|
+
cancelled = true;
|
|
918
|
+
clearInterval(timer);
|
|
919
|
+
};
|
|
920
|
+
}, []);
|
|
921
|
+
(0, react.useEffect)(() => {
|
|
922
|
+
const onOpenPanel = (event) => {
|
|
923
|
+
const activeSession = currentRef.current;
|
|
924
|
+
if (activeSession === void 0) return;
|
|
925
|
+
setOpenOwner(activeSession);
|
|
926
|
+
setOpen(true);
|
|
927
|
+
const detail = event.detail;
|
|
928
|
+
if (detail?.teamId !== void 0) {
|
|
929
|
+
const owner = detail.captainSessionId !== "" ? detail.captainSessionId : currentRef.current ?? "";
|
|
930
|
+
const teamKey = `${owner}:${detail.teamId}`;
|
|
931
|
+
setHistoric((previous) => {
|
|
932
|
+
const next = new Map(previous);
|
|
933
|
+
next.set(teamKey, {
|
|
934
|
+
data: detail,
|
|
935
|
+
owner
|
|
936
|
+
});
|
|
937
|
+
return next;
|
|
938
|
+
});
|
|
939
|
+
}
|
|
940
|
+
};
|
|
941
|
+
window.addEventListener(OPEN_PANEL_EVENT, onOpenPanel);
|
|
942
|
+
return () => {
|
|
943
|
+
window.removeEventListener(OPEN_PANEL_EVENT, onOpenPanel);
|
|
944
|
+
};
|
|
945
|
+
}, []);
|
|
946
|
+
const visibleTeams = (0, react.useMemo)(() => current === void 0 ? [] : teams.filter((team) => team.captainSessionId === current), [teams, current]);
|
|
947
|
+
const visibleHistoric = (0, react.useMemo)(() => current === void 0 ? [] : [...historic.values()].filter(({ data, owner }) => owner === current && !teams.some((live) => live.captainSessionId === current && live.teamId === data.teamId) && !archivedTeams.some((archived) => archived.captainSessionId === current && archived.teamId === data.teamId)), [
|
|
948
|
+
historic,
|
|
949
|
+
current,
|
|
950
|
+
teams,
|
|
951
|
+
archivedTeams
|
|
952
|
+
]);
|
|
953
|
+
const visibleArchived = (0, react.useMemo)(() => current === void 0 ? [] : archivedTeams.filter((team) => team.captainSessionId === current && !teams.some((live) => live.captainSessionId === current && live.teamId === team.teamId)), [
|
|
954
|
+
archivedTeams,
|
|
955
|
+
current,
|
|
956
|
+
teams
|
|
957
|
+
]);
|
|
958
|
+
const visibleCount = visibleTeams.length + visibleArchived.length + visibleHistoric.length;
|
|
959
|
+
(0, react.useEffect)(() => {
|
|
960
|
+
if (visibleCount > 0) {
|
|
961
|
+
setWasActive(true);
|
|
962
|
+
const settled = performance.now() - mountedAtRef.current >= AUTO_OPEN_SETTLE_MS;
|
|
963
|
+
if (!autoOpened && settled) {
|
|
964
|
+
setOpenOwner(current);
|
|
965
|
+
setOpen(true);
|
|
966
|
+
setAutoOpened(true);
|
|
967
|
+
}
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
if (!wasActive) return;
|
|
971
|
+
const timer = setTimeout(() => {
|
|
972
|
+
setOpen(false);
|
|
973
|
+
setOpenOwner(void 0);
|
|
974
|
+
setWasActive(false);
|
|
975
|
+
setAutoOpened(false);
|
|
976
|
+
}, AUTOCLOSE_GRACE_MS);
|
|
977
|
+
return () => {
|
|
978
|
+
clearTimeout(timer);
|
|
979
|
+
};
|
|
980
|
+
}, [
|
|
981
|
+
visibleCount,
|
|
982
|
+
autoOpened,
|
|
983
|
+
wasActive
|
|
984
|
+
]);
|
|
985
|
+
const busy = (0, react.useMemo)(() => visibleTeams.some((team) => team.members.some((member) => member.activity === "working")), [visibleTeams]);
|
|
986
|
+
if (!(visibleCount > 0) && !expanded) return null;
|
|
987
|
+
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [!expanded && (0, react_jsx_runtime.jsx)(CollapsedBadge, {
|
|
988
|
+
count: visibleCount,
|
|
989
|
+
busy,
|
|
990
|
+
onClick: () => {
|
|
991
|
+
if (current === void 0) return;
|
|
992
|
+
setOpenOwner(current);
|
|
993
|
+
setOpen(true);
|
|
994
|
+
}
|
|
995
|
+
}), expanded && (0, react_jsx_runtime.jsxs)("aside", {
|
|
996
|
+
className: ActivityPanel_module_css_default.panel,
|
|
997
|
+
"data-agent-teams-activity": true,
|
|
998
|
+
children: [(0, react_jsx_runtime.jsxs)("header", {
|
|
999
|
+
className: ActivityPanel_module_css_default.panelHead,
|
|
1000
|
+
children: [(0, react_jsx_runtime.jsxs)("span", {
|
|
1001
|
+
className: ActivityPanel_module_css_default.panelTitle,
|
|
1002
|
+
children: ["AgentTeams 活动", (0, react_jsx_runtime.jsx)("span", {
|
|
1003
|
+
className: ActivityPanel_module_css_default.panelDot,
|
|
1004
|
+
"data-busy": busy,
|
|
1005
|
+
"aria-hidden": true
|
|
1006
|
+
})]
|
|
1007
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
1008
|
+
type: "button",
|
|
1009
|
+
className: ActivityPanel_module_css_default.closeButton,
|
|
1010
|
+
onClick: () => {
|
|
1011
|
+
setOpen(false);
|
|
1012
|
+
setOpenOwner(void 0);
|
|
1013
|
+
},
|
|
1014
|
+
"aria-label": "关闭",
|
|
1015
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, {})
|
|
1016
|
+
})]
|
|
1017
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
1018
|
+
className: ActivityPanel_module_css_default.teams,
|
|
1019
|
+
children: visibleCount === 0 ? (0, react_jsx_runtime.jsx)("span", {
|
|
1020
|
+
className: ActivityPanel_module_css_default.emptyHint,
|
|
1021
|
+
children: "暂无团队活动"
|
|
1022
|
+
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1023
|
+
visibleTeams.map((team) => (0, react_jsx_runtime.jsx)(TeamSection, {
|
|
1024
|
+
team,
|
|
1025
|
+
onNavigate: navigateToSession
|
|
1026
|
+
}, team.teamId)),
|
|
1027
|
+
visibleArchived.map((team) => (0, react_jsx_runtime.jsx)("div", {
|
|
1028
|
+
"data-team-id": team.teamId,
|
|
1029
|
+
"data-historic": true,
|
|
1030
|
+
className: ActivityPanel_module_css_default.archivedWrap,
|
|
1031
|
+
children: (0, react_jsx_runtime.jsx)(TeamSection, {
|
|
1032
|
+
team,
|
|
1033
|
+
onNavigate: navigateToSession,
|
|
1034
|
+
historic: true
|
|
1035
|
+
})
|
|
1036
|
+
}, `${team.captainSessionId}:${team.teamId}`)),
|
|
1037
|
+
visibleHistoric.map(({ data: team, owner }) => {
|
|
1038
|
+
const teamKey = `${owner}:${team.teamId}`;
|
|
1039
|
+
return (0, react_jsx_runtime.jsxs)("section", {
|
|
1040
|
+
className: ActivityPanel_module_css_default.team,
|
|
1041
|
+
"data-team-id": team.teamId,
|
|
1042
|
+
"data-historic": true,
|
|
1043
|
+
children: [(0, react_jsx_runtime.jsxs)("header", {
|
|
1044
|
+
className: ActivityPanel_module_css_default.teamHead,
|
|
1045
|
+
children: [(0, react_jsx_runtime.jsxs)("span", {
|
|
1046
|
+
className: ActivityPanel_module_css_default.teamName,
|
|
1047
|
+
title: team.teamName,
|
|
1048
|
+
children: [
|
|
1049
|
+
(0, react_jsx_runtime.jsx)("img", {
|
|
1050
|
+
className: ActivityPanel_module_css_default.leadAvatar,
|
|
1051
|
+
src: LEAD_ART,
|
|
1052
|
+
alt: "",
|
|
1053
|
+
"aria-hidden": true
|
|
1054
|
+
}),
|
|
1055
|
+
" ",
|
|
1056
|
+
team.teamName
|
|
1057
|
+
]
|
|
1058
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
1059
|
+
className: ActivityPanel_module_css_default.historicPill,
|
|
1060
|
+
children: "已结束"
|
|
1061
|
+
})]
|
|
1062
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
1063
|
+
className: ActivityPanel_module_css_default.members,
|
|
1064
|
+
children: team.members.map((member) => (0, react_jsx_runtime.jsxs)("button", {
|
|
1065
|
+
type: "button",
|
|
1066
|
+
className: ActivityPanel_module_css_default.memberRow,
|
|
1067
|
+
"data-activity": "idle",
|
|
1068
|
+
onClick: () => {
|
|
1069
|
+
if (member.id !== "") navigateToSession(member.id);
|
|
1070
|
+
},
|
|
1071
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
1072
|
+
className: ActivityPanel_module_css_default.memberAvatar,
|
|
1073
|
+
children: memberArtUrl(member.name, member.role) !== null ? (0, react_jsx_runtime.jsx)("img", {
|
|
1074
|
+
className: ActivityPanel_module_css_default.memberArt,
|
|
1075
|
+
src: memberArtUrl(member.name, member.role) ?? "",
|
|
1076
|
+
alt: "",
|
|
1077
|
+
"aria-hidden": true
|
|
1078
|
+
}) : (0, react_jsx_runtime.jsx)("span", {
|
|
1079
|
+
className: ActivityPanel_module_css_default.memberInitial,
|
|
1080
|
+
style: { background: accentOf(member.id) },
|
|
1081
|
+
children: memberInitial(member.name)
|
|
1082
|
+
})
|
|
1083
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
1084
|
+
className: ActivityPanel_module_css_default.memberInfo,
|
|
1085
|
+
children: (0, react_jsx_runtime.jsxs)("span", {
|
|
1086
|
+
className: ActivityPanel_module_css_default.memberLine,
|
|
1087
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
1088
|
+
className: ActivityPanel_module_css_default.memberName,
|
|
1089
|
+
children: member.name
|
|
1090
|
+
}), member.role !== "" && (0, react_jsx_runtime.jsx)("span", {
|
|
1091
|
+
className: ActivityPanel_module_css_default.memberRole,
|
|
1092
|
+
children: member.role
|
|
1093
|
+
})]
|
|
1094
|
+
})
|
|
1095
|
+
})]
|
|
1096
|
+
}, member.id))
|
|
1097
|
+
})]
|
|
1098
|
+
}, teamKey);
|
|
1099
|
+
})
|
|
1100
|
+
] })
|
|
1101
|
+
})]
|
|
1102
|
+
})] });
|
|
1103
|
+
}
|
|
1104
|
+
//#endregion
|
|
1105
|
+
//#region lib/client/agent-teams-card-definition.js
|
|
1106
|
+
/**
|
|
1107
|
+
* AgentTeams conversation card: a lightweight in-conversation summary shown
|
|
1108
|
+
* when a team is created — the captain's name, the member roster with whale
|
|
1109
|
+
* avatars, and an entry point that re-activates the top-right activity
|
|
1110
|
+
* panel (useful after the floater was closed, or when re-opening an old
|
|
1111
|
+
* session for review).
|
|
1112
|
+
*
|
|
1113
|
+
* The fold anchors to the Harness's durable `tool/call` + `tool/result`
|
|
1114
|
+
* records for `agent_teams_create`. Those are first-party session events, so
|
|
1115
|
+
* the card survives restarts without writing an out-of-repo event type.
|
|
1116
|
+
* @module dsh-agent-teams/client/card
|
|
1117
|
+
*/
|
|
1118
|
+
/** Parse the only create-call fields the historic card owns. */
|
|
1119
|
+
function parseAgentTeamsCreateArgs(value) {
|
|
1120
|
+
try {
|
|
1121
|
+
const parsed = JSON.parse(value);
|
|
1122
|
+
if (typeof parsed !== "object" || parsed === null || !("name" in parsed) || typeof parsed.name !== "string") return;
|
|
1123
|
+
const name = parsed.name.trim();
|
|
1124
|
+
if (name === "") return void 0;
|
|
1125
|
+
const cleaned = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
1126
|
+
return {
|
|
1127
|
+
teamId: cleaned === "" ? "team" : cleaned,
|
|
1128
|
+
name
|
|
1129
|
+
};
|
|
1130
|
+
} catch {
|
|
1131
|
+
return;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
/** Durable first-party tool events folded into one keyed Chat node. */
|
|
1135
|
+
const agentTeamsCardDefinition = {
|
|
1136
|
+
kind: "agent-teams",
|
|
1137
|
+
target: "chat",
|
|
1138
|
+
match: (event) => {
|
|
1139
|
+
if (event.type === "tool/call" && event.data.name === "agent_teams_create") return parseAgentTeamsCreateArgs(event.data.arguments) === void 0 ? null : {
|
|
1140
|
+
id: String(event.data.callId),
|
|
1141
|
+
role: "start"
|
|
1142
|
+
};
|
|
1143
|
+
if (event.type === "tool/result" && event.data.message.source.kind === "tool") return {
|
|
1144
|
+
id: String(event.data.message.source.callId),
|
|
1145
|
+
role: "update"
|
|
1146
|
+
};
|
|
1147
|
+
return null;
|
|
1148
|
+
},
|
|
1149
|
+
start: (_context, match) => {
|
|
1150
|
+
if (match.event.type !== "tool/call") throw new Error("agent-teams card start requires agent_teams_create tool/call");
|
|
1151
|
+
const parsed = parseAgentTeamsCreateArgs(match.event.data.arguments);
|
|
1152
|
+
if (parsed === void 0) throw new Error("agent-teams card start requires valid create arguments");
|
|
1153
|
+
return {
|
|
1154
|
+
...parsed,
|
|
1155
|
+
accepted: false
|
|
1156
|
+
};
|
|
1157
|
+
},
|
|
1158
|
+
update: (context, match) => {
|
|
1159
|
+
if (match.event.type !== "tool/result") return context.state;
|
|
1160
|
+
if (match.event.data.error !== void 0 || match.event.data.message.content.some((block) => block.type === "tool-result" && block.isError === true)) return context.state;
|
|
1161
|
+
return {
|
|
1162
|
+
...context.state,
|
|
1163
|
+
accepted: true
|
|
1164
|
+
};
|
|
1165
|
+
},
|
|
1166
|
+
buildViewNode: (context) => {
|
|
1167
|
+
if (context.start === void 0) return null;
|
|
1168
|
+
const state = context.state;
|
|
1169
|
+
if (!state.accepted) return null;
|
|
1170
|
+
return {
|
|
1171
|
+
key: context.key,
|
|
1172
|
+
kind: "agent-teams",
|
|
1173
|
+
id: context.id,
|
|
1174
|
+
target: "chat",
|
|
1175
|
+
anchorSeq: context.start.event.seq,
|
|
1176
|
+
location: context.start.location,
|
|
1177
|
+
visibility: "visible",
|
|
1178
|
+
data: {
|
|
1179
|
+
teamId: state.teamId,
|
|
1180
|
+
captainSessionId: "",
|
|
1181
|
+
teamName: state.name,
|
|
1182
|
+
members: []
|
|
1183
|
+
}
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
};
|
|
1187
|
+
//#endregion
|
|
1188
|
+
//#region lib/client/index.js
|
|
1189
|
+
/** Required services: conversation nodes, slots, and sessions navigation. */
|
|
1190
|
+
const inject = [
|
|
1191
|
+
"conversationEvents",
|
|
1192
|
+
"slots",
|
|
1193
|
+
"sessions"
|
|
1194
|
+
];
|
|
1195
|
+
/**
|
|
1196
|
+
* Mount the floater through a body portal (the web shell has no top-right
|
|
1197
|
+
* slot) and register the in-conversation team card, whose "activity panel"
|
|
1198
|
+
* button re-activates the floater via a window event — the recovery path
|
|
1199
|
+
* for a closed floater or a re-opened session.
|
|
1200
|
+
*/
|
|
1201
|
+
function apply(ctx) {
|
|
1202
|
+
const host = document.createElement("div");
|
|
1203
|
+
host.dataset.agentTeamsHost = "";
|
|
1204
|
+
document.body.appendChild(host);
|
|
1205
|
+
const root = (0, react_dom_client.createRoot)(host);
|
|
1206
|
+
root.render((0, react_jsx_runtime.jsx)(ActivityPanel, {
|
|
1207
|
+
sessionsList: ctx.sessions.list,
|
|
1208
|
+
openSession: (id) => {
|
|
1209
|
+
ctx.sessions.open(id);
|
|
1210
|
+
}
|
|
1211
|
+
}));
|
|
1212
|
+
ctx.effect(() => () => {
|
|
1213
|
+
root.unmount();
|
|
1214
|
+
host.remove();
|
|
1215
|
+
}, "agent-teams: activity panel");
|
|
1216
|
+
ctx.conversationEvents.register(agentTeamsCardDefinition);
|
|
1217
|
+
ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({
|
|
1218
|
+
name: "conversation.chat.node",
|
|
1219
|
+
key: "agent-teams",
|
|
1220
|
+
inject: () => ({
|
|
1221
|
+
openSession: (id) => {
|
|
1222
|
+
ctx.sessions.open(id);
|
|
1223
|
+
},
|
|
1224
|
+
currentSessionId: () => ctx.sessions.list.getSnapshot().current
|
|
1225
|
+
})
|
|
1226
|
+
}, AgentTeamsCard));
|
|
1227
|
+
}
|
|
1228
|
+
//#endregion
|
|
1229
|
+
exports.apply = apply;
|
|
1230
|
+
exports.inject = inject;
|
|
1231
|
+
return module.exports;
|
|
1232
|
+
}
|
|
1233
|
+
});
|
|
1234
|
+
|
|
1235
|
+
//# sourceMappingURL=client.js.map
|