@wowyuarm/dsh-agent-team 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -3
- package/README.zh.md +23 -3
- package/package.json +50 -43
- package/packages/agent-team/README.md +8 -0
- package/packages/agent-team/README.zh.md +8 -0
- package/packages/agent-team/core-skills/member-skill-manager/SKILL.md +41 -0
- package/packages/agent-team/core-skills/member-skill-manager/references/auth-and-config.md +30 -0
- package/packages/agent-team/core-skills/member-skill-manager/references/writing-great-skills.md +17 -0
- package/packages/agent-team/lib/index.js +168 -37
- package/packages/agent-team/lib/ledger.js +440 -18
- package/packages/agent-team/lib/member-context.js +7 -3
- package/packages/agent-team/lib/member-runtime.js +229 -0
- package/packages/agent-team/lib/member-skills.js +94 -0
- package/packages/agent-team/lib/preset-roster.js +1 -0
- package/packages/agent-team/lib/spec.js +56 -1
- package/packages/agent-team/lib/typert.host.js +359 -77
- package/packages/agent-team/lib/typert.remote-client.d.ts +5 -1
- package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
- package/packages/agent-team/lib/typert.remote-client.js +248 -43
- package/packages/agent-team/lib/types/entities.js +1 -0
- package/packages/agent-team/lib/types/index.d.ts +51 -7
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +62 -1
- package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-runtime.d.ts +108 -0
- package/packages/agent-team/lib/types/member-runtime.d.ts.map +1 -0
- package/packages/agent-team/lib/types/member-skills.d.ts +45 -0
- package/packages/agent-team/lib/types/member-skills.d.ts.map +1 -0
- package/packages/agent-team/lib/types/operations.js +1 -0
- package/packages/agent-team/lib/types/preset-roster.d.ts.map +1 -1
- package/packages/agent-team/lib/types/requests-results.js +1 -0
- package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/entities.d.ts +339 -0
- package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -0
- package/packages/agent-team/lib/types/types/operations.d.ts +303 -0
- package/packages/agent-team/lib/types/types/operations.d.ts.map +1 -0
- package/packages/agent-team/lib/types/types/requests-results.d.ts +527 -0
- package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -0
- package/packages/agent-team/lib/types/types.d.ts +10 -985
- package/packages/agent-team/lib/types/types.d.ts.map +1 -1
- package/packages/agent-team/preset/team-member/agent.cordis.yml +11 -6
- package/packages/client-agent-team/README.md +4 -2
- package/packages/client-agent-team/README.zh.md +4 -2
- package/packages/client-agent-team/lib/client.js +636 -572
- package/packages/client-agent-team/lib/client.js.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +3 -5
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +37 -26
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +2 -2
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts +2 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +31 -5
- package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamComposer.js +2 -1
- package/packages/client-agent-team/lib/types/client/TeamMemberDock.d.ts +12 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberDock.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberDock.js +13 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts +4 -8
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.js +7 -40
- package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMessage.js +10 -3
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +61 -20
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +2 -2
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceRow.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceRow.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.js +25 -28
- package/packages/client-agent-team/lib/types/client/locales.d.ts +32 -16
- package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/locales.js +32 -16
- package/packages/client-agent-team/lib/types/client/member-session-input.d.ts +1 -3
- package/packages/client-agent-team/lib/types/client/member-session-input.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/member-session-input.js +18 -6
- package/packages/client-agent-team/lib/types/client/navigation.d.ts +2 -1
- package/packages/client-agent-team/lib/types/client/navigation.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/sidebar-order.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/sidebar-order.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/sidebar-sections.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/sidebar-sections.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/slots.d.ts +3 -1
- package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-membership.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/team-membership.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/timeline-scroll.d.ts +5 -7
- package/packages/client-agent-team/lib/types/client/timeline-scroll.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/timeline-scroll.js +9 -22
- package/packages/tool-agent-team/lib/index.js +25 -5
- package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.d.ts +0 -17
- package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.js +0 -135
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import type { AgentTeamAddMemberRequest, AgentTeamClientMemberStatus } from '@wowyuarm/dsh-agent-team/types';
|
|
2
|
-
import type { WorkspaceId } from '@deepseek-ai/dsh-
|
|
2
|
+
import type { WorkspaceId } from '@deepseek-ai/dsh-api-workspace-controller/client';
|
|
3
3
|
import type { TeamSidebarProps } from './slots.ts';
|
|
4
4
|
interface TeamAgentsPanelProps {
|
|
5
5
|
readonly workspaceId: WorkspaceId;
|
|
6
6
|
readonly loadMembers: TeamSidebarProps['loadMembers'];
|
|
7
7
|
readonly subscribeChanges: TeamSidebarProps['subscribeChanges'];
|
|
8
|
-
readonly loadChannels: TeamSidebarProps['loadChannels'];
|
|
9
8
|
readonly addMember: TeamSidebarProps['addMember'];
|
|
10
9
|
readonly updateMember: TeamSidebarProps['updateMember'];
|
|
11
10
|
readonly recoverMember: TeamSidebarProps['recoverMember'];
|
|
12
11
|
readonly clearMemberContext: TeamSidebarProps['clearMemberContext'];
|
|
13
|
-
readonly
|
|
14
|
-
readonly removeChannelMember: TeamSidebarProps['removeChannelMember'];
|
|
12
|
+
readonly archiveMember: TeamSidebarProps['archiveMember'];
|
|
15
13
|
readonly loadModels: TeamSidebarProps['loadModels'];
|
|
16
14
|
/** The Member Session currently embedded in the conversation seat, if any. */
|
|
17
15
|
readonly memberSessionId?: AgentTeamClientMemberStatus['member']['sessionId'];
|
|
@@ -19,6 +17,6 @@ interface TeamAgentsPanelProps {
|
|
|
19
17
|
readonly onCreatingChange: (request: AgentTeamAddMemberRequest, creating: boolean) => void;
|
|
20
18
|
readonly t: TeamSidebarProps['t'];
|
|
21
19
|
}
|
|
22
|
-
export declare function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges,
|
|
20
|
+
export declare function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, addMember, updateMember, recoverMember, clearMemberContext, archiveMember, loadModels, memberSessionId, openMemberSession, onCreatingChange, t }: TeamAgentsPanelProps): import("react").JSX.Element;
|
|
23
21
|
export {};
|
|
24
22
|
//# sourceMappingURL=TeamAgentsPanel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamAgentsPanel.d.ts","sourceRoot":"","sources":["../../../src/client/TeamAgentsPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EACzB,2BAA2B,
|
|
1
|
+
{"version":3,"file":"TeamAgentsPanel.d.ts","sourceRoot":"","sources":["../../../src/client/TeamAgentsPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EACzB,2BAA2B,EAE5B,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAYlD,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAA;IACrD,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAA;IAC/D,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAA;IACjD,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAA;IACvD,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,kBAAkB,EAAE,gBAAgB,CAAC,oBAAoB,CAAC,CAAA;IACnE,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAA;IACnD,8EAA8E;IAC9E,QAAQ,CAAC,eAAe,CAAC,EAAE,2BAA2B,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAA;IAC7E,QAAQ,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,CAAA;IACjE,QAAQ,CAAC,gBAAgB,EAAE,CAAC,OAAO,EAAE,yBAAyB,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;IAC1F,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC;AAED,wBAAgB,eAAe,CAAC,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC,EAAE,EAAE,oBAAoB,+BAuKnP"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
-
import { Button, IconEditOutline16, IconNewChatOutline16, IconPlayOutline16, IconPlusOutline16, IconRefreshOutline16, Input, Modal, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
3
|
+
import { Button, IconArchiveOutline20, IconEditOutline16, IconNewChatOutline16, IconPlayOutline16, IconPlusOutline16, IconRefreshOutline16, Input, Modal, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
4
|
import { TeamMemberAvatar } from "./TeamMemberAvatar.js";
|
|
5
5
|
import { SortableRow, useSidebarRowDrag } from "./sidebar-drag.js";
|
|
6
6
|
import { moveSidebarItem, useSidebarOrder } from "./sidebar-order.js";
|
|
@@ -8,14 +8,11 @@ import { useSidebarSectionOpen, setSidebarSectionOpen } from "./sidebar-sections
|
|
|
8
8
|
import { mintRequestId } from "./requests.js";
|
|
9
9
|
import { TeamRowMenu } from "./TeamRowMenu.js";
|
|
10
10
|
import { TeamSidebarSection } from "./TeamSidebarSection.js";
|
|
11
|
-
import { MultiMenuField } from "./multi-menu-field.js";
|
|
12
11
|
import { AgentEditorDialog, ModelPickerField, sameModel } from "./TeamMemberEditor.js";
|
|
13
12
|
import createCss from './create.module.css';
|
|
14
13
|
import css from './sidebar.module.css';
|
|
15
|
-
export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges,
|
|
14
|
+
export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, addMember, updateMember, recoverMember, clearMemberContext, archiveMember, loadModels, memberSessionId, openMemberSession, onCreatingChange, t }) {
|
|
16
15
|
const [members, setMembers] = useState([]);
|
|
17
|
-
const [channels, setChannels] = useState([]);
|
|
18
|
-
const [channelRefs, setChannelRefs] = useState([]);
|
|
19
16
|
const [loading, setLoading] = useState(true);
|
|
20
17
|
const [error, setError] = useState();
|
|
21
18
|
const [formOpen, setFormOpen] = useState(false);
|
|
@@ -42,7 +39,9 @@ export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, lo
|
|
|
42
39
|
setLoading(true);
|
|
43
40
|
const result = await loadMembers({ workspaceId });
|
|
44
41
|
if (result.ok) {
|
|
45
|
-
|
|
42
|
+
// Archived Members are hidden from every surface; the row disappears
|
|
43
|
+
// the moment the workspace-scope wake delivers the archived state.
|
|
44
|
+
setMembers(result.value.filter(status => status.member.state !== 'inactive' && status.member.state !== 'archived'));
|
|
46
45
|
setError(undefined);
|
|
47
46
|
}
|
|
48
47
|
else {
|
|
@@ -51,22 +50,15 @@ export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, lo
|
|
|
51
50
|
setLoading(false);
|
|
52
51
|
}, [loadMembers, workspaceId]);
|
|
53
52
|
useEffect(() => { void refresh(); }, [refresh]);
|
|
54
|
-
const loadWorkspaceChannels = useCallback(async () => {
|
|
55
|
-
const result = await loadChannels({ workspaceId, topLevelOnly: true, includeActivities: false, limit: 1 });
|
|
56
|
-
if (result.ok)
|
|
57
|
-
setChannels(result.value.channels);
|
|
58
|
-
}, [loadChannels, workspaceId]);
|
|
59
|
-
useEffect(() => { void loadWorkspaceChannels(); }, [loadWorkspaceChannels]);
|
|
60
53
|
useEffect(() => subscribeChanges({ kind: 'workspace', workspaceId }, update => {
|
|
61
54
|
if (update.type === 'failed') {
|
|
62
55
|
setError(update.message);
|
|
63
56
|
return;
|
|
64
57
|
}
|
|
65
|
-
// The section stays mounted across Channel creation, so
|
|
66
|
-
//
|
|
58
|
+
// The section stays mounted across Channel creation, so the Member roster
|
|
59
|
+
// rides every workspace invalidation.
|
|
67
60
|
void refresh();
|
|
68
|
-
|
|
69
|
-
}), [subscribeChanges, refresh, loadWorkspaceChannels, workspaceId]);
|
|
61
|
+
}), [subscribeChanges, refresh, workspaceId]);
|
|
70
62
|
const closeForm = () => {
|
|
71
63
|
if (creating)
|
|
72
64
|
return;
|
|
@@ -83,12 +75,13 @@ export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, lo
|
|
|
83
75
|
if (result.ok) {
|
|
84
76
|
setMembers(current => {
|
|
85
77
|
const retained = current.filter(status => status.member.memberId !== result.value.status.member.memberId);
|
|
86
|
-
return
|
|
78
|
+
return result.value.status.member.state === 'inactive' || result.value.status.member.state === 'archived'
|
|
79
|
+
? retained
|
|
80
|
+
: [...retained, result.value.status];
|
|
87
81
|
});
|
|
88
82
|
setHandle('');
|
|
89
83
|
setDescription('');
|
|
90
84
|
setModel(undefined);
|
|
91
|
-
setChannelRefs([]);
|
|
92
85
|
setFormOpen(false);
|
|
93
86
|
if (result.value.status.presence === 'unavailable') {
|
|
94
87
|
setError(result.value.status.diagnostic ?? t('statusUnavailable'));
|
|
@@ -120,31 +113,31 @@ export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, lo
|
|
|
120
113
|
const sameRequest = retryRequest !== undefined && retryRequest.workspaceId === workspaceId
|
|
121
114
|
&& retryRequest.handle === normalizedHandle && retryRequest.description === normalizedDescription
|
|
122
115
|
&& sameModel(retryRequest.model, model)
|
|
123
|
-
&& retryRequest.channelRefs.length ===
|
|
116
|
+
&& retryRequest.channelRefs.length === 0;
|
|
124
117
|
void provision(sameRequest ? retryRequest : {
|
|
125
118
|
requestId: mintRequestId(),
|
|
126
119
|
workspaceId,
|
|
127
120
|
handle: normalizedHandle,
|
|
128
121
|
description: normalizedDescription,
|
|
129
122
|
presetId: 'team-member',
|
|
130
|
-
|
|
123
|
+
// No initial Channels at creation: the Member joins Channels later from
|
|
124
|
+
// the Channel side and stays reachable through its DM view meanwhile.
|
|
125
|
+
channelRefs: [],
|
|
131
126
|
...(model === undefined ? {} : { model }),
|
|
132
127
|
});
|
|
133
128
|
};
|
|
134
|
-
return (_jsxs("div", { className: css.panel, children: [_jsx(Modal, { open: formOpen, onClose: closeForm, title: t('addAgent'), closeLabel: t('close'), contentClassName: createCss.dialogContent, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: creating, onClick: closeForm, children: t('cancel') }), _jsx(Button, { type: "submit", form: "team-agent-create-form", variant: "primary", disabled: creating || handle.trim().length === 0, children: creating ? t('creatingAgent') : t('createAgent') })] }), children: _jsxs("form", { id: "team-agent-create-form", className: createCss.form, onSubmit: submit, children: [_jsxs("label", { className: createCss.field, children: [_jsx("span", { children: t('agentName') }), _jsx(Input, { className: createCss.input, value: handle, onChange: event => { setHandle(event.target.value); setRetryRequest(undefined); }, disabled: creating, autoFocus: true })] }), _jsxs("label", { className: createCss.field, children: [_jsxs("span", { children: [t('agentDescription'), t('optionalSuffix')] }), _jsx(Input, { className: createCss.input, value: description, placeholder: t('agentDescriptionPlaceholder'), onChange: event => { setDescription(event.target.value); setRetryRequest(undefined); }, disabled: creating })] }), _jsx(ModelPickerField, { model: model, onModelChange: choice => { setModel(choice); setRetryRequest(undefined); }, loadModels: loadModels, disabled: creating, t: t }), _jsx(
|
|
135
|
-
setChannelRefs(current => current.includes(ref) ? current.filter(item => item !== ref) : [...current, ref]);
|
|
136
|
-
setRetryRequest(undefined);
|
|
137
|
-
}, emptyText: t('noChannelsForAgent'), triggerEmptyLabel: t('channelsPickerEmpty'), formatCount: count => t('channelsPickerCount', { count }) }), formOpen && error !== undefined && _jsx("p", { className: createCss.error, role: "alert", children: error })] }) }), _jsxs(TeamSidebarSection, { title: t('agents'), open: sectionOpen, onToggle: open => { setSidebarSectionOpen(workspaceId, 'agents', open); }, actions: (_jsx(Tooltip, { label: t('addAgent'), delayMs: 500, children: _jsx("button", { ref: triggerRef, type: "button", className: css.iconButton, "aria-label": t('addAgent'), onClick: () => { setError(undefined); setFormOpen(true); }, children: _jsx(IconPlusOutline16, { size: 14 }) }) })), children: [loading && members.length === 0 && _jsx("p", { className: css.emptyState, children: t('loadingAgents') }), !loading && members.length === 0 && _jsx("p", { className: css.emptyState, children: t('emptyAgents') }), _jsx("div", { className: css.agentList, children: orderedMembers.map(status => (_jsx(SortableRow, { drag: drag, orderKey: status.member.memberId, children: _jsx(AgentRow, { status: status, ...(memberSessionId === undefined ? {} : { current: status.member.sessionId === memberSessionId }), channels: channels, loadChannels: loadChannels, updateMember: updateMember, recoverMember: recoverMember, clearMemberContext: clearMemberContext, joinChannel: joinChannel, removeChannelMember: removeChannelMember, loadModels: loadModels, openMemberSession: openMemberSession, onUpdated: () => { void refresh(); }, t: t }) }, status.member.memberId))) })] }), !formOpen && error !== undefined && (_jsxs("div", { className: css.retryError, role: "alert", children: [_jsx("span", { children: error }), retryRequest !== undefined && _jsx("button", { type: "button", className: css.textButton, disabled: creating, onClick: () => { setFormOpen(true); }, children: t('retry') })] }))] }));
|
|
129
|
+
return (_jsxs("div", { className: css.panel, children: [_jsx(Modal, { open: formOpen, onClose: closeForm, title: t('addAgent'), closeLabel: t('close'), contentClassName: createCss.dialogContent, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: creating, onClick: closeForm, children: t('cancel') }), _jsx(Button, { type: "submit", form: "team-agent-create-form", variant: "primary", disabled: creating || handle.trim().length === 0, children: creating ? t('creatingAgent') : t('createAgent') })] }), children: _jsxs("form", { id: "team-agent-create-form", className: createCss.form, onSubmit: submit, children: [_jsxs("label", { className: createCss.field, children: [_jsx("span", { children: t('agentName') }), _jsx(Input, { className: createCss.input, value: handle, onChange: event => { setHandle(event.target.value); setRetryRequest(undefined); }, disabled: creating, autoFocus: true })] }), _jsxs("label", { className: createCss.field, children: [_jsxs("span", { children: [t('agentDescription'), t('optionalSuffix')] }), _jsx(Input, { className: createCss.input, value: description, placeholder: t('agentDescriptionPlaceholder'), onChange: event => { setDescription(event.target.value); setRetryRequest(undefined); }, disabled: creating })] }), _jsx(ModelPickerField, { model: model, onModelChange: choice => { setModel(choice); setRetryRequest(undefined); }, loadModels: loadModels, disabled: creating, t: t }), formOpen && error !== undefined && _jsx("p", { className: createCss.error, role: "alert", children: error })] }) }), _jsxs(TeamSidebarSection, { title: t('agents'), open: sectionOpen, onToggle: open => { setSidebarSectionOpen(workspaceId, 'agents', open); }, actions: (_jsx(Tooltip, { label: t('addAgent'), delayMs: 500, children: _jsx("button", { ref: triggerRef, type: "button", className: css.iconButton, "aria-label": t('addAgent'), onClick: () => { setError(undefined); setFormOpen(true); }, children: _jsx(IconPlusOutline16, { size: 14 }) }) })), children: [loading && members.length === 0 && _jsx("p", { className: css.emptyState, children: t('loadingAgents') }), !loading && members.length === 0 && _jsx("p", { className: css.emptyState, children: t('emptyAgents') }), _jsx("div", { className: css.agentList, children: orderedMembers.map(status => (_jsx(SortableRow, { drag: drag, orderKey: status.member.memberId, children: _jsx(AgentRow, { status: status, ...(memberSessionId === undefined ? {} : { current: status.member.sessionId === memberSessionId }), updateMember: updateMember, recoverMember: recoverMember, clearMemberContext: clearMemberContext, archiveMember: archiveMember, loadModels: loadModels, openMemberSession: openMemberSession, onUpdated: () => { void refresh(); }, t: t }) }, status.member.memberId))) })] }), !formOpen && error !== undefined && (_jsxs("div", { className: css.retryError, role: "alert", children: [_jsx("span", { children: error }), retryRequest !== undefined && _jsx("button", { type: "button", className: css.textButton, disabled: creating, onClick: () => { setFormOpen(true); }, children: t('retry') })] }))] }));
|
|
138
130
|
}
|
|
139
131
|
/**
|
|
140
132
|
* One sidebar Agent row: the select button opens the Member's own Session
|
|
141
133
|
* conversation page, the avatar carries identity plus the presence badge, and
|
|
142
134
|
* the row menu opens the editor.
|
|
143
135
|
*/
|
|
144
|
-
function AgentRow({ status, current,
|
|
136
|
+
function AgentRow({ status, current, updateMember, recoverMember, clearMemberContext, archiveMember, loadModels, openMemberSession, onUpdated, t }) {
|
|
145
137
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
146
138
|
const [editing, setEditing] = useState(false);
|
|
147
139
|
const [clearing, setClearing] = useState(false);
|
|
140
|
+
const [archiving, setArchiving] = useState(false);
|
|
148
141
|
const [rowAlert, setRowAlert] = useState();
|
|
149
142
|
// Both row actions ride the same runtime remote: the Host steers a live
|
|
150
143
|
// session, rebuilds an orphaned composition, or re-runs a failed activation.
|
|
@@ -203,18 +196,36 @@ function AgentRow({ status, current, channels, loadChannels, updateMember, recov
|
|
|
203
196
|
// handle's error markers are dropped with it). Only a running turn or a
|
|
204
197
|
// missing handle gates the entry.
|
|
205
198
|
const contextClearable = status.presence === 'available' || status.presence === 'error';
|
|
199
|
+
const archive = async () => {
|
|
200
|
+
try {
|
|
201
|
+
const result = await archiveMember({
|
|
202
|
+
requestId: mintRequestId(),
|
|
203
|
+
memberId: status.member.memberId,
|
|
204
|
+
});
|
|
205
|
+
await onUpdated();
|
|
206
|
+
if (!result.ok) {
|
|
207
|
+
setRowAlert(t('archiveAgentFailed', { message: result.error.message }));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch (cause) {
|
|
211
|
+
setRowAlert(t('archiveAgentFailed', { message: cause instanceof Error ? cause.message : String(cause) }));
|
|
212
|
+
}
|
|
213
|
+
};
|
|
206
214
|
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: css.agentRow, "data-menu-open": menuOpen || undefined, children: [_jsxs("button", { type: "button", className: css.agentSelect, "aria-label": t('openAgentSession', { name: status.member.handle }), "aria-current": current ? 'page' : undefined, disabled: status.availability !== 'active', onClick: () => { openMemberSession(status.member.sessionId); }, children: [_jsx(TeamMemberAvatar, { status: status, t: t }), _jsxs("span", { className: css.agentCopy, children: [_jsx("strong", { children: status.member.handle }), _jsx("small", { children: status.member.description })] })] }), _jsx("span", { className: css.rowMenu, children: _jsx(TeamRowMenu, { label: t('actionsAgent', { name: status.member.handle }), items: [
|
|
207
215
|
{ id: 'edit', label: t('editAgent'), icon: _jsx(IconEditOutline16, {}) },
|
|
208
216
|
...(status.presence === 'error' ? [{ id: 'resume', label: t('resumeAgent'), icon: _jsx(IconPlayOutline16, {}) }] : []),
|
|
209
217
|
...(status.availability === 'unavailable' ? [{ id: 'restart', label: t('restartAgent'), icon: _jsx(IconRefreshOutline16, {}) }] : []),
|
|
210
218
|
{ id: 'clear-context', label: t('clearContextAgent'), icon: _jsx(IconNewChatOutline16, {}), danger: true, disabled: !contextClearable },
|
|
211
219
|
...(!contextClearable ? [{ type: 'label', id: 'clear-context-reason', text: status.presence === 'working' ? t('clearContextWorkingReason') : t('clearContextUnavailableReason') }] : []),
|
|
220
|
+
{ id: 'archive', label: t('archiveAgent'), icon: _jsx(IconArchiveOutline20, { size: 16 }), danger: true },
|
|
212
221
|
], onSelect: (id) => {
|
|
213
222
|
if (id === 'edit')
|
|
214
223
|
setEditing(true);
|
|
215
224
|
else if (id === 'clear-context')
|
|
216
225
|
setClearing(true);
|
|
226
|
+
else if (id === 'archive')
|
|
227
|
+
setArchiving(true);
|
|
217
228
|
else
|
|
218
229
|
void recover();
|
|
219
|
-
}, onOpenChange: setMenuOpen }) })] }), rowAlert !== undefined && _jsx("div", { className: css.rowAlert, role: "alert", children: rowAlert }), clearing && (_jsx(Modal, { open: true, onClose: () => { setClearing(false); }, title: t('clearContextTitle', { name: status.member.handle }), closeLabel: t('close'), contentClassName: createCss.dialogContent, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", onClick: () => { setClearing(false); }, children: t('cancel') }), _jsx(Button, { variant: "primary", onClick: () => { setClearing(false); void clearContext(); }, children: t('clearContextConfirm') })] }), children: _jsx("p", { className: createCss.error, children: t('clearContextNotice', { name: status.member.handle }) }) })),
|
|
230
|
+
}, onOpenChange: setMenuOpen }) })] }), rowAlert !== undefined && _jsx("div", { className: css.rowAlert, role: "alert", children: rowAlert }), clearing && (_jsx(Modal, { open: true, onClose: () => { setClearing(false); }, title: t('clearContextTitle', { name: status.member.handle }), closeLabel: t('close'), contentClassName: createCss.dialogContent, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", onClick: () => { setClearing(false); }, children: t('cancel') }), _jsx(Button, { variant: "primary", onClick: () => { setClearing(false); void clearContext(); }, children: t('clearContextConfirm') })] }), children: _jsx("p", { className: createCss.error, children: t('clearContextNotice', { name: status.member.handle }) }) })), archiving && (_jsx(Modal, { open: true, onClose: () => { setArchiving(false); }, title: t('archiveAgentTitle', { name: status.member.handle }), closeLabel: t('close'), contentClassName: createCss.dialogContent, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", onClick: () => { setArchiving(false); }, children: t('cancel') }), _jsx(Button, { variant: "primary", onClick: () => { setArchiving(false); void archive(); }, children: t('archiveAgentConfirm') })] }), children: _jsx("p", { className: createCss.error, children: t('archiveAgentNotice', { name: status.member.handle }) }) })), editing && (_jsx(AgentEditorDialog, { status: status, updateMember: updateMember, loadModels: loadModels, onCommitted: onUpdated, onClose: () => { setEditing(false); }, t: t }))] }));
|
|
220
231
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentTeamChannelRef } from '@wowyuarm/dsh-agent-team/types';
|
|
2
|
-
import type { WorkspaceId } from '@deepseek-ai/dsh-
|
|
2
|
+
import type { WorkspaceId } from '@deepseek-ai/dsh-api-workspace-controller/client';
|
|
3
3
|
import type { TeamConversationProps } from './slots.ts';
|
|
4
4
|
import type { TeamDraftStore } from './drafts.ts';
|
|
5
5
|
interface TeamChannelPageProps {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamChannelPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamChannelPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA+B,mBAAmB,EAE7D,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"TeamChannelPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamChannelPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA+B,mBAAmB,EAE7D,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAIvD,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,aAAa,CAAA;AAc/D,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAA;IACxC,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,CAAA;IACpE,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,mBAAmB,EAAE,qBAAqB,CAAC,qBAAqB,CAAC,CAAA;IAC1E,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,cAAc,EAAE,qBAAqB,CAAC,gBAAgB,CAAC,CAAA;IAChE,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AAmBD,wBAAgB,eAAe,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,mBAAmB,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC,EAAE,EAAE,oBAAoB,+BAmVnR"}
|
|
@@ -95,7 +95,7 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
95
95
|
const timeline = useTimelineScroll(`${view?.items.length ?? 0}:${channelLastItem?.message.messageRef ?? ''}`);
|
|
96
96
|
const channel = view?.channels.find(item => item.channelRef === channelRef);
|
|
97
97
|
const channelMemberIds = new Set(view?.members.filter(item => item.channelRef === channelRef).map(item => item.memberId) ?? []);
|
|
98
|
-
const channelMembers = members.filter(status => channelMemberIds.has(status.member.memberId) && status.member.state !== 'inactive');
|
|
98
|
+
const channelMembers = members.filter(status => channelMemberIds.has(status.member.memberId) && status.member.state !== 'inactive' && status.member.state !== 'archived');
|
|
99
99
|
// Presence counts ride the header meta line; error and unavailable do not count as online.
|
|
100
100
|
const onlineCount = channelMembers.filter(status => status.presence === 'available' || status.presence === 'working').length;
|
|
101
101
|
const messageSender = (item) => item.message.sender;
|
|
@@ -290,7 +290,7 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
290
290
|
setPending(false);
|
|
291
291
|
}
|
|
292
292
|
};
|
|
293
|
-
return _jsxs("main", { className: css.surface, "data-team-channel": channelRef, children: [_jsxs("div", { className: css.surfaceHeader, children: [_jsx("div", { className: css.backRow, children: _jsx(Button, { size: "sm", icon: _jsx(IconChevronLeftOutline14, {}), onClick: backToChannels, children: t('backToChannels') }) }), _jsxs("header", { className: css.headerRow, children: [_jsxs("div", { className: css.headerCopy, children: [_jsx("h1", { children: channel === undefined ? '# …' : `# ${channel.name}` }), channel !== undefined && _jsx("p", { children: channel.description }), channel !== undefined && _jsxs("div", { className: channelCss.headerMeta, children: [_jsx("span", { children: t('memberCount', { count: channelMembers.length }) }), _jsx("span", { children: t('onlineCount', { count: onlineCount }) })] })] }), channel !== undefined && _jsx("span", { ref: manageTriggerRef, children: _jsx(Button, { size: "sm", variant: "outline", "aria-haspopup": "dialog", onClick: () => { setManagingMembers(true); }, children: t('manageMembers') }) })] })] }), _jsx(Modal, { open: managingMembers, onClose: closeMembers, title: t('channelMembers'), ...(channel === undefined ? {} : { description: `# ${channel.name} · ${t('memberCount', { count: channelMembers.length })}` }), closeLabel: t('close'), contentClassName: channelCss.modalBody, children: _jsx("div", { ref: memberListRef, className: channelCss.memberList, children: members.filter(status => status.member.state !== 'inactive').map(status => {
|
|
293
|
+
return _jsxs("main", { className: css.surface, "data-team-channel": channelRef, children: [_jsxs("div", { className: css.surfaceHeader, children: [_jsx("div", { className: css.backRow, children: _jsx(Button, { size: "sm", icon: _jsx(IconChevronLeftOutline14, {}), onClick: backToChannels, children: t('backToChannels') }) }), _jsxs("header", { className: css.headerRow, children: [_jsxs("div", { className: css.headerCopy, children: [_jsx("h1", { children: channel === undefined ? '# …' : `# ${channel.name}` }), channel !== undefined && _jsx("p", { children: channel.description }), channel !== undefined && _jsxs("div", { className: channelCss.headerMeta, children: [_jsx("span", { children: t('memberCount', { count: channelMembers.length }) }), _jsx("span", { children: t('onlineCount', { count: onlineCount }) })] })] }), channel !== undefined && _jsx("span", { ref: manageTriggerRef, children: _jsx(Button, { size: "sm", variant: "outline", "aria-haspopup": "dialog", onClick: () => { setManagingMembers(true); }, children: t('manageMembers') }) })] })] }), _jsx(Modal, { open: managingMembers, onClose: closeMembers, title: t('channelMembers'), ...(channel === undefined ? {} : { description: `# ${channel.name} · ${t('memberCount', { count: channelMembers.length })}` }), closeLabel: t('close'), contentClassName: channelCss.modalBody, children: _jsx("div", { ref: memberListRef, className: channelCss.memberList, children: members.filter(status => status.member.state !== 'inactive' && status.member.state !== 'archived').map(status => {
|
|
294
294
|
const joined = channelMemberIds.has(status.member.memberId);
|
|
295
295
|
const rowPending = membership.pending.has(status.member.memberId);
|
|
296
296
|
const disabled = rowPending || (!joined && status.presence === 'unavailable');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentTeamAddMemberRequest, AgentTeamChannelRef } from '@wowyuarm/dsh-agent-team/types';
|
|
2
|
-
import type { WorkspaceId } from '@deepseek-ai/dsh-
|
|
2
|
+
import type { WorkspaceId } from '@deepseek-ai/dsh-api-workspace-controller/client';
|
|
3
3
|
import type { TeamSidebarProps } from './slots.ts';
|
|
4
4
|
interface TeamChannelsPanelProps {
|
|
5
5
|
readonly workspaceId: WorkspaceId;
|
|
@@ -9,6 +9,7 @@ interface TeamChannelsPanelProps {
|
|
|
9
9
|
readonly subscribeChanges: TeamSidebarProps['subscribeChanges'];
|
|
10
10
|
readonly createChannel: TeamSidebarProps['createChannel'];
|
|
11
11
|
readonly updateChannel: TeamSidebarProps['updateChannel'];
|
|
12
|
+
readonly archiveChannel: TeamSidebarProps['archiveChannel'];
|
|
12
13
|
readonly joinChannel: TeamSidebarProps['joinChannel'];
|
|
13
14
|
readonly removeChannelMember: TeamSidebarProps['removeChannelMember'];
|
|
14
15
|
readonly creatingAgents: readonly AgentTeamAddMemberRequest[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamChannelsPanel.d.ts","sourceRoot":"","sources":["../../../src/client/TeamChannelsPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EAEzB,mBAAmB,EAMpB,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"TeamChannelsPanel.d.ts","sourceRoot":"","sources":["../../../src/client/TeamChannelsPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EAEzB,mBAAmB,EAMpB,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAalD,UAAU,sBAAsB;IAC9B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAA;IACrD,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAA;IACvD,wGAAwG;IACxG,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAA;IAC/D,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,cAAc,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,CAAA;IAC3D,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAA;IACrD,QAAQ,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAA;IACrE,QAAQ,CAAC,cAAc,EAAE,SAAS,yBAAyB,EAAE,CAAA;IAC7D,QAAQ,CAAC,kBAAkB,CAAC,EAAE,mBAAmB,CAAA;IACjD,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,+BA+L9D"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
-
import { Button, IconEditOutline16, IconPlusOutline16, Input, Modal, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
3
|
+
import { Button, IconArchiveOutline20, IconEditOutline16, IconPlusOutline16, Input, Modal, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
4
|
import { TeamPresenceDot } from "./TeamPresenceDot.js";
|
|
5
5
|
import { MultiMenuField } from "./multi-menu-field.js";
|
|
6
6
|
import { SortableRow, useSidebarRowDrag } from "./sidebar-drag.js";
|
|
@@ -47,7 +47,7 @@ export function TeamChannelsPanel(props) {
|
|
|
47
47
|
]);
|
|
48
48
|
if (channelResult.ok && memberResult.ok) {
|
|
49
49
|
setView(channelResult.value);
|
|
50
|
-
const visibleMembers = memberResult.value.filter(status => status.member.state !== 'inactive');
|
|
50
|
+
const visibleMembers = memberResult.value.filter(status => status.member.state !== 'inactive' && status.member.state !== 'archived');
|
|
51
51
|
setMembers(visibleMembers);
|
|
52
52
|
const selectable = new Set(visibleMembers.filter(status => status.presence !== 'unavailable')
|
|
53
53
|
.map(status => status.member.memberId));
|
|
@@ -148,17 +148,43 @@ export function TeamChannelsPanel(props) {
|
|
|
148
148
|
setPendingCreate(undefined);
|
|
149
149
|
}, triggerEmptyLabel: t('membersPickerEmpty'), formatCount: count => t('membersPickerCount', { count }) }), error !== undefined && _jsx("p", { className: createCss.error, role: "alert", children: error })] }) }), _jsxs(TeamSidebarSection, { title: t('channels'), open: sectionOpen, onToggle: open => { setSidebarSectionOpen(workspaceId, 'channels', open); }, actions: (_jsx(Tooltip, { label: t('addChannel'), delayMs: 500, children: _jsx("button", { ref: triggerRef, type: "button", className: css.iconButton, "aria-label": t('addChannel'), onClick: () => { setError(undefined); setFormOpen(true); }, children: _jsx(IconPlusOutline16, { size: 14 }) }) })), children: [loading && view === undefined && _jsx("p", { className: css.emptyState, children: t('loadingChannels') }), !loading && (view?.channels.length ?? 0) === 0 && _jsx("p", { className: css.emptyState, children: t('emptyChannels') }), _jsx("div", { className: css.channelList, children: orderedChannels.map(channel => {
|
|
150
150
|
const joined = membership.get(channel.channelRef) ?? new Set();
|
|
151
|
-
return (_jsx(SortableRow, { drag: drag, orderKey: channel.channelRef, children: _jsx(ChannelRow, { channel: channel, members: members, joinedIds: joined, selected: selectedChannelRef === channel.channelRef, updateChannel: updateChannel, joinChannel: props.joinChannel, removeChannelMember: props.removeChannelMember, onCommitted: () => { void refresh(); }, selectChannel: selectChannel, t: t }) }, channel.channelRef));
|
|
151
|
+
return (_jsx(SortableRow, { drag: drag, orderKey: channel.channelRef, children: _jsx(ChannelRow, { channel: channel, members: members, joinedIds: joined, selected: selectedChannelRef === channel.channelRef, updateChannel: updateChannel, archiveChannel: props.archiveChannel, joinChannel: props.joinChannel, removeChannelMember: props.removeChannelMember, onCommitted: () => { void refresh(); }, selectChannel: selectChannel, t: t }) }, channel.channelRef));
|
|
152
152
|
}) })] }), !formOpen && error !== undefined && _jsx("p", { className: css.error, role: "alert", children: error })] }));
|
|
153
153
|
}
|
|
154
154
|
/**
|
|
155
155
|
* One sidebar Channel row: the select button keeps the `#` identity while the
|
|
156
156
|
* row menu carries the entry point; editing covers display facts and membership.
|
|
157
157
|
*/
|
|
158
|
-
function ChannelRow({ channel, members, joinedIds, selected, updateChannel, joinChannel, removeChannelMember, onCommitted, selectChannel, t }) {
|
|
158
|
+
function ChannelRow({ channel, members, joinedIds, selected, updateChannel, archiveChannel, joinChannel, removeChannelMember, onCommitted, selectChannel, t }) {
|
|
159
159
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
160
160
|
const [editing, setEditing] = useState(false);
|
|
161
|
-
|
|
161
|
+
const [archiving, setArchiving] = useState(false);
|
|
162
|
+
const [rowAlert, setRowAlert] = useState();
|
|
163
|
+
const archive = async () => {
|
|
164
|
+
try {
|
|
165
|
+
const result = await archiveChannel({
|
|
166
|
+
requestId: mintRequestId(),
|
|
167
|
+
workspaceId: channel.workspaceId,
|
|
168
|
+
channelRef: channel.channelRef,
|
|
169
|
+
});
|
|
170
|
+
await onCommitted();
|
|
171
|
+
if (!result.ok) {
|
|
172
|
+
setRowAlert(t('archiveChannelFailed', { message: result.error.message }));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch (cause) {
|
|
176
|
+
setRowAlert(t('archiveChannelFailed', { message: cause instanceof Error ? cause.message : String(cause) }));
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
return (_jsxs(_Fragment, { children: [_jsxs("article", { className: css.channelRow, "data-menu-open": menuOpen || undefined, "aria-current": selected ? 'page' : undefined, children: [_jsx("button", { type: "button", className: css.channelSelect, "aria-label": `# ${channel.name}`, onClick: () => { selectChannel(channel.channelRef); }, children: _jsxs("strong", { className: css.channelName, children: ["# ", channel.name] }) }), _jsx("span", { className: css.rowMenu, children: _jsx(TeamRowMenu, { label: t('actionsChannel', { name: channel.name }), items: [
|
|
180
|
+
{ id: 'edit', label: t('editChannel'), icon: _jsx(IconEditOutline16, {}) },
|
|
181
|
+
{ id: 'archive', label: t('archiveChannel'), icon: _jsx(IconArchiveOutline20, { size: 16 }), danger: true },
|
|
182
|
+
], onSelect: (id) => {
|
|
183
|
+
if (id === 'edit')
|
|
184
|
+
setEditing(true);
|
|
185
|
+
else
|
|
186
|
+
setArchiving(true);
|
|
187
|
+
}, onOpenChange: setMenuOpen }) })] }), rowAlert !== undefined && _jsx("div", { className: css.rowAlert, role: "alert", children: rowAlert }), archiving && (_jsx(Modal, { open: true, onClose: () => { setArchiving(false); }, title: t('archiveChannelTitle', { name: channel.name }), closeLabel: t('close'), contentClassName: createCss.dialogContent, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", onClick: () => { setArchiving(false); }, children: t('cancel') }), _jsx(Button, { variant: "primary", onClick: () => { setArchiving(false); void archive(); }, children: t('archiveChannelConfirm') })] }), children: _jsx("p", { className: createCss.error, children: t('archiveChannelNotice', { name: channel.name }) }) })), editing && (_jsx(ChannelEditorDialog, { channel: channel, members: members, joinedIds: joinedIds, updateChannel: updateChannel, joinChannel: joinChannel, removeChannelMember: removeChannelMember, onCommitted: onCommitted, onClose: () => { setEditing(false); }, t: t }))] }));
|
|
162
188
|
}
|
|
163
189
|
/**
|
|
164
190
|
* Channel editor: name and description commit through one durable update;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamComposer.d.ts","sourceRoot":"","sources":["../../../src/client/TeamComposer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,2BAA2B,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAEpG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"TeamComposer.d.ts","sourceRoot":"","sources":["../../../src/client/TeamComposer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,2BAA2B,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAEpG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AA+DvD,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,EAAE,EAAE;IAC3M,QAAQ,CAAC,OAAO,EAAE,SAAS,2BAA2B,EAAE,CAAA;IACxD,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,iBAAiB,CAAC,CAAA;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/C,QAAQ,CAAC,kBAAkB,EAAE,CAAC,UAAU,EAAE,WAAW,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAA;IACjF,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,gGAAgG;IAChG,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,IAAI,EAAE,CAAA;IACvC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,KAAK,IAAI,CAAA;IACzD,gFAAgF;IAChF,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;IACnD,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC,+BAqSA"}
|
|
@@ -28,11 +28,12 @@ function mentionCandidates(members, query) {
|
|
|
28
28
|
const normalized = query.toLocaleLowerCase();
|
|
29
29
|
return members.filter(status => status.presence !== 'unavailable'
|
|
30
30
|
&& status.member.state !== 'inactive'
|
|
31
|
+
&& status.member.state !== 'archived'
|
|
31
32
|
&& status.member.handle.toLocaleLowerCase().startsWith(normalized));
|
|
32
33
|
}
|
|
33
34
|
/** Every member a manual handle pick could reach: the @all expansion snapshot. */
|
|
34
35
|
function allMentionMembers(members) {
|
|
35
|
-
return members.filter(status => status.presence !== 'unavailable' && status.member.state !== 'inactive');
|
|
36
|
+
return members.filter(status => status.presence !== 'unavailable' && status.member.state !== 'inactive' && status.member.state !== 'archived');
|
|
36
37
|
}
|
|
37
38
|
function containsAllMention(draft) {
|
|
38
39
|
return /(?:^|[^\p{L}\p{N}_])@all(?=$|[^\p{L}\p{N}_])/u.test(draft);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
2
|
+
/** Public input-dock slot currency for the Member Session strip. */
|
|
3
|
+
export type TeamMemberDockProps = PropsRuntime<'conversation.input.dock'> & PropsLocale<'team'>;
|
|
4
|
+
/**
|
|
5
|
+
* Team-owned strip above the shipped composer while a Member Session is
|
|
6
|
+
* embedded. The shipped InputBar keeps the whole input surface (draft,
|
|
7
|
+
* trigger menus, submit); this dock only carries what the shipped bar cannot
|
|
8
|
+
* know — the Member-Session vocabulary hint and the Member turn's prompt
|
|
9
|
+
* error, read through the standard useSession hook.
|
|
10
|
+
*/
|
|
11
|
+
export declare function TeamMemberDock({ t, useSession }: TeamMemberDockProps): import("react").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=TeamMemberDock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TeamMemberDock.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMemberDock.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAGjF,oEAAoE;AACpE,MAAM,MAAM,mBAAmB,GAAG,YAAY,CAAC,yBAAyB,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,CAAA;AAE/F;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,mBAAmB,+BAQpE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import css from './composer.module.css';
|
|
3
|
+
/**
|
|
4
|
+
* Team-owned strip above the shipped composer while a Member Session is
|
|
5
|
+
* embedded. The shipped InputBar keeps the whole input surface (draft,
|
|
6
|
+
* trigger menus, submit); this dock only carries what the shipped bar cannot
|
|
7
|
+
* know — the Member-Session vocabulary hint and the Member turn's prompt
|
|
8
|
+
* error, read through the standard useSession hook.
|
|
9
|
+
*/
|
|
10
|
+
export function TeamMemberDock({ t, useSession }) {
|
|
11
|
+
const promptError = useSession(state => state.promptError ?? null);
|
|
12
|
+
return _jsxs("div", { className: css.memberSessionDock, "data-team-member-dock": "true", children: [_jsx("span", { className: css.memberSessionHint, children: t('memberSessionHint') }), promptError !== null && (_jsx("p", { className: css.memberSessionStatus, role: "alert", children: promptError.error.message }))] });
|
|
13
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AgentTeamClientMemberStatus, AgentTeamModelSelection } from '@wowyuarm/dsh-agent-team/types';
|
|
2
2
|
import type { TeamSidebarProps } from './slots.ts';
|
|
3
3
|
/**
|
|
4
4
|
* Shared provider/model dropdown for the create and edit forms. The option
|
|
@@ -15,16 +15,12 @@ export declare function ModelPickerField({ model, onModelChange, loadModels, dis
|
|
|
15
15
|
}): import("react").JSX.Element;
|
|
16
16
|
/**
|
|
17
17
|
* Agent editor: handle, description, and per-Member model selection commit
|
|
18
|
-
* through one durable update
|
|
19
|
-
*
|
|
18
|
+
* through one durable update. Channel membership is managed from the Channel
|
|
19
|
+
* side, not here.
|
|
20
20
|
*/
|
|
21
|
-
export declare function AgentEditorDialog({ status,
|
|
21
|
+
export declare function AgentEditorDialog({ status, updateMember, loadModels, onCommitted, onClose, t }: {
|
|
22
22
|
readonly status: AgentTeamClientMemberStatus;
|
|
23
|
-
readonly channels: readonly AgentTeamChannel[];
|
|
24
|
-
readonly loadChannels: TeamSidebarProps['loadChannels'];
|
|
25
23
|
readonly updateMember: TeamSidebarProps['updateMember'];
|
|
26
|
-
readonly joinChannel: TeamSidebarProps['joinChannel'];
|
|
27
|
-
readonly removeChannelMember: TeamSidebarProps['removeChannelMember'];
|
|
28
24
|
readonly loadModels: TeamSidebarProps['loadModels'];
|
|
29
25
|
readonly onCommitted: () => Promise<void> | void;
|
|
30
26
|
readonly onClose: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamMemberEditor.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMemberEditor.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"TeamMemberEditor.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMemberEditor.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,uBAAuB,EAAgC,MAAM,gCAAgC,CAAA;AACxI,OAAO,KAAK,EAAiD,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAYjG;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE;IAClF,QAAQ,CAAC,KAAK,EAAE,uBAAuB,GAAG,SAAS,CAAA;IACnD,QAAQ,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,uBAAuB,GAAG,SAAS,KAAK,IAAI,CAAA;IAC7E,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAA;IACnD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC,+BA0GA;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE;IAC/F,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAA;IAC5C,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAA;IACvD,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAA;IACnD,QAAQ,CAAC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAChD,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAA;IAC5B,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC,+BA0EA;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,uBAAuB,GAAG,SAAS,EAAE,KAAK,EAAE,uBAAuB,GAAG,SAAS,GAAG,OAAO,CAIxH"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { Button, IconChevronDownOutline14, Input, Menu, Modal } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
|
-
import { useChannelMembership } from "./team-membership.js";
|
|
5
4
|
import { mintRequestId } from "./requests.js";
|
|
6
5
|
import createCss from './create.module.css';
|
|
7
6
|
import css from './sidebar.module.css';
|
|
@@ -70,10 +69,10 @@ export function ModelPickerField({ model, onModelChange, loadModels, disabled, t
|
|
|
70
69
|
}
|
|
71
70
|
/**
|
|
72
71
|
* Agent editor: handle, description, and per-Member model selection commit
|
|
73
|
-
* through one durable update
|
|
74
|
-
*
|
|
72
|
+
* through one durable update. Channel membership is managed from the Channel
|
|
73
|
+
* side, not here.
|
|
75
74
|
*/
|
|
76
|
-
export function AgentEditorDialog({ status,
|
|
75
|
+
export function AgentEditorDialog({ status, updateMember, loadModels, onCommitted, onClose, t }) {
|
|
77
76
|
const memberId = status.member.memberId;
|
|
78
77
|
const [handle, setHandle] = useState(status.member.handle);
|
|
79
78
|
const [description, setDescription] = useState(status.member.description);
|
|
@@ -81,35 +80,6 @@ export function AgentEditorDialog({ status, channels, loadChannels, updateMember
|
|
|
81
80
|
const [saving, setSaving] = useState(false);
|
|
82
81
|
const [error, setError] = useState();
|
|
83
82
|
const pendingRequest = useRef();
|
|
84
|
-
// Membership comes from a fresh projection at open time so stale checkbox
|
|
85
|
-
// state never flips a committed fact backwards.
|
|
86
|
-
const [memberships, setMemberships] = useState();
|
|
87
|
-
const [loadError, setLoadError] = useState();
|
|
88
|
-
useEffect(() => {
|
|
89
|
-
let mounted = true;
|
|
90
|
-
void loadChannels({ workspaceId: status.member.workspaceId, topLevelOnly: true, includeActivities: false, limit: 1 }).then(result => {
|
|
91
|
-
if (!mounted)
|
|
92
|
-
return;
|
|
93
|
-
if (result.ok) {
|
|
94
|
-
setMemberships(result.value.members);
|
|
95
|
-
setLoadError(undefined);
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
setLoadError(result.error.message);
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
return () => { mounted = false; };
|
|
102
|
-
}, [loadChannels, status.member.workspaceId]);
|
|
103
|
-
const membership = useChannelMembership({ joinChannel, removeChannelMember }, change => change.channelRef, change => {
|
|
104
|
-
setMemberships(current => {
|
|
105
|
-
const base = current ?? [];
|
|
106
|
-
return change.joined
|
|
107
|
-
? base.filter(item => !(item.channelRef === change.channelRef && item.memberId === change.memberId))
|
|
108
|
-
: [...base, { channelRef: change.channelRef, memberId: change.memberId }];
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
// A successful join appends the durable fact; removal filters it out above.
|
|
112
|
-
const joinedChannels = new Set((memberships ?? []).filter(item => item.memberId === memberId).map(item => item.channelRef));
|
|
113
83
|
const dirty = handle.trim() !== status.member.handle || description.trim() !== status.member.description
|
|
114
84
|
|| !sameModel(model, status.member.model);
|
|
115
85
|
const submit = async (event) => {
|
|
@@ -123,6 +93,9 @@ export function AgentEditorDialog({ status, channels, loadChannels, updateMember
|
|
|
123
93
|
handle: normalizedHandle,
|
|
124
94
|
description: normalizedDescription,
|
|
125
95
|
...(model === undefined ? {} : { model }),
|
|
96
|
+
// The editor owns no capabilities UI, but an absent field would clear a
|
|
97
|
+
// Remote-written override; echo the stored intent through the edit.
|
|
98
|
+
...(status.member.capabilities === undefined ? {} : { capabilities: status.member.capabilities }),
|
|
126
99
|
};
|
|
127
100
|
const samePending = pendingRequest.current !== undefined && pendingRequest.current.memberId === payload.memberId
|
|
128
101
|
&& pendingRequest.current.handle === payload.handle && pendingRequest.current.description === payload.description
|
|
@@ -152,13 +125,7 @@ export function AgentEditorDialog({ status, channels, loadChannels, updateMember
|
|
|
152
125
|
setSaving(false);
|
|
153
126
|
}
|
|
154
127
|
};
|
|
155
|
-
return (_jsx(Modal, { open: true, onClose: onClose, title: t('editAgent'), description: `@${status.member.handle}`, closeLabel: t('close'), contentClassName: createCss.dialogContent, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: saving, onClick: onClose, children: t('cancel') }), _jsx(Button, { type: "submit", form: "team-agent-edit-form", variant: "primary", disabled: saving || !dirty || handle.trim().length === 0, children: saving ? t('editSaving') : t('editSave') })] }), children: _jsxs("form", { id: "team-agent-edit-form", className: createCss.form, onSubmit: event => { void submit(event); }, children: [_jsxs("label", { className: createCss.field, children: [_jsx("span", { children: t('agentName') }), _jsx(Input, { className: createCss.input, value: handle, onChange: event => { setHandle(event.target.value); pendingRequest.current = undefined; }, disabled: saving, autoFocus: true })] }), _jsxs("label", { className: createCss.field, children: [_jsxs("span", { children: [t('agentDescription'), t('optionalSuffix')] }), _jsx(Input, { className: createCss.input, value: description, placeholder: t('agentDescriptionPlaceholder'), onChange: event => { setDescription(event.target.value); pendingRequest.current = undefined; }, disabled: saving })] }), _jsx(ModelPickerField, { model: model, onModelChange: choice => { pendingRequest.current = undefined; setModel(choice); }, loadModels: loadModels, disabled: saving, t: t }),
|
|
156
|
-
const joined = joinedChannels.has(channel.channelRef);
|
|
157
|
-
const rowPending = membership.pending.has(channel.channelRef);
|
|
158
|
-
const disabled = rowPending || (!joined && status.presence === 'unavailable');
|
|
159
|
-
const rowError = membership.errors.get(channel.channelRef);
|
|
160
|
-
return _jsxs("div", { className: `${css.editMemberRow} ${css.editMemberRowChannels}`, children: [_jsxs("strong", { className: css.editChannelName, children: ["# ", channel.name] }), _jsx(Button, { size: "sm", variant: "outline", disabled: disabled, onClick: () => { void membership.change({ workspaceId: status.member.workspaceId, channelRef: channel.channelRef, memberId, joined }); }, children: rowPending ? t('membershipUpdating') : joined ? t('removeFromChannel') : t('addToChannel') }), rowError !== undefined && _jsx("p", { className: css.rowError, role: "alert", children: rowError })] }, channel.channelRef);
|
|
161
|
-
}), channels.length === 0 && _jsx("small", { children: t('noChannelsForAgent') }), loadError !== undefined && _jsx("p", { className: css.rowError, role: "alert", children: loadError })] }), error !== undefined && _jsx("p", { className: createCss.error, role: "alert", children: error })] }) }));
|
|
128
|
+
return (_jsx(Modal, { open: true, onClose: onClose, title: t('editAgent'), description: `@${status.member.handle}`, closeLabel: t('close'), contentClassName: createCss.dialogContent, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: saving, onClick: onClose, children: t('cancel') }), _jsx(Button, { type: "submit", form: "team-agent-edit-form", variant: "primary", disabled: saving || !dirty || handle.trim().length === 0, children: saving ? t('editSaving') : t('editSave') })] }), children: _jsxs("form", { id: "team-agent-edit-form", className: createCss.form, onSubmit: event => { void submit(event); }, children: [_jsxs("label", { className: createCss.field, children: [_jsx("span", { children: t('agentName') }), _jsx(Input, { className: createCss.input, value: handle, onChange: event => { setHandle(event.target.value); pendingRequest.current = undefined; }, disabled: saving, autoFocus: true })] }), _jsxs("label", { className: createCss.field, children: [_jsxs("span", { children: [t('agentDescription'), t('optionalSuffix')] }), _jsx(Input, { className: createCss.input, value: description, placeholder: t('agentDescriptionPlaceholder'), onChange: event => { setDescription(event.target.value); pendingRequest.current = undefined; }, disabled: saving })] }), _jsx(ModelPickerField, { model: model, onModelChange: choice => { pendingRequest.current = undefined; setModel(choice); }, loadModels: loadModels, disabled: saving, t: t }), error !== undefined && _jsx("p", { className: createCss.error, role: "alert", children: error })] }) }));
|
|
162
129
|
}
|
|
163
130
|
export function sameModel(left, right) {
|
|
164
131
|
if (left === undefined && right === undefined)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamMessage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"TeamMessage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoG,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAGxI,OAAO,KAAK,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AACrH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEvD,OAAO,EAA4E,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAI/H,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAA;IACpC,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,uFAAuF;IACvF,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACzC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B;2DACuD;IACvD,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAA;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,0BAA0B,EAAE,GAAG,SAAS,CAAA;IACxE,6EAA6E;IAC7E,QAAQ,CAAC,cAAc,CAAC,EAAE,qBAAqB,CAAC,eAAe,CAAC,GAAG,SAAS,CAAA;IAC5E,QAAQ,CAAC,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,GAAG,SAAS,CAAA;IACnD,0FAA0F;IAC1F,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAA;IACxD,sFAAsF;IACtF,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,KAAK,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC,CAAC,GAAG,SAAS,CAAA;IACzH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAC9B;AAED,kFAAkF;AAClF,wBAAgB,WAAW,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC,EAAE,SAAS,EAAE,iBAAiB,EAAE,QAAQ,EAAE,EAAE,gBAAgB,+BAqH3N"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Fragment, useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
2
|
+
import { Fragment, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { MarkdownText, MessageText, Modal } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
4
|
import { cachedAttachmentDataUrl, formatByteSize, loadAttachmentDataUrl } from "./attachment-preview.js";
|
|
5
5
|
import { cachedResolvedTaskRef, resolveUnknownTaskRefs, useResolvedTaskRefVersion } from "./task-refs.js";
|
|
@@ -30,6 +30,13 @@ export function TeamMessage({ senderName, memberId, human, body, occurredAt, men
|
|
|
30
30
|
}, [onResolveTaskRefs, bodyTaskRefKey, refVersion]);
|
|
31
31
|
const taskLabel = useCallback((taskNumber) => t?.('taskLabel', { number: taskNumber }) ?? `Task #${taskNumber}`, [t]);
|
|
32
32
|
const refLabel = useCallback((ref) => ref.startsWith('thread:') ? (t?.('threadLabel') ?? 'Thread') : ref.startsWith('channel:') ? (t?.('channels') ?? 'Channels') : ref, [t]);
|
|
33
|
+
// Markdown chrome (code-copy buttons, footnotes heading) is locale copy the
|
|
34
|
+
// cordis-free primitive receives via props. Stable per locale revision — a
|
|
35
|
+
// fresh object per render would rebuild the component table every chunk.
|
|
36
|
+
const markdownLabels = useMemo(() => ({
|
|
37
|
+
code: { copyLabel: t?.('copyCode') ?? 'Copy', copiedLabel: t?.('copiedCode') ?? 'Copied' },
|
|
38
|
+
footnotes: t?.('markdownFootnotes') ?? 'Footnotes',
|
|
39
|
+
}), [t]);
|
|
33
40
|
// Long bodies start clamped behind the expand control. The default derives
|
|
34
41
|
// from the body alone; the toggle itself is per-mount view state nothing
|
|
35
42
|
// persists.
|
|
@@ -84,7 +91,7 @@ export function TeamMessage({ senderName, memberId, human, body, occurredAt, men
|
|
|
84
91
|
: _jsx(Fragment, { children: renderRefs(segment.text, onOpenRef, taskLabel, refLabel) }, index)) })
|
|
85
92
|
: plan.render === 'literal'
|
|
86
93
|
? _jsx("div", { className: css.messageText, children: onOpenRef === undefined ? _jsx(MessageText, { text: displayBody }) : renderRefs(displayBody, onOpenRef, taskLabel, refLabel) })
|
|
87
|
-
: _jsx("div", { ref: markdownRef, className: css.messageMarkdown, children: _jsx(MarkdownText, { text: displayBody }, `${displayBody}:${onOpenRef === undefined ? 'literal' : 'refs'}`) });
|
|
94
|
+
: _jsx("div", { ref: markdownRef, className: css.messageMarkdown, children: _jsx(MarkdownText, { text: displayBody, labels: markdownLabels }, `${displayBody}:${onOpenRef === undefined ? 'literal' : 'refs'}`) });
|
|
88
95
|
return (_jsxs("article", { className: css.messageRow, "data-human": human || undefined, "data-grouped": grouped || undefined, children: [_jsx("div", { className: css.messageIdentity, style: avatarStyle, "aria-hidden": "true", children: senderName.replace('@', '').slice(0, 1).toUpperCase() }), _jsxs("div", { className: css.messageBody, children: [(!grouped || showGroupedTime === true) && (_jsxs("div", { className: css.nameRow, children: [!grouped && _jsx("strong", { ...(senderTitle === undefined ? {} : { title: senderTitle }), children: senderName }), occurredAt !== undefined && _jsx("span", { className: css.messageTime, children: formatMessageTime(occurredAt) })] })), clampable ? _jsx("div", { className: clamped ? css.messageClamp : undefined, children: bodyNode }) : bodyNode, clampable && (_jsx("button", { type: "button", className: css.messageExpand, "data-message-expand": "true", "aria-expanded": expanded, onClick: () => { setExpanded(value => !value); }, children: expanded ? (t?.('collapseMessage') ?? 'Show less') : (t?.('expandMessage') ?? 'Show more') })), (plan.fallbackNames.length > 0 || plan.fallbackRefs.length > 0) && (_jsxs("div", { className: css.mentionsRow, children: [plan.fallbackNames.map(name => _jsxs("span", { className: css.mention, children: ["@", name] }, name)), plan.fallbackRefs.map(ref => {
|
|
89
96
|
const resolved = cachedResolvedTaskRef(ref);
|
|
90
97
|
const label = resolved !== undefined && ref.startsWith('task:') ? taskLabel(resolved.taskNumber) : ref;
|
|
@@ -218,7 +225,7 @@ function renderRefs(text, onOpenRef, taskLabel, refLabel) {
|
|
|
218
225
|
/** One message's attachment strip: image thumbnails with a large view, or name chips when bytes are gone. */
|
|
219
226
|
function TeamAttachmentStrip({ attachments, loadAttachment, t }) {
|
|
220
227
|
const [zoomed, setZoomed] = useState();
|
|
221
|
-
return _jsxs("div", { className: css.attachmentStrip, children: [attachments.map(attachment => _jsx(TeamAttachment, { attachment: attachment, ...(loadAttachment === undefined ? {} : { loadAttachment }), ...(t === undefined ? {} : { t }), onZoom: setZoomed }, attachment.attachmentId)), zoomed !== undefined && _jsx(Modal, { open: true, ...(css.attachmentModal === undefined ? {} : { className: css.attachmentModal }), title: zoomed.name, onClose: () => { setZoomed(undefined); }, children: _jsx("img", { className: css.attachmentZoom, src: cachedAttachmentDataUrl(zoomed.attachmentId) ?? undefined, alt: zoomed.name }) })] });
|
|
228
|
+
return _jsxs("div", { className: css.attachmentStrip, children: [attachments.map(attachment => _jsx(TeamAttachment, { attachment: attachment, ...(loadAttachment === undefined ? {} : { loadAttachment }), ...(t === undefined ? {} : { t }), onZoom: setZoomed }, attachment.attachmentId)), zoomed !== undefined && _jsx(Modal, { open: true, ...(css.attachmentModal === undefined ? {} : { className: css.attachmentModal }), title: zoomed.name, closeLabel: t?.('close') ?? 'Close', onClose: () => { setZoomed(undefined); }, children: _jsx("img", { className: css.attachmentZoom, src: cachedAttachmentDataUrl(zoomed.attachmentId) ?? undefined, alt: zoomed.name }) })] });
|
|
222
229
|
}
|
|
223
230
|
function TeamAttachment({ attachment, loadAttachment, t, onZoom }) {
|
|
224
231
|
const wantsPreview = loadAttachment !== undefined && attachment.mediaType.startsWith('image/');
|