@wowyuarm/dsh-agent-team 0.1.1 → 0.1.3

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 (92) hide show
  1. package/README.md +1 -0
  2. package/README.zh.md +2 -0
  3. package/package.json +42 -25
  4. package/packages/agent-team/README.md +1 -1
  5. package/packages/agent-team/README.zh.md +1 -1
  6. package/packages/agent-team/lib/attachments.js +11 -12
  7. package/packages/agent-team/lib/auto-compaction.js +163 -0
  8. package/packages/agent-team/lib/index.js +262 -189
  9. package/packages/agent-team/lib/ledger.js +140 -109
  10. package/packages/agent-team/lib/recovery.js +30 -35
  11. package/packages/agent-team/lib/spec.js +10 -4
  12. package/packages/agent-team/lib/typert.host.js +68 -71
  13. package/packages/agent-team/lib/typert.remote-client.d.ts +3 -3
  14. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  15. package/packages/agent-team/lib/typert.remote-client.js +41 -56
  16. package/packages/agent-team/lib/types/attachments.d.ts +2 -2
  17. package/packages/agent-team/lib/types/attachments.d.ts.map +1 -1
  18. package/packages/agent-team/lib/types/auto-compaction.d.ts +38 -0
  19. package/packages/agent-team/lib/types/auto-compaction.d.ts.map +1 -0
  20. package/packages/agent-team/lib/types/index.d.ts +49 -24
  21. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  22. package/packages/agent-team/lib/types/ledger.d.ts +24 -11
  23. package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
  24. package/packages/agent-team/lib/types/recovery.d.ts +15 -16
  25. package/packages/agent-team/lib/types/recovery.d.ts.map +1 -1
  26. package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
  27. package/packages/agent-team/lib/types/types.d.ts +20 -12
  28. package/packages/agent-team/lib/types/types.d.ts.map +1 -1
  29. package/packages/agent-team/preset/team-member/agent.cordis.yml +8 -3
  30. package/packages/client-agent-team/README.md +3 -2
  31. package/packages/client-agent-team/README.zh.md +3 -2
  32. package/packages/client-agent-team/lib/client.js +1507 -525
  33. package/packages/client-agent-team/lib/client.js.map +1 -1
  34. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +1 -2
  35. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
  36. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +24 -182
  37. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts +3 -1
  38. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
  39. package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +27 -5
  40. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
  41. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +19 -4
  42. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
  43. package/packages/client-agent-team/lib/types/client/TeamComposer.js +22 -2
  44. package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts +1 -1
  45. package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts.map +1 -1
  46. package/packages/client-agent-team/lib/types/client/TeamConversation.js +3 -3
  47. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts +34 -0
  48. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts.map +1 -0
  49. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.js +169 -0
  50. package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.d.ts +17 -0
  51. package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.d.ts.map +1 -0
  52. package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.js +120 -0
  53. package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts +7 -2
  54. package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts.map +1 -1
  55. package/packages/client-agent-team/lib/types/client/TeamMessage.js +170 -18
  56. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts +4 -0
  57. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
  58. package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +70 -13
  59. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
  60. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
  61. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +2 -2
  62. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  63. package/packages/client-agent-team/lib/types/client/index.js +72 -2
  64. package/packages/client-agent-team/lib/types/client/locales.d.ts +8 -2
  65. package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
  66. package/packages/client-agent-team/lib/types/client/locales.js +8 -2
  67. package/packages/client-agent-team/lib/types/client/member-session-input.d.ts +22 -0
  68. package/packages/client-agent-team/lib/types/client/member-session-input.d.ts.map +1 -0
  69. package/packages/client-agent-team/lib/types/client/member-session-input.js +98 -0
  70. package/packages/client-agent-team/lib/types/client/requests.d.ts +16 -0
  71. package/packages/client-agent-team/lib/types/client/requests.d.ts.map +1 -0
  72. package/packages/client-agent-team/lib/types/client/requests.js +22 -0
  73. package/packages/client-agent-team/lib/types/client/sidebar-drag.d.ts +35 -0
  74. package/packages/client-agent-team/lib/types/client/sidebar-drag.d.ts.map +1 -0
  75. package/packages/client-agent-team/lib/types/client/sidebar-drag.js +70 -0
  76. package/packages/client-agent-team/lib/types/client/sidebar-order.d.ts +27 -0
  77. package/packages/client-agent-team/lib/types/client/sidebar-order.d.ts.map +1 -0
  78. package/packages/client-agent-team/lib/types/client/sidebar-order.js +170 -0
  79. package/packages/client-agent-team/lib/types/client/slots.d.ts +2 -2
  80. package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
  81. package/packages/client-agent-team/lib/types/client/task-refs.d.ts +25 -0
  82. package/packages/client-agent-team/lib/types/client/task-refs.d.ts.map +1 -0
  83. package/packages/client-agent-team/lib/types/client/task-refs.js +77 -0
  84. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +54 -1
  85. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
  86. package/packages/client-agent-team/lib/types/client/team-formatters.js +83 -2
  87. package/packages/client-agent-team/lib/types/client/team-membership.d.ts.map +1 -1
  88. package/packages/client-agent-team/lib/types/client/team-membership.js +2 -1
  89. package/packages/tool-agent-team/lib/index.js +4 -4
  90. package/packages/client-agent-team/lib/types/client/TeamInboxPanel.d.ts +0 -13
  91. package/packages/client-agent-team/lib/types/client/TeamInboxPanel.d.ts.map +0 -1
  92. package/packages/client-agent-team/lib/types/client/TeamInboxPanel.js +0 -90
@@ -35,6 +35,49 @@ export function memberHue(memberId) {
35
35
  hash = (hash * 31 + memberId.charCodeAt(index)) % 360;
36
36
  return hash;
37
37
  }
38
+ const BRANDED_REF_PATTERN = /\b(task|channel|thread):{1,2}[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi;
39
+ /**
40
+ * Canonical form of one matched ref: models occasionally double the colon or
41
+ * uppercase the UUID when citing a ref in prose, while Host lookups and
42
+ * navigation only accept the lowercase single-colon ref the ledger mints.
43
+ */
44
+ function canonicalBrandedRef(match) {
45
+ return match.replace('::', ':').toLowerCase();
46
+ }
47
+ /**
48
+ * Split a literal text run into plain and branded-ref segments. The pattern
49
+ * anchors on the fixed ref prefixes plus the UUID shape, so ordinary prose
50
+ * containing a colon never linkifies; a doubled colon from model output is
51
+ * tolerated. Segment refs are always canonical, so resolution and navigation
52
+ * work regardless of how the ref was spelled; text without any ref comes
53
+ * back as one untouched segment.
54
+ */
55
+ export function splitBrandedRefs(text) {
56
+ const segments = [];
57
+ let cursor = 0;
58
+ for (const match of text.matchAll(BRANDED_REF_PATTERN)) {
59
+ const start = match.index ?? 0;
60
+ if (start > cursor)
61
+ segments.push({ text: text.slice(cursor, start) });
62
+ segments.push({ text: match[0], ref: canonicalBrandedRef(match[0]) });
63
+ cursor = start + match[0].length;
64
+ }
65
+ if (cursor < text.length)
66
+ segments.push({ text: text.slice(cursor) });
67
+ return segments;
68
+ }
69
+ /**
70
+ * Whether one string's whole content is exactly one branded ref. A code span
71
+ * like this is the model styling a ref as an identifier, not publishing code,
72
+ * so the Markdown pass may linkify it; anything larger stays literal.
73
+ */
74
+ export function isSingleBrandedRef(text) {
75
+ const trimmed = text.trim();
76
+ if (trimmed === '')
77
+ return false;
78
+ const matches = [...trimmed.matchAll(BRANDED_REF_PATTERN)];
79
+ return matches.length === 1 && matches[0][0] === trimmed;
80
+ }
38
81
  function escapeRegExp(value) {
39
82
  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
40
83
  }
@@ -107,8 +150,11 @@ export function formatMessageTime(occurredAt, now = new Date()) {
107
150
  }
108
151
  export function formatActivity(activity, options) {
109
152
  const actor = options.actorName(activity.actor);
110
- if (activity.kind === 'accept')
111
- return options.t('activityAccepted', { actor });
153
+ if (activity.kind === 'accept') {
154
+ return activity.completedClaimRefs !== undefined && activity.completedClaimRefs.length > 0
155
+ ? options.t('activityAcceptedWithClaims', { actor, count: activity.completedClaimRefs.length })
156
+ : options.t('activityAccepted', { actor });
157
+ }
112
158
  if (activity.kind === 'close')
113
159
  return options.t('activityClosed', { actor });
114
160
  if (activity.kind === 'reopen')
@@ -130,3 +176,38 @@ export function formatActivity(activity, options) {
130
176
  export function stripAttachmentLines(body) {
131
177
  return body.replaceAll(/^\[attachment\] .*$(\n)?/gm, '').replace(/\n+$/, '');
132
178
  }
179
+ /**
180
+ * Decide how one Message body renders. Human input and plain-prose Agent
181
+ * bodies stay literal, with structured mention chips inline where possible;
182
+ * rich Agent Markdown keeps unmatched mentions and non-Task refs in the
183
+ * trailing fallback row while the post-render pass handles Task refs at their
184
+ * authored position. Surfaces without ref navigation render everything
185
+ * literally and keep the full fallback row.
186
+ */
187
+ export function planMessageBody(body, options) {
188
+ const stripped = stripAttachmentLines(body);
189
+ const displayBody = stripped === '' ? body : stripped;
190
+ const richAgentBody = !options.human && !isPlainTextBody(displayBody);
191
+ const inline = (options.human || isPlainTextBody(displayBody)) && options.mentionNames !== undefined && options.mentionNames.length > 0
192
+ ? splitMentionNames(displayBody, options.mentionNames)
193
+ : undefined;
194
+ const fallbackNames = inline !== undefined ? inline.unmatched
195
+ : richAgentBody && options.canOpenRefs && options.mentionNames !== undefined
196
+ ? splitMentionNames(displayBody, options.mentionNames).unmatched
197
+ : options.mentionNames ?? [];
198
+ const refs = splitBrandedRefs(displayBody).flatMap(segment => segment.ref === undefined ? [] : [segment.ref]);
199
+ const render = inline !== undefined ? 'inline'
200
+ : options.human || (options.canOpenRefs && !richAgentBody && refs.length > 0) ? 'literal'
201
+ : 'markdown';
202
+ return {
203
+ displayBody,
204
+ richAgentBody,
205
+ render,
206
+ ...(inline === undefined ? {} : { inline }),
207
+ fallbackNames,
208
+ fallbackRefs: richAgentBody && options.canOpenRefs ? refs.filter(ref => !ref.startsWith('task:')) : [],
209
+ taskRefs: options.canOpenRefs && !richAgentBody
210
+ ? refs.filter(ref => ref.startsWith('task:')).map(ref => ref)
211
+ : [],
212
+ };
213
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"team-membership.d.ts","sourceRoot":"","sources":["../../../src/client/team-membership.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,mBAAmB,EACnB,2BAA2B,EAC3B,0BAA0B,EAC1B,iBAAiB,EACjB,mCAAmC,EACnC,kCAAkC,EAEnC,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAEzE,0EAA0E;AAC1E,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAA;IACxC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAA;IACpC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CACzB;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,2BAA2B,KAAK,OAAO,CAAC,YAAY,CAAC,0BAA0B,CAAC,CAAC,CAAA;IACjH,QAAQ,CAAC,mBAAmB,EAAE,CAAC,OAAO,EAAE,mCAAmC,KAAK,OAAO,CAAC,YAAY,CAAC,kCAAkC,CAAC,CAAC,CAAA;CAC1I;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,0BAA0B,EACrC,QAAQ,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,MAAM,EACrD,WAAW,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GACrE;IACD,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACrC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC5C,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACpE,CA6BA"}
1
+ {"version":3,"file":"team-membership.d.ts","sourceRoot":"","sources":["../../../src/client/team-membership.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,mBAAmB,EACnB,2BAA2B,EAC3B,0BAA0B,EAC1B,iBAAiB,EACjB,mCAAmC,EACnC,kCAAkC,EAEnC,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAEzE,0EAA0E;AAC1E,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAA;IACxC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAA;IACpC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CACzB;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,2BAA2B,KAAK,OAAO,CAAC,YAAY,CAAC,0BAA0B,CAAC,CAAC,CAAA;IACjH,QAAQ,CAAC,mBAAmB,EAAE,CAAC,OAAO,EAAE,mCAAmC,KAAK,OAAO,CAAC,YAAY,CAAC,kCAAkC,CAAC,CAAC,CAAA;CAC1I;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,0BAA0B,EACrC,QAAQ,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,MAAM,EACrD,WAAW,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GACrE;IACD,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACrC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC5C,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACpE,CA6BA"}
@@ -1,4 +1,5 @@
1
1
  import { useRef, useState } from 'react';
2
+ import { mintRequestId } from "./requests.js";
2
3
  /**
3
4
  * Shared Channel membership mutation. One stable requestId per direction,
4
5
  * Member, and Channel survives transport failures until the Host commits it;
@@ -15,7 +16,7 @@ export function useChannelMembership(transport, rowKeyOf, onCommitted) {
15
16
  setPending(current => new Set(current).add(rowKey));
16
17
  setErrors(current => { const next = new Map(current); next.delete(rowKey); return next; });
17
18
  const key = `${membership.joined ? 'remove' : 'join'}:${membership.memberId}:${membership.channelRef}`;
18
- const requestId = requestIds.current.get(key) ?? crypto.randomUUID();
19
+ const requestId = requestIds.current.get(key) ?? mintRequestId();
19
20
  requestIds.current.set(key, requestId);
20
21
  const request = { requestId, workspaceId: membership.workspaceId, channelRef: membership.channelRef, memberId: membership.memberId };
21
22
  try {
@@ -131,12 +131,12 @@ function threadResult(kind, snapshot, attention, facts, extra = {}) {
131
131
  }
132
132
  const teamMessage = markAgentTeamPreset(defineTool({
133
133
  name: 'team_message',
134
- description: 'Create a top-level Task or reply to one existing Task Thread. Read the Thread first; replies require its current revision. A top-level start may mention related Agents directly; in replies, only a Human can invite an unfollowed Agent. Pass Member refs in mentions and spell their handles inside the body; only mentioned Members render as mention chips.',
134
+ description: 'Create a top-level Task or reply to one existing Task Thread. Read the Thread first; replies require its current revision (an internal concurrency token carried by baseRevision, never quoted in bodies). A top-level start may mention related Agents directly; in replies, only a Human can invite an unfollowed Agent. Pass Member refs in mentions and spell their handles inside the body; only mentioned Members render as mention chips.',
135
135
  parameters: {
136
136
  action: { type: 'string', required: true, enum: ['start', 'reply'] },
137
137
  channelRef: { type: 'string', description: "Full branded Channel ref exactly as returned by Team tools, including the 'channel:' prefix." },
138
138
  taskRef: { type: 'string', description: "Full branded Task ref exactly as returned by Team tools, including the 'task:' prefix." },
139
- body: { type: 'string', required: true }, baseRevision: { type: 'number', description: "Positive integer; use the current Thread revision as shown by the latest team_inbox or team_thread result for this Task." },
139
+ body: { type: 'string', required: true, description: "Markdown body. Cite Team refs exactly as returned, as bare text with one colon (e.g. task:0f0a…) — never a double colon, never inside backticks or quotes. Spell each mentioned Member's handle in the prose so the mention renders inline." }, baseRevision: { type: 'number', description: "Positive integer; use the current Thread revision as shown by the latest team_inbox or team_thread result for this Task. The revision is an internal concurrency token, not a citable fact." },
140
140
  mentions: { type: 'array', items: { type: 'string' }, description: 'Member refs to mention. Mentioned Agents receive the Message directly; write their handles in the body (any casing, optional @) so the mention renders inline.' },
141
141
  attachments: { type: 'array', items: { type: 'string' }, description: 'Absolute file paths to share, e.g. screenshots or generated artifacts; images render as thumbnails for recipients. The Host validates each path and copies the file into the attachment cache, and members also receive one cached path per attachment; if any path fails validation the whole send is rejected.' },
142
142
  },
@@ -192,11 +192,11 @@ function messageOutcome(result) {
192
192
  }
193
193
  const teamClaim = defineTool({
194
194
  name: 'team_claim',
195
- description: 'List or mutate your Direction Claims. Read the Thread first; every mutation uses the current Thread revision.',
195
+ description: 'List or mutate your Direction Claims. Read the Thread first; every mutation uses the current Thread revision. A Claim is your one-sentence direction statement on a Task — "the angle I am taking" — so others can spot collisions and track progress: Tasks define scope (owned by Humans), Claims declare the angle (owned by you). Good direction: "Unify the four form dialogs on shared field components before wiring submits." Bad direction: a multi-paragraph plan with step order, file lists, or acceptance criteria — those belong in Thread messages, not the Claim.',
196
196
  parameters: {
197
197
  action: { type: 'string', required: true, enum: ['list', 'claim', 'done', 'release'] },
198
198
  taskRef: { type: 'string', required: true, description: "Full branded Task ref exactly as returned by Team tools, including the 'task:' prefix." },
199
- baseRevision: { type: 'number', description: "Positive integer; use the current Thread revision as shown by the latest team_inbox or team_thread result for this Task." }, direction: { type: 'string' },
199
+ baseRevision: { type: 'number', description: "Positive integer; use the current Thread revision as shown by the latest team_inbox or team_thread result for this Task. The revision is an internal concurrency token, not a citable fact." }, direction: { type: 'string' },
200
200
  claimRef: { type: 'string', description: "Full branded Claim ref exactly as returned by team_claim, including the 'claim:' prefix." },
201
201
  },
202
202
  output: {
@@ -1,13 +0,0 @@
1
- import type { WorkspaceId } from '@deepseek-ai/dsh-client-runtime/client';
2
- import type { TeamConversationProps } from './slots.ts';
3
- interface TeamInboxPanelProps {
4
- readonly workspaceId: WorkspaceId;
5
- readonly loadInbox: TeamConversationProps['loadInbox'];
6
- readonly loadChannels: TeamConversationProps['loadChannels'];
7
- readonly loadChanges: TeamConversationProps['loadChanges'];
8
- readonly selectThread: TeamConversationProps['selectThread'];
9
- readonly t: TeamConversationProps['t'];
10
- }
11
- export declare function TeamInboxPanel({ workspaceId, loadInbox, loadChannels, loadChanges, selectThread, t }: TeamInboxPanelProps): import("react").JSX.Element;
12
- export {};
13
- //# sourceMappingURL=TeamInboxPanel.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"TeamInboxPanel.d.ts","sourceRoot":"","sources":["../../../src/client/TeamInboxPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAEzE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAIvD,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAA;IACtD,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AAED,wBAAgB,cAAc,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC,EAAE,EAAE,mBAAmB,+BAkGzH"}
@@ -1,90 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useEffect, useMemo, useRef, useState } from 'react';
3
- import { Button } from '@deepseek-ai/dsh-client-ui-primitives';
4
- import { formatTaskStatus } from "./team-formatters.js";
5
- import css from './inbox.module.css';
6
- export function TeamInboxPanel({ workspaceId, loadInbox, loadChannels, loadChanges, selectThread, t }) {
7
- const [inbox, setInbox] = useState();
8
- const [view, setView] = useState();
9
- const [error, setError] = useState();
10
- const [loading, setLoading] = useState(true);
11
- const active = useRef(false);
12
- const refreshSequence = useRef(0);
13
- const refresh = async (clearError = false) => {
14
- const sequence = refreshSequence.current + 1;
15
- refreshSequence.current = sequence;
16
- if (clearError)
17
- setError(undefined);
18
- try {
19
- const [nextInbox, nextView] = await Promise.all([
20
- loadInbox({ workspaceId }),
21
- loadChannels({ workspaceId, topLevelOnly: true, includeActivities: false, limit: 100 }),
22
- ]);
23
- if (!active.current || sequence !== refreshSequence.current)
24
- return;
25
- if (!nextInbox.ok) {
26
- setError(nextInbox.error.message);
27
- return;
28
- }
29
- if (!nextView.ok) {
30
- setError(nextView.error.message);
31
- return;
32
- }
33
- setInbox(nextInbox.value);
34
- setView(nextView.value);
35
- setError(undefined);
36
- }
37
- catch (cause) {
38
- if (active.current && sequence === refreshSequence.current)
39
- setError(cause instanceof Error ? cause.message : String(cause));
40
- }
41
- finally {
42
- if (active.current && sequence === refreshSequence.current)
43
- setLoading(false);
44
- }
45
- };
46
- useEffect(() => {
47
- let listening = true;
48
- active.current = true;
49
- setInbox(undefined);
50
- setView(undefined);
51
- setError(undefined);
52
- setLoading(true);
53
- void refresh();
54
- void (async () => {
55
- let version = 0;
56
- while (listening) {
57
- try {
58
- const changed = await loadChanges({ afterVersion: version });
59
- if (!listening)
60
- return;
61
- if (!changed.ok) {
62
- setError(changed.error.message);
63
- return;
64
- }
65
- if (changed.value.version > version) {
66
- version = changed.value.version;
67
- await refresh();
68
- }
69
- }
70
- catch (cause) {
71
- if (listening)
72
- setError(cause instanceof Error ? cause.message : String(cause));
73
- return;
74
- }
75
- }
76
- })();
77
- return () => {
78
- listening = false;
79
- active.current = false;
80
- refreshSequence.current += 1;
81
- };
82
- }, [workspaceId]);
83
- const channels = useMemo(() => new Map(view?.channels.map(channel => [channel.channelRef, channel]) ?? []), [view]);
84
- const taskNumbers = useMemo(() => new Map(view?.taskNumbers.map(item => [item.taskRef, item.taskNumber]) ?? []), [view]);
85
- return _jsxs("main", { className: css.surface, "data-team-inbox": true, children: [_jsxs("header", { className: css.header, children: [_jsxs("div", { children: [_jsx("h1", { children: t('inbox') }), inbox !== undefined && _jsx("p", { children: inbox.totalUnreadCount === 0 ? t('inboxEmpty') : t('inboxUnreadCount', { count: inbox.totalUnreadCount }) })] }), inbox !== undefined && inbox.totalDirectCount > 0 && _jsx("span", { className: css.directTotal, children: t('inboxDirectCount', { count: inbox.totalDirectCount }) })] }), _jsxs("section", { className: css.list, "aria-label": t('inbox'), children: [loading && inbox === undefined && error === undefined && _jsx("p", { className: css.state, children: t('loadingInbox') }), !loading && inbox?.items.length === 0 && error === undefined && _jsx("p", { className: css.state, children: t('inboxEmpty') }), error !== undefined && _jsxs("div", { className: css.error, role: "alert", children: [_jsx("span", { children: error }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => { void refresh(true); }, children: t('retry') })] }), inbox?.items.map(item => {
86
- const channel = channels.get(item.channelRef);
87
- const taskNumber = taskNumbers.get(item.task.taskRef);
88
- return _jsxs("button", { type: "button", className: css.item, onClick: () => { selectThread(item.task.taskRef, item.thread.threadRef, item.channelRef, taskNumber); }, children: [_jsx("span", { className: css.priority, "data-direct": item.directCount > 0, "aria-hidden": "true" }), _jsxs("span", { className: css.copy, children: [_jsx("strong", { children: taskNumber === undefined ? t('task') : `Task #${taskNumber}` }), _jsxs("small", { children: [channel === undefined ? t('channelUnknown') : `# ${channel.name}`, " \u00B7 ", formatTaskStatus(item.task.status, t)] })] }), _jsxs("span", { className: css.count, "aria-label": `${t('inboxUnreadCount', { count: item.unreadCount })}${item.directCount > 0 ? `, ${t('inboxDirectCount', { count: item.directCount })}` : ''}`, children: [t('inboxUnreadCount', { count: item.unreadCount }), item.directCount > 0 && _jsxs(_Fragment, { children: [" \u00B7 ", t('inboxDirectCount', { count: item.directCount })] })] })] }, item.thread.threadRef);
89
- })] })] });
90
- }