@wowyuarm/dsh-agent-team 0.1.5 → 0.1.7

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 (100) hide show
  1. package/README.md +23 -3
  2. package/README.zh.md +23 -3
  3. package/package.json +50 -43
  4. package/packages/agent-team/README.md +8 -0
  5. package/packages/agent-team/README.zh.md +8 -0
  6. package/packages/agent-team/core-skills/member-skill-manager/SKILL.md +41 -0
  7. package/packages/agent-team/core-skills/member-skill-manager/references/auth-and-config.md +30 -0
  8. package/packages/agent-team/core-skills/member-skill-manager/references/writing-great-skills.md +17 -0
  9. package/packages/agent-team/lib/index.js +168 -37
  10. package/packages/agent-team/lib/ledger.js +440 -18
  11. package/packages/agent-team/lib/member-context.js +7 -3
  12. package/packages/agent-team/lib/member-runtime.js +229 -0
  13. package/packages/agent-team/lib/member-skills.js +94 -0
  14. package/packages/agent-team/lib/preset-roster.js +1 -0
  15. package/packages/agent-team/lib/spec.js +56 -1
  16. package/packages/agent-team/lib/typert.host.js +359 -77
  17. package/packages/agent-team/lib/typert.remote-client.d.ts +5 -1
  18. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  19. package/packages/agent-team/lib/typert.remote-client.js +248 -43
  20. package/packages/agent-team/lib/types/entities.js +1 -0
  21. package/packages/agent-team/lib/types/index.d.ts +51 -7
  22. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  23. package/packages/agent-team/lib/types/ledger.d.ts +62 -1
  24. package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
  25. package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
  26. package/packages/agent-team/lib/types/member-runtime.d.ts +108 -0
  27. package/packages/agent-team/lib/types/member-runtime.d.ts.map +1 -0
  28. package/packages/agent-team/lib/types/member-skills.d.ts +45 -0
  29. package/packages/agent-team/lib/types/member-skills.d.ts.map +1 -0
  30. package/packages/agent-team/lib/types/operations.js +1 -0
  31. package/packages/agent-team/lib/types/preset-roster.d.ts.map +1 -1
  32. package/packages/agent-team/lib/types/requests-results.js +1 -0
  33. package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
  34. package/packages/agent-team/lib/types/types/entities.d.ts +339 -0
  35. package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -0
  36. package/packages/agent-team/lib/types/types/operations.d.ts +303 -0
  37. package/packages/agent-team/lib/types/types/operations.d.ts.map +1 -0
  38. package/packages/agent-team/lib/types/types/requests-results.d.ts +527 -0
  39. package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -0
  40. package/packages/agent-team/lib/types/types.d.ts +10 -985
  41. package/packages/agent-team/lib/types/types.d.ts.map +1 -1
  42. package/packages/agent-team/preset/team-member/agent.cordis.yml +11 -6
  43. package/packages/client-agent-team/README.md +4 -2
  44. package/packages/client-agent-team/README.zh.md +4 -2
  45. package/packages/client-agent-team/lib/client.js +636 -572
  46. package/packages/client-agent-team/lib/client.js.map +1 -1
  47. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +3 -5
  48. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
  49. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +37 -26
  50. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts +1 -1
  51. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
  52. package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +2 -2
  53. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts +2 -1
  54. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
  55. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +31 -5
  56. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
  57. package/packages/client-agent-team/lib/types/client/TeamComposer.js +2 -1
  58. package/packages/client-agent-team/lib/types/client/TeamMemberDock.d.ts +12 -0
  59. package/packages/client-agent-team/lib/types/client/TeamMemberDock.d.ts.map +1 -0
  60. package/packages/client-agent-team/lib/types/client/TeamMemberDock.js +13 -0
  61. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts +4 -8
  62. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts.map +1 -1
  63. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.js +7 -40
  64. package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts.map +1 -1
  65. package/packages/client-agent-team/lib/types/client/TeamMessage.js +10 -3
  66. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts +1 -1
  67. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
  68. package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +61 -20
  69. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
  70. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
  71. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +2 -2
  72. package/packages/client-agent-team/lib/types/client/TeamWorkspaceRow.d.ts +1 -1
  73. package/packages/client-agent-team/lib/types/client/TeamWorkspaceRow.d.ts.map +1 -1
  74. package/packages/client-agent-team/lib/types/client/index.d.ts +1 -1
  75. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  76. package/packages/client-agent-team/lib/types/client/index.js +25 -28
  77. package/packages/client-agent-team/lib/types/client/locales.d.ts +32 -16
  78. package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
  79. package/packages/client-agent-team/lib/types/client/locales.js +32 -16
  80. package/packages/client-agent-team/lib/types/client/member-session-input.d.ts +1 -3
  81. package/packages/client-agent-team/lib/types/client/member-session-input.d.ts.map +1 -1
  82. package/packages/client-agent-team/lib/types/client/member-session-input.js +18 -6
  83. package/packages/client-agent-team/lib/types/client/navigation.d.ts +2 -1
  84. package/packages/client-agent-team/lib/types/client/navigation.d.ts.map +1 -1
  85. package/packages/client-agent-team/lib/types/client/sidebar-order.d.ts +1 -1
  86. package/packages/client-agent-team/lib/types/client/sidebar-order.d.ts.map +1 -1
  87. package/packages/client-agent-team/lib/types/client/sidebar-sections.d.ts +1 -1
  88. package/packages/client-agent-team/lib/types/client/sidebar-sections.d.ts.map +1 -1
  89. package/packages/client-agent-team/lib/types/client/slots.d.ts +3 -1
  90. package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
  91. package/packages/client-agent-team/lib/types/client/team-membership.d.ts +1 -1
  92. package/packages/client-agent-team/lib/types/client/team-membership.d.ts.map +1 -1
  93. package/packages/client-agent-team/lib/types/client/timeline-scroll.d.ts +5 -7
  94. package/packages/client-agent-team/lib/types/client/timeline-scroll.d.ts.map +1 -1
  95. package/packages/client-agent-team/lib/types/client/timeline-scroll.js +9 -22
  96. package/packages/tool-agent-team/lib/index.js +25 -5
  97. package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
  98. package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.d.ts +0 -17
  99. package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.d.ts.map +0 -1
  100. package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.js +0 -135
@@ -1,5 +1,5 @@
1
1
  import type { AgentTeamChannelRef, AgentTeamTaskRef, AgentTeamThreadRef } from '@wowyuarm/dsh-agent-team/types';
2
- import type { WorkspaceId } from '@deepseek-ai/dsh-client-runtime/client';
2
+ import type { WorkspaceId } from '@deepseek-ai/dsh-api-workspace-controller/client';
3
3
  import type { TeamConversationProps } from './slots.ts';
4
4
  import type { TeamDraftStore } from './drafts.ts';
5
5
  interface TeamThreadPageProps {
@@ -1 +1 @@
1
- {"version":3,"file":"TeamThreadPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamThreadPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,mBAAmB,EAInB,gBAAgB,EAGhB,kBAAkB,EAEnB,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAEzE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,aAAa,CAAA;AAc/D,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,mBAAmB,CAAA;IACzC,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAA;IACnC,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAA;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAA;IACxD,QAAQ,CAAC,iBAAiB,EAAE,qBAAqB,CAAC,mBAAmB,CAAC,CAAA;IACtE,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,CAAA;IACpE,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAA;IAC9C,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAA;IACxD,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AA8BD,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,+BAgoBxD"}
1
+ {"version":3,"file":"TeamThreadPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamThreadPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,mBAAmB,EAInB,gBAAgB,EAGhB,kBAAkB,EAEnB,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,aAAa,CAAA;AAc/D,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,mBAAmB,CAAA;IACzC,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAA;IACnC,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAA;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAA;IACxD,QAAQ,CAAC,iBAAiB,EAAE,qBAAqB,CAAC,mBAAmB,CAAC,CAAA;IACtE,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,CAAA;IACpE,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAA;IAC9C,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAA;IACxD,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AA8BD,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,+BAuqBxD"}
@@ -43,7 +43,13 @@ export function TeamThreadPage(props) {
43
43
  const [readFacts, setReadFacts] = useState([]);
44
44
  const [historyCursor, setHistoryCursor] = useState();
45
45
  const [historyHasMore, setHistoryHasMore] = useState(false);
46
- const [remainingUnreadCount, setRemainingUnreadCount] = useState(0);
46
+ // A bounded read acknowledges at most 20 unread facts; larger backlogs need
47
+ // continuation reads. Reads also never self-wake a change scope, so a
48
+ // backlog beyond a handful of batches would otherwise linger forever. The
49
+ // cap stops a pathological feed (facts arriving faster than they are read)
50
+ // from looping without bound; the error surface keeps the remainder visible.
51
+ const MAX_AUTO_READ_ROUNDS = 50;
52
+ const [autoReadExhausted, setAutoReadExhausted] = useState(false);
47
53
  const [newFactsCount, setNewFactsCount] = useState(0);
48
54
  // The reply draft lives in the keyed draft cache: view switches unmount
49
55
  // this page, and a refresh must not cost the half-written message either.
@@ -70,13 +76,14 @@ export function TeamThreadPage(props) {
70
76
  const currentFactsRef = useRef([]);
71
77
  const sequenceRef = useRef(0);
72
78
  const readRequestIdRef = useRef(mintRequestId());
79
+ const projectionRef = useRef();
73
80
  const mutationRequests = useRef(new Map());
74
81
  const threadLastFact = currentFacts[currentFacts.length - 1];
75
82
  const timeline = useTimelineScroll(`${currentFacts.length}:${olderFacts.length}:${threadLastFact === undefined ? '' : factKey(threadLastFact)}`);
76
83
  const updateProjection = (next) => {
84
+ projectionRef.current = next;
77
85
  setProjection(next);
78
86
  setReadFacts(next.facts);
79
- setRemainingUnreadCount(next.remainingUnreadCount);
80
87
  const anchor = messageFact(next.anchor, next.anchorMentions);
81
88
  const batch = [anchor, ...next.facts.map(fact => fact.fact)];
82
89
  setCurrentFacts(current => {
@@ -84,7 +91,28 @@ export function TeamThreadPage(props) {
84
91
  currentFactsRef.current = merged;
85
92
  return merged;
86
93
  });
87
- setNewFactsCount(0);
94
+ };
95
+ // Continue a bounded read while unread facts remain. Each round must mint a
96
+ // fresh requestId: the Host replays a repeated id from its idempotency
97
+ // cache, which would return the same batch forever. The loop terminates on
98
+ // a zero remainder, a failed read (the existing error surface offers
99
+ // retry), a superseding sequence, or the round cap.
100
+ const drainUnread = async () => {
101
+ for (let round = 1; round <= MAX_AUTO_READ_ROUNDS; round += 1) {
102
+ const snapshot = projectionRef.current;
103
+ if (snapshot === undefined || snapshot.remainingUnreadCount <= 0)
104
+ return;
105
+ const beforeSequence = sequenceRef.current;
106
+ if (!await readCurrent(true))
107
+ return;
108
+ // A newer read or remount owns the tail now; it drains the remainder.
109
+ if (!mountedRef.current || sequenceRef.current !== beforeSequence + 1)
110
+ return;
111
+ // A stalled remainder (Host fault) must not spin the loop.
112
+ if (projectionRef.current?.remainingUnreadCount === snapshot.remainingUnreadCount)
113
+ return;
114
+ }
115
+ setAutoReadExhausted(true);
88
116
  };
89
117
  const readCurrent = async (newRequest = false) => {
90
118
  if (!mountedRef.current)
@@ -157,23 +185,26 @@ export function TeamThreadPage(props) {
157
185
  currentFactsRef.current = merged;
158
186
  return merged;
159
187
  });
160
- setProjection(current => current === undefined ? current : { ...current, ...(result.value.task === undefined ? {} : { task: result.value.task }), thread: result.value.thread, claims: result.value.claims });
188
+ setProjection(current => {
189
+ const next = current === undefined ? current : { ...current, ...(result.value.task === undefined ? {} : { task: result.value.task }), thread: result.value.thread, claims: result.value.claims };
190
+ if (next !== undefined)
191
+ projectionRef.current = next;
192
+ return next;
193
+ });
161
194
  if (additions.length === 0)
162
195
  return;
163
- // A reader scrolled away from the tail must be offered the explicit
164
- // new-updates action; a reader pinned to the bottom is watching these
165
- // facts arrive, so they are already seen and the batch is acknowledged
166
- // durably instead of being counted for an explicit read.
167
- if (!timeline.isPinned()) {
196
+ // Every arrival while the Thread is open is acknowledged durably: the
197
+ // timeline renders it either way, and the Human has no manual read
198
+ // action anymore. The count only feeds the pure jump hint for a reader
199
+ // away from the bottom; returning to the bottom clears it.
200
+ if (!timeline.isPinned())
168
201
  setNewFactsCount(current => current + additions.length);
169
- return;
170
- }
171
202
  const priorSequence = sequenceRef.current;
172
203
  if (await readCurrent(true))
173
204
  return;
174
205
  // The durable acknowledgment did not happen (it failed, a newer read
175
- // superseded it, or the page unmounted); fall back to the explicit
176
- // action unless that newer read now owns the tail.
206
+ // superseded it, or the page unmounted); the count keeps the jump hint
207
+ // visible unless that newer read now owns the tail.
177
208
  if (!mountedRef.current || sequenceRef.current !== priorSequence + 1)
178
209
  return;
179
210
  setNewFactsCount(current => current + additions.length);
@@ -184,6 +215,7 @@ export function TeamThreadPage(props) {
184
215
  };
185
216
  useEffect(() => {
186
217
  mountedRef.current = true;
218
+ projectionRef.current = undefined;
187
219
  setProjection(undefined);
188
220
  setChannelView(undefined);
189
221
  setMembers([]);
@@ -193,7 +225,7 @@ export function TeamThreadPage(props) {
193
225
  setReadFacts([]);
194
226
  setHistoryCursor(undefined);
195
227
  setHistoryHasMore(false);
196
- setRemainingUnreadCount(0);
228
+ setAutoReadExhausted(false);
197
229
  setNewFactsCount(0);
198
230
  setError(undefined);
199
231
  setStatusMessage(undefined);
@@ -215,9 +247,9 @@ export function TeamThreadPage(props) {
215
247
  return;
216
248
  }
217
249
  updateProjection(read.value);
218
- // Opened onto unread updates: land on the boundary instead of the floor.
219
- if (read.value.facts.some(fact => fact.unread))
220
- timeline.jumpToBoundary();
250
+ // The Thread opens at the latest fact; the unread boundary stays
251
+ // rendered as information, but reading is automatic from here on.
252
+ timeline.scrollToBottom();
221
253
  if (history !== undefined && history.ok) {
222
254
  setCurrentFacts(current => {
223
255
  const merged = mergeFacts(current, history.value.facts);
@@ -229,6 +261,7 @@ export function TeamThreadPage(props) {
229
261
  }
230
262
  setError(undefined);
231
263
  setLoading(false);
264
+ await drainUnread();
232
265
  })();
233
266
  void refreshSupplemental();
234
267
  const disposers = [
@@ -258,6 +291,13 @@ export function TeamThreadPage(props) {
258
291
  dispose();
259
292
  };
260
293
  }, [workspaceId, taskRef, threadRef]);
294
+ // Returning to the bottom is the reader's answer to the jump hint: the
295
+ // arrivals are on screen, their durable read already happened (or will be
296
+ // retried by the next change wake), and the hint has nothing left to say.
297
+ useEffect(() => {
298
+ if (newFactsCount > 0 && timeline.isPinned())
299
+ setNewFactsCount(0);
300
+ }, [newFactsCount, currentFacts, olderFacts, timeline]);
261
301
  const loadOlder = async () => {
262
302
  if (historyHasMore === false && historyCursor === undefined)
263
303
  return;
@@ -379,7 +419,7 @@ export function TeamThreadPage(props) {
379
419
  }
380
420
  flushRun();
381
421
  if (boundaryIndex === index)
382
- nodes.push(_jsx("p", { className: threadCss.unreadBoundary, role: "separator", "data-thread-boundary": true, children: _jsx("span", { children: t('unreadBoundary') }) }, `boundary-${index}`));
422
+ nodes.push(_jsx("p", { className: threadCss.unreadBoundary, role: "separator", children: _jsx("span", { children: t('unreadBoundary') }) }, `boundary-${index}`));
383
423
  if (sender !== undefined)
384
424
  run.push(fact);
385
425
  else
@@ -389,9 +429,10 @@ export function TeamThreadPage(props) {
389
429
  return nodes;
390
430
  };
391
431
  const refreshAfterFence = async () => {
392
- timeline.jumpToLatest();
432
+ timeline.scrollToBottom();
393
433
  await readCurrent(true);
394
434
  await refreshSupplemental();
435
+ await drainUnread();
395
436
  };
396
437
  const convertToTask = async () => {
397
438
  if (pending || thread === undefined || task !== undefined)
@@ -596,7 +637,7 @@ export function TeamThreadPage(props) {
596
637
  })(), 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 => {
597
638
  const ownerStatus = members.find(status => status.member.memberId === claim.owner);
598
639
  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);
599
- })] }) }) })] }), _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'
640
+ })] }) }) })] }), _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) }), autoReadExhausted && _jsxs("div", { className: css.timelineAction, role: "alert", children: [_jsx("span", { children: t('autoReadIncomplete') }), _jsx(Button, { size: "sm", onClick: () => { setAutoReadExhausted(false); void drainUnread(); }, disabled: loading, children: t('retry') })] }), newFactsCount > 0 && _jsx("div", { className: threadCss.newUpdates, role: "status", children: _jsx("button", { type: "button", className: threadCss.newUpdatesJump, onClick: timeline.scrollToBottom, children: t('newUpdatesJump', { count: newFactsCount }) }) })] }) }), projection !== undefined && thread !== undefined ? (task?.resolution === 'closed'
600
641
  ? _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') })] })] })
601
642
  : _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", {})] });
602
643
  }
@@ -1,3 +1,3 @@
1
1
  import type { TeamSidebarProps } from './slots.ts';
2
- export declare function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, t, useWorkspaces, loadMembers, subscribeChanges, addMember, loadChannels, createChannel, updateChannel, updateMember, recoverMember, clearMemberContext, joinChannel, removeChannelMember, loadModels, openMemberSession }: TeamSidebarProps): import("react").JSX.Element;
2
+ export declare function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, t, useWorkspaces, loadMembers, subscribeChanges, addMember, loadChannels, createChannel, updateChannel, archiveChannel, updateMember, recoverMember, clearMemberContext, archiveMember, joinChannel, removeChannelMember, loadModels, openMemberSession }: TeamSidebarProps): import("react").JSX.Element;
3
3
  //# sourceMappingURL=TeamWorkspaceBrowser.d.ts.map
@@ -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;AAUlD,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,kBAAkB,EAAE,WAAW,EAAE,mBAAmB,EAAE,UAAU,EAAE,iBAAiB,EAAE,EAAE,gBAAgB,+BA8DnV"}
1
+ {"version":3,"file":"TeamWorkspaceBrowser.d.ts","sourceRoot":"","sources":["../../../src/client/TeamWorkspaceBrowser.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAUlD,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,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,aAAa,EAAE,WAAW,EAAE,mBAAmB,EAAE,UAAU,EAAE,iBAAiB,EAAE,EAAE,gBAAgB,+BA8DlX"}
@@ -7,7 +7,7 @@ import { useSidebarSectionOpen, setSidebarSectionOpen } from "./sidebar-sections
7
7
  import { TeamAgentsPanel } from "./TeamAgentsPanel.js";
8
8
  import { TeamChannelsPanel } from "./TeamChannelsPanel.js";
9
9
  import css from './sidebar.module.css';
10
- export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, t, useWorkspaces, loadMembers, subscribeChanges, addMember, loadChannels, createChannel, updateChannel, updateMember, recoverMember, clearMemberContext, joinChannel, removeChannelMember, loadModels, openMemberSession }) {
10
+ export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, t, useWorkspaces, loadMembers, subscribeChanges, addMember, loadChannels, createChannel, updateChannel, archiveChannel, updateMember, recoverMember, clearMemberContext, archiveMember, joinChannel, removeChannelMember, loadModels, openMemberSession }) {
11
11
  const navigationState = useSyncExternalStore(navigation.subscribe, navigation.getSnapshot, navigation.getSnapshot);
12
12
  const workspaces = useWorkspaces(state => state.items);
13
13
  const selected = navigationState.workspaceId;
@@ -39,5 +39,5 @@ export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWo
39
39
  if (!wide) {
40
40
  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 }) }) })] });
41
41
  }
42
- return _jsxs("section", { className: css.workspaceBrowser, "aria-label": t('workspaces'), children: [_jsx(TeamSidebarSection, { title: t('workspaces'), open: workspacesOpen, onToggle: open => { setSidebarSectionOpen(undefined, 'workspaces', open); }, children: _jsxs("div", { className: css.workspaceList, children: [workspaces.map(workspace => _jsx(TeamWorkspaceRow, { workspaceId: workspace.workspaceId, title: workspace.title, path: workspace.path, selected: workspace.workspaceId === selectedId, current: workspace.workspaceId === selectedId && overviewIsCurrent, onSelect: selectWorkspace }, workspace.workspaceId)), workspaces.length === 0 && _jsx("p", { className: css.emptyState, children: t('empty') })] }) }), selectedId !== undefined && _jsxs("div", { className: css.workspaceSection, children: [_jsx("div", { ref: channelsRef, children: _jsx(TeamChannelsPanel, { workspaceId: selectedId, loadMembers: loadMembers, loadChannels: loadChannels, subscribeChanges: subscribeChanges, createChannel: createChannel, updateChannel: updateChannel, 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, clearMemberContext: clearMemberContext, 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) })] })] });
42
+ return _jsxs("section", { className: css.workspaceBrowser, "aria-label": t('workspaces'), children: [_jsx(TeamSidebarSection, { title: t('workspaces'), open: workspacesOpen, onToggle: open => { setSidebarSectionOpen(undefined, 'workspaces', open); }, children: _jsxs("div", { className: css.workspaceList, children: [workspaces.map(workspace => _jsx(TeamWorkspaceRow, { workspaceId: workspace.workspaceId, title: workspace.title, path: workspace.path, selected: workspace.workspaceId === selectedId, current: workspace.workspaceId === selectedId && overviewIsCurrent, onSelect: selectWorkspace }, workspace.workspaceId)), workspaces.length === 0 && _jsx("p", { className: css.emptyState, children: t('empty') })] }) }), selectedId !== undefined && _jsxs("div", { className: css.workspaceSection, children: [_jsx("div", { ref: channelsRef, children: _jsx(TeamChannelsPanel, { workspaceId: selectedId, loadMembers: loadMembers, loadChannels: loadChannels, subscribeChanges: subscribeChanges, createChannel: createChannel, updateChannel: updateChannel, archiveChannel: archiveChannel, joinChannel: joinChannel, removeChannelMember: removeChannelMember, creatingAgents: creatingAgents.filter(request => request.workspaceId === selectedId), ...(navigationState.memberSessionId !== undefined || navigationState.channelRef === undefined ? {} : { selectedChannelRef: navigationState.channelRef }), selectChannel: selectChannel, t: t }, selectedId) }), _jsx("div", { ref: agentsRef, children: _jsx(TeamAgentsPanel, { workspaceId: selectedId, loadMembers: loadMembers, subscribeChanges: subscribeChanges, addMember: addMember, updateMember: updateMember, recoverMember: recoverMember, clearMemberContext: clearMemberContext, archiveMember: archiveMember, 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) })] })] });
43
43
  }
@@ -1,4 +1,4 @@
1
- import type { WorkspaceId } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { WorkspaceId } from '@deepseek-ai/dsh-api-workspace-controller/client';
2
2
  export declare function TeamWorkspaceRow({ workspaceId, title, path, selected, current, onSelect }: {
3
3
  workspaceId: WorkspaceId;
4
4
  title: string;
@@ -1 +1 @@
1
- {"version":3,"file":"TeamWorkspaceRow.d.ts","sourceRoot":"","sources":["../../../src/client/TeamWorkspaceRow.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAGzE,wBAAgB,gBAAgB,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE;IAC1F,WAAW,EAAE,WAAW,CAAA;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;IACjB,4EAA4E;IAC5E,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,IAAI,CAAA;CAC7C,+BAgBA"}
1
+ {"version":3,"file":"TeamWorkspaceRow.d.ts","sourceRoot":"","sources":["../../../src/client/TeamWorkspaceRow.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAGnF,wBAAgB,gBAAgB,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE;IAC1F,WAAW,EAAE,WAAW,CAAA;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;IACjB,4EAA4E;IAC5E,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,IAAI,CAAA;CAC7C,+BAgBA"}
@@ -1,4 +1,4 @@
1
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { Context as ClientContext } from '@deepseek-ai/cordis';
2
2
  import { TeamNavigation } from './navigation.ts';
3
3
  import { TeamDraftStore } from './drafts.ts';
4
4
  import { type TeamKey } from './locales.ts';
@@ -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;AAiCtF,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;AA0ND,wBAAsB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAoCnE,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;AAuND,wBAAsB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D"}
@@ -6,13 +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";
9
+ import { TeamMemberDock } from "./TeamMemberDock.js";
10
10
  import { admitTeamCompact, createTeamMemberSessionSources } from "./member-session-input.js";
11
11
  import { en, zh } from "./locales.js";
12
12
  export { TeamNavigation } from "./navigation.js";
13
13
  const NS = 'team';
14
14
  export const inject = [
15
- 'slots', 'workspaces', 'locale', 'remote', 'sessions', 'connection', 'conversation', 'inputTriggers',
15
+ 'slots', 'workspaces', 'locale', 'remote', 'remote.session', 'sessions', 'connection', 'conversation', 'inputTriggers',
16
16
  ];
17
17
  function registerModeShadow(ctx, navigation, changes, drafts, name, component, extraInject) {
18
18
  // Stay in Team mode: the conversation shadow stands down for Member Session
@@ -37,15 +37,13 @@ function registerModeShadow(ctx, navigation, changes, drafts, name, component, e
37
37
  joinChannel: (request) => ctx.remote.agentTeam.joinChannel(request),
38
38
  removeChannelMember: (request) => ctx.remote.agentTeam.removeChannelMember(request),
39
39
  updateChannel: (request) => ctx.remote.agentTeam.updateChannel(request),
40
+ archiveChannel: (request) => ctx.remote.agentTeam.archiveChannel(request),
40
41
  updateMember: (request) => ctx.remote.agentTeam.updateMember(request),
41
42
  recoverMember: (request) => ctx.remote.agentTeam.recoverMember(request),
42
43
  clearMemberContext: (request) => ctx.remote.agentTeam.clearMemberContext(request),
44
+ archiveMember: (request) => ctx.remote.agentTeam.archiveMember(request),
43
45
  // The Host-scoped catalog needs no live Member, so suspended ones stay editable too.
44
- loadModels: async () => {
45
- const connection = ctx.get('connection');
46
- const response = await connection.api.llm.models({});
47
- return response.result;
48
- },
46
+ loadModels: () => ctx.remote.session.modelCatalog(),
49
47
  openMemberSession: openMemberSessionImpl,
50
48
  };
51
49
  ctx.slots.inject(name, () => {
@@ -98,8 +96,13 @@ function registerModeShadow(ctx, navigation, changes, drafts, name, component, e
98
96
  };
99
97
  });
100
98
  }
101
- function registerMemberSessionComposer(ctx, navigation) {
102
- ctx.slots.inject('conversation.composer.bar', () => {
99
+ function registerMemberSessionDock(ctx, navigation) {
100
+ // rc.1: the shipped InputBar owns `conversation.composer.bar` and with it
101
+ // the trigger-menu overlay; shadowing it stranded the menus inside a hidden
102
+ // subtree. The Team surface moves to the public input-dock list slot above
103
+ // the shipped bar — it renders in both the hero (blank session) and active
104
+ // composer forms, so the strip stays visible from the very first turn.
105
+ ctx.slots.inject('conversation.input.dock', () => {
103
106
  let dispose;
104
107
  let registeredSessionId;
105
108
  const reconcile = () => {
@@ -112,25 +115,16 @@ function registerMemberSessionComposer(ctx, navigation) {
112
115
  }
113
116
  if (active && dispose === undefined) {
114
117
  registeredSessionId = memberSessionId;
118
+ const sessions = ctx.sessions;
115
119
  dispose = ctx.slots.register({
116
- name: 'conversation.composer.bar',
117
- priority: -100,
120
+ name: 'conversation.input.dock',
121
+ id: 'agent-team-member',
122
+ locale: NS,
118
123
  // The registration may remain live during a session transition, but
119
- // it elects only when the shell's current Session is the embedded
120
- // Member. This avoids taking an ordinary Session if selection races.
121
- select: () => ctx.sessions.list.getSnapshot().current === memberSessionId ? {} : null,
122
- inject: (sessionId) => {
123
- const actx = ctx.sessions.scope(sessionId);
124
- if (actx === undefined)
125
- throw new Error(`agent-team: Member session ${String(sessionId)} has no client scope`);
126
- const sessions = ctx.sessions;
127
- return {
128
- controller: ctx.get('inputTriggers').sessionOf(actx),
129
- stop: () => { void sessions.sessionOf(actx)?.cancel(); },
130
- submitInput: (mode) => ctx.conversation.input.for(actx).submit(mode),
131
- };
132
- },
133
- }, TeamMemberSessionComposer);
124
+ // it shows only when the shell's current Session is the embedded
125
+ // Member. This avoids stamping an ordinary Session if selection races.
126
+ select: () => sessions.list.getSnapshot().current === memberSessionId ? {} : null,
127
+ }, TeamMemberDock);
134
128
  }
135
129
  };
136
130
  const offNavigation = navigation.subscribe(reconcile);
@@ -184,7 +178,10 @@ function applyUi(ctx) {
184
178
  const result = await ctx.remote.agentTeam.members({ workspaceId: workspace.workspaceId });
185
179
  if (!result.ok)
186
180
  throw new Error(result.error.message);
187
- return { workspaceId: workspace.workspaceId, workspaceTitle: workspace.title, members: result.value };
181
+ // The members modal is a listing surface: archived Members are hidden
182
+ // everywhere, and removed (inactive) ones never belong in a roster.
183
+ const members = result.value.filter(status => status.member.state !== 'inactive' && status.member.state !== 'archived');
184
+ return { workspaceId: workspace.workspaceId, workspaceTitle: workspace.title, members };
188
185
  }));
189
186
  return groups.filter(group => group.members.length > 0);
190
187
  };
@@ -216,7 +213,7 @@ function applyUi(ctx) {
216
213
  }, TeamFooterAction));
217
214
  registerModeShadow(ctx, navigation, changes, drafts, 'sidebar.workspaces', TeamWorkspaceBrowser);
218
215
  registerModeShadow(ctx, navigation, changes, drafts, 'conversation', TeamConversation);
219
- registerMemberSessionComposer(ctx, navigation);
216
+ registerMemberSessionDock(ctx, navigation);
220
217
  registerModeShadow(ctx, navigation, changes, drafts, 'sidebar.settings', TeamSettings, () => ({ loadMemberGroups }));
221
218
  }
222
219
  export async function apply(ctx) {
@@ -12,11 +12,13 @@ export declare const zh: {
12
12
  readonly addAgent: "添加 Agent";
13
13
  readonly cancel: "取消";
14
14
  readonly close: "关闭";
15
+ readonly memberSessionHint: "成员会话:/compact 压缩上下文 · @成员 引用;普通消息直接发给该成员。";
16
+ readonly copyCode: "复制";
17
+ readonly copiedCode: "已复制";
18
+ readonly markdownFootnotes: "脚注";
15
19
  readonly retry: "重试";
16
20
  readonly agentName: "名称";
17
21
  readonly agentDescription: "说明";
18
- readonly initialChannels: "初始频道";
19
- readonly noChannelsForAgent: "请先创建至少一个频道";
20
22
  readonly createAgent: "创建 Agent";
21
23
  readonly creatingAgent: "正在创建…";
22
24
  readonly loadingAgents: "正在加载 Agents…";
@@ -47,10 +49,18 @@ export declare const zh: {
47
49
  readonly clearContextNotice: "将结束 {name} 当前的会话上下文并从空白开始:旧对话会归档保留在会话记录中。{name} 的身份、私有记忆与 notes、频道和会话绑定都保持不变,后续协作从新上下文继续累积。";
48
50
  readonly clearContextConfirm: "开始全新上下文";
49
51
  readonly clearContextFailed: "清空上下文失败:{message}";
52
+ readonly archiveAgent: "归档";
53
+ readonly archiveAgentTitle: "归档 Agent:{name}";
54
+ readonly archiveAgentNotice: "将把 {name} 从所有列表收起:会话与私有记忆保留在磁盘上、活跃 Claim 会释放,但暂无恢复入口。";
55
+ readonly archiveAgentConfirm: "归档";
56
+ readonly archiveAgentFailed: "归档失败:{message}";
57
+ readonly archiveChannel: "归档频道";
58
+ readonly archiveChannelTitle: "归档频道:{name}";
59
+ readonly archiveChannelNotice: "将把 {name} 及其全部讨论从所有列表收起:数据保留、所有成员在此频道的活跃 Claim 会释放,但暂无恢复入口。";
60
+ readonly archiveChannelConfirm: "归档频道";
61
+ readonly archiveChannelFailed: "归档频道失败:{message}";
50
62
  readonly optionalSuffix: "(可选)";
51
63
  readonly agentDescriptionPlaceholder: "留空则暂无描述";
52
- readonly channelsPickerEmpty: "选择初始频道";
53
- readonly channelsPickerCount: "已选 {count} 个频道";
54
64
  readonly membersPickerEmpty: "选择初始成员";
55
65
  readonly membersPickerCount: "已选 {count} 个成员";
56
66
  readonly reasoningEffort: "推理强度";
@@ -112,10 +122,8 @@ export declare const zh: {
112
122
  readonly backToWorkspace: "返回工作区";
113
123
  readonly loadingThread: "正在加载 Thread…";
114
124
  readonly unreadBoundary: "以下是本次打开收到的更新";
115
- readonly readNewUpdates: "读取 {count} 条新更新";
116
- readonly markRead: "标记为已读";
117
- readonly remainingUnread: "还有 {count} 条未读更新";
118
- readonly continueReading: "继续阅读";
125
+ readonly newUpdatesJump: " {count} 条新更新";
126
+ readonly autoReadIncomplete: "仍有未读更新未能自动读取";
119
127
  readonly olderHistory: "更早历史";
120
128
  readonly runtimeRisk: "当前运行风险";
121
129
  readonly runtimeRiskDetail: "@{member} 当前不可用:{diagnostic}";
@@ -160,11 +168,13 @@ export declare const en: {
160
168
  readonly addAgent: "Add Agent";
161
169
  readonly cancel: "Cancel";
162
170
  readonly close: "Close";
171
+ readonly memberSessionHint: "Member session: /compact compresses context · @member inserts a reference; plain messages go straight to the member.";
172
+ readonly copyCode: "Copy";
173
+ readonly copiedCode: "Copied";
174
+ readonly markdownFootnotes: "Footnotes";
163
175
  readonly retry: "Retry";
164
176
  readonly agentName: "Name";
165
177
  readonly agentDescription: "Description";
166
- readonly initialChannels: "Initial Channels";
167
- readonly noChannelsForAgent: "Create at least one Channel first";
168
178
  readonly createAgent: "Create Agent";
169
179
  readonly creatingAgent: "Creating…";
170
180
  readonly loadingAgents: "Loading Agents…";
@@ -195,10 +205,18 @@ export declare const en: {
195
205
  readonly clearContextNotice: "This ends {name}'s current session context and starts blank: the previous conversation is archived and stays in the session history. {name}'s identity, private memory and notes, channel and session bindings are untouched, and future collaboration accumulates from the new context.";
196
206
  readonly clearContextConfirm: "Start from new context";
197
207
  readonly clearContextFailed: "Failed to clear context: {message}";
208
+ readonly archiveAgent: "Archive";
209
+ readonly archiveAgentTitle: "Archive Agent: {name}";
210
+ readonly archiveAgentNotice: "This hides {name} from every list: the session log and private memory stay on disk and active Claims release, but there is no restore entry point yet.";
211
+ readonly archiveAgentConfirm: "Archive";
212
+ readonly archiveAgentFailed: "Failed to archive: {message}";
213
+ readonly archiveChannel: "Archive Channel";
214
+ readonly archiveChannelTitle: "Archive Channel: {name}";
215
+ readonly archiveChannelNotice: "This hides {name} and all of its discussions from every list: the data stays, every Member's active Claims in this Channel release, but there is no restore entry point yet.";
216
+ readonly archiveChannelConfirm: "Archive Channel";
217
+ readonly archiveChannelFailed: "Failed to archive Channel: {message}";
198
218
  readonly optionalSuffix: " (optional)";
199
219
  readonly agentDescriptionPlaceholder: "Leave empty if not needed";
200
- readonly channelsPickerEmpty: "Choose initial channels";
201
- readonly channelsPickerCount: "{count} selected";
202
220
  readonly membersPickerEmpty: "Choose initial members";
203
221
  readonly membersPickerCount: "{count} selected";
204
222
  readonly reasoningEffort: "Reasoning effort";
@@ -260,10 +278,8 @@ export declare const en: {
260
278
  readonly backToWorkspace: "Back to Workspace";
261
279
  readonly loadingThread: "Loading Thread…";
262
280
  readonly unreadBoundary: "Updates received when you opened this Thread";
263
- readonly readNewUpdates: "Read {count} new update(s)";
264
- readonly markRead: "Mark read";
265
- readonly remainingUnread: "{count} unread update(s) remain";
266
- readonly continueReading: "Continue reading";
281
+ readonly newUpdatesJump: " {count} new update(s)";
282
+ readonly autoReadIncomplete: "Some unread updates could not be read automatically";
267
283
  readonly olderHistory: "Older history";
268
284
  readonly runtimeRisk: "Current runtime risk";
269
285
  readonly runtimeRiskDetail: "@{member} is unavailable: {diagnostic}";
@@ -1 +1 @@
1
- {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmJL,CAAA;AAEV,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmJL,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2JL,CAAA;AAEV,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2JL,CAAA;AAEV,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,EAAE,CAAA"}
@@ -12,11 +12,13 @@ export const zh = {
12
12
  addAgent: '添加 Agent',
13
13
  cancel: '取消',
14
14
  close: '关闭',
15
+ memberSessionHint: '成员会话:/compact 压缩上下文 · @成员 引用;普通消息直接发给该成员。',
16
+ copyCode: '复制',
17
+ copiedCode: '已复制',
18
+ markdownFootnotes: '脚注',
15
19
  retry: '重试',
16
20
  agentName: '名称',
17
21
  agentDescription: '说明',
18
- initialChannels: '初始频道',
19
- noChannelsForAgent: '请先创建至少一个频道',
20
22
  createAgent: '创建 Agent',
21
23
  creatingAgent: '正在创建…',
22
24
  loadingAgents: '正在加载 Agents…',
@@ -47,10 +49,18 @@ export const zh = {
47
49
  clearContextNotice: '将结束 {name} 当前的会话上下文并从空白开始:旧对话会归档保留在会话记录中。{name} 的身份、私有记忆与 notes、频道和会话绑定都保持不变,后续协作从新上下文继续累积。',
48
50
  clearContextConfirm: '开始全新上下文',
49
51
  clearContextFailed: '清空上下文失败:{message}',
52
+ archiveAgent: '归档',
53
+ archiveAgentTitle: '归档 Agent:{name}',
54
+ archiveAgentNotice: '将把 {name} 从所有列表收起:会话与私有记忆保留在磁盘上、活跃 Claim 会释放,但暂无恢复入口。',
55
+ archiveAgentConfirm: '归档',
56
+ archiveAgentFailed: '归档失败:{message}',
57
+ archiveChannel: '归档频道',
58
+ archiveChannelTitle: '归档频道:{name}',
59
+ archiveChannelNotice: '将把 {name} 及其全部讨论从所有列表收起:数据保留、所有成员在此频道的活跃 Claim 会释放,但暂无恢复入口。',
60
+ archiveChannelConfirm: '归档频道',
61
+ archiveChannelFailed: '归档频道失败:{message}',
50
62
  optionalSuffix: '(可选)',
51
63
  agentDescriptionPlaceholder: '留空则暂无描述',
52
- channelsPickerEmpty: '选择初始频道',
53
- channelsPickerCount: '已选 {count} 个频道',
54
64
  membersPickerEmpty: '选择初始成员',
55
65
  membersPickerCount: '已选 {count} 个成员',
56
66
  reasoningEffort: '推理强度',
@@ -112,10 +122,8 @@ export const zh = {
112
122
  backToWorkspace: '返回工作区',
113
123
  loadingThread: '正在加载 Thread…',
114
124
  unreadBoundary: '以下是本次打开收到的更新',
115
- readNewUpdates: '读取 {count} 条新更新',
116
- markRead: '标记为已读',
117
- remainingUnread: '还有 {count} 条未读更新',
118
- continueReading: '继续阅读',
125
+ newUpdatesJump: ' {count} 条新更新',
126
+ autoReadIncomplete: '仍有未读更新未能自动读取',
119
127
  olderHistory: '更早历史',
120
128
  runtimeRisk: '当前运行风险',
121
129
  runtimeRiskDetail: '@{member} 当前不可用:{diagnostic}',
@@ -160,11 +168,13 @@ export const en = {
160
168
  addAgent: 'Add Agent',
161
169
  cancel: 'Cancel',
162
170
  close: 'Close',
171
+ memberSessionHint: 'Member session: /compact compresses context · @member inserts a reference; plain messages go straight to the member.',
172
+ copyCode: 'Copy',
173
+ copiedCode: 'Copied',
174
+ markdownFootnotes: 'Footnotes',
163
175
  retry: 'Retry',
164
176
  agentName: 'Name',
165
177
  agentDescription: 'Description',
166
- initialChannels: 'Initial Channels',
167
- noChannelsForAgent: 'Create at least one Channel first',
168
178
  createAgent: 'Create Agent',
169
179
  creatingAgent: 'Creating…',
170
180
  loadingAgents: 'Loading Agents…',
@@ -195,10 +205,18 @@ export const en = {
195
205
  clearContextNotice: 'This ends {name}\'s current session context and starts blank: the previous conversation is archived and stays in the session history. {name}\'s identity, private memory and notes, channel and session bindings are untouched, and future collaboration accumulates from the new context.',
196
206
  clearContextConfirm: 'Start from new context',
197
207
  clearContextFailed: 'Failed to clear context: {message}',
208
+ archiveAgent: 'Archive',
209
+ archiveAgentTitle: 'Archive Agent: {name}',
210
+ archiveAgentNotice: 'This hides {name} from every list: the session log and private memory stay on disk and active Claims release, but there is no restore entry point yet.',
211
+ archiveAgentConfirm: 'Archive',
212
+ archiveAgentFailed: 'Failed to archive: {message}',
213
+ archiveChannel: 'Archive Channel',
214
+ archiveChannelTitle: 'Archive Channel: {name}',
215
+ archiveChannelNotice: 'This hides {name} and all of its discussions from every list: the data stays, every Member\'s active Claims in this Channel release, but there is no restore entry point yet.',
216
+ archiveChannelConfirm: 'Archive Channel',
217
+ archiveChannelFailed: 'Failed to archive Channel: {message}',
198
218
  optionalSuffix: ' (optional)',
199
219
  agentDescriptionPlaceholder: 'Leave empty if not needed',
200
- channelsPickerEmpty: 'Choose initial channels',
201
- channelsPickerCount: '{count} selected',
202
220
  membersPickerEmpty: 'Choose initial members',
203
221
  membersPickerCount: '{count} selected',
204
222
  reasoningEffort: 'Reasoning effort',
@@ -260,10 +278,8 @@ export const en = {
260
278
  backToWorkspace: 'Back to Workspace',
261
279
  loadingThread: 'Loading Thread…',
262
280
  unreadBoundary: 'Updates received when you opened this Thread',
263
- readNewUpdates: 'Read {count} new update(s)',
264
- markRead: 'Mark read',
265
- remainingUnread: '{count} unread update(s) remain',
266
- continueReading: 'Continue reading',
281
+ newUpdatesJump: ' {count} new update(s)',
282
+ autoReadIncomplete: 'Some unread updates could not be read automatically',
267
283
  olderHistory: 'Older history',
268
284
  runtimeRisk: 'Current runtime risk',
269
285
  runtimeRiskDetail: '@{member} is unavailable: {diagnostic}',
@@ -1,5 +1,5 @@
1
1
  import type { AgentTeamClientMemberStatus } from '@wowyuarm/dsh-agent-team/types';
2
- import type { ISession } from '@deepseek-ai/dsh-client-runtime/client';
2
+ import type { ISession } from '@deepseek-ai/dsh-api-session-controller/client';
3
3
  import type { ClientSessionContext, InputTriggerSource, SubmitOutcome } from '@deepseek-ai/dsh-client-ui-input-trigger/client';
4
4
  export declare const TEAM_COMMAND_SOURCE = "agent-team-command";
5
5
  export declare const TEAM_MEMBER_SOURCE = "agent-team-member";
@@ -17,6 +17,4 @@ export declare function admitTeamCompact(session: Pick<ISession, 'command'>): Pr
17
17
  * handle from plain text.
18
18
  */
19
19
  export declare function createTeamMemberSessionSources(options: TeamMemberSessionInputOptions): readonly InputTriggerSource[];
20
- /** Unknown leading slash must never fall into the shipped global palette. */
21
- export declare function allowsMemberSessionSubmit(draft: string, claimToken: string | undefined): boolean;
22
20
  //# sourceMappingURL=member-session-input.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"member-session-input.d.ts","sourceRoot":"","sources":["../../../src/client/member-session-input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAqB,MAAM,gCAAgC,CAAA;AACpG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wCAAwC,CAAA;AACtE,OAAO,KAAK,EACV,oBAAoB,EAAgB,kBAAkB,EAAmB,aAAa,EACvF,MAAM,iDAAiD,CAAA;AAExD,eAAO,MAAM,mBAAmB,uBAAuB,CAAA;AACvD,eAAO,MAAM,kBAAkB,sBAAsB,CAAA;AAErD,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,uBAAuB,EAAE,CAAC,SAAS,EAAE,oBAAoB,CAAC,WAAW,CAAC,KAAK,OAAO,CAAA;IAC3F,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,SAAS,2BAA2B,EAAE,CAAC,CAAA;IACvE,QAAQ,CAAC,cAAc,EAAE,CAAC,SAAS,EAAE,oBAAoB,CAAC,WAAW,CAAC,KAAK,OAAO,CAAC,aAAa,CAAC,CAAA;CAClG;AAED,mFAAmF;AACnF,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAIjG;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,6BAA6B,GAAG,SAAS,kBAAkB,EAAE,CAiEpH;AAED,6EAA6E;AAC7E,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAGhG"}
1
+ {"version":3,"file":"member-session-input.d.ts","sourceRoot":"","sources":["../../../src/client/member-session-input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAqB,MAAM,gCAAgC,CAAA;AACpG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gDAAgD,CAAA;AAC9E,OAAO,KAAK,EACV,oBAAoB,EAAgB,kBAAkB,EAAmB,aAAa,EACvF,MAAM,iDAAiD,CAAA;AAExD,eAAO,MAAM,mBAAmB,uBAAuB,CAAA;AACvD,eAAO,MAAM,kBAAkB,sBAAsB,CAAA;AAErD,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,uBAAuB,EAAE,CAAC,SAAS,EAAE,oBAAoB,CAAC,WAAW,CAAC,KAAK,OAAO,CAAA;IAC3F,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,SAAS,2BAA2B,EAAE,CAAC,CAAA;IACvE,QAAQ,CAAC,cAAc,EAAE,CAAC,SAAS,EAAE,oBAAoB,CAAC,WAAW,CAAC,KAAK,OAAO,CAAC,aAAa,CAAC,CAAA;CAClG;AAED,mFAAmF;AACnF,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAIjG;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,6BAA6B,GAAG,SAAS,kBAAkB,EAAE,CAgFpH"}