@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
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { WorkspaceId } from '@deepseek-ai/dsh-api-workspace-controller/client';
|
|
2
|
+
import type { TeamSidebarProps } from './slots.ts';
|
|
3
|
+
/** Selection is a Host join, not a new Agent or a copied Session. */
|
|
4
|
+
export declare function TeamAgentImport({ workspaceId, loadMembers, joinWorkspace, onJoined, onPending, t }: {
|
|
5
|
+
readonly workspaceId: WorkspaceId;
|
|
6
|
+
readonly loadMembers: TeamSidebarProps['loadMembers'];
|
|
7
|
+
readonly joinWorkspace: TeamSidebarProps['joinWorkspace'];
|
|
8
|
+
readonly onJoined: () => Promise<void>;
|
|
9
|
+
readonly onPending: (pending: boolean) => void;
|
|
10
|
+
readonly t: TeamSidebarProps['t'];
|
|
11
|
+
}): import("react").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=TeamAgentImport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TeamAgentImport.d.ts","sourceRoot":"","sources":["../../../src/client/TeamAgentImport.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAKlD,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE;IACnG,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAA;IACrD,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACtC,QAAQ,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IAC9C,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC,+BA2DA"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { Button } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
|
+
import { TeamMemberRow } from "./TeamMemberRow.js";
|
|
5
|
+
import { mintRequestId } from "./requests.js";
|
|
6
|
+
import css from './create.module.css';
|
|
7
|
+
/** Selection is a Host join, not a new Agent or a copied Session. */
|
|
8
|
+
export function TeamAgentImport({ workspaceId, loadMembers, joinWorkspace, onJoined, onPending, t }) {
|
|
9
|
+
const [members, setMembers] = useState([]);
|
|
10
|
+
const [loading, setLoading] = useState(true);
|
|
11
|
+
const [error, setError] = useState();
|
|
12
|
+
const [pending, setPending] = useState();
|
|
13
|
+
const retry = useRef();
|
|
14
|
+
const busy = useRef(false);
|
|
15
|
+
const generation = useRef(0);
|
|
16
|
+
const load = useCallback(async () => {
|
|
17
|
+
const current = ++generation.current;
|
|
18
|
+
setLoading(true);
|
|
19
|
+
setError(undefined);
|
|
20
|
+
try {
|
|
21
|
+
const result = await loadMembers({});
|
|
22
|
+
if (current !== generation.current)
|
|
23
|
+
return;
|
|
24
|
+
if (!result.ok)
|
|
25
|
+
throw new Error(result.error.message);
|
|
26
|
+
setMembers(result.value.filter(status => (status.member.state === 'enabled' || status.member.state === 'suspended') && !status.workspaceIds.includes(workspaceId)));
|
|
27
|
+
}
|
|
28
|
+
catch (cause) {
|
|
29
|
+
if (current === generation.current)
|
|
30
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
if (current === generation.current)
|
|
34
|
+
setLoading(false);
|
|
35
|
+
}
|
|
36
|
+
}, [loadMembers, workspaceId]);
|
|
37
|
+
useEffect(() => { void load(); return () => { generation.current++; }; }, [load]);
|
|
38
|
+
const join = async (status) => {
|
|
39
|
+
if (busy.current)
|
|
40
|
+
return;
|
|
41
|
+
busy.current = true;
|
|
42
|
+
setPending(status.member.memberId);
|
|
43
|
+
onPending(true);
|
|
44
|
+
setError(undefined);
|
|
45
|
+
const request = retry.current?.memberId === status.member.memberId ? retry.current : {
|
|
46
|
+
requestId: mintRequestId(), workspaceId, memberId: status.member.memberId,
|
|
47
|
+
};
|
|
48
|
+
retry.current = request;
|
|
49
|
+
try {
|
|
50
|
+
const result = await joinWorkspace(request);
|
|
51
|
+
if (!result.ok)
|
|
52
|
+
throw new Error(result.error.message);
|
|
53
|
+
await onJoined();
|
|
54
|
+
}
|
|
55
|
+
catch (cause) {
|
|
56
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
busy.current = false;
|
|
60
|
+
setPending(undefined);
|
|
61
|
+
onPending(false);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
return _jsxs("div", { className: css.form, children: [_jsx("p", { className: css.notice, children: t('importAgentNotice') }), loading && _jsx("p", { className: css.state, role: "status", children: t('loadingAgents') }), !loading && error === undefined && members.length === 0 && _jsx("p", { className: css.state, children: t('emptyImportAgents') }), !loading && members.length > 0 && _jsx("div", { className: css.roster, children: members.map(status => _jsx(TeamMemberRow, { status: status, t: t, action: {
|
|
65
|
+
label: pending === status.member.memberId ? t('importingAgent') : t('importAgent'),
|
|
66
|
+
disabled: pending !== undefined,
|
|
67
|
+
onSelect: () => { void join(status); },
|
|
68
|
+
} }, status.member.memberId)) }), error !== undefined && _jsxs("div", { className: css.failure, role: "alert", children: [_jsx("p", { className: css.error, children: error }), _jsx(Button, { disabled: pending !== undefined, variant: "outline", onClick: () => { void load(); }, children: t('retry') })] })] });
|
|
69
|
+
}
|
|
@@ -9,6 +9,8 @@ interface TeamAgentsPanelProps {
|
|
|
9
9
|
readonly updateMember: TeamSidebarProps['updateMember'];
|
|
10
10
|
readonly recoverMember: TeamSidebarProps['recoverMember'];
|
|
11
11
|
readonly archiveMember: TeamSidebarProps['archiveMember'];
|
|
12
|
+
readonly joinWorkspace: TeamSidebarProps['joinWorkspace'];
|
|
13
|
+
readonly leaveWorkspace: TeamSidebarProps['leaveWorkspace'];
|
|
12
14
|
readonly loadModels: TeamSidebarProps['loadModels'];
|
|
13
15
|
/** The Member Session currently embedded in the conversation seat, if any. */
|
|
14
16
|
readonly memberSessionId?: AgentTeamClientMemberStatus['member']['sessionId'];
|
|
@@ -16,6 +18,6 @@ interface TeamAgentsPanelProps {
|
|
|
16
18
|
readonly onCreatingChange: (request: AgentTeamAddMemberRequest, creating: boolean) => void;
|
|
17
19
|
readonly t: TeamSidebarProps['t'];
|
|
18
20
|
}
|
|
19
|
-
export declare function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, addMember, updateMember, recoverMember, archiveMember, loadModels, memberSessionId, openMemberSession, onCreatingChange, t }: TeamAgentsPanelProps): import("react").JSX.Element;
|
|
21
|
+
export declare function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, addMember, updateMember, recoverMember, archiveMember, joinWorkspace, leaveWorkspace, loadModels, memberSessionId, openMemberSession, onCreatingChange, t }: TeamAgentsPanelProps): import("react").JSX.Element;
|
|
20
22
|
export {};
|
|
21
23
|
//# sourceMappingURL=TeamAgentsPanel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamAgentsPanel.d.ts","sourceRoot":"","sources":["../../../src/client/TeamAgentsPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EACzB,2BAA2B,EAE5B,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"TeamAgentsPanel.d.ts","sourceRoot":"","sources":["../../../src/client/TeamAgentsPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EACzB,2BAA2B,EAE5B,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAclD,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAA;IACrD,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAA;IAC/D,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAA;IACjD,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAA;IACvD,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,cAAc,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,CAAA;IAC3D,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAA;IACnD,8EAA8E;IAC9E,QAAQ,CAAC,eAAe,CAAC,EAAE,2BAA2B,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAA;IAC7E,QAAQ,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,CAAA;IACjE,QAAQ,CAAC,gBAAgB,EAAE,CAAC,OAAO,EAAE,yBAAyB,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;IAC1F,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC;AAED,wBAAgB,eAAe,CAAC,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC,EAAE,EAAE,oBAAoB,+BA2O9P"}
|
|
@@ -10,13 +10,15 @@ import { diagnosticText, restartOffered } from "./TeamPresenceDot.js";
|
|
|
10
10
|
import { TeamRowMenu } from "./TeamRowMenu.js";
|
|
11
11
|
import { TeamSidebarSection } from "./TeamSidebarSection.js";
|
|
12
12
|
import { AgentEditorDialog, ModelPickerField, sameModel } from "./TeamMemberEditor.js";
|
|
13
|
+
import { TeamAgentImport } from "./TeamAgentImport.js";
|
|
13
14
|
import createCss from './create.module.css';
|
|
14
15
|
import css from './sidebar.module.css';
|
|
15
|
-
export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, addMember, updateMember, recoverMember, archiveMember, loadModels, memberSessionId, openMemberSession, onCreatingChange, t }) {
|
|
16
|
+
export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, addMember, updateMember, recoverMember, archiveMember, joinWorkspace, leaveWorkspace, loadModels, memberSessionId, openMemberSession, onCreatingChange, t }) {
|
|
16
17
|
const [members, setMembers] = useState([]);
|
|
17
18
|
const [loading, setLoading] = useState(true);
|
|
18
19
|
const [error, setError] = useState();
|
|
19
20
|
const [formOpen, setFormOpen] = useState(false);
|
|
21
|
+
const [importing, setImporting] = useState(false);
|
|
20
22
|
const [handle, setHandle] = useState('');
|
|
21
23
|
const [description, setDescription] = useState('');
|
|
22
24
|
const [model, setModel] = useState(undefined);
|
|
@@ -142,11 +144,10 @@ export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, ad
|
|
|
142
144
|
try {
|
|
143
145
|
const result = await addMember(request);
|
|
144
146
|
if (result.ok) {
|
|
147
|
+
const committed = { ...result.value.status, workspaceIds: [result.value.status.member.workspaceId] };
|
|
145
148
|
setMembers(current => {
|
|
146
|
-
const retained = current.filter(status => status.member.memberId !==
|
|
147
|
-
return
|
|
148
|
-
? retained
|
|
149
|
-
: [...retained, result.value.status];
|
|
149
|
+
const retained = current.filter(status => status.member.memberId !== committed.member.memberId);
|
|
150
|
+
return committed.member.state === 'inactive' || committed.member.state === 'archived' ? retained : [...retained, committed];
|
|
150
151
|
});
|
|
151
152
|
setHandle('');
|
|
152
153
|
setDescription('');
|
|
@@ -195,18 +196,21 @@ export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, ad
|
|
|
195
196
|
...(model === undefined ? {} : { model }),
|
|
196
197
|
});
|
|
197
198
|
};
|
|
198
|
-
return (_jsxs("div", { className: css.panel, children: [
|
|
199
|
+
return (_jsxs("div", { className: css.panel, children: [_jsxs(Modal, { open: formOpen, onClose: closeForm, title: t('addAgent'), closeLabel: t('close'), contentClassName: createCss.dialogContent, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: creating, onClick: closeForm, children: t('cancel') }), !importing && _jsx(Button, { type: "submit", form: "team-agent-create-form", variant: "primary", disabled: creating || handle.trim().length === 0, children: creating ? t('creatingAgent') : t('createAgent') })] }), children: [_jsx(Button, { className: createCss.modeSwitch, variant: "outline", disabled: creating, "aria-expanded": importing, onClick: () => { setImporting(value => !value); setError(undefined); }, children: importing ? t('createAgent') : t('importAgentTitle') }), formOpen && importing ? _jsx(TeamAgentImport, { workspaceId: workspaceId, loadMembers: loadMembers, joinWorkspace: joinWorkspace, onPending: setCreating, onJoined: async () => { await refresh(); setFormOpen(false); queueMicrotask(() => { triggerRef.current?.focus(); }); }, t: t }) : _jsxs("form", { id: "team-agent-create-form", className: createCss.form, onSubmit: submit, children: [_jsxs("label", { className: createCss.field, children: [_jsx("span", { children: t('agentName') }), _jsx(Input, { className: createCss.input, value: handle, onChange: event => { setHandle(event.target.value); setRetryRequest(undefined); }, disabled: creating, autoFocus: true })] }), _jsxs("label", { className: createCss.field, children: [_jsxs("span", { children: [t('agentDescription'), t('optionalSuffix')] }), _jsx(Input, { className: createCss.input, value: description, placeholder: t('agentDescriptionPlaceholder'), onChange: event => { setDescription(event.target.value); setRetryRequest(undefined); }, disabled: creating })] }), _jsx(ModelPickerField, { model: model, onModelChange: choice => { setModel(choice); setRetryRequest(undefined); }, loadModels: loadModels, disabled: creating, t: t }), formOpen && error !== undefined && _jsx("p", { className: createCss.error, role: "alert", children: error })] })] }), _jsxs(TeamSidebarSection, { title: t('agents'), open: sectionOpen, onToggle: open => { setSidebarSectionOpen(workspaceId, 'agents', open); }, actions: (_jsx(Tooltip, { label: t('addAgent'), delayMs: 500, children: _jsx("button", { ref: triggerRef, type: "button", className: css.iconButton, "aria-label": t('addAgent'), onClick: () => { setError(undefined); setImporting(false); setFormOpen(true); }, children: _jsx(IconPlusOutline16, { size: 14 }) }) })), children: [loading && members.length === 0 && _jsx("p", { className: css.emptyState, children: t('loadingAgents') }), !loading && error === undefined && members.length === 0 && _jsx("p", { className: css.emptyState, children: t('emptyAgents') }), _jsx("div", { className: css.agentList, children: orderedMembers.map(status => (_jsx(SortableRow, { drag: drag, orderKey: status.member.memberId, children: _jsx(AgentRow, { workspaceId: workspaceId, leaveWorkspace: leaveWorkspace, status: status, ...(memberSessionId === undefined ? {} : { current: status.member.sessionId === memberSessionId }), updateMember: updateMember, recoverMember: recoverMember, archiveMember: archiveMember, loadModels: loadModels, openMemberSession: openMemberSession, onUpdated: refresh, t: t }) }, status.member.memberId))) })] }), !formOpen && error !== undefined && (_jsxs("div", { className: css.retryError, role: "alert", children: [_jsx("span", { children: error }), retryRequest !== undefined && _jsx("button", { type: "button", className: css.textButton, disabled: creating, onClick: () => { setFormOpen(true); }, children: t('retry') })] }))] }));
|
|
199
200
|
}
|
|
200
201
|
/**
|
|
201
202
|
* One sidebar Agent row: the select button opens the Member's own Session
|
|
202
203
|
* conversation page, the avatar carries identity plus the presence badge, and
|
|
203
204
|
* the row menu opens the editor.
|
|
204
205
|
*/
|
|
205
|
-
function AgentRow({ status, current, updateMember, recoverMember, archiveMember, loadModels, openMemberSession, onUpdated, t }) {
|
|
206
|
+
function AgentRow({ workspaceId, leaveWorkspace, status, current, updateMember, recoverMember, archiveMember, loadModels, openMemberSession, onUpdated, t }) {
|
|
206
207
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
207
208
|
const [editing, setEditing] = useState(false);
|
|
208
209
|
const [archiving, setArchiving] = useState(false);
|
|
209
210
|
const [rowAlert, setRowAlert] = useState();
|
|
211
|
+
const [archivePending, setArchivePending] = useState(false);
|
|
212
|
+
const archiveRequest = useRef();
|
|
213
|
+
const withdrawing = workspaceId !== status.member.workspaceId;
|
|
210
214
|
// Both row actions ride the same runtime remote: the Host steers a live
|
|
211
215
|
// session, rebuilds an orphaned composition, or re-runs a failed activation.
|
|
212
216
|
const recover = async () => {
|
|
@@ -241,25 +245,32 @@ function AgentRow({ status, current, updateMember, recoverMember, archiveMember,
|
|
|
241
245
|
}
|
|
242
246
|
};
|
|
243
247
|
const archive = async () => {
|
|
248
|
+
if (archivePending)
|
|
249
|
+
return;
|
|
250
|
+
setArchivePending(true);
|
|
251
|
+
setRowAlert(undefined);
|
|
252
|
+
archiveRequest.current ??= mintRequestId();
|
|
253
|
+
const request = { requestId: archiveRequest.current, memberId: status.member.memberId };
|
|
244
254
|
try {
|
|
245
|
-
const result = await archiveMember(
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
255
|
+
const result = withdrawing ? await leaveWorkspace({ ...request, workspaceId }) : await archiveMember(request);
|
|
256
|
+
if (!result.ok)
|
|
257
|
+
throw new Error(result.error.message);
|
|
258
|
+
setArchiving(false);
|
|
259
|
+
archiveRequest.current = undefined;
|
|
249
260
|
await onUpdated();
|
|
250
|
-
if (!result.ok) {
|
|
251
|
-
setRowAlert(t('archiveAgentFailed', { message: result.error.message }));
|
|
252
|
-
}
|
|
253
261
|
}
|
|
254
262
|
catch (cause) {
|
|
255
|
-
setRowAlert(
|
|
263
|
+
setRowAlert(cause instanceof Error ? cause.message : String(cause));
|
|
264
|
+
}
|
|
265
|
+
finally {
|
|
266
|
+
setArchivePending(false);
|
|
256
267
|
}
|
|
257
268
|
};
|
|
258
269
|
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: css.agentRow, "data-agent-row": true, "data-menu-open": menuOpen || undefined, children: [_jsx("button", { type: "button", className: css.agentSelect, "aria-label": t('openAgentSession', { name: status.member.handle }), "aria-current": current ? 'page' : undefined, disabled: status.availability !== 'active', onClick: () => { openMemberSession(status.member.sessionId); }, children: _jsx(TeamMemberIdentity, { status: status, name: status.member.handle.replace(/^@/, ''), className: css.agentCopy, t: t }) }), _jsx("span", { className: css.rowMenu, children: _jsx(TeamRowMenu, { label: t('actionsAgent', { name: status.member.handle }), items: [
|
|
259
270
|
{ id: 'edit', label: t('editAgent'), icon: _jsx(IconEditOutline16, {}) },
|
|
260
271
|
...(status.presence === 'error' ? [{ id: 'resume', label: t('resumeAgent'), icon: _jsx(IconPlayOutline16, {}) }] : []),
|
|
261
272
|
...(status.availability === 'unavailable' && restartOffered(status) ? [{ id: 'restart', label: t('restartAgent'), icon: _jsx(IconRefreshOutline16, {}) }] : []),
|
|
262
|
-
{ id: 'archive', label: t('archiveAgent'), icon: _jsx(IconArchiveOutline20, { size: 16 }), danger: true },
|
|
273
|
+
{ id: 'archive', label: t(withdrawing ? 'withdrawAgent' : 'archiveAgent'), icon: _jsx(IconArchiveOutline20, { size: 16 }), danger: true },
|
|
263
274
|
], onSelect: (id) => {
|
|
264
275
|
if (id === 'edit')
|
|
265
276
|
setEditing(true);
|
|
@@ -267,5 +278,6 @@ function AgentRow({ status, current, updateMember, recoverMember, archiveMember,
|
|
|
267
278
|
setArchiving(true);
|
|
268
279
|
else
|
|
269
280
|
void recover();
|
|
270
|
-
}, onOpenChange: setMenuOpen }) })] }), rowAlert !== undefined && _jsx("div", { className: css.rowAlert, role: "alert", children: rowAlert }), archiving && (
|
|
281
|
+
}, onOpenChange: setMenuOpen }) })] }), !archiving && rowAlert !== undefined && _jsx("div", { className: css.rowAlert, role: "alert", children: rowAlert }), archiving && (_jsxs(Modal, { open: true, onClose: () => { if (!archivePending)
|
|
282
|
+
setArchiving(false); }, title: t(withdrawing ? 'withdrawAgentTitle' : 'archiveAgentTitle', { name: status.member.handle }), closeLabel: t('close'), contentClassName: createCss.dialogContent, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: archivePending, onClick: () => { setArchiving(false); }, children: t('cancel') }), _jsx(Button, { variant: "primary", disabled: archivePending, onClick: () => { void archive(); }, children: t(withdrawing ? 'withdrawAgent' : 'archiveAgentConfirm') })] }), children: [_jsx("p", { className: createCss.error, children: t(withdrawing ? 'withdrawAgentNotice' : 'archiveAgentNotice', { name: status.member.handle }) }), !withdrawing && status.workspaceIds.length > 1 && _jsx("p", { children: t('archiveOtherWorkspaces', { count: status.workspaceIds.length - 1 }) }), rowAlert !== undefined && _jsx("p", { className: createCss.error, role: "alert", children: rowAlert })] })), editing && (_jsx(AgentEditorDialog, { status: status, updateMember: updateMember, loadModels: loadModels, onCommitted: onUpdated, onClose: () => { setEditing(false); }, t: t }))] }));
|
|
271
283
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamChannelPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamChannelPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA+B,mBAAmB,EAE7D,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEvD,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,aAAa,CAAA;AAiB/D,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAA;IACxC,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,CAAA;IACpE,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,iGAAiG;IACjG,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAA;IACtD,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,mBAAmB,EAAE,qBAAqB,CAAC,qBAAqB,CAAC,CAAA;IAC1E,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,cAAc,EAAE,qBAAqB,CAAC,gBAAgB,CAAC,CAAA;IAChE,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;
|
|
1
|
+
{"version":3,"file":"TeamChannelPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamChannelPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA+B,mBAAmB,EAE7D,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEvD,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,aAAa,CAAA;AAiB/D,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAA;IACxC,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,CAAA;IACpE,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,iGAAiG;IACjG,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAA;IACtD,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,mBAAmB,EAAE,qBAAqB,CAAC,qBAAqB,CAAC,CAAA;IAC1E,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,cAAc,EAAE,qBAAqB,CAAC,gBAAgB,CAAC,CAAA;IAChE,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AAoCD,wBAAgB,eAAe,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,mBAAmB,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC,EAAE,EAAE,oBAAoB,+BAgX9R"}
|
|
@@ -8,7 +8,7 @@ import { TeamMessage } from "./TeamMessage.js";
|
|
|
8
8
|
import { TeamAvatarStack } from "./TeamAvatarStack.js";
|
|
9
9
|
import { TeamCountBadge } from "./TeamCountBadge.js";
|
|
10
10
|
import { TeamRunDivider } from "./TeamRunDivider.js";
|
|
11
|
-
import { formatAbsoluteTime, formatInboxTime, formatTaskStatus, taskStatusDot, mentionNamesOf } from "./team-formatters.js";
|
|
11
|
+
import { claimersLabel, formatAbsoluteTime, formatInboxTime, formatTaskStatus, taskStatusDot, mentionNamesOf } from "./team-formatters.js";
|
|
12
12
|
import { TeamStateDot } from "./TeamStateDot.js";
|
|
13
13
|
import { useChannelMembership } from "./team-membership.js";
|
|
14
14
|
import { useTimelineScroll } from "./timeline-scroll.js";
|
|
@@ -35,30 +35,6 @@ function mergeChannelView(current, fresh) {
|
|
|
35
35
|
hasMore: fresh.hasMore || current.cursor < fresh.cursor,
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
|
-
/**
|
|
39
|
-
* The people the Channel feed shows on one Task: owners of its live Claims, in
|
|
40
|
-
* claim order, deduped. Claim state is a Host fact, not decoration — a released
|
|
41
|
-
* Claim is no longer work — and only a Task still in progress or review has
|
|
42
|
-
* any, because a done or closed Task keeps its Claims as history that the state
|
|
43
|
-
* word already tells the reader.
|
|
44
|
-
*/
|
|
45
|
-
function liveOwnersByTask(items, claims) {
|
|
46
|
-
const live = new Set(items
|
|
47
|
-
.flatMap(item => item.task === undefined ? [] : [item.task])
|
|
48
|
-
.filter(task => task.status === 'in_progress' || task.status === 'in_review')
|
|
49
|
-
.map(task => task.taskRef));
|
|
50
|
-
const owners = new Map();
|
|
51
|
-
for (const claim of claims) {
|
|
52
|
-
if (!live.has(claim.taskRef) || claim.state === 'released')
|
|
53
|
-
continue;
|
|
54
|
-
const known = owners.get(claim.taskRef);
|
|
55
|
-
if (known === undefined)
|
|
56
|
-
owners.set(claim.taskRef, [claim.owner]);
|
|
57
|
-
else if (!known.includes(claim.owner))
|
|
58
|
-
known.push(claim.owner);
|
|
59
|
-
}
|
|
60
|
-
return owners;
|
|
61
|
-
}
|
|
62
38
|
/**
|
|
63
39
|
* The newest fact instant, or nothing when the entry's own Message is still the
|
|
64
40
|
* newest fact on its Thread. That difference is exactly what "has follow-up
|
|
@@ -76,7 +52,9 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
76
52
|
const [view, setView] = useState();
|
|
77
53
|
const [members, setMembers] = useState([]);
|
|
78
54
|
const [unreadByThread, setUnreadByThread] = useState(new Map());
|
|
79
|
-
const [
|
|
55
|
+
const [actionError, setError] = useState();
|
|
56
|
+
const [loadError, setLoadError] = useState();
|
|
57
|
+
const error = actionError ?? loadError;
|
|
80
58
|
const [pendingFiles, setPendingFiles] = useState([]);
|
|
81
59
|
const [statusMessage, setStatusMessage] = useState();
|
|
82
60
|
const [loading, setLoading] = useState(true);
|
|
@@ -146,10 +124,6 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
146
124
|
const onlineCount = channelMembers.filter(status => status.presence === 'available' || status.presence === 'working').length;
|
|
147
125
|
const messageSender = (item) => item.message.sender;
|
|
148
126
|
const handleByMember = new Map(members.map(status => [status.member.memberId, status.member.handle.replace(/^@/, '')]));
|
|
149
|
-
// Claim owners ride the same Host projection as everything else; the map is
|
|
150
|
-
// rebuilt per render because the window is small and identity must never lag
|
|
151
|
-
// a change wake.
|
|
152
|
-
const ownersByTask = liveOwnersByTask(view?.items ?? [], view?.claims ?? []);
|
|
153
127
|
const refresh = async (clearError = false) => {
|
|
154
128
|
if (!mountedRef.current)
|
|
155
129
|
return false;
|
|
@@ -160,7 +134,7 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
160
134
|
if (!loadedRef.current)
|
|
161
135
|
setLoading(true);
|
|
162
136
|
if (clearError) {
|
|
163
|
-
|
|
137
|
+
setLoadError(undefined);
|
|
164
138
|
setStatusMessage(undefined);
|
|
165
139
|
}
|
|
166
140
|
try {
|
|
@@ -180,24 +154,26 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
180
154
|
loadedRef.current = true;
|
|
181
155
|
}
|
|
182
156
|
else
|
|
183
|
-
|
|
157
|
+
setLoadError(loaded.error.message);
|
|
184
158
|
if (loadedMembers.ok)
|
|
185
159
|
setMembers(loadedMembers.value);
|
|
186
160
|
else
|
|
187
|
-
|
|
161
|
+
setLoadError(loadedMembers.error.message);
|
|
188
162
|
// A failed unread read drops the badges instead of leaving counts the
|
|
189
163
|
// reader can no longer trust; the failure surfaces like any other read.
|
|
190
164
|
if (loadedInbox.ok)
|
|
191
165
|
setUnreadByThread(unreadCounts(loadedInbox.value));
|
|
192
166
|
else {
|
|
193
167
|
setUnreadByThread(new Map());
|
|
194
|
-
|
|
168
|
+
setLoadError(loadedInbox.error.message);
|
|
195
169
|
}
|
|
170
|
+
if (loaded.ok && loadedMembers.ok && loadedInbox.ok)
|
|
171
|
+
setLoadError(undefined);
|
|
196
172
|
return loaded.ok && loadedMembers.ok && loadedInbox.ok;
|
|
197
173
|
}
|
|
198
174
|
catch (cause) {
|
|
199
175
|
if (mountedRef.current && sequence === refreshSequenceRef.current)
|
|
200
|
-
|
|
176
|
+
setLoadError(cause instanceof Error ? cause.message : String(cause));
|
|
201
177
|
return false;
|
|
202
178
|
}
|
|
203
179
|
finally {
|
|
@@ -217,18 +193,18 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
217
193
|
if (loaded.ok)
|
|
218
194
|
setMembers(loaded.value);
|
|
219
195
|
else
|
|
220
|
-
|
|
196
|
+
setLoadError(loaded.error.message);
|
|
221
197
|
}
|
|
222
198
|
catch (cause) {
|
|
223
199
|
if (mountedRef.current)
|
|
224
|
-
|
|
200
|
+
setLoadError(cause instanceof Error ? cause.message : String(cause));
|
|
225
201
|
}
|
|
226
202
|
};
|
|
227
203
|
useEffect(() => {
|
|
228
204
|
mountedRef.current = true;
|
|
229
205
|
loadedRef.current = false;
|
|
230
206
|
setView(undefined);
|
|
231
|
-
|
|
207
|
+
setLoadError(undefined);
|
|
232
208
|
setLoading(true);
|
|
233
209
|
setManagingMembers(false);
|
|
234
210
|
void refresh();
|
|
@@ -237,7 +213,7 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
237
213
|
if (!mountedRef.current)
|
|
238
214
|
return;
|
|
239
215
|
if (update.type === 'failed') {
|
|
240
|
-
|
|
216
|
+
setLoadError(update.message);
|
|
241
217
|
return;
|
|
242
218
|
}
|
|
243
219
|
void refresh();
|
|
@@ -246,7 +222,7 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
246
222
|
if (!mountedRef.current)
|
|
247
223
|
return;
|
|
248
224
|
if (update.type === 'failed') {
|
|
249
|
-
|
|
225
|
+
setLoadError(update.message);
|
|
250
226
|
return;
|
|
251
227
|
}
|
|
252
228
|
void refreshMembers();
|
|
@@ -257,7 +233,7 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
257
233
|
if (!mountedRef.current)
|
|
258
234
|
return;
|
|
259
235
|
if (update.type === 'failed') {
|
|
260
|
-
|
|
236
|
+
setLoadError(update.message);
|
|
261
237
|
return;
|
|
262
238
|
}
|
|
263
239
|
void refreshMembers();
|
|
@@ -395,10 +371,9 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
395
371
|
// leads that line: ownership, status, and unread answer the reader
|
|
396
372
|
// where they are already reading. A reply inside a Thread has none
|
|
397
373
|
// of it — the Thread page owns that surface.
|
|
398
|
-
const owners = task === undefined ? [] : ownersByTask.get(task.taskRef) ?? [];
|
|
399
374
|
const unread = unreadByThread.get(item.thread.threadRef) ?? 0;
|
|
400
375
|
// A turn divider already labels the gapped entry; its row stays chrome-free.
|
|
401
|
-
return _jsxs(Fragment, { children: [turnGap && _jsx(TeamRunDivider, { occurredAt: item.message.occurredAt }), _jsx(TeamMessage, { senderName: sender, memberId: item.message.sender, human: human, body: item.message.body, attachments: item.message.attachments, loadAttachment: getAttachment, t: t, occurredAt: item.message.occurredAt, mentionNames: mentionNamesOf(item.mentions, handleByMember), onOpenRef: openRef, onResolveTaskRefs: lookupTaskRefs, grouped: index > 0, showGroupedTime: item.message.topLevel === true && !turnGap, ...(senderStatus === undefined ? {} : { senderTitle: senderStatus.member.description }), children: item.message.topLevel && _jsx(ThreadEntryRow, { item: item, owners:
|
|
376
|
+
return _jsxs(Fragment, { children: [turnGap && _jsx(TeamRunDivider, { occurredAt: item.message.occurredAt }), _jsx(TeamMessage, { senderName: sender, memberId: item.message.sender, human: human, body: item.message.body, attachments: item.message.attachments, loadAttachment: getAttachment, t: t, occurredAt: item.message.occurredAt, mentionNames: mentionNamesOf(item.mentions, handleByMember), onOpenRef: openRef, onResolveTaskRefs: lookupTaskRefs, grouped: index > 0, showGroupedTime: item.message.topLevel === true && !turnGap, ...(senderStatus === undefined ? {} : { senderTitle: senderStatus.member.description }), children: item.message.topLevel && _jsx(ThreadEntryRow, { item: item, owners: item.claimOwners, unread: unread, t: t, onOpen: () => { selectThread(item.thread.threadRef, channelRef, task?.taskRef, item.taskNumber); } }) })] }, item.message.messageRef);
|
|
402
377
|
}) }, `run-${block.items[0].message.messageRef}`))] }) }), channel !== undefined ? _jsx(TeamComposer, { members: channelMembers, drafts: drafts, draftKey: draftKey, pending: pending, ...(statusMessage === undefined ? {} : { confirmation: statusMessage }), ...(error === undefined ? {} : { error }), onEdit: clearSendState, onSubmit: () => { void send(); }, pendingFiles: pendingFiles, onFilesChange: setPendingFiles, asTask: asTask, onAsTaskChange: setAsTask, t: t }, draftKey) : _jsx("div", {})] });
|
|
403
378
|
}
|
|
404
379
|
/**
|
|
@@ -413,7 +388,7 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
413
388
|
function ThreadStateCluster({ task, owners, unread, t }) {
|
|
414
389
|
if (task === undefined && unread === 0)
|
|
415
390
|
return null;
|
|
416
|
-
return _jsxs("span", { className: css.stateCluster, children: [task !== undefined && _jsx(TeamAvatarStack, { owners: owners, label:
|
|
391
|
+
return _jsxs("span", { className: css.stateCluster, children: [task !== undefined && _jsx(TeamAvatarStack, { owners: owners, label: claimersLabel(owners, t) }), task !== undefined && _jsx(TeamStateDot, { size: 8, state: taskStatusDot(task.status) }), task !== undefined && _jsx("span", { className: css.statusWord, children: formatTaskStatus(task.status, t) }), _jsx(TeamCountBadge, { count: unread })] });
|
|
417
392
|
}
|
|
418
393
|
/**
|
|
419
394
|
* The gate under one top-level Message: the single row that opens its Thread,
|
|
@@ -12,8 +12,8 @@ interface TeamInboxPageProps {
|
|
|
12
12
|
* The Human Inbox: one Inbox call per visible Workspace, rendering the Host's
|
|
13
13
|
* two slices — the unread queue (「需要我」, mentions counted inside it rather
|
|
14
14
|
* than alone) and the 「最近活跃」 tail of Threads the reader took part in.
|
|
15
|
-
* Both merge across every Workspace into one
|
|
16
|
-
* first
|
|
15
|
+
* Both merge across every Workspace into one list in the Host's own order,
|
|
16
|
+
* mentions first and then newest, rather than by Workspace.
|
|
17
17
|
* Opening the page never acknowledges anything — only a durable Thread read
|
|
18
18
|
* advances the watermark and consumes a mention marker, so rows and the badge
|
|
19
19
|
* drop after the Thread is opened through the existing auto-ack path. A Thread
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamInboxPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamInboxPage.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAavD,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAA;IACtD,mGAAmG;IACnG,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,CAAA;IACpE,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;
|
|
1
|
+
{"version":3,"file":"TeamInboxPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamInboxPage.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAavD,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAA;IACtD,mGAAmG;IACnG,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,CAAA;IACpE,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AA0BD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAAE,aAAa,EAAE,SAAS,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC,EAAE,EAAE,kBAAkB,+BA0GjI"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { Button } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
|
-
import { formatAbsoluteTime, formatInboxTime } from "./team-formatters.js";
|
|
4
|
+
import { claimersLabel, formatAbsoluteTime, formatInboxTime } from "./team-formatters.js";
|
|
5
5
|
import { TeamAvatarStack } from "./TeamAvatarStack.js";
|
|
6
6
|
import { TeamCountBadge } from "./TeamCountBadge.js";
|
|
7
7
|
import css from './conversation.module.css';
|
|
@@ -15,24 +15,25 @@ import inboxCss from './inbox.module.css';
|
|
|
15
15
|
*/
|
|
16
16
|
const RECENT_ROWS_LIMIT = 5;
|
|
17
17
|
/**
|
|
18
|
-
* Queue order
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
18
|
+
* Queue order, one total order across Workspaces: the Host's own keys —
|
|
19
|
+
* mentions first, then the ledger sequence, then the Thread ref. Each Workspace
|
|
20
|
+
* slice already arrives in this order, and it is also the Host's truncation
|
|
21
|
+
* policy, so the merge re-applies it instead of inventing a second one: a row
|
|
22
|
+
* that survived the cut on mentions must not sink below a merely newer row
|
|
23
|
+
* after the merge. `newestSequence` is a global ledger position, so it stays
|
|
24
|
+
* comparable across Workspaces.
|
|
23
25
|
*/
|
|
24
26
|
function compareInboxRows(left, right) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return byTime !== 0 ? byTime : right.item.newestSequence - left.item.newestSequence;
|
|
27
|
+
return right.item.directCount - left.item.directCount
|
|
28
|
+
|| right.item.newestSequence - left.item.newestSequence
|
|
29
|
+
|| left.item.thread.threadRef.localeCompare(right.item.thread.threadRef);
|
|
29
30
|
}
|
|
30
31
|
/**
|
|
31
32
|
* The Human Inbox: one Inbox call per visible Workspace, rendering the Host's
|
|
32
33
|
* two slices — the unread queue (「需要我」, mentions counted inside it rather
|
|
33
34
|
* than alone) and the 「最近活跃」 tail of Threads the reader took part in.
|
|
34
|
-
* Both merge across every Workspace into one
|
|
35
|
-
* first
|
|
35
|
+
* Both merge across every Workspace into one list in the Host's own order,
|
|
36
|
+
* mentions first and then newest, rather than by Workspace.
|
|
36
37
|
* Opening the page never acknowledges anything — only a durable Thread read
|
|
37
38
|
* advances the watermark and consumes a mention marker, so rows and the badge
|
|
38
39
|
* drop after the Thread is opened through the existing auto-ack path. A Thread
|
|
@@ -61,7 +62,7 @@ export function TeamInboxPage({ useWorkspaces, loadInbox, subscribeChanges, sele
|
|
|
61
62
|
const asRows = (items, workspaceId, workspaceTitle) => items.map(item => ({ workspaceId, workspaceTitle, item }));
|
|
62
63
|
setRows(results.flatMap(result => result.ok ? asRows(result.items, result.workspaceId, result.workspaceTitle) : []).sort(compareInboxRows));
|
|
63
64
|
// The tail is one global bound rather than one per Workspace: the reader was
|
|
64
|
-
// promised
|
|
65
|
+
// promised five Threads to step back into, and every Workspace's slice is
|
|
65
66
|
// already capped on its own, so the merged list is trimmed here.
|
|
66
67
|
setRecentRows(results.flatMap(result => result.ok ? asRows(result.recent, result.workspaceId, result.workspaceTitle) : [])
|
|
67
68
|
.sort(compareInboxRows).slice(0, RECENT_ROWS_LIMIT));
|
|
@@ -134,6 +135,6 @@ function InboxQueueRow({ row, t, showWorkspace, onOpen }) {
|
|
|
134
135
|
? t('inboxRowUnreadMentions', { count: item.unreadCount, mentions: item.directCount })
|
|
135
136
|
: t('inboxRowUnread', { count: item.unreadCount });
|
|
136
137
|
return _jsxs("button", { type: "button", className: inboxCss.row, "data-named": named || undefined, onClick: onOpen, children: [_jsx("span", { className: inboxCss.rowActor, children: owners.length > 0
|
|
137
|
-
? _jsx(TeamAvatarStack, { owners: owners, label:
|
|
138
|
+
? _jsx(TeamAvatarStack, { owners: owners, label: claimersLabel(owners, t) })
|
|
138
139
|
: _jsx(TeamAvatarStack, { owners: [actor], label: t('inboxRowActor', { name: `@${actor.name}` }) }) }), _jsxs("span", { className: inboxCss.rowLine, children: [_jsxs("span", { className: inboxCss.rowCrumb, children: [showWorkspace && _jsx("span", { className: inboxCss.rowWorkspace, children: row.workspaceTitle }), showWorkspace && ' / ', _jsxs("span", { className: inboxCss.rowChannel, children: ["#", item.channelName] }), ' ', item.taskNumber !== undefined && _jsx("span", { className: inboxCss.rowTask, children: t('taskLabel', { number: item.taskNumber }) })] }), _jsx(TeamCountBadge, { count: item.unreadCount, tone: named ? 'solid' : 'hairline', label: countLabel }), _jsx("time", { className: inboxCss.rowTime, dateTime: item.newestOccurredAt, title: formatAbsoluteTime(item.newestOccurredAt), children: formatInboxTime(item.newestOccurredAt, t) })] }), _jsx("span", { className: inboxCss.rowPreview, children: item.previewText })] });
|
|
139
140
|
}
|
|
@@ -3,7 +3,7 @@ import type { TeamSidebarProps } from './slots.ts';
|
|
|
3
3
|
import type { TeamStateDotState } from './TeamStateDot.tsx';
|
|
4
4
|
export declare function presenceLabel(status: AgentTeamClientMemberStatus, t: TeamSidebarProps['t']): string;
|
|
5
5
|
/** One line of human-readable diagnostic text: the reason, plus the refused artifact path when one was reported. */
|
|
6
|
-
export declare function diagnosticText(status: AgentTeamClientMemberStatus): string;
|
|
6
|
+
export declare function diagnosticText(status: Pick<AgentTeamClientMemberStatus, 'diagnostic'>): string;
|
|
7
7
|
/**
|
|
8
8
|
* Whether the restart action can help an unavailable Member: it heals
|
|
9
9
|
* transient and repairable failures, but not a transient rollover window
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamPresenceDot.d.ts","sourceRoot":"","sources":["../../../src/client/TeamPresenceDot.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAG3D,wBAAgB,aAAa,CAAC,MAAM,EAAE,2BAA2B,EAAE,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,MAAM,CAKnG;AAED,oHAAoH;AACpH,wBAAgB,cAAc,CAAC,MAAM,EAAE,2BAA2B,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"TeamPresenceDot.d.ts","sourceRoot":"","sources":["../../../src/client/TeamPresenceDot.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAG3D,wBAAgB,aAAa,CAAC,MAAM,EAAE,2BAA2B,EAAE,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,MAAM,CAKnG;AAED,oHAAoH;AACpH,wBAAgB,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,2BAA2B,EAAE,YAAY,CAAC,GAAG,MAAM,CAI9F;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,2BAA2B,GAAG,OAAO,CAK3E;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,2BAA2B,CAAC,UAAU,CAAC,GAAG,iBAAiB,CAErG;AAED,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE;IAC7C,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAA;IAC5C,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC,+BASA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamThreadPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamThreadPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,mBAAmB,EAInB,gBAAgB,EAGhB,kBAAkB,EAEnB,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"TeamThreadPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamThreadPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,mBAAmB,EAInB,gBAAgB,EAGhB,kBAAkB,EAEnB,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,aAAa,CAAA;AAc/D,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,mBAAmB,CAAA;IACzC,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAA;IACnC,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAA;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAA;IACxD,QAAQ,CAAC,iBAAiB,EAAE,qBAAqB,CAAC,mBAAmB,CAAC,CAAA;IACtE,QAAQ,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,oBAAoB,CAAC,CAAA;IACxE,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,CAAA;IACpE,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAA;IAC9C,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAA;IACxD,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AA+CD,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,+BA2uBxD"}
|