@wowyuarm/dsh-agent-team 0.1.11 → 0.1.13

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 (114) hide show
  1. package/README.md +6 -4
  2. package/README.zh.md +6 -4
  3. package/cordis.patch.yml +7 -3
  4. package/package.json +16 -3
  5. package/packages/agent-team/README.md +4 -4
  6. package/packages/agent-team/README.zh.md +4 -4
  7. package/packages/agent-team/lib/context-projection.js +5 -1
  8. package/packages/agent-team/lib/index.js +162 -113
  9. package/packages/agent-team/lib/ledger.js +496 -169
  10. package/packages/agent-team/lib/member-context.js +18 -1
  11. package/packages/agent-team/lib/member-runtime.js +48 -9
  12. package/packages/agent-team/lib/mentions.js +80 -0
  13. package/packages/agent-team/lib/spec.js +20 -0
  14. package/packages/agent-team/lib/typert.host.js +241 -46
  15. package/packages/agent-team/lib/typert.remote-client.d.ts +7 -3
  16. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  17. package/packages/agent-team/lib/typert.remote-client.js +178 -28
  18. package/packages/agent-team/lib/types/context-projection.d.ts.map +1 -1
  19. package/packages/agent-team/lib/types/index.d.ts +33 -14
  20. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  21. package/packages/agent-team/lib/types/ledger.d.ts +120 -18
  22. package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
  23. package/packages/agent-team/lib/types/member-context.d.ts +6 -0
  24. package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
  25. package/packages/agent-team/lib/types/member-runtime.d.ts +2 -1
  26. package/packages/agent-team/lib/types/member-runtime.d.ts.map +1 -1
  27. package/packages/agent-team/lib/types/mentions.d.ts +47 -0
  28. package/packages/agent-team/lib/types/mentions.d.ts.map +1 -0
  29. package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
  30. package/packages/agent-team/lib/types/types/entities.d.ts +3 -20
  31. package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
  32. package/packages/agent-team/lib/types/types/operations.d.ts +37 -1
  33. package/packages/agent-team/lib/types/types/operations.d.ts.map +1 -1
  34. package/packages/agent-team/lib/types/types/requests-results.d.ts +107 -25
  35. package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
  36. package/packages/agent-team/lib/types/vendor/storage-sqlite/index.d.ts +87 -0
  37. package/packages/agent-team/lib/types/vendor/storage-sqlite/index.d.ts.map +1 -0
  38. package/packages/agent-team/lib/types/vendor/storage-sqlite/schema.d.ts +59 -0
  39. package/packages/agent-team/lib/types/vendor/storage-sqlite/schema.d.ts.map +1 -0
  40. package/packages/agent-team/lib/types/vendor/storage-sqlite/unit.d.ts +57 -0
  41. package/packages/agent-team/lib/types/vendor/storage-sqlite/unit.d.ts.map +1 -0
  42. package/packages/agent-team/lib/vendor/storage-sqlite/index.js +139 -0
  43. package/packages/agent-team/lib/vendor/storage-sqlite/schema.js +120 -0
  44. package/packages/agent-team/lib/vendor/storage-sqlite/unit.js +132 -0
  45. package/packages/agent-team/preset/team-member/agent.cordis.yml +48 -8
  46. package/packages/client-agent-team/README.md +1 -1
  47. package/packages/client-agent-team/README.zh.md +1 -1
  48. package/packages/client-agent-team/lib/client.js +2123 -1406
  49. package/packages/client-agent-team/lib/client.js.map +1 -1
  50. package/packages/client-agent-team/lib/types/client/TeamAgentImport.d.ts +12 -0
  51. package/packages/client-agent-team/lib/types/client/TeamAgentImport.d.ts.map +1 -0
  52. package/packages/client-agent-team/lib/types/client/TeamAgentImport.js +69 -0
  53. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +3 -1
  54. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
  55. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +31 -19
  56. package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts +18 -0
  57. package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts.map +1 -0
  58. package/packages/client-agent-team/lib/types/client/TeamAvatarStack.js +22 -0
  59. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts +3 -1
  60. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
  61. package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +111 -24
  62. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
  63. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +10 -3
  64. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
  65. package/packages/client-agent-team/lib/types/client/TeamComposer.js +11 -17
  66. package/packages/client-agent-team/lib/types/client/TeamConversation.js +1 -1
  67. package/packages/client-agent-team/lib/types/client/TeamCountBadge.d.ts +20 -0
  68. package/packages/client-agent-team/lib/types/client/TeamCountBadge.d.ts.map +1 -0
  69. package/packages/client-agent-team/lib/types/client/TeamCountBadge.js +25 -0
  70. package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts +9 -5
  71. package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts.map +1 -1
  72. package/packages/client-agent-team/lib/types/client/TeamInboxPage.js +92 -23
  73. package/packages/client-agent-team/lib/types/client/TeamMemberRow.d.ts +43 -0
  74. package/packages/client-agent-team/lib/types/client/TeamMemberRow.d.ts.map +1 -0
  75. package/packages/client-agent-team/lib/types/client/TeamMemberRow.js +27 -0
  76. package/packages/client-agent-team/lib/types/client/TeamMembersAction.d.ts +2 -2
  77. package/packages/client-agent-team/lib/types/client/TeamMembersAction.d.ts.map +1 -1
  78. package/packages/client-agent-team/lib/types/client/TeamMembersAction.js +2 -2
  79. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts +1 -1
  80. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts.map +1 -1
  81. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
  82. package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +21 -31
  83. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
  84. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
  85. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +29 -11
  86. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  87. package/packages/client-agent-team/lib/types/client/index.js +11 -5
  88. package/packages/client-agent-team/lib/types/client/locales.d.ts +54 -16
  89. package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
  90. package/packages/client-agent-team/lib/types/client/locales.js +54 -16
  91. package/packages/client-agent-team/lib/types/client/slots.d.ts +3 -2
  92. package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
  93. package/packages/client-agent-team/lib/types/client/team-changes.d.ts +15 -25
  94. package/packages/client-agent-team/lib/types/client/team-changes.d.ts.map +1 -1
  95. package/packages/client-agent-team/lib/types/client/team-changes.js +82 -80
  96. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +45 -10
  97. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
  98. package/packages/client-agent-team/lib/types/client/team-formatters.js +71 -30
  99. package/packages/tool-agent-team/README.md +3 -3
  100. package/packages/tool-agent-team/README.zh.md +3 -3
  101. package/packages/tool-agent-team/lib/host-access.js +19 -0
  102. package/packages/tool-agent-team/lib/index.js +71 -49
  103. package/packages/tool-agent-team/lib/types/host-access.d.ts +10 -0
  104. package/packages/tool-agent-team/lib/types/host-access.d.ts.map +1 -1
  105. package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
  106. package/packages/agent-team/lib/progress-nudge.js +0 -328
  107. package/packages/agent-team/lib/types/progress-nudge.d.ts +0 -136
  108. package/packages/agent-team/lib/types/progress-nudge.d.ts.map +0 -1
  109. package/packages/client-agent-team/lib/types/client/TeamSettings.d.ts +0 -3
  110. package/packages/client-agent-team/lib/types/client/TeamSettings.d.ts.map +0 -1
  111. package/packages/client-agent-team/lib/types/client/TeamSettings.js +0 -5
  112. package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts +0 -41
  113. package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts.map +0 -1
  114. package/packages/client-agent-team/lib/types/client/scope-coverage.js +0 -64
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
3
  import { Button, IconArchiveOutline20, IconEditOutline16, IconPlusOutline16, Input, Modal, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
4
4
  import { TeamPresenceDot } from "./TeamPresenceDot.js";
5
+ import { TeamMemberRow } from "./TeamMemberRow.js";
5
6
  import { MultiMenuField } from "./multi-menu-field.js";
6
7
  import { SortableRow, useSidebarRowDrag } from "./sidebar-drag.js";
7
8
  import { moveSidebarItem, useSidebarOrder } from "./sidebar-order.js";
@@ -152,7 +153,7 @@ export function TeamChannelsPanel(props) {
152
153
  return next;
153
154
  });
154
155
  setPendingCreate(undefined);
155
- }, 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 => {
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
157
  const joined = membership.get(channel.channelRef) ?? new Set();
157
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));
158
159
  }) })] }), !formOpen && error !== undefined && _jsx("p", { className: css.error, role: "alert", children: error })] }));
@@ -226,8 +227,14 @@ function ChannelEditorDialog({ channel, members, joinedIds, updateChannel, joinC
226
227
  return (_jsx(Modal, { open: true, onClose: onClose, title: t('editChannel'), description: `# ${channel.name}`, 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-channel-edit-form", variant: "primary", disabled: saving || !dirty || name.trim() === '', children: saving ? t('editSaving') : t('editSave') })] }), children: _jsxs("form", { id: "team-channel-edit-form", className: createCss.form, onSubmit: event => { void submit(event); }, children: [_jsxs("label", { className: createCss.field, children: [_jsx("span", { children: t('channelName') }), _jsx(Input, { className: createCss.input, value: name, onChange: event => { setName(event.target.value); pendingRequest.current = undefined; }, disabled: saving, autoFocus: true })] }), _jsxs("label", { className: createCss.field, children: [_jsxs("span", { children: [t('channelDescription'), t('optionalSuffix')] }), _jsx(Input, { className: createCss.input, value: description, placeholder: t('agentDescriptionPlaceholder'), onChange: event => { setDescription(event.target.value); pendingRequest.current = undefined; }, disabled: saving })] }), _jsxs("fieldset", { className: createCss.memberPicker, disabled: saving, children: [_jsx("legend", { children: t('channelMembersSection') }), members.map(status => {
227
228
  const joined = joinedIds.has(status.member.memberId);
228
229
  const rowPending = membership.pending.has(status.member.memberId);
229
- const disabled = rowPending || (!joined && status.presence === 'unavailable');
230
+ // Same membership law as the Channel page roster: joining needs an
231
+ // active Member, leaving only needs the fact.
232
+ const disabled = rowPending || (!joined && status.availability !== 'active');
230
233
  const rowError = membership.errors.get(status.member.memberId);
231
- return _jsxs("div", { className: css.editMemberRow, children: [_jsx(TeamPresenceDot, { status: status, t: t }), _jsxs("span", { className: css.editMemberCopy, children: [_jsxs("strong", { children: ["@", status.member.handle] }), _jsx("small", { children: status.member.description })] }), _jsx(Button, { size: "sm", variant: "outline", disabled: disabled, onClick: () => { void membership.change({ workspaceId: channel.workspaceId, channelRef: channel.channelRef, memberId: status.member.memberId, joined }); }, children: rowPending ? t('membershipUpdating') : joined ? t('removeFromChannel') : t('addToChannel') }), rowError !== undefined && _jsx("p", { className: css.rowError, role: "alert", children: rowError })] }, status.member.memberId);
234
+ return _jsx(TeamMemberRow, { status: status, action: {
235
+ label: rowPending ? t('membershipUpdating') : joined ? t('removeFromChannel') : t('addToChannel'),
236
+ disabled,
237
+ onSelect: () => { void membership.change({ workspaceId: channel.workspaceId, channelRef: channel.channelRef, memberId: status.member.memberId, joined }); },
238
+ }, ...(rowError === undefined ? {} : { error: rowError }), t: t }, status.member.memberId);
232
239
  })] }), error !== undefined && _jsx("p", { className: createCss.error, role: "alert", children: error })] }) }));
233
240
  }
@@ -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;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAqE/D,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,EAAE,EAAE;IAClM,QAAQ,CAAC,OAAO,EAAE,SAAS,2BAA2B,EAAE,CAAA;IACxD,oGAAoG;IACpG,QAAQ,CAAC,iBAAiB,CAAC,EAAE,WAAW,CAAC,iBAAiB,CAAC,CAAA;IAC3D;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAA;IAC/B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IAC5B,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,+BAyTA"}
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;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAqD/D,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,EAAE,EAAE;IAClM,QAAQ,CAAC,OAAO,EAAE,SAAS,2BAA2B,EAAE,CAAA;IACxD,oGAAoG;IACpG,QAAQ,CAAC,iBAAiB,CAAC,EAAE,WAAW,CAAC,iBAAiB,CAAC,CAAA;IAC3D;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAA;IAC/B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IAC5B,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,+BAiUA"}
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore } from 'react';
3
3
  import { IconChecklistOutline14, IconPaperclipOutline16, IconSendOutline16, Tooltip, useAnchoredMaxHeight, useDismissOnOutsidePointer } from '@deepseek-ai/dsh-client-ui-primitives';
4
4
  import { TeamPresenceDot } from "./TeamPresenceDot.js";
5
+ import { allMentionMembers, containsAllMention, containsMention, mentionedMemberIds } from "./team-formatters.js";
5
6
  import css from './composer.module.css';
6
7
  import { formatByteSize } from "./attachment-preview.js";
7
8
  function findMention(draft, caret) {
@@ -18,12 +19,6 @@ function findMention(draft, caret) {
18
19
  return undefined;
19
20
  return { start: at, end: caret, query: beforeCaret.slice(at + 1) };
20
21
  }
21
- function escapeRegExp(value) {
22
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
23
- }
24
- function containsMention(draft, handle) {
25
- return new RegExp(`(?:^|[^\\p{L}\\p{N}_])@${escapeRegExp(handle)}(?=$|[^\\p{L}\\p{N}_])`, 'u').test(draft);
26
- }
27
22
  function mentionCandidates(members, query) {
28
23
  const normalized = query.toLocaleLowerCase();
29
24
  return members.filter(status => status.presence !== 'unavailable'
@@ -37,13 +32,6 @@ function rankMentionCandidates(candidates, followers) {
37
32
  return candidates;
38
33
  return [...candidates].sort((left, right) => Number(followers.has(right.member.memberId)) - Number(followers.has(left.member.memberId)));
39
34
  }
40
- /** Every member a manual handle pick could reach: the @all expansion snapshot. */
41
- function allMentionMembers(members) {
42
- return members.filter(status => status.presence !== 'unavailable' && status.member.state !== 'inactive' && status.member.state !== 'archived');
43
- }
44
- function containsAllMention(draft) {
45
- return /(?:^|[^\p{L}\p{N}_])@all(?=$|[^\p{L}\p{N}_])/u.test(draft);
46
- }
47
35
  /** One object URL per draft file; revoked when the draft is removed. */
48
36
  const draftPreviewUrls = new WeakMap();
49
37
  function draftPreviewUrl(file) {
@@ -121,15 +109,17 @@ export function TeamComposer({ members, followerMemberIds, drafts, draftKey, pen
121
109
  return;
122
110
  inputRef.current?.focus({ preventScroll: true });
123
111
  }, [confirmation, pending]);
112
+ // Handle lookup for both directions of the same judgement: whether a picked
113
+ // recipient is still spelled in the text, and which Members the text names.
114
+ const memberHandles = new Map(members.map(status => [status.member.memberId, status.member.handle]));
124
115
  const pruneRecipients = (nextDraft) => {
125
116
  // An @all marker stands for its expansion snapshot: the member handles it
126
117
  // stands for are not in the text, so text-based pruning must stand down.
127
118
  if (containsAllMention(nextDraft))
128
119
  return;
129
- const knownMembers = new Map(members.map(status => [status.member.memberId, status.member]));
130
120
  const next = new Set([...recipients].filter(memberId => {
131
- const member = knownMembers.get(memberId);
132
- return member !== undefined && containsMention(nextDraft, member.handle);
121
+ const handle = memberHandles.get(memberId);
122
+ return handle !== undefined && containsMention(nextDraft, handle);
133
123
  }));
134
124
  if (next.size !== recipients.size)
135
125
  drafts.writeRecipients(draftKey, next);
@@ -143,6 +133,10 @@ export function TeamComposer({ members, followerMemberIds, drafts, draftKey, pen
143
133
  return;
144
134
  pruneRecipients(draft);
145
135
  }, [draft, recipients, members]);
136
+ // The notify row reports what the Host will resolve from this draft, not just
137
+ // what the mention menu picked: an authored `@Handle` delivers exactly like a
138
+ // pick, and `@all` stands for the menu's expansion.
139
+ const notifiedIds = [...new Set([...recipients, ...mentionedMemberIds(draft, members)])].sort();
146
140
  const updateMention = (nextDraft, caret) => {
147
141
  const match = findMention(nextDraft, caret);
148
142
  setMention(match);
@@ -252,7 +246,7 @@ export function TeamComposer({ members, followerMemberIds, drafts, draftKey, pen
252
246
  return option.kind === 'all'
253
247
  ? _jsxs("button", { id: optionId, type: "button", role: "option", "aria-selected": selected, className: css.mentionOption, ref: selected ? activeOptionRef : undefined, onMouseDown: event => { event.preventDefault(); }, onClick: () => { selectOption(option); }, children: [_jsx("span", { className: css.mentionAllDot, "aria-hidden": "true" }), _jsx("span", { className: css.mentionName, children: "@all" }), _jsx("span", { className: css.mentionDescription, children: t('mentionAll', { count: allCount }) })] }, "all")
254
248
  : _jsxs("button", { id: optionId, type: "button", role: "option", "aria-selected": selected, className: css.mentionOption, ref: selected ? activeOptionRef : undefined, onMouseDown: event => { event.preventDefault(); }, onClick: () => { selectOption(option); }, children: [_jsx(TeamPresenceDot, { status: option.status, t: t }), _jsxs("span", { className: css.mentionName, children: ["@", option.status.member.handle] }), _jsx("span", { className: css.mentionDescription, children: option.status.member.description })] }, option.status.member.memberId);
255
- }) }), _jsx("textarea", { ref: inputRef, "aria-label": t('messageDraft'), "aria-autocomplete": "list", "aria-controls": menuOpen ? listId : undefined, "aria-activedescendant": menuOpen && activeOption !== undefined ? activeOption.kind === 'all' ? `${listId}-all` : `${listId}-${activeOption.status.member.memberId}` : undefined, "aria-expanded": menuOpen, value: draft, readOnly: pending, placeholder: placeholder ?? t('messagePlaceholder'), rows: 1, onChange: onChange, onPaste: onPaste, onKeyDown: onKeyDown, onSelect: event => { updateMention(event.currentTarget.value, event.currentTarget.selectionStart ?? event.currentTarget.value.length); }, onCompositionStart: () => { composingRef.current = true; }, onCompositionEnd: () => { setTimeout(() => { composingRef.current = false; }, 10); } })] }), recipients.size > 0 && _jsx("p", { className: css.notifyRow, "data-team-notify": true, children: t('composerNotify', { ids: [...recipients].sort().map(memberId => `@${members.find(candidate => candidate.member.memberId === memberId)?.member.handle ?? memberId}`).join(', ') }) }), onFilesChange !== undefined && pendingFiles !== undefined && pendingFiles.length > 0 && (_jsx("ul", { className: css.fileChips, "aria-label": t('attachFiles'), children: pendingFiles.map((file, index) => {
249
+ }) }), _jsx("textarea", { ref: inputRef, "aria-label": t('messageDraft'), "aria-autocomplete": "list", "aria-controls": menuOpen ? listId : undefined, "aria-activedescendant": menuOpen && activeOption !== undefined ? activeOption.kind === 'all' ? `${listId}-all` : `${listId}-${activeOption.status.member.memberId}` : undefined, "aria-expanded": menuOpen, value: draft, readOnly: pending, placeholder: placeholder ?? t('messagePlaceholder'), rows: 1, onChange: onChange, onPaste: onPaste, onKeyDown: onKeyDown, onSelect: event => { updateMention(event.currentTarget.value, event.currentTarget.selectionStart ?? event.currentTarget.value.length); }, onCompositionStart: () => { composingRef.current = true; }, onCompositionEnd: () => { setTimeout(() => { composingRef.current = false; }, 10); } })] }), notifiedIds.length > 0 && _jsx("p", { className: css.notifyRow, "data-team-notify": true, children: t('composerNotify', { ids: notifiedIds.map(memberId => `@${memberHandles.get(memberId) ?? memberId}`).join(', ') }) }), onFilesChange !== undefined && pendingFiles !== undefined && pendingFiles.length > 0 && (_jsx("ul", { className: css.fileChips, "aria-label": t('attachFiles'), children: pendingFiles.map((file, index) => {
256
250
  const previewUrl = draftPreviewUrl(file);
257
251
  return _jsxs("li", { className: `${css.fileChip} ${previewUrl !== undefined ? css.imageChip : ''}`, children: [previewUrl !== undefined && _jsx("img", { src: previewUrl, alt: "", className: css.imageChipPreview }), _jsxs("span", { className: css.fileChipName, title: file.name, children: [file.name, _jsx("span", { className: css.fileChipSize, children: formatByteSize(file.size) })] }), _jsx("button", { type: "button", className: css.fileChipRemove, "aria-label": t('removeFile', { name: file.name }), disabled: pending, onClick: () => {
258
252
  const url = draftPreviewUrls.get(file);
@@ -18,7 +18,7 @@ export function TeamConversation({ t, useWorkspaces, navigation, drafts, putAtta
18
18
  return _jsx(TeamThreadPage, { workspaceId: current.workspaceId, putAttachment: putAttachment, threadRef: navigationState.threadRef, backToWorkspace: backToWorkspace, selectChannel: selectChannel, selectThread: selectThread, resolveTaskRefs: resolveTaskRefs, ...(navigationState.channelRef === undefined ? {} : { channelRef: navigationState.channelRef }), ...(navigationState.taskRef === undefined ? {} : { taskRef: navigationState.taskRef }), ...(navigationState.taskNumber === undefined ? {} : { taskNumber: navigationState.taskNumber }), drafts: drafts, getAttachment: getAttachment, readThread: readThread, loadChannels: loadChannels, loadThreadHistory: loadThreadHistory, threadObservations: threadObservations, subscribeChanges: subscribeChanges, loadMembers: loadMembers, reply: reply, changeTask: changeTask, promoteThread: promoteThread, t: t }, navigationState.threadRef);
19
19
  }
20
20
  if (current !== undefined && navigationState.channelRef !== undefined) {
21
- return _jsx(TeamChannelPage, { workspaceId: current.workspaceId, channelRef: navigationState.channelRef, drafts: drafts, putAttachment: putAttachment, getAttachment: getAttachment, loadChannels: loadChannels, subscribeChanges: subscribeChanges, loadMembers: loadMembers, sendMessage: sendMessage, joinChannel: joinChannel, removeChannelMember: removeChannelMember, selectThread: selectThread, selectChannel: selectChannel, backToChannels: backToChannels, resolveTaskRefs: resolveTaskRefs, t: t }, navigationState.channelRef);
21
+ return _jsx(TeamChannelPage, { workspaceId: current.workspaceId, channelRef: navigationState.channelRef, drafts: drafts, putAttachment: putAttachment, getAttachment: getAttachment, loadChannels: loadChannels, subscribeChanges: subscribeChanges, loadMembers: loadMembers, loadInbox: loadInbox, sendMessage: sendMessage, joinChannel: joinChannel, removeChannelMember: removeChannelMember, selectThread: selectThread, selectChannel: selectChannel, backToChannels: backToChannels, resolveTaskRefs: resolveTaskRefs, t: t }, navigationState.channelRef);
22
22
  }
23
23
  const welcome = current === undefined
24
24
  ? { eyebrow: t('teamMode'), title: t('team'), body: t('empty') }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The one count capsule. The Human Inbox entry, the Channel feed's Thread
3
+ * entry, and the Inbox queue row all answer the same question — how much is
4
+ * waiting here — so they wear the same box rather than one hand-written copy
5
+ * of the same declarations per surface. Three copies is how the feed's digit
6
+ * ended up on a different line box from the other two.
7
+ *
8
+ * Zero is the absence of a count rather than a capsule reading zero, which is
9
+ * the rule every caller wants and therefore the component's own.
10
+ */
11
+ export declare function TeamCountBadge({ count, tone, label, className }: {
12
+ readonly count: number;
13
+ /** `hairline` is unread that merely arrived; the solid fill is unread that names this reader. */
14
+ readonly tone?: 'solid' | 'hairline' | undefined;
15
+ /** The accessible name while the count is the only thing saying it; omit it when the surrounding control already carries the number. */
16
+ readonly label?: string | undefined;
17
+ /** Placement belongs to the surface hanging the capsule: the narrow rail pins it to the icon's corner. */
18
+ readonly className?: string | undefined;
19
+ }): import("react").JSX.Element | null;
20
+ //# sourceMappingURL=TeamCountBadge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TeamCountBadge.d.ts","sourceRoot":"","sources":["../../../src/client/TeamCountBadge.tsx"],"names":[],"mappings":"AAKA;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,EAAE,KAAK,EAAE,IAAc,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;IAC1E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,iGAAiG;IACjG,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAAA;IAChD,wIAAwI;IACxI,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,0GAA0G;IAC1G,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACxC,sCASA"}
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import css from './countBadge.module.css';
3
+ /** Every count the Human reads is capped at this, so one wide number never widens the capsule. */
4
+ const COUNT_CAP = 99;
5
+ /**
6
+ * The one count capsule. The Human Inbox entry, the Channel feed's Thread
7
+ * entry, and the Inbox queue row all answer the same question — how much is
8
+ * waiting here — so they wear the same box rather than one hand-written copy
9
+ * of the same declarations per surface. Three copies is how the feed's digit
10
+ * ended up on a different line box from the other two.
11
+ *
12
+ * Zero is the absence of a count rather than a capsule reading zero, which is
13
+ * the rule every caller wants and therefore the component's own.
14
+ */
15
+ export function TeamCountBadge({ count, tone = 'solid', label, className }) {
16
+ if (count <= 0)
17
+ return null;
18
+ const text = count > COUNT_CAP ? `${COUNT_CAP}+` : String(count);
19
+ const classes = `${css.badge}${tone === 'hairline' ? ` ${css.hairline}` : ''}${className === undefined ? '' : ` ${className}`}`;
20
+ // Tests and the browser journey read the capsule by this attribute rather
21
+ // than by a CSS-module hash, which changes whenever a rule is renamed.
22
+ return label === undefined
23
+ ? _jsx("span", { className: classes, "data-team-count-badge": tone, "aria-hidden": "true", children: text })
24
+ : _jsx("span", { className: classes, "data-team-count-badge": tone, role: "img", "aria-label": label, title: label, children: text });
25
+ }
@@ -9,12 +9,16 @@ interface TeamInboxPageProps {
9
9
  readonly t: TeamConversationProps['t'];
10
10
  }
11
11
  /**
12
- * The Human 「提到我」 queue: one direct-only Inbox call per visible Workspace,
13
- * merged into a single recency-ordered list newest mention first across every
14
- * Workspace, since a queue is read by recency rather than by Workspace.
12
+ * The Human Inbox: one Inbox call per visible Workspace, rendering the Host's
13
+ * two slices the unread queue (「需要我」, mentions counted inside it rather
14
+ * than alone) and the 「最近活跃」 tail of Threads the reader took part in.
15
+ * Both merge across every Workspace into one list in the Host's own order,
16
+ * mentions first and then newest, rather than by Workspace.
15
17
  * Opening the page never acknowledges anything — only a durable Thread read
16
- * consumes a mention marker, so rows and the badge drop after the Thread is
17
- * opened through the existing auto-ack path.
18
+ * advances the watermark and consumes a mention marker, so rows and the badge
19
+ * drop after the Thread is opened through the existing auto-ack path. A Thread
20
+ * holding unread is only ever in the queue: the Host already excludes it from
21
+ * the tail, and this page never re-derives that judgement.
18
22
  */
19
23
  export declare function TeamInboxPage({ useWorkspaces, loadInbox, subscribeChanges, selectWorkspace, selectThread, t }: TeamInboxPageProps): import("react").JSX.Element;
20
24
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"TeamInboxPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamInboxPage.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAWvD,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAA;IACtD,mGAAmG;IACnG,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,CAAA;IACpE,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AAgBD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,EAAE,aAAa,EAAE,SAAS,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC,EAAE,EAAE,kBAAkB,+BAiFjI"}
1
+ {"version":3,"file":"TeamInboxPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamInboxPage.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAavD,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAA;IACtD,mGAAmG;IACnG,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,CAAA;IACpE,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AA0BD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAAE,aAAa,EAAE,SAAS,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC,EAAE,EAAE,kBAAkB,+BA0GjI"}
@@ -1,33 +1,49 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useRef, useState } from 'react';
3
3
  import { Button } from '@deepseek-ai/dsh-client-ui-primitives';
4
- import { formatAbsoluteTime, formatInboxTime } from "./team-formatters.js";
4
+ import { claimersLabel, formatAbsoluteTime, formatInboxTime } from "./team-formatters.js";
5
+ import { TeamAvatarStack } from "./TeamAvatarStack.js";
6
+ import { TeamCountBadge } from "./TeamCountBadge.js";
5
7
  import css from './conversation.module.css';
6
8
  import inboxCss from './inbox.module.css';
7
9
  /**
8
- * Queue order: newest mention first, one total order across Workspaces. Each
9
- * Workspace slice arrives in the Host's own order (that order is the Host's
10
- * truncation policy); the merged display order is decided here, where the
11
- * merge happens, and the ledger sequence breaks ties so the queue never
12
- * reshuffles two rows that share an instant.
10
+ * How many 「最近活跃」 rows the merged page may show. The Host bounds each
11
+ * Workspace's own slice; this is the single bound across every Workspace on
12
+ * screen, so the section stays the same size no matter how many are open — and
13
+ * it stays a way back into work rather than a second queue, which is why it is
14
+ * shorter than the queue the reader is actually being asked to work through.
15
+ */
16
+ const RECENT_ROWS_LIMIT = 5;
17
+ /**
18
+ * Queue order, one total order across Workspaces: the Host's own keys —
19
+ * mentions first, then the ledger sequence, then the Thread ref. Each Workspace
20
+ * slice already arrives in this order, and it is also the Host's truncation
21
+ * policy, so the merge re-applies it instead of inventing a second one: a row
22
+ * that survived the cut on mentions must not sink below a merely newer row
23
+ * after the merge. `newestSequence` is a global ledger position, so it stays
24
+ * comparable across Workspaces.
13
25
  */
14
26
  function compareInboxRows(left, right) {
15
- const leftAt = Date.parse(left.item.newestOccurredAt);
16
- const rightAt = Date.parse(right.item.newestOccurredAt);
17
- const byTime = (Number.isNaN(rightAt) ? 0 : rightAt) - (Number.isNaN(leftAt) ? 0 : leftAt);
18
- return byTime !== 0 ? byTime : right.item.newestSequence - left.item.newestSequence;
27
+ return right.item.directCount - left.item.directCount
28
+ || right.item.newestSequence - left.item.newestSequence
29
+ || left.item.thread.threadRef.localeCompare(right.item.thread.threadRef);
19
30
  }
20
31
  /**
21
- * The Human 「提到我」 queue: one direct-only Inbox call per visible Workspace,
22
- * merged into a single recency-ordered list newest mention first across every
23
- * Workspace, since a queue is read by recency rather than by Workspace.
32
+ * The Human Inbox: one Inbox call per visible Workspace, rendering the Host's
33
+ * two slices the unread queue (「需要我」, mentions counted inside it rather
34
+ * than alone) and the 「最近活跃」 tail of Threads the reader took part in.
35
+ * Both merge across every Workspace into one list in the Host's own order,
36
+ * mentions first and then newest, rather than by Workspace.
24
37
  * Opening the page never acknowledges anything — only a durable Thread read
25
- * consumes a mention marker, so rows and the badge drop after the Thread is
26
- * opened through the existing auto-ack path.
38
+ * advances the watermark and consumes a mention marker, so rows and the badge
39
+ * drop after the Thread is opened through the existing auto-ack path. A Thread
40
+ * holding unread is only ever in the queue: the Host already excludes it from
41
+ * the tail, and this page never re-derives that judgement.
27
42
  */
28
43
  export function TeamInboxPage({ useWorkspaces, loadInbox, subscribeChanges, selectWorkspace, selectThread, t }) {
29
44
  const workspaces = useWorkspaces(state => state.items);
30
45
  const [rows, setRows] = useState();
46
+ const [recentRows, setRecentRows] = useState([]);
31
47
  const [loading, setLoading] = useState(true);
32
48
  const [error, setError] = useState();
33
49
  // Only the first refresh owns the loading surface; later wakes refresh the
@@ -37,15 +53,19 @@ export function TeamInboxPage({ useWorkspaces, loadInbox, subscribeChanges, sele
37
53
  if (!loadedRef.current)
38
54
  setLoading(true);
39
55
  const results = await Promise.all(workspaces.map(async (workspace) => {
40
- const result = await loadInbox({ workspaceId: workspace.workspaceId, directOnly: true, limit: 100 });
56
+ const result = await loadInbox({ workspaceId: workspace.workspaceId, limit: 100 });
41
57
  return result.ok
42
- ? { ok: true, workspaceId: workspace.workspaceId, workspaceTitle: workspace.title, items: result.value.items }
58
+ ? { ok: true, workspaceId: workspace.workspaceId, workspaceTitle: workspace.title, items: result.value.items, recent: result.value.recent }
43
59
  : { ok: false, message: result.error.message };
44
60
  }));
45
61
  const failure = results.find(result => !result.ok);
46
- setRows(results.flatMap(result => result.ok
47
- ? result.items.map(item => ({ workspaceId: result.workspaceId, workspaceTitle: result.workspaceTitle, item }))
48
- : []).sort(compareInboxRows));
62
+ const asRows = (items, workspaceId, workspaceTitle) => items.map(item => ({ workspaceId, workspaceTitle, item }));
63
+ setRows(results.flatMap(result => result.ok ? asRows(result.items, result.workspaceId, result.workspaceTitle) : []).sort(compareInboxRows));
64
+ // The tail is one global bound rather than one per Workspace: the reader was
65
+ // promised five Threads to step back into, and every Workspace's slice is
66
+ // already capped on its own, so the merged list is trimmed here.
67
+ setRecentRows(results.flatMap(result => result.ok ? asRows(result.recent, result.workspaceId, result.workspaceTitle) : [])
68
+ .sort(compareInboxRows).slice(0, RECENT_ROWS_LIMIT));
49
69
  setError(failure?.ok === false ? failure.message : undefined);
50
70
  loadedRef.current = true;
51
71
  setLoading(false);
@@ -65,7 +85,56 @@ export function TeamInboxPage({ useWorkspaces, loadInbox, subscribeChanges, sele
65
85
  // The page rides the shared conversation seat: the same header band, 880px
66
86
  // reading column, responsive gutters, and scrollbar gutter as Channel and
67
87
  // Thread, so switching surfaces does not shift the content column.
68
- return _jsxs("main", { className: css.surface, "data-team-inbox": true, children: [_jsx("div", { className: css.surfaceHeader, children: _jsx("header", { className: css.headerRow, children: _jsxs("div", { className: css.headerCopy, children: [_jsx("h1", { children: t('mentionsOfMe') }), rows !== undefined && rows.length > 0 && _jsx("p", { className: inboxCss.headerMeta, children: t('inboxHeaderMeta', { threads: rows.length, mentions: rows.reduce((sum, row) => sum + row.item.directCount, 0) }) })] }) }) }), _jsx("div", { className: css.timeline, children: _jsxs("div", { className: css.timelineContent, children: [loading && rows === undefined && error === undefined && _jsx("div", { className: css.emptySurface, children: _jsxs("p", { className: css.loadingState, children: [_jsx("span", { className: css.loadingMark, "aria-hidden": "true" }), t('loadingInbox')] }) }), !loading && rows === undefined && error !== undefined && _jsxs("div", { className: css.errorState, role: "alert", children: [_jsx("span", { children: error }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => { void refresh(); }, children: t('retry') })] }), rows !== undefined && (rows.length === 0
88
+ const totalUnread = rows?.reduce((sum, row) => sum + row.item.unreadCount, 0) ?? 0;
89
+ const totalMentions = rows?.reduce((sum, row) => sum + row.item.directCount, 0) ?? 0;
90
+ // A row names its Workspace only while the rows on screen span more than one.
91
+ // With a single Workspace in the list the segment is a constant printed down
92
+ // every row, which spends the row's most readable position on something that
93
+ // never varies; the moment a second Workspace reaches the list it comes back,
94
+ // because two rows then have to be tellable apart. This reads the rows rather
95
+ // than the open Workspaces: a Workspace holding nothing to show here is not a
96
+ // reason to keep printing the name of the one that is.
97
+ const shownWorkspaces = new Set();
98
+ for (const row of rows ?? [])
99
+ shownWorkspaces.add(row.workspaceTitle);
100
+ for (const row of recentRows)
101
+ shownWorkspaces.add(row.workspaceTitle);
102
+ const showWorkspace = shownWorkspaces.size > 1;
103
+ return _jsxs("main", { className: css.surface, "data-team-inbox": true, children: [_jsx("div", { className: css.surfaceHeader, children: _jsx("header", { className: css.headerRow, children: _jsxs("div", { className: css.headerCopy, children: [_jsx("h1", { children: t('inboxTitle') }), rows !== undefined && rows.length > 0 && _jsxs("p", { className: inboxCss.headerMeta, children: [_jsx("span", { children: t('inboxHeaderThreads', { count: rows.length }) }), _jsx("span", { className: inboxCss.headerUnread, children: t('inboxHeaderUnread', { count: totalUnread }) }), totalMentions > 0 && _jsx("span", { children: t('inboxHeaderMentions', { count: totalMentions }) })] })] }) }) }), _jsx("div", { className: css.timeline, children: _jsxs("div", { className: css.timelineContent, children: [loading && rows === undefined && error === undefined && _jsx("div", { className: css.emptySurface, children: _jsxs("p", { className: css.loadingState, children: [_jsx("span", { className: css.loadingMark, "aria-hidden": "true" }), t('loadingInbox')] }) }), !loading && rows === undefined && error !== undefined && _jsxs("div", { className: css.errorState, role: "alert", children: [_jsx("span", { children: error }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => { void refresh(); }, children: t('retry') })] }), rows !== undefined && (rows.length === 0 && recentRows.length === 0
69
104
  ? _jsx("div", { className: css.emptySurface, children: _jsxs("div", { className: css.emptyState, children: [_jsx("strong", { children: t('inboxEmptyTitle') }), _jsx("span", { children: t('inboxEmptyHint') })] }) })
70
- : _jsx("div", { className: inboxCss.list, children: rows.map(row => (_jsxs("button", { type: "button", className: inboxCss.row, onClick: () => { open(row); }, children: [_jsxs("span", { className: inboxCss.rowCrumb, children: [row.workspaceTitle, " / ", _jsxs("span", { className: inboxCss.rowChannel, children: ["#", row.item.channelName] }), row.item.taskNumber !== undefined && _jsx("span", { className: inboxCss.rowTask, children: t('taskLabel', { number: row.item.taskNumber }) })] }), _jsx("span", { className: inboxCss.rowPreview, children: row.item.previewText }), _jsx("time", { className: inboxCss.rowTime, dateTime: row.item.newestOccurredAt, title: formatAbsoluteTime(row.item.newestOccurredAt), children: formatInboxTime(row.item.newestOccurredAt, t) })] }, `${row.workspaceId} ${row.item.thread.threadRef}`))) })), rows !== undefined && error !== undefined && _jsx("p", { className: css.error, role: "alert", children: error })] }) })] });
105
+ : _jsxs(_Fragment, { children: [rows.length > 0 && _jsxs("section", { className: inboxCss.section, children: [_jsxs("h2", { className: inboxCss.sectionTitle, children: [t('inboxSectionNeedsMe'), _jsx("span", { className: inboxCss.sectionCount, children: rows.length })] }), _jsx("div", { className: inboxCss.list, children: rows.map(row => _jsx(InboxQueueRow, { row: row, t: t, showWorkspace: showWorkspace, onOpen: () => { open(row); } }, `${row.workspaceId} ${row.item.thread.threadRef}`)) })] }), recentRows.length > 0 && _jsxs("section", { className: inboxCss.section, children: [_jsxs("h2", { className: inboxCss.sectionTitle, children: [t('inboxSectionRecent'), _jsx("span", { className: inboxCss.sectionCount, children: recentRows.length })] }), _jsx("div", { className: inboxCss.list, children: recentRows.map(row => _jsx(InboxQueueRow, { row: row, t: t, showWorkspace: showWorkspace, onOpen: () => { open(row); } }, `${row.workspaceId} ${row.item.thread.threadRef}`)) })] })] })), rows !== undefined && error !== undefined && _jsx("p", { className: css.error, role: "alert", children: error })] }) })] });
106
+ }
107
+ /**
108
+ * One queue row, shaped like the shipped two-line result row: who is on this
109
+ * Thread leads in the gutter, the identity line answers which Thread this is,
110
+ * how much is waiting, and when it last moved, and the gist sits under it on the
111
+ * same column as evidence for that identity rather than as the row's subject.
112
+ *
113
+ * The gutter carries the one thing every row has — who is on the work, or who
114
+ * moved a Thread nobody has claimed — so a Thread that merely arrived and one
115
+ * that named the reader open on the same edge instead of the quieter one opening
116
+ * on a slot reserved for a count it does not hold. It is the grammar the Channel
117
+ * feed's Thread entry row already speaks, where the people on the work lead the
118
+ * row.
119
+ *
120
+ * Before the queue admitted every unread Thread, each row was a mention and the
121
+ * rows were interchangeable; now that named and ambient unread share one list,
122
+ * the row has to carry that difference itself. The count closes the identity
123
+ * line and only its ink changes — the shared capsule fill for a row that names
124
+ * the reader, a hairline for one that merely moved. The two numbers behind that
125
+ * ink (unread, mentions) reach assistive tech through the capsule's own name,
126
+ * because a second visible count beside the first would cost the row the one
127
+ * thing it needs to stay scannable.
128
+ */
129
+ function InboxQueueRow({ row, t, showWorkspace, onOpen }) {
130
+ const { item } = row;
131
+ const actor = item.newestActor;
132
+ const owners = item.claimOwners;
133
+ const named = item.directCount > 0;
134
+ const countLabel = named
135
+ ? t('inboxRowUnreadMentions', { count: item.unreadCount, mentions: item.directCount })
136
+ : t('inboxRowUnread', { count: item.unreadCount });
137
+ return _jsxs("button", { type: "button", className: inboxCss.row, "data-named": named || undefined, onClick: onOpen, children: [_jsx("span", { className: inboxCss.rowActor, children: owners.length > 0
138
+ ? _jsx(TeamAvatarStack, { owners: owners, label: claimersLabel(owners, t) })
139
+ : _jsx(TeamAvatarStack, { owners: [actor], label: t('inboxRowActor', { name: `@${actor.name}` }) }) }), _jsxs("span", { className: inboxCss.rowLine, children: [_jsxs("span", { className: inboxCss.rowCrumb, children: [showWorkspace && _jsx("span", { className: inboxCss.rowWorkspace, children: row.workspaceTitle }), showWorkspace && ' / ', _jsxs("span", { className: inboxCss.rowChannel, children: ["#", item.channelName] }), ' ', item.taskNumber !== undefined && _jsx("span", { className: inboxCss.rowTask, children: t('taskLabel', { number: item.taskNumber }) })] }), _jsx(TeamCountBadge, { count: item.unreadCount, tone: named ? 'solid' : 'hairline', label: countLabel }), _jsx("time", { className: inboxCss.rowTime, dateTime: item.newestOccurredAt, title: formatAbsoluteTime(item.newestOccurredAt), children: formatInboxTime(item.newestOccurredAt, t) })] }), _jsx("span", { className: inboxCss.rowPreview, children: item.previewText })] });
71
140
  }
@@ -0,0 +1,43 @@
1
+ import type { AgentTeamClientMemberStatus } from '@wowyuarm/dsh-agent-team/types';
2
+ import type { TeamSidebarProps } from './slots.ts';
3
+ /** One membership action: what it says and which Member it acts on. */
4
+ export interface TeamMemberAction {
5
+ readonly label: string;
6
+ readonly onSelect: () => void;
7
+ readonly disabled?: boolean;
8
+ }
9
+ /**
10
+ * The one place a Member's identity is drawn: the presence-bearing avatar plus
11
+ * the handle over its description. Read-only rosters, the rosters with a
12
+ * membership action, and the sidebar Agent list all render this, so identity,
13
+ * tone and truncation cannot drift between surfaces that show the same person.
14
+ *
15
+ * A fragment, not a row: each surface owns its own row element, hit target and
16
+ * grid, and places this identity in that grid's first two tracks. The handle
17
+ * spelling is the surface's call — rosters address Members the way the
18
+ * composer does (`@handle`), the sidebar names them as the directory does.
19
+ */
20
+ export declare function TeamMemberIdentity({ status, name, className, t }: {
21
+ readonly status: AgentTeamClientMemberStatus;
22
+ /** Handle spelling for this surface; defaults to the mention form. */
23
+ readonly name?: string | undefined;
24
+ /** Surface-local copy hook (sidebar line heights, dialog density). */
25
+ readonly className?: string | undefined;
26
+ readonly t: TeamSidebarProps['t'];
27
+ }): import("react").JSX.Element;
28
+ /**
29
+ * The one roster row: identity, an optional membership action, and the row's
30
+ * own failure line. The action is the row's only chrome, so the eye lands on
31
+ * the handle first and on the action second. A read-only roster omits it and
32
+ * the trailing track collapses, handing its width back to the description.
33
+ */
34
+ export declare function TeamMemberRow({ status, action, error, className, t }: {
35
+ readonly status: AgentTeamClientMemberStatus;
36
+ readonly action?: TeamMemberAction | undefined;
37
+ /** Transport failure for this row's last mutation, announced in place. */
38
+ readonly error?: string | undefined;
39
+ /** Surface-local hook (dialog, sidebar, footer) for its own row rules. */
40
+ readonly className?: string | undefined;
41
+ readonly t: TeamSidebarProps['t'];
42
+ }): import("react").JSX.Element;
43
+ //# sourceMappingURL=TeamMemberRow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TeamMemberRow.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMemberRow.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAIlD,uEAAuE;AACvE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE;IACjE,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAA;IAC5C,sEAAsE;IACtE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,sEAAsE;IACtE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC,+BAQA;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE;IACrE,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAA;IAC5C,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAA;IAC9C,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC,+BAMA"}
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Button } from '@deepseek-ai/dsh-client-ui-primitives';
3
+ import { TeamMemberAvatar } from "./TeamMemberAvatar.js";
4
+ import css from './member-row.module.css';
5
+ /**
6
+ * The one place a Member's identity is drawn: the presence-bearing avatar plus
7
+ * the handle over its description. Read-only rosters, the rosters with a
8
+ * membership action, and the sidebar Agent list all render this, so identity,
9
+ * tone and truncation cannot drift between surfaces that show the same person.
10
+ *
11
+ * A fragment, not a row: each surface owns its own row element, hit target and
12
+ * grid, and places this identity in that grid's first two tracks. The handle
13
+ * spelling is the surface's call — rosters address Members the way the
14
+ * composer does (`@handle`), the sidebar names them as the directory does.
15
+ */
16
+ export function TeamMemberIdentity({ status, name, className, t }) {
17
+ return _jsxs(_Fragment, { children: [_jsx(TeamMemberAvatar, { status: status, t: t }), _jsxs("span", { className: className === undefined ? css.copy : `${css.copy} ${className}`, children: [_jsx("strong", { children: name ?? `@${status.member.handle.replace(/^@/, '')}` }), _jsx("small", { children: status.member.description })] })] });
18
+ }
19
+ /**
20
+ * The one roster row: identity, an optional membership action, and the row's
21
+ * own failure line. The action is the row's only chrome, so the eye lands on
22
+ * the handle first and on the action second. A read-only roster omits it and
23
+ * the trailing track collapses, handing its width back to the description.
24
+ */
25
+ export function TeamMemberRow({ status, action, error, className, t }) {
26
+ return _jsxs("div", { className: className === undefined ? css.row : `${css.row} ${className}`, "data-team-member-row": true, children: [_jsx(TeamMemberIdentity, { status: status, t: t }), action !== undefined && _jsx(Button, { size: "sm", variant: "outline", className: css.action, disabled: action.disabled === true, onClick: action.onSelect, children: action.label }), error !== undefined && _jsx("p", { className: css.error, role: "alert", children: error })] });
27
+ }
@@ -1,5 +1,5 @@
1
- import type { TeamFooterProps } from './slots.ts';
2
- type TeamMembersActionProps = Pick<TeamFooterProps, 'wide' | 'loadMemberGroups' | 't'>;
1
+ import type { TeamSettingsProps } from './slots.ts';
2
+ type TeamMembersActionProps = Pick<TeamSettingsProps, 'wide' | 'loadMemberGroups' | 't'>;
3
3
  export declare function TeamMembersAction({ wide, loadMemberGroups, t }: TeamMembersActionProps): import("react").JSX.Element;
4
4
  export {};
5
5
  //# sourceMappingURL=TeamMembersAction.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TeamMembersAction.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMembersAction.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAKjD,KAAK,sBAAsB,GAAG,IAAI,CAAC,eAAe,EAAE,MAAM,GAAG,kBAAkB,GAAG,GAAG,CAAC,CAAA;AAEtF,wBAAgB,iBAAiB,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,EAAE,EAAE,sBAAsB,+BAuDtF"}
1
+ {"version":3,"file":"TeamMembersAction.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMembersAction.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAKnD,KAAK,sBAAsB,GAAG,IAAI,CAAC,iBAAiB,EAAE,MAAM,GAAG,kBAAkB,GAAG,GAAG,CAAC,CAAA;AAExF,wBAAgB,iBAAiB,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,EAAE,EAAE,sBAAsB,+BAkDtF"}
@@ -1,7 +1,7 @@
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 { IconUserOutline16, Modal, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
4
- import { TeamPresenceDot } from "./TeamPresenceDot.js";
4
+ import { TeamMemberRow } from "./TeamMemberRow.js";
5
5
  import membersCss from './members.module.css';
6
6
  import css from './team.module.css';
7
7
  export function TeamMembersAction({ wide, loadMemberGroups, t }) {
@@ -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 => (_jsxs("div", { className: membersCss.member, children: [_jsx(TeamPresenceDot, { status: status, t: t }), _jsxs("span", { className: membersCss.copy, children: [_jsxs("strong", { children: ["@", status.member.handle] }), _jsx("small", { children: status.member.description })] })] }, 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(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 })] }) })] }));
32
32
  }
@@ -3,7 +3,7 @@ import type { TeamSidebarProps } from './slots.ts';
3
3
  import type { TeamStateDotState } from './TeamStateDot.tsx';
4
4
  export declare function presenceLabel(status: AgentTeamClientMemberStatus, t: TeamSidebarProps['t']): string;
5
5
  /** One line of human-readable diagnostic text: the reason, plus the refused artifact path when one was reported. */
6
- export declare function diagnosticText(status: AgentTeamClientMemberStatus): string;
6
+ export declare function diagnosticText(status: Pick<AgentTeamClientMemberStatus, 'diagnostic'>): string;
7
7
  /**
8
8
  * Whether the restart action can help an unavailable Member: it heals
9
9
  * transient and repairable failures, but not a transient rollover window
@@ -1 +1 @@
1
- {"version":3,"file":"TeamPresenceDot.d.ts","sourceRoot":"","sources":["../../../src/client/TeamPresenceDot.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAG3D,wBAAgB,aAAa,CAAC,MAAM,EAAE,2BAA2B,EAAE,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,MAAM,CAKnG;AAED,oHAAoH;AACpH,wBAAgB,cAAc,CAAC,MAAM,EAAE,2BAA2B,GAAG,MAAM,CAI1E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,2BAA2B,GAAG,OAAO,CAK3E;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,2BAA2B,CAAC,UAAU,CAAC,GAAG,iBAAiB,CAErG;AAED,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE;IAC7C,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAA;IAC5C,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC,+BASA"}
1
+ {"version":3,"file":"TeamPresenceDot.d.ts","sourceRoot":"","sources":["../../../src/client/TeamPresenceDot.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAG3D,wBAAgB,aAAa,CAAC,MAAM,EAAE,2BAA2B,EAAE,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,MAAM,CAKnG;AAED,oHAAoH;AACpH,wBAAgB,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,2BAA2B,EAAE,YAAY,CAAC,GAAG,MAAM,CAI9F;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,2BAA2B,GAAG,OAAO,CAK3E;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,2BAA2B,CAAC,UAAU,CAAC,GAAG,iBAAiB,CAErG;AAED,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE;IAC7C,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAA;IAC5C,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC,+BASA"}
@@ -1 +1 @@
1
- {"version":3,"file":"TeamThreadPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamThreadPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,mBAAmB,EAInB,gBAAgB,EAGhB,kBAAkB,EAEnB,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,aAAa,CAAA;AAe/D,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,mBAAmB,CAAA;IACzC,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAA;IACnC,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAA;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAA;IACxD,QAAQ,CAAC,iBAAiB,EAAE,qBAAqB,CAAC,mBAAmB,CAAC,CAAA;IACtE,QAAQ,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,oBAAoB,CAAC,CAAA;IACxE,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,KAAK,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAA;IAC9C,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAA;IACxD,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AA+CD,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,+BAmvBxD"}
1
+ {"version":3,"file":"TeamThreadPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamThreadPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,mBAAmB,EAInB,gBAAgB,EAGhB,kBAAkB,EAEnB,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,aAAa,CAAA;AAc/D,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,mBAAmB,CAAA;IACzC,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAA;IACnC,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAA;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAA;IACxD,QAAQ,CAAC,iBAAiB,EAAE,qBAAqB,CAAC,mBAAmB,CAAC,CAAA;IACtE,QAAQ,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,oBAAoB,CAAC,CAAA;IACxE,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,KAAK,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAA;IAC9C,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAA;IACxD,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AA+CD,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,+BA2uBxD"}