@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.
- package/README.md +1 -0
- package/README.zh.md +2 -0
- package/package.json +42 -25
- package/packages/agent-team/README.md +1 -1
- package/packages/agent-team/README.zh.md +1 -1
- package/packages/agent-team/lib/attachments.js +11 -12
- package/packages/agent-team/lib/auto-compaction.js +163 -0
- package/packages/agent-team/lib/index.js +262 -189
- package/packages/agent-team/lib/ledger.js +140 -109
- package/packages/agent-team/lib/recovery.js +30 -35
- package/packages/agent-team/lib/spec.js +10 -4
- package/packages/agent-team/lib/typert.host.js +68 -71
- package/packages/agent-team/lib/typert.remote-client.d.ts +3 -3
- package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
- package/packages/agent-team/lib/typert.remote-client.js +41 -56
- package/packages/agent-team/lib/types/attachments.d.ts +2 -2
- package/packages/agent-team/lib/types/attachments.d.ts.map +1 -1
- package/packages/agent-team/lib/types/auto-compaction.d.ts +38 -0
- package/packages/agent-team/lib/types/auto-compaction.d.ts.map +1 -0
- package/packages/agent-team/lib/types/index.d.ts +49 -24
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +24 -11
- package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
- package/packages/agent-team/lib/types/recovery.d.ts +15 -16
- package/packages/agent-team/lib/types/recovery.d.ts.map +1 -1
- package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types.d.ts +20 -12
- package/packages/agent-team/lib/types/types.d.ts.map +1 -1
- package/packages/agent-team/preset/team-member/agent.cordis.yml +8 -3
- package/packages/client-agent-team/README.md +3 -2
- package/packages/client-agent-team/README.zh.md +3 -2
- package/packages/client-agent-team/lib/client.js +1507 -525
- package/packages/client-agent-team/lib/client.js.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +1 -2
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +24 -182
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts +3 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +27 -5
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +19 -4
- package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamComposer.js +22 -2
- package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamConversation.js +3 -3
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts +34 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.js +169 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.d.ts +17 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.js +120 -0
- package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts +7 -2
- package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMessage.js +170 -18
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts +4 -0
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +70 -13
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +2 -2
- package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.js +72 -2
- package/packages/client-agent-team/lib/types/client/locales.d.ts +8 -2
- package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/locales.js +8 -2
- package/packages/client-agent-team/lib/types/client/member-session-input.d.ts +22 -0
- package/packages/client-agent-team/lib/types/client/member-session-input.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/member-session-input.js +98 -0
- package/packages/client-agent-team/lib/types/client/requests.d.ts +16 -0
- package/packages/client-agent-team/lib/types/client/requests.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/requests.js +22 -0
- package/packages/client-agent-team/lib/types/client/sidebar-drag.d.ts +35 -0
- package/packages/client-agent-team/lib/types/client/sidebar-drag.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/sidebar-drag.js +70 -0
- package/packages/client-agent-team/lib/types/client/sidebar-order.d.ts +27 -0
- package/packages/client-agent-team/lib/types/client/sidebar-order.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/sidebar-order.js +170 -0
- package/packages/client-agent-team/lib/types/client/slots.d.ts +2 -2
- package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/task-refs.d.ts +25 -0
- package/packages/client-agent-team/lib/types/client/task-refs.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/task-refs.js +77 -0
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +54 -1
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-formatters.js +83 -2
- package/packages/client-agent-team/lib/types/client/team-membership.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-membership.js +2 -1
- package/packages/tool-agent-team/lib/index.js +4 -4
- package/packages/client-agent-team/lib/types/client/TeamInboxPanel.d.ts +0 -13
- package/packages/client-agent-team/lib/types/client/TeamInboxPanel.d.ts.map +0 -1
- 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
|
|
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":"
|
|
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) ??
|
|
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
|
-
}
|