@wowyuarm/dsh-agent-team 0.1.10 → 0.1.12
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 +17 -4
- package/README.zh.md +17 -4
- package/package.json +53 -47
- package/packages/agent-team/README.md +6 -4
- package/packages/agent-team/README.zh.md +6 -4
- package/packages/agent-team/lib/context-management.js +40 -50
- package/packages/agent-team/lib/context-projection.js +15 -1
- package/packages/agent-team/lib/index.js +244 -154
- package/packages/agent-team/lib/invariant.js +38 -4
- package/packages/agent-team/lib/ledger.js +775 -383
- package/packages/agent-team/lib/member-context.js +6 -2
- package/packages/agent-team/lib/member-runtime.js +47 -9
- package/packages/agent-team/lib/member-time-context.js +20 -5
- package/packages/agent-team/lib/mentions.js +56 -0
- package/packages/agent-team/lib/pressure-policy.js +33 -9
- package/packages/agent-team/lib/session-event-cursor.js +116 -0
- package/packages/agent-team/lib/session-remediation.js +38 -26
- package/packages/agent-team/lib/spec.js +47 -34
- package/packages/agent-team/lib/stored-session-reader.js +138 -0
- package/packages/agent-team/lib/typert.host.js +157 -41
- package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
- package/packages/agent-team/lib/typert.remote-client.js +129 -32
- package/packages/agent-team/lib/types/context-management.d.ts +7 -0
- package/packages/agent-team/lib/types/context-management.d.ts.map +1 -1
- package/packages/agent-team/lib/types/context-projection.d.ts +8 -0
- package/packages/agent-team/lib/types/context-projection.d.ts.map +1 -1
- package/packages/agent-team/lib/types/index.d.ts +77 -7
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/invariant.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +251 -20
- package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-runtime.d.ts +2 -1
- package/packages/agent-team/lib/types/member-runtime.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-time-context.d.ts.map +1 -1
- package/packages/agent-team/lib/types/mentions.d.ts +34 -0
- package/packages/agent-team/lib/types/mentions.d.ts.map +1 -0
- package/packages/agent-team/lib/types/pressure-policy.d.ts +18 -0
- package/packages/agent-team/lib/types/pressure-policy.d.ts.map +1 -1
- package/packages/agent-team/lib/types/session-event-cursor.d.ts +119 -0
- package/packages/agent-team/lib/types/session-event-cursor.d.ts.map +1 -0
- package/packages/agent-team/lib/types/session-remediation.d.ts +23 -0
- package/packages/agent-team/lib/types/session-remediation.d.ts.map +1 -1
- package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
- package/packages/agent-team/lib/types/stored-session-reader.d.ts +92 -0
- package/packages/agent-team/lib/types/stored-session-reader.d.ts.map +1 -0
- package/packages/agent-team/lib/types/types/entities.d.ts +28 -20
- package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/operations.d.ts +45 -19
- package/packages/agent-team/lib/types/types/operations.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/requests-results.d.ts +87 -4
- package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
- package/packages/agent-team/preset/team-member/agent.cordis.yml +49 -7
- 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 +2357 -1207
- package/packages/client-agent-team/lib/client.js.map +1 -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 +27 -7
- package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts +18 -0
- package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamAvatarStack.js +22 -0
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts +3 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +167 -35
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +23 -27
- package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts +11 -5
- package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamComposer.js +26 -26
- package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamConversation.js +9 -2
- package/packages/client-agent-team/lib/types/client/TeamCountBadge.d.ts +20 -0
- package/packages/client-agent-team/lib/types/client/TeamCountBadge.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamCountBadge.js +25 -0
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts +25 -0
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.js +139 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.js +8 -24
- package/packages/client-agent-team/lib/types/client/TeamMemberRow.d.ts +43 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberRow.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberRow.js +27 -0
- package/packages/client-agent-team/lib/types/client/TeamMembersAction.d.ts +2 -2
- package/packages/client-agent-team/lib/types/client/TeamMembersAction.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMembersAction.js +2 -2
- package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts +9 -2
- package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMessage.js +11 -4
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts +8 -0
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.js +21 -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 +108 -30
- 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 +68 -7
- package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.js +19 -9
- package/packages/client-agent-team/lib/types/client/locales.d.ts +40 -2
- package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/locales.js +40 -2
- package/packages/client-agent-team/lib/types/client/navigation.d.ts +10 -0
- package/packages/client-agent-team/lib/types/client/navigation.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/navigation.js +18 -7
- package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts +41 -0
- package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/scope-coverage.js +64 -0
- package/packages/client-agent-team/lib/types/client/slots.d.ts +7 -2
- 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 +33 -2
- 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 +107 -25
- package/packages/client-agent-team/lib/types/client/team-dialog-save.d.ts +20 -0
- package/packages/client-agent-team/lib/types/client/team-dialog-save.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/team-dialog-save.js +36 -0
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +43 -1
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-formatters.js +81 -6
- package/packages/tool-agent-team/README.md +2 -2
- package/packages/tool-agent-team/README.zh.md +2 -2
- package/packages/tool-agent-team/lib/context-tools.js +18 -14
- package/packages/tool-agent-team/lib/host-access.js +20 -0
- package/packages/tool-agent-team/lib/index.js +44 -32
- package/packages/tool-agent-team/lib/types/context-tools.d.ts.map +1 -1
- package/packages/tool-agent-team/lib/types/host-access.d.ts +14 -0
- package/packages/tool-agent-team/lib/types/host-access.d.ts.map +1 -0
- package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/progress-nudge.js +0 -328
- package/packages/agent-team/lib/types/progress-nudge.d.ts +0 -136
- package/packages/agent-team/lib/types/progress-nudge.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/TeamSettings.d.ts +0 -3
- package/packages/client-agent-team/lib/types/client/TeamSettings.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/TeamSettings.js +0 -5
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useRef, useState, useSyncExternalStore } from 'react';
|
|
3
|
-
import { IconAgentPresetOutline16, IconListPenOutline16, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
3
|
+
import { IconAgentPresetOutline16, IconListPenOutline16, IconQueueOutline14, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
4
|
import { TeamWorkspaceRow } from "./TeamWorkspaceRow.js";
|
|
5
5
|
import { TeamSidebarSection } from "./TeamSidebarSection.js";
|
|
6
6
|
import { useSidebarSectionOpen, setSidebarSectionOpen } from "./sidebar-sections.js";
|
|
7
7
|
import { TeamAgentsPanel } from "./TeamAgentsPanel.js";
|
|
8
8
|
import { TeamChannelsPanel } from "./TeamChannelsPanel.js";
|
|
9
9
|
import css from './sidebar.module.css';
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* The Inbox entry's icon with its unread mark. The quantity left this surface
|
|
12
|
+
* and lives in the control's accessible name: the sidebar answers whether
|
|
13
|
+
* anything is waiting at a glance, and the number — which moves on every fact —
|
|
14
|
+
* is what a reader asks for on purpose. The mark hangs off the icon rather than
|
|
15
|
+
* off the control, so the wide card and the 36px rail button put the same dot
|
|
16
|
+
* on the same corner of the same glyph.
|
|
17
|
+
*/
|
|
18
|
+
function InboxMark({ unread }) {
|
|
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
|
+
}
|
|
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 }) {
|
|
11
22
|
const navigationState = useSyncExternalStore(navigation.subscribe, navigation.getSnapshot, navigation.getSnapshot);
|
|
12
23
|
const workspaces = useWorkspaces(state => state.items);
|
|
13
24
|
const selected = navigationState.workspaceId;
|
|
@@ -16,19 +27,69 @@ export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWo
|
|
|
16
27
|
// Exactly one sidebar row carries aria-current='page': the open Channel while
|
|
17
28
|
// one is set, the selected Agent card while a Member Session view is open,
|
|
18
29
|
// otherwise the browsed Workspace's overview. The selected row keeps its
|
|
19
|
-
// quiet folder tint (data-selected) in every case.
|
|
20
|
-
|
|
30
|
+
// quiet folder tint (data-selected) in every case. The mention-Inbox card
|
|
31
|
+
// takes the marker while the Inbox page stands, and stands down while the
|
|
32
|
+
// embedded Member Session covers that page: the Inbox stays the remembered
|
|
33
|
+
// face underneath — closing the overlay returns to it, marker included —
|
|
34
|
+
// but the card is not a second current page while an Agent holds the seat.
|
|
35
|
+
const overviewIsCurrent = navigationState.channelRef === undefined && navigationState.memberSessionId === undefined && navigationState.inbox !== true;
|
|
36
|
+
const inboxIsCurrent = navigationState.inbox === true && navigationState.memberSessionId === undefined;
|
|
21
37
|
const [creatingAgents, setCreatingAgents] = useState([]);
|
|
22
38
|
// Rail icons request expansion and name the section to reveal once wide.
|
|
23
39
|
const [pendingSection, setPendingSection] = useState();
|
|
24
40
|
const channelsRef = useRef(null);
|
|
25
41
|
const agentsRef = useRef(null);
|
|
26
42
|
const workspacesOpen = useSidebarSectionOpen(undefined, 'workspaces');
|
|
43
|
+
// The cross-Workspace Inbox badge: one scope-less subscription while the
|
|
44
|
+
// Team sidebar stands; every wake re-pulls each Workspace's unread total
|
|
45
|
+
// (limit 1 — totals cover every row, never the list). Same-burst wakes
|
|
46
|
+
// coalesce behind a short debounce; the number is whatever the Host's whole
|
|
47
|
+
// unread slice returns, mentions included rather than alone.
|
|
48
|
+
const [inboxTotal, setInboxTotal] = useState(0);
|
|
49
|
+
// One name for both entries: what the control is, and how much waits behind
|
|
50
|
+
// it. The rail repeats it as its hover hint, which is the only place a reader
|
|
51
|
+
// still meets the quantity without opening the page.
|
|
52
|
+
const inboxLabel = inboxTotal > 0 ? t('inboxTitleWithCount', { count: inboxTotal }) : t('inboxTitle');
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
let disposed = false;
|
|
55
|
+
let scheduled;
|
|
56
|
+
const refresh = async () => {
|
|
57
|
+
const results = await Promise.all(workspaces.map(workspace => loadInbox({ workspaceId: workspace.workspaceId, limit: 1 })));
|
|
58
|
+
if (disposed)
|
|
59
|
+
return;
|
|
60
|
+
setInboxTotal(results.reduce((sum, result) => result.ok ? sum + result.value.totalUnreadCount : sum, 0));
|
|
61
|
+
};
|
|
62
|
+
const schedule = () => {
|
|
63
|
+
if (scheduled !== undefined)
|
|
64
|
+
return;
|
|
65
|
+
scheduled = setTimeout(() => { scheduled = undefined; void refresh(); }, 200);
|
|
66
|
+
};
|
|
67
|
+
void refresh();
|
|
68
|
+
const unsubscribe = subscribeChanges(undefined, update => {
|
|
69
|
+
if (update.type === 'changed')
|
|
70
|
+
schedule();
|
|
71
|
+
});
|
|
72
|
+
// A durable Thread read consumes this reader's mention markers without a
|
|
73
|
+
// changes wake (reads change no shared projection), so the badge also
|
|
74
|
+
// refreshes from every completed read.
|
|
75
|
+
const unsubscribeReads = subscribeReads(schedule);
|
|
76
|
+
return () => {
|
|
77
|
+
disposed = true;
|
|
78
|
+
if (scheduled !== undefined)
|
|
79
|
+
clearTimeout(scheduled);
|
|
80
|
+
unsubscribe();
|
|
81
|
+
unsubscribeReads();
|
|
82
|
+
};
|
|
83
|
+
}, [loadInbox, subscribeChanges, subscribeReads, workspaces]);
|
|
27
84
|
useEffect(() => {
|
|
85
|
+
// The Inbox page is global and needs no selected Workspace, so the
|
|
86
|
+
// auto-select must not yank the seat back to a Workspace overview.
|
|
87
|
+
if (navigationState.inbox === true)
|
|
88
|
+
return;
|
|
28
89
|
if (navigationState.mode === 'team' && selectedId !== undefined && selectedId !== selected) {
|
|
29
90
|
selectWorkspace(selectedId);
|
|
30
91
|
}
|
|
31
|
-
}, [navigationState.mode, selected, selectedId, selectWorkspace]);
|
|
92
|
+
}, [navigationState.inbox, navigationState.mode, selected, selectedId, selectWorkspace]);
|
|
32
93
|
useEffect(() => {
|
|
33
94
|
if (!wide || pendingSection === undefined)
|
|
34
95
|
return;
|
|
@@ -37,7 +98,7 @@ export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWo
|
|
|
37
98
|
queueMicrotask(() => { node?.querySelector('button')?.focus(); });
|
|
38
99
|
}, [wide, pendingSection]);
|
|
39
100
|
if (!wide) {
|
|
40
|
-
return _jsxs("nav", { className: css.railWorkspace, "aria-label": t('workspaceSections'), children: [_jsx(Tooltip, { label: t('channels'), side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": t('channels'), onClick: () => { setPendingSection('channels'); expandSidebar(); }, children: _jsx(IconListPenOutline16, { size: 16 }) }) }), _jsx(Tooltip, { label: t('agents'), side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": t('agents'), onClick: () => { setPendingSection('agents'); expandSidebar(); }, children: _jsx(IconAgentPresetOutline16, { size: 16 }) }) })] });
|
|
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 }) }) })] });
|
|
41
102
|
}
|
|
42
|
-
return _jsxs("section", { className: css.workspaceBrowser, "aria-label": t('workspaces'), children: [_jsx(TeamSidebarSection, { title: t('workspaces'), open: workspacesOpen, onToggle: open => { setSidebarSectionOpen(undefined, 'workspaces', open); }, children: _jsxs("div", { className: css.workspaceList, children: [workspaces.map(workspace => _jsx(TeamWorkspaceRow, { workspaceId: workspace.workspaceId, title: workspace.title, path: workspace.path, selected: workspace.workspaceId === selectedId, current: workspace.workspaceId === selectedId && overviewIsCurrent, onSelect: selectWorkspace }, workspace.workspaceId)), workspaces.length === 0 && _jsx("p", { className: css.emptyState, children: t('empty') })] }) }), selectedId !== undefined && _jsxs("div", { className: css.workspaceSection, children: [_jsx("div", { ref: channelsRef, children: _jsx(TeamChannelsPanel, { workspaceId: selectedId, loadMembers: loadMembers, loadChannels: loadChannels, subscribeChanges: subscribeChanges, createChannel: createChannel, updateChannel: updateChannel, archiveChannel: archiveChannel, joinChannel: joinChannel, removeChannelMember: removeChannelMember, creatingAgents: creatingAgents.filter(request => request.workspaceId === selectedId), ...(navigationState.memberSessionId !== undefined || navigationState.channelRef === undefined ? {} : { selectedChannelRef: navigationState.channelRef }), selectChannel: selectChannel, t: t }, selectedId) }), _jsx("div", { ref: agentsRef, children: _jsx(TeamAgentsPanel, { workspaceId: selectedId, loadMembers: loadMembers, subscribeChanges: subscribeChanges, addMember: addMember, updateMember: updateMember, recoverMember: recoverMember, 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, loadModels: loadModels, ...(navigationState.memberSessionId === undefined ? {} : { memberSessionId: navigationState.memberSessionId }), openMemberSession: openMemberSession, onCreatingChange: (request, creating) => { setCreatingAgents(current => creating ? [...current.filter(item => item.requestId !== request.requestId), request] : current.filter(item => item.requestId !== request.requestId)); }, t: t }, selectedId) })] })] });
|
|
43
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;
|
|
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,9 +1,9 @@
|
|
|
1
|
-
import agentTeamRemote from '
|
|
1
|
+
import agentTeamRemote from '@wowyuarm/dsh-agent-team/remote';
|
|
2
2
|
import { TeamNavigation } from "./navigation.js";
|
|
3
|
-
import { TeamChangeStream } from "./team-changes.js";
|
|
3
|
+
import { TeamChangeStream, TeamReadStream } from "./team-changes.js";
|
|
4
4
|
import { TeamDraftStore } from "./drafts.js";
|
|
5
5
|
import { TeamFooterAction } from "./TeamFooterAction.js";
|
|
6
|
-
import {
|
|
6
|
+
import { TeamMembersAction } from "./TeamMembersAction.js";
|
|
7
7
|
import { TeamConversation } from "./TeamConversation.js";
|
|
8
8
|
import { TeamWorkspaceBrowser } from "./TeamWorkspaceBrowser.js";
|
|
9
9
|
import { en, zh } from "./locales.js";
|
|
@@ -12,7 +12,7 @@ const NS = 'team';
|
|
|
12
12
|
export const inject = [
|
|
13
13
|
'slots', 'workspaces', 'locale', 'remote', 'remote.session', 'sessions', 'connection', 'conversation',
|
|
14
14
|
];
|
|
15
|
-
function registerModeShadow(ctx, navigation, changes, drafts, name, component, extraInject,
|
|
15
|
+
function registerModeShadow(ctx, navigation, changes, reads, drafts, name, component, extraInject,
|
|
16
16
|
// Keyed seats (`main`) address one panel by key; the reserved 'conversation'
|
|
17
17
|
// key is where the shipped Conversation registers, so the Team seat shadows
|
|
18
18
|
// that same panel instead of adding a second one.
|
|
@@ -33,6 +33,8 @@ entryKey) {
|
|
|
33
33
|
// Remote bindings shared by every Team slot; surface-specific entries extend it below.
|
|
34
34
|
const sharedRemotes = {
|
|
35
35
|
loadChannels: (request) => ctx.remote.agentTeam.view(request),
|
|
36
|
+
loadInbox: (request) => ctx.remote.agentTeam.inbox(request),
|
|
37
|
+
subscribeReads: (listener) => reads.subscribe(listener),
|
|
36
38
|
subscribeChanges: (scope, listener) => changes.subscribe(scope, listener),
|
|
37
39
|
drafts,
|
|
38
40
|
loadMembers: (request) => ctx.remote.agentTeam.members(request),
|
|
@@ -68,7 +70,15 @@ entryKey) {
|
|
|
68
70
|
...navigation.actions(),
|
|
69
71
|
...sharedRemotes,
|
|
70
72
|
...(name === 'main' ? {
|
|
71
|
-
|
|
73
|
+
// A committed durable read consumes this reader's mention
|
|
74
|
+
// markers; the Host's changes stream never wakes on reads, so
|
|
75
|
+
// the Human's badge refreshes from the completed read itself.
|
|
76
|
+
readThread: async (request) => {
|
|
77
|
+
const result = await ctx.remote.agentTeam.readThread(request);
|
|
78
|
+
if (result.ok)
|
|
79
|
+
reads.bump();
|
|
80
|
+
return result;
|
|
81
|
+
},
|
|
72
82
|
loadThreadHistory: (request) => ctx.remote.agentTeam.threadHistory(request),
|
|
73
83
|
threadObservations: (request) => ctx.remote.agentTeam.threadObservations(request),
|
|
74
84
|
sendMessage: (request) => ctx.remote.agentTeam.sendMessage(request),
|
|
@@ -143,6 +153,7 @@ function applyUi(ctx) {
|
|
|
143
153
|
};
|
|
144
154
|
}, 'agent-team: member session restore');
|
|
145
155
|
const changes = new TeamChangeStream((request, signal) => ctx.remote.agentTeam.changes(request, signal));
|
|
156
|
+
const reads = new TeamReadStream();
|
|
146
157
|
const loadMemberGroups = async () => {
|
|
147
158
|
const workspaces = ctx.workspaces.list.getSnapshot().items;
|
|
148
159
|
const groups = await Promise.all(workspaces.map(async (workspace) => {
|
|
@@ -172,12 +183,11 @@ function applyUi(ctx) {
|
|
|
172
183
|
navigation.actions().exitMemberSession();
|
|
173
184
|
navigation.actions().leaveTeam();
|
|
174
185
|
},
|
|
175
|
-
loadMemberGroups,
|
|
176
186
|
}),
|
|
177
187
|
}, TeamFooterAction));
|
|
178
|
-
registerModeShadow(ctx, navigation, changes, drafts, 'sidebar.workspaces', TeamWorkspaceBrowser);
|
|
179
|
-
registerModeShadow(ctx, navigation, changes, drafts, 'main', TeamConversation, undefined, 'conversation');
|
|
180
|
-
registerModeShadow(ctx, navigation, changes, drafts, 'sidebar.settings',
|
|
188
|
+
registerModeShadow(ctx, navigation, changes, reads, drafts, 'sidebar.workspaces', TeamWorkspaceBrowser);
|
|
189
|
+
registerModeShadow(ctx, navigation, changes, reads, drafts, 'main', TeamConversation, undefined, 'conversation');
|
|
190
|
+
registerModeShadow(ctx, navigation, changes, reads, drafts, 'sidebar.settings', TeamMembersAction, () => ({ loadMemberGroups }));
|
|
181
191
|
}
|
|
182
192
|
export async function apply(ctx) {
|
|
183
193
|
const disposeRemote = await ctx.remote.$mount(agentTeamRemote);
|
|
@@ -27,6 +27,20 @@ export declare const zh: {
|
|
|
27
27
|
readonly statusError: "错误";
|
|
28
28
|
readonly statusUnavailable: "不可用";
|
|
29
29
|
readonly addChannel: "新建频道";
|
|
30
|
+
readonly inboxTitle: "收件箱";
|
|
31
|
+
readonly inboxTitleWithCount: "收件箱,{count} 条未读";
|
|
32
|
+
readonly loadingInbox: "正在加载收件箱…";
|
|
33
|
+
readonly inboxEmptyTitle: "收件箱是空的";
|
|
34
|
+
readonly inboxEmptyHint: "你参与的 Thread 有新活动、或有人提到你时,会出现在这里";
|
|
35
|
+
readonly inboxTimeYesterday: "昨天";
|
|
36
|
+
readonly inboxHeaderThreads: "{count} 个 Thread";
|
|
37
|
+
readonly inboxHeaderUnread: "{count} 条未读";
|
|
38
|
+
readonly inboxHeaderMentions: "{count} 条提及";
|
|
39
|
+
readonly inboxRowUnread: "{count} 条未读";
|
|
40
|
+
readonly inboxRowUnreadMentions: "{count} 条未读,其中 {mentions} 条提及";
|
|
41
|
+
readonly inboxRowActor: "最新来自 {name}";
|
|
42
|
+
readonly inboxSectionNeedsMe: "需要我";
|
|
43
|
+
readonly inboxSectionRecent: "最近活跃";
|
|
30
44
|
readonly channelName: "名称";
|
|
31
45
|
readonly channelDescription: "说明";
|
|
32
46
|
readonly initialMembers: "初始成员";
|
|
@@ -40,6 +54,7 @@ export declare const zh: {
|
|
|
40
54
|
readonly resumeAgent: "恢复";
|
|
41
55
|
readonly restartAgent: "重启";
|
|
42
56
|
readonly restartStillUnavailable: "重启已执行,成员仍不可用:{diagnostic}";
|
|
57
|
+
readonly restartRefusedNoRestart: "会话日志被确定拒绝,修复无可用项,重启无法解决:{detail}";
|
|
43
58
|
readonly restartFailed: "重启执行失败:{message}";
|
|
44
59
|
readonly archiveAgent: "归档";
|
|
45
60
|
readonly archiveAgentTitle: "归档 Agent:{name}";
|
|
@@ -91,12 +106,16 @@ export declare const zh: {
|
|
|
91
106
|
readonly taskStatusInReview: "待验收";
|
|
92
107
|
readonly taskStatusDone: "已完成";
|
|
93
108
|
readonly taskStatusClosed: "已关闭";
|
|
94
|
-
readonly taskMessageCount: "{count} 条消息";
|
|
95
109
|
readonly taskLabel: "Task #{number}";
|
|
96
110
|
readonly taskPending: "Task …";
|
|
97
111
|
readonly openTask: "打开 Task #{number}";
|
|
98
112
|
readonly openThread: "打开讨论";
|
|
113
|
+
readonly openTaskUnread: "打开 Task #{number}({count} 条新动态)";
|
|
114
|
+
readonly openThreadUnread: "打开讨论({count} 条新动态)";
|
|
99
115
|
readonly threadLabel: "讨论";
|
|
116
|
+
readonly recentActivity: "最近活动 {time}";
|
|
117
|
+
readonly replyAction: "回复";
|
|
118
|
+
readonly claimers: "由 {names} 处理";
|
|
100
119
|
readonly asTask: "作为任务";
|
|
101
120
|
readonly promoteToTask: "转为 Task";
|
|
102
121
|
readonly promotingTask: "正在转为 Task…";
|
|
@@ -175,6 +194,20 @@ export declare const en: {
|
|
|
175
194
|
readonly statusError: "Error";
|
|
176
195
|
readonly statusUnavailable: "Unavailable";
|
|
177
196
|
readonly addChannel: "New Channel";
|
|
197
|
+
readonly inboxTitle: "Inbox";
|
|
198
|
+
readonly inboxTitleWithCount: "Inbox, {count} unread";
|
|
199
|
+
readonly loadingInbox: "Loading Inbox…";
|
|
200
|
+
readonly inboxEmptyTitle: "Your Inbox is empty";
|
|
201
|
+
readonly inboxEmptyHint: "Threads you take part in appear here when they have new activity or mention you";
|
|
202
|
+
readonly inboxTimeYesterday: "Yesterday";
|
|
203
|
+
readonly inboxHeaderThreads: "{count} Thread(s)";
|
|
204
|
+
readonly inboxHeaderUnread: "{count} unread";
|
|
205
|
+
readonly inboxHeaderMentions: "{count} mention(s)";
|
|
206
|
+
readonly inboxRowUnread: "{count} unread";
|
|
207
|
+
readonly inboxRowUnreadMentions: "{count} unread, {mentions} mention(s)";
|
|
208
|
+
readonly inboxRowActor: "Latest from {name}";
|
|
209
|
+
readonly inboxSectionNeedsMe: "Needs me";
|
|
210
|
+
readonly inboxSectionRecent: "Recently active";
|
|
178
211
|
readonly channelName: "Name";
|
|
179
212
|
readonly channelDescription: "Description";
|
|
180
213
|
readonly initialMembers: "Initial members";
|
|
@@ -188,6 +221,7 @@ export declare const en: {
|
|
|
188
221
|
readonly resumeAgent: "Resume";
|
|
189
222
|
readonly restartAgent: "Restart";
|
|
190
223
|
readonly restartStillUnavailable: "Restart ran, but the Member is still unavailable: {diagnostic}";
|
|
224
|
+
readonly restartRefusedNoRestart: "The session log is deterministically refused with nothing repairable; restarting cannot fix it: {detail}";
|
|
191
225
|
readonly restartFailed: "Restart failed: {message}";
|
|
192
226
|
readonly archiveAgent: "Archive";
|
|
193
227
|
readonly archiveAgentTitle: "Archive Agent: {name}";
|
|
@@ -239,12 +273,16 @@ export declare const en: {
|
|
|
239
273
|
readonly taskStatusInReview: "In review";
|
|
240
274
|
readonly taskStatusDone: "Done";
|
|
241
275
|
readonly taskStatusClosed: "Closed";
|
|
242
|
-
readonly taskMessageCount: "{count} messages";
|
|
243
276
|
readonly taskLabel: "Task #{number}";
|
|
244
277
|
readonly taskPending: "Task …";
|
|
245
278
|
readonly openTask: "Open Task #{number}";
|
|
246
279
|
readonly openThread: "Open thread";
|
|
280
|
+
readonly openTaskUnread: "Open Task #{number} ({count} new updates)";
|
|
281
|
+
readonly openThreadUnread: "Open thread ({count} new updates)";
|
|
247
282
|
readonly threadLabel: "Thread";
|
|
283
|
+
readonly recentActivity: "Last activity {time}";
|
|
284
|
+
readonly replyAction: "Reply";
|
|
285
|
+
readonly claimers: "Handled by {names}";
|
|
248
286
|
readonly asTask: "As task";
|
|
249
287
|
readonly promoteToTask: "Convert to Task";
|
|
250
288
|
readonly promotingTask: "Converting to Task…";
|
|
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsKL,CAAA;AAEV,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsKL,CAAA;AAEV,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,EAAE,CAAA"}
|
|
@@ -27,6 +27,20 @@ export const zh = {
|
|
|
27
27
|
statusError: '错误',
|
|
28
28
|
statusUnavailable: '不可用',
|
|
29
29
|
addChannel: '新建频道',
|
|
30
|
+
inboxTitle: '收件箱',
|
|
31
|
+
inboxTitleWithCount: '收件箱,{count} 条未读',
|
|
32
|
+
loadingInbox: '正在加载收件箱…',
|
|
33
|
+
inboxEmptyTitle: '收件箱是空的',
|
|
34
|
+
inboxEmptyHint: '你参与的 Thread 有新活动、或有人提到你时,会出现在这里',
|
|
35
|
+
inboxTimeYesterday: '昨天',
|
|
36
|
+
inboxHeaderThreads: '{count} 个 Thread',
|
|
37
|
+
inboxHeaderUnread: '{count} 条未读',
|
|
38
|
+
inboxHeaderMentions: '{count} 条提及',
|
|
39
|
+
inboxRowUnread: '{count} 条未读',
|
|
40
|
+
inboxRowUnreadMentions: '{count} 条未读,其中 {mentions} 条提及',
|
|
41
|
+
inboxRowActor: '最新来自 {name}',
|
|
42
|
+
inboxSectionNeedsMe: '需要我',
|
|
43
|
+
inboxSectionRecent: '最近活跃',
|
|
30
44
|
channelName: '名称',
|
|
31
45
|
channelDescription: '说明',
|
|
32
46
|
initialMembers: '初始成员',
|
|
@@ -40,6 +54,7 @@ export const zh = {
|
|
|
40
54
|
resumeAgent: '恢复',
|
|
41
55
|
restartAgent: '重启',
|
|
42
56
|
restartStillUnavailable: '重启已执行,成员仍不可用:{diagnostic}',
|
|
57
|
+
restartRefusedNoRestart: '会话日志被确定拒绝,修复无可用项,重启无法解决:{detail}',
|
|
43
58
|
restartFailed: '重启执行失败:{message}',
|
|
44
59
|
archiveAgent: '归档',
|
|
45
60
|
archiveAgentTitle: '归档 Agent:{name}',
|
|
@@ -91,12 +106,16 @@ export const zh = {
|
|
|
91
106
|
taskStatusInReview: '待验收',
|
|
92
107
|
taskStatusDone: '已完成',
|
|
93
108
|
taskStatusClosed: '已关闭',
|
|
94
|
-
taskMessageCount: '{count} 条消息',
|
|
95
109
|
taskLabel: 'Task #{number}',
|
|
96
110
|
taskPending: 'Task …',
|
|
97
111
|
openTask: '打开 Task #{number}',
|
|
98
112
|
openThread: '打开讨论',
|
|
113
|
+
openTaskUnread: '打开 Task #{number}({count} 条新动态)',
|
|
114
|
+
openThreadUnread: '打开讨论({count} 条新动态)',
|
|
99
115
|
threadLabel: '讨论',
|
|
116
|
+
recentActivity: '最近活动 {time}',
|
|
117
|
+
replyAction: '回复',
|
|
118
|
+
claimers: '由 {names} 处理',
|
|
100
119
|
asTask: '作为任务',
|
|
101
120
|
promoteToTask: '转为 Task',
|
|
102
121
|
promotingTask: '正在转为 Task…',
|
|
@@ -175,6 +194,20 @@ export const en = {
|
|
|
175
194
|
statusError: 'Error',
|
|
176
195
|
statusUnavailable: 'Unavailable',
|
|
177
196
|
addChannel: 'New Channel',
|
|
197
|
+
inboxTitle: 'Inbox',
|
|
198
|
+
inboxTitleWithCount: 'Inbox, {count} unread',
|
|
199
|
+
loadingInbox: 'Loading Inbox…',
|
|
200
|
+
inboxEmptyTitle: 'Your Inbox is empty',
|
|
201
|
+
inboxEmptyHint: 'Threads you take part in appear here when they have new activity or mention you',
|
|
202
|
+
inboxTimeYesterday: 'Yesterday',
|
|
203
|
+
inboxHeaderThreads: '{count} Thread(s)',
|
|
204
|
+
inboxHeaderUnread: '{count} unread',
|
|
205
|
+
inboxHeaderMentions: '{count} mention(s)',
|
|
206
|
+
inboxRowUnread: '{count} unread',
|
|
207
|
+
inboxRowUnreadMentions: '{count} unread, {mentions} mention(s)',
|
|
208
|
+
inboxRowActor: 'Latest from {name}',
|
|
209
|
+
inboxSectionNeedsMe: 'Needs me',
|
|
210
|
+
inboxSectionRecent: 'Recently active',
|
|
178
211
|
channelName: 'Name',
|
|
179
212
|
channelDescription: 'Description',
|
|
180
213
|
initialMembers: 'Initial members',
|
|
@@ -188,6 +221,7 @@ export const en = {
|
|
|
188
221
|
resumeAgent: 'Resume',
|
|
189
222
|
restartAgent: 'Restart',
|
|
190
223
|
restartStillUnavailable: 'Restart ran, but the Member is still unavailable: {diagnostic}',
|
|
224
|
+
restartRefusedNoRestart: 'The session log is deterministically refused with nothing repairable; restarting cannot fix it: {detail}',
|
|
191
225
|
restartFailed: 'Restart failed: {message}',
|
|
192
226
|
archiveAgent: 'Archive',
|
|
193
227
|
archiveAgentTitle: 'Archive Agent: {name}',
|
|
@@ -239,12 +273,16 @@ export const en = {
|
|
|
239
273
|
taskStatusInReview: 'In review',
|
|
240
274
|
taskStatusDone: 'Done',
|
|
241
275
|
taskStatusClosed: 'Closed',
|
|
242
|
-
taskMessageCount: '{count} messages',
|
|
243
276
|
taskLabel: 'Task #{number}',
|
|
244
277
|
taskPending: 'Task …',
|
|
245
278
|
openTask: 'Open Task #{number}',
|
|
246
279
|
openThread: 'Open thread',
|
|
280
|
+
openTaskUnread: 'Open Task #{number} ({count} new updates)',
|
|
281
|
+
openThreadUnread: 'Open thread ({count} new updates)',
|
|
247
282
|
threadLabel: 'Thread',
|
|
283
|
+
recentActivity: 'Last activity {time}',
|
|
284
|
+
replyAction: 'Reply',
|
|
285
|
+
claimers: 'Handled by {names}',
|
|
248
286
|
asTask: 'As task',
|
|
249
287
|
promoteToTask: 'Convert to Task',
|
|
250
288
|
promotingTask: 'Converting to Task…',
|
|
@@ -9,6 +9,12 @@ export interface TeamNavigationSnapshot {
|
|
|
9
9
|
taskRef?: AgentTeamTaskRef;
|
|
10
10
|
threadRef?: AgentTeamThreadRef;
|
|
11
11
|
taskNumber?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Durable position of the Human mention-Inbox page (a navigation fact, not
|
|
14
|
+
* an unread fact): selecting Inbox clears the Channel/Thread faces, and a
|
|
15
|
+
* reload reopens the page. Read markers only move through Thread reads.
|
|
16
|
+
*/
|
|
17
|
+
inbox?: boolean;
|
|
12
18
|
/** Runtime-only Member Session embedded in the conversation seat; never persisted. */
|
|
13
19
|
memberSessionId?: SessionId;
|
|
14
20
|
/** Runtime-only session to restore when the Member view closes; never persisted. */
|
|
@@ -21,6 +27,8 @@ export interface TeamNavigationActions {
|
|
|
21
27
|
selectWorkspace: (workspaceId: WorkspaceId) => void;
|
|
22
28
|
selectChannel: (channelRef: AgentTeamChannelRef) => void;
|
|
23
29
|
selectThread: (threadRef: AgentTeamThreadRef, channelRef?: AgentTeamChannelRef, taskRef?: AgentTeamTaskRef, taskNumber?: number) => void;
|
|
30
|
+
/** Open the Human mention-Inbox page; clears the Channel/Thread faces. */
|
|
31
|
+
selectInbox: () => void;
|
|
24
32
|
backToWorkspace: () => void;
|
|
25
33
|
/** Leave the selected Channel for the workspace Channel list; keeps mode and Workspace. */
|
|
26
34
|
backToChannels: () => void;
|
|
@@ -47,6 +55,8 @@ export declare class TeamNavigation {
|
|
|
47
55
|
private clearMemberSession;
|
|
48
56
|
private setWorkspace;
|
|
49
57
|
private setChannel;
|
|
58
|
+
/** The Inbox is a face, not workspace content: selecting a Workspace leaves it. */
|
|
59
|
+
private setInbox;
|
|
50
60
|
private clearChannel;
|
|
51
61
|
private setThread;
|
|
52
62
|
private commit;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../../src/client/navigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AACnF,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAE/G,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,MAAM,CAAA;AAE9C,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,QAAQ,CAAA;IACd,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,UAAU,CAAC,EAAE,mBAAmB,CAAA;IAChC,OAAO,CAAC,EAAE,gBAAgB,CAAA;IAC1B,SAAS,CAAC,EAAE,kBAAkB,CAAA;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sFAAsF;IACtF,eAAe,CAAC,EAAE,SAAS,CAAA;IAC3B,oFAAoF;IACpF,iBAAiB,CAAC,EAAE,SAAS,CAAA;CAC9B;AAED,QAAA,MAAM,WAAW,8BAA8B,CAAA;
|
|
1
|
+
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../../src/client/navigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AACnF,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAE/G,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,MAAM,CAAA;AAE9C,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,QAAQ,CAAA;IACd,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,UAAU,CAAC,EAAE,mBAAmB,CAAA;IAChC,OAAO,CAAC,EAAE,gBAAgB,CAAA;IAC1B,SAAS,CAAC,EAAE,kBAAkB,CAAA;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,sFAAsF;IACtF,eAAe,CAAC,EAAE,SAAS,CAAA;IAC3B,oFAAoF;IACpF,iBAAiB,CAAC,EAAE,SAAS,CAAA;CAC9B;AAED,QAAA,MAAM,WAAW,8BAA8B,CAAA;AAyC/C,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,eAAe,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,IAAI,CAAA;IACnD,aAAa,EAAE,CAAC,UAAU,EAAE,mBAAmB,KAAK,IAAI,CAAA;IACxD,YAAY,EAAE,CAAC,SAAS,EAAE,kBAAkB,EAAE,UAAU,CAAC,EAAE,mBAAmB,EAAE,OAAO,CAAC,EAAE,gBAAgB,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACxI,0EAA0E;IAC1E,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,eAAe,EAAE,MAAM,IAAI,CAAA;IAC3B,2FAA2F;IAC3F,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B;;;;OAIG;IACH,kBAAkB,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,iBAAiB,CAAC,EAAE,SAAS,KAAK,IAAI,CAAA;IACjF,2EAA2E;IAC3E,iBAAiB,EAAE,MAAM,IAAI,CAAA;CAC9B;AAED,4EAA4E;AAC5E,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwB;IAElD,QAAQ,CAAC,WAAW,QAAO,sBAAsB,CAAiB;IAElE,QAAQ,CAAC,SAAS,GAAI,UAAU,MAAM,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC,CAGxD;IAED,OAAO,IAAI,qBAAqB;IAehC,OAAO,IAAI,IAAI;IAIf,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,gBAAgB;IAaxB,6EAA6E;IAC7E,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,UAAU;IAOlB,mFAAmF;IACnF,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,SAAS;IAkBjB,OAAO,CAAC,MAAM;CAKf;AAED,OAAO,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -9,6 +9,7 @@ function readSnapshot() {
|
|
|
9
9
|
mode: parsed.mode === 'team' ? 'team' : 'conversation',
|
|
10
10
|
...(typeof parsed.workspaceId === 'string' ? { workspaceId: parsed.workspaceId } : {}),
|
|
11
11
|
...(typeof parsed.channelRef === 'string' ? { channelRef: parsed.channelRef } : {}),
|
|
12
|
+
...(parsed.inbox === true ? { inbox: true } : {}),
|
|
12
13
|
...(hasThread ? {
|
|
13
14
|
threadRef: parsed.threadRef,
|
|
14
15
|
...(typeof parsed.taskRef === 'string' ? { taskRef: parsed.taskRef } : {}),
|
|
@@ -24,11 +25,12 @@ function persistSnapshot(snapshot) {
|
|
|
24
25
|
if (typeof localStorage === 'undefined')
|
|
25
26
|
return;
|
|
26
27
|
try {
|
|
27
|
-
const { mode, workspaceId, channelRef, taskRef, threadRef, taskNumber } = snapshot;
|
|
28
|
+
const { mode, workspaceId, channelRef, taskRef, threadRef, taskNumber, inbox } = snapshot;
|
|
28
29
|
localStorage.setItem(STORAGE_KEY, JSON.stringify({
|
|
29
30
|
mode,
|
|
30
31
|
...(workspaceId === undefined ? {} : { workspaceId }),
|
|
31
32
|
...(channelRef === undefined ? {} : { channelRef }),
|
|
33
|
+
...(inbox === true ? { inbox: true } : {}),
|
|
32
34
|
...(taskRef === undefined ? {} : { taskRef }),
|
|
33
35
|
...(threadRef === undefined ? {} : { threadRef }),
|
|
34
36
|
...(taskNumber === undefined ? {} : { taskNumber }),
|
|
@@ -54,6 +56,7 @@ export class TeamNavigation {
|
|
|
54
56
|
selectWorkspace: workspaceId => { this.clearMemberSession(); this.setWorkspace(workspaceId); },
|
|
55
57
|
selectChannel: channelRef => { this.clearMemberSession(); this.setChannel(channelRef); },
|
|
56
58
|
selectThread: (threadRef, channelRef, taskRef, taskNumber) => { this.clearMemberSession(); this.setThread(threadRef, channelRef, taskRef, taskNumber); },
|
|
59
|
+
selectInbox: () => { this.clearMemberSession(); this.setInbox(); },
|
|
57
60
|
backToWorkspace: () => { this.clearMemberSession(); this.setThread(undefined); },
|
|
58
61
|
backToChannels: () => { this.clearMemberSession(); this.clearChannel(); },
|
|
59
62
|
enterMemberSession: (sessionId, returnToSessionId) => { this.setMemberSession(sessionId, returnToSessionId); },
|
|
@@ -91,19 +94,27 @@ export class TeamNavigation {
|
|
|
91
94
|
this.commit();
|
|
92
95
|
}
|
|
93
96
|
setWorkspace(workspaceId) {
|
|
94
|
-
if (this.snapshot.workspaceId === workspaceId)
|
|
97
|
+
if (this.snapshot.workspaceId === workspaceId && this.snapshot.inbox !== true)
|
|
95
98
|
return;
|
|
96
|
-
const { channelRef: _channelRef, taskRef: _taskRef, threadRef: _threadRef, taskNumber: _taskNumber, ...base } = this.snapshot;
|
|
99
|
+
const { channelRef: _channelRef, taskRef: _taskRef, threadRef: _threadRef, taskNumber: _taskNumber, inbox: _inbox, ...base } = this.snapshot;
|
|
97
100
|
this.snapshot = { ...base, workspaceId };
|
|
98
101
|
this.commit();
|
|
99
102
|
}
|
|
100
103
|
setChannel(channelRef) {
|
|
101
|
-
if (this.snapshot.channelRef === channelRef && this.snapshot.threadRef === undefined)
|
|
104
|
+
if (this.snapshot.channelRef === channelRef && this.snapshot.threadRef === undefined && this.snapshot.inbox !== true)
|
|
102
105
|
return;
|
|
103
|
-
const { taskRef: _taskRef, threadRef: _threadRef, taskNumber: _taskNumber, ...base } = this.snapshot;
|
|
106
|
+
const { taskRef: _taskRef, threadRef: _threadRef, taskNumber: _taskNumber, inbox: _inbox, ...base } = this.snapshot;
|
|
104
107
|
this.snapshot = { ...base, channelRef };
|
|
105
108
|
this.commit();
|
|
106
109
|
}
|
|
110
|
+
/** The Inbox is a face, not workspace content: selecting a Workspace leaves it. */
|
|
111
|
+
setInbox() {
|
|
112
|
+
if (this.snapshot.inbox === true && this.snapshot.channelRef === undefined && this.snapshot.threadRef === undefined)
|
|
113
|
+
return;
|
|
114
|
+
const { channelRef: _channelRef, taskRef: _taskRef, threadRef: _threadRef, taskNumber: _taskNumber, ...base } = this.snapshot;
|
|
115
|
+
this.snapshot = { ...base, inbox: true };
|
|
116
|
+
this.commit();
|
|
117
|
+
}
|
|
107
118
|
clearChannel() {
|
|
108
119
|
const { channelRef: _channelRef, ...base } = this.snapshot;
|
|
109
120
|
if (this.snapshot.channelRef === undefined)
|
|
@@ -112,14 +123,14 @@ export class TeamNavigation {
|
|
|
112
123
|
this.commit();
|
|
113
124
|
}
|
|
114
125
|
setThread(threadRef, channelRef, taskRef, taskNumber) {
|
|
115
|
-
if (this.snapshot.threadRef === threadRef && this.snapshot.taskRef === taskRef && this.snapshot.channelRef === channelRef && this.snapshot.taskNumber === taskNumber)
|
|
126
|
+
if (this.snapshot.threadRef === threadRef && this.snapshot.taskRef === taskRef && this.snapshot.channelRef === channelRef && this.snapshot.taskNumber === taskNumber && this.snapshot.inbox !== true)
|
|
116
127
|
return;
|
|
117
128
|
if (threadRef === undefined) {
|
|
118
129
|
const { taskRef: _taskRef, threadRef: _threadRef, taskNumber: _taskNumber, ...base } = this.snapshot;
|
|
119
130
|
this.snapshot = base;
|
|
120
131
|
}
|
|
121
132
|
else {
|
|
122
|
-
const { channelRef: _channelRef, taskRef: _taskRef, threadRef: _threadRef, taskNumber: _taskNumber, ...base } = this.snapshot;
|
|
133
|
+
const { channelRef: _channelRef, taskRef: _taskRef, threadRef: _threadRef, taskNumber: _taskNumber, inbox: _inbox, ...base } = this.snapshot;
|
|
123
134
|
this.snapshot = {
|
|
124
135
|
...base,
|
|
125
136
|
threadRef,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** The change scopes whose wakes one surface answers with a shared refresh round. */
|
|
2
|
+
export type SupplementalScope = 'workspace' | 'presence';
|
|
3
|
+
/** One change wake, carrying a version from the scope that issued it. */
|
|
4
|
+
export interface ScopeWake {
|
|
5
|
+
readonly scope: SupplementalScope;
|
|
6
|
+
readonly version: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Per-scope coverage of the change versions one surface has already answered.
|
|
10
|
+
*
|
|
11
|
+
* A version is only comparable inside the scope that issued it: the Host
|
|
12
|
+
* answers a workspace scope from the durable ledger position and a presence
|
|
13
|
+
* scope from its process-local wake epoch, which starts low and climbs on every
|
|
14
|
+
* Agent transition. One high-water mark shared by both would therefore let a
|
|
15
|
+
* presence epoch swallow a later, smaller ledger sequence and park the surface
|
|
16
|
+
* on stale data, so coverage and pending versions are kept per scope.
|
|
17
|
+
*
|
|
18
|
+
* One round answers one version per scope. The Host delivers one event to every
|
|
19
|
+
* matching scope, so the first version a round sees in a scope it has not
|
|
20
|
+
* answered yet is that event reaching a second scope, and joins the round
|
|
21
|
+
* already fetching instead of earning a second identical read. A newer version
|
|
22
|
+
* in a scope the round has answered arrived after the round issued its fetch,
|
|
23
|
+
* so it owes one trailing round.
|
|
24
|
+
*/
|
|
25
|
+
export declare class ScopeCoverage {
|
|
26
|
+
private readonly covered;
|
|
27
|
+
private readonly pending;
|
|
28
|
+
/** The scopes the open round has an answer for. */
|
|
29
|
+
private readonly answered;
|
|
30
|
+
private fetching;
|
|
31
|
+
/** Folds one wake in and answers whether it opens a round. */
|
|
32
|
+
wake(scope: SupplementalScope, version: number): boolean;
|
|
33
|
+
/** Opens a round's fetch window; versions observed from here on are pending. */
|
|
34
|
+
beginRound(): void;
|
|
35
|
+
/** Closes a round's fetch window and answers whether a trailing round is owed. */
|
|
36
|
+
finishRound(): boolean;
|
|
37
|
+
/** Drops every observation: a new owner starts with nothing covered. */
|
|
38
|
+
reset(): void;
|
|
39
|
+
private coveredOf;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=scope-coverage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope-coverage.d.ts","sourceRoot":"","sources":["../../../src/client/scope-coverage.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,UAAU,CAAA;AAExD,yEAAyE;AACzE,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAA;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,mDAAmD;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA+B;IACxD,OAAO,CAAC,QAAQ,CAAQ;IAExB,8DAA8D;IAC9D,IAAI,CAAC,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAWxD,gFAAgF;IAChF,UAAU,IAAI,IAAI;IAKlB,kFAAkF;IAClF,WAAW,IAAI,OAAO;IAYtB,wEAAwE;IACxE,KAAK,IAAI,IAAI;IAOb,OAAO,CAAC,SAAS;CAGlB"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-scope coverage of the change versions one surface has already answered.
|
|
3
|
+
*
|
|
4
|
+
* A version is only comparable inside the scope that issued it: the Host
|
|
5
|
+
* answers a workspace scope from the durable ledger position and a presence
|
|
6
|
+
* scope from its process-local wake epoch, which starts low and climbs on every
|
|
7
|
+
* Agent transition. One high-water mark shared by both would therefore let a
|
|
8
|
+
* presence epoch swallow a later, smaller ledger sequence and park the surface
|
|
9
|
+
* on stale data, so coverage and pending versions are kept per scope.
|
|
10
|
+
*
|
|
11
|
+
* One round answers one version per scope. The Host delivers one event to every
|
|
12
|
+
* matching scope, so the first version a round sees in a scope it has not
|
|
13
|
+
* answered yet is that event reaching a second scope, and joins the round
|
|
14
|
+
* already fetching instead of earning a second identical read. A newer version
|
|
15
|
+
* in a scope the round has answered arrived after the round issued its fetch,
|
|
16
|
+
* so it owes one trailing round.
|
|
17
|
+
*/
|
|
18
|
+
export class ScopeCoverage {
|
|
19
|
+
covered = new Map();
|
|
20
|
+
pending = new Map();
|
|
21
|
+
/** The scopes the open round has an answer for. */
|
|
22
|
+
answered = new Set();
|
|
23
|
+
fetching = false;
|
|
24
|
+
/** Folds one wake in and answers whether it opens a round. */
|
|
25
|
+
wake(scope, version) {
|
|
26
|
+
if (version <= this.coveredOf(scope))
|
|
27
|
+
return false;
|
|
28
|
+
if (this.fetching && this.answered.has(scope)) {
|
|
29
|
+
this.pending.set(scope, Math.max(this.pending.get(scope) ?? 0, version));
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
this.answered.add(scope);
|
|
33
|
+
this.covered.set(scope, version);
|
|
34
|
+
return !this.fetching;
|
|
35
|
+
}
|
|
36
|
+
/** Opens a round's fetch window; versions observed from here on are pending. */
|
|
37
|
+
beginRound() {
|
|
38
|
+
this.pending.clear();
|
|
39
|
+
this.fetching = true;
|
|
40
|
+
}
|
|
41
|
+
/** Closes a round's fetch window and answers whether a trailing round is owed. */
|
|
42
|
+
finishRound() {
|
|
43
|
+
this.fetching = false;
|
|
44
|
+
this.answered.clear();
|
|
45
|
+
let owed = false;
|
|
46
|
+
for (const [scope, version] of this.pending) {
|
|
47
|
+
if (version <= this.coveredOf(scope))
|
|
48
|
+
continue;
|
|
49
|
+
this.covered.set(scope, version);
|
|
50
|
+
owed = true;
|
|
51
|
+
}
|
|
52
|
+
return owed;
|
|
53
|
+
}
|
|
54
|
+
/** Drops every observation: a new owner starts with nothing covered. */
|
|
55
|
+
reset() {
|
|
56
|
+
this.covered.clear();
|
|
57
|
+
this.pending.clear();
|
|
58
|
+
this.answered.clear();
|
|
59
|
+
this.fetching = false;
|
|
60
|
+
}
|
|
61
|
+
coveredOf(scope) {
|
|
62
|
+
return this.covered.get(scope) ?? 0;
|
|
63
|
+
}
|
|
64
|
+
}
|