@wowyuarm/dsh-agent-team 0.1.13 → 0.1.14-alpha.2

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.
Files changed (67) hide show
  1. package/README.md +1 -1
  2. package/README.zh.md +1 -1
  3. package/cordis.patch.yml +185 -2
  4. package/package.json +45 -49
  5. package/packages/agent-team/lib/context-management.js +2 -3
  6. package/packages/agent-team/lib/context-projection.js +7 -11
  7. package/packages/agent-team/lib/context-source.js +36 -17
  8. package/packages/agent-team/lib/index.js +26 -64
  9. package/packages/agent-team/lib/member-context.js +5 -3
  10. package/packages/agent-team/lib/member-time-context.js +5 -2
  11. package/packages/agent-team/lib/pressure-policy.js +5 -3
  12. package/packages/agent-team/lib/stored-session-reader.js +1 -2
  13. package/packages/agent-team/lib/typert.host.js +289 -211
  14. package/packages/agent-team/lib/typert.remote-client.d.ts +3 -2
  15. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  16. package/packages/agent-team/lib/typert.remote-client.js +243 -189
  17. package/packages/agent-team/lib/types/context-management.d.ts.map +1 -1
  18. package/packages/agent-team/lib/types/context-projection.d.ts.map +1 -1
  19. package/packages/agent-team/lib/types/context-source.d.ts +46 -13
  20. package/packages/agent-team/lib/types/context-source.d.ts.map +1 -1
  21. package/packages/agent-team/lib/types/index.d.ts +0 -8
  22. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  23. package/packages/agent-team/lib/types/member-context.d.ts +14 -0
  24. package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
  25. package/packages/agent-team/lib/types/member-time-context.d.ts +15 -0
  26. package/packages/agent-team/lib/types/member-time-context.d.ts.map +1 -1
  27. package/packages/agent-team/lib/types/pressure-policy.d.ts.map +1 -1
  28. package/packages/agent-team/lib/types/stored-session-reader.d.ts +1 -2
  29. package/packages/agent-team/lib/types/stored-session-reader.d.ts.map +1 -1
  30. package/packages/agent-team/lib/types/types/entities.d.ts +3 -3
  31. package/packages/client-agent-team/lib/client.js +467 -341
  32. package/packages/client-agent-team/lib/client.js.map +1 -1
  33. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +6 -6
  34. package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +3 -3
  35. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +4 -4
  36. package/packages/client-agent-team/lib/types/client/TeamComposer.js +3 -3
  37. package/packages/client-agent-team/lib/types/client/TeamFooterAction.js +2 -2
  38. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.js +3 -3
  39. package/packages/client-agent-team/lib/types/client/TeamMembersAction.js +2 -2
  40. package/packages/client-agent-team/lib/types/client/TeamRowMenu.d.ts.map +1 -1
  41. package/packages/client-agent-team/lib/types/client/TeamRowMenu.js +2 -2
  42. package/packages/client-agent-team/lib/types/client/TeamSidebarSection.js +2 -2
  43. package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +3 -3
  44. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
  45. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +5 -8
  46. package/packages/client-agent-team/lib/types/client/TeamWorkspaceSelector.d.ts +37 -0
  47. package/packages/client-agent-team/lib/types/client/TeamWorkspaceSelector.d.ts.map +1 -0
  48. package/packages/client-agent-team/lib/types/client/TeamWorkspaceSelector.js +58 -0
  49. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  50. package/packages/client-agent-team/lib/types/client/index.js +37 -18
  51. package/packages/client-agent-team/lib/types/client/locales.d.ts +2 -0
  52. package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
  53. package/packages/client-agent-team/lib/types/client/locales.js +2 -0
  54. package/packages/client-agent-team/lib/types/client/multi-menu-field.js +2 -2
  55. package/packages/client-agent-team/lib/types/client/sidebar-sections.d.ts +1 -1
  56. package/packages/client-agent-team/lib/types/client/sidebar-sections.d.ts.map +1 -1
  57. package/packages/client-agent-team/lib/types/client/sidebar-sections.js +4 -3
  58. package/packages/agent-team/lib/preset-roster.js +0 -15
  59. package/packages/agent-team/lib/session-remediation.js +0 -493
  60. package/packages/agent-team/lib/types/preset-roster.d.ts +0 -5
  61. package/packages/agent-team/lib/types/preset-roster.d.ts.map +0 -1
  62. package/packages/agent-team/lib/types/session-remediation.d.ts +0 -172
  63. package/packages/agent-team/lib/types/session-remediation.d.ts.map +0 -1
  64. package/packages/agent-team/preset/team-member/agent.cordis.yml +0 -164
  65. package/packages/client-agent-team/lib/types/client/TeamWorkspaceRow.d.ts +0 -11
  66. package/packages/client-agent-team/lib/types/client/TeamWorkspaceRow.d.ts.map +0 -1
  67. package/packages/client-agent-team/lib/types/client/TeamWorkspaceRow.js +0 -6
@@ -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, IconArchiveOutline20, IconEditOutline16, IconPlayOutline16, IconPlusOutline16, IconRefreshOutline16, Input, Modal, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
3
+ import { Button, IconArchiveOutlineRegular, IconEditOutlineRegular, IconPlayOutlineRegular, IconPlusOutlineRegular, IconRefreshOutlineRegular, Input, Modal, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
4
4
  import { TeamMemberIdentity } from "./TeamMemberRow.js";
5
5
  import { SortableRow, useSidebarRowDrag } from "./sidebar-drag.js";
6
6
  import { moveSidebarItem, useSidebarOrder } from "./sidebar-order.js";
@@ -196,7 +196,7 @@ export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, ad
196
196
  ...(model === undefined ? {} : { model }),
197
197
  });
198
198
  };
199
- return (_jsxs("div", { className: css.panel, children: [_jsxs(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') }), !importing && _jsx(Button, { type: "submit", form: "team-agent-create-form", variant: "primary", disabled: creating || handle.trim().length === 0, children: creating ? t('creatingAgent') : t('createAgent') })] }), children: [_jsx(Button, { className: createCss.modeSwitch, variant: "outline", disabled: creating, "aria-expanded": importing, onClick: () => { setImporting(value => !value); setError(undefined); }, children: importing ? t('createAgent') : t('importAgentTitle') }), formOpen && importing ? _jsx(TeamAgentImport, { workspaceId: workspaceId, loadMembers: loadMembers, joinWorkspace: joinWorkspace, onPending: setCreating, onJoined: async () => { await refresh(); setFormOpen(false); queueMicrotask(() => { triggerRef.current?.focus(); }); }, t: t }) : _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); setImporting(false); setFormOpen(true); }, children: _jsx(IconPlusOutline16, { size: 14 }) }) })), children: [loading && members.length === 0 && _jsx("p", { className: css.emptyState, children: t('loadingAgents') }), !loading && error === undefined && 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, { workspaceId: workspaceId, leaveWorkspace: leaveWorkspace, status: status, ...(memberSessionId === undefined ? {} : { current: status.member.sessionId === memberSessionId }), updateMember: updateMember, recoverMember: recoverMember, archiveMember: archiveMember, loadModels: loadModels, openMemberSession: openMemberSession, onUpdated: 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') })] }))] }));
199
+ return (_jsxs("div", { className: css.panel, children: [_jsxs(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') }), !importing && _jsx(Button, { type: "submit", form: "team-agent-create-form", variant: "primary", disabled: creating || handle.trim().length === 0, children: creating ? t('creatingAgent') : t('createAgent') })] }), children: [_jsx(Button, { className: createCss.modeSwitch, variant: "outline", disabled: creating, "aria-expanded": importing, onClick: () => { setImporting(value => !value); setError(undefined); }, children: importing ? t('createAgent') : t('importAgentTitle') }), formOpen && importing ? _jsx(TeamAgentImport, { workspaceId: workspaceId, loadMembers: loadMembers, joinWorkspace: joinWorkspace, onPending: setCreating, onJoined: async () => { await refresh(); setFormOpen(false); queueMicrotask(() => { triggerRef.current?.focus(); }); }, t: t }) : _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); setImporting(false); setFormOpen(true); }, children: _jsx(IconPlusOutlineRegular, { size: 14 }) }) })), children: [loading && members.length === 0 && _jsx("p", { className: css.emptyState, children: t('loadingAgents') }), !loading && error === undefined && 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, { workspaceId: workspaceId, leaveWorkspace: leaveWorkspace, status: status, ...(memberSessionId === undefined ? {} : { current: status.member.sessionId === memberSessionId }), updateMember: updateMember, recoverMember: recoverMember, archiveMember: archiveMember, loadModels: loadModels, openMemberSession: openMemberSession, onUpdated: 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') })] }))] }));
200
200
  }
201
201
  /**
202
202
  * One sidebar Agent row: the select button opens the Member's own Session
@@ -267,10 +267,10 @@ function AgentRow({ workspaceId, leaveWorkspace, status, current, updateMember,
267
267
  }
268
268
  };
269
269
  return (_jsxs(_Fragment, { children: [_jsxs("div", { className: css.agentRow, "data-agent-row": true, "data-menu-open": menuOpen || undefined, children: [_jsx("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(TeamMemberIdentity, { status: status, name: status.member.handle.replace(/^@/, ''), className: css.agentCopy, t: t }) }), _jsx("span", { className: css.rowMenu, children: _jsx(TeamRowMenu, { label: t('actionsAgent', { name: status.member.handle }), items: [
270
- { id: 'edit', label: t('editAgent'), icon: _jsx(IconEditOutline16, {}) },
271
- ...(status.presence === 'error' ? [{ id: 'resume', label: t('resumeAgent'), icon: _jsx(IconPlayOutline16, {}) }] : []),
272
- ...(status.availability === 'unavailable' && restartOffered(status) ? [{ id: 'restart', label: t('restartAgent'), icon: _jsx(IconRefreshOutline16, {}) }] : []),
273
- { id: 'archive', label: t(withdrawing ? 'withdrawAgent' : 'archiveAgent'), icon: _jsx(IconArchiveOutline20, { size: 16 }), danger: true },
270
+ { id: 'edit', label: t('editAgent'), icon: _jsx(IconEditOutlineRegular, {}) },
271
+ ...(status.presence === 'error' ? [{ id: 'resume', label: t('resumeAgent'), icon: _jsx(IconPlayOutlineRegular, {}) }] : []),
272
+ ...(status.availability === 'unavailable' && restartOffered(status) ? [{ id: 'restart', label: t('restartAgent'), icon: _jsx(IconRefreshOutlineRegular, {}) }] : []),
273
+ { id: 'archive', label: t(withdrawing ? 'withdrawAgent' : 'archiveAgent'), icon: _jsx(IconArchiveOutlineRegular, { size: 16 }), danger: true },
274
274
  ], onSelect: (id) => {
275
275
  if (id === 'edit')
276
276
  setEditing(true);
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Fragment, useCallback, useEffect, useRef, useState } from 'react';
3
- import { Button, IconChevronLeftOutline14, IconChevronRightOutline14, Modal } from '@deepseek-ai/dsh-client-ui-primitives';
3
+ import { Button, IconChevronLeftOutlineRegular, IconChevronRightOutlineRegular, Modal } from '@deepseek-ai/dsh-client-ui-primitives';
4
4
  import { mintRequestId, uploadComposerFiles } from "./requests.js";
5
5
  import { TeamComposer } from "./TeamComposer.js";
6
6
  import { TeamMemberRow } from "./TeamMemberRow.js";
@@ -346,7 +346,7 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
346
346
  setPending(false);
347
347
  }
348
348
  };
349
- 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 => {
349
+ 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(IconChevronLeftOutlineRegular, {}), 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 => {
350
350
  const joined = channelMemberIds.has(status.member.memberId);
351
351
  const rowPending = membership.pending.has(status.member.memberId);
352
352
  // Joining needs an active Member — the Host refuses any other
@@ -413,5 +413,5 @@ function ThreadEntryRow({ item, owners, unread, t, onOpen }) {
413
413
  // owner stack keeps its own accessible name — a labeled button prunes its
414
414
  // descendants from the accessibility tree — and so the control's name says
415
415
  // exactly what clicking it does.
416
- return _jsxs("span", { className: css.entryLine, "data-thread-entry": "", children: [_jsx(ThreadStateCluster, { task: item.task, owners: owners, unread: unread, t: t }), _jsxs("button", { type: "button", className: css.entryRow, "aria-label": openLabel, ...(followUp === undefined ? {} : { title: formatAbsoluteTime(followUp) }), onClick: onOpen, children: [_jsx("span", { children: text }), _jsx("span", { className: css.entryArrow, "aria-hidden": "true", children: _jsx(IconChevronRightOutline14, { size: 12 }) })] })] });
416
+ return _jsxs("span", { className: css.entryLine, "data-thread-entry": "", children: [_jsx(ThreadStateCluster, { task: item.task, owners: owners, unread: unread, t: t }), _jsxs("button", { type: "button", className: css.entryRow, "aria-label": openLabel, ...(followUp === undefined ? {} : { title: formatAbsoluteTime(followUp) }), onClick: onOpen, children: [_jsx("span", { children: text }), _jsx("span", { className: css.entryArrow, "aria-hidden": "true", children: _jsx(IconChevronRightOutlineRegular, { size: 12 }) })] })] });
417
417
  }
@@ -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, IconArchiveOutline20, IconEditOutline16, IconPlusOutline16, Input, Modal, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
3
+ import { Button, IconArchiveOutlineRegular, IconEditOutlineRegular, IconPlusOutlineRegular, Input, Modal, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
4
4
  import { TeamPresenceDot } from "./TeamPresenceDot.js";
5
5
  import { TeamMemberRow } from "./TeamMemberRow.js";
6
6
  import { MultiMenuField } from "./multi-menu-field.js";
@@ -153,7 +153,7 @@ export function TeamChannelsPanel(props) {
153
153
  return next;
154
154
  });
155
155
  setPendingCreate(undefined);
156
- }, 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 && error === undefined && view !== undefined && view.channels.length === 0 && _jsx("p", { className: css.emptyState, children: t('emptyChannels') }), _jsx("div", { className: css.channelList, children: orderedChannels.map(channel => {
156
+ }, 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(IconPlusOutlineRegular, { size: 14 }) }) })), children: [loading && view === undefined && _jsx("p", { className: css.emptyState, children: t('loadingChannels') }), !loading && error === undefined && view !== undefined && view.channels.length === 0 && _jsx("p", { className: css.emptyState, children: t('emptyChannels') }), _jsx("div", { className: css.channelList, children: orderedChannels.map(channel => {
157
157
  const joined = membership.get(channel.channelRef) ?? new Set();
158
158
  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));
159
159
  }) })] }), !formOpen && error !== undefined && _jsx("p", { className: css.error, role: "alert", children: error })] }));
@@ -184,8 +184,8 @@ function ChannelRow({ channel, members, joinedIds, selected, updateChannel, arch
184
184
  }
185
185
  };
186
186
  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: [
187
- { id: 'edit', label: t('editChannel'), icon: _jsx(IconEditOutline16, {}) },
188
- { id: 'archive', label: t('archiveChannel'), icon: _jsx(IconArchiveOutline20, { size: 16 }), danger: true },
187
+ { id: 'edit', label: t('editChannel'), icon: _jsx(IconEditOutlineRegular, {}) },
188
+ { id: 'archive', label: t('archiveChannel'), icon: _jsx(IconArchiveOutlineRegular, { size: 16 }), danger: true },
189
189
  ], onSelect: (id) => {
190
190
  if (id === 'edit')
191
191
  setEditing(true);
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore } from 'react';
3
- import { IconChecklistOutline14, IconPaperclipOutline16, IconSendOutline16, Tooltip, useAnchoredMaxHeight, useDismissOnOutsidePointer } from '@deepseek-ai/dsh-client-ui-primitives';
3
+ import { IconChecklistOutlineRegular, IconPaperclipOutlineRegular, IconSendOutlineRegular, Tooltip, useAnchoredMaxHeight, useDismissOnOutsidePointer } from '@deepseek-ai/dsh-client-ui-primitives';
4
4
  import { TeamPresenceDot } from "./TeamPresenceDot.js";
5
5
  import { allMentionMembers, containsAllMention, containsMention, mentionedMemberIds } from "./team-formatters.js";
6
6
  import css from './composer.module.css';
@@ -259,9 +259,9 @@ export function TeamComposer({ members, followerMemberIds, drafts, draftKey, pen
259
259
  if (chosen.length > 0 && pendingFiles !== undefined)
260
260
  onFilesChange([...pendingFiles, ...chosen]);
261
261
  event.target.value = '';
262
- } }), _jsx(Tooltip, { label: t('attachFiles'), side: "top", delayMs: 500, children: _jsx("button", { type: "button", className: css.attachButton, "aria-label": t('attachFiles'), disabled: pending, onClick: () => { fileInputRef.current?.click(); }, children: _jsx(IconPaperclipOutline16, { size: 14 }) }) })] })), onAsTaskChange !== undefined && (_jsxs("button", { type: "button", className: asTask === true ? `${css.asTaskPill} ${css.asTaskPillOn}` : css.asTaskPill, "aria-label": t('asTask'), "aria-pressed": asTask === true, title: t('asTask'), disabled: pending, onClick: () => { onAsTaskChange(asTask !== true); }, children: [_jsx(IconChecklistOutline14, { size: 14 }), _jsx("span", { className: css.asTaskLabel, children: t('asTask') })] })), _jsx("button", { type: "submit", className: css.sendButton, "aria-label": pending ? t('sendingMessage') : t('sendMessage'), disabled: pending || draft.trim() === '', onMouseDown: event => {
262
+ } }), _jsx(Tooltip, { label: t('attachFiles'), side: "top", delayMs: 500, children: _jsx("button", { type: "button", className: css.attachButton, "aria-label": t('attachFiles'), disabled: pending, onClick: () => { fileInputRef.current?.click(); }, children: _jsx(IconPaperclipOutlineRegular, { size: 14 }) }) })] })), onAsTaskChange !== undefined && (_jsxs("button", { type: "button", className: asTask === true ? `${css.asTaskPill} ${css.asTaskPillOn}` : css.asTaskPill, "aria-label": t('asTask'), "aria-pressed": asTask === true, title: t('asTask'), disabled: pending, onClick: () => { onAsTaskChange(asTask !== true); }, children: [_jsx(IconChecklistOutlineRegular, { size: 14 }), _jsx("span", { className: css.asTaskLabel, children: t('asTask') })] })), _jsx("button", { type: "submit", className: css.sendButton, "aria-label": pending ? t('sendingMessage') : t('sendMessage'), disabled: pending || draft.trim() === '', onMouseDown: event => {
263
263
  // Keep the composer focused when the send control is clicked.
264
264
  event.preventDefault();
265
265
  inputRef.current?.focus({ preventScroll: true });
266
- }, children: _jsx(IconSendOutline16, { size: 16 }) })] })] }), error !== undefined && _jsx("p", { className: css.error, role: "alert", children: error })] });
266
+ }, children: _jsx(IconSendOutlineRegular, { size: 16 }) })] })] }), error !== undefined && _jsx("p", { className: css.error, role: "alert", children: error })] });
267
267
  }
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useLayoutEffect, useSyncExternalStore } from 'react';
3
- import { IconAgentPresetOutline16, IconChevronLeftOutline14, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
3
+ import { IconAgentPresetOutlineRegular, IconChevronLeftOutlineRegular, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
4
4
  import css from './team.module.css';
5
5
  export function TeamFooterAction({ wide, navigation, enterTeam, leaveTeam, t }) {
6
6
  const state = useSyncExternalStore(navigation.subscribe, navigation.getSnapshot, navigation.getSnapshot);
@@ -15,5 +15,5 @@ export function TeamFooterAction({ wide, navigation, enterTeam, leaveTeam, t })
15
15
  }
16
16
  delete document.documentElement.dataset.agentTeamMode;
17
17
  }, [inTeam]);
18
- return (_jsx(_Fragment, { children: _jsx("div", { className: wide ? css.footerStack : `${css.footerStack} ${css.railStack}`, children: _jsx(Tooltip, { label: label, delayMs: 500, disabled: wide, children: _jsxs("button", { type: "button", className: wide ? css.footerAction : `${css.footerAction} ${css.rail}`, "aria-label": label, "data-team-action": inTeam ? 'leave' : 'enter', onClick: inTeam ? leaveTeam : enterTeam, children: [inTeam ? _jsx(IconChevronLeftOutline14, { size: wide ? 16 : 18 }) : _jsx(IconAgentPresetOutline16, { size: wide ? 16 : 18 }), wide && _jsx("span", { children: label })] }) }) }) }));
18
+ return (_jsx(_Fragment, { children: _jsx("div", { className: wide ? css.footerStack : `${css.footerStack} ${css.railStack}`, children: _jsx(Tooltip, { label: label, delayMs: 500, disabled: wide, children: _jsxs("button", { type: "button", className: wide ? css.footerAction : `${css.footerAction} ${css.rail}`, "aria-label": label, "data-team-action": inTeam ? 'leave' : 'enter', onClick: inTeam ? leaveTeam : enterTeam, children: [inTeam ? _jsx(IconChevronLeftOutlineRegular, { size: wide ? 16 : 18 }) : _jsx(IconAgentPresetOutlineRegular, { size: wide ? 16 : 18 }), wide && _jsx("span", { children: label })] }) }) }) }));
19
19
  }
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from 'react';
3
- import { Button, IconChevronDownOutline14, Input, Menu, Modal } from '@deepseek-ai/dsh-client-ui-primitives';
3
+ import { Button, IconChevronDownOutlineRegular, Input, Menu, Modal } from '@deepseek-ai/dsh-client-ui-primitives';
4
4
  import { mintRequestId } from "./requests.js";
5
5
  import { useEditDialogSave } from "./team-dialog-save.js";
6
6
  import createCss from './create.module.css';
@@ -61,12 +61,12 @@ export function ModelPickerField({ model, onModelChange, loadModels, disabled, t
61
61
  setModelOpen(false);
62
62
  const choice = byKey.get(key);
63
63
  onModelChange(choice === undefined ? undefined : { provider: choice.provider, model: choice.id });
64
- }, onClose: () => { setModelOpen(false); }, anchor: _jsxs("button", { type: "button", className: createCss.selectTrigger, "aria-label": t('memberModel'), "aria-haspopup": "listbox", "aria-expanded": open, disabled: disabled, onClick: () => { setModelOpen(value => !value); }, children: [_jsx("span", { className: createCss.selectValue, children: triggerLabel }), _jsx("span", { className: `${createCss.chevron} ${open ? createCss.chevronOpen : ''}`, "aria-hidden": true, children: _jsx(IconChevronDownOutline14, {}) })] }) })), model !== undefined && efforts.length > 0 && (_jsx(Menu, { open: effortOpen, portal: true, className: createCss.menuCap, items: effortItems, selectedId: selectedEffort, onSelect: key => {
64
+ }, onClose: () => { setModelOpen(false); }, anchor: _jsxs("button", { type: "button", className: createCss.selectTrigger, "aria-label": t('memberModel'), "aria-haspopup": "menu", "aria-expanded": open, disabled: disabled, onClick: () => { setModelOpen(value => !value); }, children: [_jsx("span", { className: createCss.selectValue, children: triggerLabel }), _jsx("span", { className: `${createCss.chevron} ${open ? createCss.chevronOpen : ''}`, "aria-hidden": true, children: _jsx(IconChevronDownOutlineRegular, {}) })] }) })), model !== undefined && efforts.length > 0 && (_jsx(Menu, { open: effortOpen, portal: true, className: createCss.menuCap, items: effortItems, selectedId: selectedEffort, onSelect: key => {
65
65
  setEffortOpen(false);
66
66
  onModelChange(key === ''
67
67
  ? { provider: model.provider, model: model.model }
68
68
  : { provider: model.provider, model: model.model, reasoningEffort: key });
69
- }, onClose: () => { setEffortOpen(false); }, anchor: _jsxs("button", { type: "button", className: createCss.selectTrigger, "aria-label": t('reasoningEffort'), "aria-haspopup": "listbox", "aria-expanded": effortOpen, disabled: disabled, onClick: () => { setEffortOpen(value => !value); }, children: [_jsx("span", { className: createCss.selectValue, children: `${t('reasoningEffort')} · ${effortTriggerLabel}` }), _jsx("span", { className: `${createCss.chevron} ${effortOpen ? createCss.chevronOpen : ''}`, "aria-hidden": true, children: _jsx(IconChevronDownOutline14, {}) })] }) }))] });
69
+ }, onClose: () => { setEffortOpen(false); }, anchor: _jsxs("button", { type: "button", className: createCss.selectTrigger, "aria-label": t('reasoningEffort'), "aria-haspopup": "menu", "aria-expanded": effortOpen, disabled: disabled, onClick: () => { setEffortOpen(value => !value); }, children: [_jsx("span", { className: createCss.selectValue, children: `${t('reasoningEffort')} · ${effortTriggerLabel}` }), _jsx("span", { className: `${createCss.chevron} ${effortOpen ? createCss.chevronOpen : ''}`, "aria-hidden": true, children: _jsx(IconChevronDownOutlineRegular, {}) })] }) }))] });
70
70
  }
71
71
  /**
72
72
  * Agent editor: handle, description, and per-Member model selection commit
@@ -1,6 +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
- import { IconUserOutline16, Modal, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
3
+ import { IconUserOutlineRegular, Modal, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
4
4
  import { TeamMemberRow } from "./TeamMemberRow.js";
5
5
  import membersCss from './members.module.css';
6
6
  import css from './team.module.css';
@@ -28,5 +28,5 @@ export function TeamMembersAction({ wide, loadMemberGroups, t }) {
28
28
  setPanelOpen(false);
29
29
  queueMicrotask(() => { triggerRef.current?.focus(); });
30
30
  };
31
- return (_jsxs(_Fragment, { children: [_jsx(Tooltip, { label: t('members'), delayMs: 500, disabled: wide, children: _jsxs("button", { ref: triggerRef, type: "button", className: wide ? css.settingsAction : `${css.settingsAction} ${css.rail}`, "aria-label": t('members'), "aria-haspopup": "dialog", onClick: openMembers, children: [_jsx(IconUserOutline16, { size: wide ? 16 : 18 }), wide && _jsx("span", { children: t('members') })] }) }), _jsx(Modal, { open: panelOpen, onClose: closeMembers, title: t('members'), closeLabel: t('close'), contentClassName: membersCss.body, children: _jsxs("div", { ref: contentRef, className: membersCss.content, tabIndex: -1, children: [loading && _jsx("p", { className: membersCss.state, role: "status", children: t('loadingAgents') }), !loading && groups.length === 0 && error === undefined && _jsx("p", { className: membersCss.state, children: t('emptyAgents') }), !loading && groups.map(group => (_jsxs("section", { className: membersCss.group, "aria-labelledby": `team-members-${group.workspaceId}`, children: [_jsx("h3", { id: `team-members-${group.workspaceId}`, children: group.workspaceTitle }), group.members.map(status => _jsx(TeamMemberRow, { status: status, className: membersCss.member, t: t }, status.member.memberId))] }, group.workspaceId))), error !== undefined && _jsx("p", { className: membersCss.error, role: "alert", children: error })] }) })] }));
31
+ return (_jsxs(_Fragment, { children: [_jsx(Tooltip, { label: t('members'), delayMs: 500, disabled: wide, children: _jsxs("button", { ref: triggerRef, type: "button", className: wide ? css.settingsAction : `${css.settingsAction} ${css.rail}`, "aria-label": t('members'), "aria-haspopup": "dialog", onClick: openMembers, children: [_jsx(IconUserOutlineRegular, { size: wide ? 16 : 18 }), wide && _jsx("span", { children: t('members') })] }) }), _jsx(Modal, { open: panelOpen, onClose: closeMembers, title: t('members'), closeLabel: t('close'), contentClassName: membersCss.body, children: _jsxs("div", { ref: contentRef, className: membersCss.content, tabIndex: -1, children: [loading && _jsx("p", { className: membersCss.state, role: "status", children: t('loadingAgents') }), !loading && groups.length === 0 && error === undefined && _jsx("p", { className: membersCss.state, children: t('emptyAgents') }), !loading && groups.map(group => (_jsxs("section", { className: membersCss.group, "aria-labelledby": `team-members-${group.workspaceId}`, children: [_jsx("h3", { id: `team-members-${group.workspaceId}`, children: group.workspaceTitle }), group.members.map(status => _jsx(TeamMemberRow, { status: status, className: membersCss.member, t: t }, status.member.memberId))] }, group.workspaceId))), error !== undefined && _jsx("p", { className: membersCss.error, role: "alert", children: error })] }) })] }));
32
32
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TeamRowMenu.d.ts","sourceRoot":"","sources":["../../../src/client/TeamRowMenu.tsx"],"names":[],"mappings":"AACA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,uCAAuC,CAAA;AAGnG;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE;IACpE,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,CAAA;IACpC,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,sEAAsE;IACtE,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;CAChD,+BAkCA"}
1
+ {"version":3,"file":"TeamRowMenu.d.ts","sourceRoot":"","sources":["../../../src/client/TeamRowMenu.tsx"],"names":[],"mappings":"AACA,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,uCAAuC,CAAA;AAGxG;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE;IACpE,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,CAAA;IACpC,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,sEAAsE;IACtE,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;CAChD,+BAkCA"}
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
- import { IconEllipsisOutline16, Menu } from '@deepseek-ai/dsh-client-ui-primitives';
3
+ import { IconEllipsisOutlineRegular, Menu } from '@deepseek-ai/dsh-client-ui-primitives';
4
4
  import css from './sidebar.module.css';
5
5
  /**
6
6
  * Row-level overflow menu shared by sidebar Channel and Agent rows, mirroring
@@ -19,5 +19,5 @@ export function TeamRowMenu({ label, items, onSelect, onOpenChange }) {
19
19
  setOpen(false);
20
20
  onOpenChange?.(false);
21
21
  };
22
- return (_jsx(Menu, { open: open, onClose: close, items: items, onSelect: (id) => { close(); onSelect(id); }, portal: true, closeOnPointerLeave: true, anchor: (_jsx("button", { type: "button", className: css.rowMenuButton, "aria-label": label, "aria-haspopup": "menu", "aria-expanded": open, onClick: (event) => { event.stopPropagation(); toggle(); }, children: _jsx(IconEllipsisOutline16, {}) })) }));
22
+ return (_jsx(Menu, { open: open, onClose: close, items: items, onSelect: (id) => { close(); onSelect(id); }, portal: true, closeOnPointerLeave: true, anchor: (_jsx("button", { type: "button", className: css.rowMenuButton, "aria-label": label, "aria-haspopup": "menu", "aria-expanded": open, onClick: (event) => { event.stopPropagation(); toggle(); }, children: _jsx(IconEllipsisOutlineRegular, {}) })) }));
23
23
  }
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { IconChevronDownOutline14 } from '@deepseek-ai/dsh-client-ui-primitives';
2
+ import { IconChevronDownOutlineRegular } from '@deepseek-ai/dsh-client-ui-primitives';
3
3
  import css from './sidebar.module.css';
4
4
  /** Collapsible sidebar section header: disclosure toggle plus trailing actions. */
5
5
  export function TeamSidebarSection({ title, actions, open, onToggle, children }) {
6
- return (_jsxs("section", { className: css.section, children: [_jsxs("div", { className: css.sectionHeader, children: [_jsxs("button", { type: "button", className: css.sectionToggle, "aria-expanded": open, onClick: () => { onToggle(!open); }, children: [_jsx(IconChevronDownOutline14, { className: css.sectionChevron }), _jsx("span", { className: css.sectionTitle, children: title })] }), actions !== undefined && _jsx("span", { className: css.sectionActions, children: actions })] }), open && children] }));
6
+ return (_jsxs("section", { className: css.section, children: [_jsxs("div", { className: css.sectionHeader, children: [_jsxs("button", { type: "button", className: css.sectionToggle, "aria-expanded": open, onClick: () => { onToggle(!open); }, children: [_jsx(IconChevronDownOutlineRegular, { className: css.sectionChevron }), _jsx("span", { className: css.sectionTitle, children: title })] }), actions !== undefined && _jsx("span", { className: css.sectionActions, children: actions })] }), open && children] }));
7
7
  }
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
- import { Button, DisclosureRow, IconChevronLeftOutline14, IconChecklistOutline14, Modal, Pill } from '@deepseek-ai/dsh-client-ui-primitives';
3
+ import { Button, DisclosureRow, IconChevronLeftOutlineRegular, IconChecklistOutlineRegular, Modal, Pill } from '@deepseek-ai/dsh-client-ui-primitives';
4
4
  import { TeamComposer } from "./TeamComposer.js";
5
5
  import { diagnosticText, TeamPresenceDot } from "./TeamPresenceDot.js";
6
6
  import { TeamMessage } from "./TeamMessage.js";
@@ -703,7 +703,7 @@ export function TeamThreadPage(props) {
703
703
  // Threads are always entered through a Channel page, so a Channel origin
704
704
  // returns to its timeline; a Thread restored without one returns further.
705
705
  const backLabel = channelRef === undefined ? t('backToWorkspace') : t('backToChannel');
706
- return _jsxs("main", { className: css.surface, "data-team-thread": threadRef, children: [_jsxs("div", { className: css.surfaceHeader, children: [_jsx("div", { className: css.backRow, children: _jsx(Button, { size: "sm", icon: _jsx(IconChevronLeftOutline14, {}), onClick: backToWorkspace, children: backLabel }) }), _jsxs("header", { className: css.headerRow, children: [_jsxs("div", { className: css.headerCopy, children: [_jsxs("div", { className: threadCss.titleLine, children: [_jsx("h1", { children: task === undefined ? t('threadLabel') : t('taskLabel', { number: resolvedTaskNumber ?? '…' }) }), task !== undefined && _jsxs(Pill, { children: [_jsx(TeamStateDot, { size: 8, state: taskStatusDot(task.status) }), formatTaskStatus(task.status, t)] })] }), taskTitle !== undefined && taskTitle !== '' && _jsx("p", { className: threadCss.taskTitle, title: taskTitle, children: taskTitle })] }), task === undefined && thread !== undefined && _jsx("div", { className: css.headerActions, children: _jsx(Button, { size: "sm", variant: "primary", disabled: pending, onClick: () => { void convertToTask(); }, children: mutating === 'promote' ? t('promotingTask') : t('promoteToTask') }) }), task !== undefined && thread !== undefined && task.resolution !== 'closed' && _jsxs("div", { className: css.headerActions, children: [(() => {
706
+ return _jsxs("main", { className: css.surface, "data-team-thread": threadRef, children: [_jsxs("div", { className: css.surfaceHeader, children: [_jsx("div", { className: css.backRow, children: _jsx(Button, { size: "sm", icon: _jsx(IconChevronLeftOutlineRegular, {}), onClick: backToWorkspace, children: backLabel }) }), _jsxs("header", { className: css.headerRow, children: [_jsxs("div", { className: css.headerCopy, children: [_jsxs("div", { className: threadCss.titleLine, children: [_jsx("h1", { children: task === undefined ? t('threadLabel') : t('taskLabel', { number: resolvedTaskNumber ?? '…' }) }), task !== undefined && _jsxs(Pill, { children: [_jsx(TeamStateDot, { size: 8, state: taskStatusDot(task.status) }), formatTaskStatus(task.status, t)] })] }), taskTitle !== undefined && taskTitle !== '' && _jsx("p", { className: threadCss.taskTitle, title: taskTitle, children: taskTitle })] }), task === undefined && thread !== undefined && _jsx("div", { className: css.headerActions, children: _jsx(Button, { size: "sm", variant: "primary", disabled: pending, onClick: () => { void convertToTask(); }, children: mutating === 'promote' ? t('promotingTask') : t('promoteToTask') }) }), task !== undefined && thread !== undefined && task.resolution !== 'closed' && _jsxs("div", { className: css.headerActions, children: [(() => {
707
707
  const activeClaims = projection?.claims.filter(claim => claim.taskRef === task.taskRef && claim.state === 'active') ?? [];
708
708
  const earlyAccept = task.resolution === 'open' && task.status === 'in_progress' && activeClaims.length > 0;
709
709
  // todo Tasks accept directly: the work finished outside the
@@ -723,7 +723,7 @@ export function TeamThreadPage(props) {
723
723
  const activeClaims = projection?.claims.filter(claim => claim.taskRef === task.taskRef && claim.state === 'active') ?? [];
724
724
  return _jsxs(Modal, { open: confirmingAccept, onClose: () => { if (!pending)
725
725
  setConfirmingAccept(false); }, title: t('acceptEarlyTitle'), closeLabel: t('cancel'), footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: pending, onClick: () => { setConfirmingAccept(false); }, children: t('cancel') }), _jsx(Button, { variant: "primary", disabled: pending, onClick: () => { void mutateTask('accept'); }, children: mutating === 'accept' ? t('acceptingTask') : t('acceptTask') })] }), children: [_jsx("p", { className: css.confirmBody, children: t('acceptEarlyBody', { count: activeClaims.length }) }), _jsx("ul", { className: css.confirmList, children: activeClaims.map(claim => (_jsxs("li", { children: [memberName(claim.owner), " \u00B7 ", claim.direction] }, claim.claimRef))) })] });
726
- })(), task !== undefined && thread !== undefined && _jsx("section", { className: threadCss.workSection, "aria-label": t('claims'), children: _jsx(DisclosureRow, { expandOnRowClick: true, expandable: true, open: claimsOpen, onToggle: () => { setClaimsOpen(current => !current); }, icon: _jsx(IconChecklistOutline14, { size: 14 }), title: `${t('claims')} · ${taskClaims.length}`, children: _jsxs("div", { className: threadCss.claimList, children: [taskClaims.length === 0 && _jsx("p", { className: threadCss.emptyClaims, children: t('noClaims') }), taskClaims.map(claim => {
726
+ })(), task !== undefined && thread !== undefined && _jsx("section", { className: threadCss.workSection, "aria-label": t('claims'), children: _jsx(DisclosureRow, { expandOnRowClick: true, expandable: true, open: claimsOpen, onToggle: () => { setClaimsOpen(current => !current); }, icon: _jsx(IconChecklistOutlineRegular, { size: 14 }), title: `${t('claims')} · ${taskClaims.length}`, children: _jsxs("div", { className: threadCss.claimList, children: [taskClaims.length === 0 && _jsx("p", { className: threadCss.emptyClaims, children: t('noClaims') }), taskClaims.map(claim => {
727
727
  const ownerStatus = members.find(status => status.member.memberId === claim.owner);
728
728
  return _jsxs("article", { className: threadCss.claimRow, children: [ownerStatus === undefined ? _jsx("span", {}) : _jsx(TeamPresenceDot, { status: ownerStatus, t: t }), _jsx("strong", { className: threadCss.claimOwner, children: memberName(claim.owner) }), _jsx("span", { className: threadCss.claimDirection, children: claim.direction }), _jsx("small", { className: threadCss.claimState, children: formatClaimState(claim.state, t) })] }, claim.claimRef);
729
729
  })] }) }) })] }), _jsx("section", { ref: timeline.ref, onScroll: handleTimelineScroll, className: css.timeline, "aria-label": t('timelineLabel'), children: _jsxs("div", { className: css.timelineContent, children: [loading && projection === undefined && error === undefined && _jsx("div", { className: css.emptySurface, children: _jsxs("p", { className: css.loadingState, children: [_jsx("span", { className: css.loadingMark, "aria-hidden": "true" }), t('loadingThread')] }) }), projection === undefined && error !== undefined && _jsxs("div", { className: css.errorState, role: "alert", children: [_jsx("span", { children: error }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => { void readCurrent(); }, children: t('retry') })] }), olderFacts.length > 0 && _jsxs("section", { className: threadCss.historySection, "aria-label": t('olderHistory'), children: [_jsx("h2", { children: t('olderHistory') }), renderFactBlocks(olderFacts, undefined)] }), historyHasMore && _jsx("div", { className: css.timelineAction, children: _jsx(Button, { size: "sm", onClick: () => { void loadOlder(); }, children: t('loadOlder') }) }), currentFactsWithAnchor.length > 0 && _jsx("section", { className: threadCss.publicSection, children: renderFactBlocks(currentFactsWithAnchor, unreadBoundary) }), autoReadExhausted && _jsxs("div", { className: css.timelineAction, role: "alert", children: [_jsx("span", { children: t('autoReadIncomplete') }), _jsx(Button, { size: "sm", onClick: () => { setAutoReadExhausted(false); void drainUnread(); }, disabled: loading, children: t('retry') })] }), newFactsCount > 0 && _jsx("div", { className: threadCss.newUpdates, role: "status", children: _jsx("button", { type: "button", className: threadCss.newUpdatesJump, onClick: () => { setNewFactsCount(0); timeline.scrollToBottom(); }, children: t('newUpdatesJump', { count: newFactsCount }) }) })] }) }), projection !== undefined && thread !== undefined ? (task?.resolution === 'closed'
@@ -1 +1 @@
1
- {"version":3,"file":"TeamWorkspaceBrowser.d.ts","sourceRoot":"","sources":["../../../src/client/TeamWorkspaceBrowser.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAyBlD,wBAAgB,oBAAoB,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,gBAAgB,EAAE,cAAc,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,mBAAmB,EAAE,UAAU,EAAE,iBAAiB,EAAE,EAAE,gBAAgB,+BAoHra"}
1
+ {"version":3,"file":"TeamWorkspaceBrowser.d.ts","sourceRoot":"","sources":["../../../src/client/TeamWorkspaceBrowser.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAuBlD,wBAAgB,oBAAoB,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,gBAAgB,EAAE,cAAc,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,mBAAmB,EAAE,UAAU,EAAE,iBAAiB,EAAE,EAAE,gBAAgB,+BAiHra"}
@@ -1,9 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useRef, useState, useSyncExternalStore } from 'react';
3
- import { IconAgentPresetOutline16, IconListPenOutline16, IconQueueOutline14, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
4
- import { TeamWorkspaceRow } from "./TeamWorkspaceRow.js";
5
- import { TeamSidebarSection } from "./TeamSidebarSection.js";
6
- import { useSidebarSectionOpen, setSidebarSectionOpen } from "./sidebar-sections.js";
3
+ import { IconAgentPresetOutlineRegular, IconListPenOutlineRegular, IconQueueOutlineRegular, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
4
+ import { TeamWorkspaceSelector } from "./TeamWorkspaceSelector.js";
7
5
  import { TeamAgentsPanel } from "./TeamAgentsPanel.js";
8
6
  import { TeamChannelsPanel } from "./TeamChannelsPanel.js";
9
7
  import css from './sidebar.module.css';
@@ -16,7 +14,7 @@ import css from './sidebar.module.css';
16
14
  * on the same corner of the same glyph.
17
15
  */
18
16
  function InboxMark({ unread }) {
19
- return _jsxs("span", { className: css.inboxMark, children: [_jsx(IconQueueOutline14, { size: 16 }), unread > 0 && _jsx("span", { className: css.inboxDot, "data-team-inbox-dot": true, "aria-hidden": "true" })] });
17
+ return _jsxs("span", { className: css.inboxMark, children: [_jsx(IconQueueOutlineRegular, { size: 16 }), unread > 0 && _jsx("span", { className: css.inboxDot, "data-team-inbox-dot": true, "aria-hidden": "true" })] });
20
18
  }
21
19
  export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, selectInbox, t, useWorkspaces, loadMembers, loadInbox, subscribeChanges, subscribeReads, addMember, loadChannels, createChannel, updateChannel, archiveChannel, updateMember, recoverMember, archiveMember, joinWorkspace, leaveWorkspace, joinChannel, removeChannelMember, loadModels, openMemberSession }) {
22
20
  const navigationState = useSyncExternalStore(navigation.subscribe, navigation.getSnapshot, navigation.getSnapshot);
@@ -39,7 +37,6 @@ export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWo
39
37
  const [pendingSection, setPendingSection] = useState();
40
38
  const channelsRef = useRef(null);
41
39
  const agentsRef = useRef(null);
42
- const workspacesOpen = useSidebarSectionOpen(undefined, 'workspaces');
43
40
  // The cross-Workspace Inbox badge: one scope-less subscription while the
44
41
  // Team sidebar stands; every wake re-pulls each Workspace's unread total
45
42
  // (limit 1 — totals cover every row, never the list). Same-burst wakes
@@ -98,7 +95,7 @@ export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWo
98
95
  queueMicrotask(() => { node?.querySelector('button')?.focus(); });
99
96
  }, [wide, pendingSection]);
100
97
  if (!wide) {
101
- return _jsxs("nav", { className: css.railWorkspace, "aria-label": t('workspaceSections'), children: [_jsx(Tooltip, { label: inboxLabel, side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": inboxLabel, "aria-current": inboxIsCurrent ? 'page' : undefined, onClick: () => { selectInbox(); expandSidebar(); }, children: _jsx(InboxMark, { unread: inboxTotal }) }) }), _jsx(Tooltip, { label: t('channels'), side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": t('channels'), onClick: () => { setPendingSection('channels'); expandSidebar(); }, children: _jsx(IconListPenOutline16, { size: 16 }) }) }), _jsx(Tooltip, { label: t('agents'), side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": t('agents'), onClick: () => { setPendingSection('agents'); expandSidebar(); }, children: _jsx(IconAgentPresetOutline16, { size: 16 }) }) })] });
98
+ return _jsxs("nav", { className: css.railWorkspace, "aria-label": t('workspaceSections'), children: [_jsx(Tooltip, { label: inboxLabel, side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": inboxLabel, "aria-current": inboxIsCurrent ? 'page' : undefined, onClick: () => { selectInbox(); expandSidebar(); }, children: _jsx(InboxMark, { unread: inboxTotal }) }) }), _jsx(Tooltip, { label: t('channels'), side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": t('channels'), onClick: () => { setPendingSection('channels'); expandSidebar(); }, children: _jsx(IconListPenOutlineRegular, { size: 16 }) }) }), _jsx(Tooltip, { label: t('agents'), side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": t('agents'), onClick: () => { setPendingSection('agents'); expandSidebar(); }, children: _jsx(IconAgentPresetOutlineRegular, { size: 16 }) }) })] });
102
99
  }
103
- return _jsxs("section", { className: css.workspaceBrowser, "aria-label": t('workspaces'), children: [_jsxs("button", { type: "button", className: css.inboxCard, "aria-label": inboxLabel, "aria-current": inboxIsCurrent ? 'page' : undefined, onClick: selectInbox, children: [_jsx(InboxMark, { unread: inboxTotal }), _jsx("span", { className: css.inboxCardLabel, children: t('inboxTitle') })] }), _jsx(TeamSidebarSection, { title: t('workspaces'), open: workspacesOpen, onToggle: open => { setSidebarSectionOpen(undefined, 'workspaces', open); }, children: _jsxs("div", { className: css.workspaceList, children: [workspaces.map(workspace => _jsx(TeamWorkspaceRow, { workspaceId: workspace.workspaceId, title: workspace.title, path: workspace.path, selected: workspace.workspaceId === selectedId, current: workspace.workspaceId === selectedId && overviewIsCurrent, onSelect: selectWorkspace }, workspace.workspaceId)), workspaces.length === 0 && _jsx("p", { className: css.emptyState, children: t('empty') })] }) }), selectedId !== undefined && _jsxs("div", { className: css.workspaceSection, children: [_jsx("div", { ref: channelsRef, children: _jsx(TeamChannelsPanel, { workspaceId: selectedId, loadMembers: loadMembers, loadChannels: loadChannels, subscribeChanges: subscribeChanges, createChannel: createChannel, updateChannel: updateChannel, archiveChannel: archiveChannel, joinChannel: joinChannel, removeChannelMember: removeChannelMember, creatingAgents: creatingAgents.filter(request => request.workspaceId === selectedId), ...(navigationState.memberSessionId !== undefined || navigationState.channelRef === undefined ? {} : { selectedChannelRef: navigationState.channelRef }), selectChannel: selectChannel, t: t }, selectedId) }), _jsx("div", { ref: agentsRef, children: _jsx(TeamAgentsPanel, { workspaceId: selectedId, loadMembers: loadMembers, subscribeChanges: subscribeChanges, addMember: addMember, updateMember: updateMember, recoverMember: recoverMember, archiveMember: archiveMember, joinWorkspace: joinWorkspace, leaveWorkspace: leaveWorkspace, loadModels: loadModels, ...(navigationState.memberSessionId === undefined ? {} : { memberSessionId: navigationState.memberSessionId }), openMemberSession: openMemberSession, onCreatingChange: (request, creating) => { setCreatingAgents(current => creating ? [...current.filter(item => item.requestId !== request.requestId), request] : current.filter(item => item.requestId !== request.requestId)); }, t: t }, selectedId) })] })] });
100
+ return _jsxs("section", { className: css.workspaceBrowser, "aria-label": t('workspaces'), children: [_jsxs("button", { type: "button", className: css.inboxCard, "aria-label": inboxLabel, "aria-current": inboxIsCurrent ? 'page' : undefined, onClick: selectInbox, children: [_jsx(InboxMark, { unread: inboxTotal }), _jsx("span", { className: css.inboxCardLabel, children: t('inboxTitle') })] }), _jsx(TeamWorkspaceSelector, { workspaces: workspaces, selectedId: selectedId, current: overviewIsCurrent, onSelect: selectWorkspace, t: t }), selectedId !== undefined && _jsxs("div", { className: css.workspaceSection, children: [_jsx("div", { ref: channelsRef, children: _jsx(TeamChannelsPanel, { workspaceId: selectedId, loadMembers: loadMembers, loadChannels: loadChannels, subscribeChanges: subscribeChanges, createChannel: createChannel, updateChannel: updateChannel, archiveChannel: archiveChannel, joinChannel: joinChannel, removeChannelMember: removeChannelMember, creatingAgents: creatingAgents.filter(request => request.workspaceId === selectedId), ...(navigationState.memberSessionId !== undefined || navigationState.channelRef === undefined ? {} : { selectedChannelRef: navigationState.channelRef }), selectChannel: selectChannel, t: t }, selectedId) }), _jsx("div", { ref: agentsRef, children: _jsx(TeamAgentsPanel, { workspaceId: selectedId, loadMembers: loadMembers, subscribeChanges: subscribeChanges, addMember: addMember, updateMember: updateMember, recoverMember: recoverMember, archiveMember: archiveMember, joinWorkspace: joinWorkspace, leaveWorkspace: leaveWorkspace, loadModels: loadModels, ...(navigationState.memberSessionId === undefined ? {} : { memberSessionId: navigationState.memberSessionId }), openMemberSession: openMemberSession, onCreatingChange: (request, creating) => { setCreatingAgents(current => creating ? [...current.filter(item => item.requestId !== request.requestId), request] : current.filter(item => item.requestId !== request.requestId)); }, t: t }, selectedId) })] })] });
104
101
  }
@@ -0,0 +1,37 @@
1
+ import type { WorkspaceId } from '@deepseek-ai/dsh-api-workspace-controller/client';
2
+ /** One selectable Workspace, in the order the Workspace list already carries. */
3
+ export interface TeamWorkspaceChoice {
4
+ readonly workspaceId: WorkspaceId;
5
+ readonly title: string;
6
+ readonly path: string;
7
+ }
8
+ /**
9
+ * The single-line Workspace selector that scopes the Team sidebar.
10
+ *
11
+ * The sections below it — Channels and Agents — belong to exactly one
12
+ * Workspace, so a flat list of every Workspace above them states a global
13
+ * scope over local content. Collapsing that list into one selector makes the
14
+ * sidebar read as "you are in X, and here is X's content", and returns the
15
+ * rows a low-frequency switch was holding. Nothing is hidden by the collapse:
16
+ * Workspace rows carry no unread mark of their own, and cross-Workspace unread
17
+ * is summarized by the Inbox entry above — the one destination that outlives
18
+ * this scope, which is why it stays outside the selector's reach.
19
+ *
20
+ * The trigger is a field rather than a row: the line that states where the
21
+ * reader is must not read as the first entry of the Channels list below it,
22
+ * and its accessible name states the Workspace it is showing, because that
23
+ * value is otherwise unavailable to a reader who cannot see the field. The
24
+ * menu is the only way to switch Workspaces, so it takes focus on open and
25
+ * hands it back to the trigger on Escape.
26
+ */
27
+ export declare function TeamWorkspaceSelector({ workspaces, selectedId, current, onSelect, t }: {
28
+ readonly workspaces: readonly TeamWorkspaceChoice[];
29
+ readonly selectedId: WorkspaceId | undefined;
30
+ /** The Team center shows the selected Workspace's overview (no Channel is open). */
31
+ readonly current: boolean;
32
+ readonly onSelect: (workspaceId: WorkspaceId) => void;
33
+ readonly t: (key: 'empty' | 'workspaceSelectorWithValue', params?: {
34
+ title: string;
35
+ }) => string;
36
+ }): import("react").JSX.Element;
37
+ //# sourceMappingURL=TeamWorkspaceSelector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TeamWorkspaceSelector.d.ts","sourceRoot":"","sources":["../../../src/client/TeamWorkspaceSelector.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAGnF,iFAAiF;AACjF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE;IACtF,QAAQ,CAAC,UAAU,EAAE,SAAS,mBAAmB,EAAE,CAAA;IACnD,QAAQ,CAAC,UAAU,EAAE,WAAW,GAAG,SAAS,CAAA;IAC5C,oFAAoF;IACpF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,IAAI,CAAA;IACrD,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,4BAA4B,EAAE,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAA;CAChG,+BA0DA"}
@@ -0,0 +1,58 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { IconChevronDownOutlineRegular, IconFolderOpenRegular, Menu } from '@deepseek-ai/dsh-client-ui-primitives';
4
+ import css from './sidebar.module.css';
5
+ /**
6
+ * The single-line Workspace selector that scopes the Team sidebar.
7
+ *
8
+ * The sections below it — Channels and Agents — belong to exactly one
9
+ * Workspace, so a flat list of every Workspace above them states a global
10
+ * scope over local content. Collapsing that list into one selector makes the
11
+ * sidebar read as "you are in X, and here is X's content", and returns the
12
+ * rows a low-frequency switch was holding. Nothing is hidden by the collapse:
13
+ * Workspace rows carry no unread mark of their own, and cross-Workspace unread
14
+ * is summarized by the Inbox entry above — the one destination that outlives
15
+ * this scope, which is why it stays outside the selector's reach.
16
+ *
17
+ * The trigger is a field rather than a row: the line that states where the
18
+ * reader is must not read as the first entry of the Channels list below it,
19
+ * and its accessible name states the Workspace it is showing, because that
20
+ * value is otherwise unavailable to a reader who cannot see the field. The
21
+ * menu is the only way to switch Workspaces, so it takes focus on open and
22
+ * hands it back to the trigger on Escape.
23
+ */
24
+ export function TeamWorkspaceSelector({ workspaces, selectedId, current, onSelect, t }) {
25
+ const [open, setOpen] = useState(false);
26
+ // A portaled Menu list is laid out `visibility: hidden` and placed by the
27
+ // primitive's own layout effect, so its `autoFocus` effect runs one render
28
+ // too early: `focus()` on a hidden row is a no-op. The menu would then open
29
+ // with focus still on the trigger, and the primitive's arrow keys — which
30
+ // index from `document.activeElement` — stay dead, leaving a keyboard reader
31
+ // no way to reach another Workspace. Focusing the opened row once the list is
32
+ // on screen restores what `autoFocus` is for; it does nothing when focus is
33
+ // already inside the list.
34
+ useEffect(() => {
35
+ if (!open)
36
+ return;
37
+ const frame = requestAnimationFrame(() => {
38
+ // Portaled lists are children of the portal target, and the list this
39
+ // open mounted is the last of them.
40
+ const lists = document.querySelectorAll('body > [role="menu"]');
41
+ const list = lists[lists.length - 1];
42
+ if (list === undefined || list.contains(document.activeElement))
43
+ return;
44
+ list.querySelector('button:not(:disabled)')?.focus();
45
+ });
46
+ return () => { cancelAnimationFrame(frame); };
47
+ }, [open]);
48
+ const selected = workspaces.find(workspace => workspace.workspaceId === selectedId);
49
+ // Nothing to state — no Workspace, or a selection the list no longer carries —
50
+ // so the browser says that in the selector's own seat instead of a dead field.
51
+ if (selected === undefined)
52
+ return _jsx("p", { className: css.emptyState, children: t('empty') });
53
+ const items = workspaces.map(workspace => ({
54
+ id: workspace.workspaceId,
55
+ label: workspace.title,
56
+ }));
57
+ return (_jsx(Menu, { open: open, portal: true, autoFocus: true, items: items, selectedIds: [selected.workspaceId], onSelect: id => { setOpen(false); onSelect(id); }, onClose: () => { setOpen(false); }, anchor: (_jsxs("button", { type: "button", className: css.workspaceTrigger, "data-team-workspace-trigger": true, "aria-label": t('workspaceSelectorWithValue', { title: selected.title }), "aria-haspopup": "menu", "aria-expanded": open, "aria-current": current ? 'page' : undefined, title: `${selected.title} · ${selected.path}`, onClick: () => { setOpen(value => !value); }, children: [_jsx("span", { className: css.workspaceIcon, "aria-hidden": "true", children: _jsx(IconFolderOpenRegular, { size: 16 }) }), _jsx("span", { className: css.workspaceValue, children: selected.title }), _jsx("span", { className: `${css.workspaceChevron} ${open ? css.workspaceChevronOpen : ''}`, "aria-hidden": "true", children: _jsx(IconChevronDownOutlineRegular, {}) })] })) }));
58
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAuCnE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAK5C,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AAEnD,YAAY,EAAE,QAAQ,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAC9F,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAIhD,eAAO,MAAM,MAAM,UAElB,CAAA;AAED,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,IAAI,EAAE,OAAO,CAAA;KACd;CACF;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,cAAc,EAAE,cAAc,CAAA;QAC9B,UAAU,EAAE,cAAc,CAAA;KAC3B;CACF;AAoMD,wBAAsB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAuCnE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAK5C,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AAEnD,YAAY,EAAE,QAAQ,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAC9F,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAIhD,eAAO,MAAM,MAAM,UAElB,CAAA;AAuBD,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,IAAI,EAAE,OAAO,CAAA;KACd;CACF;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,cAAc,EAAE,cAAc,CAAA;QAC9B,UAAU,EAAE,cAAc,CAAA;KAC3B;CACF;AAqMD,wBAAsB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D"}
@@ -10,8 +10,27 @@ import { en, zh } from "./locales.js";
10
10
  export { TeamNavigation } from "./navigation.js";
11
11
  const NS = 'team';
12
12
  export const inject = [
13
- 'slots', 'workspaces', 'locale', 'remote', 'remote.session', 'sessions', 'connection', 'conversation',
13
+ 'slots', 'workspaces', 'locale', 'remote', 'remote.session', 'sessions', 'connection', 'conversation', 'uiWorkspace',
14
14
  ];
15
+ /**
16
+ * 0.1.7 moved the conversation selection into the workspace service: the
17
+ * rendered session is the one holding its `mainView` reference (the shipped
18
+ * consumers read the same projection), so the Team client reads the selection
19
+ * through retention instead of a service-owned `current`.
20
+ */
21
+ function currentMainSessionId(ctx) {
22
+ const sessions = ctx.sessions;
23
+ return Object.values(sessions.list.getSnapshot().byId)
24
+ .find(session => (session.retainedBy.mainView ?? 0) > 0)?.id;
25
+ }
26
+ /**
27
+ * Session ids this client opened as Member views, per client instance. The
28
+ * 0.1.7 workspace service exposes no clear, so a dead return target leaves
29
+ * the departed Member selection in place; excluding Member sessions from the
30
+ * next capture keeps that stale selection from becoming a false return
31
+ * target.
32
+ */
33
+ const openedMemberSessions = new WeakMap();
15
34
  function registerModeShadow(ctx, navigation, changes, reads, drafts, name, component, extraInject,
16
35
  // Keyed seats (`main`) address one panel by key; the reserved 'conversation'
17
36
  // key is where the shipped Conversation registers, so the Team seat shadows
@@ -21,14 +40,16 @@ entryKey) {
21
40
  // views (see registerModeShadow), so the shipped conversation root renders
22
41
  // the selected Member Session inside the Team shell.
23
42
  const openMemberSessionImpl = (sessionId) => {
24
- const sessions = ctx.sessions;
25
43
  const snapshot = navigation.getSnapshot();
26
- const current = sessions.list.getSnapshot().current;
44
+ const current = currentMainSessionId(ctx);
27
45
  // The return target is captured on first entry only — switching between
28
46
  // Member Sessions must keep pointing at the Human's original session.
29
- const returnTo = snapshot.memberSessionId === undefined && current !== undefined && current !== sessionId ? current : undefined;
47
+ const memberSessions = openedMemberSessions.get(ctx) ?? new Set();
48
+ openedMemberSessions.set(ctx, memberSessions);
49
+ memberSessions.add(sessionId);
50
+ const returnTo = snapshot.memberSessionId === undefined && current !== undefined && current !== sessionId && !memberSessions.has(current) ? current : undefined;
30
51
  navigation.actions().enterMemberSession(sessionId, returnTo);
31
- sessions.open(sessionId);
52
+ ctx.uiWorkspace.openSession(sessionId);
32
53
  };
33
54
  // Remote bindings shared by every Team slot; surface-specific entries extend it below.
34
55
  const sharedRemotes = {
@@ -125,12 +146,13 @@ function applyUi(ctx) {
125
146
  void disposeDrafts();
126
147
  }, 'agent-team: navigation service');
127
148
  // The one restore owner: leaving an embedded Member Session view must
128
- // rebind the underlying current session, or the stale Member current later
129
- // masks to undefined when the Host disposes that session (rollover) and
130
- // the conversation seat remounts. Takeover is conditional — only when the
131
- // current still IS the departed Member session — so a selection someone
132
- // else made in the meantime survives. A dead return target clears instead
133
- // of opening an unknown id.
149
+ // rebind the underlying selection, or the departed Member session stays the
150
+ // workspace service's `mainView` retention into the next Member entry's
151
+ // return-target capture. Takeover is conditional — only when the selection
152
+ // still IS the departed Member session — so a selection someone else made
153
+ // in the meantime survives. A dead return target keeps the departed
154
+ // selection: 0.1.7 exposes no public clear, and the retention is inert
155
+ // behind the Team seat until the next open.
134
156
  ctx.effect(() => {
135
157
  let previous = navigation.getSnapshot();
136
158
  const restore = () => {
@@ -140,13 +162,10 @@ function applyUi(ctx) {
140
162
  previous = snapshot;
141
163
  if (departed === undefined || snapshot.memberSessionId !== undefined)
142
164
  return;
143
- const sessions = ctx.sessions;
144
- if (sessions.list.getSnapshot().current !== departed)
165
+ if (currentMainSessionId(ctx) !== departed)
145
166
  return;
146
- if (returnTo !== undefined && sessions.list.getSnapshot().byId[returnTo] !== undefined)
147
- sessions.open(returnTo);
148
- else
149
- sessions.clear();
167
+ if (returnTo !== undefined && ctx.sessions.list.getSnapshot().byId[returnTo] !== undefined)
168
+ ctx.uiWorkspace.openSession(returnTo);
150
169
  };
151
170
  const unsubscribe = navigation.subscribe(restore);
152
171
  return () => {
@@ -183,7 +202,7 @@ function applyUi(ctx) {
183
202
  navigation,
184
203
  ...navigation.actions(),
185
204
  // The footer is the only surface that leaves Team mode; closing the
186
- // embedded Member Session view rebinds the underlying current through
205
+ // embedded Member Session view rebinds the underlying selection through
187
206
  // the same root-scope restore owner, so there is exactly one restore
188
207
  // path and no double open.
189
208
  leaveTeam: () => {
@@ -2,6 +2,7 @@ export declare const zh: {
2
2
  readonly team: "团队";
3
3
  readonly backToConversations: "对话";
4
4
  readonly workspaces: "工作区";
5
+ readonly workspaceSelectorWithValue: "工作区,{title}";
5
6
  readonly channels: "频道";
6
7
  readonly agents: "Agents";
7
8
  readonly members: "成员";
@@ -178,6 +179,7 @@ export declare const en: {
178
179
  readonly team: "Team";
179
180
  readonly backToConversations: "Conversations";
180
181
  readonly workspaces: "Workspaces";
182
+ readonly workspaceSelectorWithValue: "Workspace, {title}";
181
183
  readonly channels: "Channels";
182
184
  readonly agents: "Agents";
183
185
  readonly members: "Members";
@@ -1 +1 @@
1
- {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+KL,CAAA;AAEV,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+KL,CAAA;AAEV,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,EAAE,CAAA"}
1
+ {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgLL,CAAA;AAEV,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgLL,CAAA;AAEV,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,EAAE,CAAA"}