@wowyuarm/dsh-agent-team 0.1.2 → 0.1.4

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 (90) hide show
  1. package/README.md +8 -1
  2. package/README.zh.md +9 -1
  3. package/package.json +12 -3
  4. package/packages/agent-team/README.md +3 -3
  5. package/packages/agent-team/README.zh.md +3 -3
  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 +252 -139
  9. package/packages/agent-team/lib/ledger.js +344 -170
  10. package/packages/agent-team/lib/recovery.js +30 -35
  11. package/packages/agent-team/lib/spec.js +27 -11
  12. package/packages/agent-team/lib/typert.host.js +197 -88
  13. package/packages/agent-team/lib/typert.remote-client.d.ts +3 -1
  14. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  15. package/packages/agent-team/lib/typert.remote-client.js +139 -59
  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 +52 -19
  21. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  22. package/packages/agent-team/lib/types/ledger.d.ts +29 -2
  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 +69 -30
  28. package/packages/agent-team/lib/types/types.d.ts.map +1 -1
  29. package/packages/agent-team/preset/team-member/agent.cordis.yml +7 -2
  30. package/packages/client-agent-team/README.md +2 -1
  31. package/packages/client-agent-team/README.zh.md +2 -1
  32. package/packages/client-agent-team/lib/client.js +1577 -863
  33. package/packages/client-agent-team/lib/client.js.map +1 -1
  34. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
  35. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +35 -174
  36. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
  37. package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +20 -30
  38. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
  39. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +3 -2
  40. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts +6 -1
  41. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
  42. package/packages/client-agent-team/lib/types/client/TeamComposer.js +4 -5
  43. package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts +1 -1
  44. package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts.map +1 -1
  45. package/packages/client-agent-team/lib/types/client/TeamConversation.js +3 -3
  46. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts +34 -0
  47. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts.map +1 -0
  48. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.js +169 -0
  49. package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.d.ts +17 -0
  50. package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.d.ts.map +1 -0
  51. package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.js +120 -0
  52. package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts +4 -1
  53. package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts.map +1 -1
  54. package/packages/client-agent-team/lib/types/client/TeamMessage.js +94 -47
  55. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts +2 -1
  56. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
  57. package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +81 -39
  58. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
  59. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +2 -1
  60. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  61. package/packages/client-agent-team/lib/types/client/index.js +72 -1
  62. package/packages/client-agent-team/lib/types/client/locales.d.ts +24 -0
  63. package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
  64. package/packages/client-agent-team/lib/types/client/locales.js +24 -0
  65. package/packages/client-agent-team/lib/types/client/member-session-input.d.ts +22 -0
  66. package/packages/client-agent-team/lib/types/client/member-session-input.d.ts.map +1 -0
  67. package/packages/client-agent-team/lib/types/client/member-session-input.js +98 -0
  68. package/packages/client-agent-team/lib/types/client/navigation.d.ts +1 -1
  69. package/packages/client-agent-team/lib/types/client/navigation.d.ts.map +1 -1
  70. package/packages/client-agent-team/lib/types/client/navigation.js +12 -6
  71. package/packages/client-agent-team/lib/types/client/requests.d.ts +16 -0
  72. package/packages/client-agent-team/lib/types/client/requests.d.ts.map +1 -0
  73. package/packages/client-agent-team/lib/types/client/requests.js +22 -0
  74. package/packages/client-agent-team/lib/types/client/slots.d.ts +2 -1
  75. package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
  76. package/packages/client-agent-team/lib/types/client/task-refs.d.ts +6 -1
  77. package/packages/client-agent-team/lib/types/client/task-refs.d.ts.map +1 -1
  78. package/packages/client-agent-team/lib/types/client/task-refs.js +19 -0
  79. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +52 -3
  80. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
  81. package/packages/client-agent-team/lib/types/client/team-formatters.js +74 -4
  82. package/packages/client-agent-team/lib/types/client/team-membership.d.ts.map +1 -1
  83. package/packages/client-agent-team/lib/types/client/team-membership.js +2 -1
  84. package/packages/tool-agent-team/README.md +7 -7
  85. package/packages/tool-agent-team/README.zh.md +7 -7
  86. package/packages/tool-agent-team/lib/index.js +38 -28
  87. package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
  88. package/packages/client-agent-team/lib/types/client/TeamInboxPanel.d.ts +0 -13
  89. package/packages/client-agent-team/lib/types/client/TeamInboxPanel.d.ts.map +0 -1
  90. package/packages/client-agent-team/lib/types/client/TeamInboxPanel.js +0 -90
@@ -6,9 +6,10 @@ import { TeamPresenceDot } from "./TeamPresenceDot.js";
6
6
  import { TeamMessage } from "./TeamMessage.js";
7
7
  import { TeamRunDivider } from "./TeamRunDivider.js";
8
8
  import { formatActivity, formatClaimState, formatTaskStatus, formatTaskTitle, mentionNamesOf } from "./team-formatters.js";
9
+ import { mintRequestId } from "./requests.js";
9
10
  import { daySeparatorLabel, isRunGap, timelineDayKey } from "./team-separators.js";
10
11
  import { useTimelineScroll } from "./timeline-scroll.js";
11
- import { rememberResolvedTaskRef } from "./task-refs.js";
12
+ import { hostTaskRefLookup, jumpToTaskThread } from "./task-refs.js";
12
13
  import { bytesToBase64 } from "./attachment-preview.js";
13
14
  import css from './conversation.module.css';
14
15
  import threadCss from './thread.module.css';
@@ -32,7 +33,8 @@ function readMeta(facts) {
32
33
  return new Map(facts.map(fact => [factKey(fact.fact), fact]));
33
34
  }
34
35
  export function TeamThreadPage(props) {
35
- const { workspaceId, channelRef, taskRef, threadRef, taskNumber, backToWorkspace, selectChannel, selectThread, resolveTaskRefs, putAttachment, loadChannels, readThread, loadThreadHistory, subscribeChanges, loadMembers, drafts, getAttachment, reply, changeTask, t, } = props;
36
+ const { workspaceId, channelRef, taskRef, threadRef, taskNumber, backToWorkspace, selectChannel, selectThread, resolveTaskRefs, putAttachment, loadChannels, readThread, loadThreadHistory, subscribeChanges, loadMembers, drafts, getAttachment, reply, changeTask, promoteThread, t, } = props;
37
+ const threadRequest = { threadRef, ...(taskRef === undefined ? {} : { taskRef }) };
36
38
  const [projection, setProjection] = useState();
37
39
  const [channelView, setChannelView] = useState();
38
40
  const [members, setMembers] = useState([]);
@@ -52,19 +54,22 @@ export function TeamThreadPage(props) {
52
54
  // confirm dialog lists exactly what will be completed with the Task.
53
55
  const [confirmingAccept, setConfirmingAccept] = useState(false);
54
56
  useEffect(() => {
55
- if (confirmingAccept && projection?.task.resolution === 'accepted')
57
+ if (confirmingAccept && projection?.task?.resolution === 'accepted')
56
58
  setConfirmingAccept(false);
57
- }, [confirmingAccept, projection?.task.resolution]);
59
+ }, [confirmingAccept, projection?.task?.resolution]);
58
60
  const [replyRequestId, setReplyRequestId] = useState();
59
61
  const [confirmation, setConfirmation] = useState();
60
62
  const [statusMessage, setStatusMessage] = useState();
61
63
  const [pending, setPending] = useState(false);
64
+ // Label source for the promote/accept buttons only: a reply send also raises
65
+ // the shared `pending` gate, and must not retitle those buttons.
66
+ const [mutating, setMutating] = useState();
62
67
  const [loading, setLoading] = useState(true);
63
68
  const [error, setError] = useState();
64
69
  const mountedRef = useRef(false);
65
70
  const currentFactsRef = useRef([]);
66
71
  const sequenceRef = useRef(0);
67
- const readRequestIdRef = useRef(crypto.randomUUID());
72
+ const readRequestIdRef = useRef(mintRequestId());
68
73
  const mutationRequests = useRef(new Map());
69
74
  const threadLastFact = currentFacts[currentFacts.length - 1];
70
75
  const timeline = useTimelineScroll(`${currentFacts.length}:${olderFacts.length}:${threadLastFact === undefined ? '' : factKey(threadLastFact)}`);
@@ -85,12 +90,12 @@ export function TeamThreadPage(props) {
85
90
  if (!mountedRef.current)
86
91
  return false;
87
92
  if (newRequest)
88
- readRequestIdRef.current = crypto.randomUUID();
93
+ readRequestIdRef.current = mintRequestId();
89
94
  const sequence = sequenceRef.current + 1;
90
95
  sequenceRef.current = sequence;
91
96
  setLoading(true);
92
97
  try {
93
- const result = await readThread({ requestId: readRequestIdRef.current, workspaceId, taskRef });
98
+ const result = await readThread({ requestId: readRequestIdRef.current, workspaceId, ...threadRequest });
94
99
  if (!mountedRef.current || sequence !== sequenceRef.current)
95
100
  return false;
96
101
  if (!result.ok) {
@@ -134,7 +139,7 @@ export function TeamThreadPage(props) {
134
139
  };
135
140
  const refreshPassiveFacts = async () => {
136
141
  try {
137
- const result = await loadThreadHistory({ workspaceId, taskRef, limit: 100 });
142
+ const result = await loadThreadHistory({ workspaceId, ...threadRequest, limit: 100 });
138
143
  if (!mountedRef.current || !result.ok)
139
144
  return;
140
145
  const incoming = result.value.facts;
@@ -152,7 +157,7 @@ export function TeamThreadPage(props) {
152
157
  currentFactsRef.current = merged;
153
158
  return merged;
154
159
  });
155
- setProjection(current => current === undefined ? current : { ...current, task: result.value.task, thread: result.value.thread, claims: result.value.claims });
160
+ setProjection(current => current === undefined ? current : { ...current, ...(result.value.task === undefined ? {} : { task: result.value.task }), thread: result.value.thread, claims: result.value.claims });
156
161
  if (additions.length === 0)
157
162
  return;
158
163
  // A reader scrolled away from the tail must be offered the explicit
@@ -199,8 +204,8 @@ export function TeamThreadPage(props) {
199
204
  // One parallel round covers the whole first paint. The durable read no
200
205
  // longer wakes any change scope, so no second wave follows it.
201
206
  const [read, history] = await Promise.all([
202
- readThread({ requestId: readRequestIdRef.current, workspaceId, taskRef }),
203
- loadThreadHistory({ workspaceId, taskRef, limit: 20 }).catch(() => undefined),
207
+ readThread({ requestId: readRequestIdRef.current, workspaceId, ...threadRequest }),
208
+ loadThreadHistory({ workspaceId, ...threadRequest, limit: 20 }).catch(() => undefined),
204
209
  ]);
205
210
  if (!mountedRef.current || sequence !== sequenceRef.current)
206
211
  return;
@@ -261,7 +266,7 @@ export function TeamThreadPage(props) {
261
266
  return;
262
267
  setLoading(true);
263
268
  try {
264
- const result = await loadThreadHistory({ workspaceId, taskRef, beforeSequence, limit: 20 });
269
+ const result = await loadThreadHistory({ workspaceId, ...threadRequest, beforeSequence, limit: 20 });
265
270
  if (!mountedRef.current)
266
271
  return;
267
272
  if (!result.ok) {
@@ -285,6 +290,7 @@ export function TeamThreadPage(props) {
285
290
  const activeProjection = projection;
286
291
  const task = activeProjection?.task;
287
292
  const thread = activeProjection?.thread;
293
+ const resolvedTaskNumber = taskNumber ?? channelView?.taskNumbers.find(entry => entry.taskRef === task?.taskRef)?.taskNumber;
288
294
  const taskTitle = activeProjection === undefined ? undefined : formatTaskTitle(activeProjection.anchor.body);
289
295
  const taskClaims = activeProjection?.claims ?? [];
290
296
  const effectiveChannelRef = task?.channelRef ?? channelRef;
@@ -293,7 +299,7 @@ export function TeamThreadPage(props) {
293
299
  const mentionHandlesMap = useMemo(() => new Map(members.map(status => [status.member.memberId, status.member.handle.replace(/^@/, '')])), [members]);
294
300
  const metadata = useMemo(() => readMeta(readFacts), [readFacts]);
295
301
  const unreadIndex = useMemo(() => {
296
- const all = mergeFacts([messageFact(activeProjection?.anchor ?? { messageRef: 'missing', sequence: 0 }, activeProjection?.anchorMentions), ...readFacts.map(fact => fact.fact), ...currentFacts]);
302
+ const all = mergeFacts(...(activeProjection === undefined ? [] : [[messageFact(activeProjection.anchor, activeProjection.anchorMentions)]]), readFacts.map(fact => fact.fact), currentFacts);
297
303
  return all.findIndex(fact => metadata.get(factKey(fact))?.unread === true);
298
304
  }, [activeProjection?.anchor, readFacts, currentFacts, metadata]);
299
305
  const memberName = (memberId) => {
@@ -312,24 +318,10 @@ export function TeamThreadPage(props) {
312
318
  selectChannel(ref);
313
319
  if (ref.startsWith('task:') && ref !== taskRef) {
314
320
  // Another Task cited here: resolve its home Channel and jump.
315
- void resolveTaskRefs({ workspaceId, taskRefs: [ref] })
316
- .then(result => {
317
- if (!result.ok)
318
- return;
319
- const hit = result.value.resolved[0];
320
- if (hit !== undefined)
321
- selectThread(hit.taskRef, hit.threadRef, hit.channelRef, hit.taskNumber);
322
- });
321
+ jumpToTaskThread(resolveTaskRefs, workspaceId, ref, selectThread);
323
322
  }
324
323
  };
325
- const lookupTaskRefs = (refs) => resolveTaskRefs({ workspaceId, taskRefs: refs })
326
- .then(result => {
327
- if (!result.ok)
328
- return [];
329
- for (const entry of result.value.resolved)
330
- rememberResolvedTaskRef(entry);
331
- return result.value.resolved;
332
- });
324
+ const lookupTaskRefs = hostTaskRefLookup(resolveTaskRefs, workspaceId);
333
325
  const renderFact = (fact, grouped = false) => {
334
326
  if (fact.kind === 'message') {
335
327
  const sender = memberName(fact.message.sender);
@@ -384,13 +376,62 @@ export function TeamThreadPage(props) {
384
376
  await readCurrent(true);
385
377
  await refreshSupplemental();
386
378
  };
379
+ const convertToTask = async () => {
380
+ if (pending || thread === undefined || task !== undefined)
381
+ return;
382
+ setPending(true);
383
+ setMutating('promote');
384
+ setError(undefined);
385
+ const key = 'promote';
386
+ const requestId = mutationRequests.current.get(key) ?? mintRequestId();
387
+ mutationRequests.current.set(key, requestId);
388
+ try {
389
+ const result = await promoteThread({ requestId, workspaceId, threadRef, baseRevision: thread.revision });
390
+ if (!result.ok) {
391
+ setError(result.error.message);
392
+ return;
393
+ }
394
+ if (result.value.kind === 'committed') {
395
+ mutationRequests.current.delete(key);
396
+ const committed = result.value;
397
+ setProjection(current => current === undefined ? current
398
+ : { ...current, task: committed.task, thread: committed.thread });
399
+ setCurrentFacts(current => {
400
+ const merged = mergeFacts(current, [{ kind: 'activity', sequence: committed.activity.sequence, activity: committed.activity }]);
401
+ currentFactsRef.current = merged;
402
+ return merged;
403
+ });
404
+ await readCurrent(true);
405
+ await refreshSupplemental();
406
+ }
407
+ else if (result.value.kind === 'unread_required') {
408
+ setError(t('unreadRequired', { count: result.value.unreadCount }));
409
+ mutationRequests.current.delete(key);
410
+ await refreshAfterFence();
411
+ }
412
+ else {
413
+ setError(t('staleRevision'));
414
+ mutationRequests.current.delete(key);
415
+ await refreshPassiveFacts();
416
+ }
417
+ }
418
+ catch (cause) {
419
+ setError(cause instanceof Error ? cause.message : String(cause));
420
+ }
421
+ finally {
422
+ setPending(false);
423
+ setMutating(undefined);
424
+ }
425
+ };
387
426
  const mutateTask = async (action) => {
388
427
  if (pending || task === undefined || thread === undefined)
389
428
  return;
390
429
  setPending(true);
430
+ if (action === 'accept')
431
+ setMutating('accept');
391
432
  setError(undefined);
392
433
  const key = `task:${action}`;
393
- const requestId = mutationRequests.current.get(key) ?? crypto.randomUUID();
434
+ const requestId = mutationRequests.current.get(key) ?? mintRequestId();
394
435
  mutationRequests.current.set(key, requestId);
395
436
  try {
396
437
  const result = await changeTask({ requestId, workspaceId, taskRef: task.taskRef, action, baseRevision: thread.revision });
@@ -426,12 +467,13 @@ export function TeamThreadPage(props) {
426
467
  }
427
468
  finally {
428
469
  setPending(false);
470
+ setMutating(undefined);
429
471
  }
430
472
  };
431
473
  const sendReply = async () => {
432
- if (pending || task === undefined || thread === undefined || draft.trim() === '')
474
+ if (pending || thread === undefined || draft.trim() === '')
433
475
  return;
434
- const id = replyRequestId ?? crypto.randomUUID();
476
+ const id = replyRequestId ?? mintRequestId();
435
477
  setReplyRequestId(id);
436
478
  setPending(true);
437
479
  setError(undefined);
@@ -441,7 +483,7 @@ export function TeamThreadPage(props) {
441
483
  const attachmentIds = [];
442
484
  for (const file of pendingFiles) {
443
485
  const uploaded = await putAttachment({
444
- requestId: crypto.randomUUID(),
486
+ requestId: mintRequestId(),
445
487
  workspaceId,
446
488
  name: file.name,
447
489
  mediaType: file.type === '' ? undefined : file.type,
@@ -453,7 +495,7 @@ export function TeamThreadPage(props) {
453
495
  }
454
496
  attachmentIds.push(uploaded.value.attachmentId);
455
497
  }
456
- const result = await reply({ requestId: id, workspaceId, taskRef: task.taskRef, body: draft.trim(), baseRevision: thread.revision, recipients: [...recipients].sort(), ...(attachmentIds.length === 0 ? {} : { attachments: attachmentIds }), ...(confirmation === undefined ? {} : { confirmationToken: confirmation }) });
498
+ const result = await reply({ requestId: id, workspaceId, threadRef, ...(task === undefined ? {} : { taskRef: task.taskRef }), body: draft.trim(), baseRevision: thread.revision, recipients: [...recipients].sort(), ...(attachmentIds.length === 0 ? {} : { attachments: attachmentIds }), ...(confirmation === undefined ? {} : { confirmationToken: confirmation }) });
457
499
  if (!result.ok) {
458
500
  setError(result.error.message);
459
501
  return;
@@ -465,7 +507,7 @@ export function TeamThreadPage(props) {
465
507
  currentFactsRef.current = merged;
466
508
  return merged;
467
509
  });
468
- setProjection(current => current === undefined ? current : { ...current, task: committed.task, thread: committed.thread });
510
+ setProjection(current => current === undefined ? current : { ...current, ...(committed.task === undefined ? {} : { task: committed.task }), thread: committed.thread });
469
511
  drafts.clear(draftKey);
470
512
  setPendingFiles([]);
471
513
  setReplyRequestId(undefined);
@@ -514,7 +556,7 @@ export function TeamThreadPage(props) {
514
556
  // Threads are always entered through a Channel page, so a Channel origin
515
557
  // returns to its timeline; a Thread restored without one returns further.
516
558
  const backLabel = channelRef === undefined ? t('backToWorkspace') : t('backToChannel');
517
- return _jsxs("main", { className: css.surface, "data-team-thread": threadRef, children: [_jsxs("div", { className: css.surfaceHeader, children: [_jsx("div", { className: css.backRow, children: _jsx(Button, { size: "sm", icon: _jsx(IconChevronLeftOutline14, {}), onClick: backToWorkspace, children: backLabel }) }), _jsxs("header", { className: css.headerRow, children: [_jsxs("div", { className: css.headerCopy, children: [_jsxs("div", { className: threadCss.titleLine, children: [_jsx("h1", { children: task === undefined ? t('taskPending') : t('taskLabel', { number: taskNumber ?? '…' }) }), task !== undefined && _jsx(Pill, { children: formatTaskStatus(task.status, t) })] }), taskTitle !== undefined && taskTitle !== '' && _jsx("p", { className: threadCss.taskTitle, children: taskTitle })] }), task !== undefined && thread !== undefined && task.resolution !== 'closed' && _jsxs("div", { className: css.headerActions, children: [(() => {
559
+ return _jsxs("main", { className: css.surface, "data-team-thread": threadRef, children: [_jsxs("div", { className: css.surfaceHeader, children: [_jsx("div", { className: css.backRow, children: _jsx(Button, { size: "sm", icon: _jsx(IconChevronLeftOutline14, {}), onClick: backToWorkspace, children: backLabel }) }), _jsxs("header", { className: css.headerRow, children: [_jsxs("div", { className: css.headerCopy, children: [_jsxs("div", { className: threadCss.titleLine, children: [_jsx("h1", { children: task === undefined ? t('threadLabel') : t('taskLabel', { number: resolvedTaskNumber ?? '…' }) }), task !== undefined && _jsx(Pill, { children: formatTaskStatus(task.status, t) })] }), taskTitle !== undefined && taskTitle !== '' && _jsx("p", { className: threadCss.taskTitle, title: taskTitle, children: taskTitle })] }), task === undefined && thread !== undefined && _jsx("div", { className: css.headerActions, children: _jsx(Button, { size: "sm", variant: "primary", disabled: pending, onClick: () => { void convertToTask(); }, children: mutating === 'promote' ? t('promotingTask') : t('promoteToTask') }) }), task !== undefined && thread !== undefined && task.resolution !== 'closed' && _jsxs("div", { className: css.headerActions, children: [(() => {
518
560
  const activeClaims = projection?.claims.filter(claim => claim.taskRef === task.taskRef && claim.state === 'active') ?? [];
519
561
  const earlyAccept = task.resolution === 'open' && task.status === 'in_progress' && activeClaims.length > 0;
520
562
  if (!(task.status === 'in_review' || earlyAccept) || task.resolution !== 'open')
@@ -531,11 +573,11 @@ export function TeamThreadPage(props) {
531
573
  // Recomputed here so the confirm list never shows stale rows.
532
574
  const activeClaims = projection?.claims.filter(claim => claim.taskRef === task.taskRef && claim.state === 'active') ?? [];
533
575
  return _jsxs(Modal, { open: confirmingAccept, onClose: () => { if (!pending)
534
- setConfirmingAccept(false); }, title: t('acceptEarlyTitle'), closeLabel: t('cancel'), footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: pending, onClick: () => { setConfirmingAccept(false); }, children: t('cancel') }), _jsx(Button, { variant: "primary", disabled: pending, onClick: () => { void mutateTask('accept'); }, children: pending ? t('acceptingTask') : t('acceptTask') })] }), children: [_jsx("p", { className: css.confirmBody, children: t('acceptEarlyBody', { count: activeClaims.length }) }), _jsx("ul", { className: css.confirmList, children: activeClaims.map(claim => (_jsxs("li", { children: [memberName(claim.owner), " \u00B7 ", claim.direction] }, claim.claimRef))) })] });
576
+ setConfirmingAccept(false); }, title: t('acceptEarlyTitle'), closeLabel: t('cancel'), footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: pending, onClick: () => { setConfirmingAccept(false); }, children: t('cancel') }), _jsx(Button, { variant: "primary", disabled: pending, onClick: () => { void mutateTask('accept'); }, children: mutating === 'accept' ? t('acceptingTask') : t('acceptTask') })] }), children: [_jsx("p", { className: css.confirmBody, children: t('acceptEarlyBody', { count: activeClaims.length }) }), _jsx("ul", { className: css.confirmList, children: activeClaims.map(claim => (_jsxs("li", { children: [memberName(claim.owner), " \u00B7 ", claim.direction] }, claim.claimRef))) })] });
535
577
  })(), task !== undefined && thread !== undefined && _jsx("section", { className: threadCss.workSection, "aria-label": t('claims'), children: _jsx(DisclosureRow, { expandOnRowClick: true, expandable: true, open: claimsOpen, onToggle: () => { setClaimsOpen(current => !current); }, icon: _jsx(IconChecklistOutline14, { size: 14 }), title: `${t('claims')} · ${taskClaims.length}`, children: _jsxs("div", { className: threadCss.claimList, children: [taskClaims.length === 0 && _jsx("p", { className: threadCss.emptyClaims, children: t('noClaims') }), taskClaims.map(claim => {
536
578
  const ownerStatus = members.find(status => status.member.memberId === claim.owner);
537
579
  return _jsxs("article", { className: threadCss.claimRow, children: [ownerStatus === undefined ? _jsx("span", {}) : _jsx(TeamPresenceDot, { status: ownerStatus, t: t }), _jsx("strong", { className: threadCss.claimOwner, children: memberName(claim.owner) }), _jsx("span", { className: threadCss.claimDirection, children: claim.direction }), _jsx("small", { className: threadCss.claimState, children: formatClaimState(claim.state, t) })] }, claim.claimRef);
538
- })] }) }) })] }), _jsx("section", { ref: timeline.ref, onScroll: timeline.onScroll, className: css.timeline, "aria-label": t('timelineLabel'), children: _jsxs("div", { className: css.timelineContent, children: [loading && projection === undefined && error === undefined && _jsx("div", { className: css.emptySurface, children: _jsxs("p", { className: css.loadingState, children: [_jsx("span", { className: css.loadingMark, "aria-hidden": "true" }), t('loadingThread')] }) }), projection === undefined && error !== undefined && _jsxs("div", { className: css.errorState, role: "alert", children: [_jsx("span", { children: error }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => { void readCurrent(); }, children: t('retry') })] }), olderFacts.length > 0 && _jsxs("section", { className: threadCss.historySection, "aria-label": t('olderHistory'), children: [_jsx("h2", { children: t('olderHistory') }), renderFactBlocks(olderFacts, undefined)] }), historyHasMore && _jsx("div", { className: css.timelineAction, children: _jsx(Button, { size: "sm", onClick: () => { void loadOlder(); }, children: t('loadOlder') }) }), currentFactsWithAnchor.length > 0 && _jsx("section", { className: threadCss.publicSection, children: renderFactBlocks(currentFactsWithAnchor, unreadBoundary) }), newFactsCount > 0 && _jsxs("div", { className: threadCss.newUpdates, role: "status", children: [_jsx("span", { children: t('readNewUpdates', { count: newFactsCount }) }), _jsx(Button, { size: "sm", variant: "outline", disabled: loading, onClick: () => { timeline.jumpToLatest(); void readCurrent(true); }, children: t('markRead') })] }), remainingUnreadCount > 0 && _jsxs("div", { className: css.timelineAction, role: "status", children: [_jsx("span", { children: t('remainingUnread', { count: remainingUnreadCount }) }), _jsx(Button, { size: "sm", onClick: () => { timeline.jumpToBoundary(); void readCurrent(true); }, disabled: loading, children: t('continueReading') })] })] }) }), projection !== undefined && task !== undefined && thread !== undefined ? (task.resolution === 'closed'
580
+ })] }) }) })] }), _jsx("section", { ref: timeline.ref, onScroll: timeline.onScroll, className: css.timeline, "aria-label": t('timelineLabel'), children: _jsxs("div", { className: css.timelineContent, children: [loading && projection === undefined && error === undefined && _jsx("div", { className: css.emptySurface, children: _jsxs("p", { className: css.loadingState, children: [_jsx("span", { className: css.loadingMark, "aria-hidden": "true" }), t('loadingThread')] }) }), projection === undefined && error !== undefined && _jsxs("div", { className: css.errorState, role: "alert", children: [_jsx("span", { children: error }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => { void readCurrent(); }, children: t('retry') })] }), olderFacts.length > 0 && _jsxs("section", { className: threadCss.historySection, "aria-label": t('olderHistory'), children: [_jsx("h2", { children: t('olderHistory') }), renderFactBlocks(olderFacts, undefined)] }), historyHasMore && _jsx("div", { className: css.timelineAction, children: _jsx(Button, { size: "sm", onClick: () => { void loadOlder(); }, children: t('loadOlder') }) }), currentFactsWithAnchor.length > 0 && _jsx("section", { className: threadCss.publicSection, children: renderFactBlocks(currentFactsWithAnchor, unreadBoundary) }), newFactsCount > 0 && _jsxs("div", { className: threadCss.newUpdates, role: "status", children: [_jsx("span", { children: t('readNewUpdates', { count: newFactsCount }) }), _jsx(Button, { size: "sm", variant: "outline", disabled: loading, onClick: () => { timeline.jumpToLatest(); void readCurrent(true); }, children: t('markRead') })] }), remainingUnreadCount > 0 && _jsxs("div", { className: css.timelineAction, role: "status", children: [_jsx("span", { children: t('remainingUnread', { count: remainingUnreadCount }) }), _jsx(Button, { size: "sm", onClick: () => { timeline.jumpToBoundary(); void readCurrent(true); }, disabled: loading, children: t('continueReading') })] })] }) }), projection !== undefined && thread !== undefined ? (task?.resolution === 'closed'
539
581
  ? _jsxs("div", { className: threadCss.closedBar, "data-team-closed": true, children: [error !== undefined && _jsx("p", { className: css.error, role: "alert", children: error }), _jsxs("div", { className: threadCss.closedNotice, children: [_jsx("span", { children: t('taskClosedNotice') }), _jsx(Button, { size: "sm", variant: "outline", disabled: pending, onClick: () => { void mutateTask('reopen'); }, children: t('reopenTask') })] })] })
540
- : _jsx(TeamComposer, { members: channelMembers, recipients: recipients, draft: draft, pending: pending, ...(statusMessage === undefined ? {} : { confirmation: statusMessage }), ...(error === undefined ? {} : { error }), onDraftChange: next => { drafts.writeDraft(draftKey, next); setConfirmation(undefined); setReplyRequestId(undefined); setStatusMessage(undefined); }, onRecipientsChange: next => { drafts.writeRecipients(draftKey, next); setConfirmation(undefined); setReplyRequestId(undefined); setStatusMessage(undefined); }, onSubmit: () => { void sendReply(); }, pendingFiles: pendingFiles, onFilesChange: setPendingFiles, t: t }, draftKey)) : _jsx("div", {})] });
582
+ : _jsx(TeamComposer, { members: channelMembers, recipients: recipients, draft: draft, pending: pending, ...(statusMessage === undefined ? {} : { confirmation: statusMessage }), ...(error === undefined ? {} : { error }), onDraftChange: next => { drafts.writeDraft(draftKey, next); setConfirmation(undefined); setReplyRequestId(undefined); setStatusMessage(undefined); }, onRecipientsChange: next => { drafts.writeRecipients(draftKey, next); setConfirmation(undefined); setReplyRequestId(undefined); setStatusMessage(undefined); }, onSubmit: () => { void sendReply(); }, placeholder: t('replyPlaceholder'), pendingFiles: pendingFiles, onFilesChange: setPendingFiles, t: t }, draftKey)) : _jsx("div", {})] });
541
583
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TeamWorkspaceBrowser.d.ts","sourceRoot":"","sources":["../../../src/client/TeamWorkspaceBrowser.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAQlD,wBAAgB,oBAAoB,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,mBAAmB,EAAE,UAAU,EAAE,iBAAiB,EAAE,EAAE,gBAAgB,+BA4D/T"}
1
+ {"version":3,"file":"TeamWorkspaceBrowser.d.ts","sourceRoot":"","sources":["../../../src/client/TeamWorkspaceBrowser.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AASlD,wBAAgB,oBAAoB,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,mBAAmB,EAAE,UAAU,EAAE,iBAAiB,EAAE,EAAE,gBAAgB,+BA6D/T"}
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useRef, useState, useSyncExternalStore } from 'react';
3
3
  import { IconAgentPresetOutline16, IconListPenOutline16, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
4
4
  import { TeamWorkspaceRow } from "./TeamWorkspaceRow.js";
5
+ import { TeamSidebarSection } from "./TeamSidebarSection.js";
5
6
  import { TeamAgentsPanel } from "./TeamAgentsPanel.js";
6
7
  import { TeamChannelsPanel } from "./TeamChannelsPanel.js";
7
8
  import css from './sidebar.module.css';
@@ -36,5 +37,5 @@ export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWo
36
37
  if (!wide) {
37
38
  return _jsxs("nav", { className: css.railWorkspace, "aria-label": t('workspaceSections'), children: [_jsx(Tooltip, { label: t('channels'), side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": t('channels'), onClick: () => { setPendingSection('channels'); expandSidebar(); }, children: _jsx(IconListPenOutline16, { size: 16 }) }) }), _jsx(Tooltip, { label: t('agents'), side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": t('agents'), onClick: () => { setPendingSection('agents'); expandSidebar(); }, children: _jsx(IconAgentPresetOutline16, { size: 16 }) }) })] });
38
39
  }
39
- return _jsxs("section", { className: css.workspaceBrowser, "aria-label": t('workspaces'), children: [_jsx("div", { className: css.workspaceHeader, children: t('workspaces') }), _jsxs("div", { className: css.workspaceList, children: [workspaces.map(workspace => _jsx(TeamWorkspaceRow, { workspaceId: workspace.workspaceId, title: workspace.title, path: workspace.path, selected: workspace.workspaceId === selectedId, current: workspace.workspaceId === selectedId && overviewIsCurrent, onSelect: selectWorkspace }, workspace.workspaceId)), workspaces.length === 0 && _jsx("p", { className: css.emptyState, children: t('empty') })] }), selectedId !== undefined && _jsxs("div", { className: css.workspaceSection, children: [_jsx("div", { ref: channelsRef, children: _jsx(TeamChannelsPanel, { workspaceId: selectedId, loadMembers: loadMembers, loadChannels: loadChannels, subscribeChanges: subscribeChanges, createChannel: createChannel, updateChannel: updateChannel, joinChannel: joinChannel, removeChannelMember: removeChannelMember, creatingAgents: creatingAgents.filter(request => request.workspaceId === selectedId), ...(navigationState.memberSessionId !== undefined || navigationState.channelRef === undefined ? {} : { selectedChannelRef: navigationState.channelRef }), selectChannel: selectChannel, t: t }, selectedId) }), _jsx("div", { ref: agentsRef, children: _jsx(TeamAgentsPanel, { workspaceId: selectedId, loadMembers: loadMembers, subscribeChanges: subscribeChanges, loadChannels: loadChannels, addMember: addMember, updateMember: updateMember, recoverMember: recoverMember, joinChannel: joinChannel, removeChannelMember: removeChannelMember, loadModels: loadModels, ...(navigationState.memberSessionId === undefined ? {} : { memberSessionId: navigationState.memberSessionId }), openMemberSession: openMemberSession, onCreatingChange: (request, creating) => { setCreatingAgents(current => creating ? [...current.filter(item => item.requestId !== request.requestId), request] : current.filter(item => item.requestId !== request.requestId)); }, t: t }, selectedId) })] })] });
40
+ return _jsxs("section", { className: css.workspaceBrowser, "aria-label": t('workspaces'), children: [_jsx(TeamSidebarSection, { title: t('workspaces'), children: _jsxs("div", { className: css.workspaceList, children: [workspaces.map(workspace => _jsx(TeamWorkspaceRow, { workspaceId: workspace.workspaceId, title: workspace.title, path: workspace.path, selected: workspace.workspaceId === selectedId, current: workspace.workspaceId === selectedId && overviewIsCurrent, onSelect: selectWorkspace }, workspace.workspaceId)), workspaces.length === 0 && _jsx("p", { className: css.emptyState, children: t('empty') })] }) }), selectedId !== undefined && _jsxs("div", { className: css.workspaceSection, children: [_jsx("div", { ref: channelsRef, children: _jsx(TeamChannelsPanel, { workspaceId: selectedId, loadMembers: loadMembers, loadChannels: loadChannels, subscribeChanges: subscribeChanges, createChannel: createChannel, updateChannel: updateChannel, joinChannel: joinChannel, removeChannelMember: removeChannelMember, creatingAgents: creatingAgents.filter(request => request.workspaceId === selectedId), ...(navigationState.memberSessionId !== undefined || navigationState.channelRef === undefined ? {} : { selectedChannelRef: navigationState.channelRef }), selectChannel: selectChannel, t: t }, selectedId) }), _jsx("div", { ref: agentsRef, children: _jsx(TeamAgentsPanel, { workspaceId: selectedId, loadMembers: loadMembers, subscribeChanges: subscribeChanges, loadChannels: loadChannels, addMember: addMember, updateMember: updateMember, recoverMember: recoverMember, joinChannel: joinChannel, removeChannelMember: removeChannelMember, loadModels: loadModels, ...(navigationState.memberSessionId === undefined ? {} : { memberSessionId: navigationState.memberSessionId }), openMemberSession: openMemberSession, onCreatingChange: (request, creating) => { setCreatingAgents(current => creating ? [...current.filter(item => item.requestId !== request.requestId), request] : current.filter(item => item.requestId !== request.requestId)); }, t: t }, selectedId) })] })] });
40
41
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,wCAAwC,CAAA;AA8BtF,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAK5C,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AAEnD,YAAY,EAAE,QAAQ,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAC9F,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAIhD,eAAO,MAAM,MAAM,UAElB,CAAA;AAED,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,IAAI,EAAE,OAAO,CAAA;KACd;CACF;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,cAAc,EAAE,cAAc,CAAA;QAC9B,UAAU,EAAE,cAAc,CAAA;KAC3B;CACF;AAoJD,wBAAsB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,wCAAwC,CAAA;AAgCtF,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAO5C,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AAEnD,YAAY,EAAE,QAAQ,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAC9F,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAIhD,eAAO,MAAM,MAAM,UAElB,CAAA;AAED,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,IAAI,EAAE,OAAO,CAAA;KACd;CACF;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,cAAc,EAAE,cAAc,CAAA;QAC9B,UAAU,EAAE,cAAc,CAAA;KAC3B;CACF;AAwND,wBAAsB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D"}
@@ -6,11 +6,13 @@ import { TeamFooterAction } from "./TeamFooterAction.js";
6
6
  import { TeamSettings } from "./TeamSettings.js";
7
7
  import { TeamConversation } from "./TeamConversation.js";
8
8
  import { TeamWorkspaceBrowser } from "./TeamWorkspaceBrowser.js";
9
+ import { TeamMemberSessionComposer } from "./TeamMemberSessionComposer.js";
10
+ import { admitTeamCompact, createTeamMemberSessionSources } from "./member-session-input.js";
9
11
  import { en, zh } from "./locales.js";
10
12
  export { TeamNavigation } from "./navigation.js";
11
13
  const NS = 'team';
12
14
  export const inject = [
13
- 'slots', 'workspaces', 'locale', 'remote', 'sessions', 'connection',
15
+ 'slots', 'workspaces', 'locale', 'remote', 'sessions', 'connection', 'conversation', 'inputTriggers',
14
16
  ];
15
17
  function registerModeShadow(ctx, navigation, changes, drafts, name, component, extraInject) {
16
18
  // Remote bindings shared by every Team slot; surface-specific entries extend it below.
@@ -70,6 +72,7 @@ function registerModeShadow(ctx, navigation, changes, drafts, name, component, e
70
72
  getAttachment: (request) => ctx.remote.agentTeam.getAttachment(request),
71
73
  reply: (request) => ctx.remote.agentTeam.reply(request),
72
74
  changeTask: (request) => ctx.remote.agentTeam.changeTask(request),
75
+ promoteThread: (request) => ctx.remote.agentTeam.promoteThread(request),
73
76
  resolveTaskRefs: (request) => ctx.remote.agentTeam.resolveTaskRefs(request),
74
77
  } : {}),
75
78
  ...(name === 'sidebar.workspaces' ? {
@@ -93,6 +96,49 @@ function registerModeShadow(ctx, navigation, changes, drafts, name, component, e
93
96
  };
94
97
  });
95
98
  }
99
+ function registerMemberSessionComposer(ctx, navigation) {
100
+ ctx.slots.inject('conversation.composer.bar', () => {
101
+ let dispose;
102
+ let registeredSessionId;
103
+ const reconcile = () => {
104
+ const memberSessionId = navigation.getSnapshot().memberSessionId;
105
+ const active = navigation.getSnapshot().mode === 'team' && memberSessionId !== undefined;
106
+ if (dispose !== undefined && (!active || registeredSessionId !== memberSessionId)) {
107
+ dispose();
108
+ dispose = undefined;
109
+ registeredSessionId = undefined;
110
+ }
111
+ if (active && dispose === undefined) {
112
+ registeredSessionId = memberSessionId;
113
+ dispose = ctx.slots.register({
114
+ name: 'conversation.composer.bar',
115
+ priority: -100,
116
+ // The registration may remain live during a session transition, but
117
+ // it elects only when the shell's current Session is the embedded
118
+ // Member. This avoids taking an ordinary Session if selection races.
119
+ select: () => ctx.sessions.list.getSnapshot().current === memberSessionId ? {} : null,
120
+ inject: (sessionId) => {
121
+ const actx = ctx.sessions.scope(sessionId);
122
+ if (actx === undefined)
123
+ throw new Error(`agent-team: Member session ${String(sessionId)} has no client scope`);
124
+ const sessions = ctx.sessions;
125
+ return {
126
+ controller: ctx.get('inputTriggers').sessionOf(actx),
127
+ stop: () => { void sessions.sessionOf(actx)?.cancel(); },
128
+ submitInput: (mode) => ctx.conversation.input.for(actx).submit(mode),
129
+ };
130
+ },
131
+ }, TeamMemberSessionComposer);
132
+ }
133
+ };
134
+ const offNavigation = navigation.subscribe(reconcile);
135
+ reconcile();
136
+ return () => {
137
+ offNavigation();
138
+ dispose?.();
139
+ };
140
+ });
141
+ }
96
142
  function applyUi(ctx) {
97
143
  ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'agent-team: dictionaries');
98
144
  const navigation = new TeamNavigation();
@@ -106,6 +152,30 @@ function applyUi(ctx) {
106
152
  void disposeDrafts();
107
153
  }, 'agent-team: navigation service');
108
154
  const changes = new TeamChangeStream((request, signal) => ctx.remote.agentTeam.changes(request, signal));
155
+ const triggerSources = createTeamMemberSessionSources({
156
+ isEmbeddedMemberSession: sessionId => {
157
+ const snapshot = navigation.getSnapshot();
158
+ return snapshot.mode === 'team' && snapshot.memberSessionId === sessionId && snapshot.workspaceId !== undefined;
159
+ },
160
+ members: async () => {
161
+ const workspaceId = navigation.getSnapshot().workspaceId;
162
+ if (workspaceId === undefined)
163
+ return [];
164
+ const result = await ctx.remote.agentTeam.members({ workspaceId });
165
+ return result.ok ? result.value : [];
166
+ },
167
+ executeCompact: async (sessionId) => {
168
+ const actx = ctx.sessions.scope(sessionId);
169
+ const session = actx === undefined ? undefined : ctx.sessions.sessionOf(actx);
170
+ return session === undefined ? { kind: 'error', text: 'current Member Session is unavailable' } : admitTeamCompact(session);
171
+ },
172
+ });
173
+ const inputTriggers = ctx.get('inputTriggers');
174
+ ctx.effect(() => {
175
+ const disposers = triggerSources.map(source => inputTriggers.registerSource(source));
176
+ return () => { for (const dispose of disposers)
177
+ dispose(); };
178
+ }, 'agent-team: Member session trigger sources');
109
179
  const loadMemberGroups = async () => {
110
180
  const workspaces = ctx.workspaces.list.getSnapshot().items;
111
181
  const groups = await Promise.all(workspaces.map(async (workspace) => {
@@ -144,6 +214,7 @@ function applyUi(ctx) {
144
214
  }, TeamFooterAction));
145
215
  registerModeShadow(ctx, navigation, changes, drafts, 'sidebar.workspaces', TeamWorkspaceBrowser);
146
216
  registerModeShadow(ctx, navigation, changes, drafts, 'conversation', TeamConversation);
217
+ registerMemberSessionComposer(ctx, navigation);
147
218
  registerModeShadow(ctx, navigation, changes, drafts, 'sidebar.settings', TeamSettings, () => ({ loadMemberGroups }));
148
219
  }
149
220
  export async function apply(ctx) {
@@ -37,6 +37,9 @@ export declare const zh: {
37
37
  readonly editChannel: "编辑频道";
38
38
  readonly editAgent: "编辑 Agent";
39
39
  readonly resumeAgent: "恢复";
40
+ readonly restartAgent: "重启";
41
+ readonly restartStillUnavailable: "重启已执行,成员仍不可用:{diagnostic}";
42
+ readonly restartFailed: "重启执行失败:{message}";
40
43
  readonly optionalSuffix: "(可选)";
41
44
  readonly agentDescriptionPlaceholder: "留空则暂无描述";
42
45
  readonly channelsPickerEmpty: "选择初始频道";
@@ -49,6 +52,8 @@ export declare const zh: {
49
52
  readonly removeFile: "移除 {name}";
50
53
  readonly attachmentExpired: "文件已过期清理";
51
54
  readonly viewImage: "查看大图 {name}";
55
+ readonly expandMessage: "展开全文";
56
+ readonly collapseMessage: "收起";
52
57
  readonly actionsChannel: "{name} 的操作";
53
58
  readonly actionsAgent: "{name} 的操作";
54
59
  readonly editSave: "保存";
@@ -81,10 +86,16 @@ export declare const zh: {
81
86
  readonly taskLabel: "Task #{number}";
82
87
  readonly taskPending: "Task …";
83
88
  readonly openTask: "打开 Task #{number}";
89
+ readonly openThread: "打开讨论";
90
+ readonly threadLabel: "讨论";
91
+ readonly asTask: "作为任务";
92
+ readonly promoteToTask: "转为 Task";
93
+ readonly promotingTask: "正在转为 Task…";
84
94
  readonly mentionSuggestions: "提及成员建议";
85
95
  readonly messageDraft: "消息内容";
86
96
  readonly composerNotify: "将通知:{ids}";
87
97
  readonly messagePlaceholder: "写一条消息…";
98
+ readonly replyPlaceholder: "回复此 Thread…";
88
99
  readonly sendMessage: "发送";
89
100
  readonly sendingMessage: "发送中…";
90
101
  readonly loadOlder: "加载更早消息";
@@ -115,6 +126,7 @@ export declare const zh: {
115
126
  readonly activityClaimsReleased: "{actor} 因成员权限变化释放了 {count} 个 Claim";
116
127
  readonly activityAccepted: "{actor} 验收了此 Task";
117
128
  readonly activityAcceptedWithClaims: "{actor} 验收了此 Task,并一并完成了 {count} 个未完成 Claim";
129
+ readonly activityPromoted: "{actor} 为此讨论创建了 Task";
118
130
  readonly acceptEarlyTitle: "提前验收任务";
119
131
  readonly acceptEarlyBody: "将验收本 Task,并把以下 {count} 个未完成的 Claim 一并标记为完成:";
120
132
  readonly acceptingTask: "验收中…";
@@ -165,6 +177,9 @@ export declare const en: {
165
177
  readonly editChannel: "Edit Channel";
166
178
  readonly editAgent: "Edit Agent";
167
179
  readonly resumeAgent: "Resume";
180
+ readonly restartAgent: "Restart";
181
+ readonly restartStillUnavailable: "Restart ran, but the Member is still unavailable: {diagnostic}";
182
+ readonly restartFailed: "Restart failed: {message}";
168
183
  readonly optionalSuffix: " (optional)";
169
184
  readonly agentDescriptionPlaceholder: "Leave empty if not needed";
170
185
  readonly channelsPickerEmpty: "Choose initial channels";
@@ -177,6 +192,8 @@ export declare const en: {
177
192
  readonly removeFile: "Remove {name}";
178
193
  readonly attachmentExpired: "File expired and cleaned up";
179
194
  readonly viewImage: "View image {name}";
195
+ readonly expandMessage: "Show more";
196
+ readonly collapseMessage: "Show less";
180
197
  readonly actionsChannel: "{name} actions";
181
198
  readonly actionsAgent: "{name} actions";
182
199
  readonly editSave: "Save";
@@ -209,10 +226,16 @@ export declare const en: {
209
226
  readonly taskLabel: "Task #{number}";
210
227
  readonly taskPending: "Task …";
211
228
  readonly openTask: "Open Task #{number}";
229
+ readonly openThread: "Open thread";
230
+ readonly threadLabel: "Thread";
231
+ readonly asTask: "As task";
232
+ readonly promoteToTask: "Convert to Task";
233
+ readonly promotingTask: "Converting to Task…";
212
234
  readonly mentionSuggestions: "Mention suggestions";
213
235
  readonly messageDraft: "Message";
214
236
  readonly composerNotify: "Will notify: {ids}";
215
237
  readonly messagePlaceholder: "Write a message…";
238
+ readonly replyPlaceholder: "Reply on this Thread…";
216
239
  readonly sendMessage: "Send";
217
240
  readonly sendingMessage: "Sending…";
218
241
  readonly loadOlder: "Load older messages";
@@ -243,6 +266,7 @@ export declare const en: {
243
266
  readonly activityClaimsReleased: "{actor} released {count} Claim(s) after a membership change";
244
267
  readonly activityAccepted: "{actor} accepted this Task";
245
268
  readonly activityAcceptedWithClaims: "{actor} accepted this Task and completed {count} unfinished Claims with it";
269
+ readonly activityPromoted: "{actor} created a Task for this Thread";
246
270
  readonly acceptEarlyTitle: "Accept Task early";
247
271
  readonly acceptEarlyBody: "This accepts the Task and marks the following {count} unfinished Claims as done:";
248
272
  readonly acceptingTask: "Accepting…";
@@ -1 +1 @@
1
- {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+HL,CAAA;AAEV,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+HL,CAAA;AAEV,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,EAAE,CAAA"}
1
+ {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2IL,CAAA;AAEV,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2IL,CAAA;AAEV,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,EAAE,CAAA"}
@@ -37,6 +37,9 @@ export const zh = {
37
37
  editChannel: '编辑频道',
38
38
  editAgent: '编辑 Agent',
39
39
  resumeAgent: '恢复',
40
+ restartAgent: '重启',
41
+ restartStillUnavailable: '重启已执行,成员仍不可用:{diagnostic}',
42
+ restartFailed: '重启执行失败:{message}',
40
43
  optionalSuffix: '(可选)',
41
44
  agentDescriptionPlaceholder: '留空则暂无描述',
42
45
  channelsPickerEmpty: '选择初始频道',
@@ -49,6 +52,8 @@ export const zh = {
49
52
  removeFile: '移除 {name}',
50
53
  attachmentExpired: '文件已过期清理',
51
54
  viewImage: '查看大图 {name}',
55
+ expandMessage: '展开全文',
56
+ collapseMessage: '收起',
52
57
  actionsChannel: '{name} 的操作',
53
58
  actionsAgent: '{name} 的操作',
54
59
  editSave: '保存',
@@ -81,10 +86,16 @@ export const zh = {
81
86
  taskLabel: 'Task #{number}',
82
87
  taskPending: 'Task …',
83
88
  openTask: '打开 Task #{number}',
89
+ openThread: '打开讨论',
90
+ threadLabel: '讨论',
91
+ asTask: '作为任务',
92
+ promoteToTask: '转为 Task',
93
+ promotingTask: '正在转为 Task…',
84
94
  mentionSuggestions: '提及成员建议',
85
95
  messageDraft: '消息内容',
86
96
  composerNotify: '将通知:{ids}',
87
97
  messagePlaceholder: '写一条消息…',
98
+ replyPlaceholder: '回复此 Thread…',
88
99
  sendMessage: '发送',
89
100
  sendingMessage: '发送中…',
90
101
  loadOlder: '加载更早消息',
@@ -115,6 +126,7 @@ export const zh = {
115
126
  activityClaimsReleased: '{actor} 因成员权限变化释放了 {count} 个 Claim',
116
127
  activityAccepted: '{actor} 验收了此 Task',
117
128
  activityAcceptedWithClaims: '{actor} 验收了此 Task,并一并完成了 {count} 个未完成 Claim',
129
+ activityPromoted: '{actor} 为此讨论创建了 Task',
118
130
  acceptEarlyTitle: '提前验收任务',
119
131
  acceptEarlyBody: '将验收本 Task,并把以下 {count} 个未完成的 Claim 一并标记为完成:',
120
132
  acceptingTask: '验收中…',
@@ -165,6 +177,9 @@ export const en = {
165
177
  editChannel: 'Edit Channel',
166
178
  editAgent: 'Edit Agent',
167
179
  resumeAgent: 'Resume',
180
+ restartAgent: 'Restart',
181
+ restartStillUnavailable: 'Restart ran, but the Member is still unavailable: {diagnostic}',
182
+ restartFailed: 'Restart failed: {message}',
168
183
  optionalSuffix: ' (optional)',
169
184
  agentDescriptionPlaceholder: 'Leave empty if not needed',
170
185
  channelsPickerEmpty: 'Choose initial channels',
@@ -177,6 +192,8 @@ export const en = {
177
192
  removeFile: 'Remove {name}',
178
193
  attachmentExpired: 'File expired and cleaned up',
179
194
  viewImage: 'View image {name}',
195
+ expandMessage: 'Show more',
196
+ collapseMessage: 'Show less',
180
197
  actionsChannel: '{name} actions',
181
198
  actionsAgent: '{name} actions',
182
199
  editSave: 'Save',
@@ -209,10 +226,16 @@ export const en = {
209
226
  taskLabel: 'Task #{number}',
210
227
  taskPending: 'Task …',
211
228
  openTask: 'Open Task #{number}',
229
+ openThread: 'Open thread',
230
+ threadLabel: 'Thread',
231
+ asTask: 'As task',
232
+ promoteToTask: 'Convert to Task',
233
+ promotingTask: 'Converting to Task…',
212
234
  mentionSuggestions: 'Mention suggestions',
213
235
  messageDraft: 'Message',
214
236
  composerNotify: 'Will notify: {ids}',
215
237
  messagePlaceholder: 'Write a message…',
238
+ replyPlaceholder: 'Reply on this Thread…',
216
239
  sendMessage: 'Send',
217
240
  sendingMessage: 'Sending…',
218
241
  loadOlder: 'Load older messages',
@@ -243,6 +266,7 @@ export const en = {
243
266
  activityClaimsReleased: '{actor} released {count} Claim(s) after a membership change',
244
267
  activityAccepted: '{actor} accepted this Task',
245
268
  activityAcceptedWithClaims: '{actor} accepted this Task and completed {count} unfinished Claims with it',
269
+ activityPromoted: '{actor} created a Task for this Thread',
246
270
  acceptEarlyTitle: 'Accept Task early',
247
271
  acceptEarlyBody: 'This accepts the Task and marks the following {count} unfinished Claims as done:',
248
272
  acceptingTask: 'Accepting…',