@wowyuarm/dsh-agent-team 0.1.12 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +2 -0
  2. package/README.zh.md +2 -0
  3. package/cordis.patch.yml +7 -3
  4. package/package.json +14 -2
  5. package/packages/agent-team/README.md +2 -2
  6. package/packages/agent-team/README.zh.md +2 -2
  7. package/packages/agent-team/lib/index.js +151 -69
  8. package/packages/agent-team/lib/ledger.js +249 -31
  9. package/packages/agent-team/lib/member-context.js +18 -1
  10. package/packages/agent-team/lib/member-runtime.js +5 -4
  11. package/packages/agent-team/lib/mentions.js +48 -24
  12. package/packages/agent-team/lib/spec.js +19 -0
  13. package/packages/agent-team/lib/typert.host.js +187 -41
  14. package/packages/agent-team/lib/typert.remote-client.d.ts +7 -3
  15. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  16. package/packages/agent-team/lib/typert.remote-client.js +132 -27
  17. package/packages/agent-team/lib/types/index.d.ts +32 -7
  18. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  19. package/packages/agent-team/lib/types/ledger.d.ts +46 -2
  20. package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
  21. package/packages/agent-team/lib/types/member-context.d.ts +6 -0
  22. package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
  23. package/packages/agent-team/lib/types/mentions.d.ts +20 -7
  24. package/packages/agent-team/lib/types/mentions.d.ts.map +1 -1
  25. package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
  26. package/packages/agent-team/lib/types/types/entities.d.ts +3 -2
  27. package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
  28. package/packages/agent-team/lib/types/types/operations.d.ts +37 -1
  29. package/packages/agent-team/lib/types/types/operations.d.ts.map +1 -1
  30. package/packages/agent-team/lib/types/types/requests-results.d.ts +50 -10
  31. package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
  32. package/packages/agent-team/lib/types/vendor/storage-sqlite/index.d.ts +87 -0
  33. package/packages/agent-team/lib/types/vendor/storage-sqlite/index.d.ts.map +1 -0
  34. package/packages/agent-team/lib/types/vendor/storage-sqlite/schema.d.ts +59 -0
  35. package/packages/agent-team/lib/types/vendor/storage-sqlite/schema.d.ts.map +1 -0
  36. package/packages/agent-team/lib/types/vendor/storage-sqlite/unit.d.ts +57 -0
  37. package/packages/agent-team/lib/types/vendor/storage-sqlite/unit.d.ts.map +1 -0
  38. package/packages/agent-team/lib/vendor/storage-sqlite/index.js +139 -0
  39. package/packages/agent-team/lib/vendor/storage-sqlite/schema.js +120 -0
  40. package/packages/agent-team/lib/vendor/storage-sqlite/unit.js +132 -0
  41. package/packages/client-agent-team/README.md +1 -1
  42. package/packages/client-agent-team/README.zh.md +1 -1
  43. package/packages/client-agent-team/lib/client.js +603 -343
  44. package/packages/client-agent-team/lib/client.js.map +1 -1
  45. package/packages/client-agent-team/lib/types/client/TeamAgentImport.d.ts +12 -0
  46. package/packages/client-agent-team/lib/types/client/TeamAgentImport.d.ts.map +1 -0
  47. package/packages/client-agent-team/lib/types/client/TeamAgentImport.js +69 -0
  48. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +3 -1
  49. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
  50. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +29 -17
  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 +19 -44
  53. package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts +2 -2
  54. package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts.map +1 -1
  55. package/packages/client-agent-team/lib/types/client/TeamInboxPage.js +15 -14
  56. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts +1 -1
  57. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts.map +1 -1
  58. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
  59. package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +15 -29
  60. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
  61. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
  62. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +2 -2
  63. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  64. package/packages/client-agent-team/lib/types/client/index.js +8 -1
  65. package/packages/client-agent-team/lib/types/client/locales.d.ts +18 -0
  66. package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
  67. package/packages/client-agent-team/lib/types/client/locales.js +18 -0
  68. package/packages/client-agent-team/lib/types/client/slots.d.ts +3 -1
  69. package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
  70. package/packages/client-agent-team/lib/types/client/team-changes.d.ts +15 -31
  71. package/packages/client-agent-team/lib/types/client/team-changes.d.ts.map +1 -1
  72. package/packages/client-agent-team/lib/types/client/team-changes.js +82 -111
  73. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +13 -11
  74. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
  75. package/packages/client-agent-team/lib/types/client/team-formatters.js +29 -35
  76. package/packages/tool-agent-team/README.md +1 -1
  77. package/packages/tool-agent-team/README.zh.md +1 -1
  78. package/packages/tool-agent-team/lib/host-access.js +19 -0
  79. package/packages/tool-agent-team/lib/index.js +42 -33
  80. package/packages/tool-agent-team/lib/types/host-access.d.ts +10 -0
  81. package/packages/tool-agent-team/lib/types/host-access.d.ts.map +1 -1
  82. package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
  83. package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts +0 -41
  84. package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts.map +0 -1
  85. package/packages/client-agent-team/lib/types/client/scope-coverage.js +0 -64
@@ -8,7 +8,6 @@ import { TeamRunDivider } from "./TeamRunDivider.js";
8
8
  import { formatActivity, formatClaimState, formatTaskStatus, formatTaskTitle, mentionNamesOf, mentionedMemberIds, taskStatusDot } from "./team-formatters.js";
9
9
  import { TeamStateDot } from "./TeamStateDot.js";
10
10
  import { mintRequestId, uploadComposerFiles } from "./requests.js";
11
- import { ScopeCoverage } from "./scope-coverage.js";
12
11
  import { daySeparatorLabel, isRunGap, timelineDayKey } from "./team-separators.js";
13
12
  import { useTimelineScroll } from "./timeline-scroll.js";
14
13
  import { hostTaskRefLookup, jumpToTaskThread } from "./task-refs.js";
@@ -189,35 +188,21 @@ export function TeamThreadPage(props) {
189
188
  return mountedRef.current;
190
189
  }
191
190
  };
192
- // One Host change event wakes every scope it matches: here a workspace commit
193
- // and a presence transition, whose separate polls both deliver that event's
194
- // version. Both asks are the same roster and view read, so each round answers
195
- // one version per scope, and a newer version arriving mid-round runs one
196
- // trailing round instead of being dropped. The two scopes count different
197
- // domains, so coverage and pending versions are tracked per scope.
198
191
  const supplementalRef = useRef();
199
- const supplementalCoverageRef = useRef(new ScopeCoverage());
200
- const refreshSupplemental = (wake) => {
201
- const inFlight = supplementalRef.current;
202
- if (wake === undefined) {
203
- if (inFlight !== undefined)
204
- return inFlight;
205
- }
206
- else if (!supplementalCoverageRef.current.wake(wake.scope, wake.version)) {
207
- return inFlight ?? Promise.resolve();
208
- }
209
- const coverage = supplementalCoverageRef.current;
192
+ const supplementalPendingRef = useRef(false);
193
+ const refreshSupplemental = () => {
194
+ supplementalPendingRef.current = true;
195
+ if (supplementalRef.current !== undefined)
196
+ return supplementalRef.current;
210
197
  const round = (async () => {
211
- for (;;) {
212
- coverage.beginRound();
213
- const applied = await applySupplemental();
214
- // A newer change landed while this round fetched: cover it too, and
215
- // keep going only while the page is still the one asking.
216
- if (!applied || !coverage.finishRound())
198
+ // Collect synchronous scope notifications before issuing the shared read.
199
+ await Promise.resolve();
200
+ while (mountedRef.current && supplementalPendingRef.current) {
201
+ supplementalPendingRef.current = false;
202
+ if (!await applySupplemental())
217
203
  return;
218
204
  }
219
205
  })().finally(() => {
220
- // A remount may already own a newer round; only this one clears itself.
221
206
  if (supplementalRef.current === round)
222
207
  supplementalRef.current = undefined;
223
208
  });
@@ -283,7 +268,7 @@ export function TeamThreadPage(props) {
283
268
  mountedRef.current = true;
284
269
  // The previous mount's supplemental round must not answer for this one.
285
270
  supplementalRef.current = undefined;
286
- supplementalCoverageRef.current.reset();
271
+ supplementalPendingRef.current = false;
287
272
  projectionRef.current = undefined;
288
273
  setProjection(undefined);
289
274
  setChannelView(undefined);
@@ -304,7 +289,8 @@ export function TeamThreadPage(props) {
304
289
  setLoading(true);
305
290
  void (async () => {
306
291
  // One parallel round covers the whole first paint. The durable read no
307
- // longer wakes any change scope, so no second wave follows it.
292
+ // longer wakes any change scope; only the subscription baseline can
293
+ // request a catch-up while this first paint is loading.
308
294
  const [read, history, observations] = await Promise.all([
309
295
  readThread({ requestId: readRequestIdRef.current, workspaceId, ...threadRequest }),
310
296
  loadThreadHistory({ workspaceId, ...threadRequest, limit: 20 }).catch(() => undefined),
@@ -356,7 +342,7 @@ export function TeamThreadPage(props) {
356
342
  setError(update.message);
357
343
  return;
358
344
  }
359
- void refreshSupplemental({ scope: 'workspace', version: update.version });
345
+ void refreshSupplemental();
360
346
  }),
361
347
  // Presence transitions commit nothing: only the member rows move, so
362
348
  // the roster refresh rides the same supplemental fetch as workspace
@@ -368,7 +354,7 @@ export function TeamThreadPage(props) {
368
354
  setError(update.message);
369
355
  return;
370
356
  }
371
- void refreshSupplemental({ scope: 'presence', version: update.version });
357
+ void refreshSupplemental();
372
358
  }),
373
359
  ];
374
360
  return () => {
@@ -1,3 +1,3 @@
1
1
  import type { TeamSidebarProps } from './slots.ts';
2
- export declare function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, selectInbox, t, useWorkspaces, loadMembers, loadInbox, subscribeChanges, subscribeReads, addMember, loadChannels, createChannel, updateChannel, archiveChannel, updateMember, recoverMember, archiveMember, joinChannel, removeChannelMember, loadModels, openMemberSession }: TeamSidebarProps): import("react").JSX.Element;
2
+ export declare function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, selectInbox, t, useWorkspaces, loadMembers, loadInbox, subscribeChanges, subscribeReads, addMember, loadChannels, createChannel, updateChannel, archiveChannel, updateMember, recoverMember, archiveMember, joinWorkspace, leaveWorkspace, 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;AAyBlD,wBAAgB,oBAAoB,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,gBAAgB,EAAE,cAAc,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,mBAAmB,EAAE,UAAU,EAAE,iBAAiB,EAAE,EAAE,gBAAgB,+BAoHtY"}
1
+ {"version":3,"file":"TeamWorkspaceBrowser.d.ts","sourceRoot":"","sources":["../../../src/client/TeamWorkspaceBrowser.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAyBlD,wBAAgB,oBAAoB,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,gBAAgB,EAAE,cAAc,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,mBAAmB,EAAE,UAAU,EAAE,iBAAiB,EAAE,EAAE,gBAAgB,+BAoHra"}
@@ -18,7 +18,7 @@ import css from './sidebar.module.css';
18
18
  function InboxMark({ unread }) {
19
19
  return _jsxs("span", { className: css.inboxMark, children: [_jsx(IconQueueOutline14, { size: 16 }), unread > 0 && _jsx("span", { className: css.inboxDot, "data-team-inbox-dot": true, "aria-hidden": "true" })] });
20
20
  }
21
- export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, selectInbox, t, useWorkspaces, loadMembers, loadInbox, subscribeChanges, subscribeReads, addMember, loadChannels, createChannel, updateChannel, archiveChannel, updateMember, recoverMember, archiveMember, joinChannel, removeChannelMember, loadModels, openMemberSession }) {
21
+ export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, selectInbox, t, useWorkspaces, loadMembers, loadInbox, subscribeChanges, subscribeReads, addMember, loadChannels, createChannel, updateChannel, archiveChannel, updateMember, recoverMember, archiveMember, joinWorkspace, leaveWorkspace, joinChannel, removeChannelMember, loadModels, openMemberSession }) {
22
22
  const navigationState = useSyncExternalStore(navigation.subscribe, navigation.getSnapshot, navigation.getSnapshot);
23
23
  const workspaces = useWorkspaces(state => state.items);
24
24
  const selected = navigationState.workspaceId;
@@ -100,5 +100,5 @@ export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWo
100
100
  if (!wide) {
101
101
  return _jsxs("nav", { className: css.railWorkspace, "aria-label": t('workspaceSections'), children: [_jsx(Tooltip, { label: inboxLabel, side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": inboxLabel, "aria-current": inboxIsCurrent ? 'page' : undefined, onClick: () => { selectInbox(); expandSidebar(); }, children: _jsx(InboxMark, { unread: inboxTotal }) }) }), _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 }) }) })] });
102
102
  }
103
- return _jsxs("section", { className: css.workspaceBrowser, "aria-label": t('workspaces'), children: [_jsxs("button", { type: "button", className: css.inboxCard, "aria-label": inboxLabel, "aria-current": inboxIsCurrent ? 'page' : undefined, onClick: selectInbox, children: [_jsx(InboxMark, { unread: inboxTotal }), _jsx("span", { className: css.inboxCardLabel, children: t('inboxTitle') })] }), _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, 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) })] })] });
103
+ return _jsxs("section", { className: css.workspaceBrowser, "aria-label": t('workspaces'), children: [_jsxs("button", { type: "button", className: css.inboxCard, "aria-label": inboxLabel, "aria-current": inboxIsCurrent ? 'page' : undefined, onClick: selectInbox, children: [_jsx(InboxMark, { unread: inboxTotal }), _jsx("span", { className: css.inboxCardLabel, children: t('inboxTitle') })] }), _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, archiveMember: archiveMember, joinWorkspace: joinWorkspace, leaveWorkspace: leaveWorkspace, 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) })] })] });
104
104
  }
@@ -1 +1 @@
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;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;AA6LD,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;AAuCnE,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;AAoMD,wBAAsB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D"}
@@ -46,6 +46,8 @@ entryKey) {
46
46
  recoverMember: (request) => ctx.remote.agentTeam.recoverMember(request),
47
47
  clearMemberContext: (request) => ctx.remote.agentTeam.clearMemberContext(request),
48
48
  archiveMember: (request) => ctx.remote.agentTeam.archiveMember(request),
49
+ joinWorkspace: (request) => ctx.remote.agentTeam.joinWorkspace(request),
50
+ leaveWorkspace: (request) => ctx.remote.agentTeam.leaveWorkspace(request),
49
51
  // The Host-scoped catalog needs no live Member, so suspended ones stay editable too.
50
52
  loadModels: () => ctx.remote.session.modelCatalog(),
51
53
  openMemberSession: openMemberSessionImpl,
@@ -152,7 +154,12 @@ function applyUi(ctx) {
152
154
  restore();
153
155
  };
154
156
  }, 'agent-team: member session restore');
155
- const changes = new TeamChangeStream((request, signal) => ctx.remote.agentTeam.changes(request, signal));
157
+ const changes = new TeamChangeStream(ctx.remote);
158
+ ctx.effect(() => () => changes.dispose(), 'agent-team: change subscriptions');
159
+ // The Harness resumes a live generation across reconnects, but a stream that
160
+ // already ended for good is this layer's to rebuild — and a new Host generation
161
+ // is the one moment the scope it was waiting for can be there again.
162
+ ctx.on('connection/reset', () => { changes.recover(); });
156
163
  const reads = new TeamReadStream();
157
164
  const loadMemberGroups = async () => {
158
165
  const workspaces = ctx.workspaces.list.getSnapshot().items;
@@ -10,6 +10,15 @@ export declare const zh: {
10
10
  readonly teamMode: "团队模式";
11
11
  readonly workspaceSections: "工作区内容";
12
12
  readonly addAgent: "添加 Agent";
13
+ readonly importAgentTitle: "从其他 Workspace 引入";
14
+ readonly importAgent: "引入";
15
+ readonly importingAgent: "引入中…";
16
+ readonly importAgentNotice: "选择已有 Agent 加入当前 Workspace。身份、记忆与会话保持不变;Channel 仍需另行加入。";
17
+ readonly emptyImportAgents: "没有可引入的 Agent。";
18
+ readonly withdrawAgent: "从此 Workspace 撤回";
19
+ readonly withdrawAgentTitle: "撤回 {name}?";
20
+ readonly withdrawAgentNotice: "仅撤出当前 Workspace:退出此处所有 Channel、释放活跃 Claim 并清除 Attention。其他 Workspace 的工作、会话和私有记忆不受影响。";
21
+ readonly archiveOtherWorkspaces: "同时从其他 {count} 个 Workspace 收起。";
13
22
  readonly cancel: "取消";
14
23
  readonly close: "关闭";
15
24
  readonly copyCode: "复制";
@@ -177,6 +186,15 @@ export declare const en: {
177
186
  readonly teamMode: "Team mode";
178
187
  readonly workspaceSections: "Workspace sections";
179
188
  readonly addAgent: "Add Agent";
189
+ readonly importAgentTitle: "Bring in from another Workspace";
190
+ readonly importAgent: "Bring in";
191
+ readonly importingAgent: "Joining…";
192
+ readonly importAgentNotice: "Choose an existing Agent to join this Workspace. Identity, memory, and session stay unchanged; join Channels separately.";
193
+ readonly emptyImportAgents: "No Agents available to bring in.";
194
+ readonly withdrawAgent: "Withdraw from this Workspace";
195
+ readonly withdrawAgentTitle: "Withdraw {name}?";
196
+ readonly withdrawAgentNotice: "Leave only this Workspace: exit its Channels, release active Claims, and clear Attention. Work elsewhere, the session, and private memory stay unchanged.";
197
+ readonly archiveOtherWorkspaces: "Also hides this Agent in {count} other Workspace(s).";
180
198
  readonly cancel: "Cancel";
181
199
  readonly close: "Close";
182
200
  readonly copyCode: "Copy";
@@ -1 +1 @@
1
- {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsKL,CAAA;AAEV,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsKL,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+KL,CAAA;AAEV,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+KL,CAAA;AAEV,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,EAAE,CAAA"}
@@ -10,6 +10,15 @@ export const zh = {
10
10
  teamMode: '团队模式',
11
11
  workspaceSections: '工作区内容',
12
12
  addAgent: '添加 Agent',
13
+ importAgentTitle: '从其他 Workspace 引入',
14
+ importAgent: '引入',
15
+ importingAgent: '引入中…',
16
+ importAgentNotice: '选择已有 Agent 加入当前 Workspace。身份、记忆与会话保持不变;Channel 仍需另行加入。',
17
+ emptyImportAgents: '没有可引入的 Agent。',
18
+ withdrawAgent: '从此 Workspace 撤回',
19
+ withdrawAgentTitle: '撤回 {name}?',
20
+ withdrawAgentNotice: '仅撤出当前 Workspace:退出此处所有 Channel、释放活跃 Claim 并清除 Attention。其他 Workspace 的工作、会话和私有记忆不受影响。',
21
+ archiveOtherWorkspaces: '同时从其他 {count} 个 Workspace 收起。',
13
22
  cancel: '取消',
14
23
  close: '关闭',
15
24
  copyCode: '复制',
@@ -177,6 +186,15 @@ export const en = {
177
186
  teamMode: 'Team mode',
178
187
  workspaceSections: 'Workspace sections',
179
188
  addAgent: 'Add Agent',
189
+ importAgentTitle: 'Bring in from another Workspace',
190
+ importAgent: 'Bring in',
191
+ importingAgent: 'Joining…',
192
+ importAgentNotice: 'Choose an existing Agent to join this Workspace. Identity, memory, and session stay unchanged; join Channels separately.',
193
+ emptyImportAgents: 'No Agents available to bring in.',
194
+ withdrawAgent: 'Withdraw from this Workspace',
195
+ withdrawAgentTitle: 'Withdraw {name}?',
196
+ withdrawAgentNotice: 'Leave only this Workspace: exit its Channels, release active Claims, and clear Attention. Work elsewhere, the session, and private memory stay unchanged.',
197
+ archiveOtherWorkspaces: 'Also hides this Agent in {count} other Workspace(s).',
180
198
  cancel: 'Cancel',
181
199
  close: 'Close',
182
200
  copyCode: 'Copy',
@@ -1,5 +1,5 @@
1
1
  import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
- import type { AgentTeamAddMemberRequest, AgentTeamArchiveChannelRequest, AgentTeamArchiveChannelResult, AgentTeamArchiveMemberRequest, AgentTeamArchiveMemberResult, AgentTeamChannelRef, AgentTeamClientMemberStatus, AgentTeamClearMemberContextRequest, AgentTeamClearMemberContextResult, AgentTeamCreateChannelRequest, AgentTeamCreateChannelResult, AgentTeamInbox, AgentTeamInboxRequest, AgentTeamJoinChannelRequest, AgentTeamJoinChannelResult, AgentTeamGetAttachmentRequest, AgentTeamGetAttachmentResult, AgentTeamPutAttachmentRequest, AgentTeamPutAttachmentResult, AgentTeamMemberResult, AgentTeamRecoverMemberRequest, AgentTeamRecoverMemberResult, AgentTeamMembersRequest, AgentTeamRemoveChannelMemberRequest, AgentTeamRemoveChannelMemberResult, AgentTeamReplyRequest, AgentTeamResolveTaskRefsRequest, AgentTeamResolveTaskRefsResult, AgentTeamReplyResult, AgentTeamConfirmationRequired, AgentTeamThreadHistory, AgentTeamThreadHistoryRequest, AgentTeamThreadObservations, AgentTeamThreadObservationsRequest, AgentTeamThreadReadRequest, AgentTeamThreadReadResult, AgentTeamPromoteThreadRequest, AgentTeamPromoteThreadResult, AgentTeamTaskRequest, AgentTeamTaskResult, AgentTeamSendMessageRequest, AgentTeamSendMessageResult, AgentTeamUpdateChannelRequest, AgentTeamUpdateChannelResult, AgentTeamUpdateMemberRequest, AgentTeamView, AgentTeamViewRequest } from '@wowyuarm/dsh-agent-team/types';
2
+ import type { AgentTeamAddMemberRequest, AgentTeamArchiveChannelRequest, AgentTeamArchiveChannelResult, AgentTeamArchiveMemberRequest, AgentTeamArchiveMemberResult, AgentTeamChannelRef, AgentTeamClientMemberStatus, AgentTeamClearMemberContextRequest, AgentTeamClearMemberContextResult, AgentTeamCreateChannelRequest, AgentTeamCreateChannelResult, AgentTeamInbox, AgentTeamInboxRequest, AgentTeamJoinWorkspaceRequest, AgentTeamJoinWorkspaceResult, AgentTeamLeaveWorkspaceRequest, AgentTeamLeaveWorkspaceResult, AgentTeamJoinChannelRequest, AgentTeamJoinChannelResult, AgentTeamGetAttachmentRequest, AgentTeamGetAttachmentResult, AgentTeamPutAttachmentRequest, AgentTeamPutAttachmentResult, AgentTeamMemberResult, AgentTeamRecoverMemberRequest, AgentTeamRecoverMemberResult, AgentTeamMembersRequest, AgentTeamRemoveChannelMemberRequest, AgentTeamRemoveChannelMemberResult, AgentTeamReplyRequest, AgentTeamResolveTaskRefsRequest, AgentTeamResolveTaskRefsResult, AgentTeamReplyResult, AgentTeamConfirmationRequired, AgentTeamThreadHistory, AgentTeamThreadHistoryRequest, AgentTeamThreadObservations, AgentTeamThreadObservationsRequest, AgentTeamThreadReadRequest, AgentTeamThreadReadResult, AgentTeamPromoteThreadRequest, AgentTeamPromoteThreadResult, AgentTeamTaskRequest, AgentTeamTaskResult, AgentTeamSendMessageRequest, AgentTeamSendMessageResult, AgentTeamUpdateChannelRequest, AgentTeamUpdateChannelResult, AgentTeamUpdateMemberRequest, AgentTeamView, AgentTeamViewRequest } from '@wowyuarm/dsh-agent-team/types';
3
3
  import type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol';
4
4
  import type { TeamNavigationActions, TeamNavigationSnapshot } from './navigation.ts';
5
5
  import type { TeamChangeListener, TeamChangeScope } from './team-changes.ts';
@@ -61,6 +61,8 @@ export type TeamSidebarProps = PropsRuntime<'sidebar.workspaces'> & PropsLocale<
61
61
  */
62
62
  clearMemberContext: (request: AgentTeamClearMemberContextRequest) => Promise<RemoteResult<AgentTeamClearMemberContextResult>>;
63
63
  archiveMember: (request: AgentTeamArchiveMemberRequest) => Promise<RemoteResult<AgentTeamArchiveMemberResult>>;
64
+ joinWorkspace: (request: AgentTeamJoinWorkspaceRequest) => Promise<RemoteResult<AgentTeamJoinWorkspaceResult>>;
65
+ leaveWorkspace: (request: AgentTeamLeaveWorkspaceRequest) => Promise<RemoteResult<AgentTeamLeaveWorkspaceResult>>;
64
66
  joinChannel: (request: AgentTeamJoinChannelRequest) => Promise<RemoteResult<AgentTeamJoinChannelResult>>;
65
67
  removeChannelMember: (request: AgentTeamRemoveChannelMemberRequest) => Promise<RemoteResult<AgentTeamRemoveChannelMemberResult>>;
66
68
  /** Session-independent Host model catalog (`llm.models`); needs no live Member. */
@@ -1 +1 @@
1
- {"version":3,"file":"slots.d.ts","sourceRoot":"","sources":["../../../src/client/slots.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"slots.d.ts","sourceRoot":"","sources":["../../../src/client/slots.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,6 @@
1
- import type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol';
2
- import type { AgentTeamChangeScope, AgentTeamChangesRequest, AgentTeamChangesResult } from '@wowyuarm/dsh-agent-team/types';
3
- /** One poll observes one scope, or every Team change when the scope is omitted. */
1
+ import type { ClientRemote } from '@deepseek-ai/dsh-api-gateway/client';
2
+ import type { AgentTeamChangeScope } from '@wowyuarm/dsh-agent-team/types';
4
3
  export type TeamChangeScope = AgentTeamChangeScope | undefined;
5
- /** One invalidation delivered to every surface subscribed to one scope. */
6
4
  export type TeamChangeUpdate = {
7
5
  readonly type: 'changed';
8
6
  readonly version: number;
@@ -11,35 +9,22 @@ export type TeamChangeUpdate = {
11
9
  readonly message: string;
12
10
  };
13
11
  export type TeamChangeListener = (update: TeamChangeUpdate) => void;
14
- type ChangesFn = (request: AgentTeamChangesRequest, signal?: AbortSignal) => Promise<RemoteResult<AgentTeamChangesResult>>;
15
- /**
16
- * One long-poll per change scope, shared by every listening surface: panels
17
- * and pages never open parallel `changes` requests for the same scope, and
18
- * the poll is aborted as soon as the last subscriber leaves.
19
- *
20
- * A failed call reports the outage to every listener once and then keeps
21
- * retrying with backoff. The transport recovers on its own terms — a Host
22
- * restart, a sleep/wake, a dropped proxy — and a surface that stayed mounted
23
- * has to resume from that recovery rather than stay silent until it remounts,
24
- * so the first answered call after an outage wakes every listener once even
25
- * when the cursor did not move.
26
- *
27
- * Each poll keeps its own cursor, and a cursor only means something inside the
28
- * scope it was issued for: the Host answers a presence scope from a
29
- * process-local wake epoch and every other scope from a durable ledger
30
- * position.
31
- */
12
+ /** One logical stream per scope per page; Harness owns the shared transport and recovery. */
32
13
  export declare class TeamChangeStream {
33
- private readonly changes;
34
- private readonly polls;
14
+ private readonly remote;
15
+ private readonly subscriptions;
16
+ constructor(remote: Pick<ClientRemote, '$stream' | 'agentTeam'>);
17
+ subscribe(scope: TeamChangeScope, listener: TeamChangeListener): () => void;
35
18
  /**
36
- * The last version each scope key answered with, kept after that scope's poll
37
- * is torn down: a commit landing while no poll exists is otherwise folded into
38
- * the replacement poll's opening sample, which reports nothing.
19
+ * Reopen every scope whose stream already ended for good. The Harness resumes a
20
+ * live generation across reconnects, but a terminated one is gone for good: a new
21
+ * Host generation is the moment the scope was waiting for can come back, and the
22
+ * listeners keep their seats, so only the stream is replaced.
39
23
  */
40
- private readonly observed;
41
- constructor(changes: ChangesFn);
42
- subscribe(scope: TeamChangeScope, listener: TeamChangeListener): () => void;
24
+ recover(): void;
25
+ private open;
26
+ dispose(): Promise<void>;
27
+ private fail;
43
28
  private run;
44
29
  }
45
30
  /**
@@ -55,5 +40,4 @@ export declare class TeamReadStream {
55
40
  bump(): void;
56
41
  subscribe(listener: () => void): () => void;
57
42
  }
58
- export {};
59
43
  //# sourceMappingURL=team-changes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"team-changes.d.ts","sourceRoot":"","sources":["../../../src/client/team-changes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAA;AAE3H,mFAAmF;AACnF,MAAM,MAAM,eAAe,GAAG,oBAAoB,GAAG,SAAS,CAAA;AAE9D,2EAA2E;AAC3E,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzD,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAA;AAEnE,KAAK,SAAS,GAAG,CAAC,OAAO,EAAE,uBAAuB,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,sBAAsB,CAAC,CAAC,CAAA;AA8B1H;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,gBAAgB;IASf,OAAO,CAAC,QAAQ,CAAC,OAAO;IARpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+B;IACrD;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;gBAExB,OAAO,EAAE,SAAS;IAE/C,SAAS,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI;YAmB7D,GAAG;CA6DlB;AAED;;;;;;GAMG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAI;IACnB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwB;IAElD,IAAI,IAAI,IAAI;IAKZ,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;CAI5C"}
1
+ {"version":3,"file":"team-changes.d.ts","sourceRoot":"","sources":["../../../src/client/team-changes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,qCAAqC,CAAA;AAErF,OAAO,KAAK,EAAE,oBAAoB,EAA0B,MAAM,gCAAgC,CAAA;AAElG,MAAM,MAAM,eAAe,GAAG,oBAAoB,GAAG,SAAS,CAAA;AAE9D,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzD,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAA;AAiBnE,6FAA6F;AAC7F,qBAAa,gBAAgB;IAGf,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuC;gBAExC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,WAAW,CAAC;IAEhF,SAAS,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI;IAmB3E;;;;;OAKG;IACH,OAAO,IAAI,IAAI;IAYf,OAAO,CAAC,IAAI;IAiBN,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAM9B,OAAO,CAAC,IAAI;YAOE,GAAG;CAclB;AAED;;;;;;GAMG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAI;IACnB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwB;IAElD,IAAI,IAAI,IAAI;IAKZ,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;CAI5C"}
@@ -1,14 +1,4 @@
1
- /** First retry delay after a failed call, doubling up to the cap. */
2
- const RETRY_BASE_MS = 1_000;
3
- const RETRY_MAX_MS = 30_000;
4
- /** Abortable delay: the poll's subscription ending must not wait out a backoff. */
5
- function sleep(ms, signal) {
6
- return new Promise(resolve => {
7
- const done = () => { clearTimeout(timer); signal.removeEventListener('abort', done); resolve(); };
8
- const timer = setTimeout(done, ms);
9
- signal.addEventListener('abort', done, { once: true });
10
- });
11
- }
1
+ import { RemoteStreamCarrierError } from '@deepseek-ai/dsh-api-gateway/client';
12
2
  function scopeKey(scope) {
13
3
  return scope === undefined ? 'all'
14
4
  : scope.kind === 'workspace' ? `workspace:${scope.workspaceId}`
@@ -16,117 +6,98 @@ function scopeKey(scope) {
16
6
  : scope.kind === 'presence' ? `presence:${scope.workspaceId}`
17
7
  : `thread:${scope.threadRef}`;
18
8
  }
19
- /**
20
- * One long-poll per change scope, shared by every listening surface: panels
21
- * and pages never open parallel `changes` requests for the same scope, and
22
- * the poll is aborted as soon as the last subscriber leaves.
23
- *
24
- * A failed call reports the outage to every listener once and then keeps
25
- * retrying with backoff. The transport recovers on its own terms — a Host
26
- * restart, a sleep/wake, a dropped proxy — and a surface that stayed mounted
27
- * has to resume from that recovery rather than stay silent until it remounts,
28
- * so the first answered call after an outage wakes every listener once even
29
- * when the cursor did not move.
30
- *
31
- * Each poll keeps its own cursor, and a cursor only means something inside the
32
- * scope it was issued for: the Host answers a presence scope from a
33
- * process-local wake epoch and every other scope from a durable ledger
34
- * position.
35
- */
9
+ /** One logical stream per scope per page; Harness owns the shared transport and recovery. */
36
10
  export class TeamChangeStream {
37
- changes;
38
- polls = new Map();
39
- /**
40
- * The last version each scope key answered with, kept after that scope's poll
41
- * is torn down: a commit landing while no poll exists is otherwise folded into
42
- * the replacement poll's opening sample, which reports nothing.
43
- */
44
- observed = new Map();
45
- constructor(changes) {
46
- this.changes = changes;
11
+ remote;
12
+ subscriptions = new Map();
13
+ constructor(remote) {
14
+ this.remote = remote;
47
15
  }
48
16
  subscribe(scope, listener) {
49
17
  const key = scopeKey(scope);
50
- let poll = this.polls.get(key);
51
- if (poll === undefined) {
52
- poll = { controller: new AbortController(), listeners: new Set(), resumeFrom: this.observed.get(key) };
53
- this.polls.set(key, poll);
54
- void this.run(key, scope, poll);
18
+ let subscription = this.subscriptions.get(key);
19
+ if (subscription === undefined) {
20
+ subscription = this.open(scope, new Set([listener]));
21
+ this.subscriptions.set(key, subscription);
22
+ void this.run(key, subscription);
23
+ }
24
+ else {
25
+ subscription.listeners.add(listener);
26
+ if (subscription.failure !== undefined)
27
+ listener({ type: 'failed', message: subscription.failure });
55
28
  }
56
- poll.listeners.add(listener);
29
+ const owned = subscription;
57
30
  return () => {
58
- const current = this.polls.get(key);
59
- if (current === undefined || !current.listeners.delete(listener))
31
+ if (!owned.listeners.delete(listener) || owned.listeners.size !== 0)
60
32
  return;
61
- if (current.listeners.size === 0) {
62
- this.polls.delete(key);
63
- current.controller.abort();
64
- }
33
+ if (this.subscriptions.get(key) === owned)
34
+ this.subscriptions.delete(key);
35
+ void owned.stream.dispose();
65
36
  };
66
37
  }
67
- async run(key, scope, poll) {
68
- const { signal } = poll.controller;
69
- const request = (afterVersion) => ({ afterVersion, ...(scope === undefined ? {} : { scope }) });
70
- // No cursor yet means the opening sample still has to be taken. A failed
71
- // call is reported once per outage and then retried, so a recovered
72
- // transport resumes every mounted surface without a remount.
73
- let version = poll.resumeFrom;
74
- let retryDelay = RETRY_BASE_MS;
75
- let reported = false;
76
- while (!signal.aborted) {
77
- const result = await this.changes(request(version ?? 0), signal);
78
- if (signal.aborted || this.polls.get(key) !== poll)
79
- return;
80
- if (!result.ok) {
81
- if (!reported) {
82
- reported = true;
83
- for (const listener of poll.listeners)
84
- listener({ type: 'failed', message: result.error.message });
85
- }
86
- await sleep(retryDelay, signal);
87
- retryDelay = Math.min(retryDelay * 2, RETRY_MAX_MS);
88
- continue;
89
- }
90
- retryDelay = RETRY_BASE_MS;
91
- if (reported) {
92
- // The first answered call after an outage is what recovery looks like
93
- // from here: the Host's parked wait answers on its own deadline even
94
- // when nothing committed, and while the transport was gone each
95
- // surface's own reads failed too. An unchanged cursor is still news to
96
- // them, so the recovery re-anchors every listener once instead of
97
- // waiting for the next unrelated commit.
98
- reported = false;
99
- version = result.value.version;
100
- this.observed.set(key, version);
101
- for (const listener of poll.listeners)
102
- listener({ type: 'changed', version });
103
- continue;
104
- }
105
- if (version === undefined) {
106
- // Nothing has been observed for this scope yet, so there is no cursor to
107
- // resume from: sample the current version silently, because the
108
- // subscribers just fetched their initial projection and an immediate wake
109
- // would double-fetch. This leaves one named gap — a commit landing between
110
- // that initial fetch being processed and this sample being answered is
111
- // missed until the next commit in the scope — which resuming from a known
112
- // version closes for every later subscription.
113
- version = result.value.version;
114
- this.observed.set(key, version);
38
+ /**
39
+ * Reopen every scope whose stream already ended for good. The Harness resumes a
40
+ * live generation across reconnects, but a terminated one is gone for good: a new
41
+ * Host generation is the moment the scope was waiting for can come back, and the
42
+ * listeners keep their seats, so only the stream is replaced.
43
+ */
44
+ recover() {
45
+ // Replacing an existing key's value is safe during Map iteration: the entry keeps
46
+ // its place, and a scope that never failed is left untouched.
47
+ for (const [key, subscription] of this.subscriptions) {
48
+ if (subscription.failure === undefined)
115
49
  continue;
50
+ const replacement = this.open(subscription.scope, subscription.listeners);
51
+ this.subscriptions.set(key, replacement);
52
+ void subscription.stream.dispose();
53
+ void this.run(key, replacement);
54
+ }
55
+ }
56
+ open(scope, listeners) {
57
+ const key = scopeKey(scope);
58
+ const stream = this.remote.$stream({
59
+ name: `Team changes ${key}`,
60
+ open: signal => this.remote.agentTeam.changes(scope === undefined ? {} : { scope }, signal),
61
+ // A normal end after the baseline is an outage, not a verdict: the Harness
62
+ // retries a carrier loss and reports it through `carrierFailed`, while every
63
+ // other error stays terminal. Only an end before the opening baseline is a
64
+ // protocol violation — this stream never yields nothing before it ends.
65
+ ended: accepted => accepted
66
+ ? new RemoteStreamCarrierError('Team change subscription ended without a terminal result')
67
+ : new Error('Team change subscription ended before its opening baseline'),
68
+ carrierFailed: error => this.fail(key, error.message),
69
+ });
70
+ return { scope, stream, listeners, failure: undefined };
71
+ }
72
+ async dispose() {
73
+ const subscriptions = [...this.subscriptions.values()];
74
+ this.subscriptions.clear();
75
+ await Promise.all(subscriptions.map(subscription => subscription.stream.dispose()));
76
+ }
77
+ fail(key, message) {
78
+ const subscription = this.subscriptions.get(key);
79
+ if (subscription === undefined || subscription.failure !== undefined)
80
+ return;
81
+ subscription.failure = message;
82
+ for (const listener of subscription.listeners)
83
+ listener({ type: 'failed', message });
84
+ }
85
+ async run(key, subscription) {
86
+ try {
87
+ for await (const item of subscription.stream) {
88
+ if (this.subscriptions.get(key) !== subscription)
89
+ return;
90
+ item.accept();
91
+ subscription.failure = undefined;
92
+ // Every opening baseline invalidates too: this closes the initial-read
93
+ // race and recovers failed reads even when nothing changed while offline.
94
+ for (const listener of subscription.listeners)
95
+ listener({ type: 'changed', version: item.value.version });
116
96
  }
117
- this.observed.set(key, result.value.version);
118
- // Any difference is a resolution in this scope's own cursor domain —
119
- // normally growth, but a cursor left over from another domain (the two
120
- // scopes count different things) or from an earlier Host lifetime can sit
121
- // ahead of the domain value. Re-anchoring on difference instead of only
122
- // on growth keeps such a subscription observable rather than silently
123
- // parked. The Host answers an equal cursor only on its keep-alive
124
- // deadline, so this stays one comparison per answered call, never a spin.
125
- if (result.value.version !== version) {
126
- version = result.value.version;
127
- for (const listener of poll.listeners)
128
- listener({ type: 'changed', version });
129
- }
97
+ }
98
+ catch (error) {
99
+ if (this.subscriptions.get(key) === subscription)
100
+ this.fail(key, error instanceof Error ? error.message : String(error));
130
101
  }
131
102
  }
132
103
  }