@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.
- package/README.md +2 -0
- package/README.zh.md +2 -0
- package/cordis.patch.yml +7 -3
- package/package.json +14 -2
- package/packages/agent-team/README.md +2 -2
- package/packages/agent-team/README.zh.md +2 -2
- package/packages/agent-team/lib/index.js +151 -69
- package/packages/agent-team/lib/ledger.js +249 -31
- package/packages/agent-team/lib/member-context.js +18 -1
- package/packages/agent-team/lib/member-runtime.js +5 -4
- package/packages/agent-team/lib/mentions.js +48 -24
- package/packages/agent-team/lib/spec.js +19 -0
- package/packages/agent-team/lib/typert.host.js +187 -41
- package/packages/agent-team/lib/typert.remote-client.d.ts +7 -3
- package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
- package/packages/agent-team/lib/typert.remote-client.js +132 -27
- package/packages/agent-team/lib/types/index.d.ts +32 -7
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +46 -2
- package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-context.d.ts +6 -0
- package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
- package/packages/agent-team/lib/types/mentions.d.ts +20 -7
- package/packages/agent-team/lib/types/mentions.d.ts.map +1 -1
- package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/entities.d.ts +3 -2
- package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/operations.d.ts +37 -1
- package/packages/agent-team/lib/types/types/operations.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/requests-results.d.ts +50 -10
- package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
- package/packages/agent-team/lib/types/vendor/storage-sqlite/index.d.ts +87 -0
- package/packages/agent-team/lib/types/vendor/storage-sqlite/index.d.ts.map +1 -0
- package/packages/agent-team/lib/types/vendor/storage-sqlite/schema.d.ts +59 -0
- package/packages/agent-team/lib/types/vendor/storage-sqlite/schema.d.ts.map +1 -0
- package/packages/agent-team/lib/types/vendor/storage-sqlite/unit.d.ts +57 -0
- package/packages/agent-team/lib/types/vendor/storage-sqlite/unit.d.ts.map +1 -0
- package/packages/agent-team/lib/vendor/storage-sqlite/index.js +139 -0
- package/packages/agent-team/lib/vendor/storage-sqlite/schema.js +120 -0
- package/packages/agent-team/lib/vendor/storage-sqlite/unit.js +132 -0
- package/packages/client-agent-team/README.md +1 -1
- package/packages/client-agent-team/README.zh.md +1 -1
- package/packages/client-agent-team/lib/client.js +603 -343
- package/packages/client-agent-team/lib/client.js.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentImport.d.ts +12 -0
- package/packages/client-agent-team/lib/types/client/TeamAgentImport.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamAgentImport.js +69 -0
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +3 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +29 -17
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +19 -44
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts +2 -2
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.js +15 -14
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +15 -29
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +2 -2
- package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.js +8 -1
- package/packages/client-agent-team/lib/types/client/locales.d.ts +18 -0
- package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/locales.js +18 -0
- package/packages/client-agent-team/lib/types/client/slots.d.ts +3 -1
- package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-changes.d.ts +15 -31
- package/packages/client-agent-team/lib/types/client/team-changes.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-changes.js +82 -111
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +13 -11
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-formatters.js +29 -35
- package/packages/tool-agent-team/README.md +1 -1
- package/packages/tool-agent-team/README.zh.md +1 -1
- package/packages/tool-agent-team/lib/host-access.js +19 -0
- package/packages/tool-agent-team/lib/index.js +42 -33
- package/packages/tool-agent-team/lib/types/host-access.d.ts +10 -0
- package/packages/tool-agent-team/lib/types/host-access.d.ts.map +1 -1
- package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts +0 -41
- package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts.map +0 -1
- 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
|
|
200
|
-
const refreshSupplemental = (
|
|
201
|
-
|
|
202
|
-
if (
|
|
203
|
-
|
|
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
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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(
|
|
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,+
|
|
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;
|
|
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(
|
|
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
|
|
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 {
|
|
2
|
-
import type { AgentTeamChangeScope
|
|
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
|
-
|
|
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
|
|
34
|
-
private readonly
|
|
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
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* the
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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":"
|
|
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
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
|
51
|
-
if (
|
|
52
|
-
|
|
53
|
-
this.
|
|
54
|
-
void this.run(key,
|
|
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
|
-
|
|
29
|
+
const owned = subscription;
|
|
57
30
|
return () => {
|
|
58
|
-
|
|
59
|
-
if (current === undefined || !current.listeners.delete(listener))
|
|
31
|
+
if (!owned.listeners.delete(listener) || owned.listeners.size !== 0)
|
|
60
32
|
return;
|
|
61
|
-
if (
|
|
62
|
-
this.
|
|
63
|
-
|
|
64
|
-
}
|
|
33
|
+
if (this.subscriptions.get(key) === owned)
|
|
34
|
+
this.subscriptions.delete(key);
|
|
35
|
+
void owned.stream.dispose();
|
|
65
36
|
};
|
|
66
37
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
}
|