agent-relay-server 0.82.0 → 0.83.1
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/docs/openapi.json +367 -1
- package/package.json +2 -2
- package/public/assets/MessageBubble-BTBQr8uG.js +3 -0
- package/public/assets/MessageBubble-BTBQr8uG.js.map +1 -0
- package/public/assets/{PlanGraphPanel-r3aVT4uc.js → PlanGraphPanel-CoWJJVyD.js} +2 -2
- package/public/assets/{PlanGraphPanel-r3aVT4uc.js.map → PlanGraphPanel-CoWJJVyD.js.map} +1 -1
- package/public/assets/activity-XqRFu_9T.js +2 -0
- package/public/assets/{activity-DtMjjws8.js.map → activity-XqRFu_9T.js.map} +1 -1
- package/public/assets/{agent-profiles-eRlq98tp.js → agent-profiles-RFCLAgnC.js} +2 -2
- package/public/assets/{agent-profiles-eRlq98tp.js.map → agent-profiles-RFCLAgnC.js.map} +1 -1
- package/public/assets/{agents-DmbjRTA7.js → agents-BWmmWj4Q.js} +2 -2
- package/public/assets/{agents-DmbjRTA7.js.map → agents-BWmmWj4Q.js.map} +1 -1
- package/public/assets/{analytics-BW7ik_Ws.js → analytics-2H2z2UNS.js} +3 -3
- package/public/assets/{analytics-BW7ik_Ws.js.map → analytics-2H2z2UNS.js.map} +1 -1
- package/public/assets/{automation-CxwGXWC7.js → automation-DRtOENs0.js} +2 -2
- package/public/assets/{automation-CxwGXWC7.js.map → automation-DRtOENs0.js.map} +1 -1
- package/public/assets/{badge-BwaoBnNO.js → badge-CK6ejiOh.js} +2 -2
- package/public/assets/{badge-BwaoBnNO.js.map → badge-CK6ejiOh.js.map} +1 -1
- package/public/assets/branch-state-badge-DxwNcWr8.js +2 -0
- package/public/assets/{branch-state-badge-CvdKPTlV.js.map → branch-state-badge-DxwNcWr8.js.map} +1 -1
- package/public/assets/{button-CFIklTDX.js → button-BAwKuRIq.js} +2 -2
- package/public/assets/{button-CFIklTDX.js.map → button-BAwKuRIq.js.map} +1 -1
- package/public/assets/{card-Bi94xEmr.js → card-DDxxo-Fo.js} +2 -2
- package/public/assets/{card-Bi94xEmr.js.map → card-DDxxo-Fo.js.map} +1 -1
- package/public/assets/{channels-D8UY3baa.js → channels-Sh_jdB7y.js} +2 -2
- package/public/assets/{channels-D8UY3baa.js.map → channels-Sh_jdB7y.js.map} +1 -1
- package/public/assets/chat-gfUxbTus.js +2 -0
- package/public/assets/{chat-CCPukbI9.js.map → chat-gfUxbTus.js.map} +1 -1
- package/public/assets/{connectors-W2MslhQ2.js → connectors-C3C4i4Gz.js} +2 -2
- package/public/assets/{connectors-W2MslhQ2.js.map → connectors-C3C4i4Gz.js.map} +1 -1
- package/public/assets/{copy-button-A0pXLXBy.js → copy-button-D3B_s7J7.js} +2 -2
- package/public/assets/{copy-button-A0pXLXBy.js.map → copy-button-D3B_s7J7.js.map} +1 -1
- package/public/assets/display-CWMHll1J.js.map +1 -1
- package/public/assets/{dist--NYpzm4f.js → dist-CAFUEpK2.js} +2 -2
- package/public/assets/{dist--NYpzm4f.js.map → dist-CAFUEpK2.js.map} +1 -1
- package/public/assets/dist-CIbvPDQV.js +2 -0
- package/public/assets/{dist-D3jA_LvQ.js.map → dist-CIbvPDQV.js.map} +1 -1
- package/public/assets/{dist-DY3KCMIN.js → dist-CL2npVDe.js} +2 -2
- package/public/assets/{dist-DY3KCMIN.js.map → dist-CL2npVDe.js.map} +1 -1
- package/public/assets/{dist-DVorlUcA.js → dist-CnRv0y2x.js} +2 -2
- package/public/assets/{dist-DVorlUcA.js.map → dist-CnRv0y2x.js.map} +1 -1
- package/public/assets/dist-CoRABSO3.js +2 -0
- package/public/assets/{dist-rLCXIl7x.js.map → dist-CoRABSO3.js.map} +1 -1
- package/public/assets/{dist-yzKYLD10.js → dist-DLsSqk6h.js} +2 -2
- package/public/assets/{dist-yzKYLD10.js.map → dist-DLsSqk6h.js.map} +1 -1
- package/public/assets/{dist-DhEz6YNy.js → dist-Dmiv1tSO.js} +2 -2
- package/public/assets/{dist-DhEz6YNy.js.map → dist-Dmiv1tSO.js.map} +1 -1
- package/public/assets/dist-DyqEeyBI.js +2 -0
- package/public/assets/{dist-HTxIFS7t.js.map → dist-DyqEeyBI.js.map} +1 -1
- package/public/assets/{dist-_EunAAFX.js → dist-ERYvDMdt.js} +2 -2
- package/public/assets/{dist-_EunAAFX.js.map → dist-ERYvDMdt.js.map} +1 -1
- package/public/assets/{dist-C4VoXCT-.js → dist-YQVQrtnc.js} +2 -2
- package/public/assets/{dist-C4VoXCT-.js.map → dist-YQVQrtnc.js.map} +1 -1
- package/public/assets/{dist-BODiHbq1.js → dist-YjP8Gd1C.js} +2 -2
- package/public/assets/{dist-BODiHbq1.js.map → dist-YjP8Gd1C.js.map} +1 -1
- package/public/assets/{es2015-BDZowz0r.js → es2015-Yto-4EBw.js} +2 -2
- package/public/assets/{es2015-BDZowz0r.js.map → es2015-Yto-4EBw.js.map} +1 -1
- package/public/assets/{formatted-body-impl-tIjgf9Kr.js → formatted-body-impl-DpNHGXXQ.js} +2 -2
- package/public/assets/{formatted-body-impl-tIjgf9Kr.js.map → formatted-body-impl-DpNHGXXQ.js.map} +1 -1
- package/public/assets/index-D8TVUdlC.js +22 -0
- package/public/assets/index-D8TVUdlC.js.map +1 -0
- package/public/assets/index-DgZLDL0K.css +2 -0
- package/public/assets/{input-CD-ZcZIA.js → input-CLW2gDUM.js} +2 -2
- package/public/assets/{input-CD-ZcZIA.js.map → input-CLW2gDUM.js.map} +1 -1
- package/public/assets/{insights-B93PGmKq.js → insights-DPaJ5Hme.js} +2 -2
- package/public/assets/{insights-B93PGmKq.js.map → insights-DPaJ5Hme.js.map} +1 -1
- package/public/assets/{integrations-BfWMAznM.js → integrations-PqWMrPJa.js} +2 -2
- package/public/assets/{integrations-BfWMAznM.js.map → integrations-PqWMrPJa.js.map} +1 -1
- package/public/assets/{lib-BqL6WCDu.js → lib-DdCM7GfN.js} +2 -2
- package/public/assets/{lib-BqL6WCDu.js.map → lib-DdCM7GfN.js.map} +1 -1
- package/public/assets/lucide-react-CsPXvXMC.js +9 -0
- package/public/assets/{lucide-react-D78N6SwK.js.map → lucide-react-CsPXvXMC.js.map} +1 -1
- package/public/assets/{maintenance-CgRASTD0.js → maintenance-DsszLb92.js} +2 -2
- package/public/assets/{maintenance-CgRASTD0.js.map → maintenance-DsszLb92.js.map} +1 -1
- package/public/assets/{managed-agents-B1AdrEv4.js → managed-agents-DqWPxFE0.js} +2 -2
- package/public/assets/{managed-agents-B1AdrEv4.js.map → managed-agents-DqWPxFE0.js.map} +1 -1
- package/public/assets/{markdown-preview-impl-D2zEt-i-.js → markdown-preview-impl-CWR4ILHK.js} +2 -2
- package/public/assets/{markdown-preview-impl-D2zEt-i-.js.map → markdown-preview-impl-CWR4ILHK.js.map} +1 -1
- package/public/assets/memory-C2s9bJ38.js +2 -0
- package/public/assets/{memory-nUBcij_9.js.map → memory-C2s9bJ38.js.map} +1 -1
- package/public/assets/{messages-BNDs53bW.js → messages-DHRJNAvy.js} +2 -2
- package/public/assets/{messages-BNDs53bW.js.map → messages-DHRJNAvy.js.map} +1 -1
- package/public/assets/{orchestrators-BouoI90a.js → orchestrators-BGNNllJc.js} +2 -2
- package/public/assets/{orchestrators-BouoI90a.js.map → orchestrators-BGNNllJc.js.map} +1 -1
- package/public/assets/{overview-C8_hAGpC.js → overview-C1vZfyhW.js} +2 -2
- package/public/assets/{overview-C8_hAGpC.js.map → overview-C1vZfyhW.js.map} +1 -1
- package/public/assets/{pairs-BcCOB1oO.js → pairs-C1uzo8x0.js} +2 -2
- package/public/assets/{pairs-BcCOB1oO.js.map → pairs-C1uzo8x0.js.map} +1 -1
- package/public/assets/{projects-MZ6CNrYO.js → projects-B2-8Eu0e.js} +2 -2
- package/public/assets/{projects-MZ6CNrYO.js.map → projects-B2-8Eu0e.js.map} +1 -1
- package/public/assets/{react-dom-CU0WCHqq.js → react-dom-CEl58oxP.js} +2 -2
- package/public/assets/{react-dom-CU0WCHqq.js.map → react-dom-CEl58oxP.js.map} +1 -1
- package/public/assets/{security-Bh8BGpZR.js → security-XhAAP6q3.js} +2 -2
- package/public/assets/{security-Bh8BGpZR.js.map → security-XhAAP6q3.js.map} +1 -1
- package/public/assets/{select-Drdvachg.js → select-DEGUFEjx.js} +2 -2
- package/public/assets/{select-Drdvachg.js.map → select-DEGUFEjx.js.map} +1 -1
- package/public/assets/settings-DTbVUdlZ.js +4 -0
- package/public/assets/{settings-IrNBT0hy.js.map → settings-DTbVUdlZ.js.map} +1 -1
- package/public/assets/{store-CqFZmc-B.js → store-DYaQAXRv.js} +5 -5
- package/public/assets/{store-CqFZmc-B.js.map → store-DYaQAXRv.js.map} +1 -1
- package/public/assets/{tasks-heEgx7vT.js → tasks-zwGo7hon.js} +2 -2
- package/public/assets/{tasks-heEgx7vT.js.map → tasks-zwGo7hon.js.map} +1 -1
- package/public/assets/{teams-BjETr-_W.js → teams-Brc5D8ox.js} +2 -2
- package/public/assets/{teams-BjETr-_W.js.map → teams-Brc5D8ox.js.map} +1 -1
- package/public/assets/{terminal-viewer-impl-BDqmbWB3.js → terminal-viewer-impl-C6yUAL8G.js} +3 -3
- package/public/assets/{terminal-viewer-impl-BDqmbWB3.js.map → terminal-viewer-impl-C6yUAL8G.js.map} +1 -1
- package/public/assets/{use-keyboard-viewport-CichJ8Jn.js → use-keyboard-viewport-DABeIMEJ.js} +2 -2
- package/public/assets/{use-keyboard-viewport-CichJ8Jn.js.map → use-keyboard-viewport-DABeIMEJ.js.map} +1 -1
- package/public/assets/user-avatar-Bw1R011j.js +2 -0
- package/public/assets/user-avatar-Bw1R011j.js.map +1 -0
- package/public/assets/{work-queue-rgQs4Wis.js → work-queue-ge4R7keo.js} +2 -2
- package/public/assets/{work-queue-rgQs4Wis.js.map → work-queue-ge4R7keo.js.map} +1 -1
- package/public/assets/workspaces-BhblC-Nd.js +3 -0
- package/public/assets/{workspaces-hIjZicaF.js.map → workspaces-BhblC-Nd.js.map} +1 -1
- package/public/index.html +21 -21
- package/src/agent-drive-arbiter.ts +112 -0
- package/src/db/artifacts.ts +2 -3
- package/src/db/drive-leases.ts +165 -0
- package/src/db/index.ts +1 -0
- package/src/db/migrations.ts +6 -0
- package/src/db/users.ts +26 -0
- package/src/maintenance/jobs.ts +11 -0
- package/src/routes/_shared.ts +1 -1
- package/src/routes/agent-sessions.ts +97 -1
- package/src/routes/artifacts.ts +7 -3
- package/src/routes/index.ts +13 -2
- package/src/routes/users.ts +152 -6
- package/src/security.ts +2 -0
- package/src/services/user-profile.ts +69 -0
- package/src/upgrade-install-verify.ts +160 -0
- package/src/upgrade.ts +40 -11
- package/public/assets/MessageBubble-ckJ2VVgq.js +0 -3
- package/public/assets/MessageBubble-ckJ2VVgq.js.map +0 -1
- package/public/assets/activity-DtMjjws8.js +0 -2
- package/public/assets/branch-state-badge-CvdKPTlV.js +0 -2
- package/public/assets/chat-CCPukbI9.js +0 -2
- package/public/assets/dist-D3jA_LvQ.js +0 -2
- package/public/assets/dist-HTxIFS7t.js +0 -2
- package/public/assets/dist-rLCXIl7x.js +0 -2
- package/public/assets/index-BfQFX8td.js +0 -22
- package/public/assets/index-BfQFX8td.js.map +0 -1
- package/public/assets/index-D8vc380x.css +0 -2
- package/public/assets/lucide-react-D78N6SwK.js +0 -9
- package/public/assets/memory-nUBcij_9.js +0 -2
- package/public/assets/settings-IrNBT0hy.js +0 -4
- package/public/assets/workspaces-hIjZicaF.js +0 -3
package/src/routes/users.ts
CHANGED
|
@@ -1,8 +1,154 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
// User directory/profile surface for dashboard attribution & presentation (#390/#630).
|
|
2
|
+
// The row holds no auth secrets; avatar bytes stay in the artifact blob stack.
|
|
3
|
+
import { isRecord } from "agent-relay-sdk";
|
|
4
|
+
import {
|
|
5
|
+
ValidationError,
|
|
6
|
+
getArtifact,
|
|
7
|
+
getArtifactBlob,
|
|
8
|
+
getUser,
|
|
9
|
+
listUsers,
|
|
10
|
+
} from "../db";
|
|
11
|
+
import { getArtifactStorage, maxArtifactBytes } from "../artifact-storage";
|
|
12
|
+
import { cleanString } from "../validation";
|
|
13
|
+
import { error, isRootCredentialRequest, json, parseBody, requestUserAddress, requestUserId, type Handler } from "./_shared";
|
|
14
|
+
import { artifactContentDisposition, sniffMediaType } from "./artifacts";
|
|
15
|
+
import { removeUserAvatar, storeUserAvatar, updateUserDisplayName } from "../services/user-profile";
|
|
16
|
+
import type { Artifact, User } from "../types";
|
|
7
17
|
|
|
8
18
|
export const getUsers: Handler = () => json(listUsers());
|
|
19
|
+
|
|
20
|
+
const AVATAR_MAX_BYTES = 2 * 1024 * 1024;
|
|
21
|
+
const VALID_AVATAR_MEDIA_TYPES = new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
|
|
22
|
+
|
|
23
|
+
function avatarMaxBytes(): number {
|
|
24
|
+
return Math.min(AVATAR_MAX_BYTES, maxArtifactBytes());
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function isAdminRequest(req: Request): boolean {
|
|
28
|
+
if (isRootCredentialRequest(req)) return true;
|
|
29
|
+
return getUser(requestUserId(req))?.role === "admin";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function canManageUser(req: Request, userId: string): boolean {
|
|
33
|
+
return requestUserId(req) === userId || isAdminRequest(req);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function canReadAvatar(req: Request, userId: string, artifact: Artifact): boolean {
|
|
37
|
+
if (artifact.visibility !== "private") return true;
|
|
38
|
+
return canManageUser(req, userId);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function userOr404(userId: string): User | Response {
|
|
42
|
+
return getUser(userId) ?? error("user not found", 404);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function userIdParam(req: Request, params: Record<string, string>): string {
|
|
46
|
+
return params.id ? decodeURIComponent(params.id) : requestUserId(req);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function profileError(e: unknown): Response {
|
|
50
|
+
if (e instanceof ValidationError) return error(e.message, 400);
|
|
51
|
+
throw e;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const getMe: Handler = (req) => {
|
|
55
|
+
const user = getUser(requestUserId(req));
|
|
56
|
+
return user ? json(user) : error("user not found", 404);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const patchMe: Handler = (req) => patchUserProfile(req, { id: requestUserId(req) });
|
|
60
|
+
|
|
61
|
+
export const patchUserById: Handler = (req, params) => patchUserProfile(req, params);
|
|
62
|
+
|
|
63
|
+
async function patchUserProfile(req: Request, params: Record<string, string>): Promise<Response> {
|
|
64
|
+
try {
|
|
65
|
+
const userId = userIdParam(req, params);
|
|
66
|
+
if (!canManageUser(req, userId)) return error("forbidden", 403);
|
|
67
|
+
const parsed = await parseBody<unknown>(req);
|
|
68
|
+
if (!parsed.ok) return error(parsed.error, parsed.status);
|
|
69
|
+
if (!isRecord(parsed.body)) return error("body must be an object");
|
|
70
|
+
const displayName = cleanString(parsed.body.displayName, "displayName", { required: true, max: 120 })!;
|
|
71
|
+
return json(updateUserDisplayName({ userId, displayName }));
|
|
72
|
+
} catch (e) {
|
|
73
|
+
return profileError(e);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const postMyAvatar: Handler = (req) => postUserAvatar(req, { id: requestUserId(req) });
|
|
78
|
+
|
|
79
|
+
export const postUserAvatarById: Handler = (req, params) => postUserAvatar(req, params);
|
|
80
|
+
|
|
81
|
+
async function avatarUploadInput(req: Request): Promise<{ bytes: Uint8Array; filename?: string; mediaType: string; digest?: string }> {
|
|
82
|
+
const contentType = req.headers.get("content-type") ?? "";
|
|
83
|
+
if (!contentType.includes("multipart/form-data")) throw new ValidationError("avatar upload requires multipart/form-data");
|
|
84
|
+
const form = await req.formData();
|
|
85
|
+
const file = form.get("file");
|
|
86
|
+
if (!(file instanceof File)) throw new ValidationError("multipart upload requires file");
|
|
87
|
+
const maxBytes = avatarMaxBytes();
|
|
88
|
+
if (file.size > maxBytes) throw new ValidationError(`avatar exceeds ${maxBytes} bytes`);
|
|
89
|
+
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
90
|
+
if (bytes.byteLength > maxBytes) throw new ValidationError(`avatar exceeds ${maxBytes} bytes`);
|
|
91
|
+
const mediaType = sniffMediaType(bytes, file.type || undefined, file.name);
|
|
92
|
+
if (!VALID_AVATAR_MEDIA_TYPES.has(mediaType)) throw new ValidationError("avatar must be a PNG, JPEG, GIF, or WebP image");
|
|
93
|
+
return {
|
|
94
|
+
bytes,
|
|
95
|
+
filename: cleanString(form.get("filename") ?? file.name, "filename", { max: 240 }),
|
|
96
|
+
mediaType,
|
|
97
|
+
digest: cleanString(form.get("digest"), "digest", { max: 80 }),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function postUserAvatar(req: Request, params: Record<string, string>): Promise<Response> {
|
|
102
|
+
try {
|
|
103
|
+
const userId = userIdParam(req, params);
|
|
104
|
+
const user = userOr404(userId);
|
|
105
|
+
if (user instanceof Response) return user;
|
|
106
|
+
if (!canManageUser(req, userId)) return error("forbidden", 403);
|
|
107
|
+
const input = await avatarUploadInput(req);
|
|
108
|
+
const result = await storeUserAvatar({ userId, actor: requestUserAddress(req), ...input });
|
|
109
|
+
return json(result, 201);
|
|
110
|
+
} catch (e) {
|
|
111
|
+
return profileError(e);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export const deleteMyAvatar: Handler = (req) => deleteUserAvatar(req, { id: requestUserId(req) });
|
|
116
|
+
|
|
117
|
+
export const deleteUserAvatarById: Handler = (req, params) => deleteUserAvatar(req, params);
|
|
118
|
+
|
|
119
|
+
function deleteUserAvatar(req: Request, params: Record<string, string>): Response {
|
|
120
|
+
try {
|
|
121
|
+
const userId = userIdParam(req, params);
|
|
122
|
+
const user = userOr404(userId);
|
|
123
|
+
if (user instanceof Response) return user;
|
|
124
|
+
if (!canManageUser(req, userId)) return error("forbidden", 403);
|
|
125
|
+
return json(removeUserAvatar({ userId }));
|
|
126
|
+
} catch (e) {
|
|
127
|
+
return profileError(e);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export const getUserAvatar: Handler = (req, params) => serveUserAvatar(req, params, false);
|
|
132
|
+
|
|
133
|
+
export const headUserAvatar: Handler = (req, params) => serveUserAvatar(req, params, true);
|
|
134
|
+
|
|
135
|
+
async function serveUserAvatar(req: Request, params: Record<string, string>, head: boolean): Promise<Response> {
|
|
136
|
+
const userId = userIdParam(req, params);
|
|
137
|
+
const user = getUser(userId);
|
|
138
|
+
if (!user?.avatarArtifactId) return error("avatar not found", 404);
|
|
139
|
+
const artifact = getArtifact(user.avatarArtifactId);
|
|
140
|
+
if (!artifact) return error("avatar artifact not found", 404);
|
|
141
|
+
if (!canReadAvatar(req, userId, artifact)) return error("forbidden", 403);
|
|
142
|
+
const blob = getArtifactBlob(artifact.blobDigest);
|
|
143
|
+
if (!blob) return error("avatar blob not found", 404);
|
|
144
|
+
const headers = {
|
|
145
|
+
"Content-Type": artifact.mediaType,
|
|
146
|
+
"Content-Length": String(artifact.size),
|
|
147
|
+
"Content-Disposition": artifactContentDisposition(artifact.filename, artifact.mediaType),
|
|
148
|
+
"Cache-Control": artifact.visibility === "private" ? "private, max-age=300" : "private, max-age=3600",
|
|
149
|
+
"X-Artifact-Digest": artifact.digest,
|
|
150
|
+
};
|
|
151
|
+
if (head) return new Response(null, { headers });
|
|
152
|
+
const content = await getArtifactStorage().retrieve(blob.storageUri);
|
|
153
|
+
return new Response(content.stream, { headers });
|
|
154
|
+
}
|
package/src/security.ts
CHANGED
|
@@ -163,6 +163,7 @@ export function requiredScopeFor(method: string, pathname: string): string | nul
|
|
|
163
163
|
if (method === "DELETE") return "artifact:admin";
|
|
164
164
|
return "artifact:write";
|
|
165
165
|
}
|
|
166
|
+
if (pathname.startsWith("/api/users")) return method === "GET" || method === "HEAD" ? "user:read" : "user:write";
|
|
166
167
|
if (pathname.startsWith("/api/memories")) {
|
|
167
168
|
if (method === "GET") return "memory:read";
|
|
168
169
|
if (pathname === "/api/memories/search") return "memory:read";
|
|
@@ -265,6 +266,7 @@ export function requiredComponentScopeFor(method: string, pathname: string): str
|
|
|
265
266
|
if (method === "DELETE") return "artifact:admin";
|
|
266
267
|
return "artifact:write";
|
|
267
268
|
}
|
|
269
|
+
if (pathname.startsWith("/api/users")) return method === "GET" || method === "HEAD" ? "user:read" : "user:write";
|
|
268
270
|
if (pathname.startsWith("/api/memories")) {
|
|
269
271
|
if (method === "GET") return "memory:read";
|
|
270
272
|
if (pathname === "/api/memories/search") return "memory:read";
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createArtifact,
|
|
3
|
+
deleteArtifactLinksForEntity,
|
|
4
|
+
linkArtifact,
|
|
5
|
+
updateUserProfile,
|
|
6
|
+
upsertArtifactBlob,
|
|
7
|
+
} from "../db";
|
|
8
|
+
import { getArtifactStorage, normalizeDigest } from "../artifact-storage";
|
|
9
|
+
import { bytesToStream } from "../http-body";
|
|
10
|
+
import { emitRelayEvent } from "../events";
|
|
11
|
+
import type { Artifact, User } from "../types";
|
|
12
|
+
|
|
13
|
+
export function updateUserDisplayName(input: { userId: string; displayName: string }): User {
|
|
14
|
+
const user = updateUserProfile({ id: input.userId, displayName: input.displayName });
|
|
15
|
+
emitRelayEvent({ type: "user.updated", source: "server", subject: user.id, data: { user } });
|
|
16
|
+
return user;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function storeUserAvatar(input: {
|
|
20
|
+
userId: string;
|
|
21
|
+
actor: string;
|
|
22
|
+
bytes: Uint8Array;
|
|
23
|
+
mediaType: string;
|
|
24
|
+
filename?: string;
|
|
25
|
+
digest?: string;
|
|
26
|
+
}): Promise<{ user: User; artifact: Artifact }> {
|
|
27
|
+
const storage = getArtifactStorage();
|
|
28
|
+
const stored = await storage.store(bytesToStream(input.bytes), {
|
|
29
|
+
mediaType: input.mediaType,
|
|
30
|
+
size: input.bytes.byteLength,
|
|
31
|
+
digest: input.digest ? normalizeDigest(input.digest) : undefined,
|
|
32
|
+
});
|
|
33
|
+
upsertArtifactBlob({
|
|
34
|
+
digest: stored.digest,
|
|
35
|
+
storageUri: stored.storageUri,
|
|
36
|
+
mediaType: input.mediaType,
|
|
37
|
+
size: stored.size,
|
|
38
|
+
});
|
|
39
|
+
const artifact = createArtifact({
|
|
40
|
+
blobDigest: stored.digest,
|
|
41
|
+
mediaType: input.mediaType,
|
|
42
|
+
kind: "avatar",
|
|
43
|
+
filename: input.filename,
|
|
44
|
+
size: stored.size,
|
|
45
|
+
visibility: "private",
|
|
46
|
+
sensitivity: "normal",
|
|
47
|
+
createdBy: input.actor,
|
|
48
|
+
metadata: { purpose: "avatar", userId: input.userId },
|
|
49
|
+
});
|
|
50
|
+
deleteArtifactLinksForEntity("user", input.userId);
|
|
51
|
+
linkArtifact({
|
|
52
|
+
artifactId: artifact.id,
|
|
53
|
+
entityType: "user",
|
|
54
|
+
entityId: input.userId,
|
|
55
|
+
role: "media",
|
|
56
|
+
title: input.filename ?? "avatar",
|
|
57
|
+
createdBy: input.actor,
|
|
58
|
+
});
|
|
59
|
+
const user = updateUserProfile({ id: input.userId, avatarArtifactId: artifact.id });
|
|
60
|
+
emitRelayEvent({ type: "user.avatar.updated", source: "server", subject: user.id, data: { user, artifact } });
|
|
61
|
+
return { user, artifact };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function removeUserAvatar(input: { userId: string }): User {
|
|
65
|
+
deleteArtifactLinksForEntity("user", input.userId);
|
|
66
|
+
const user = updateUserProfile({ id: input.userId, avatarArtifactId: null });
|
|
67
|
+
emitRelayEvent({ type: "user.avatar.removed", source: "server", subject: user.id, data: { user } });
|
|
68
|
+
return user;
|
|
69
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { chmodSync, existsSync, readFileSync, rmSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Post-install verification + repair for a runtime-prefix upgrade (#631).
|
|
6
|
+
*
|
|
7
|
+
* A clean `npm install` exit code is NOT proof the upgrade landed: npm reports
|
|
8
|
+
* "up to date" (exit 0, nothing installed) when its hidden
|
|
9
|
+
* `node_modules/.package-lock.json` claims the target version while the extracted
|
|
10
|
+
* package dirs are still stale (lock-vs-disk divergence). That silently stranded
|
|
11
|
+
* macmini2 on 0.82.0 during the v0.83.0 deploy. This module asserts the ACTUAL
|
|
12
|
+
* on-disk versions, repairs the divergence by forcing a real re-extraction, and
|
|
13
|
+
* restores the exec bit that extraction drops from bin entries.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** Metadata describing what a runtime-prefix install action must verify. */
|
|
17
|
+
export type VerifyInstall = {
|
|
18
|
+
/** Runtime prefix whose node_modules holds the installed packages. */
|
|
19
|
+
prefix: string;
|
|
20
|
+
targetVersion: string;
|
|
21
|
+
/** Package names (no version spec) to assert + repair + restore exec bits on. */
|
|
22
|
+
packages: string[];
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
type CommandOutput = { exitCode: number; stdout: string; stderr: string };
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Filesystem operations the verification needs, factored out so tests can drive
|
|
29
|
+
* the assertion/repair/exec-bit logic without a real npm install or touching
|
|
30
|
+
* disk. Defaults to {@link defaultInstallIo}.
|
|
31
|
+
*/
|
|
32
|
+
export type InstallIo = {
|
|
33
|
+
/** Actual installed version from `<prefix>/node_modules/<pkg>/package.json`. */
|
|
34
|
+
readInstalledVersion: (prefix: string, pkg: string) => string | undefined;
|
|
35
|
+
/** Delete `<prefix>/node_modules/<pkg>` so the next install must re-extract it. */
|
|
36
|
+
forceReextract: (prefix: string, pkg: string) => void;
|
|
37
|
+
/** Delete npm's hidden `<prefix>/node_modules/.package-lock.json`. */
|
|
38
|
+
removeHiddenLock: (prefix: string) => void;
|
|
39
|
+
/** chmod +x each of a package's bin entry targets; returns the files changed. */
|
|
40
|
+
restoreExecBits: (prefix: string, pkg: string) => string[];
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
type VersionMismatch = { pkg: string; expected: string; actual?: string };
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Assert the runtime packages reached the target version after npm reported
|
|
47
|
+
* success; on divergence, force a clean re-extraction and re-assert; finally
|
|
48
|
+
* restore the exec bit that npm extraction drops from bin entries. Appends a
|
|
49
|
+
* human-readable trace to `lines` and throws a loud, specific error on failure.
|
|
50
|
+
*/
|
|
51
|
+
export async function verifyAndRepairInstall(
|
|
52
|
+
action: { label: string; command: string[] },
|
|
53
|
+
verify: VerifyInstall,
|
|
54
|
+
runInstall: (command: string[]) => Promise<CommandOutput>,
|
|
55
|
+
io: InstallIo,
|
|
56
|
+
lines: string[],
|
|
57
|
+
): Promise<void> {
|
|
58
|
+
const findMismatches = (): VersionMismatch[] =>
|
|
59
|
+
verify.packages
|
|
60
|
+
.map((pkg) => ({ pkg, expected: verify.targetVersion, actual: io.readInstalledVersion(verify.prefix, pkg) }))
|
|
61
|
+
.filter((m) => m.actual !== verify.targetVersion);
|
|
62
|
+
|
|
63
|
+
let mismatches = findMismatches();
|
|
64
|
+
if (mismatches.length > 0) {
|
|
65
|
+
// Lock-vs-disk divergence: npm's hidden node_modules/.package-lock.json
|
|
66
|
+
// claimed the target while the extracted dirs lagged, so `npm install`
|
|
67
|
+
// returned "up to date" and installed nothing. Drop the stale dirs + hidden
|
|
68
|
+
// lock so the reinstall is forced to actually re-extract the tarballs.
|
|
69
|
+
lines.push(
|
|
70
|
+
`Installed versions disagree with ${verify.targetVersion} after npm reported success ` +
|
|
71
|
+
`(lock-vs-disk divergence): ${formatMismatches(mismatches)}. Forcing a clean re-extraction.`,
|
|
72
|
+
);
|
|
73
|
+
for (const m of mismatches) io.forceReextract(verify.prefix, m.pkg);
|
|
74
|
+
io.removeHiddenLock(verify.prefix);
|
|
75
|
+
|
|
76
|
+
const result = await runInstall(action.command);
|
|
77
|
+
if (result.stdout.trim()) lines.push(result.stdout.trim());
|
|
78
|
+
if (result.stderr.trim()) lines.push(result.stderr.trim());
|
|
79
|
+
if (result.exitCode !== 0) {
|
|
80
|
+
const detail = (result.stderr.trim() || result.stdout.trim()).slice(-2000);
|
|
81
|
+
throw new Error(`${action.label} re-extraction failed with exit code ${result.exitCode}${detail ? `:\n${detail}` : ""}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
mismatches = findMismatches();
|
|
85
|
+
if (mismatches.length > 0) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`${action.label} did not install ${verify.targetVersion}: ${formatMismatches(mismatches)}. ` +
|
|
88
|
+
`npm reported success but the runtime is unchanged; re-run the upgrade or inspect ${join(verify.prefix, "node_modules")}.`,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
lines.push(`Re-extraction reconciled the runtime to ${verify.targetVersion}.`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// npm extraction creates bin entry files mode 0644 (no +x). The systemd units
|
|
95
|
+
// ExecStart the .bin symlink → src/index.ts directly, which needs the exec bit
|
|
96
|
+
// or it dies with status=203/EXEC. Restore +x on every upgraded package's bin
|
|
97
|
+
// targets so a re-extracted runtime still starts.
|
|
98
|
+
const restored: string[] = [];
|
|
99
|
+
for (const pkg of verify.packages) restored.push(...io.restoreExecBits(verify.prefix, pkg));
|
|
100
|
+
if (restored.length > 0) {
|
|
101
|
+
lines.push(`Restored exec bit on ${restored.length} runtime bin entr${restored.length === 1 ? "y" : "ies"}.`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function formatMismatches(mismatches: VersionMismatch[]): string {
|
|
106
|
+
return mismatches.map((m) => `${m.pkg} (expected ${m.expected}, got ${m.actual ?? "not installed"})`).join(", ");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Strip the version spec from a package install arg (`name@1.2.3` → `name`). */
|
|
110
|
+
export function packageName(spec: string): string {
|
|
111
|
+
const at = spec.lastIndexOf("@");
|
|
112
|
+
return at > 0 ? spec.slice(0, at) : spec;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export const defaultInstallIo: InstallIo = {
|
|
116
|
+
readInstalledVersion(prefix, pkg) {
|
|
117
|
+
const manifest = join(prefix, "node_modules", pkg, "package.json");
|
|
118
|
+
if (!existsSync(manifest)) return undefined;
|
|
119
|
+
try {
|
|
120
|
+
return (JSON.parse(readFileSync(manifest, "utf8")) as { version?: string }).version;
|
|
121
|
+
} catch {
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
forceReextract(prefix, pkg) {
|
|
126
|
+
rmSync(join(prefix, "node_modules", pkg), { recursive: true, force: true });
|
|
127
|
+
},
|
|
128
|
+
removeHiddenLock(prefix) {
|
|
129
|
+
rmSync(join(prefix, "node_modules", ".package-lock.json"), { force: true });
|
|
130
|
+
},
|
|
131
|
+
restoreExecBits(prefix, pkg) {
|
|
132
|
+
const pkgDir = join(prefix, "node_modules", pkg);
|
|
133
|
+
const manifest = join(pkgDir, "package.json");
|
|
134
|
+
if (!existsSync(manifest)) return [];
|
|
135
|
+
let bin: unknown;
|
|
136
|
+
try {
|
|
137
|
+
bin = (JSON.parse(readFileSync(manifest, "utf8")) as { bin?: unknown }).bin;
|
|
138
|
+
} catch {
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
const targets = typeof bin === "string"
|
|
142
|
+
? [bin]
|
|
143
|
+
: bin && typeof bin === "object"
|
|
144
|
+
? Object.values(bin as Record<string, unknown>).filter((v): v is string => typeof v === "string")
|
|
145
|
+
: [];
|
|
146
|
+
const restored: string[] = [];
|
|
147
|
+
for (const rel of targets) {
|
|
148
|
+
const file = join(pkgDir, rel);
|
|
149
|
+
if (!existsSync(file)) continue;
|
|
150
|
+
try {
|
|
151
|
+
chmodSync(file, 0o755);
|
|
152
|
+
restored.push(file);
|
|
153
|
+
} catch {
|
|
154
|
+
// Best-effort: a chmod failure is surfaced later by the service refusing
|
|
155
|
+
// to start; don't abort the whole upgrade on a single unreadable bin.
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return restored;
|
|
159
|
+
},
|
|
160
|
+
};
|
package/src/upgrade.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { VERSION, cliRelayUrl, relayAuthHeaders } from "./config";
|
|
|
5
5
|
import type { RuntimeContracts, RuntimePackageMetadata } from "./contracts";
|
|
6
6
|
import { defaultRuntimePrefix, runtimeBinPath } from "./runtime-prefix";
|
|
7
7
|
import { resolveLocalOrchestratorId } from "./upgrade-local-id";
|
|
8
|
+
import { defaultInstallIo, packageName, verifyAndRepairInstall, type InstallIo, type VerifyInstall } from "./upgrade-install-verify";
|
|
8
9
|
import { errMessage, runInstallWithRetry } from "agent-relay-sdk";
|
|
9
10
|
import { shellEscape as shellQuote } from "agent-relay-sdk/shell-utils";
|
|
10
11
|
|
|
@@ -72,6 +73,12 @@ type UpgradeAction = {
|
|
|
72
73
|
reason: string;
|
|
73
74
|
mutates: boolean;
|
|
74
75
|
retryInstall?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Post-install verification metadata for a runtime-prefix install (#631).
|
|
78
|
+
* When set, the executor asserts each package's ACTUAL on-disk version equals
|
|
79
|
+
* the target, repairs lock-vs-disk divergence, and restores bin exec bits.
|
|
80
|
+
*/
|
|
81
|
+
verifyInstall?: VerifyInstall;
|
|
75
82
|
};
|
|
76
83
|
|
|
77
84
|
type UpgradePlan = {
|
|
@@ -183,6 +190,12 @@ export function createUpgradePlan(snapshot: UpgradeSnapshot, options: UpgradeOpt
|
|
|
183
190
|
reason: `Update server${runnerRequested ? ", provider runner" : ""}${orchestratorRequested ? ", and orchestrator" : ""} packages to ${targetVersion}.`,
|
|
184
191
|
mutates: true,
|
|
185
192
|
retryInstall: true,
|
|
193
|
+
// Only the isolated runtime prefix has a deterministic node_modules path we
|
|
194
|
+
// can read actual versions from (and it's the systemd-managed deploy that
|
|
195
|
+
// strands hosts on a silent no-op). Global bun/npm installs are left as-is.
|
|
196
|
+
verifyInstall: snapshot.packageManager === "runtime-npm"
|
|
197
|
+
? { prefix: snapshot.runtimePrefix, targetVersion, packages: packages.map(packageName) }
|
|
198
|
+
: undefined,
|
|
186
199
|
});
|
|
187
200
|
if (snapshot.packageManager === "runtime-npm") {
|
|
188
201
|
actions.push({
|
|
@@ -268,6 +281,8 @@ export function createUpgradePlan(snapshot: UpgradeSnapshot, options: UpgradeOpt
|
|
|
268
281
|
type ExecuteUpgradeOptions = {
|
|
269
282
|
dryRun?: boolean;
|
|
270
283
|
runner?: Runner;
|
|
284
|
+
/** Filesystem ops for post-install verification (injectable for tests). */
|
|
285
|
+
installIo?: InstallIo;
|
|
271
286
|
/** Re-register grace window for post-restart version checks (default 30s). */
|
|
272
287
|
verifyTimeoutMs?: number;
|
|
273
288
|
/** Poll interval while waiting for re-register (default 1s). */
|
|
@@ -283,6 +298,7 @@ type ExecuteUpgradeOptions = {
|
|
|
283
298
|
export async function executeUpgradePlan(plan: UpgradePlan, options: ExecuteUpgradeOptions = {}): Promise<string> {
|
|
284
299
|
if (options.dryRun) return formatUpgradePlan(plan, { dryRun: true });
|
|
285
300
|
const runner = options.runner ?? runCommand;
|
|
301
|
+
const io = options.installIo ?? defaultInstallIo;
|
|
286
302
|
const sleep = options.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));
|
|
287
303
|
const probeServerVersion = options.probeServerVersion ?? runningServerVersion;
|
|
288
304
|
const probeOrchestrators = options.probeOrchestrators ?? runningOrchestrators;
|
|
@@ -301,23 +317,36 @@ export async function executeUpgradePlan(plan: UpgradePlan, options: ExecuteUpgr
|
|
|
301
317
|
return value;
|
|
302
318
|
};
|
|
303
319
|
const lines = [`Upgrading Agent Relay to ${plan.targetVersion}`];
|
|
320
|
+
const runInstall = (command: string[]) => runInstallWithRetry(command, runner, {
|
|
321
|
+
sleep,
|
|
322
|
+
retries: options.installRetries,
|
|
323
|
+
baseDelayMs: options.installRetryBaseMs,
|
|
324
|
+
onRetry: ({ attempt, delayMs }) => {
|
|
325
|
+
lines.push(`npm cache race detected; retrying install attempt ${attempt} in ${delayMs}ms.`);
|
|
326
|
+
},
|
|
327
|
+
});
|
|
304
328
|
for (const action of plan.actions) {
|
|
305
329
|
lines.push(`\n${action.label}`);
|
|
306
330
|
lines.push(`$ ${action.command.map(shellQuote).join(" ")}`);
|
|
307
|
-
const result = action.retryInstall
|
|
308
|
-
? await runInstallWithRetry(action.command, runner, {
|
|
309
|
-
sleep,
|
|
310
|
-
retries: options.installRetries,
|
|
311
|
-
baseDelayMs: options.installRetryBaseMs,
|
|
312
|
-
onRetry: ({ attempt, delayMs }) => {
|
|
313
|
-
lines.push(`npm cache race detected; retrying install attempt ${attempt} in ${delayMs}ms.`);
|
|
314
|
-
},
|
|
315
|
-
})
|
|
316
|
-
: runner(action.command);
|
|
331
|
+
const result = action.retryInstall ? await runInstall(action.command) : runner(action.command);
|
|
317
332
|
if (result.stdout.trim()) lines.push(result.stdout.trim());
|
|
318
333
|
if (result.stderr.trim()) lines.push(result.stderr.trim());
|
|
319
334
|
if (result.exitCode !== 0) {
|
|
320
|
-
|
|
335
|
+
// Surface the child command's own output in the thrown error, not just the
|
|
336
|
+
// exit code (#631). The CLI reports only the error message on failure, so a
|
|
337
|
+
// bare "failed with exit code 1" hides the npm resolver failure and forces
|
|
338
|
+
// guess-and-check. The orchestrator self-upgrade path (self-upgrade.ts)
|
|
339
|
+
// already attaches the captured output — mirror it here so the local path
|
|
340
|
+
// is just as diagnosable.
|
|
341
|
+
const detail = (result.stderr.trim() || result.stdout.trim()).slice(-2000);
|
|
342
|
+
throw new Error(`${action.label} failed with exit code ${result.exitCode}${detail ? `:\n${detail}` : ""}`);
|
|
343
|
+
}
|
|
344
|
+
// A clean exit code is NOT proof the upgrade landed: npm reports "up to date"
|
|
345
|
+
// (exit 0, nothing installed) when its hidden lock claims the target while the
|
|
346
|
+
// extracted dirs are stale. Assert actual on-disk versions, repair divergence,
|
|
347
|
+
// and restore exec bits dropped by re-extraction (#631).
|
|
348
|
+
if (action.verifyInstall) {
|
|
349
|
+
await verifyAndRepairInstall(action, action.verifyInstall, runInstall, io, lines);
|
|
321
350
|
}
|
|
322
351
|
}
|
|
323
352
|
if (plan.actions.some((action) => action.command.join(" ") === "systemctl --user restart agent-relay.service")) {
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{r as e}from"./chunk-CilyBKbf.js";import{$t as t,Bn as n,Ct as r,En as i,Ft as a,Gt as o,Hn as s,Kt as c,L as l,Mn as u,Nn as d,P as f,R as p,St as m,Wn as h,a as g,at as _,c as v,ct as y,dn as b,h as x,hn as S,i as C,ln as w,mn as T,nn as ee,p as E,pn as D,r as O,rn as te,tr as k,un as A,v as j,xn as M,y as N}from"./lucide-react-D78N6SwK.js";import{g as P,r as ne,t as F}from"./store-CqFZmc-B.js";import{E as I,H as L,N as R,P as re,R as ie,S as z,V as ae,Z as B,_ as oe,d as se,f as ce,k as V,lt as H,q as U,v as le}from"./display-CWMHll1J.js";import{C as W,a as ue,i as de,o as fe,t as G}from"./index-BfQFX8td.js";var K=e(k(),1),pe={online:`came online`,offline:`went offline`,shutdown:`shut down`,restarted:`restarted`,"compaction-requested":`compaction requested`,compacting:`compaction started`,compacted:`context compacted`,"compaction-stalled":`compaction stalled — may need manual intervention`,"clear-requested":`clear requested`,"clearing-context":`clear started`,"context-cleared":`context cleared`,"clear-stalled":`context clear stalled — may need manual intervention`,"shutting-down":`shutting down`},me=new Set(Object.keys(pe)),he=3e3;function q(e){return new Date(e.occurredAt??e.createdAt).getTime()}function ge(e){if(e.kind!==`session`)return null;let t=e.payload?.session;return!t||t.type!==`narration`&&t.type!==`reasoning`&&t.type!==`tool`?null:{id:e.id,kind:t.type,label:typeof t.label==`string`?t.label:void 0,text:e.body,ts:q(e),turnId:typeof t.turnId==`string`?t.turnId:void 0}}function _e(e){if(e.kind!==`session`)return null;let t=e.payload?.session;if(t?.type!==`notice`)return null;let n=typeof t.label==`string`&&t.label?t.label:`compacted`;return{id:`notice-${e.id}`,status:n,timestamp:q(e)}}function ve(e){if(e.kind!==`session`)return null;let t=e.payload?.session;if(t?.type!==`relay-injection`)return null;let n=t.relayInjection&&typeof t.relayInjection==`object`&&!Array.isArray(t.relayInjection)?t.relayInjection:{},r=typeof n.category==`string`&&[`memory`,`instructions`,`tools`,`comms`,`knowledge`,`context`].includes(n.category)?n.category:`context`,i=typeof n.timestamp==`number`&&Number.isFinite(n.timestamp)?n.timestamp:q(e),a=n.detail&&typeof n.detail==`object`&&!Array.isArray(n.detail)?n.detail:{};return{id:e.id,category:r,summary:typeof n.summary==`string`&&n.summary.trim()?n.summary:e.body,detail:a,agentId:typeof n.agentId==`string`&&n.agentId?n.agentId:e.from,timestamp:i}}function ye(e,t){let n=e.trim();for(let e of t){let t=e.trim();if(t){if(n===t)break;n.startsWith(`${t}\n\n`)&&(n=n.slice(t.length+2).trimStart())}}return n.trim()||e.trim()}function be(e){return e.kind===`system`&&e.from===`system`}var xe=new Set([`agent.ready`,`agent.exited`,`agent.spawn_failed`]);function J(e){let t=new Date(e);return`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,`0`)}-${String(t.getDate()).padStart(2,`0`)}`}function Se(e){let t=e.filter(e=>me.has(e.status)).slice().sort((e,t)=>e.timestamp-t.timestamp),n=[];for(let e of t)n.some(t=>t.id===e.id)||n.some(t=>t.status===e.status&&Math.abs(t.timestamp-e.timestamp)<=he)||n.push(e);return n}function Ce(e,t,n,r=[],i){let a=[];for(let e of r){let t=e.entries.reduce((e,t)=>Math.min(e,U(t.originalCreatedAt)),1/0),n=Number.isFinite(t)?t-1:e.importedAt;a.push({ts:n,entry:{type:`import-boundary`,history:e,timestamp:n}});for(let t of e.entries)a.push({ts:U(t.originalCreatedAt),entry:{type:`imported-message`,history:e,entry:t}})}if(n){let e=new Date(n).getTime();Number.isFinite(e)&&a.push({ts:e,entry:{type:`created`,timestamp:e}})}if(i?.spawnedBy){let e=n?new Date(n).getTime():0,t=Number.isFinite(e)?e:0;a.push({ts:t,entry:{type:`agent-action`,direction:`spawned-by`,agentId:i.spawnedBy.agentId,provider:i.spawnedBy.provider,status:`ready`,timestamp:t}})}let o=i?.spawnedBy?.agentId,s=null,c=1/0;for(let t of e){if(t.kind===`session`||be(t)||I(t)||!(t.from===`user`||o!==void 0&&t.from===o)||!V(t).trim())continue;let e=q(t);e<c&&(c=e,s=t.id)}let l=new Map,u=new Map,d=new Map;for(let t of e){if(t.kind!==`session`)continue;let e=t.payload?.session;if(e?.type===`narration`&&typeof e.turnId==`string`){let n=u.get(e.turnId)??[];n.push({id:t.id,body:t.body.trim()}),u.set(e.turnId,n)}else if(e?.type===`response`&&typeof e.turnId==`string`){let n=l.get(e.turnId)??[];n.push(t.body.trim()),l.set(e.turnId,n)}}let f=new Map;for(let[e,t]of l){let n=(u.get(e)??[]).map(e=>e.body);f.set(e,t.map(e=>ye(e,n)))}for(let t of e){if(t.kind!==`session`)continue;let e=t.payload?.session;if(e?.type!==`response`||typeof e.turnId!=`string`)continue;let n=ye(t.body,(u.get(e.turnId)??[]).map(e=>e.body));n&&n!==t.body&&d.set(t.id,n)}let p=new Set;for(let[e,t]of f){let n=u.get(e)??[];for(let e of t)for(let t=n.length-1;t>=0;t--){let r=n[t];if(!p.has(r.id)&&L(e,r.body)){p.add(r.id);break}}}let m=new Map,h=[];for(let t of e){if(be(t)){let e=typeof t.payload?.kind==`string`?t.payload.kind:``;if(xe.has(e)){let n=t.payload,r=typeof n.agentId==`string`?n.agentId:``,i=q(t);if(!r){a.push({ts:i,entry:{type:`notice`,msg:t}});continue}let o=e===`agent.ready`?`ready`:e===`agent.exited`?`exited`:`failed`,s=m.get(r);if(s)s.entry.status=o,typeof n.reason==`string`&&(s.entry.reason=n.reason),s.entry.timestamp=i,s.ts=i;else{let e={ts:i,entry:{type:`agent-action`,direction:`spawned-child`,agentId:r,provider:typeof n.provider==`string`?n.provider:void 0,status:o,reason:typeof n.reason==`string`?n.reason:void 0,timestamp:i}};m.set(r,e),a.push(e)}continue}a.push({ts:q(t),entry:{type:`notice`,msg:t}});continue}let e=_e(t);if(e){h.push(e);continue}let n=ge(t);if(n){if(n.kind===`narration`&&p.has(n.id))continue;a.push({ts:n.ts,entry:{type:`activity`,steps:[n],timestamp:n.ts}});continue}let r=ve(t);if(r){a.push({ts:r.timestamp,entry:{type:`relay-injection`,event:r}});continue}if(t.kind===`session`){let e=t.payload?.session;if(e?.type===`response`&&typeof e.turnId==`string`){let e=d.get(t.id);if(e&&e!==t.body){a.push({ts:q(t),entry:{type:`message`,msg:{...t,body:e}}});continue}}}let i=t.id===s?`initial-prompt`:`message`;a.push({ts:q(t),entry:{type:i,msg:t}})}for(let e of Se([...t,...h]))a.push({ts:e.timestamp,entry:{type:`status`,event:e}});let g={created:0,date:1,"import-boundary":2,"imported-message":3,"initial-prompt":4,message:4,activity:4,notice:4,"agent-action":4,"relay-injection":4,status:5};a.sort((e,t)=>{let n=e.ts-t.ts;return Math.abs(n)<3e3&&g[e.entry.type]-g[t.entry.type]||n});let _=[],v=``;for(let{ts:e,entry:t}of a){if(t.type===`created`){_.push(t);continue}let n=J(e);if(n!==v&&(_.push({type:`date`,date:n,timestamp:e}),v=n),t.type===`activity`){let e=_[_.length-1];if(e&&e.type===`activity`&&Ee(e,t)){e.steps.push(...t.steps);continue}}_.push(t)}return _}function we(e){return e.type===`message`?`msg-${e.msg.id}`:e.type===`initial-prompt`?`initprompt-${e.msg.id}`:e.type===`notice`?`notice-${e.msg.id}`:e.type===`relay-injection`?`relay-injection-${e.event.id}`:e.type===`agent-action`?`agent-action-${e.direction}-${e.agentId}`:e.type===`activity`?`act-${e.steps[0]?.id??e.timestamp}`:e.type===`import-boundary`?`import-${e.history.id}`:e.type===`imported-message`?`import-msg-${e.history.id}-${e.entry.originalMessageId}-${e.entry.position}`:e.type===`status`?`status-${e.event.id}`:e.type===`date`?`date-${e.date}`:`created-${e.timestamp}`}function Te(e){return e.type===`message`||e.type===`initial-prompt`||e.type===`notice`?(e.msg.subject?`${e.msg.subject} `:``)+V(e.msg):e.type===`imported-message`?V(e.entry.message):e.type===`activity`?e.steps.map(e=>[e.label,e.text].filter(Boolean).join(` `)).join(`
|
|
2
|
-
`):e.type===`relay-injection`?`${e.event.category} ${e.event.summary}\n${JSON.stringify(e.event.detail)}`:``}function Ee(e,t){let n=e.steps[e.steps.length-1]?.turnId,r=t.steps[0]?.turnId;return n&&r?n===r:!n&&!r}function De(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(1)} MB`}function Oe(e,t){if(t.startsWith(`/`))return t;let n=`${e.replace(/\/+$/,``)}/${t}`.split(`/`),r=[];for(let e of n)!e||e===`.`||(e===`..`?r.pop():r.push(e));return`/`+r.join(`/`)}function ke(e){let t=e.replace(/\/+$/,``),n=t.lastIndexOf(`/`);return n>0?t.slice(0,n):`/`}function Ae(e,t){return e.filter(e=>e.status===`online`&&ie(t,e.baseDir)).sort((e,t)=>R(t.baseDir).length-R(e.baseDir).length)[0]||e.find(e=>e.status===`online`)}function je(){return typeof window<`u`&&window.matchMedia(`(min-width: 1280px)`).matches}function Me(){return typeof window<`u`&&!!window.getSelection()?.toString()}function Ne(e){let t=e.payload?.attachments;return Array.isArray(t)?t.filter(e=>!!(e&&typeof e==`object`&&typeof e.artifactId==`string`)):[]}var Pe=[`👍`,`❤️`,`✅`,`👀`];function Fe(e){let t=new Map;for(let n of e.reactions||[]){let e=re(n.emoji),r=t.get(e)??{emoji:e,count:0,mine:!1,actors:[]};r.count+=1,r.mine=r.mine||n.actorId===`user`,r.actors.push(n.actorId),t.set(e,r)}return[...t.values()].sort((e,t)=>t.count-e.count||e.emoji.localeCompare(t.emoji))}function Y(e){return I(e)}function Ie(e,n){let r=e.readBy||[],i=e.resolvedToAgent||n||e.to,a=i?r.includes(i):!1,o=r.some(e=>e!==H);if(a||o){let e=a?i:r.find(e=>e!==H);return{label:`read`,title:e?`Read by ${e}`:`Read by agent`,tone:`ok`,icon:S}}if(e.deliveryStatus===`delivered`)return{label:`delivered`,title:`Delivered to agent inbox`,tone:`ok`,icon:S};if(e.deliveryStatus===`queued`)return{label:`queued`,title:`Queued until the target agent is available`,tone:`warn`,icon:t};if(e.deliveryStatus===`failed`||e.deliveryStatus===`dead`){let t=e.deliveryPoisonReason||e.deliveryLastError||e.deliveryStatus;return{label:e.deliveryStatus,title:t,tone:`danger`,icon:w}}return{label:`sent`,title:`Accepted by Relay`,tone:`muted`,icon:T}}function Le(e){let t=U(e.createdAt);return(e.reactions||[]).reduce((e,t)=>Math.max(e,U(t.updatedAt||t.createdAt)),t)}function Re(e){return e?e.messages.reduce((e,t)=>Math.max(e,Le(t)),0):0}function ze(e,t,n){return(e-t)*n}function Be(e){if(!e)return 0;let t=0;for(let n of e.messages)z(n)&&(t=Math.max(t,U(n.createdAt)));return t}function X(e){return new Date(e).toLocaleTimeString([],{hour:`2-digit`,minute:`2-digit`})}function Ve(e){for(let t of e)t.previewUrl&&URL.revokeObjectURL(t.previewUrl)}function He(e,t,n,r){if(e?.teamId)return{teamId:e.teamId};let i=[...t];n&&!i.some(e=>e.id===n.id)&&i.push(n);let a=i.filter(e=>e.threadId).reverse(),o=a.find(e=>!!r[ne(e.threadId,e.channel)])??a[0];return o?.threadId?{threadId:o.threadId,...o.channel?{channel:o.channel}:{}}:null}var Z=s(),Ue={online:`text-emerald-400`,offline:`text-zinc-400`,shutdown:`text-zinc-400`,restarted:`text-blue-400`,"compaction-requested":`text-zinc-400`,compacting:`text-amber-400`,compacted:`text-amber-400`,"compaction-stalled":`text-red-400`,"clear-requested":`text-zinc-400`,"clearing-context":`text-amber-400`,"context-cleared":`text-amber-400`,"clear-stalled":`text-red-400`,"shutting-down":`text-zinc-400`};function We(e){let t=new Date,[n,r,i]=e.split(`-`).map(Number),a=new Date(n,r-1,i);if(e===J(t.getTime()))return`Today`;let o=new Date(t);return o.setDate(o.getDate()-1),e===J(o.getTime())?`Yesterday`:a.toLocaleDateString(void 0,{weekday:`short`,month:`short`,day:`numeric`,year:a.getFullYear()===t.getFullYear()?void 0:`numeric`})}function Ge({event:e}){return(0,Z.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,Z.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,Z.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs text-muted-foreground`,children:[(0,Z.jsx)(ee,{className:n(`w-2 h-2 fill-current`,Ue[e.status]||`text-zinc-400`)}),(0,Z.jsx)(`span`,{children:pe[e.status]||e.status}),(0,Z.jsx)(`span`,{className:`text-muted-foreground/60`,children:X(e.timestamp)})]}),(0,Z.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}var Ke={"branch.landed":m,"context.warning":E,"agent.context_threshold":E,"agent.resume_budget_exhausted":E,"agent.rate_limit_resume":p},qe={"branch.landed":`branch landed`,"context.warning":`context warning`,"agent.context_threshold":`context threshold reached`};function Je(e){return e&&(e.includes(`.`)?e.slice(e.indexOf(`.`)+1):e).replace(/[._-]+/g,` `).trim()||`system signal`}function Q({agentId:e,fallbackLabel:t,className:r,noIcon:i}){let a=F(t=>t.agentsById[e])||null,o=F(e=>e.openInboxThread),s=F(e=>e.switchView),c=a?se(a):t||e;return(0,Z.jsxs)(`button`,{type:`button`,className:n(`inline-flex max-w-full items-center gap-1 rounded px-1 text-muted-foreground transition-colors hover:bg-muted/50 hover:text-foreground`,r),onClick:t=>{t.stopPropagation(),o(e),s(`chat`)},title:`Open chat for ${c}`,children:[!i&&(0,Z.jsx)(W,{agent:a,className:`w-4 h-4 text-[10px]`}),(0,Z.jsx)(`span`,{className:`max-w-[160px] truncate`,children:c})]})}function Ye({msg:e}){let t=e.payload??{},n=typeof t.sha==`string`?t.sha:``,r=n?n.slice(0,7):``,i=typeof t.author==`string`?t.author:``,a=typeof t.branch==`string`?t.branch:``,o=typeof t.base==`string`?t.base:``,s=t.pushed;return(0,Z.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,Z.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,Z.jsxs)(`div`,{className:`flex max-w-full flex-wrap items-center justify-center gap-x-1.5 gap-y-0.5 rounded-full border border-emerald-600/35 bg-emerald-500/10 px-2.5 py-1 text-xs text-emerald-700 dark:border-emerald-500/25 dark:text-emerald-300/90`,children:[(0,Z.jsx)(m,{className:`h-3 w-3 shrink-0 text-emerald-600 dark:text-emerald-400`}),(0,Z.jsx)(`span`,{className:`text-emerald-700 dark:text-emerald-300`,children:`branch landed`}),a&&o&&(0,Z.jsxs)(`span`,{className:`font-mono text-emerald-700/80 dark:text-emerald-200/70`,title:`${a} → ${o}`,children:[a,(0,Z.jsx)(`span`,{className:`opacity-50`,children:` → `}),o]}),r&&(0,Z.jsx)(`span`,{className:`rounded bg-emerald-500/15 px-1 font-mono text-emerald-800 dark:text-emerald-200`,title:n,children:r}),i&&(0,Z.jsxs)(`span`,{className:`inline-flex items-center gap-1 text-emerald-700/80 dark:text-emerald-300/80`,children:[(0,Z.jsx)(`span`,{className:`opacity-70`,children:`by`}),(0,Z.jsx)(Q,{agentId:i,className:`text-emerald-700 hover:text-emerald-900 dark:text-emerald-300/90 dark:hover:text-emerald-100`})]}),s===!1&&(0,Z.jsx)(`span`,{className:`text-amber-600 dark:text-amber-300/80`,title:`Local-only land — not pushed to origin`,children:`· local only`}),(0,Z.jsx)(`span`,{className:`text-emerald-700/60 dark:text-emerald-300/50`,children:X(e.occurredAt??e.createdAt)})]}),(0,Z.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}function Xe({msg:e}){let t=typeof e.payload?.kind==`string`?e.payload.kind:``;if(t===`branch.landed`)return(0,Z.jsx)(Ye,{msg:e});let n=Ke[t]??f,r=qe[t]??Je(t);return(0,Z.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,Z.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,Z.jsxs)(`div`,{className:`flex items-center gap-1.5 rounded-full border border-border bg-muted/30 px-2.5 py-1 text-xs text-muted-foreground`,children:[(0,Z.jsx)(n,{className:`h-3 w-3`}),(0,Z.jsx)(`span`,{children:r}),(0,Z.jsx)(`span`,{className:`text-muted-foreground/60`,children:X(e.occurredAt??e.createdAt)})]}),(0,Z.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}var Ze={"spawned-child":{ready:`spawned`,exited:`spawned · exited`,failed:`spawn failed`},"spawned-by":{ready:`spawned by`,exited:`spawned by`,failed:`spawned by`}},Qe={"spawned-child-ready":l,"spawned-child-exited":_,"spawned-child-failed":w,"spawned-by-ready":d,"spawned-by-exited":d,"spawned-by-failed":d},$e={"spawned-child-ready":`text-emerald-400`,"spawned-child-exited":`text-zinc-400`,"spawned-child-failed":`text-red-400`,"spawned-by-ready":`text-blue-400`,"spawned-by-exited":`text-blue-400`,"spawned-by-failed":`text-blue-400`};function et({entry:e}){let t=`${e.direction}-${e.status}`,r=Ze[e.direction]?.[e.status]??e.direction,i=Qe[t]??f,a=$e[t]??`text-muted-foreground`,o=e.status===`failed`;return(0,Z.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,Z.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,Z.jsxs)(`div`,{className:n(`flex items-center gap-1.5 rounded-full border bg-muted/30 px-2.5 py-1 text-xs`,o?`border-red-500/30`:`border-border`),children:[(0,Z.jsx)(i,{className:n(`h-3 w-3 shrink-0`,a)}),(0,Z.jsx)(`span`,{className:`text-muted-foreground`,children:r}),(0,Z.jsx)(Q,{agentId:e.agentId}),e.reason&&o&&(0,Z.jsxs)(`span`,{className:`text-red-400/80 max-w-[120px] truncate`,title:e.reason,children:[`— `,e.reason]}),(0,Z.jsx)(`span`,{className:`text-muted-foreground/60 shrink-0`,children:X(e.timestamp)})]}),(0,Z.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}var tt={memory:M,instructions:a,tools:g,comms:f,knowledge:i,context:c},nt={memory:`border-emerald-500/25 bg-emerald-500/10 text-emerald-300`,instructions:`border-sky-500/25 bg-sky-500/10 text-sky-300`,tools:`border-amber-500/25 bg-amber-500/10 text-amber-300`,comms:`border-violet-500/25 bg-violet-500/10 text-violet-300`,knowledge:`border-cyan-500/25 bg-cyan-500/10 text-cyan-300`,context:`border-zinc-500/25 bg-zinc-500/10 text-zinc-300`};function rt(e){try{return JSON.stringify(e,null,2)}catch{return String(e)}}function it({entry:e}){let[t,r]=(0,K.useState)(!1),i=e.event,a=tt[i.category]??j;return(0,Z.jsx)(`div`,{className:`flex justify-center py-2 my-1`,children:(0,Z.jsxs)(`div`,{className:n(`w-full max-w-[85%] md:max-w-[75%] rounded-lg border px-2.5 py-1.5 text-xs shadow-sm`,nt[i.category]??nt.context),children:[(0,Z.jsxs)(`button`,{type:`button`,className:`flex w-full min-w-0 items-center gap-1.5 text-left`,onClick:()=>r(e=>!e),children:[(0,Z.jsx)(a,{className:`h-3.5 w-3.5 shrink-0`}),(0,Z.jsx)(`span`,{className:`shrink-0 font-medium`,children:i.category}),(0,Z.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-foreground/80`,children:i.summary}),(0,Z.jsx)(`span`,{className:`shrink-0 text-muted-foreground/60`,children:X(i.timestamp)}),(0,Z.jsx)(b,{className:n(`h-3.5 w-3.5 shrink-0 transition-transform`,t&&`rotate-90`)})]}),t&&(0,Z.jsx)(`pre`,{className:`mt-2 max-h-72 overflow-auto rounded-md border border-border/60 bg-background/75 p-2 font-mono text-[11px] leading-relaxed text-muted-foreground whitespace-pre-wrap break-words`,children:rt(i.detail)})]})})}function at({blockedLabel:e,onInterrupt:t}){return e?(0,Z.jsx)(`div`,{className:`flex justify-start mb-3 animate-in fade-in slide-in-from-bottom-1 duration-150`,children:(0,Z.jsxs)(`div`,{className:`flex h-9 items-center gap-2 rounded-2xl rounded-bl-sm bg-card ring-1 ring-red-500/30 px-4`,children:[(0,Z.jsx)(w,{className:`w-3.5 h-3.5 text-red-400`}),(0,Z.jsxs)(`span`,{className:`text-xs text-red-300`,children:[`blocked: `,e]})]})}):(0,Z.jsx)(`div`,{className:`flex justify-start mb-3 animate-in fade-in slide-in-from-bottom-1 duration-150`,children:(0,Z.jsxs)(`div`,{className:`flex h-9 items-center gap-2 rounded-2xl rounded-bl-sm bg-card ring-1 ring-foreground/10 px-4`,children:[(0,Z.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,Z.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full bg-yellow-400 animate-[pulse_1.4s_ease-in-out_infinite]`}),(0,Z.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full bg-yellow-400 animate-[pulse_1.4s_ease-in-out_0.2s_infinite]`}),(0,Z.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full bg-yellow-400 animate-[pulse_1.4s_ease-in-out_0.4s_infinite]`})]}),(0,Z.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`working`}),t&&(0,Z.jsxs)(`button`,{onClick:t,title:`Interrupt`,className:`ml-1 flex items-center gap-1 rounded-full px-1.5 py-0.5 text-xs text-muted-foreground hover:text-red-300 hover:bg-red-500/10 transition-colors`,children:[(0,Z.jsx)(te,{className:`w-3.5 h-3.5`}),`Stop`]})]})})}var $=`agent-relay:chat-hide-tools`,ot=(()=>{let e=new Set,t=(()=>{try{return window.localStorage.getItem($)===`on`}catch{return!1}})(),n=()=>e.forEach(e=>e());return typeof window<`u`&&window.addEventListener(`storage`,e=>{e.key===$&&(t=e.newValue===`on`,n())}),{subscribe(t){return e.add(t),()=>e.delete(t)},get:()=>t,toggle(){t=!t;try{window.localStorage.setItem($,t?`on`:`off`)}catch{}n()}}})();function st(){return[(0,K.useSyncExternalStore)(ot.subscribe,ot.get,()=>!1),ot.toggle]}function ct({steps:e,showReasoning:t,issueRepo:r}){let[i,a]=st(),o=t?e:e.filter(e=>e.kind!==`reasoning`);if(!o.length)return null;let s=o.filter(e=>e.kind===`tool`).length;return(0,Z.jsx)(`div`,{className:`flex justify-start mb-2`,children:(0,Z.jsxs)(`div`,{className:`max-w-[85%] md:max-w-[75%] min-w-0 space-y-1.5`,children:[o.map(e=>e.kind===`narration`?(0,Z.jsx)(G,{text:e.text,issueRepo:r,className:`text-sm leading-relaxed break-words text-foreground/90 min-w-0`},e.id):e.kind===`reasoning`?(0,Z.jsxs)(`div`,{className:`flex items-start gap-1.5 text-xs leading-relaxed text-muted-foreground/80`,children:[(0,Z.jsx)(M,{className:`w-3.5 h-3.5 mt-0.5 shrink-0 opacity-70`}),(0,Z.jsx)(G,{text:e.text,issueRepo:r,className:`italic break-words min-w-0`})]},e.id):i?null:(0,Z.jsxs)(`div`,{className:`flex items-start gap-1.5 text-xs leading-relaxed text-muted-foreground`,children:[(0,Z.jsx)(x,{className:`w-3 h-3 mt-0.5 shrink-0 opacity-70`}),(0,Z.jsxs)(`span`,{className:`min-w-0 break-words`,children:[(0,Z.jsx)(`span`,{className:`font-medium`,children:e.label||`tool`}),e.text&&e.text.trim()&&e.text.trim()!==(e.label??``).trim()?(0,Z.jsxs)(`span`,{className:`opacity-70`,children:[` — `,e.text]}):null]})]},e.id)),s>0&&(0,Z.jsxs)(`button`,{onClick:a,className:`flex items-center gap-1 text-[11px] text-muted-foreground/50 hover:text-muted-foreground transition-colors text-left`,children:[(0,Z.jsx)(b,{className:n(`w-3 h-3 shrink-0 transition-transform`,!i&&`rotate-90`)}),(0,Z.jsx)(`span`,{children:i?`show ${s} tool step${s===1?``:`s`}`:`hide tool steps`})]})]})})}function lt({date:e}){return(0,Z.jsxs)(`div`,{className:`flex items-center justify-center gap-3 py-3 my-1`,children:[(0,Z.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,Z.jsx)(`span`,{className:`text-xs font-medium text-muted-foreground`,children:We(e)}),(0,Z.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}function ut({timestamp:e}){let t=new Date(e).toLocaleString(void 0,{month:`short`,day:`numeric`,year:`numeric`,hour:`2-digit`,minute:`2-digit`});return(0,Z.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,Z.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,Z.jsxs)(`span`,{className:`text-xs text-muted-foreground/60`,children:[`created `,t]}),(0,Z.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}function dt({history:e}){let t=e.sourceAgentLabel||e.sourcePeerId,n=e.entries.length;return(0,Z.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,Z.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,Z.jsxs)(`div`,{className:`flex items-center gap-1.5 rounded-full border border-dashed border-border bg-muted/30 px-2 py-1 text-[11px] text-muted-foreground`,children:[(0,Z.jsx)(r,{className:`h-3 w-3`}),(0,Z.jsxs)(`span`,{children:[`forked history from `,t]}),(0,Z.jsxs)(`span`,{className:`text-muted-foreground/60`,children:[n,` `,n===1?`entry`:`entries`]})]}),(0,Z.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}function ft({entry:e,sourceLabel:t,issueRepo:r}){let i=e.message,a=V(i),o=e.originalFrom===H;return(0,Z.jsx)(`div`,{className:n(`flex mb-3 opacity-80`,o?`justify-end`:`justify-start`),children:(0,Z.jsx)(`div`,{className:`max-w-[85%] md:max-w-[75%]`,children:(0,Z.jsxs)(`div`,{className:n(`rounded-2xl border border-dashed px-3.5 py-2 text-sm select-text`,o?`border-primary/25 bg-primary/10 text-foreground rounded-br-sm`:`border-border bg-card/70 rounded-bl-sm`),children:[(0,Z.jsxs)(`div`,{className:n(`mb-1 text-[10px] uppercase tracking-normal`,o?`text-primary/70`:`text-muted-foreground`),children:[`forked history · `,o?`you`:t||e.originalFrom]}),(0,Z.jsx)(G,{text:a,rawBody:i.body,issueRepo:r,className:`leading-relaxed`}),(0,Z.jsxs)(`p`,{className:n(`mt-1 flex items-center justify-end gap-1.5 text-xs`,o?`text-primary/60`:`text-muted-foreground`),children:[(0,Z.jsxs)(`span`,{className:`opacity-40`,children:[`#`,e.originalMessageId]}),(0,Z.jsx)(`span`,{children:X(e.originalCreatedAt)})]})]})})})}function pt({msg:e,issueRepo:t}){let n=V(e),r=X(e.occurredAt??e.createdAt);return(0,Z.jsx)(`div`,{"data-msg-id":e.id,className:`mb-3`,children:(0,Z.jsxs)(`div`,{className:`rounded-xl border border-primary/30 bg-primary/[0.06] px-3.5 py-2.5 shadow-sm`,children:[(0,Z.jsxs)(`div`,{className:`mb-1.5 flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide text-primary/80`,children:[(0,Z.jsx)(j,{className:`h-3.5 w-3.5`}),(0,Z.jsx)(`span`,{children:`Initial prompt`}),(0,Z.jsx)(`span`,{className:`ml-auto text-[10px] font-normal normal-case text-muted-foreground/60`,children:r})]}),(0,Z.jsx)(G,{text:n,rawBody:e.body,issueRepo:t,className:`text-sm leading-relaxed text-foreground`})]})})}function mt({scrollEl:e,timeline:t}){let[r,i]=(0,K.useState)(!0),[a,o]=(0,K.useState)(null),[s,c]=(0,K.useState)(null),[l,u]=(0,K.useState)(!1),d=(0,K.useMemo)(()=>{for(let e=t.length-1;e>=0;e--){let n=t[e];if(!(!n||n.type!==`message`&&n.type!==`initial-prompt`)&&n.msg.from===`user`)return{id:n.msg.id,body:V(n.msg)}}return null},[t]);if((0,K.useEffect)(()=>{if(!d||!e){i(!0);return}let t=null,n=null,r=()=>{let r=e.querySelector(`[data-msg-id="${d.id}"]`);if(!r){t?.disconnect(),t=null,n=null,i(!1);return}let a=r.getBoundingClientRect(),o=e.getBoundingClientRect();u(a.top<o.top),r!==n&&(t?.disconnect(),n=r,t=new IntersectionObserver(([e])=>{e&&i(e.isIntersecting)},{root:e,threshold:0}),t.observe(r))};return r(),e.addEventListener(`scroll`,r,{passive:!0}),()=>{t?.disconnect(),e.removeEventListener(`scroll`,r)}},[d?.id,e]),r||!d||!d.body.trim())return null;let f=a?.id===d.id?a.value:!1,p=s?.id===d.id?s.value:!1;function m(){!e||!d||e.querySelector(`[data-msg-id="${d.id}"]`)?.scrollIntoView({behavior:`smooth`,block:`center`})}let h=l?`↑`:`↓`;return p?(0,Z.jsx)(`div`,{className:`flex shrink-0 bg-card/45 border-b border-border`,children:(0,Z.jsxs)(`button`,{type:`button`,className:`w-full flex items-center justify-center gap-1.5 py-1 text-[11px] text-primary/60 hover:text-primary transition-colors`,onClick:()=>c({id:d.id,value:!1}),children:[(0,Z.jsx)(`span`,{children:`Your prompt`}),(0,Z.jsx)(D,{className:`w-3 h-3`})]})}):(0,Z.jsxs)(`section`,{className:`flex shrink-0 flex-col border-b border-border bg-card/45 px-3 py-2`,children:[(0,Z.jsxs)(`div`,{className:`flex items-center gap-2 text-[11px] text-muted-foreground mb-0.5`,children:[(0,Z.jsx)(`span`,{className:`font-medium text-primary/70`,children:`Your prompt`}),(0,Z.jsxs)(`button`,{type:`button`,className:`ml-auto hover:text-foreground transition-colors`,onClick:m,children:[h,` scroll to original`]}),(0,Z.jsx)(`button`,{type:`button`,className:`hover:text-foreground transition-colors`,onClick:()=>c({id:d.id,value:!0}),title:`Minimize`,children:(0,Z.jsx)(A,{className:`w-3 h-3`})})]}),(0,Z.jsx)(`p`,{className:n(`text-sm text-foreground leading-snug cursor-pointer`,!f&&`line-clamp-2`),onClick:()=>o({id:d.id,value:!f}),children:d.body})]})}var ht={id:H};function gt({user:e,address:t,distinct:r=!1,className:i}){let a=e?.avatarArtifactId??null,[o,s]=(0,K.useState)(null);(0,K.useEffect)(()=>{if(!a){s(null);return}let e=!1,t=null;return(async()=>{try{let n=await h(`/artifacts/${encodeURIComponent(a)}/content`);if(e)return;t=URL.createObjectURL(n),s(t)}catch{e||s(null)}})(),()=>{e=!0,t&&URL.revokeObjectURL(t)}},[a]);let c=e?.displayName||e?.handle||`User`;if(o)return(0,Z.jsx)(`img`,{src:o,alt:c,title:c,className:n(`w-7 h-7 rounded-md object-cover`,i)});if(r){let e=(c.trim()[0]||`U`).toUpperCase();return(0,Z.jsx)(`span`,{title:c,className:n(`inline-flex w-7 h-7 items-center justify-center rounded-md bg-muted text-xs font-semibold ring-1 ring-foreground/10`,oe(t),i),children:e})}return(0,Z.jsx)(W,{agent:ht,className:i})}function _t(){return(0,K.useSyncExternalStore)(e=>P.subscribe(e),()=>P.getPlayingKey(),()=>null)}function vt({msg:e,peer:t}){return(0,Z.jsx)(pt,{msg:e,issueRepo:F(e=>e.agentsById[t]?.issueRepo)})}function yt({agent:e,onClick:t}){let r=!!(t&&e);return(0,Z.jsx)(`button`,{type:`button`,title:e?e.label||e.name||e.id:void 0,onClick:t,disabled:!r,className:n(`shrink-0 self-end transition-opacity`,r?`cursor-pointer hover:opacity-80`:`cursor-default opacity-60`),children:(0,Z.jsx)(W,{agent:e})})}function bt({attachment:e,outbound:t}){let r=e.kind===`image`,i=e.title||e.artifactId,[s,c]=(0,K.useState)(null),[l,u]=(0,K.useState)(null),[d,f]=(0,K.useState)(!1),[p,m]=(0,K.useState)(!1);(0,K.useEffect)(()=>{let t=!1,n=null;async function r(){f(!0),u(null),c(null);try{let r=await h(`/artifacts/${encodeURIComponent(e.artifactId)}/content`);if(t)return;n=URL.createObjectURL(r),c(n)}catch(e){t||u(e.message)}finally{t||f(!1)}}return r(),()=>{t=!0,n&&URL.revokeObjectURL(n)}},[e.artifactId]);function g(){if(!s)return;let e=document.createElement(`a`);e.href=s,e.download=i,document.body.appendChild(e),e.click(),e.remove()}return r?(0,Z.jsxs)(Z.Fragment,{children:[(0,Z.jsx)(`button`,{type:`button`,onClick:()=>s&&m(!0),disabled:!s,className:`group/img mt-2 block overflow-hidden rounded-md border border-foreground/10 bg-black/10 text-left disabled:cursor-default relative`,children:s?(0,Z.jsxs)(Z.Fragment,{children:[(0,Z.jsx)(`img`,{src:s,alt:i,loading:`lazy`,className:`block max-h-72 max-w-full object-contain`}),(0,Z.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center bg-black/0 group-hover/img:bg-black/30 transition-colors`,children:(0,Z.jsx)(O,{className:`w-6 h-6 text-white opacity-0 group-hover/img:opacity-100 transition-opacity drop-shadow-md`})})]}):(0,Z.jsxs)(`span`,{className:n(`flex min-h-20 items-center gap-2 px-3 py-2 text-xs`,l?`text-red-400`:`text-muted-foreground`),children:[d?(0,Z.jsx)(y,{className:`h-4 w-4 animate-spin`}):(0,Z.jsx)(w,{className:`h-4 w-4`}),l||`Loading image`]})}),s&&(0,Z.jsx)(de,{open:p,onOpenChange:m,children:(0,Z.jsxs)(ue,{className:`max-w-[95vw] max-h-[95vh] w-auto p-0 bg-black/95 border-zinc-800 gap-0 overflow-hidden`,showCloseButton:!1,children:[(0,Z.jsx)(fe,{className:`sr-only`,children:i}),(0,Z.jsxs)(`div`,{className:`relative flex items-center justify-center min-h-[200px]`,children:[(0,Z.jsx)(`img`,{src:s,alt:i,className:`max-w-[93vw] max-h-[90vh] object-contain`}),(0,Z.jsxs)(`div`,{className:`absolute top-2 right-2 flex gap-1`,children:[(0,Z.jsx)(`button`,{type:`button`,onClick:g,className:`rounded-md bg-black/60 hover:bg-black/80 p-2 text-white transition-colors`,title:`Download`,children:(0,Z.jsx)(o,{className:`w-4 h-4`})}),(0,Z.jsx)(`button`,{type:`button`,onClick:()=>m(!1),className:`rounded-md bg-black/60 hover:bg-black/80 p-2 text-white transition-colors`,title:`Close`,children:(0,Z.jsx)(C,{className:`w-4 h-4`})})]})]})]})})]}):(0,Z.jsxs)(`button`,{type:`button`,onClick:g,disabled:!s,className:n(`mt-2 flex w-full items-center gap-2 rounded-md border px-2.5 py-2 text-left text-xs transition-colors disabled:cursor-default disabled:opacity-70`,t?`border-primary-foreground/20 bg-primary-foreground/10 hover:bg-primary-foreground/15`:`border-border bg-background hover:bg-muted`),children:[d?(0,Z.jsx)(y,{className:`h-4 w-4 shrink-0 animate-spin`}):l?(0,Z.jsx)(w,{className:`h-4 w-4 shrink-0 text-red-400`}):(0,Z.jsx)(a,{className:`h-4 w-4 shrink-0`}),(0,Z.jsx)(`span`,{className:n(`min-w-0 flex-1 truncate`,l&&`text-red-400`),children:l||i}),(0,Z.jsx)(o,{className:`h-3.5 w-3.5 shrink-0`})]})}function xt({open:e,onToggle:t,onReact:r}){return(0,Z.jsxs)(`div`,{className:`relative shrink-0`,children:[(0,Z.jsx)(`button`,{type:`button`,title:`Add reaction`,onClick:t,className:n(`inline-flex h-5 w-6 items-center justify-center rounded-full border border-border bg-popover text-muted-foreground shadow-sm transition hover:bg-muted hover:text-foreground`,e?`opacity-100`:`opacity-0 pointer-events-none md:group-hover/msg:opacity-100 md:group-hover/msg:pointer-events-auto`),children:(0,Z.jsx)(N,{className:`h-3 w-3`})}),e&&(0,Z.jsx)(`div`,{className:`absolute bottom-full left-0 z-30 mb-1 flex gap-0.5 rounded-full border border-border bg-popover p-0.5 shadow-md`,children:Pe.map(e=>(0,Z.jsx)(`button`,{type:`button`,title:`React ${e}`,onClick:()=>r(e),className:`inline-flex h-6 w-7 items-center justify-center rounded-full text-xs transition-colors hover:bg-muted`,children:e},e))})]})}function St({msg:e,peer:t}){let[r,i]=(0,K.useState)(!1),a=F(e=>e.agentsById),o=F(e=>e.openAgentDetail),s=e.from===t,c=(s?e.to:e.from)||``,l=a[s?t:c]?.issueRepo??a[t]?.issueRepo,f=!c||c===`broadcast`||c.includes(`:`),p=V(e),m=X(e.occurredAt??e.createdAt),h=s?u:d,g=a[e.from??``]??null;function _(e){e.stopPropagation(),g&&o(g)}return(0,Z.jsx)(`div`,{"data-msg-id":e.id,className:`flex justify-center mb-1.5`,children:(0,Z.jsxs)(`div`,{className:`w-full max-w-[94%] rounded-md border border-border/50 bg-muted/15 px-2.5 py-1`,children:[(0,Z.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs cursor-pointer select-none`,onClick:()=>i(e=>!e),children:[(0,Z.jsx)(b,{className:n(`h-3 w-3 shrink-0 text-muted-foreground/60 transition-transform`,r&&`rotate-90`)}),(0,Z.jsx)(`button`,{type:`button`,title:g?g.label||g.name||g.id:void 0,disabled:!g,onClick:_,className:n(`shrink-0 transition-opacity`,g?`cursor-pointer hover:opacity-80`:`cursor-default opacity-60`),children:(0,Z.jsx)(W,{agent:g,className:`!w-4 !h-4 !rounded-sm opacity-70`})}),(0,Z.jsx)(h,{className:`h-3 w-3 shrink-0 text-muted-foreground/70`}),(0,Z.jsxs)(`span`,{className:`shrink-0 text-muted-foreground`,children:[`Message `,s?`to`:`from`]}),f?(0,Z.jsx)(`span`,{className:`shrink-0 font-medium text-muted-foreground`,children:ce(c,a)}):(0,Z.jsx)(Q,{agentId:c,className:`shrink-0 px-0.5 text-foreground/80`,noIcon:!0}),!r&&(0,Z.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-muted-foreground/50`,children:p}),(0,Z.jsx)(`span`,{className:`ml-auto shrink-0 text-muted-foreground/40`,children:m})]}),r&&(0,Z.jsx)(`div`,{className:`mt-1.5 pl-5`,children:(0,Z.jsx)(G,{text:p,rawBody:e.body,issueRepo:l,className:`text-sm leading-relaxed text-foreground/90`})})]})})}var Ct=(0,K.memo)(function({msg:e,peer:t,showAvatar:r=!1,onOpenReferencedPath:i,onPreviewReferencedPath:a,onPreviewReferencedPathEnd:o}){if(!B(e.from)&&!B(e.to))return(0,Z.jsx)(St,{msg:e,peer:t});let s=e.kind===`session`?e.payload?.session:void 0;if(s?.type===`prompt`&&s?.origin===`provider`)return(0,Z.jsx)(vt,{msg:e,peer:t});let c=B(e.from),l=F(e=>e.reactToMessage),u=F(e=>e.voiceTtsEnabled),d=_t(),f=F(e=>{let n=e.agentsById[t]?.meta?.cwd;return typeof n==`string`?n:``}),p=F(e=>e.agentsById[t]?.issueRepo),m=F(e=>e.agentsById[t]??null),h=F(e=>e.usersById),g=F(e=>e.users.length>1),_=c?ae(e.from,h):void 0,y=F(e=>e.openAgentDetail),[b,x]=(0,K.useState)(!1),S=(0,K.useRef)(null),C=(0,K.useRef)(null),w=(0,K.useRef)(!1),T=V(e),ee=X(e.occurredAt??e.createdAt),E=Ne(e),D=Fe(e),O=c?Ie(e,t):null,k=O?.icon,A=d===String(e.id),j=u&&!c&&!Y(e)&&T.trim().length>0;function M(t){t.stopPropagation(),A?P.bargeIn():P.speak(e.body,String(e.id))}(0,K.useEffect)(()=>{if(!b)return;function e(e){Me()||S.current&&!S.current.contains(e.target)&&x(!1)}return document.addEventListener(`mousedown`,e),document.addEventListener(`touchstart`,e),()=>{document.removeEventListener(`mousedown`,e),document.removeEventListener(`touchstart`,e)}},[b]);function N(e){return Oe(f||`/`,e)}function ne(e,t){let n=N(e);i?.(n,t)}function I(e,t,n){let r=N(e);a?.(r,t,n)}function L(t){l(e,t),x(!1)}function R(e){e.button===0&&(C.current={x:e.clientX,y:e.clientY},w.current=!1)}function re(e){let t=C.current;t&&(Math.abs(e.clientX-t.x)>3||Math.abs(e.clientY-t.y)>3)&&(w.current=!0)}function ie(t){if(!(Y(e)||c)&&!t.target.closest(`a,button,input,textarea,select,[role="button"]`)){if(w.current||Me()){w.current=!1;return}x(e=>!e)}}let z=r&&!Y(e);function se(){!c&&m&&y(m)}return(0,Z.jsxs)(`div`,{"data-msg-id":e.id,className:n(`group/msg flex mb-3 items-end`,c?`justify-end`:`justify-start`,z&&`gap-1.5`),children:[!c&&z&&(0,Z.jsx)(yt,{agent:m,onClick:se}),(0,Z.jsxs)(`div`,{ref:S,className:n(`relative`,z?`max-w-[calc(85%-2rem)] md:max-w-[calc(75%-2rem)]`:`max-w-[85%] md:max-w-[75%]`),children:[j&&(0,Z.jsx)(`button`,{type:`button`,title:A?`Stop playback`:`Play aloud`,onClick:M,className:n(`absolute -top-2 -right-2 z-20 inline-flex h-6 w-6 items-center justify-center rounded-full border bg-popover shadow-sm transition`,A?`border-primary/50 text-primary opacity-100`:`border-border text-muted-foreground opacity-70 hover:bg-muted hover:text-foreground hover:opacity-100 [@media(hover:hover)]:md:opacity-0 [@media(hover:hover)]:md:group-hover/msg:opacity-100`),children:A?(0,Z.jsx)(te,{className:`h-3.5 w-3.5 animate-pulse`}):(0,Z.jsx)(v,{className:`h-3.5 w-3.5`})}),(0,Z.jsxs)(`div`,{className:n(`rounded-2xl px-3.5 py-2 text-sm select-text`,!c&&!Y(e)&&`cursor-pointer`,c?`bg-primary text-primary-foreground rounded-br-sm`:`bg-card ring-1 ring-foreground/10 rounded-bl-sm`),onPointerDown:R,onPointerMove:re,onClick:ie,children:[c&&g&&(0,Z.jsx)(`p`,{className:n(`text-[11px] font-semibold mb-0.5 text-right`,oe(e.from)),children:le(e.from,h)}),e.subject&&(0,Z.jsx)(`p`,{className:n(`text-xs font-semibold mb-1`,c?`text-primary-foreground/70`:`text-muted-foreground`),children:e.subject}),(0,Z.jsx)(G,{text:T,rawBody:e.body,issueRepo:p,className:`leading-relaxed`,onPrimary:c,onOpenPath:ne,onPreviewPath:I,onPreviewPathEnd:o,resolvePathTitle:(e,t)=>`${N(e)}${t?`:${t}`:``}`}),E.map(t=>(0,Z.jsx)(bt,{attachment:t,outbound:c},`${e.id}-${t.artifactId}-${t.role||``}`)),(0,Z.jsxs)(`p`,{className:n(`text-xs mt-1 flex items-center gap-1.5`,c?`justify-end text-primary-foreground/60`:`justify-end text-muted-foreground`),children:[(0,Z.jsxs)(`span`,{className:`opacity-40`,children:[`#`,e.id]}),(0,Z.jsx)(`span`,{children:ee}),O&&k&&(0,Z.jsxs)(`span`,{className:n(`inline-flex items-center gap-1`,O.tone===`ok`&&`text-emerald-300`,O.tone===`warn`&&`text-amber-200`,O.tone===`danger`&&`text-red-200`),title:O.title,children:[(0,Z.jsx)(k,{className:`h-3 w-3`}),O.label]})]})]}),!Y(e)&&D.length>0&&(0,Z.jsxs)(`div`,{className:n(`flex flex-wrap items-center gap-0.5 -mt-1 relative z-10`,c?`justify-end pr-2`:`justify-start pl-2`),children:[!c&&(0,Z.jsx)(xt,{open:b,onToggle:()=>x(e=>!e),onReact:L}),D.map(e=>(0,Z.jsxs)(`button`,{type:`button`,title:e.actors.join(`, `),onClick:()=>L(e.emoji),className:n(`inline-flex h-5 items-center gap-0.5 rounded-full border px-1.5 text-[11px] shadow-sm transition-colors`,e.mine?`border-primary/40 bg-primary/10 text-primary`:`border-border bg-background hover:bg-muted text-foreground`),children:[(0,Z.jsx)(`span`,{children:e.emoji}),e.count>1&&(0,Z.jsx)(`span`,{children:e.count})]},e.emoji))]}),!Y(e)&&!c&&D.length===0&&(0,Z.jsx)(`div`,{className:`absolute -bottom-2.5 left-1 z-20`,children:(0,Z.jsx)(xt,{open:b,onToggle:()=>x(e=>!e),onReact:L})})]}),c&&z&&(0,Z.jsx)(`span`,{className:`shrink-0 self-end opacity-60`,children:(0,Z.jsx)(gt,{user:_,address:e.from,distinct:g})})]})});export{Ce as C,Re as S,Te as T,Ae as _,ut as a,Ve as b,ft as c,it as d,Ge as f,Be as g,De as h,at as i,pt as l,ze as m,ct as n,lt as o,mt as p,et as r,dt as s,Ct as t,Xe as u,ke as v,we as w,je as x,He as y};
|
|
3
|
-
//# sourceMappingURL=MessageBubble-ckJ2VVgq.js.map
|