shadow-claw 1.31.0 → 1.32.0
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/.well-known/mcp/server-card.json +1 -1
- package/.well-known/mcp.json +1 -1
- package/dist/lib/components/index.js +21 -21
- package/dist/lib/components/settings/shadow-claw-channel-config.js +1 -1
- package/dist/lib/components/settings/shadow-claw-control-plane.js +1 -1
- package/dist/lib/components/settings/shadow-claw-git.js +1 -1
- package/dist/lib/components/settings/shadow-claw-llm.js +1 -1
- package/dist/lib/components/settings/shadow-claw-networking.js +1 -1
- package/dist/lib/components/settings/shadow-claw-notifications.js +1 -1
- package/dist/lib/components/settings/shadow-claw-peerjs.js +1 -1
- package/dist/lib/components/settings/shadow-claw-storage.js +1 -1
- package/dist/lib/components/settings/shadow-claw-task-server.js +1 -1
- package/dist/lib/components/settings/shadow-claw-webvm.js +1 -1
- package/dist/lib/components/shadow-claw-channel-config.js +1 -1
- package/dist/lib/components/shadow-claw-channels.js +1 -1
- package/dist/lib/components/shadow-claw-chat.js +1 -1
- package/dist/lib/components/shadow-claw-control-plane.js +1 -1
- package/dist/lib/components/shadow-claw-conversations.js +1 -1
- package/dist/lib/components/shadow-claw-file-viewer.js +1 -1
- package/dist/lib/components/shadow-claw-files.js +1 -1
- package/dist/lib/components/shadow-claw-git.js +1 -1
- package/dist/lib/components/shadow-claw-llm.js +1 -1
- package/dist/lib/components/shadow-claw-networking.js +1 -1
- package/dist/lib/components/shadow-claw-notifications.js +1 -1
- package/dist/lib/components/shadow-claw-pages.js +1 -1
- package/dist/lib/components/shadow-claw-peerjs.js +1 -1
- package/dist/lib/components/shadow-claw-settings.js +1 -1
- package/dist/lib/components/shadow-claw-storage.js +1 -1
- package/dist/lib/components/shadow-claw-task-server.js +1 -1
- package/dist/lib/components/shadow-claw-tasks.js +1 -1
- package/dist/lib/components/shadow-claw-terminal.js +1 -1
- package/dist/lib/components/shadow-claw-tools.js +1 -1
- package/dist/lib/components/shadow-claw-webvm.js +1 -1
- package/dist/lib/components/shadow-claw.js +1 -1
- package/dist/lib/{configurePeerJs-u7CYSquX.js → configurePeerJs-DD3G3Pms.js} +2 -2
- package/dist/lib/{configurePeerJs-u7CYSquX.js.map → configurePeerJs-DD3G3Pms.js.map} +1 -1
- package/dist/lib/{git-DAP_EV6R.js → git-Brr7JIbs.js} +25 -8
- package/dist/lib/{git-DAP_EV6R.js.map → git-Brr7JIbs.js.map} +1 -1
- package/dist/lib/index.js +21 -21
- package/dist/lib/{initControlPlane-DCK_SHeR.js → initControlPlane-3TUdhRBM.js} +7 -7
- package/dist/lib/{initControlPlane-DCK_SHeR.js.map → initControlPlane-3TUdhRBM.js.map} +1 -1
- package/dist/lib/{orchestrator-XygttQw2.js → orchestrator-DLnCmeTZ.js} +5 -5
- package/dist/lib/{orchestrator-XygttQw2.js.map → orchestrator-DLnCmeTZ.js.map} +1 -1
- package/dist/lib/{orchestrator-DNamnY-k.js → orchestrator-DW5l2bbW.js} +22 -4
- package/dist/lib/{orchestrator-DNamnY-k.js.map → orchestrator-DW5l2bbW.js.map} +1 -1
- package/dist/lib/{peerjs-BgkPSHKa.js → peerjs-BXlMuIQn.js} +3 -3
- package/dist/lib/{peerjs-BgkPSHKa.js.map → peerjs-BXlMuIQn.js.map} +1 -1
- package/dist/lib/{push-client-C09NQEk5.js → push-client-B419nn-i.js} +2 -2
- package/dist/lib/{push-client-C09NQEk5.js.map → push-client-B419nn-i.js.map} +1 -1
- package/dist/lib/{shadow-claw-vzcggiax.js → shadow-claw-DmMO4vVG.js} +4 -4
- package/dist/lib/{shadow-claw-vzcggiax.js.map → shadow-claw-DmMO4vVG.js.map} +1 -1
- package/dist/lib/{shadow-claw-channel-config-Cl3JvxIJ.js → shadow-claw-channel-config-BhxHf6wZ.js} +3 -3
- package/dist/lib/{shadow-claw-channel-config-Cl3JvxIJ.js.map → shadow-claw-channel-config-BhxHf6wZ.js.map} +1 -1
- package/dist/lib/{shadow-claw-channels-kv21lr_O.js → shadow-claw-channels-B5vzE9Z2.js} +2 -2
- package/dist/lib/{shadow-claw-channels-kv21lr_O.js.map → shadow-claw-channels-B5vzE9Z2.js.map} +1 -1
- package/dist/lib/{shadow-claw-chat-Cj1fHQIl.js → shadow-claw-chat-BsYnJ4-G.js} +3 -3
- package/dist/lib/{shadow-claw-chat-Cj1fHQIl.js.map → shadow-claw-chat-BsYnJ4-G.js.map} +1 -1
- package/dist/lib/{shadow-claw-control-plane-DySeKB36.js → shadow-claw-control-plane-DqcgQsun.js} +6 -6
- package/dist/lib/{shadow-claw-control-plane-DySeKB36.js.map → shadow-claw-control-plane-DqcgQsun.js.map} +1 -1
- package/dist/lib/{shadow-claw-conversations-DghueOOD.js → shadow-claw-conversations-B9Pn58g3.js} +2 -2
- package/dist/lib/{shadow-claw-conversations-DghueOOD.js.map → shadow-claw-conversations-B9Pn58g3.js.map} +1 -1
- package/dist/lib/{shadow-claw-file-viewer-C_ITv8T6.js → shadow-claw-file-viewer-DL6c4oPK.js} +2 -2
- package/dist/lib/{shadow-claw-file-viewer-C_ITv8T6.js.map → shadow-claw-file-viewer-DL6c4oPK.js.map} +1 -1
- package/dist/lib/{shadow-claw-files-CWBaYt9p.js → shadow-claw-files-C_ksPb8W.js} +2 -2
- package/dist/lib/{shadow-claw-files-CWBaYt9p.js.map → shadow-claw-files-C_ksPb8W.js.map} +1 -1
- package/dist/lib/{shadow-claw-git-XfPBpfXd.js → shadow-claw-git-jwsY7L1N.js} +3 -3
- package/dist/lib/{shadow-claw-git-XfPBpfXd.js.map → shadow-claw-git-jwsY7L1N.js.map} +1 -1
- package/dist/lib/{shadow-claw-llm-Gzx4ufL_.js → shadow-claw-llm-CEPJh1Jh.js} +2 -2
- package/dist/lib/{shadow-claw-llm-Gzx4ufL_.js.map → shadow-claw-llm-CEPJh1Jh.js.map} +1 -1
- package/dist/lib/{shadow-claw-networking-CYEbc5TR.js → shadow-claw-networking-Bi4yvc73.js} +2 -2
- package/dist/lib/{shadow-claw-networking-CYEbc5TR.js.map → shadow-claw-networking-Bi4yvc73.js.map} +1 -1
- package/dist/lib/{shadow-claw-notifications-DHvkTrgv.js → shadow-claw-notifications-C-JgGqQx.js} +2 -2
- package/dist/lib/{shadow-claw-notifications-DHvkTrgv.js.map → shadow-claw-notifications-C-JgGqQx.js.map} +1 -1
- package/dist/lib/{shadow-claw-pages-Bj3w3V6Y.js → shadow-claw-pages-OEOClgA8.js} +2 -2
- package/dist/lib/{shadow-claw-pages-Bj3w3V6Y.js.map → shadow-claw-pages-OEOClgA8.js.map} +1 -1
- package/dist/lib/{shadow-claw-peerjs-B3sx2xLA.js → shadow-claw-peerjs-DmC2CV-9.js} +3 -3
- package/dist/lib/{shadow-claw-peerjs-B3sx2xLA.js.map → shadow-claw-peerjs-DmC2CV-9.js.map} +1 -1
- package/dist/lib/{shadow-claw-settings-DK-0kp3A.js → shadow-claw-settings-xAtFog0T.js} +2 -2
- package/dist/lib/{shadow-claw-settings-DK-0kp3A.js.map → shadow-claw-settings-xAtFog0T.js.map} +1 -1
- package/dist/lib/{shadow-claw-storage-p9nVMQPF.js → shadow-claw-storage-B4UHl-po.js} +2 -2
- package/dist/lib/{shadow-claw-storage-p9nVMQPF.js.map → shadow-claw-storage-B4UHl-po.js.map} +1 -1
- package/dist/lib/{shadow-claw-task-server-BNKCWG2M.js → shadow-claw-task-server-B0eWzg57.js} +2 -2
- package/dist/lib/{shadow-claw-task-server-BNKCWG2M.js.map → shadow-claw-task-server-B0eWzg57.js.map} +1 -1
- package/dist/lib/{shadow-claw-tasks-Dbq9rUku.js → shadow-claw-tasks-HHU_8Gyg.js} +2 -2
- package/dist/lib/{shadow-claw-tasks-Dbq9rUku.js.map → shadow-claw-tasks-HHU_8Gyg.js.map} +1 -1
- package/dist/lib/{shadow-claw-terminal-Wk2qRWJ9.js → shadow-claw-terminal-CdC2G6Zz.js} +2 -2
- package/dist/lib/{shadow-claw-terminal-Wk2qRWJ9.js.map → shadow-claw-terminal-CdC2G6Zz.js.map} +1 -1
- package/dist/lib/{shadow-claw-tools-C9TEf2k7.js → shadow-claw-tools-2AICxVXA.js} +3 -3
- package/dist/lib/{shadow-claw-tools-C9TEf2k7.js.map → shadow-claw-tools-2AICxVXA.js.map} +1 -1
- package/dist/lib/{shadow-claw-webvm-VoKerWW8.js → shadow-claw-webvm-Cy-Ia2vs.js} +2 -2
- package/dist/lib/{shadow-claw-webvm-VoKerWW8.js.map → shadow-claw-webvm-Cy-Ia2vs.js.map} +1 -1
- package/dist/lib/subsystems/git/git.d.ts +8 -1
- package/dist/lib/subsystems/git/types.d.ts +7 -1
- package/dist/lib/{syncWebMcpRegistration-DEs4JjI_.js → syncWebMcpRegistration-CaAPPg2V.js} +2 -2
- package/dist/lib/{syncWebMcpRegistration-DEs4JjI_.js.map → syncWebMcpRegistration-CaAPPg2V.js.map} +1 -1
- package/dist/public/.well-known/mcp/server-card.json +1 -1
- package/dist/public/.well-known/mcp.json +1 -1
- package/dist/public/agent.worker.js +2 -2
- package/dist/public/{configurePeerJs-B68egTBd.js → configurePeerJs--JGpJVti.js} +1 -1
- package/dist/public/docs/example/article/index.html +1 -1
- package/dist/public/docs/publishing/index.html +1 -1
- package/dist/public/docs/skill-creator/index.html +1 -1
- package/dist/public/{e2e-bridge-DQ4Mb_eC.js → e2e-bridge-CbYqdMp-.js} +1 -1
- package/dist/public/{file-viewer-BqNHyqzy.js → file-viewer-vHJ5Zsgk.js} +1 -1
- package/dist/public/git-8F7wvoUB.js +100 -0
- package/dist/public/git-DgFF7xTW.js +100 -0
- package/dist/public/index.html +1 -1
- package/dist/public/index.js +1 -1
- package/dist/public/{initControlPlane-DG_LcLDy.js → initControlPlane-C5v0FtJE.js} +1 -1
- package/dist/public/main/index.html +1 -1
- package/dist/public/main/memory/index.html +1 -1
- package/dist/public/{orchestrator-DAJkyJmV.js → orchestrator-BeJfwtvz.js} +3 -3
- package/dist/public/{orchestrator-BXwxW4N2.js → orchestrator-DNr2HDI2.js} +1 -1
- package/dist/public/{peerjs-BaDbzfgl.js → peerjs-mG30TAJ_.js} +1 -1
- package/dist/public/{push-client-B1CCaldJ.js → push-client-C2zMT3Sf.js} +1 -1
- package/dist/public/service-worker.js +1 -1
- package/dist/public/{shadow-claw-CpBmveOh.js → shadow-claw-Ble6l0Iw.js} +2 -2
- package/dist/public/{shadow-claw-channels-7Oew09u0.js → shadow-claw-channels-D_xfBoWp.js} +1 -1
- package/dist/public/{shadow-claw-chat-CskwjDzZ.js → shadow-claw-chat-D_Lbi5oH.js} +1 -1
- package/dist/public/{shadow-claw-control-plane-BqjEyhx7.js → shadow-claw-control-plane-CrnA5lM0.js} +2 -2
- package/dist/public/{shadow-claw-conversations-ClGgBPVY.js → shadow-claw-conversations-BN-hFmN1.js} +1 -1
- package/dist/public/{shadow-claw-file-viewer-rDepUwFJ.js → shadow-claw-file-viewer-BKEpzpbx.js} +1 -1
- package/dist/public/{shadow-claw-files-C0r05PYf.js → shadow-claw-files-DDZMk5AA.js} +1 -1
- package/dist/public/{shadow-claw-git-CXrECHKy.js → shadow-claw-git-CqOO97Re.js} +2 -2
- package/dist/public/{shadow-claw-llm-jeGVNciG.js → shadow-claw-llm-DoGxEHQL.js} +1 -1
- package/dist/public/{shadow-claw-networking--q6MgEAT.js → shadow-claw-networking-DJeCdb7e.js} +1 -1
- package/dist/public/{shadow-claw-notifications-CrFUF0fl.js → shadow-claw-notifications-hSKJeMXb.js} +1 -1
- package/dist/public/{shadow-claw-pages-_n1wVXAV.js → shadow-claw-pages-DTS98Zbi.js} +1 -1
- package/dist/public/{shadow-claw-settings-5yIfa3ie.js → shadow-claw-settings-5w0ce8SP.js} +2 -2
- package/dist/public/{shadow-claw-storage-PLX9EFGn.js → shadow-claw-storage-DqlVt27X.js} +1 -1
- package/dist/public/{shadow-claw-task-server-BMps7aSr.js → shadow-claw-task-server-ByZwKI6S.js} +1 -1
- package/dist/public/{shadow-claw-tasks-CHO1xvsu.js → shadow-claw-tasks-Dc4G4zBu.js} +1 -1
- package/dist/public/{shadow-claw-terminal-BJnSXRsb.js → shadow-claw-terminal-DvusP7wg.js} +1 -1
- package/dist/public/{shadow-claw-tools-BHfxRckC.js → shadow-claw-tools-BEsid8q-.js} +1 -1
- package/dist/public/{shadow-claw-webvm-CyI23mQT.js → shadow-claw-webvm-BWlIeK78.js} +1 -1
- package/dist/public/{syncWebMcpRegistration-R0tha3kP.js → syncWebMcpRegistration-CqVCB6m8.js} +1 -1
- package/package.json +1 -1
- package/src/storage/staticMainSite.ts +16 -2
- package/src/stores/orchestrator.test.ts +33 -0
- package/src/stores/orchestrator.ts +36 -0
- package/src/subsystems/git/git.test.ts +99 -0
- package/src/subsystems/git/git.ts +92 -12
- package/src/subsystems/git/types.ts +7 -0
- package/dist/public/git-BDaM5VT5.js +0 -100
- package/dist/public/git-D4n46G9B.js +0 -100
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"peerjs-BgkPSHKa.js","names":[],"sources":["../../src/content/message-attachments.ts","../../src/subsystems/channels/peer-protocol.ts","../../src/subsystems/channels/peer-agent-card.ts","../../src/subsystems/channels/peer-task-manager.ts","../../src/subsystems/channels/peerjs.ts"],"sourcesContent":["import { uploadGroupFile } from \"../storage/uploadGroupFile.js\";\nimport type { MessageAttachment, MessageAttachmentSource } from \"./types.js\";\nimport type { ShadowClawDatabase } from \"../db/types.js\";\n\nconst MIME_TYPES_BY_EXTENSION: Record<string, string> = {\n apng: \"image/apng\",\n avif: \"image/avif\",\n bmp: \"image/bmp\",\n css: \"text/css\",\n gif: \"image/gif\",\n htm: \"text/html\",\n html: \"text/html\",\n jpeg: \"image/jpeg\",\n jpg: \"image/jpeg\",\n js: \"text/javascript\",\n json: \"application/json\",\n markdown: \"text/markdown\",\n md: \"text/markdown\",\n mp3: \"audio/mpeg\",\n mp4: \"video/mp4\",\n oga: \"audio/ogg\",\n ogg: \"audio/ogg\",\n ogv: \"video/ogg\",\n pdf: \"application/pdf\",\n png: \"image/png\",\n svg: \"image/svg+xml\",\n txt: \"text/plain\",\n wav: \"audio/wav\",\n webm: \"video/webm\",\n webp: \"image/webp\",\n};\n\nexport function sanitizeAttachmentFileName(fileName: string): string {\n const trimmed = fileName.trim();\n const normalized = trimmed\n .replace(/[\\u0000-\\u001f\\u007f]+/g, \"\")\n .replace(/[\\\\/:*?\"<>|]+/g, \"-\")\n .replace(/\\s+/g, \" \")\n .replace(/^\\.+/, \"\")\n .trim();\n\n return normalized || \"attachment\";\n}\n\nexport function inferAttachmentMimeType(\n fileName: string,\n explicitMimeType = \"\",\n): string {\n if (explicitMimeType) {\n return explicitMimeType;\n }\n\n const extension = fileName.toLowerCase().split(\".\").pop() || \"\";\n\n return MIME_TYPES_BY_EXTENSION[extension] || \"application/octet-stream\";\n}\n\nexport function shouldInlineAttachmentInChat(\n attachment: Pick<\n MessageAttachment,\n \"fileName\" | \"mimeType\" | \"previewDisposition\"\n >,\n): boolean {\n if (attachment.previewDisposition === \"inline\") {\n return true;\n }\n\n return (\n inferAttachmentMimeType(attachment.fileName, attachment.mimeType || \"\") ===\n \"image/png\"\n );\n}\n\nexport function buildAttachmentStoragePath(\n fileName: string,\n attachmentId = \"\",\n timestamp = Date.now(),\n): string {\n const safeName = sanitizeAttachmentFileName(fileName);\n const safeId = attachmentId\n .trim()\n .replace(/[^a-zA-Z0-9._-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n const prefix = safeId ? `${safeId}-` : \"\";\n\n return `attachments/${timestamp}-${prefix}${safeName}`;\n}\n\nexport async function persistMessageAttachments(\n db: ShadowClawDatabase,\n groupId: string,\n attachments: MessageAttachment[] = [],\n): Promise<MessageAttachment[]> {\n const persisted: MessageAttachment[] = [];\n\n for (const attachment of attachments) {\n const fileName = sanitizeAttachmentFileName(attachment.fileName || \"\");\n const path =\n attachment.path || buildAttachmentStoragePath(fileName, attachment.id);\n const source = attachment.source;\n\n let mimeType = inferAttachmentMimeType(fileName, attachment.mimeType || \"\");\n let size = attachment.size;\n\n if (source) {\n const blob = await readAttachmentSourceAsBlob(source);\n mimeType = inferAttachmentMimeType(\n fileName,\n attachment.mimeType || blob.type,\n );\n size = typeof size === \"number\" ? size : blob.size;\n await uploadGroupFile(db, groupId, path, blob);\n }\n\n persisted.push(\n stripAttachmentSource({\n ...attachment,\n fileName,\n mimeType,\n size,\n path,\n previewDisposition:\n attachment.previewDisposition ||\n (mimeType === \"image/png\" ? \"inline\" : \"file\"),\n }),\n );\n }\n\n return persisted;\n}\n\nasync function readAttachmentSourceAsBlob(\n source: MessageAttachmentSource,\n): Promise<Blob> {\n if (source.kind === \"local-file\") {\n return source.file;\n }\n\n if (source.kind === \"inline-text\") {\n return new Blob([source.text], {\n type: source.mimeType || \"text/plain\",\n });\n }\n\n const response = await fetch(source.url, {\n headers: source.headers,\n });\n\n if (!response.ok) {\n throw new Error(\n `Attachment download failed: HTTP ${response.status} ${response.statusText}`,\n );\n }\n\n return await response.blob();\n}\n\nfunction stripAttachmentSource(\n attachment: MessageAttachment,\n): MessageAttachment {\n const { source, ...storedAttachment } = attachment;\n\n return storedAttachment;\n}\n","/**\n * A2A v1.0 + AG-UI Protocol Types for WebRTC DataChannel Binding\n *\n * Custom binding identifier:\n * https://xt-ml.github.io/shadow-claw/bindings/webrtc-datachannel/v1\n *\n * This module defines:\n * - A2A v1.0 canonical data model (Task, Message, Part, Artifact, TaskState)\n * - AG-UI event types for streaming visibility\n * - Wire protocol envelope (JSON-RPC 2.0 over DataChannel)\n * - Error codes per A2A spec §5.4\n *\n * References:\n * - https://a2a-protocol.org/latest/specification/\n * - https://docs.ag-ui.com/concepts/events\n */\n\nimport type { A2UIAction, A2UIEnvelope } from \"../../ui/a2ui/types.js\";\nimport type { RoomMember } from \"./types.js\";\n\n// =============================================================================\n// A2A v1.0 Protocol Binding Identifier\n// =============================================================================\n\nexport const A2A_PROTOCOL_BINDING =\n \"https://xt-ml.github.io/shadow-claw/bindings/webrtc-datachannel/v1\";\n\nexport const A2A_PROTOCOL_VERSION = \"1.0\";\n\n// =============================================================================\n// A2A Task States (spec §4.1.3)\n// =============================================================================\n\nexport enum TaskState {\n UNSPECIFIED = \"TASK_STATE_UNSPECIFIED\",\n SUBMITTED = \"TASK_STATE_SUBMITTED\",\n WORKING = \"TASK_STATE_WORKING\",\n COMPLETED = \"TASK_STATE_COMPLETED\",\n FAILED = \"TASK_STATE_FAILED\",\n CANCELED = \"TASK_STATE_CANCELED\",\n INPUT_REQUIRED = \"TASK_STATE_INPUT_REQUIRED\",\n REJECTED = \"TASK_STATE_REJECTED\",\n AUTH_REQUIRED = \"TASK_STATE_AUTH_REQUIRED\",\n}\n\n/** Terminal states — no further transitions allowed */\nexport const TERMINAL_STATES: ReadonlySet<TaskState> = new Set([\n TaskState.COMPLETED,\n TaskState.FAILED,\n TaskState.CANCELED,\n TaskState.REJECTED,\n]);\n\n/** Interrupted states — can transition back to WORKING */\nexport const INTERRUPTED_STATES: ReadonlySet<TaskState> = new Set([\n TaskState.INPUT_REQUIRED,\n TaskState.AUTH_REQUIRED,\n]);\n\n// =============================================================================\n// A2A Roles (spec §4.1.5)\n// =============================================================================\n\nexport enum Role {\n UNSPECIFIED = \"ROLE_UNSPECIFIED\",\n USER = \"ROLE_USER\",\n AGENT = \"ROLE_AGENT\",\n}\n\n// =============================================================================\n// A2A Part (spec §4.1.6 — v1.0 member-name discriminator)\n// =============================================================================\n\nexport interface TextPart {\n text: string;\n mediaType?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface RawPart {\n raw: string; // base64-encoded bytes\n filename?: string;\n mediaType?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface UrlPart {\n url: string;\n filename?: string;\n mediaType?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface DataPart {\n data: unknown;\n mediaType?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport type Part = TextPart | RawPart | UrlPart | DataPart;\n\n// =============================================================================\n// A2A Message (spec §4.1.4)\n// =============================================================================\n\nexport interface A2AMessage {\n messageId: string;\n role: Role;\n parts: Part[];\n contextId?: string;\n taskId?: string;\n metadata?: Record<string, unknown>;\n extensions?: string[];\n referenceTaskIds?: string[];\n}\n\n// =============================================================================\n// A2A TaskStatus (spec §4.1.2)\n// =============================================================================\n\nexport interface TaskStatus {\n state: TaskState;\n message?: A2AMessage;\n timestamp?: string; // ISO 8601\n}\n\n// =============================================================================\n// A2A Task (spec §4.1.1)\n// =============================================================================\n\nexport interface A2ATask {\n id: string;\n contextId?: string;\n status: TaskStatus;\n artifacts?: Artifact[];\n history?: A2AMessage[];\n metadata?: Record<string, unknown>;\n}\n\n// =============================================================================\n// A2A Artifact (spec §4.1.7)\n// =============================================================================\n\nexport interface Artifact {\n artifactId: string;\n name?: string;\n description?: string;\n parts: Part[];\n metadata?: Record<string, unknown>;\n extensions?: string[];\n}\n\n// =============================================================================\n// A2A Streaming Events (spec §4.2)\n// =============================================================================\n\nexport interface TaskStatusUpdateEvent {\n taskId: string;\n contextId: string;\n status: TaskStatus;\n metadata?: Record<string, unknown>;\n}\n\nexport interface TaskArtifactUpdateEvent {\n taskId: string;\n contextId: string;\n artifact: Artifact;\n append?: boolean;\n lastChunk?: boolean;\n metadata?: Record<string, unknown>;\n}\n\n// =============================================================================\n// A2A Agent Discovery (spec §4.4)\n// =============================================================================\n\nexport interface AgentCard {\n name: string;\n description: string;\n version: string;\n supportedInterfaces: AgentInterface[];\n capabilities: AgentCapabilities;\n defaultInputModes: string[];\n defaultOutputModes: string[];\n skills: AgentSkill[];\n provider?: AgentProvider;\n iconUrl?: string;\n documentationUrl?: string;\n}\n\nexport interface AgentInterface {\n url: string;\n protocolBinding: string;\n protocolVersion: string;\n tenant?: string;\n}\n\nexport interface AgentCapabilities {\n streaming?: boolean;\n pushNotifications?: boolean;\n extendedAgentCard?: boolean;\n extensions?: AgentExtension[];\n}\n\nexport interface AgentExtension {\n uri: string;\n description?: string;\n required?: boolean;\n params?: Record<string, unknown>;\n}\n\nexport interface AgentSkill {\n id: string;\n name: string;\n description: string;\n tags: string[];\n examples?: string[];\n inputModes?: string[];\n outputModes?: string[];\n}\n\nexport interface AgentProvider {\n organization: string;\n url: string;\n}\n\n// =============================================================================\n// A2A SendMessage Request/Response (spec §3.2.1, §3.2.2)\n// =============================================================================\n\nexport interface SendMessageRequest {\n message: A2AMessage;\n configuration?: SendMessageConfiguration;\n metadata?: Record<string, unknown>;\n}\n\nexport interface SendMessageConfiguration {\n acceptedOutputModes?: string[];\n historyLength?: number;\n returnImmediately?: boolean;\n}\n\nexport interface SendMessageResponse {\n task?: A2ATask;\n message?: A2AMessage;\n}\n\n// =============================================================================\n// A2A StreamResponse (spec §3.2.3)\n// =============================================================================\n\nexport type StreamResponse =\n | { task: A2ATask }\n | { message: A2AMessage }\n | { statusUpdate: TaskStatusUpdateEvent }\n | { artifactUpdate: TaskArtifactUpdateEvent };\n\n// =============================================================================\n// AG-UI Events (https://docs.ag-ui.com/concepts/events)\n// =============================================================================\n\n// --- Lifecycle ---\n\nexport interface AGUIRunStarted {\n type: \"RUN_STARTED\";\n threadId: string;\n runId: string;\n timestamp?: number;\n}\n\nexport interface AGUIRunFinished {\n type: \"RUN_FINISHED\";\n threadId: string;\n runId: string;\n timestamp?: number;\n}\n\nexport interface AGUIRunError {\n type: \"RUN_ERROR\";\n message: string;\n code?: string;\n timestamp?: number;\n}\n\nexport interface AGUIStepStarted {\n type: \"STEP_STARTED\";\n stepName: string;\n timestamp?: number;\n}\n\nexport interface AGUIStepFinished {\n type: \"STEP_FINISHED\";\n stepName: string;\n timestamp?: number;\n}\n\n// --- Text Message ---\n\nexport interface AGUITextMessageStart {\n type: \"TEXT_MESSAGE_START\";\n messageId: string;\n role: \"assistant\" | \"user\" | \"developer\" | \"system\" | \"tool\";\n timestamp?: number;\n}\n\nexport interface AGUITextMessageContent {\n type: \"TEXT_MESSAGE_CONTENT\";\n messageId: string;\n delta: string;\n timestamp?: number;\n}\n\nexport interface AGUITextMessageEnd {\n type: \"TEXT_MESSAGE_END\";\n messageId: string;\n timestamp?: number;\n}\n\n// --- Tool Calls ---\n\nexport interface AGUIToolCallStart {\n type: \"TOOL_CALL_START\";\n toolCallId: string;\n toolCallName: string;\n parentMessageId?: string;\n timestamp?: number;\n}\n\nexport interface AGUIToolCallArgs {\n type: \"TOOL_CALL_ARGS\";\n toolCallId: string;\n delta: string;\n timestamp?: number;\n}\n\nexport interface AGUIToolCallEnd {\n type: \"TOOL_CALL_END\";\n toolCallId: string;\n timestamp?: number;\n}\n\nexport interface AGUIToolCallResult {\n type: \"TOOL_CALL_RESULT\";\n toolCallId: string;\n messageId?: string;\n content: string;\n role?: \"tool\";\n timestamp?: number;\n}\n\n// --- State Management ---\n\nexport interface AGUIStateSnapshot {\n type: \"STATE_SNAPSHOT\";\n snapshot: Record<string, unknown>;\n timestamp?: number;\n}\n\nexport interface AGUIStateDelta {\n type: \"STATE_DELTA\";\n delta: Array<{ op: string; path: string; value?: unknown }>;\n timestamp?: number;\n}\n\nexport interface AGUIMessagesSnapshot {\n type: \"MESSAGES_SNAPSHOT\";\n messages: Array<Record<string, unknown>>;\n timestamp?: number;\n}\n\n// --- Custom ---\n\nexport interface AGUICustomEvent {\n type: \"CUSTOM\";\n name: string;\n value: unknown;\n timestamp?: number;\n}\n\n/** Union of all AG-UI event types */\nexport type AGUIEvent =\n | AGUIRunStarted\n | AGUIRunFinished\n | AGUIRunError\n | AGUIStepStarted\n | AGUIStepFinished\n | AGUITextMessageStart\n | AGUITextMessageContent\n | AGUITextMessageEnd\n | AGUIToolCallStart\n | AGUIToolCallArgs\n | AGUIToolCallEnd\n | AGUIToolCallResult\n | AGUIStateSnapshot\n | AGUIStateDelta\n | AGUIMessagesSnapshot\n | AGUICustomEvent;\n\n// =============================================================================\n// Wire Protocol — JSON-RPC 2.0 over WebRTC DataChannel\n// =============================================================================\n\n/**\n * JSON-RPC 2.0 error object (spec §9.5)\n */\nexport interface A2AJsonRpcError {\n code: number;\n message: string;\n data?: unknown[];\n}\n\n/**\n * JSON-RPC 2.0 Request (has `id` and `method`)\n */\nexport interface A2AJsonRpcRequest {\n jsonrpc: \"2.0\";\n id: string;\n method: string;\n params?: unknown;\n}\n\n/**\n * JSON-RPC 2.0 Response (has `id` and either `result` or `error`)\n */\nexport interface A2AJsonRpcResponse {\n jsonrpc: \"2.0\";\n id: string;\n result?: unknown;\n error?: A2AJsonRpcError;\n}\n\n/**\n * JSON-RPC 2.0 Notification (has `method` but no `id`)\n */\nexport interface A2AJsonRpcNotification {\n jsonrpc: \"2.0\";\n method: string;\n params?: unknown;\n}\n\n/** Union of all wire message types */\nexport type A2AWireMessage =\n | A2AJsonRpcRequest\n | A2AJsonRpcResponse\n | A2AJsonRpcNotification;\n\n// =============================================================================\n// Wire Protocol Methods\n// =============================================================================\n\n/** Standard A2A methods (spec §9.4) */\nexport const A2A_METHOD = {\n SEND_MESSAGE: \"SendMessage\",\n SEND_STREAMING_MESSAGE: \"SendStreamingMessage\",\n GET_TASK: \"GetTask\",\n CANCEL_TASK: \"CancelTask\",\n GET_AGENT_CARD: \"GetAgentCard\",\n} as const;\n\n/** AG-UI event notification method */\nexport const AGUI_METHOD = {\n EVENT: \"agui/event\",\n} as const;\n\n/** A2A streaming notification methods */\nexport const A2A_STREAM_METHOD = {\n STATUS_UPDATE: \"tasks/statusUpdate\",\n ARTIFACT_UPDATE: \"tasks/artifactUpdate\",\n} as const;\n\n// =============================================================================\n// Room (multi-party) Wire Protocol\n// =============================================================================\n\n/**\n * Room notification methods carried over the same JSON-RPC 2.0 DataChannel.\n *\n * Topology is hybrid: the room host runs a star for signaling/roster/membership\n * (`room/join`, `room/roster`, `room/leave`, `room/invite`), while actual\n * message traffic (`room/message`) flows peer-to-peer over the mesh, falling\n * back to host relay (`room/relay`) when a direct connection is unavailable.\n */\nexport const ROOM_METHOD = {\n /** member → host: request to join; host updates roster and broadcasts it. */\n JOIN: \"room/join\",\n /** host → all members: authoritative roster snapshot (pushed on change). */\n ROSTER: \"room/roster\",\n /** member → host (leaving) or host → all (disbanded). */\n LEAVE: \"room/leave\",\n /** any → recipient: a chat message tagged with the originating room. */\n MESSAGE: \"room/message\",\n /** peer → peer: out-of-band invitation to join a room. */\n INVITE: \"room/invite\",\n /** sender → host: ask the host to forward an inner notification to a target. */\n RELAY: \"room/relay\",\n /** owner → all members: a shared A2UI surface envelope (create/update/delete). */\n A2UI: \"room/a2ui\",\n /** any member → all members: a user action fired on a shared A2UI surface. */\n A2UI_ACTION: \"room/a2ui-action\",\n} as const;\n\n/** A file attachment reference within a room message. */\nexport interface RoomMessageAttachment {\n fileName: string;\n mimeType?: string;\n path?: string;\n size?: number;\n}\n\n/** Envelope for a chat message broadcast within a room. */\nexport interface RoomMessageEnvelope {\n roomId: string;\n /** Stable id used for cross-path (mesh + relay) de-duplication. */\n messageId: string;\n senderPeerId: string;\n senderAlias?: string;\n text: string;\n attachments?: RoomMessageAttachment[];\n}\n\n/** Payload for {@link ROOM_METHOD.JOIN}. */\nexport interface RoomJoinPayload {\n roomId: string;\n member: RoomMember;\n}\n\n/** Payload for {@link ROOM_METHOD.ROSTER}. */\nexport interface RoomRosterPayload {\n roomId: string;\n name: string;\n hostPeerId: string;\n members: RoomMember[];\n}\n\n/** Payload for {@link ROOM_METHOD.LEAVE}. */\nexport interface RoomLeavePayload {\n roomId: string;\n peerId: string;\n /** When true, the host has disbanded the room for everyone. */\n disbanded?: boolean;\n}\n\n/** Payload for {@link ROOM_METHOD.INVITE}. */\nexport interface RoomInvitePayload {\n roomId: string;\n roomName: string;\n hostPeerId: string;\n fromPeerId: string;\n fromAlias?: string;\n}\n\n/** Payload for {@link ROOM_METHOD.RELAY}. */\nexport interface RoomRelayPayload {\n roomId: string;\n targetPeerId: string;\n /** A JSON-RPC notification to be forwarded verbatim to {@link targetPeerId}. */\n inner: A2AJsonRpcNotification;\n}\n\n/**\n * Payload for {@link ROOM_METHOD.A2UI} — a shared A2UI surface broadcast.\n *\n * The surface is **owner-authoritative**: only {@link ownerPeerId}'s agent\n * mutates the data model. Other members render the broadcast envelope and route\n * their interactions back via {@link ROOM_METHOD.A2UI_ACTION}.\n */\nexport interface RoomA2UIEnvelope {\n roomId: string;\n /** Stable id used for cross-path (mesh + relay) de-duplication. */\n broadcastId: string;\n /** The peer whose agent owns (created) the surface. */\n ownerPeerId: string;\n /** The peer that emitted this notification. */\n senderPeerId: string;\n /** The A2UI surface envelope (createSurface / updateDataModel / …). */\n envelope: A2UIEnvelope;\n}\n\n/**\n * Payload for {@link ROOM_METHOD.A2UI_ACTION} — a user interaction on a shared\n * surface, broadcast so the surface owner's agent can process it.\n */\nexport interface RoomA2UIActionEnvelope {\n roomId: string;\n /** Stable id used for cross-path (mesh + relay) de-duplication. */\n broadcastId: string;\n /** The peer that owns the surface (whose agent should process the action). */\n ownerPeerId: string;\n /** The peer that fired the action. */\n senderPeerId: string;\n senderAlias?: string;\n /** The A2UI action (surfaceId, actionId, dataModel). */\n action: A2UIAction;\n}\n\n// =============================================================================\n// A2A Error Codes (spec §5.4)\n// =============================================================================\n\nexport const A2A_ERROR_CODE = {\n TASK_NOT_FOUND: -32001,\n TASK_NOT_CANCELABLE: -32002,\n PUSH_NOTIFICATION_NOT_SUPPORTED: -32003,\n UNSUPPORTED_OPERATION: -32004,\n CONTENT_TYPE_NOT_SUPPORTED: -32005,\n INVALID_AGENT_RESPONSE: -32006,\n\n // Standard JSON-RPC errors\n PARSE_ERROR: -32700,\n INVALID_REQUEST: -32600,\n METHOD_NOT_FOUND: -32601,\n INVALID_PARAMS: -32602,\n INTERNAL_ERROR: -32603,\n} as const;\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\nexport function isJsonRpcRequest(msg: unknown): msg is A2AJsonRpcRequest {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n (msg as any).jsonrpc === \"2.0\" &&\n typeof (msg as any).id === \"string\" &&\n typeof (msg as any).method === \"string\"\n );\n}\n\nexport function isJsonRpcResponse(msg: unknown): msg is A2AJsonRpcResponse {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n (msg as any).jsonrpc === \"2.0\" &&\n typeof (msg as any).id === \"string\" &&\n !(\"method\" in (msg as any))\n );\n}\n\nexport function isJsonRpcNotification(\n msg: unknown,\n): msg is A2AJsonRpcNotification {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n (msg as any).jsonrpc === \"2.0\" &&\n typeof (msg as any).method === \"string\" &&\n !(\"id\" in (msg as any))\n );\n}\n\nexport function isTextPart(part: Part): part is TextPart {\n return \"text\" in part;\n}\n\nexport function isRawPart(part: Part): part is RawPart {\n return \"raw\" in part;\n}\n\nexport function isUrlPart(part: Part): part is UrlPart {\n return \"url\" in part && !(\"raw\" in part) && !(\"text\" in part);\n}\n\nexport function isDataPart(part: Part): part is DataPart {\n return \"data\" in part;\n}\n\n/**\n * Check if a TaskState is terminal (no further transitions allowed).\n */\nexport function isTerminalState(state: TaskState): boolean {\n return TERMINAL_STATES.has(state);\n}\n\n/**\n * Check if a TaskState is interrupted (can resume to WORKING).\n */\nexport function isInterruptedState(state: TaskState): boolean {\n return INTERRUPTED_STATES.has(state);\n}\n","/**\n * AgentCard construction and exchange logic for A2A peer protocol.\n *\n * An AgentCard is exchanged immediately when a WebRTC DataChannel opens,\n * providing capability discovery between peers. It is constructed from\n * the local agent's configuration (name, model, tools).\n *\n * References:\n * - A2A spec §4.4 (Agent Discovery)\n * - ADR: docs/decisions/peer-protocol-a2a-agui.md\n */\n\nimport type {\n AgentCard,\n AgentInterface,\n AgentCapabilities,\n AgentSkill,\n A2AJsonRpcRequest,\n A2AJsonRpcResponse,\n} from \"./peer-protocol.js\";\n\nimport {\n A2A_PROTOCOL_BINDING,\n A2A_PROTOCOL_VERSION,\n A2A_METHOD,\n} from \"./peer-protocol.js\";\nimport { ulid } from \"../../utils/ulid.js\";\n\n// =============================================================================\n// Agent Card Builder\n// =============================================================================\n\nexport interface AgentCardOptions {\n /** Local peer ID (used to construct the interface URL) */\n peerId: string;\n /** Display name for this agent */\n name: string;\n /** Short description of what this agent does */\n description?: string;\n /** Application version */\n version?: string;\n /** Skills/capabilities this agent advertises */\n skills?: AgentSkill[];\n /** Whether streaming is supported */\n streaming?: boolean;\n /** Icon URL (optional) */\n iconUrl?: string;\n}\n\n/**\n * Build an AgentCard from local configuration.\n */\nexport function buildAgentCard(options: AgentCardOptions): AgentCard {\n const iface: AgentInterface = {\n url: `webrtc://${options.peerId}`,\n protocolBinding: A2A_PROTOCOL_BINDING,\n protocolVersion: A2A_PROTOCOL_VERSION,\n };\n\n const capabilities: AgentCapabilities = {\n streaming: options.streaming ?? true,\n pushNotifications: false, // WebRTC DataChannel handles real-time delivery\n };\n\n return {\n name: options.name,\n description: options.description ?? `AI assistant agent (${options.name})`,\n version: options.version ?? \"1.0.0\",\n supportedInterfaces: [iface],\n capabilities,\n defaultInputModes: [\"text/plain\", \"application/json\"],\n defaultOutputModes: [\"text/plain\", \"application/json\"],\n skills: options.skills ?? [],\n iconUrl: options.iconUrl,\n };\n}\n\n// =============================================================================\n// Agent Card Exchange Protocol\n// =============================================================================\n\n/**\n * Create a GetAgentCard JSON-RPC request.\n */\nexport function createGetAgentCardRequest(): A2AJsonRpcRequest {\n return {\n jsonrpc: \"2.0\",\n id: ulid(),\n method: A2A_METHOD.GET_AGENT_CARD,\n };\n}\n\n/**\n * Create a GetAgentCard JSON-RPC response with the local agent card.\n */\nexport function createGetAgentCardResponse(\n requestId: string,\n card: AgentCard,\n): A2AJsonRpcResponse {\n return {\n jsonrpc: \"2.0\",\n id: requestId,\n result: card,\n };\n}\n\n/**\n * Parse a GetAgentCard response to extract the remote agent card.\n * Returns null if the response is malformed.\n */\nexport function parseAgentCardResponse(\n response: A2AJsonRpcResponse,\n): AgentCard | null {\n if (response.error) {\n console.warn(\"GetAgentCard returned error:\", response.error);\n\n return null;\n }\n\n const result = response.result as Record<string, unknown> | undefined;\n if (!result || typeof result !== \"object\") {\n return null;\n }\n\n // Validate minimum required fields\n if (typeof result.name !== \"string\" || typeof result.version !== \"string\") {\n return null;\n }\n\n return result as unknown as AgentCard;\n}\n\n// =============================================================================\n// Peer Card Store (per-connection)\n// =============================================================================\n\n/**\n * Stores remote agent cards received from peers.\n * Keyed by remote peer ID.\n */\nexport class PeerCardStore {\n private _cards = new Map<string, AgentCard>();\n\n /** Clear all stored cards */\n clear(): void {\n this._cards.clear();\n }\n\n /** Remove a peer's card (on disconnect) */\n delete(peerId: string): void {\n this._cards.delete(peerId);\n }\n\n /** Get all stored cards */\n entries(): IterableIterator<[string, AgentCard]> {\n return this._cards.entries();\n }\n\n /** Retrieve a remote peer's agent card */\n get(peerId: string): AgentCard | undefined {\n return this._cards.get(peerId);\n }\n\n /** Get the display name for a peer (falls back to peer ID) */\n getDisplayName(peerId: string): string {\n const card = this._cards.get(peerId);\n\n return card?.name ?? peerId;\n }\n\n /** Check if we have a card for a peer */\n has(peerId: string): boolean {\n return this._cards.has(peerId);\n }\n\n /** Store a remote peer's agent card */\n set(peerId: string, card: AgentCard): void {\n this._cards.set(peerId, card);\n }\n\n /** Check if a peer supports streaming */\n supportsStreaming(peerId: string): boolean {\n const card = this._cards.get(peerId);\n\n return card?.capabilities?.streaming ?? false;\n }\n}\n","/**\n * A2A Task Lifecycle State Machine for WebRTC DataChannel Peer Protocol.\n *\n * Manages per-connection task state following the A2A v1.0 spec:\n * SUBMITTED → WORKING → COMPLETED | FAILED | CANCELED\n * → INPUT_REQUIRED → WORKING\n *\n * Emits AG-UI events during task execution for streaming visibility.\n *\n * References:\n * - A2A spec §4.1.1 (Task), §4.1.3 (TaskState)\n * - ADR: docs/decisions/peer-protocol-a2a-agui.md (Phase 4)\n */\n\nimport type {\n A2ATask,\n A2AMessage,\n TaskStatusUpdateEvent,\n TaskArtifactUpdateEvent,\n Artifact,\n AGUIEvent,\n AGUIRunStarted,\n AGUIRunFinished,\n AGUIRunError,\n AGUITextMessageStart,\n AGUITextMessageContent,\n AGUITextMessageEnd,\n AGUIToolCallStart,\n AGUIToolCallEnd,\n AGUIStateSnapshot,\n SendMessageRequest,\n SendMessageResponse,\n} from \"./peer-protocol.js\";\n\nimport {\n TaskState,\n Role,\n TERMINAL_STATES,\n INTERRUPTED_STATES,\n} from \"./peer-protocol.js\";\n\nimport { ulid } from \"../../utils/ulid.js\";\n\n// =============================================================================\n// Task Manager Configuration\n// =============================================================================\n\nexport interface TaskManagerConfig {\n /** Maximum number of tasks to retain in memory (LRU eviction) */\n maxTasks?: number;\n /** Maximum messages to retain in task history */\n maxHistoryPerTask?: number;\n}\n\nconst DEFAULT_CONFIG: Required<TaskManagerConfig> = {\n maxTasks: 100,\n maxHistoryPerTask: 50,\n};\n\n// =============================================================================\n// Event Emitter Types\n// =============================================================================\n\nexport type TaskEventType = \"statusUpdate\" | \"artifactUpdate\" | \"aguiEvent\";\n\nexport interface TaskEvent {\n type: TaskEventType;\n taskId: string;\n contextId: string;\n payload: TaskStatusUpdateEvent | TaskArtifactUpdateEvent | AGUIEvent;\n}\n\nexport type TaskEventListener = (event: TaskEvent) => void;\n\n// =============================================================================\n// Valid State Transitions\n// =============================================================================\n\n/**\n * Map of allowed transitions: from → Set of valid target states.\n * Based on A2A spec state diagram (§4.1.3).\n */\nconst VALID_TRANSITIONS = new Map<TaskState, Set<TaskState>>([\n [\n TaskState.SUBMITTED,\n new Set([\n TaskState.WORKING,\n TaskState.REJECTED,\n TaskState.CANCELED,\n TaskState.FAILED,\n ]),\n ],\n [\n TaskState.WORKING,\n new Set([\n TaskState.COMPLETED,\n TaskState.FAILED,\n TaskState.CANCELED,\n TaskState.INPUT_REQUIRED,\n TaskState.AUTH_REQUIRED,\n ]),\n ],\n [\n TaskState.INPUT_REQUIRED,\n new Set([TaskState.WORKING, TaskState.CANCELED, TaskState.FAILED]),\n ],\n [\n TaskState.AUTH_REQUIRED,\n new Set([TaskState.WORKING, TaskState.CANCELED, TaskState.FAILED]),\n ],\n]);\n\n// =============================================================================\n// PeerTaskManager\n// =============================================================================\n\n/**\n * Per-connection task lifecycle state machine.\n *\n * Responsibilities:\n * 1. Creates tasks when SendMessage is received without a taskId\n * 2. Transitions states following A2A state diagram\n * 3. Emits AG-UI events during task execution\n * 4. Stores task history (recent messages per task)\n * 5. Handles CancelTask requests gracefully\n */\nexport class PeerTaskManager {\n // LRU order (oldest first)\n private _config: Required<TaskManagerConfig>;\n /** Maps contextId → active (non-terminal) taskId */\n private _contextActiveTask = new Map<string, string>();\n private _listeners: Set<TaskEventListener> = new Set();\n private _taskOrder: string[] = [];\n private _tasks = new Map<string, A2ATask>();\n\n constructor(config?: TaskManagerConfig) {\n this._config = { ...DEFAULT_CONFIG, ...config };\n }\n\n /**\n * Add an artifact to a task.\n */\n addArtifact(taskId: string, artifact: Artifact, append = false): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n if (!task.artifacts) {\n task.artifacts = [];\n }\n\n if (append) {\n const existing = task.artifacts.find(\n (a) => a.artifactId === artifact.artifactId,\n );\n if (existing) {\n existing.parts.push(...artifact.parts);\n } else {\n task.artifacts.push(artifact);\n }\n } else {\n task.artifacts.push(artifact);\n }\n\n const event: TaskArtifactUpdateEvent = {\n taskId: task.id,\n contextId: task.contextId ?? \"\",\n artifact,\n append,\n lastChunk: false,\n };\n\n this._emit({\n type: \"artifactUpdate\",\n taskId: task.id,\n contextId: task.contextId ?? \"\",\n payload: event,\n });\n }\n\n /**\n * Cancel a task. Returns true if cancellation was accepted.\n */\n cancelTask(taskId: string): boolean {\n const task = this._tasks.get(taskId);\n if (!task) {\n return false;\n }\n\n if (TERMINAL_STATES.has(task.status.state)) {\n return false; // Already terminal, cannot cancel\n }\n\n this._transitionState(task, TaskState.CANCELED, {\n messageId: ulid(),\n role: Role.AGENT,\n parts: [{ text: \"Task canceled by peer request.\" }],\n });\n\n return true;\n }\n\n /** Clear all tasks and state */\n clear(): void {\n this._tasks.clear();\n this._taskOrder = [];\n this._contextActiveTask.clear();\n }\n\n /**\n * Emit a RUN_ERROR AG-UI event for a task.\n */\n emitRunError(taskId: string, message: string, code?: string): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUIRunError = {\n type: \"RUN_ERROR\",\n message,\n code,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n /**\n * Emit a RUN_FINISHED AG-UI event for a task.\n */\n emitRunFinished(taskId: string): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUIRunFinished = {\n type: \"RUN_FINISHED\",\n threadId: task.contextId ?? task.id,\n runId: task.id,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n // ---------------------------------------------------------------------------\n // AG-UI Event Emission Helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Emit a RUN_STARTED AG-UI event for a task.\n */\n emitRunStarted(taskId: string): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUIRunStarted = {\n type: \"RUN_STARTED\",\n threadId: task.contextId ?? task.id,\n runId: task.id,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n /**\n * Emit STATE_SNAPSHOT AG-UI event (shared ground truth).\n */\n emitStateSnapshot(taskId: string, snapshot: Record<string, unknown>): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUIStateSnapshot = {\n type: \"STATE_SNAPSHOT\",\n snapshot,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n /**\n * Emit TEXT_MESSAGE_CONTENT AG-UI event (streaming delta).\n */\n emitTextMessageContent(\n taskId: string,\n messageId: string,\n delta: string,\n ): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUITextMessageContent = {\n type: \"TEXT_MESSAGE_CONTENT\",\n messageId,\n delta,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n /**\n * Emit TEXT_MESSAGE_END AG-UI event.\n */\n emitTextMessageEnd(taskId: string, messageId: string): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUITextMessageEnd = {\n type: \"TEXT_MESSAGE_END\",\n messageId,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n /**\n * Emit TEXT_MESSAGE_START AG-UI event.\n */\n emitTextMessageStart(\n taskId: string,\n messageId: string,\n role: \"assistant\" | \"user\" = \"assistant\",\n ): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUITextMessageStart = {\n type: \"TEXT_MESSAGE_START\",\n messageId,\n role,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n /**\n * Emit TOOL_CALL_END AG-UI event.\n */\n emitToolCallEnd(taskId: string, toolCallId: string): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUIToolCallEnd = {\n type: \"TOOL_CALL_END\",\n toolCallId,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n /**\n * Emit TOOL_CALL_START AG-UI event.\n */\n emitToolCallStart(\n taskId: string,\n toolCallId: string,\n toolCallName: string,\n parentMessageId?: string,\n ): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUIToolCallStart = {\n type: \"TOOL_CALL_START\",\n toolCallId,\n toolCallName,\n parentMessageId,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n /** Get the active task for a context, if any */\n getActiveTaskForContext(contextId: string): A2ATask | undefined {\n const taskId = this._contextActiveTask.get(contextId);\n if (!taskId) {\n return undefined;\n }\n\n return this._tasks.get(taskId);\n }\n\n /** Get active (non-terminal) tasks */\n getActiveTasks(): A2ATask[] {\n return Array.from(this._tasks.values()).filter(\n (t) => !TERMINAL_STATES.has(t.status.state),\n );\n }\n\n // ---------------------------------------------------------------------------\n // Query\n // ---------------------------------------------------------------------------\n\n /** Get all tasks (for debugging/introspection) */\n getAllTasks(): A2ATask[] {\n return Array.from(this._tasks.values());\n }\n\n /**\n * Get a task by ID. Returns undefined if not found.\n */\n getTask(taskId: string): A2ATask | undefined {\n return this._tasks.get(taskId);\n }\n\n // ---------------------------------------------------------------------------\n // Task Lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Handle an incoming SendMessage request. Creates or continues a task.\n * Returns the task in its current state (for the JSON-RPC response).\n */\n handleSendMessage(request: SendMessageRequest): SendMessageResponse {\n const message = request.message;\n const contextId = message.contextId ?? ulid();\n const taskId = message.taskId ?? this._contextActiveTask.get(contextId);\n\n if (taskId && this._tasks.has(taskId)) {\n // Continue existing task\n\n return this._continueTask(taskId, message);\n }\n\n // Create new task\n\n return this._createTask(contextId, message);\n }\n\n /**\n * Transition a task to COMPLETED state with an optional final message.\n */\n markCompleted(taskId: string, message?: A2AMessage): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n this._transitionState(task, TaskState.COMPLETED, message);\n }\n\n /**\n * Transition a task to FAILED state with an error message.\n */\n markFailed(taskId: string, errorMessage: string): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n this._transitionState(task, TaskState.FAILED, {\n messageId: ulid(),\n role: Role.AGENT,\n parts: [{ text: errorMessage }],\n });\n }\n\n /**\n * Transition a task to INPUT_REQUIRED state.\n */\n markInputRequired(taskId: string, message?: A2AMessage): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n this._transitionState(task, TaskState.INPUT_REQUIRED, message);\n }\n\n /**\n * Transition a task to WORKING state. Called when the local agent\n * starts processing the task.\n */\n markWorking(taskId: string): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n this._transitionState(task, TaskState.WORKING);\n }\n\n /** Unsubscribe from task events */\n off(listener: TaskEventListener): void {\n this._listeners.delete(listener);\n }\n\n // ---------------------------------------------------------------------------\n // Event Subscription\n // ---------------------------------------------------------------------------\n\n /** Subscribe to task events */\n on(listener: TaskEventListener): void {\n this._listeners.add(listener);\n }\n\n private _addTask(task: A2ATask): void {\n this._tasks.set(task.id, task);\n this._taskOrder.push(task.id);\n\n // Evict oldest tasks if over limit\n while (this._taskOrder.length > this._config.maxTasks) {\n const oldestId = this._taskOrder.shift()!;\n const oldest = this._tasks.get(oldestId);\n // Only evict terminal tasks; keep active ones\n if (oldest && TERMINAL_STATES.has(oldest.status.state)) {\n this._tasks.delete(oldestId);\n if (oldest.contextId) {\n this._contextActiveTask.delete(oldest.contextId);\n }\n } else {\n // Put it back at the front — we'll try the next one\n this._taskOrder.unshift(oldestId);\n\n break;\n }\n }\n }\n\n private _continueTask(\n taskId: string,\n message: A2AMessage,\n ): SendMessageResponse {\n const task = this._tasks.get(taskId)!;\n\n // If the task was in an interrupted state, transition back to WORKING\n if (INTERRUPTED_STATES.has(task.status.state)) {\n this._transitionState(task, TaskState.WORKING);\n }\n\n // Add to history\n if (!task.history) {\n task.history = [];\n }\n\n task.history.push(message);\n\n // Trim history if needed\n if (task.history.length > this._config.maxHistoryPerTask) {\n task.history = task.history.slice(-this._config.maxHistoryPerTask);\n }\n\n // Touch LRU\n this._touchTask(taskId);\n\n return { task };\n }\n\n // ---------------------------------------------------------------------------\n // Internal\n // ---------------------------------------------------------------------------\n\n private _createTask(\n contextId: string,\n message: A2AMessage,\n ): SendMessageResponse {\n const taskId = ulid();\n\n const task: A2ATask = {\n id: taskId,\n contextId,\n status: {\n state: TaskState.SUBMITTED,\n timestamp: new Date().toISOString(),\n },\n history: [message],\n };\n\n this._addTask(task);\n this._contextActiveTask.set(contextId, taskId);\n\n // Emit status update\n this._emitStatusUpdate(task);\n\n return { task };\n }\n\n private _emit(event: TaskEvent): void {\n for (const listener of this._listeners) {\n try {\n listener(event);\n } catch (err) {\n console.error(\"PeerTaskManager: listener error\", err);\n }\n }\n }\n\n private _emitAGUI(task: A2ATask, event: AGUIEvent): void {\n this._emit({\n type: \"aguiEvent\",\n taskId: task.id,\n contextId: task.contextId ?? \"\",\n payload: event,\n });\n }\n\n private _emitStatusUpdate(task: A2ATask): void {\n const event: TaskStatusUpdateEvent = {\n taskId: task.id,\n contextId: task.contextId ?? \"\",\n status: task.status,\n };\n\n this._emit({\n type: \"statusUpdate\",\n taskId: task.id,\n contextId: task.contextId ?? \"\",\n payload: event,\n });\n }\n\n private _touchTask(taskId: string): void {\n const idx = this._taskOrder.indexOf(taskId);\n if (idx !== -1) {\n this._taskOrder.splice(idx, 1);\n this._taskOrder.push(taskId);\n }\n }\n\n private _transitionState(\n task: A2ATask,\n newState: TaskState,\n message?: A2AMessage,\n ): void {\n const currentState = task.status.state;\n\n // Validate transition\n const allowed = VALID_TRANSITIONS.get(currentState);\n if (allowed && !allowed.has(newState)) {\n console.warn(\n `PeerTaskManager: invalid transition ${currentState} → ${newState} for task ${task.id}`,\n );\n\n return;\n }\n\n // Cannot transition from terminal states\n if (TERMINAL_STATES.has(currentState)) {\n console.warn(\n `PeerTaskManager: task ${task.id} is in terminal state ${currentState}, cannot transition`,\n );\n\n return;\n }\n\n task.status = {\n state: newState,\n message,\n timestamp: new Date().toISOString(),\n };\n\n // If transitioning to a terminal state, remove from active context map\n if (TERMINAL_STATES.has(newState) && task.contextId) {\n if (this._contextActiveTask.get(task.contextId) === task.id) {\n this._contextActiveTask.delete(task.contextId);\n }\n }\n\n this._emitStatusUpdate(task);\n }\n}\n","import { Signal } from \"signal-polyfill\";\n\nimport {\n PEERJS_DEFAULT_HOST,\n PEERJS_DEFAULT_PATH,\n PEERJS_DEFAULT_PORT,\n PEERJS_DEFAULT_SECURE,\n} from \"../../config/config.js\";\n\nimport { getDb } from \"../../db/db.js\";\nimport { groupFileExists } from \"../../storage/groupFileExists.js\";\nimport { readGroupFileBytes } from \"../../storage/readGroupFileBytes.js\";\nimport { writeGroupFileBytes } from \"../../storage/writeGroupFileBytes.js\";\nimport { ulid } from \"../../utils/ulid.js\";\n\nimport type { DataConnection, Peer, PeerError } from \"peerjs\";\nimport type { MessageAttachment } from \"../../content/types.js\";\nimport type { A2UIAction, A2UIEnvelope } from \"../../ui/a2ui/types.js\";\nimport type {\n Channel,\n ChannelMessageCallback,\n ChannelTypingCallback,\n RoomMeta,\n} from \"./types.js\";\n\n// A2A Protocol imports\nimport {\n PeerCardStore,\n buildAgentCard,\n createGetAgentCardRequest,\n createGetAgentCardResponse,\n parseAgentCardResponse,\n} from \"./peer-agent-card.js\";\n\nimport {\n A2A_ERROR_CODE,\n A2A_METHOD,\n A2A_STREAM_METHOD,\n AGUI_METHOD,\n Role,\n TERMINAL_STATES,\n isJsonRpcRequest,\n isJsonRpcResponse,\n} from \"./peer-protocol.js\";\n\nimport { PeerTaskManager } from \"./peer-task-manager.js\";\n\nimport type {\n A2AJsonRpcNotification,\n A2AJsonRpcRequest,\n A2AJsonRpcResponse,\n AGUIEvent,\n AgentCard,\n SendMessageRequest,\n TaskStatusUpdateEvent,\n} from \"./peer-protocol.js\";\n\n/**\n * Module-level singleton so the chat UI can import and subscribe to it\n * directly without going through the non-reactive orchestratorStore.orchestrator chain.\n */\nexport const transferProgressSignal = new Signal.State<{\n count: number;\n total: number;\n direction: \"send\" | \"receive\";\n} | null>(null);\n\nlet transferProgressClearTimeout: ReturnType<typeof setTimeout> | null = null;\n\n/**\n * Update transfer progress signal and cancel any pending delayed clear timer.\n */\nexport function updateTransferProgress(\n progress: {\n count: number;\n total: number;\n direction: \"send\" | \"receive\";\n } | null,\n): void {\n if (transferProgressClearTimeout !== null) {\n clearTimeout(transferProgressClearTimeout);\n transferProgressClearTimeout = null;\n }\n transferProgressSignal.set(progress);\n}\n\n/**\n * Clear transfer progress after a delay, ensuring any existing timer is reset.\n */\nexport function clearTransferProgressDelayed(delayMs = 1500): void {\n if (transferProgressClearTimeout !== null) {\n clearTimeout(transferProgressClearTimeout);\n }\n transferProgressClearTimeout = setTimeout(() => {\n transferProgressSignal.set(null);\n transferProgressClearTimeout = null;\n }, delayMs);\n}\n\n/** Maximum chunk size in bytes for application-level file transfers (15 KB to stay safely under PeerJS 16,300 MTU after msgpack framing) */\nexport const FILE_CHUNK_SIZE = 15360;\n\n/** Threshold for WebRTC DataChannel bufferedAmount backpressure (64 KB) */\nexport const FILE_BUFFER_DRAIN_THRESHOLD = 65536;\n\ninterface InboundFileTransfer {\n transferId: string;\n name: string;\n mimeType: string;\n size: number;\n totalChunks: number;\n receivedChunks: Map<number, Uint8Array>;\n receivedBytes: number;\n targetGroupId?: string;\n}\n\nexport interface PeerJsServerConfig {\n host?: string;\n port?: number;\n path?: string;\n secure?: boolean;\n iceServers?: RTCIceServer[];\n}\n\n/**\n * A PeerJS-based WebRTC data-channel messaging channel.\n *\n * - Prefix: `peer:`\n * - groupId format: `peer:<remote-peer-id>`\n * - Uses the public PeerJS cloud signaling server by default (no self-hosted\n * server required). A custom signaling server can be passed via serverConfig.\n * - Trusted peer IDs: when non-empty, only accepts connections from listed IDs.\n * When empty, accepts connections from any peer.\n */\nexport class PeerJsChannel implements Channel {\n private static readonly _RECONNECT_BASE_MS = 1000;\n private static readonly _RECONNECT_MAX_MS = 60_000;\n\n /** Signal of connected remote peer IDs */\n connectedPeersSignal = new Signal.State<string[]>([]);\n\n /** Active data connections keyed by remote peer ID */\n connections: Map<string, DataConnection> = new Map();\n messageCallback: ChannelMessageCallback | null = null;\n\n myPeerId: string = \"\";\n\n // A2A Protocol state\n /** Remote agent cards keyed by peer ID */\n readonly peerCards = new PeerCardStore();\n\n running = false;\n serverConfig: PeerJsServerConfig = {};\n\n /** Delegate to the module-level singleton for reactivity across components */\n readonly transferProgressSignal = transferProgressSignal;\n trustedPeerIds: Set<string> = new Set();\n type: Channel[\"type\"] = \"peerjs\";\n typingCallback: ChannelTypingCallback | null = null;\n\n /** Maps inbound original canonical filenames to their locally renamed final filenames */\n private _inboundRemap = new Map<string, string>();\n /** Local agent card (constructed on start) */\n private _localCard: AgentCard | null = null;\n\n /** Callback invoked when a remote peer signals task completion */\n private _onTaskCompleteCallback: ((groupId: string) => void) | null = null;\n\n private peer: InstanceType<typeof Peer> | null = null;\n\n private _pendingInboundFile: {\n name: string;\n mimeType: string;\n size: number;\n } | null = null;\n /** Pending JSON-RPC response callbacks keyed by request ID */\n private _pendingRequests = new Map<\n string,\n {\n resolve: (resp: A2AJsonRpcResponse) => void;\n timer: ReturnType<typeof setTimeout>;\n }\n >();\n\n // Reconnection backoff state\n private _reconnectAttempts = 0;\n private _reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\n /** Handler for inbound multi-party room notifications (`room/*`). */\n private _roomNotificationHandler:\n | ((fromPeerId: string, method: string, params: unknown) => void)\n | null = null;\n /** Per-connection task managers keyed by remote peer ID */\n private _taskManagers = new Map<string, PeerTaskManager>();\n /** Inbound multi-chunk file transfers keyed by transferId */\n private _inboundTransfers = new Map<string, InboundFileTransfer>();\n\n constructor() {\n if (typeof globalThis.addEventListener === \"function\") {\n globalThis.addEventListener(\"peerjs-dc-handle-chunk\", (e: any) => {\n if (e?.detail?.chunkInfo) {\n // If an application-level multi-chunk file transfer is in progress,\n // ignore underlying PeerJS binarypack frame chunks to prevent fighting/flickering.\n if (this._inboundTransfers.size > 0) {\n return;\n }\n\n // PeerJS dispatches `count` BEFORE incrementing it (0-indexed pre-increment),\n // so the actual number of received chunks is count + 1.\n const { count: rawCount, total } = e.detail.chunkInfo;\n const received = rawCount + 1;\n updateTransferProgress({\n count: received,\n total,\n direction: \"receive\",\n });\n\n if (received >= total) {\n clearTransferProgressDelayed(1500);\n }\n }\n });\n }\n }\n\n /**\n * Mark the active task for a peer groupId as COMPLETED.\n * Sends a terminal `tasks/statusUpdate` notification to the remote peer,\n * signaling that no further responses are expected.\n *\n * @returns true if a task was completed, false if no active task exists.\n */\n completeActiveTask(groupId: string): boolean {\n const remotePeerId = groupId.replace(/^peer:/, \"\");\n const tm = this._taskManagers.get(remotePeerId);\n if (!tm) {\n return false;\n }\n\n const activeTasks = tm.getActiveTasks();\n if (activeTasks.length === 0) {\n return false;\n }\n\n // Complete the most recent active task\n const task = activeTasks[activeTasks.length - 1];\n tm.markWorking(task.id);\n tm.markCompleted(task.id);\n\n return true;\n }\n\n // ---------------------------------------------------------------------------\n // Public API\n // ---------------------------------------------------------------------------\n\n configure(\n myPeerId: string,\n trustedPeerIds: string[],\n serverConfig: PeerJsServerConfig = {},\n ): void {\n this.myPeerId = myPeerId.trim();\n this.trustedPeerIds = new Set(\n trustedPeerIds.map((id) => id.trim()).filter(Boolean),\n );\n this.serverConfig = serverConfig;\n }\n\n /** Best-effort: ensure an outbound connection to the peer is opened. */\n connectPeer(peerId: string): void {\n this._getOrOpenConnection(peerId);\n }\n\n /**\n * Get the task manager for a peer (creates one if needed).\n */\n getTaskManager(remotePeerId: string): PeerTaskManager {\n let tm = this._taskManagers.get(remotePeerId);\n if (!tm) {\n tm = new PeerTaskManager();\n this._taskManagers.set(remotePeerId, tm);\n tm.on((event) => {\n this._forwardTaskEvent(remotePeerId, event);\n });\n }\n\n return tm;\n }\n\n isConfigured(): boolean {\n return this.myPeerId.length > 0;\n }\n\n /** Whether a direct, open DataConnection to the peer currently exists. */\n isPeerConnected(peerId: string): boolean {\n const conn = this.connections.get(peerId);\n\n return !!conn && !!(conn as any).open;\n }\n\n onMessage(callback: ChannelMessageCallback): void {\n this.messageCallback = callback;\n }\n\n /**\n * Register a callback invoked when a remote peer sends a terminal\n * task status update (COMPLETED, FAILED, CANCELED). This allows the\n * orchestrator to suppress further auto-triggers for that conversation.\n */\n onTaskComplete(callback: (groupId: string) => void): void {\n this._onTaskCompleteCallback = callback;\n }\n\n onTyping(callback: ChannelTypingCallback): void {\n this.typingCallback = callback;\n }\n\n /**\n * Send a JSON-RPC notification object to a single peer. If the connection is\n * still opening, the send is deferred until it opens. Returns true when the\n * send was dispatched or queued, false when no connection could be created.\n */\n sendRoomNotification(peerId: string, notification: unknown): boolean {\n const conn = this._getOrOpenConnection(peerId);\n if (!conn) {\n return false;\n }\n\n if ((conn as any).open) {\n try {\n conn.send(notification);\n\n return true;\n } catch (err) {\n console.error(\n `PeerJsChannel: failed to send room notification to ${peerId}:`,\n err,\n );\n\n return false;\n }\n }\n\n // Connection still opening — flush once it is ready.\n this._waitForOpen(conn)\n .then(() => {\n try {\n conn.send(notification);\n } catch (err) {\n console.error(\n `PeerJsChannel: failed to flush room notification to ${peerId}:`,\n err,\n );\n }\n })\n .catch(() => {\n // Connection failed to open; nothing more to do.\n });\n\n return true;\n }\n\n // ---------------------------------------------------------------------------\n // Multi-party room transport\n // ---------------------------------------------------------------------------\n\n /**\n * Register the handler for inbound `room/*` JSON-RPC notifications. The\n * {@link RoomManager} uses this to receive join/roster/leave/message/invite/\n * relay traffic carried over the existing DataChannel.\n */\n setRoomNotificationHandler(\n handler: (fromPeerId: string, method: string, params: unknown) => void,\n ): void {\n this._roomNotificationHandler = handler;\n }\n\n /**\n * Stream file attachments to all other members in a room over WebRTC DataConnections,\n * tagged with the room groupId.\n */\n async sendAttachmentsToRoom(\n room: RoomMeta,\n groupId: string,\n attachments: MessageAttachment[],\n ): Promise<void> {\n const me = this.myPeerId;\n const fileAttachments = (attachments || []).filter(\n (a): a is MessageAttachment & { path: string } => !!a.path,\n );\n if (fileAttachments.length === 0) {\n return;\n }\n\n try {\n const db = await getDb();\n for (const att of fileAttachments) {\n let bytes: Uint8Array;\n try {\n bytes = await readGroupFileBytes(db, groupId, att.path);\n } catch (err) {\n console.warn(\n `PeerJsChannel: failed to read file ${att.path} for room:`,\n err,\n );\n continue;\n }\n\n const canonicalName = att.path;\n const mimeType = att.mimeType || \"application/octet-stream\";\n const totalChunks = Math.max(\n 1,\n Math.ceil(bytes.length / FILE_CHUNK_SIZE),\n );\n\n for (const member of room.members) {\n if (member.peerId === me) {\n continue;\n }\n\n const conn = this._getOrOpenConnection(member.peerId);\n if (!conn) {\n continue;\n }\n\n try {\n await this._waitForOpen(conn);\n const transferId = ulid();\n\n conn.send({\n type: \"__file_header\",\n id: transferId,\n name: canonicalName,\n mimeType,\n size: bytes.length,\n totalChunks,\n chunkSize: FILE_CHUNK_SIZE,\n groupId,\n });\n\n for (let i = 0; i < totalChunks; i++) {\n const start = i * FILE_CHUNK_SIZE;\n const end = Math.min(start + FILE_CHUNK_SIZE, bytes.length);\n const chunk = bytes.subarray(start, end);\n const chunkBuf = chunk.buffer.slice(\n chunk.byteOffset,\n chunk.byteOffset + chunk.byteLength,\n );\n\n conn.send({\n type: \"__file_chunk\",\n id: transferId,\n name: canonicalName,\n index: i,\n totalChunks,\n data: chunkBuf,\n });\n\n updateTransferProgress({\n count: i + 1,\n total: totalChunks,\n direction: \"send\",\n });\n\n await this._waitForBufferDrain(conn);\n }\n\n clearTransferProgressDelayed(1500);\n } catch (err) {\n console.warn(\n `PeerJsChannel: failed to stream file ${att.path} to room member ${member.peerId}:`,\n err,\n );\n }\n }\n }\n } catch (err) {\n console.error(\n \"PeerJsChannel: failed to access DB for room file transfer\",\n err,\n );\n }\n }\n\n setTyping(groupId: string, typing: boolean): void {\n const remotePeerId = groupId.replace(/^peer:/, \"\");\n const conn = this.connections.get(remotePeerId);\n if (!conn) {\n return;\n }\n\n try {\n conn.send({ type: \"typing\", typing });\n } catch {\n // silently ignore typing send errors\n }\n }\n\n start(): void {\n if (!this.isConfigured() || this.running) {\n return;\n }\n\n this.running = true;\n this._localCard = buildAgentCard({\n peerId: this.myPeerId,\n name: this.myPeerId,\n description: \"ShadowClaw AI assistant\",\n streaming: true,\n });\n this._initPeer();\n }\n\n ensureConnected(force: boolean = false): void {\n if (!this.running || !this.isConfigured()) {\n return;\n }\n\n if (this._reconnectTimer !== null) {\n clearTimeout(this._reconnectTimer);\n this._reconnectTimer = null;\n }\n this._reconnectAttempts = 0;\n\n const peer = this.peer as any;\n if (!peer || peer.destroyed || (force && !peer.open)) {\n if (peer && !peer.destroyed) {\n try {\n peer.destroy();\n } catch (_) {}\n }\n this.peer = null;\n this._initPeer();\n } else if (peer.disconnected) {\n try {\n peer.reconnect?.();\n } catch {\n this._initPeer();\n }\n }\n }\n\n stop(): void {\n this.running = false;\n if (this._reconnectTimer !== null) {\n clearTimeout(this._reconnectTimer);\n this._reconnectTimer = null;\n }\n\n this._reconnectAttempts = 0;\n this.connections.forEach((conn) => {\n try {\n conn.close();\n } catch {\n // ignore\n }\n });\n this.connections.clear();\n this.peerCards.clear();\n this._taskManagers.clear();\n this._pendingRequests.forEach(({ timer }) => clearTimeout(timer));\n this._pendingRequests.clear();\n this._updateConnectedPeersSignal();\n\n if (this.peer) {\n try {\n this.peer.destroy();\n } catch {\n // ignore\n }\n\n this.peer = null;\n }\n }\n\n async send(\n groupId: string,\n text: string,\n attachments?: MessageAttachment[],\n ): Promise<void> {\n const remotePeerId = groupId.replace(/^peer:/, \"\");\n const conn = this._getOrOpenConnection(remotePeerId);\n\n if (!conn) {\n console.warn(\n `PeerJsChannel: no connection available for ${remotePeerId}`,\n );\n\n return;\n }\n\n try {\n // Wait for connection to be open if it just was created\n await this._waitForOpen(conn);\n\n // Extract markdown local links from the outgoing text\n const { attachments: markdownAttachments } =\n extractMarkdownAttachments(text);\n\n const allAttachments: { path: string; mimeType?: string }[] = [\n ...(attachments || []).filter(\n (a): a is MessageAttachment & { path: string } => !!a.path,\n ),\n ...markdownAttachments.map((ma) => ({\n path: ma.path,\n mimeType: \"application/octet-stream\",\n })),\n ];\n\n // Build a map of oldPath -> canonical hash-prefixed basename.\n // The sender is responsible for computing the canonical name so both\n // sides end up with the same filename in their workspaces.\n const pathRemap = new Map<string, string>();\n const fileParts: any[] = [];\n\n try {\n const db = await getDb();\n for (const att of allAttachments) {\n if (!att.path) {\n continue;\n }\n\n try {\n const bytes = await readGroupFileBytes(db, groupId, att.path);\n const canonicalName = att.path;\n\n if (!pathRemap.has(att.path)) {\n pathRemap.set(att.path, canonicalName);\n }\n\n const mimeType =\n (att as any).mimeType || \"application/octet-stream\";\n\n const transferId = ulid();\n const totalChunks = Math.max(\n 1,\n Math.ceil(bytes.length / FILE_CHUNK_SIZE),\n );\n\n // Send the header\n conn.send({\n type: \"__file_header\",\n id: transferId,\n name: canonicalName,\n mimeType,\n size: bytes.length,\n totalChunks,\n chunkSize: FILE_CHUNK_SIZE,\n groupId,\n });\n\n // Send each chunk frame sequentially with flow control\n for (let i = 0; i < totalChunks; i++) {\n const start = i * FILE_CHUNK_SIZE;\n const end = Math.min(start + FILE_CHUNK_SIZE, bytes.length);\n const chunk = bytes.subarray(start, end);\n\n // Copy into a clean ArrayBuffer slice for transfer\n const chunkBuf = chunk.buffer.slice(\n chunk.byteOffset,\n chunk.byteOffset + chunk.byteLength,\n );\n\n conn.send({\n type: \"__file_chunk\",\n id: transferId,\n name: canonicalName,\n index: i,\n totalChunks,\n data: chunkBuf,\n });\n\n updateTransferProgress({\n count: i + 1,\n total: totalChunks,\n direction: \"send\",\n });\n\n // Apply backpressure if the DataChannel buffer is filling up\n await this._waitForBufferDrain(conn);\n }\n\n clearTransferProgressDelayed(1500);\n\n // Prepare the metadata part for the A2A envelope\n fileParts.push({\n kind: \"file\",\n name: canonicalName,\n mimeType,\n size: bytes.length,\n });\n } catch (err) {\n console.warn(\n `PeerJsChannel: failed to process file ${att.path}:`,\n err,\n );\n }\n }\n } catch (err) {\n console.error(\"PeerJsChannel: failed to access DB\", err);\n }\n\n // Rewrite the outgoing text so links point to the canonical names\n let outText = text;\n for (const [oldPath, canonicalName] of pathRemap) {\n const escapedOld = oldPath.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n outText = outText.replace(\n new RegExp(`(!?\\\\[.*?\\\\])\\\\(${escapedOld}\\\\)`, \"g\"),\n `$1(${canonicalName})`,\n );\n }\n\n // File parts go first so the receiver processes them before text\n const parts = [...fileParts, { kind: \"text\", text: outText }];\n\n // Use A2A SendMessage (JSON-RPC request with id) so the remote peer's\n // task manager tracks the conversation lifecycle and can signal completion.\n const requestId = ulid();\n const envelope: A2AJsonRpcRequest = {\n jsonrpc: \"2.0\",\n id: requestId,\n method: A2A_METHOD.SEND_MESSAGE,\n params: {\n message: {\n messageId: ulid(),\n role: Role.AGENT,\n parts,\n },\n } satisfies SendMessageRequest,\n };\n\n conn.send(envelope);\n\n // Register pending request so we can process the task response\n this._registerPendingRequest(requestId, (_response) => {\n // Response contains the task state — no action needed here,\n // the remote peer's task manager handles lifecycle.\n });\n } catch (err) {\n console.error(`PeerJsChannel: send failed for ${remotePeerId}:`, err);\n window.dispatchEvent(\n new CustomEvent(\"shadow-claw-peer-error\", {\n detail: {\n remotePeerId,\n error: err instanceof Error ? err.message : String(err),\n },\n }),\n );\n }\n }\n\n /**\n * Send an A2UI surface envelope to a peer as a `kind: \"a2ui\"` A2A part.\n */\n async sendA2UI(groupId: string, envelope: A2UIEnvelope): Promise<void> {\n const remotePeerId = groupId.replace(/^peer:/, \"\");\n const conn = this._getOrOpenConnection(remotePeerId);\n\n if (!conn) {\n console.warn(\n `PeerJsChannel.sendA2UI: no connection available for ${remotePeerId}`,\n );\n\n return;\n }\n\n try {\n await this._waitForOpen(conn);\n\n const a2uiEnvelopeObj = {\n jsonrpc: \"2.0\",\n method: \"message/send\",\n id: ulid(),\n params: {\n message: {\n role: \"agent\",\n parts: [{ kind: \"a2ui\", envelope }],\n },\n },\n };\n conn.send(a2uiEnvelopeObj);\n } catch (err) {\n console.error(`PeerJsChannel.sendA2UI: failed for ${remotePeerId}:`, err);\n }\n }\n\n /**\n * Send an A2UI action back to the peer (fired when the local user interacts\n * with a rendered surface — e.g. clicks a Button).\n */\n async sendA2UIAction(groupId: string, action: A2UIAction): Promise<void> {\n const remotePeerId = groupId.replace(/^peer:/, \"\");\n const conn = this._getOrOpenConnection(remotePeerId);\n\n if (!conn) {\n console.warn(\n `PeerJsChannel.sendA2UIAction: no connection available for ${remotePeerId}`,\n );\n\n return;\n }\n\n try {\n await this._waitForOpen(conn);\n\n const actionEnvelope = {\n jsonrpc: \"2.0\",\n method: \"message/send\",\n id: ulid(),\n params: {\n message: {\n role: \"user\",\n parts: [{ kind: \"a2ui-action\", action }],\n },\n },\n };\n conn.send(actionEnvelope);\n } catch (err) {\n console.error(\n `PeerJsChannel.sendA2UIAction: failed for ${remotePeerId}:`,\n err,\n );\n }\n }\n\n // ---------------------------------------------------------------------------\n // A2A Protocol Handlers\n // ---------------------------------------------------------------------------\n\n /**\n * Exchange agent cards on connection open.\n * Sends our card request and stores the remote peer's card.\n */\n private _exchangeAgentCards(\n remotePeerId: string,\n conn: DataConnection,\n ): void {\n if (!this._localCard) {\n return;\n }\n\n const request = createGetAgentCardRequest();\n conn.send(request);\n\n // Register pending request for the response\n this._registerPendingRequest(request.id, (response) => {\n const card = parseAgentCardResponse(response);\n if (card) {\n this.peerCards.set(remotePeerId, card);\n console.log(\n `PeerJsChannel: received AgentCard from ${remotePeerId}: \"${card.name}\"`,\n );\n }\n });\n }\n\n /**\n * Forward task manager events over the DataChannel as notifications.\n */\n private _forwardTaskEvent(\n remotePeerId: string,\n event: {\n type: string;\n taskId: string;\n contextId: string;\n payload: unknown;\n },\n ): void {\n const conn = this.connections.get(remotePeerId);\n if (!conn) {\n return;\n }\n\n let method: string;\n switch (event.type) {\n case \"statusUpdate\":\n method = A2A_STREAM_METHOD.STATUS_UPDATE;\n\n break;\n case \"artifactUpdate\":\n method = A2A_STREAM_METHOD.ARTIFACT_UPDATE;\n\n break;\n case \"aguiEvent\":\n method = AGUI_METHOD.EVENT;\n\n break;\n default:\n return;\n }\n\n const notification: A2AJsonRpcNotification = {\n jsonrpc: \"2.0\",\n method,\n params: event.payload,\n };\n\n try {\n conn.send(notification);\n } catch (err) {\n console.error(\n `PeerJsChannel: failed to forward ${event.type} to ${remotePeerId}:`,\n err,\n );\n }\n }\n\n /**\n * Returns an existing open DataConnection for the given remote peer ID,\n * or initiates a new outbound connection.\n */\n private _getOrOpenConnection(remotePeerId: string): DataConnection | null {\n const existing = this.connections.get(remotePeerId);\n if (existing) {\n return existing;\n }\n\n if (!this.peer) {\n return null;\n }\n\n try {\n const conn = this.peer.connect(remotePeerId, {\n reliable: true,\n serialization: \"binary\",\n });\n\n // PeerJS returns undefined if the peer is disconnected/destroyed\n if (!conn) {\n return null;\n }\n\n this._handleIncomingConnection(conn);\n\n return conn;\n } catch (err) {\n console.error(\n `PeerJsChannel: failed to connect to ${remotePeerId}:`,\n err,\n );\n\n return null;\n }\n }\n\n /**\n * Handle A2A CancelTask request.\n */\n private _handleA2ACancelTask(\n remotePeerId: string,\n request: A2AJsonRpcRequest,\n ): void {\n const params = request.params as { taskId?: string } | undefined;\n if (!params?.taskId) {\n this._sendJsonRpcError(remotePeerId, request.id, {\n code: A2A_ERROR_CODE.INVALID_PARAMS,\n message: \"Missing taskId in CancelTask params\",\n });\n\n return;\n }\n\n const taskManager = this._taskManagers.get(remotePeerId);\n if (!taskManager) {\n this._sendJsonRpcError(remotePeerId, request.id, {\n code: A2A_ERROR_CODE.TASK_NOT_FOUND,\n message: `Task not found: ${params.taskId}`,\n });\n\n return;\n }\n\n const success = taskManager.cancelTask(params.taskId);\n if (!success) {\n this._sendJsonRpcError(remotePeerId, request.id, {\n code: A2A_ERROR_CODE.TASK_NOT_CANCELABLE,\n message: `Task not cancelable: ${params.taskId}`,\n });\n\n return;\n }\n\n const conn = this.connections.get(remotePeerId);\n if (conn) {\n const task = taskManager.getTask(params.taskId);\n const rpcResponse: A2AJsonRpcResponse = {\n jsonrpc: \"2.0\",\n id: request.id,\n result: { task },\n };\n conn.send(rpcResponse);\n }\n }\n\n /**\n * Handle A2A GetTask request.\n */\n private _handleA2AGetTask(\n remotePeerId: string,\n request: A2AJsonRpcRequest,\n ): void {\n const params = request.params as { taskId?: string } | undefined;\n if (!params?.taskId) {\n this._sendJsonRpcError(remotePeerId, request.id, {\n code: A2A_ERROR_CODE.INVALID_PARAMS,\n message: \"Missing taskId in GetTask params\",\n });\n\n return;\n }\n\n const taskManager = this._taskManagers.get(remotePeerId);\n const task = taskManager?.getTask(params.taskId);\n if (!task) {\n this._sendJsonRpcError(remotePeerId, request.id, {\n code: A2A_ERROR_CODE.TASK_NOT_FOUND,\n message: `Task not found: ${params.taskId}`,\n });\n\n return;\n }\n\n const conn = this.connections.get(remotePeerId);\n if (conn) {\n const rpcResponse: A2AJsonRpcResponse = {\n jsonrpc: \"2.0\",\n id: request.id,\n result: { task },\n };\n conn.send(rpcResponse);\n }\n }\n\n /**\n * Dispatch an inbound JSON-RPC 2.0 message (request, response, or notification).\n */\n private _handleA2AJsonRpc(\n remotePeerId: string,\n msg: Record<string, unknown>,\n ): void {\n // Response to a pending request (e.g., GetAgentCard response)\n if (isJsonRpcResponse(msg)) {\n const pending = this._pendingRequests.get(msg.id);\n if (pending) {\n clearTimeout(pending.timer);\n this._pendingRequests.delete(msg.id);\n pending.resolve(msg as A2AJsonRpcResponse);\n }\n\n return;\n }\n\n const method = msg.method as string | undefined;\n if (!method) {\n return;\n }\n\n // Multi-party room notifications (`room/*`) — forward to the RoomManager.\n if (method.startsWith(\"room/\")) {\n this._roomNotificationHandler?.(remotePeerId, method, msg.params);\n\n return;\n }\n\n // JSON-RPC Request (has id — expects a response)\n if (isJsonRpcRequest(msg)) {\n switch (method) {\n case A2A_METHOD.GET_AGENT_CARD:\n this._handleGetAgentCard(remotePeerId, msg as A2AJsonRpcRequest);\n\n break;\n case A2A_METHOD.SEND_MESSAGE:\n this._handleA2ASendMessage(remotePeerId, msg as A2AJsonRpcRequest);\n\n break;\n case A2A_METHOD.CANCEL_TASK:\n this._handleA2ACancelTask(remotePeerId, msg as A2AJsonRpcRequest);\n\n break;\n case A2A_METHOD.GET_TASK:\n this._handleA2AGetTask(remotePeerId, msg as A2AJsonRpcRequest);\n\n break;\n default:\n // Legacy \"message/send\" (existing format) — process as before\n if (method === \"message/send\") {\n const params = msg.params as any;\n if (params?.message?.parts && Array.isArray(params.message.parts)) {\n this._processInboundA2AEnvelope(\n remotePeerId,\n params.message.parts,\n ).catch((err) =>\n console.error(\n \"PeerJsChannel: failed to process inbound A2A envelope\",\n err,\n ),\n );\n }\n } else {\n this._sendJsonRpcError(remotePeerId, msg.id as string, {\n code: A2A_ERROR_CODE.METHOD_NOT_FOUND,\n message: `Method not found: ${method}`,\n });\n }\n }\n\n return;\n }\n\n // JSON-RPC Notification (no id — no response expected)\n switch (method) {\n case AGUI_METHOD.EVENT:\n this._handleAGUIEventNotification(remotePeerId, msg.params);\n\n break;\n case A2A_STREAM_METHOD.STATUS_UPDATE:\n this._handleTaskStatusNotification(remotePeerId, msg.params);\n\n break;\n case A2A_STREAM_METHOD.ARTIFACT_UPDATE:\n // Future: handle artifact streaming notifications\n\n break;\n case \"message/send\":\n // Legacy notification format (no id)\n {\n const params = msg.params as any;\n if (params?.message?.parts && Array.isArray(params.message.parts)) {\n this._processInboundA2AEnvelope(\n remotePeerId,\n params.message.parts,\n ).catch((err) =>\n console.error(\n \"PeerJsChannel: failed to process inbound A2A envelope\",\n err,\n ),\n );\n }\n }\n\n break;\n }\n }\n\n /**\n * Handle A2A SendMessage request — route through task manager.\n */\n private _handleA2ASendMessage(\n remotePeerId: string,\n request: A2AJsonRpcRequest,\n ): void {\n const params = request.params as SendMessageRequest | undefined;\n if (!params?.message) {\n this._sendJsonRpcError(remotePeerId, request.id, {\n code: A2A_ERROR_CODE.INVALID_PARAMS,\n message: \"Missing message in SendMessage params\",\n });\n\n return;\n }\n\n // Get or create task manager for this peer\n let taskManager = this._taskManagers.get(remotePeerId);\n if (!taskManager) {\n taskManager = new PeerTaskManager();\n this._taskManagers.set(remotePeerId, taskManager);\n\n // Wire up task events to emit over the DataChannel\n taskManager.on((event) => {\n this._forwardTaskEvent(remotePeerId, event);\n });\n }\n\n // Process through task manager\n const response = taskManager.handleSendMessage(params);\n\n // Send JSON-RPC response with task state\n const conn = this.connections.get(remotePeerId);\n if (conn) {\n const rpcResponse: A2AJsonRpcResponse = {\n jsonrpc: \"2.0\",\n id: request.id,\n result: response,\n };\n conn.send(rpcResponse);\n }\n\n // Also deliver the message content to the existing chat UI\n if (params.message.parts && Array.isArray(params.message.parts)) {\n this._processInboundA2AEnvelope(\n remotePeerId,\n params.message.parts,\n response.task?.id,\n response.task?.contextId,\n ).catch((err) =>\n console.error(\"PeerJsChannel: failed to process A2A SendMessage\", err),\n );\n }\n }\n\n /**\n * Handle an inbound AG-UI event notification from a remote peer.\n */\n private _handleAGUIEventNotification(\n remotePeerId: string,\n params: unknown,\n ): void {\n if (!params || typeof params !== \"object\") {\n return;\n }\n\n const event = params as AGUIEvent;\n\n // Dispatch a DOM event so UI components can react\n window.dispatchEvent(\n new CustomEvent(\"shadow-claw-agui-event\", {\n detail: { remotePeerId, event },\n }),\n );\n }\n\n /**\n * Handle GetAgentCard request — respond with our local card.\n */\n private _handleGetAgentCard(\n remotePeerId: string,\n request: A2AJsonRpcRequest,\n ): void {\n if (!this._localCard) {\n this._sendJsonRpcError(remotePeerId, request.id, {\n code: A2A_ERROR_CODE.INTERNAL_ERROR,\n message: \"Agent card not available\",\n });\n\n return;\n }\n\n const response = createGetAgentCardResponse(request.id, this._localCard);\n const conn = this.connections.get(remotePeerId);\n if (conn) {\n conn.send(response);\n }\n }\n\n private _handleInboundData(remotePeerId: string, data: unknown): void {\n if (data instanceof ArrayBuffer || data instanceof Uint8Array) {\n if (this._pendingInboundFile) {\n const canonicalName = this._pendingInboundFile.name;\n const bytes = new Uint8Array(data as ArrayBuffer);\n this._saveInboundFile(remotePeerId, canonicalName, bytes);\n this._pendingInboundFile = null;\n }\n\n return;\n }\n\n if (!data || typeof data !== \"object\") {\n return;\n }\n\n const msg = data as Record<string, unknown>;\n\n if (msg.type === \"__file_header\") {\n const transferId = (msg.id as string) || (msg.name as string);\n const totalChunks = (msg.totalChunks as number) || 1;\n const existing = this._inboundTransfers.get(transferId);\n\n this._inboundTransfers.set(transferId, {\n transferId,\n name: msg.name as string,\n mimeType: (msg.mimeType as string) || \"application/octet-stream\",\n size: (msg.size as number) || 0,\n totalChunks,\n receivedChunks: existing?.receivedChunks || new Map(),\n receivedBytes: existing?.receivedBytes || 0,\n targetGroupId:\n typeof msg.groupId === \"string\" ? msg.groupId : undefined,\n });\n\n this._pendingInboundFile = {\n name: msg.name as string,\n mimeType: msg.mimeType as string,\n size: msg.size as number,\n };\n\n updateTransferProgress({\n count: 0,\n total: totalChunks,\n direction: \"receive\",\n });\n\n return;\n }\n\n if (msg.type === \"__file_chunk\") {\n const transferId = (msg.id as string) || (msg.name as string);\n let transfer = this._inboundTransfers.get(transferId);\n if (!transfer) {\n const totalChunks = (msg.totalChunks as number) || 1;\n transfer = {\n transferId,\n name: msg.name as string,\n mimeType: \"application/octet-stream\",\n size: 0,\n totalChunks,\n receivedChunks: new Map(),\n receivedBytes: 0,\n };\n this._inboundTransfers.set(transferId, transfer);\n }\n\n const index = typeof msg.index === \"number\" ? msg.index : 0;\n const chunkData =\n msg.data instanceof ArrayBuffer\n ? new Uint8Array(msg.data)\n : msg.data instanceof Uint8Array\n ? msg.data\n : new Uint8Array((msg.data as any) || []);\n\n if (!transfer.receivedChunks.has(index)) {\n transfer.receivedChunks.set(index, chunkData);\n transfer.receivedBytes += chunkData.byteLength;\n }\n\n updateTransferProgress({\n count: transfer.receivedChunks.size,\n total: transfer.totalChunks,\n direction: \"receive\",\n });\n\n if (transfer.receivedChunks.size >= transfer.totalChunks) {\n const completeBytes = new Uint8Array(\n transfer.size || transfer.receivedBytes,\n );\n let offset = 0;\n for (let i = 0; i < transfer.totalChunks; i++) {\n const part = transfer.receivedChunks.get(i);\n if (part) {\n completeBytes.set(part, offset);\n offset += part.byteLength;\n }\n }\n\n const targetGroupId = transfer.targetGroupId || `peer:${remotePeerId}`;\n this._saveInboundFile(targetGroupId, transfer.name, completeBytes);\n this._inboundTransfers.delete(transferId);\n this._pendingInboundFile = null;\n\n clearTransferProgressDelayed(1500);\n }\n\n return;\n }\n\n if (msg.type === \"typing\") {\n this.typingCallback?.(`peer:${remotePeerId}`, !!msg.typing);\n\n return;\n }\n\n // Support legacy { type: \"chat\", text }\n if (msg.type === \"chat\") {\n const text = typeof msg.text === \"string\" ? msg.text.trim() : \"\";\n if (text) {\n this.messageCallback?.({\n id: ulid(),\n groupId: `peer:${remotePeerId}`,\n sender: remotePeerId,\n content: text,\n timestamp: Date.now(),\n channel: \"peerjs\",\n });\n }\n\n return;\n }\n\n // A2A JSON-RPC 2.0 dispatch\n if (msg.jsonrpc === \"2.0\") {\n this._handleA2AJsonRpc(remotePeerId, msg as Record<string, unknown>);\n\n return;\n }\n\n // Control-plane command execution over WebRTC DataChannel\n if (msg.type === \"command:execute\") {\n const payload = (msg.payload || {}) as {\n commandId?: string;\n action?: string;\n args?: any;\n };\n const action = payload.action || \"\";\n const args = payload.args || {};\n const commandId = payload.commandId || \"\";\n\n import(\"../../core/utils/initControlPlane.js\")\n .then(({ executeClientControlCommand }) =>\n executeClientControlCommand(action, args),\n )\n .then((result) => {\n const conn = this.connections.get(remotePeerId);\n if (conn) {\n const hasError = Boolean(result?.error);\n conn.send({\n id: ulid(),\n type: \"command:result\",\n payload: {\n commandId,\n action,\n success: !hasError,\n data: result,\n ...(hasError ? { error: result.error } : {}),\n },\n });\n }\n })\n .catch((err) => {\n const conn = this.connections.get(remotePeerId);\n if (conn) {\n conn.send({\n id: ulid(),\n type: \"command:result\",\n payload: {\n commandId,\n action,\n success: false,\n error: err?.message || String(err),\n },\n });\n }\n });\n\n return;\n }\n }\n\n private _isTrustedPeer(remotePeerId: string): boolean {\n if (this.trustedPeerIds.size === 0) {\n return true;\n }\n if (this.trustedPeerIds.has(remotePeerId)) {\n return true;\n }\n for (const trusted of this.trustedPeerIds) {\n const clean = trusted.trim();\n if (clean.endsWith(\"*\") && remotePeerId.startsWith(clean.slice(0, -1))) {\n return true;\n }\n if (clean === \"cli\" && remotePeerId.startsWith(\"cli-\")) {\n return true;\n }\n }\n return false;\n }\n\n private _handleIncomingConnection(conn: DataConnection): void {\n const remotePeerId = conn.peer;\n\n // Reject untrusted peers when a trusted list is configured\n if (!this._isTrustedPeer(remotePeerId)) {\n console.warn(\n `PeerJsChannel: rejecting connection from untrusted peer: ${remotePeerId}`,\n );\n try {\n conn.close();\n } catch {\n // ignore\n }\n\n return;\n }\n\n // Attach chunk progress interceptor to track inbound file transfers\n this._attachChunkProgressTracker(conn);\n\n // Register the connection\n this.connections.set(remotePeerId, conn);\n this._updateConnectedPeersSignal();\n\n conn.on(\"open\", () => {\n console.log(`PeerJsChannel: connection opened with ${remotePeerId}`);\n this._exchangeAgentCards(remotePeerId, conn);\n });\n\n conn.on(\"data\", (data: unknown) => {\n this._handleInboundData(remotePeerId, data);\n });\n\n conn.on(\"close\", () => {\n console.log(`PeerJsChannel: connection closed with ${remotePeerId}`);\n this.connections.delete(remotePeerId);\n this.peerCards.delete(remotePeerId);\n this._taskManagers.delete(remotePeerId);\n this._updateConnectedPeersSignal();\n });\n\n conn.on(\"error\", (err: Error) => {\n console.error(\n `PeerJsChannel: connection error with ${remotePeerId}:`,\n err,\n );\n this.connections.delete(remotePeerId);\n this._updateConnectedPeersSignal();\n window.dispatchEvent(\n new CustomEvent(\"shadow-claw-peer-error\", {\n detail: {\n remotePeerId,\n error: err.message,\n },\n }),\n );\n });\n\n conn.on(\"iceStateChanged\", (state: string) => {\n if (\n state === \"failed\" ||\n state === \"disconnected\" ||\n state === \"closed\"\n ) {\n console.warn(\n `PeerJsChannel: ICE state changed to ${state} for ${remotePeerId}`,\n );\n this.connections.delete(remotePeerId);\n this._updateConnectedPeersSignal();\n }\n });\n }\n\n /**\n * Intercept incoming BinaryPack chunk handling on DataConnection to track\n * file reception progress without requiring a custom PeerJS fork.\n */\n private _attachChunkProgressTracker(conn: DataConnection): void {\n const connAny = conn as any;\n if (connAny._chunkProgressPatched) {\n return;\n }\n connAny._chunkProgressPatched = true;\n\n const self = this;\n const origHandleChunk = connAny._handleChunk;\n if (typeof origHandleChunk === \"function\") {\n connAny._handleChunk = function (data: any) {\n if (data && typeof data === \"object\" && \"__peerData\" in data) {\n // If an application-level multi-chunk file transfer is in progress, ignore\n // raw PeerJS binarypack frame chunks to prevent fighting/flickering.\n if (self._inboundTransfers.size === 0) {\n const id = data.__peerData;\n const currentCount = this._chunkedData?.[id]?.count ?? 0;\n const total = data.total;\n\n if (\n typeof globalThis.dispatchEvent === \"function\" &&\n typeof CustomEvent === \"function\"\n ) {\n globalThis.dispatchEvent(\n new CustomEvent(\"peerjs-dc-handle-chunk\", {\n detail: {\n chunkInfo: {\n count: currentCount,\n total,\n },\n },\n }),\n );\n } else {\n const received = currentCount + 1;\n updateTransferProgress({\n count: received,\n total,\n direction: \"receive\",\n });\n\n if (received >= total) {\n clearTransferProgressDelayed(1500);\n }\n }\n }\n }\n\n return origHandleChunk.call(this, data);\n };\n }\n }\n\n /**\n * Handle an inbound task status update notification.\n */\n private _handleTaskStatusNotification(\n remotePeerId: string,\n params: unknown,\n ): void {\n if (!params || typeof params !== \"object\") {\n return;\n }\n\n const statusUpdate = params as TaskStatusUpdateEvent;\n\n // If the remote peer signaled a terminal state, notify the orchestrator\n // so it can suppress further auto-triggers for this conversation.\n if (\n statusUpdate.status?.state &&\n TERMINAL_STATES.has(statusUpdate.status.state as any)\n ) {\n const groupId = `peer:${remotePeerId}`;\n this._onTaskCompleteCallback?.(groupId);\n }\n\n window.dispatchEvent(\n new CustomEvent(\"shadow-claw-task-status\", {\n detail: { remotePeerId, ...statusUpdate },\n }),\n );\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private async _initPeer(): Promise<void> {\n const { Peer } = await import(\"peerjs\");\n const opts: Record<string, unknown> = {};\n\n // Only override defaults when explicitly configured\n const host = this.serverConfig.host ?? PEERJS_DEFAULT_HOST;\n const port = this.serverConfig.port ?? PEERJS_DEFAULT_PORT;\n const path = this.serverConfig.path ?? PEERJS_DEFAULT_PATH;\n const secure = this.serverConfig.secure ?? PEERJS_DEFAULT_SECURE;\n\n opts.host = host;\n opts.port = port;\n opts.path = path;\n opts.secure = secure;\n opts.debug = 3; // Verbose PeerJS logging for connection diagnostics\n\n // ICE servers for WebRTC connectivity (STUN for NAT traversal)\n const iceServers: RTCIceServer[] = this.serverConfig.iceServers ?? [\n { urls: \"stun:stun.l.google.com:19302\" },\n { urls: \"stun:stun1.l.google.com:19302\" },\n ];\n opts.config = { iceServers };\n\n this.peer = new Peer(this.myPeerId, opts);\n\n this.peer.on(\"open\", (id) => {\n console.log(\n `PeerJsChannel: connected to signaling server, peer ID: ${id}`,\n );\n // Reset backoff on successful connection\n this._reconnectAttempts = 0;\n });\n\n this.peer.on(\"connection\", (conn: DataConnection) => {\n this._handleIncomingConnection(conn);\n });\n\n this.peer.on(\"error\", (err: PeerError<string>) => {\n console.error(`PeerJsChannel: peer error [${err.type}]:`, err.message);\n\n if (err.type === \"peer-unavailable\" || err.type === \"unavailable-id\") {\n window.dispatchEvent(\n new CustomEvent(\"shadow-claw-peer-error\", {\n detail: {\n error: err.message,\n },\n }),\n );\n }\n\n // Recoverable errors — don't stop the channel\n if (\n err.type === \"peer-unavailable\" ||\n err.type === \"network\" ||\n err.type === \"disconnected\"\n ) {\n return;\n }\n\n // Non-recoverable\n if (err.type === \"unavailable-id\") {\n console.warn(\n \"PeerJsChannel: peer ID is already in use. Stop the channel and reconfigure.\",\n );\n }\n });\n\n this.peer.on(\"disconnected\", () => {\n if (this.running) {\n this._scheduleReconnect();\n }\n });\n\n this.peer.on(\"close\", () => {\n console.log(\"PeerJsChannel: peer closed\");\n });\n }\n\n /**\n * Register a pending JSON-RPC request (with 10s timeout).\n */\n private _registerPendingRequest(\n requestId: string,\n callback: (response: A2AJsonRpcResponse) => void,\n ): void {\n const timer = setTimeout(() => {\n this._pendingRequests.delete(requestId);\n console.warn(\n `PeerJsChannel: JSON-RPC request ${requestId} timed out (10s)`,\n );\n }, 10_000);\n\n this._pendingRequests.set(requestId, {\n resolve: callback,\n timer,\n });\n }\n\n /**\n * Schedule a reconnection attempt with exponential backoff.\n * Delay doubles each attempt: 1s, 2s, 4s, 8s, ... up to 60s max.\n */\n private _scheduleReconnect(): void {\n if (this._reconnectTimer !== null) {\n return; // Already scheduled\n }\n\n const delay = Math.min(\n PeerJsChannel._RECONNECT_BASE_MS * Math.pow(2, this._reconnectAttempts),\n PeerJsChannel._RECONNECT_MAX_MS,\n );\n\n this._reconnectAttempts++;\n\n console.log(\n `PeerJsChannel: disconnected from signaling server, reconnecting in ${(delay / 1000).toFixed(1)}s (attempt ${this._reconnectAttempts})`,\n );\n\n this._reconnectTimer = setTimeout(() => {\n this._reconnectTimer = null;\n if (!this.running) {\n return;\n }\n\n try {\n (this.peer as any)?.reconnect?.();\n } catch {\n // If reconnect throws, schedule another attempt\n this._scheduleReconnect();\n }\n }, delay);\n }\n\n // ---------------------------------------------------------------------------\n // JSON-RPC Helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Send a JSON-RPC error response to a remote peer.\n */\n private _sendJsonRpcError(\n remotePeerId: string,\n requestId: string,\n error: { code: number; message: string; data?: unknown[] },\n ): void {\n const conn = this.connections.get(remotePeerId);\n if (!conn) {\n return;\n }\n\n const response: A2AJsonRpcResponse = {\n jsonrpc: \"2.0\",\n id: requestId,\n error,\n };\n\n try {\n conn.send(response);\n } catch {\n // Ignore send errors for error responses\n }\n }\n\n /**\n * Pause execution if the underlying WebRTC DataChannel send buffer\n * exceeds the drain threshold, preventing buffer bloat during large transfers.\n */\n private async _waitForBufferDrain(\n conn: DataConnection,\n threshold: number = FILE_BUFFER_DRAIN_THRESHOLD,\n ): Promise<void> {\n const rawDc =\n ((conn as any).dataChannel as RTCDataChannel | undefined) ||\n ((conn as any)._dc as RTCDataChannel | undefined);\n if (!rawDc || typeof rawDc.bufferedAmount !== \"number\") {\n return;\n }\n if (rawDc.bufferedAmount <= threshold) {\n return;\n }\n\n await new Promise<void>((resolve) => {\n const poll = setInterval(() => {\n if (!rawDc || rawDc.bufferedAmount <= threshold) {\n clearInterval(poll);\n resolve();\n }\n }, 20);\n\n if (typeof rawDc.addEventListener === \"function\") {\n const onLow = () => {\n clearInterval(poll);\n rawDc.removeEventListener(\"bufferedamountlow\", onLow);\n resolve();\n };\n try {\n rawDc.bufferedAmountLowThreshold = threshold;\n rawDc.addEventListener(\"bufferedamountlow\", onLow, { once: true });\n } catch {\n // Fall back to polling if bufferedAmountLowThreshold throws\n }\n }\n });\n }\n\n /**\n * Persist complete received file bytes into group storage, handling\n * duplicate filename incrementing and path remapping.\n */\n private _saveInboundFile(\n groupId: string,\n canonicalName: string,\n bytes: Uint8Array,\n ): void {\n getDb().then(async (db) => {\n let finalName = canonicalName;\n let counter = 1;\n\n while (await groupFileExists(db, groupId, finalName)) {\n const lastDotIndex = canonicalName.lastIndexOf(\".\");\n const hasExt =\n lastDotIndex > 0 && lastDotIndex < canonicalName.length - 1;\n\n if (hasExt) {\n const base = canonicalName.substring(0, lastDotIndex);\n const ext = canonicalName.substring(lastDotIndex);\n finalName = `${base} (${counter})${ext}`;\n } else {\n finalName = `${canonicalName} (${counter})`;\n }\n\n counter++;\n }\n\n if (finalName !== canonicalName) {\n this._inboundRemap.set(canonicalName, finalName);\n }\n\n writeGroupFileBytes(db, groupId, finalName, bytes).catch((err) => {\n console.error(\"PeerJsChannel: failed to write inbound file bytes\", err);\n });\n });\n }\n\n private _updateConnectedPeersSignal(): void {\n this.connectedPeersSignal.set(Array.from(this.connections.keys()));\n }\n\n /**\n * Waits up to 5s for a DataConnection to open. Resolves immediately if\n * already open. Rejects if the connection errors or the timeout fires\n * without the connection opening.\n */\n private _waitForOpen(conn: DataConnection): Promise<void> {\n if ((conn as any).open) {\n return Promise.resolve();\n }\n\n return new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error(\"Connection open timeout (5s)\"));\n }, 5000);\n\n const openHandler = () => {\n clearTimeout(timeout);\n resolve();\n };\n\n const errorHandler = (err: Error) => {\n clearTimeout(timeout);\n reject(err);\n };\n\n conn.on(\"open\", openHandler);\n conn.on(\"error\", errorHandler);\n });\n }\n\n private async _processInboundA2AEnvelope(\n remotePeerId: string,\n parts: any[],\n taskId?: string,\n contextId?: string,\n ): Promise<void> {\n const groupId = `peer:${remotePeerId}`;\n\n let text = \"\";\n const inboundAttachments: MessageAttachment[] = [];\n const a2uiEnvelopes: A2UIEnvelope[] = [];\n let a2uiAction: A2UIAction | undefined;\n\n // The sender has already transmitted the raw binary buffers sequentially and\n // saved them into OPFS in `_handleInboundData`. Here we just compile the metadata\n // for the chat UI.\n for (const part of parts) {\n if (part.kind === \"text\" && typeof part.text === \"string\") {\n text += part.text;\n } else if (part.kind === \"file\") {\n let rawPath = part.name || \"attachment\";\n\n if (this._inboundRemap.has(rawPath)) {\n const remappedName = this._inboundRemap.get(rawPath)!;\n\n // Rewrite the text to use the remapped name\n const escapedOld = rawPath.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n text = text.replace(\n new RegExp(`(!?\\\\[.*?\\\\])\\\\(${escapedOld}\\\\)`, \"g\"),\n `$1(${remappedName})`,\n );\n\n this._inboundRemap.delete(rawPath);\n rawPath = remappedName;\n }\n\n const fileName = rawPath.split(\"/\").pop() || \"attachment\";\n\n inboundAttachments.push({\n fileName,\n mimeType: part.mimeType,\n path: rawPath,\n size: part.size || 0,\n });\n } else if (part.kind === \"a2ui\" && part.envelope) {\n a2uiEnvelopes.push(part.envelope as A2UIEnvelope);\n } else if (part.kind === \"a2ui-action\" && part.action) {\n a2uiAction = part.action as A2UIAction;\n }\n }\n\n text = text.trim();\n\n // Only suppress the callback if there is truly nothing to deliver.\n if (\n !text &&\n inboundAttachments.length === 0 &&\n a2uiEnvelopes.length === 0 &&\n !a2uiAction\n ) {\n return;\n }\n\n this.messageCallback?.({\n id: ulid(),\n groupId,\n sender: remotePeerId,\n content: text,\n timestamp: Date.now(),\n channel: \"peerjs\",\n attachments:\n inboundAttachments.length > 0 ? inboundAttachments : undefined,\n a2uiEnvelopes: a2uiEnvelopes.length > 0 ? a2uiEnvelopes : undefined,\n a2uiAction,\n taskId,\n contextId,\n });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction extractMarkdownAttachments(text: string): {\n remainingText: string;\n attachments: { alt: string; path: string }[];\n} {\n const attachments: { alt: string; path: string }[] = [];\n const regex = /!?\\[([^\\]]*)\\]\\(([^)]+)\\)/g;\n\n let match;\n let remainingText = text;\n\n // Find all matches\n while ((match = regex.exec(text)) !== null) {\n const alt = match[1];\n const path = (match[2] || \"\").trim();\n\n const normalizedPath = normalizeAttachmentPath(path);\n\n if (normalizedPath) {\n attachments.push({ alt, path: normalizedPath });\n }\n }\n\n return { remainingText, attachments };\n}\n\nfunction normalizeAttachmentPath(path: string): string | null {\n if (!path) {\n return null;\n }\n\n const trimmed = path.trim();\n\n // Ignore URI schemes (https:, data:, mailto:, etc.) and protocol-relative URLs.\n if (/^[a-zA-Z][a-zA-Z\\d+.-]*:/.test(trimmed) || trimmed.startsWith(\"//\")) {\n return null;\n }\n\n const normalized = trimmed\n .replace(/\\\\/g, \"/\")\n .replace(/^\\/+/, \"\")\n .replace(/^\\.\\//, \"\");\n\n if (!normalized) {\n return null;\n }\n\n const segments = normalized.split(\"/\").filter(Boolean);\n if (segments.some((seg) => seg === \"..\")) {\n return null;\n }\n\n return segments.join(\"/\");\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"peerjs-BXlMuIQn.js","names":[],"sources":["../../src/content/message-attachments.ts","../../src/subsystems/channels/peer-protocol.ts","../../src/subsystems/channels/peer-agent-card.ts","../../src/subsystems/channels/peer-task-manager.ts","../../src/subsystems/channels/peerjs.ts"],"sourcesContent":["import { uploadGroupFile } from \"../storage/uploadGroupFile.js\";\nimport type { MessageAttachment, MessageAttachmentSource } from \"./types.js\";\nimport type { ShadowClawDatabase } from \"../db/types.js\";\n\nconst MIME_TYPES_BY_EXTENSION: Record<string, string> = {\n apng: \"image/apng\",\n avif: \"image/avif\",\n bmp: \"image/bmp\",\n css: \"text/css\",\n gif: \"image/gif\",\n htm: \"text/html\",\n html: \"text/html\",\n jpeg: \"image/jpeg\",\n jpg: \"image/jpeg\",\n js: \"text/javascript\",\n json: \"application/json\",\n markdown: \"text/markdown\",\n md: \"text/markdown\",\n mp3: \"audio/mpeg\",\n mp4: \"video/mp4\",\n oga: \"audio/ogg\",\n ogg: \"audio/ogg\",\n ogv: \"video/ogg\",\n pdf: \"application/pdf\",\n png: \"image/png\",\n svg: \"image/svg+xml\",\n txt: \"text/plain\",\n wav: \"audio/wav\",\n webm: \"video/webm\",\n webp: \"image/webp\",\n};\n\nexport function sanitizeAttachmentFileName(fileName: string): string {\n const trimmed = fileName.trim();\n const normalized = trimmed\n .replace(/[\\u0000-\\u001f\\u007f]+/g, \"\")\n .replace(/[\\\\/:*?\"<>|]+/g, \"-\")\n .replace(/\\s+/g, \" \")\n .replace(/^\\.+/, \"\")\n .trim();\n\n return normalized || \"attachment\";\n}\n\nexport function inferAttachmentMimeType(\n fileName: string,\n explicitMimeType = \"\",\n): string {\n if (explicitMimeType) {\n return explicitMimeType;\n }\n\n const extension = fileName.toLowerCase().split(\".\").pop() || \"\";\n\n return MIME_TYPES_BY_EXTENSION[extension] || \"application/octet-stream\";\n}\n\nexport function shouldInlineAttachmentInChat(\n attachment: Pick<\n MessageAttachment,\n \"fileName\" | \"mimeType\" | \"previewDisposition\"\n >,\n): boolean {\n if (attachment.previewDisposition === \"inline\") {\n return true;\n }\n\n return (\n inferAttachmentMimeType(attachment.fileName, attachment.mimeType || \"\") ===\n \"image/png\"\n );\n}\n\nexport function buildAttachmentStoragePath(\n fileName: string,\n attachmentId = \"\",\n timestamp = Date.now(),\n): string {\n const safeName = sanitizeAttachmentFileName(fileName);\n const safeId = attachmentId\n .trim()\n .replace(/[^a-zA-Z0-9._-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n const prefix = safeId ? `${safeId}-` : \"\";\n\n return `attachments/${timestamp}-${prefix}${safeName}`;\n}\n\nexport async function persistMessageAttachments(\n db: ShadowClawDatabase,\n groupId: string,\n attachments: MessageAttachment[] = [],\n): Promise<MessageAttachment[]> {\n const persisted: MessageAttachment[] = [];\n\n for (const attachment of attachments) {\n const fileName = sanitizeAttachmentFileName(attachment.fileName || \"\");\n const path =\n attachment.path || buildAttachmentStoragePath(fileName, attachment.id);\n const source = attachment.source;\n\n let mimeType = inferAttachmentMimeType(fileName, attachment.mimeType || \"\");\n let size = attachment.size;\n\n if (source) {\n const blob = await readAttachmentSourceAsBlob(source);\n mimeType = inferAttachmentMimeType(\n fileName,\n attachment.mimeType || blob.type,\n );\n size = typeof size === \"number\" ? size : blob.size;\n await uploadGroupFile(db, groupId, path, blob);\n }\n\n persisted.push(\n stripAttachmentSource({\n ...attachment,\n fileName,\n mimeType,\n size,\n path,\n previewDisposition:\n attachment.previewDisposition ||\n (mimeType === \"image/png\" ? \"inline\" : \"file\"),\n }),\n );\n }\n\n return persisted;\n}\n\nasync function readAttachmentSourceAsBlob(\n source: MessageAttachmentSource,\n): Promise<Blob> {\n if (source.kind === \"local-file\") {\n return source.file;\n }\n\n if (source.kind === \"inline-text\") {\n return new Blob([source.text], {\n type: source.mimeType || \"text/plain\",\n });\n }\n\n const response = await fetch(source.url, {\n headers: source.headers,\n });\n\n if (!response.ok) {\n throw new Error(\n `Attachment download failed: HTTP ${response.status} ${response.statusText}`,\n );\n }\n\n return await response.blob();\n}\n\nfunction stripAttachmentSource(\n attachment: MessageAttachment,\n): MessageAttachment {\n const { source, ...storedAttachment } = attachment;\n\n return storedAttachment;\n}\n","/**\n * A2A v1.0 + AG-UI Protocol Types for WebRTC DataChannel Binding\n *\n * Custom binding identifier:\n * https://xt-ml.github.io/shadow-claw/bindings/webrtc-datachannel/v1\n *\n * This module defines:\n * - A2A v1.0 canonical data model (Task, Message, Part, Artifact, TaskState)\n * - AG-UI event types for streaming visibility\n * - Wire protocol envelope (JSON-RPC 2.0 over DataChannel)\n * - Error codes per A2A spec §5.4\n *\n * References:\n * - https://a2a-protocol.org/latest/specification/\n * - https://docs.ag-ui.com/concepts/events\n */\n\nimport type { A2UIAction, A2UIEnvelope } from \"../../ui/a2ui/types.js\";\nimport type { RoomMember } from \"./types.js\";\n\n// =============================================================================\n// A2A v1.0 Protocol Binding Identifier\n// =============================================================================\n\nexport const A2A_PROTOCOL_BINDING =\n \"https://xt-ml.github.io/shadow-claw/bindings/webrtc-datachannel/v1\";\n\nexport const A2A_PROTOCOL_VERSION = \"1.0\";\n\n// =============================================================================\n// A2A Task States (spec §4.1.3)\n// =============================================================================\n\nexport enum TaskState {\n UNSPECIFIED = \"TASK_STATE_UNSPECIFIED\",\n SUBMITTED = \"TASK_STATE_SUBMITTED\",\n WORKING = \"TASK_STATE_WORKING\",\n COMPLETED = \"TASK_STATE_COMPLETED\",\n FAILED = \"TASK_STATE_FAILED\",\n CANCELED = \"TASK_STATE_CANCELED\",\n INPUT_REQUIRED = \"TASK_STATE_INPUT_REQUIRED\",\n REJECTED = \"TASK_STATE_REJECTED\",\n AUTH_REQUIRED = \"TASK_STATE_AUTH_REQUIRED\",\n}\n\n/** Terminal states — no further transitions allowed */\nexport const TERMINAL_STATES: ReadonlySet<TaskState> = new Set([\n TaskState.COMPLETED,\n TaskState.FAILED,\n TaskState.CANCELED,\n TaskState.REJECTED,\n]);\n\n/** Interrupted states — can transition back to WORKING */\nexport const INTERRUPTED_STATES: ReadonlySet<TaskState> = new Set([\n TaskState.INPUT_REQUIRED,\n TaskState.AUTH_REQUIRED,\n]);\n\n// =============================================================================\n// A2A Roles (spec §4.1.5)\n// =============================================================================\n\nexport enum Role {\n UNSPECIFIED = \"ROLE_UNSPECIFIED\",\n USER = \"ROLE_USER\",\n AGENT = \"ROLE_AGENT\",\n}\n\n// =============================================================================\n// A2A Part (spec §4.1.6 — v1.0 member-name discriminator)\n// =============================================================================\n\nexport interface TextPart {\n text: string;\n mediaType?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface RawPart {\n raw: string; // base64-encoded bytes\n filename?: string;\n mediaType?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface UrlPart {\n url: string;\n filename?: string;\n mediaType?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface DataPart {\n data: unknown;\n mediaType?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport type Part = TextPart | RawPart | UrlPart | DataPart;\n\n// =============================================================================\n// A2A Message (spec §4.1.4)\n// =============================================================================\n\nexport interface A2AMessage {\n messageId: string;\n role: Role;\n parts: Part[];\n contextId?: string;\n taskId?: string;\n metadata?: Record<string, unknown>;\n extensions?: string[];\n referenceTaskIds?: string[];\n}\n\n// =============================================================================\n// A2A TaskStatus (spec §4.1.2)\n// =============================================================================\n\nexport interface TaskStatus {\n state: TaskState;\n message?: A2AMessage;\n timestamp?: string; // ISO 8601\n}\n\n// =============================================================================\n// A2A Task (spec §4.1.1)\n// =============================================================================\n\nexport interface A2ATask {\n id: string;\n contextId?: string;\n status: TaskStatus;\n artifacts?: Artifact[];\n history?: A2AMessage[];\n metadata?: Record<string, unknown>;\n}\n\n// =============================================================================\n// A2A Artifact (spec §4.1.7)\n// =============================================================================\n\nexport interface Artifact {\n artifactId: string;\n name?: string;\n description?: string;\n parts: Part[];\n metadata?: Record<string, unknown>;\n extensions?: string[];\n}\n\n// =============================================================================\n// A2A Streaming Events (spec §4.2)\n// =============================================================================\n\nexport interface TaskStatusUpdateEvent {\n taskId: string;\n contextId: string;\n status: TaskStatus;\n metadata?: Record<string, unknown>;\n}\n\nexport interface TaskArtifactUpdateEvent {\n taskId: string;\n contextId: string;\n artifact: Artifact;\n append?: boolean;\n lastChunk?: boolean;\n metadata?: Record<string, unknown>;\n}\n\n// =============================================================================\n// A2A Agent Discovery (spec §4.4)\n// =============================================================================\n\nexport interface AgentCard {\n name: string;\n description: string;\n version: string;\n supportedInterfaces: AgentInterface[];\n capabilities: AgentCapabilities;\n defaultInputModes: string[];\n defaultOutputModes: string[];\n skills: AgentSkill[];\n provider?: AgentProvider;\n iconUrl?: string;\n documentationUrl?: string;\n}\n\nexport interface AgentInterface {\n url: string;\n protocolBinding: string;\n protocolVersion: string;\n tenant?: string;\n}\n\nexport interface AgentCapabilities {\n streaming?: boolean;\n pushNotifications?: boolean;\n extendedAgentCard?: boolean;\n extensions?: AgentExtension[];\n}\n\nexport interface AgentExtension {\n uri: string;\n description?: string;\n required?: boolean;\n params?: Record<string, unknown>;\n}\n\nexport interface AgentSkill {\n id: string;\n name: string;\n description: string;\n tags: string[];\n examples?: string[];\n inputModes?: string[];\n outputModes?: string[];\n}\n\nexport interface AgentProvider {\n organization: string;\n url: string;\n}\n\n// =============================================================================\n// A2A SendMessage Request/Response (spec §3.2.1, §3.2.2)\n// =============================================================================\n\nexport interface SendMessageRequest {\n message: A2AMessage;\n configuration?: SendMessageConfiguration;\n metadata?: Record<string, unknown>;\n}\n\nexport interface SendMessageConfiguration {\n acceptedOutputModes?: string[];\n historyLength?: number;\n returnImmediately?: boolean;\n}\n\nexport interface SendMessageResponse {\n task?: A2ATask;\n message?: A2AMessage;\n}\n\n// =============================================================================\n// A2A StreamResponse (spec §3.2.3)\n// =============================================================================\n\nexport type StreamResponse =\n | { task: A2ATask }\n | { message: A2AMessage }\n | { statusUpdate: TaskStatusUpdateEvent }\n | { artifactUpdate: TaskArtifactUpdateEvent };\n\n// =============================================================================\n// AG-UI Events (https://docs.ag-ui.com/concepts/events)\n// =============================================================================\n\n// --- Lifecycle ---\n\nexport interface AGUIRunStarted {\n type: \"RUN_STARTED\";\n threadId: string;\n runId: string;\n timestamp?: number;\n}\n\nexport interface AGUIRunFinished {\n type: \"RUN_FINISHED\";\n threadId: string;\n runId: string;\n timestamp?: number;\n}\n\nexport interface AGUIRunError {\n type: \"RUN_ERROR\";\n message: string;\n code?: string;\n timestamp?: number;\n}\n\nexport interface AGUIStepStarted {\n type: \"STEP_STARTED\";\n stepName: string;\n timestamp?: number;\n}\n\nexport interface AGUIStepFinished {\n type: \"STEP_FINISHED\";\n stepName: string;\n timestamp?: number;\n}\n\n// --- Text Message ---\n\nexport interface AGUITextMessageStart {\n type: \"TEXT_MESSAGE_START\";\n messageId: string;\n role: \"assistant\" | \"user\" | \"developer\" | \"system\" | \"tool\";\n timestamp?: number;\n}\n\nexport interface AGUITextMessageContent {\n type: \"TEXT_MESSAGE_CONTENT\";\n messageId: string;\n delta: string;\n timestamp?: number;\n}\n\nexport interface AGUITextMessageEnd {\n type: \"TEXT_MESSAGE_END\";\n messageId: string;\n timestamp?: number;\n}\n\n// --- Tool Calls ---\n\nexport interface AGUIToolCallStart {\n type: \"TOOL_CALL_START\";\n toolCallId: string;\n toolCallName: string;\n parentMessageId?: string;\n timestamp?: number;\n}\n\nexport interface AGUIToolCallArgs {\n type: \"TOOL_CALL_ARGS\";\n toolCallId: string;\n delta: string;\n timestamp?: number;\n}\n\nexport interface AGUIToolCallEnd {\n type: \"TOOL_CALL_END\";\n toolCallId: string;\n timestamp?: number;\n}\n\nexport interface AGUIToolCallResult {\n type: \"TOOL_CALL_RESULT\";\n toolCallId: string;\n messageId?: string;\n content: string;\n role?: \"tool\";\n timestamp?: number;\n}\n\n// --- State Management ---\n\nexport interface AGUIStateSnapshot {\n type: \"STATE_SNAPSHOT\";\n snapshot: Record<string, unknown>;\n timestamp?: number;\n}\n\nexport interface AGUIStateDelta {\n type: \"STATE_DELTA\";\n delta: Array<{ op: string; path: string; value?: unknown }>;\n timestamp?: number;\n}\n\nexport interface AGUIMessagesSnapshot {\n type: \"MESSAGES_SNAPSHOT\";\n messages: Array<Record<string, unknown>>;\n timestamp?: number;\n}\n\n// --- Custom ---\n\nexport interface AGUICustomEvent {\n type: \"CUSTOM\";\n name: string;\n value: unknown;\n timestamp?: number;\n}\n\n/** Union of all AG-UI event types */\nexport type AGUIEvent =\n | AGUIRunStarted\n | AGUIRunFinished\n | AGUIRunError\n | AGUIStepStarted\n | AGUIStepFinished\n | AGUITextMessageStart\n | AGUITextMessageContent\n | AGUITextMessageEnd\n | AGUIToolCallStart\n | AGUIToolCallArgs\n | AGUIToolCallEnd\n | AGUIToolCallResult\n | AGUIStateSnapshot\n | AGUIStateDelta\n | AGUIMessagesSnapshot\n | AGUICustomEvent;\n\n// =============================================================================\n// Wire Protocol — JSON-RPC 2.0 over WebRTC DataChannel\n// =============================================================================\n\n/**\n * JSON-RPC 2.0 error object (spec §9.5)\n */\nexport interface A2AJsonRpcError {\n code: number;\n message: string;\n data?: unknown[];\n}\n\n/**\n * JSON-RPC 2.0 Request (has `id` and `method`)\n */\nexport interface A2AJsonRpcRequest {\n jsonrpc: \"2.0\";\n id: string;\n method: string;\n params?: unknown;\n}\n\n/**\n * JSON-RPC 2.0 Response (has `id` and either `result` or `error`)\n */\nexport interface A2AJsonRpcResponse {\n jsonrpc: \"2.0\";\n id: string;\n result?: unknown;\n error?: A2AJsonRpcError;\n}\n\n/**\n * JSON-RPC 2.0 Notification (has `method` but no `id`)\n */\nexport interface A2AJsonRpcNotification {\n jsonrpc: \"2.0\";\n method: string;\n params?: unknown;\n}\n\n/** Union of all wire message types */\nexport type A2AWireMessage =\n | A2AJsonRpcRequest\n | A2AJsonRpcResponse\n | A2AJsonRpcNotification;\n\n// =============================================================================\n// Wire Protocol Methods\n// =============================================================================\n\n/** Standard A2A methods (spec §9.4) */\nexport const A2A_METHOD = {\n SEND_MESSAGE: \"SendMessage\",\n SEND_STREAMING_MESSAGE: \"SendStreamingMessage\",\n GET_TASK: \"GetTask\",\n CANCEL_TASK: \"CancelTask\",\n GET_AGENT_CARD: \"GetAgentCard\",\n} as const;\n\n/** AG-UI event notification method */\nexport const AGUI_METHOD = {\n EVENT: \"agui/event\",\n} as const;\n\n/** A2A streaming notification methods */\nexport const A2A_STREAM_METHOD = {\n STATUS_UPDATE: \"tasks/statusUpdate\",\n ARTIFACT_UPDATE: \"tasks/artifactUpdate\",\n} as const;\n\n// =============================================================================\n// Room (multi-party) Wire Protocol\n// =============================================================================\n\n/**\n * Room notification methods carried over the same JSON-RPC 2.0 DataChannel.\n *\n * Topology is hybrid: the room host runs a star for signaling/roster/membership\n * (`room/join`, `room/roster`, `room/leave`, `room/invite`), while actual\n * message traffic (`room/message`) flows peer-to-peer over the mesh, falling\n * back to host relay (`room/relay`) when a direct connection is unavailable.\n */\nexport const ROOM_METHOD = {\n /** member → host: request to join; host updates roster and broadcasts it. */\n JOIN: \"room/join\",\n /** host → all members: authoritative roster snapshot (pushed on change). */\n ROSTER: \"room/roster\",\n /** member → host (leaving) or host → all (disbanded). */\n LEAVE: \"room/leave\",\n /** any → recipient: a chat message tagged with the originating room. */\n MESSAGE: \"room/message\",\n /** peer → peer: out-of-band invitation to join a room. */\n INVITE: \"room/invite\",\n /** sender → host: ask the host to forward an inner notification to a target. */\n RELAY: \"room/relay\",\n /** owner → all members: a shared A2UI surface envelope (create/update/delete). */\n A2UI: \"room/a2ui\",\n /** any member → all members: a user action fired on a shared A2UI surface. */\n A2UI_ACTION: \"room/a2ui-action\",\n} as const;\n\n/** A file attachment reference within a room message. */\nexport interface RoomMessageAttachment {\n fileName: string;\n mimeType?: string;\n path?: string;\n size?: number;\n}\n\n/** Envelope for a chat message broadcast within a room. */\nexport interface RoomMessageEnvelope {\n roomId: string;\n /** Stable id used for cross-path (mesh + relay) de-duplication. */\n messageId: string;\n senderPeerId: string;\n senderAlias?: string;\n text: string;\n attachments?: RoomMessageAttachment[];\n}\n\n/** Payload for {@link ROOM_METHOD.JOIN}. */\nexport interface RoomJoinPayload {\n roomId: string;\n member: RoomMember;\n}\n\n/** Payload for {@link ROOM_METHOD.ROSTER}. */\nexport interface RoomRosterPayload {\n roomId: string;\n name: string;\n hostPeerId: string;\n members: RoomMember[];\n}\n\n/** Payload for {@link ROOM_METHOD.LEAVE}. */\nexport interface RoomLeavePayload {\n roomId: string;\n peerId: string;\n /** When true, the host has disbanded the room for everyone. */\n disbanded?: boolean;\n}\n\n/** Payload for {@link ROOM_METHOD.INVITE}. */\nexport interface RoomInvitePayload {\n roomId: string;\n roomName: string;\n hostPeerId: string;\n fromPeerId: string;\n fromAlias?: string;\n}\n\n/** Payload for {@link ROOM_METHOD.RELAY}. */\nexport interface RoomRelayPayload {\n roomId: string;\n targetPeerId: string;\n /** A JSON-RPC notification to be forwarded verbatim to {@link targetPeerId}. */\n inner: A2AJsonRpcNotification;\n}\n\n/**\n * Payload for {@link ROOM_METHOD.A2UI} — a shared A2UI surface broadcast.\n *\n * The surface is **owner-authoritative**: only {@link ownerPeerId}'s agent\n * mutates the data model. Other members render the broadcast envelope and route\n * their interactions back via {@link ROOM_METHOD.A2UI_ACTION}.\n */\nexport interface RoomA2UIEnvelope {\n roomId: string;\n /** Stable id used for cross-path (mesh + relay) de-duplication. */\n broadcastId: string;\n /** The peer whose agent owns (created) the surface. */\n ownerPeerId: string;\n /** The peer that emitted this notification. */\n senderPeerId: string;\n /** The A2UI surface envelope (createSurface / updateDataModel / …). */\n envelope: A2UIEnvelope;\n}\n\n/**\n * Payload for {@link ROOM_METHOD.A2UI_ACTION} — a user interaction on a shared\n * surface, broadcast so the surface owner's agent can process it.\n */\nexport interface RoomA2UIActionEnvelope {\n roomId: string;\n /** Stable id used for cross-path (mesh + relay) de-duplication. */\n broadcastId: string;\n /** The peer that owns the surface (whose agent should process the action). */\n ownerPeerId: string;\n /** The peer that fired the action. */\n senderPeerId: string;\n senderAlias?: string;\n /** The A2UI action (surfaceId, actionId, dataModel). */\n action: A2UIAction;\n}\n\n// =============================================================================\n// A2A Error Codes (spec §5.4)\n// =============================================================================\n\nexport const A2A_ERROR_CODE = {\n TASK_NOT_FOUND: -32001,\n TASK_NOT_CANCELABLE: -32002,\n PUSH_NOTIFICATION_NOT_SUPPORTED: -32003,\n UNSUPPORTED_OPERATION: -32004,\n CONTENT_TYPE_NOT_SUPPORTED: -32005,\n INVALID_AGENT_RESPONSE: -32006,\n\n // Standard JSON-RPC errors\n PARSE_ERROR: -32700,\n INVALID_REQUEST: -32600,\n METHOD_NOT_FOUND: -32601,\n INVALID_PARAMS: -32602,\n INTERNAL_ERROR: -32603,\n} as const;\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\nexport function isJsonRpcRequest(msg: unknown): msg is A2AJsonRpcRequest {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n (msg as any).jsonrpc === \"2.0\" &&\n typeof (msg as any).id === \"string\" &&\n typeof (msg as any).method === \"string\"\n );\n}\n\nexport function isJsonRpcResponse(msg: unknown): msg is A2AJsonRpcResponse {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n (msg as any).jsonrpc === \"2.0\" &&\n typeof (msg as any).id === \"string\" &&\n !(\"method\" in (msg as any))\n );\n}\n\nexport function isJsonRpcNotification(\n msg: unknown,\n): msg is A2AJsonRpcNotification {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n (msg as any).jsonrpc === \"2.0\" &&\n typeof (msg as any).method === \"string\" &&\n !(\"id\" in (msg as any))\n );\n}\n\nexport function isTextPart(part: Part): part is TextPart {\n return \"text\" in part;\n}\n\nexport function isRawPart(part: Part): part is RawPart {\n return \"raw\" in part;\n}\n\nexport function isUrlPart(part: Part): part is UrlPart {\n return \"url\" in part && !(\"raw\" in part) && !(\"text\" in part);\n}\n\nexport function isDataPart(part: Part): part is DataPart {\n return \"data\" in part;\n}\n\n/**\n * Check if a TaskState is terminal (no further transitions allowed).\n */\nexport function isTerminalState(state: TaskState): boolean {\n return TERMINAL_STATES.has(state);\n}\n\n/**\n * Check if a TaskState is interrupted (can resume to WORKING).\n */\nexport function isInterruptedState(state: TaskState): boolean {\n return INTERRUPTED_STATES.has(state);\n}\n","/**\n * AgentCard construction and exchange logic for A2A peer protocol.\n *\n * An AgentCard is exchanged immediately when a WebRTC DataChannel opens,\n * providing capability discovery between peers. It is constructed from\n * the local agent's configuration (name, model, tools).\n *\n * References:\n * - A2A spec §4.4 (Agent Discovery)\n * - ADR: docs/decisions/peer-protocol-a2a-agui.md\n */\n\nimport type {\n AgentCard,\n AgentInterface,\n AgentCapabilities,\n AgentSkill,\n A2AJsonRpcRequest,\n A2AJsonRpcResponse,\n} from \"./peer-protocol.js\";\n\nimport {\n A2A_PROTOCOL_BINDING,\n A2A_PROTOCOL_VERSION,\n A2A_METHOD,\n} from \"./peer-protocol.js\";\nimport { ulid } from \"../../utils/ulid.js\";\n\n// =============================================================================\n// Agent Card Builder\n// =============================================================================\n\nexport interface AgentCardOptions {\n /** Local peer ID (used to construct the interface URL) */\n peerId: string;\n /** Display name for this agent */\n name: string;\n /** Short description of what this agent does */\n description?: string;\n /** Application version */\n version?: string;\n /** Skills/capabilities this agent advertises */\n skills?: AgentSkill[];\n /** Whether streaming is supported */\n streaming?: boolean;\n /** Icon URL (optional) */\n iconUrl?: string;\n}\n\n/**\n * Build an AgentCard from local configuration.\n */\nexport function buildAgentCard(options: AgentCardOptions): AgentCard {\n const iface: AgentInterface = {\n url: `webrtc://${options.peerId}`,\n protocolBinding: A2A_PROTOCOL_BINDING,\n protocolVersion: A2A_PROTOCOL_VERSION,\n };\n\n const capabilities: AgentCapabilities = {\n streaming: options.streaming ?? true,\n pushNotifications: false, // WebRTC DataChannel handles real-time delivery\n };\n\n return {\n name: options.name,\n description: options.description ?? `AI assistant agent (${options.name})`,\n version: options.version ?? \"1.0.0\",\n supportedInterfaces: [iface],\n capabilities,\n defaultInputModes: [\"text/plain\", \"application/json\"],\n defaultOutputModes: [\"text/plain\", \"application/json\"],\n skills: options.skills ?? [],\n iconUrl: options.iconUrl,\n };\n}\n\n// =============================================================================\n// Agent Card Exchange Protocol\n// =============================================================================\n\n/**\n * Create a GetAgentCard JSON-RPC request.\n */\nexport function createGetAgentCardRequest(): A2AJsonRpcRequest {\n return {\n jsonrpc: \"2.0\",\n id: ulid(),\n method: A2A_METHOD.GET_AGENT_CARD,\n };\n}\n\n/**\n * Create a GetAgentCard JSON-RPC response with the local agent card.\n */\nexport function createGetAgentCardResponse(\n requestId: string,\n card: AgentCard,\n): A2AJsonRpcResponse {\n return {\n jsonrpc: \"2.0\",\n id: requestId,\n result: card,\n };\n}\n\n/**\n * Parse a GetAgentCard response to extract the remote agent card.\n * Returns null if the response is malformed.\n */\nexport function parseAgentCardResponse(\n response: A2AJsonRpcResponse,\n): AgentCard | null {\n if (response.error) {\n console.warn(\"GetAgentCard returned error:\", response.error);\n\n return null;\n }\n\n const result = response.result as Record<string, unknown> | undefined;\n if (!result || typeof result !== \"object\") {\n return null;\n }\n\n // Validate minimum required fields\n if (typeof result.name !== \"string\" || typeof result.version !== \"string\") {\n return null;\n }\n\n return result as unknown as AgentCard;\n}\n\n// =============================================================================\n// Peer Card Store (per-connection)\n// =============================================================================\n\n/**\n * Stores remote agent cards received from peers.\n * Keyed by remote peer ID.\n */\nexport class PeerCardStore {\n private _cards = new Map<string, AgentCard>();\n\n /** Clear all stored cards */\n clear(): void {\n this._cards.clear();\n }\n\n /** Remove a peer's card (on disconnect) */\n delete(peerId: string): void {\n this._cards.delete(peerId);\n }\n\n /** Get all stored cards */\n entries(): IterableIterator<[string, AgentCard]> {\n return this._cards.entries();\n }\n\n /** Retrieve a remote peer's agent card */\n get(peerId: string): AgentCard | undefined {\n return this._cards.get(peerId);\n }\n\n /** Get the display name for a peer (falls back to peer ID) */\n getDisplayName(peerId: string): string {\n const card = this._cards.get(peerId);\n\n return card?.name ?? peerId;\n }\n\n /** Check if we have a card for a peer */\n has(peerId: string): boolean {\n return this._cards.has(peerId);\n }\n\n /** Store a remote peer's agent card */\n set(peerId: string, card: AgentCard): void {\n this._cards.set(peerId, card);\n }\n\n /** Check if a peer supports streaming */\n supportsStreaming(peerId: string): boolean {\n const card = this._cards.get(peerId);\n\n return card?.capabilities?.streaming ?? false;\n }\n}\n","/**\n * A2A Task Lifecycle State Machine for WebRTC DataChannel Peer Protocol.\n *\n * Manages per-connection task state following the A2A v1.0 spec:\n * SUBMITTED → WORKING → COMPLETED | FAILED | CANCELED\n * → INPUT_REQUIRED → WORKING\n *\n * Emits AG-UI events during task execution for streaming visibility.\n *\n * References:\n * - A2A spec §4.1.1 (Task), §4.1.3 (TaskState)\n * - ADR: docs/decisions/peer-protocol-a2a-agui.md (Phase 4)\n */\n\nimport type {\n A2ATask,\n A2AMessage,\n TaskStatusUpdateEvent,\n TaskArtifactUpdateEvent,\n Artifact,\n AGUIEvent,\n AGUIRunStarted,\n AGUIRunFinished,\n AGUIRunError,\n AGUITextMessageStart,\n AGUITextMessageContent,\n AGUITextMessageEnd,\n AGUIToolCallStart,\n AGUIToolCallEnd,\n AGUIStateSnapshot,\n SendMessageRequest,\n SendMessageResponse,\n} from \"./peer-protocol.js\";\n\nimport {\n TaskState,\n Role,\n TERMINAL_STATES,\n INTERRUPTED_STATES,\n} from \"./peer-protocol.js\";\n\nimport { ulid } from \"../../utils/ulid.js\";\n\n// =============================================================================\n// Task Manager Configuration\n// =============================================================================\n\nexport interface TaskManagerConfig {\n /** Maximum number of tasks to retain in memory (LRU eviction) */\n maxTasks?: number;\n /** Maximum messages to retain in task history */\n maxHistoryPerTask?: number;\n}\n\nconst DEFAULT_CONFIG: Required<TaskManagerConfig> = {\n maxTasks: 100,\n maxHistoryPerTask: 50,\n};\n\n// =============================================================================\n// Event Emitter Types\n// =============================================================================\n\nexport type TaskEventType = \"statusUpdate\" | \"artifactUpdate\" | \"aguiEvent\";\n\nexport interface TaskEvent {\n type: TaskEventType;\n taskId: string;\n contextId: string;\n payload: TaskStatusUpdateEvent | TaskArtifactUpdateEvent | AGUIEvent;\n}\n\nexport type TaskEventListener = (event: TaskEvent) => void;\n\n// =============================================================================\n// Valid State Transitions\n// =============================================================================\n\n/**\n * Map of allowed transitions: from → Set of valid target states.\n * Based on A2A spec state diagram (§4.1.3).\n */\nconst VALID_TRANSITIONS = new Map<TaskState, Set<TaskState>>([\n [\n TaskState.SUBMITTED,\n new Set([\n TaskState.WORKING,\n TaskState.REJECTED,\n TaskState.CANCELED,\n TaskState.FAILED,\n ]),\n ],\n [\n TaskState.WORKING,\n new Set([\n TaskState.COMPLETED,\n TaskState.FAILED,\n TaskState.CANCELED,\n TaskState.INPUT_REQUIRED,\n TaskState.AUTH_REQUIRED,\n ]),\n ],\n [\n TaskState.INPUT_REQUIRED,\n new Set([TaskState.WORKING, TaskState.CANCELED, TaskState.FAILED]),\n ],\n [\n TaskState.AUTH_REQUIRED,\n new Set([TaskState.WORKING, TaskState.CANCELED, TaskState.FAILED]),\n ],\n]);\n\n// =============================================================================\n// PeerTaskManager\n// =============================================================================\n\n/**\n * Per-connection task lifecycle state machine.\n *\n * Responsibilities:\n * 1. Creates tasks when SendMessage is received without a taskId\n * 2. Transitions states following A2A state diagram\n * 3. Emits AG-UI events during task execution\n * 4. Stores task history (recent messages per task)\n * 5. Handles CancelTask requests gracefully\n */\nexport class PeerTaskManager {\n // LRU order (oldest first)\n private _config: Required<TaskManagerConfig>;\n /** Maps contextId → active (non-terminal) taskId */\n private _contextActiveTask = new Map<string, string>();\n private _listeners: Set<TaskEventListener> = new Set();\n private _taskOrder: string[] = [];\n private _tasks = new Map<string, A2ATask>();\n\n constructor(config?: TaskManagerConfig) {\n this._config = { ...DEFAULT_CONFIG, ...config };\n }\n\n /**\n * Add an artifact to a task.\n */\n addArtifact(taskId: string, artifact: Artifact, append = false): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n if (!task.artifacts) {\n task.artifacts = [];\n }\n\n if (append) {\n const existing = task.artifacts.find(\n (a) => a.artifactId === artifact.artifactId,\n );\n if (existing) {\n existing.parts.push(...artifact.parts);\n } else {\n task.artifacts.push(artifact);\n }\n } else {\n task.artifacts.push(artifact);\n }\n\n const event: TaskArtifactUpdateEvent = {\n taskId: task.id,\n contextId: task.contextId ?? \"\",\n artifact,\n append,\n lastChunk: false,\n };\n\n this._emit({\n type: \"artifactUpdate\",\n taskId: task.id,\n contextId: task.contextId ?? \"\",\n payload: event,\n });\n }\n\n /**\n * Cancel a task. Returns true if cancellation was accepted.\n */\n cancelTask(taskId: string): boolean {\n const task = this._tasks.get(taskId);\n if (!task) {\n return false;\n }\n\n if (TERMINAL_STATES.has(task.status.state)) {\n return false; // Already terminal, cannot cancel\n }\n\n this._transitionState(task, TaskState.CANCELED, {\n messageId: ulid(),\n role: Role.AGENT,\n parts: [{ text: \"Task canceled by peer request.\" }],\n });\n\n return true;\n }\n\n /** Clear all tasks and state */\n clear(): void {\n this._tasks.clear();\n this._taskOrder = [];\n this._contextActiveTask.clear();\n }\n\n /**\n * Emit a RUN_ERROR AG-UI event for a task.\n */\n emitRunError(taskId: string, message: string, code?: string): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUIRunError = {\n type: \"RUN_ERROR\",\n message,\n code,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n /**\n * Emit a RUN_FINISHED AG-UI event for a task.\n */\n emitRunFinished(taskId: string): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUIRunFinished = {\n type: \"RUN_FINISHED\",\n threadId: task.contextId ?? task.id,\n runId: task.id,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n // ---------------------------------------------------------------------------\n // AG-UI Event Emission Helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Emit a RUN_STARTED AG-UI event for a task.\n */\n emitRunStarted(taskId: string): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUIRunStarted = {\n type: \"RUN_STARTED\",\n threadId: task.contextId ?? task.id,\n runId: task.id,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n /**\n * Emit STATE_SNAPSHOT AG-UI event (shared ground truth).\n */\n emitStateSnapshot(taskId: string, snapshot: Record<string, unknown>): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUIStateSnapshot = {\n type: \"STATE_SNAPSHOT\",\n snapshot,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n /**\n * Emit TEXT_MESSAGE_CONTENT AG-UI event (streaming delta).\n */\n emitTextMessageContent(\n taskId: string,\n messageId: string,\n delta: string,\n ): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUITextMessageContent = {\n type: \"TEXT_MESSAGE_CONTENT\",\n messageId,\n delta,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n /**\n * Emit TEXT_MESSAGE_END AG-UI event.\n */\n emitTextMessageEnd(taskId: string, messageId: string): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUITextMessageEnd = {\n type: \"TEXT_MESSAGE_END\",\n messageId,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n /**\n * Emit TEXT_MESSAGE_START AG-UI event.\n */\n emitTextMessageStart(\n taskId: string,\n messageId: string,\n role: \"assistant\" | \"user\" = \"assistant\",\n ): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUITextMessageStart = {\n type: \"TEXT_MESSAGE_START\",\n messageId,\n role,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n /**\n * Emit TOOL_CALL_END AG-UI event.\n */\n emitToolCallEnd(taskId: string, toolCallId: string): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUIToolCallEnd = {\n type: \"TOOL_CALL_END\",\n toolCallId,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n /**\n * Emit TOOL_CALL_START AG-UI event.\n */\n emitToolCallStart(\n taskId: string,\n toolCallId: string,\n toolCallName: string,\n parentMessageId?: string,\n ): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n const event: AGUIToolCallStart = {\n type: \"TOOL_CALL_START\",\n toolCallId,\n toolCallName,\n parentMessageId,\n timestamp: Date.now(),\n };\n\n this._emitAGUI(task, event);\n }\n\n /** Get the active task for a context, if any */\n getActiveTaskForContext(contextId: string): A2ATask | undefined {\n const taskId = this._contextActiveTask.get(contextId);\n if (!taskId) {\n return undefined;\n }\n\n return this._tasks.get(taskId);\n }\n\n /** Get active (non-terminal) tasks */\n getActiveTasks(): A2ATask[] {\n return Array.from(this._tasks.values()).filter(\n (t) => !TERMINAL_STATES.has(t.status.state),\n );\n }\n\n // ---------------------------------------------------------------------------\n // Query\n // ---------------------------------------------------------------------------\n\n /** Get all tasks (for debugging/introspection) */\n getAllTasks(): A2ATask[] {\n return Array.from(this._tasks.values());\n }\n\n /**\n * Get a task by ID. Returns undefined if not found.\n */\n getTask(taskId: string): A2ATask | undefined {\n return this._tasks.get(taskId);\n }\n\n // ---------------------------------------------------------------------------\n // Task Lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Handle an incoming SendMessage request. Creates or continues a task.\n * Returns the task in its current state (for the JSON-RPC response).\n */\n handleSendMessage(request: SendMessageRequest): SendMessageResponse {\n const message = request.message;\n const contextId = message.contextId ?? ulid();\n const taskId = message.taskId ?? this._contextActiveTask.get(contextId);\n\n if (taskId && this._tasks.has(taskId)) {\n // Continue existing task\n\n return this._continueTask(taskId, message);\n }\n\n // Create new task\n\n return this._createTask(contextId, message);\n }\n\n /**\n * Transition a task to COMPLETED state with an optional final message.\n */\n markCompleted(taskId: string, message?: A2AMessage): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n this._transitionState(task, TaskState.COMPLETED, message);\n }\n\n /**\n * Transition a task to FAILED state with an error message.\n */\n markFailed(taskId: string, errorMessage: string): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n this._transitionState(task, TaskState.FAILED, {\n messageId: ulid(),\n role: Role.AGENT,\n parts: [{ text: errorMessage }],\n });\n }\n\n /**\n * Transition a task to INPUT_REQUIRED state.\n */\n markInputRequired(taskId: string, message?: A2AMessage): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n this._transitionState(task, TaskState.INPUT_REQUIRED, message);\n }\n\n /**\n * Transition a task to WORKING state. Called when the local agent\n * starts processing the task.\n */\n markWorking(taskId: string): void {\n const task = this._tasks.get(taskId);\n if (!task) {\n return;\n }\n\n this._transitionState(task, TaskState.WORKING);\n }\n\n /** Unsubscribe from task events */\n off(listener: TaskEventListener): void {\n this._listeners.delete(listener);\n }\n\n // ---------------------------------------------------------------------------\n // Event Subscription\n // ---------------------------------------------------------------------------\n\n /** Subscribe to task events */\n on(listener: TaskEventListener): void {\n this._listeners.add(listener);\n }\n\n private _addTask(task: A2ATask): void {\n this._tasks.set(task.id, task);\n this._taskOrder.push(task.id);\n\n // Evict oldest tasks if over limit\n while (this._taskOrder.length > this._config.maxTasks) {\n const oldestId = this._taskOrder.shift()!;\n const oldest = this._tasks.get(oldestId);\n // Only evict terminal tasks; keep active ones\n if (oldest && TERMINAL_STATES.has(oldest.status.state)) {\n this._tasks.delete(oldestId);\n if (oldest.contextId) {\n this._contextActiveTask.delete(oldest.contextId);\n }\n } else {\n // Put it back at the front — we'll try the next one\n this._taskOrder.unshift(oldestId);\n\n break;\n }\n }\n }\n\n private _continueTask(\n taskId: string,\n message: A2AMessage,\n ): SendMessageResponse {\n const task = this._tasks.get(taskId)!;\n\n // If the task was in an interrupted state, transition back to WORKING\n if (INTERRUPTED_STATES.has(task.status.state)) {\n this._transitionState(task, TaskState.WORKING);\n }\n\n // Add to history\n if (!task.history) {\n task.history = [];\n }\n\n task.history.push(message);\n\n // Trim history if needed\n if (task.history.length > this._config.maxHistoryPerTask) {\n task.history = task.history.slice(-this._config.maxHistoryPerTask);\n }\n\n // Touch LRU\n this._touchTask(taskId);\n\n return { task };\n }\n\n // ---------------------------------------------------------------------------\n // Internal\n // ---------------------------------------------------------------------------\n\n private _createTask(\n contextId: string,\n message: A2AMessage,\n ): SendMessageResponse {\n const taskId = ulid();\n\n const task: A2ATask = {\n id: taskId,\n contextId,\n status: {\n state: TaskState.SUBMITTED,\n timestamp: new Date().toISOString(),\n },\n history: [message],\n };\n\n this._addTask(task);\n this._contextActiveTask.set(contextId, taskId);\n\n // Emit status update\n this._emitStatusUpdate(task);\n\n return { task };\n }\n\n private _emit(event: TaskEvent): void {\n for (const listener of this._listeners) {\n try {\n listener(event);\n } catch (err) {\n console.error(\"PeerTaskManager: listener error\", err);\n }\n }\n }\n\n private _emitAGUI(task: A2ATask, event: AGUIEvent): void {\n this._emit({\n type: \"aguiEvent\",\n taskId: task.id,\n contextId: task.contextId ?? \"\",\n payload: event,\n });\n }\n\n private _emitStatusUpdate(task: A2ATask): void {\n const event: TaskStatusUpdateEvent = {\n taskId: task.id,\n contextId: task.contextId ?? \"\",\n status: task.status,\n };\n\n this._emit({\n type: \"statusUpdate\",\n taskId: task.id,\n contextId: task.contextId ?? \"\",\n payload: event,\n });\n }\n\n private _touchTask(taskId: string): void {\n const idx = this._taskOrder.indexOf(taskId);\n if (idx !== -1) {\n this._taskOrder.splice(idx, 1);\n this._taskOrder.push(taskId);\n }\n }\n\n private _transitionState(\n task: A2ATask,\n newState: TaskState,\n message?: A2AMessage,\n ): void {\n const currentState = task.status.state;\n\n // Validate transition\n const allowed = VALID_TRANSITIONS.get(currentState);\n if (allowed && !allowed.has(newState)) {\n console.warn(\n `PeerTaskManager: invalid transition ${currentState} → ${newState} for task ${task.id}`,\n );\n\n return;\n }\n\n // Cannot transition from terminal states\n if (TERMINAL_STATES.has(currentState)) {\n console.warn(\n `PeerTaskManager: task ${task.id} is in terminal state ${currentState}, cannot transition`,\n );\n\n return;\n }\n\n task.status = {\n state: newState,\n message,\n timestamp: new Date().toISOString(),\n };\n\n // If transitioning to a terminal state, remove from active context map\n if (TERMINAL_STATES.has(newState) && task.contextId) {\n if (this._contextActiveTask.get(task.contextId) === task.id) {\n this._contextActiveTask.delete(task.contextId);\n }\n }\n\n this._emitStatusUpdate(task);\n }\n}\n","import { Signal } from \"signal-polyfill\";\n\nimport {\n PEERJS_DEFAULT_HOST,\n PEERJS_DEFAULT_PATH,\n PEERJS_DEFAULT_PORT,\n PEERJS_DEFAULT_SECURE,\n} from \"../../config/config.js\";\n\nimport { getDb } from \"../../db/db.js\";\nimport { groupFileExists } from \"../../storage/groupFileExists.js\";\nimport { readGroupFileBytes } from \"../../storage/readGroupFileBytes.js\";\nimport { writeGroupFileBytes } from \"../../storage/writeGroupFileBytes.js\";\nimport { ulid } from \"../../utils/ulid.js\";\n\nimport type { DataConnection, Peer, PeerError } from \"peerjs\";\nimport type { MessageAttachment } from \"../../content/types.js\";\nimport type { A2UIAction, A2UIEnvelope } from \"../../ui/a2ui/types.js\";\nimport type {\n Channel,\n ChannelMessageCallback,\n ChannelTypingCallback,\n RoomMeta,\n} from \"./types.js\";\n\n// A2A Protocol imports\nimport {\n PeerCardStore,\n buildAgentCard,\n createGetAgentCardRequest,\n createGetAgentCardResponse,\n parseAgentCardResponse,\n} from \"./peer-agent-card.js\";\n\nimport {\n A2A_ERROR_CODE,\n A2A_METHOD,\n A2A_STREAM_METHOD,\n AGUI_METHOD,\n Role,\n TERMINAL_STATES,\n isJsonRpcRequest,\n isJsonRpcResponse,\n} from \"./peer-protocol.js\";\n\nimport { PeerTaskManager } from \"./peer-task-manager.js\";\n\nimport type {\n A2AJsonRpcNotification,\n A2AJsonRpcRequest,\n A2AJsonRpcResponse,\n AGUIEvent,\n AgentCard,\n SendMessageRequest,\n TaskStatusUpdateEvent,\n} from \"./peer-protocol.js\";\n\n/**\n * Module-level singleton so the chat UI can import and subscribe to it\n * directly without going through the non-reactive orchestratorStore.orchestrator chain.\n */\nexport const transferProgressSignal = new Signal.State<{\n count: number;\n total: number;\n direction: \"send\" | \"receive\";\n} | null>(null);\n\nlet transferProgressClearTimeout: ReturnType<typeof setTimeout> | null = null;\n\n/**\n * Update transfer progress signal and cancel any pending delayed clear timer.\n */\nexport function updateTransferProgress(\n progress: {\n count: number;\n total: number;\n direction: \"send\" | \"receive\";\n } | null,\n): void {\n if (transferProgressClearTimeout !== null) {\n clearTimeout(transferProgressClearTimeout);\n transferProgressClearTimeout = null;\n }\n transferProgressSignal.set(progress);\n}\n\n/**\n * Clear transfer progress after a delay, ensuring any existing timer is reset.\n */\nexport function clearTransferProgressDelayed(delayMs = 1500): void {\n if (transferProgressClearTimeout !== null) {\n clearTimeout(transferProgressClearTimeout);\n }\n transferProgressClearTimeout = setTimeout(() => {\n transferProgressSignal.set(null);\n transferProgressClearTimeout = null;\n }, delayMs);\n}\n\n/** Maximum chunk size in bytes for application-level file transfers (15 KB to stay safely under PeerJS 16,300 MTU after msgpack framing) */\nexport const FILE_CHUNK_SIZE = 15360;\n\n/** Threshold for WebRTC DataChannel bufferedAmount backpressure (64 KB) */\nexport const FILE_BUFFER_DRAIN_THRESHOLD = 65536;\n\ninterface InboundFileTransfer {\n transferId: string;\n name: string;\n mimeType: string;\n size: number;\n totalChunks: number;\n receivedChunks: Map<number, Uint8Array>;\n receivedBytes: number;\n targetGroupId?: string;\n}\n\nexport interface PeerJsServerConfig {\n host?: string;\n port?: number;\n path?: string;\n secure?: boolean;\n iceServers?: RTCIceServer[];\n}\n\n/**\n * A PeerJS-based WebRTC data-channel messaging channel.\n *\n * - Prefix: `peer:`\n * - groupId format: `peer:<remote-peer-id>`\n * - Uses the public PeerJS cloud signaling server by default (no self-hosted\n * server required). A custom signaling server can be passed via serverConfig.\n * - Trusted peer IDs: when non-empty, only accepts connections from listed IDs.\n * When empty, accepts connections from any peer.\n */\nexport class PeerJsChannel implements Channel {\n private static readonly _RECONNECT_BASE_MS = 1000;\n private static readonly _RECONNECT_MAX_MS = 60_000;\n\n /** Signal of connected remote peer IDs */\n connectedPeersSignal = new Signal.State<string[]>([]);\n\n /** Active data connections keyed by remote peer ID */\n connections: Map<string, DataConnection> = new Map();\n messageCallback: ChannelMessageCallback | null = null;\n\n myPeerId: string = \"\";\n\n // A2A Protocol state\n /** Remote agent cards keyed by peer ID */\n readonly peerCards = new PeerCardStore();\n\n running = false;\n serverConfig: PeerJsServerConfig = {};\n\n /** Delegate to the module-level singleton for reactivity across components */\n readonly transferProgressSignal = transferProgressSignal;\n trustedPeerIds: Set<string> = new Set();\n type: Channel[\"type\"] = \"peerjs\";\n typingCallback: ChannelTypingCallback | null = null;\n\n /** Maps inbound original canonical filenames to their locally renamed final filenames */\n private _inboundRemap = new Map<string, string>();\n /** Local agent card (constructed on start) */\n private _localCard: AgentCard | null = null;\n\n /** Callback invoked when a remote peer signals task completion */\n private _onTaskCompleteCallback: ((groupId: string) => void) | null = null;\n\n private peer: InstanceType<typeof Peer> | null = null;\n\n private _pendingInboundFile: {\n name: string;\n mimeType: string;\n size: number;\n } | null = null;\n /** Pending JSON-RPC response callbacks keyed by request ID */\n private _pendingRequests = new Map<\n string,\n {\n resolve: (resp: A2AJsonRpcResponse) => void;\n timer: ReturnType<typeof setTimeout>;\n }\n >();\n\n // Reconnection backoff state\n private _reconnectAttempts = 0;\n private _reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\n /** Handler for inbound multi-party room notifications (`room/*`). */\n private _roomNotificationHandler:\n | ((fromPeerId: string, method: string, params: unknown) => void)\n | null = null;\n /** Per-connection task managers keyed by remote peer ID */\n private _taskManagers = new Map<string, PeerTaskManager>();\n /** Inbound multi-chunk file transfers keyed by transferId */\n private _inboundTransfers = new Map<string, InboundFileTransfer>();\n\n constructor() {\n if (typeof globalThis.addEventListener === \"function\") {\n globalThis.addEventListener(\"peerjs-dc-handle-chunk\", (e: any) => {\n if (e?.detail?.chunkInfo) {\n // If an application-level multi-chunk file transfer is in progress,\n // ignore underlying PeerJS binarypack frame chunks to prevent fighting/flickering.\n if (this._inboundTransfers.size > 0) {\n return;\n }\n\n // PeerJS dispatches `count` BEFORE incrementing it (0-indexed pre-increment),\n // so the actual number of received chunks is count + 1.\n const { count: rawCount, total } = e.detail.chunkInfo;\n const received = rawCount + 1;\n updateTransferProgress({\n count: received,\n total,\n direction: \"receive\",\n });\n\n if (received >= total) {\n clearTransferProgressDelayed(1500);\n }\n }\n });\n }\n }\n\n /**\n * Mark the active task for a peer groupId as COMPLETED.\n * Sends a terminal `tasks/statusUpdate` notification to the remote peer,\n * signaling that no further responses are expected.\n *\n * @returns true if a task was completed, false if no active task exists.\n */\n completeActiveTask(groupId: string): boolean {\n const remotePeerId = groupId.replace(/^peer:/, \"\");\n const tm = this._taskManagers.get(remotePeerId);\n if (!tm) {\n return false;\n }\n\n const activeTasks = tm.getActiveTasks();\n if (activeTasks.length === 0) {\n return false;\n }\n\n // Complete the most recent active task\n const task = activeTasks[activeTasks.length - 1];\n tm.markWorking(task.id);\n tm.markCompleted(task.id);\n\n return true;\n }\n\n // ---------------------------------------------------------------------------\n // Public API\n // ---------------------------------------------------------------------------\n\n configure(\n myPeerId: string,\n trustedPeerIds: string[],\n serverConfig: PeerJsServerConfig = {},\n ): void {\n this.myPeerId = myPeerId.trim();\n this.trustedPeerIds = new Set(\n trustedPeerIds.map((id) => id.trim()).filter(Boolean),\n );\n this.serverConfig = serverConfig;\n }\n\n /** Best-effort: ensure an outbound connection to the peer is opened. */\n connectPeer(peerId: string): void {\n this._getOrOpenConnection(peerId);\n }\n\n /**\n * Get the task manager for a peer (creates one if needed).\n */\n getTaskManager(remotePeerId: string): PeerTaskManager {\n let tm = this._taskManagers.get(remotePeerId);\n if (!tm) {\n tm = new PeerTaskManager();\n this._taskManagers.set(remotePeerId, tm);\n tm.on((event) => {\n this._forwardTaskEvent(remotePeerId, event);\n });\n }\n\n return tm;\n }\n\n isConfigured(): boolean {\n return this.myPeerId.length > 0;\n }\n\n /** Whether a direct, open DataConnection to the peer currently exists. */\n isPeerConnected(peerId: string): boolean {\n const conn = this.connections.get(peerId);\n\n return !!conn && !!(conn as any).open;\n }\n\n onMessage(callback: ChannelMessageCallback): void {\n this.messageCallback = callback;\n }\n\n /**\n * Register a callback invoked when a remote peer sends a terminal\n * task status update (COMPLETED, FAILED, CANCELED). This allows the\n * orchestrator to suppress further auto-triggers for that conversation.\n */\n onTaskComplete(callback: (groupId: string) => void): void {\n this._onTaskCompleteCallback = callback;\n }\n\n onTyping(callback: ChannelTypingCallback): void {\n this.typingCallback = callback;\n }\n\n /**\n * Send a JSON-RPC notification object to a single peer. If the connection is\n * still opening, the send is deferred until it opens. Returns true when the\n * send was dispatched or queued, false when no connection could be created.\n */\n sendRoomNotification(peerId: string, notification: unknown): boolean {\n const conn = this._getOrOpenConnection(peerId);\n if (!conn) {\n return false;\n }\n\n if ((conn as any).open) {\n try {\n conn.send(notification);\n\n return true;\n } catch (err) {\n console.error(\n `PeerJsChannel: failed to send room notification to ${peerId}:`,\n err,\n );\n\n return false;\n }\n }\n\n // Connection still opening — flush once it is ready.\n this._waitForOpen(conn)\n .then(() => {\n try {\n conn.send(notification);\n } catch (err) {\n console.error(\n `PeerJsChannel: failed to flush room notification to ${peerId}:`,\n err,\n );\n }\n })\n .catch(() => {\n // Connection failed to open; nothing more to do.\n });\n\n return true;\n }\n\n // ---------------------------------------------------------------------------\n // Multi-party room transport\n // ---------------------------------------------------------------------------\n\n /**\n * Register the handler for inbound `room/*` JSON-RPC notifications. The\n * {@link RoomManager} uses this to receive join/roster/leave/message/invite/\n * relay traffic carried over the existing DataChannel.\n */\n setRoomNotificationHandler(\n handler: (fromPeerId: string, method: string, params: unknown) => void,\n ): void {\n this._roomNotificationHandler = handler;\n }\n\n /**\n * Stream file attachments to all other members in a room over WebRTC DataConnections,\n * tagged with the room groupId.\n */\n async sendAttachmentsToRoom(\n room: RoomMeta,\n groupId: string,\n attachments: MessageAttachment[],\n ): Promise<void> {\n const me = this.myPeerId;\n const fileAttachments = (attachments || []).filter(\n (a): a is MessageAttachment & { path: string } => !!a.path,\n );\n if (fileAttachments.length === 0) {\n return;\n }\n\n try {\n const db = await getDb();\n for (const att of fileAttachments) {\n let bytes: Uint8Array;\n try {\n bytes = await readGroupFileBytes(db, groupId, att.path);\n } catch (err) {\n console.warn(\n `PeerJsChannel: failed to read file ${att.path} for room:`,\n err,\n );\n continue;\n }\n\n const canonicalName = att.path;\n const mimeType = att.mimeType || \"application/octet-stream\";\n const totalChunks = Math.max(\n 1,\n Math.ceil(bytes.length / FILE_CHUNK_SIZE),\n );\n\n for (const member of room.members) {\n if (member.peerId === me) {\n continue;\n }\n\n const conn = this._getOrOpenConnection(member.peerId);\n if (!conn) {\n continue;\n }\n\n try {\n await this._waitForOpen(conn);\n const transferId = ulid();\n\n conn.send({\n type: \"__file_header\",\n id: transferId,\n name: canonicalName,\n mimeType,\n size: bytes.length,\n totalChunks,\n chunkSize: FILE_CHUNK_SIZE,\n groupId,\n });\n\n for (let i = 0; i < totalChunks; i++) {\n const start = i * FILE_CHUNK_SIZE;\n const end = Math.min(start + FILE_CHUNK_SIZE, bytes.length);\n const chunk = bytes.subarray(start, end);\n const chunkBuf = chunk.buffer.slice(\n chunk.byteOffset,\n chunk.byteOffset + chunk.byteLength,\n );\n\n conn.send({\n type: \"__file_chunk\",\n id: transferId,\n name: canonicalName,\n index: i,\n totalChunks,\n data: chunkBuf,\n });\n\n updateTransferProgress({\n count: i + 1,\n total: totalChunks,\n direction: \"send\",\n });\n\n await this._waitForBufferDrain(conn);\n }\n\n clearTransferProgressDelayed(1500);\n } catch (err) {\n console.warn(\n `PeerJsChannel: failed to stream file ${att.path} to room member ${member.peerId}:`,\n err,\n );\n }\n }\n }\n } catch (err) {\n console.error(\n \"PeerJsChannel: failed to access DB for room file transfer\",\n err,\n );\n }\n }\n\n setTyping(groupId: string, typing: boolean): void {\n const remotePeerId = groupId.replace(/^peer:/, \"\");\n const conn = this.connections.get(remotePeerId);\n if (!conn) {\n return;\n }\n\n try {\n conn.send({ type: \"typing\", typing });\n } catch {\n // silently ignore typing send errors\n }\n }\n\n start(): void {\n if (!this.isConfigured() || this.running) {\n return;\n }\n\n this.running = true;\n this._localCard = buildAgentCard({\n peerId: this.myPeerId,\n name: this.myPeerId,\n description: \"ShadowClaw AI assistant\",\n streaming: true,\n });\n this._initPeer();\n }\n\n ensureConnected(force: boolean = false): void {\n if (!this.running || !this.isConfigured()) {\n return;\n }\n\n if (this._reconnectTimer !== null) {\n clearTimeout(this._reconnectTimer);\n this._reconnectTimer = null;\n }\n this._reconnectAttempts = 0;\n\n const peer = this.peer as any;\n if (!peer || peer.destroyed || (force && !peer.open)) {\n if (peer && !peer.destroyed) {\n try {\n peer.destroy();\n } catch (_) {}\n }\n this.peer = null;\n this._initPeer();\n } else if (peer.disconnected) {\n try {\n peer.reconnect?.();\n } catch {\n this._initPeer();\n }\n }\n }\n\n stop(): void {\n this.running = false;\n if (this._reconnectTimer !== null) {\n clearTimeout(this._reconnectTimer);\n this._reconnectTimer = null;\n }\n\n this._reconnectAttempts = 0;\n this.connections.forEach((conn) => {\n try {\n conn.close();\n } catch {\n // ignore\n }\n });\n this.connections.clear();\n this.peerCards.clear();\n this._taskManagers.clear();\n this._pendingRequests.forEach(({ timer }) => clearTimeout(timer));\n this._pendingRequests.clear();\n this._updateConnectedPeersSignal();\n\n if (this.peer) {\n try {\n this.peer.destroy();\n } catch {\n // ignore\n }\n\n this.peer = null;\n }\n }\n\n async send(\n groupId: string,\n text: string,\n attachments?: MessageAttachment[],\n ): Promise<void> {\n const remotePeerId = groupId.replace(/^peer:/, \"\");\n const conn = this._getOrOpenConnection(remotePeerId);\n\n if (!conn) {\n console.warn(\n `PeerJsChannel: no connection available for ${remotePeerId}`,\n );\n\n return;\n }\n\n try {\n // Wait for connection to be open if it just was created\n await this._waitForOpen(conn);\n\n // Extract markdown local links from the outgoing text\n const { attachments: markdownAttachments } =\n extractMarkdownAttachments(text);\n\n const allAttachments: { path: string; mimeType?: string }[] = [\n ...(attachments || []).filter(\n (a): a is MessageAttachment & { path: string } => !!a.path,\n ),\n ...markdownAttachments.map((ma) => ({\n path: ma.path,\n mimeType: \"application/octet-stream\",\n })),\n ];\n\n // Build a map of oldPath -> canonical hash-prefixed basename.\n // The sender is responsible for computing the canonical name so both\n // sides end up with the same filename in their workspaces.\n const pathRemap = new Map<string, string>();\n const fileParts: any[] = [];\n\n try {\n const db = await getDb();\n for (const att of allAttachments) {\n if (!att.path) {\n continue;\n }\n\n try {\n const bytes = await readGroupFileBytes(db, groupId, att.path);\n const canonicalName = att.path;\n\n if (!pathRemap.has(att.path)) {\n pathRemap.set(att.path, canonicalName);\n }\n\n const mimeType =\n (att as any).mimeType || \"application/octet-stream\";\n\n const transferId = ulid();\n const totalChunks = Math.max(\n 1,\n Math.ceil(bytes.length / FILE_CHUNK_SIZE),\n );\n\n // Send the header\n conn.send({\n type: \"__file_header\",\n id: transferId,\n name: canonicalName,\n mimeType,\n size: bytes.length,\n totalChunks,\n chunkSize: FILE_CHUNK_SIZE,\n groupId,\n });\n\n // Send each chunk frame sequentially with flow control\n for (let i = 0; i < totalChunks; i++) {\n const start = i * FILE_CHUNK_SIZE;\n const end = Math.min(start + FILE_CHUNK_SIZE, bytes.length);\n const chunk = bytes.subarray(start, end);\n\n // Copy into a clean ArrayBuffer slice for transfer\n const chunkBuf = chunk.buffer.slice(\n chunk.byteOffset,\n chunk.byteOffset + chunk.byteLength,\n );\n\n conn.send({\n type: \"__file_chunk\",\n id: transferId,\n name: canonicalName,\n index: i,\n totalChunks,\n data: chunkBuf,\n });\n\n updateTransferProgress({\n count: i + 1,\n total: totalChunks,\n direction: \"send\",\n });\n\n // Apply backpressure if the DataChannel buffer is filling up\n await this._waitForBufferDrain(conn);\n }\n\n clearTransferProgressDelayed(1500);\n\n // Prepare the metadata part for the A2A envelope\n fileParts.push({\n kind: \"file\",\n name: canonicalName,\n mimeType,\n size: bytes.length,\n });\n } catch (err) {\n console.warn(\n `PeerJsChannel: failed to process file ${att.path}:`,\n err,\n );\n }\n }\n } catch (err) {\n console.error(\"PeerJsChannel: failed to access DB\", err);\n }\n\n // Rewrite the outgoing text so links point to the canonical names\n let outText = text;\n for (const [oldPath, canonicalName] of pathRemap) {\n const escapedOld = oldPath.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n outText = outText.replace(\n new RegExp(`(!?\\\\[.*?\\\\])\\\\(${escapedOld}\\\\)`, \"g\"),\n `$1(${canonicalName})`,\n );\n }\n\n // File parts go first so the receiver processes them before text\n const parts = [...fileParts, { kind: \"text\", text: outText }];\n\n // Use A2A SendMessage (JSON-RPC request with id) so the remote peer's\n // task manager tracks the conversation lifecycle and can signal completion.\n const requestId = ulid();\n const envelope: A2AJsonRpcRequest = {\n jsonrpc: \"2.0\",\n id: requestId,\n method: A2A_METHOD.SEND_MESSAGE,\n params: {\n message: {\n messageId: ulid(),\n role: Role.AGENT,\n parts,\n },\n } satisfies SendMessageRequest,\n };\n\n conn.send(envelope);\n\n // Register pending request so we can process the task response\n this._registerPendingRequest(requestId, (_response) => {\n // Response contains the task state — no action needed here,\n // the remote peer's task manager handles lifecycle.\n });\n } catch (err) {\n console.error(`PeerJsChannel: send failed for ${remotePeerId}:`, err);\n window.dispatchEvent(\n new CustomEvent(\"shadow-claw-peer-error\", {\n detail: {\n remotePeerId,\n error: err instanceof Error ? err.message : String(err),\n },\n }),\n );\n }\n }\n\n /**\n * Send an A2UI surface envelope to a peer as a `kind: \"a2ui\"` A2A part.\n */\n async sendA2UI(groupId: string, envelope: A2UIEnvelope): Promise<void> {\n const remotePeerId = groupId.replace(/^peer:/, \"\");\n const conn = this._getOrOpenConnection(remotePeerId);\n\n if (!conn) {\n console.warn(\n `PeerJsChannel.sendA2UI: no connection available for ${remotePeerId}`,\n );\n\n return;\n }\n\n try {\n await this._waitForOpen(conn);\n\n const a2uiEnvelopeObj = {\n jsonrpc: \"2.0\",\n method: \"message/send\",\n id: ulid(),\n params: {\n message: {\n role: \"agent\",\n parts: [{ kind: \"a2ui\", envelope }],\n },\n },\n };\n conn.send(a2uiEnvelopeObj);\n } catch (err) {\n console.error(`PeerJsChannel.sendA2UI: failed for ${remotePeerId}:`, err);\n }\n }\n\n /**\n * Send an A2UI action back to the peer (fired when the local user interacts\n * with a rendered surface — e.g. clicks a Button).\n */\n async sendA2UIAction(groupId: string, action: A2UIAction): Promise<void> {\n const remotePeerId = groupId.replace(/^peer:/, \"\");\n const conn = this._getOrOpenConnection(remotePeerId);\n\n if (!conn) {\n console.warn(\n `PeerJsChannel.sendA2UIAction: no connection available for ${remotePeerId}`,\n );\n\n return;\n }\n\n try {\n await this._waitForOpen(conn);\n\n const actionEnvelope = {\n jsonrpc: \"2.0\",\n method: \"message/send\",\n id: ulid(),\n params: {\n message: {\n role: \"user\",\n parts: [{ kind: \"a2ui-action\", action }],\n },\n },\n };\n conn.send(actionEnvelope);\n } catch (err) {\n console.error(\n `PeerJsChannel.sendA2UIAction: failed for ${remotePeerId}:`,\n err,\n );\n }\n }\n\n // ---------------------------------------------------------------------------\n // A2A Protocol Handlers\n // ---------------------------------------------------------------------------\n\n /**\n * Exchange agent cards on connection open.\n * Sends our card request and stores the remote peer's card.\n */\n private _exchangeAgentCards(\n remotePeerId: string,\n conn: DataConnection,\n ): void {\n if (!this._localCard) {\n return;\n }\n\n const request = createGetAgentCardRequest();\n conn.send(request);\n\n // Register pending request for the response\n this._registerPendingRequest(request.id, (response) => {\n const card = parseAgentCardResponse(response);\n if (card) {\n this.peerCards.set(remotePeerId, card);\n console.log(\n `PeerJsChannel: received AgentCard from ${remotePeerId}: \"${card.name}\"`,\n );\n }\n });\n }\n\n /**\n * Forward task manager events over the DataChannel as notifications.\n */\n private _forwardTaskEvent(\n remotePeerId: string,\n event: {\n type: string;\n taskId: string;\n contextId: string;\n payload: unknown;\n },\n ): void {\n const conn = this.connections.get(remotePeerId);\n if (!conn) {\n return;\n }\n\n let method: string;\n switch (event.type) {\n case \"statusUpdate\":\n method = A2A_STREAM_METHOD.STATUS_UPDATE;\n\n break;\n case \"artifactUpdate\":\n method = A2A_STREAM_METHOD.ARTIFACT_UPDATE;\n\n break;\n case \"aguiEvent\":\n method = AGUI_METHOD.EVENT;\n\n break;\n default:\n return;\n }\n\n const notification: A2AJsonRpcNotification = {\n jsonrpc: \"2.0\",\n method,\n params: event.payload,\n };\n\n try {\n conn.send(notification);\n } catch (err) {\n console.error(\n `PeerJsChannel: failed to forward ${event.type} to ${remotePeerId}:`,\n err,\n );\n }\n }\n\n /**\n * Returns an existing open DataConnection for the given remote peer ID,\n * or initiates a new outbound connection.\n */\n private _getOrOpenConnection(remotePeerId: string): DataConnection | null {\n const existing = this.connections.get(remotePeerId);\n if (existing) {\n return existing;\n }\n\n if (!this.peer) {\n return null;\n }\n\n try {\n const conn = this.peer.connect(remotePeerId, {\n reliable: true,\n serialization: \"binary\",\n });\n\n // PeerJS returns undefined if the peer is disconnected/destroyed\n if (!conn) {\n return null;\n }\n\n this._handleIncomingConnection(conn);\n\n return conn;\n } catch (err) {\n console.error(\n `PeerJsChannel: failed to connect to ${remotePeerId}:`,\n err,\n );\n\n return null;\n }\n }\n\n /**\n * Handle A2A CancelTask request.\n */\n private _handleA2ACancelTask(\n remotePeerId: string,\n request: A2AJsonRpcRequest,\n ): void {\n const params = request.params as { taskId?: string } | undefined;\n if (!params?.taskId) {\n this._sendJsonRpcError(remotePeerId, request.id, {\n code: A2A_ERROR_CODE.INVALID_PARAMS,\n message: \"Missing taskId in CancelTask params\",\n });\n\n return;\n }\n\n const taskManager = this._taskManagers.get(remotePeerId);\n if (!taskManager) {\n this._sendJsonRpcError(remotePeerId, request.id, {\n code: A2A_ERROR_CODE.TASK_NOT_FOUND,\n message: `Task not found: ${params.taskId}`,\n });\n\n return;\n }\n\n const success = taskManager.cancelTask(params.taskId);\n if (!success) {\n this._sendJsonRpcError(remotePeerId, request.id, {\n code: A2A_ERROR_CODE.TASK_NOT_CANCELABLE,\n message: `Task not cancelable: ${params.taskId}`,\n });\n\n return;\n }\n\n const conn = this.connections.get(remotePeerId);\n if (conn) {\n const task = taskManager.getTask(params.taskId);\n const rpcResponse: A2AJsonRpcResponse = {\n jsonrpc: \"2.0\",\n id: request.id,\n result: { task },\n };\n conn.send(rpcResponse);\n }\n }\n\n /**\n * Handle A2A GetTask request.\n */\n private _handleA2AGetTask(\n remotePeerId: string,\n request: A2AJsonRpcRequest,\n ): void {\n const params = request.params as { taskId?: string } | undefined;\n if (!params?.taskId) {\n this._sendJsonRpcError(remotePeerId, request.id, {\n code: A2A_ERROR_CODE.INVALID_PARAMS,\n message: \"Missing taskId in GetTask params\",\n });\n\n return;\n }\n\n const taskManager = this._taskManagers.get(remotePeerId);\n const task = taskManager?.getTask(params.taskId);\n if (!task) {\n this._sendJsonRpcError(remotePeerId, request.id, {\n code: A2A_ERROR_CODE.TASK_NOT_FOUND,\n message: `Task not found: ${params.taskId}`,\n });\n\n return;\n }\n\n const conn = this.connections.get(remotePeerId);\n if (conn) {\n const rpcResponse: A2AJsonRpcResponse = {\n jsonrpc: \"2.0\",\n id: request.id,\n result: { task },\n };\n conn.send(rpcResponse);\n }\n }\n\n /**\n * Dispatch an inbound JSON-RPC 2.0 message (request, response, or notification).\n */\n private _handleA2AJsonRpc(\n remotePeerId: string,\n msg: Record<string, unknown>,\n ): void {\n // Response to a pending request (e.g., GetAgentCard response)\n if (isJsonRpcResponse(msg)) {\n const pending = this._pendingRequests.get(msg.id);\n if (pending) {\n clearTimeout(pending.timer);\n this._pendingRequests.delete(msg.id);\n pending.resolve(msg as A2AJsonRpcResponse);\n }\n\n return;\n }\n\n const method = msg.method as string | undefined;\n if (!method) {\n return;\n }\n\n // Multi-party room notifications (`room/*`) — forward to the RoomManager.\n if (method.startsWith(\"room/\")) {\n this._roomNotificationHandler?.(remotePeerId, method, msg.params);\n\n return;\n }\n\n // JSON-RPC Request (has id — expects a response)\n if (isJsonRpcRequest(msg)) {\n switch (method) {\n case A2A_METHOD.GET_AGENT_CARD:\n this._handleGetAgentCard(remotePeerId, msg as A2AJsonRpcRequest);\n\n break;\n case A2A_METHOD.SEND_MESSAGE:\n this._handleA2ASendMessage(remotePeerId, msg as A2AJsonRpcRequest);\n\n break;\n case A2A_METHOD.CANCEL_TASK:\n this._handleA2ACancelTask(remotePeerId, msg as A2AJsonRpcRequest);\n\n break;\n case A2A_METHOD.GET_TASK:\n this._handleA2AGetTask(remotePeerId, msg as A2AJsonRpcRequest);\n\n break;\n default:\n // Legacy \"message/send\" (existing format) — process as before\n if (method === \"message/send\") {\n const params = msg.params as any;\n if (params?.message?.parts && Array.isArray(params.message.parts)) {\n this._processInboundA2AEnvelope(\n remotePeerId,\n params.message.parts,\n ).catch((err) =>\n console.error(\n \"PeerJsChannel: failed to process inbound A2A envelope\",\n err,\n ),\n );\n }\n } else {\n this._sendJsonRpcError(remotePeerId, msg.id as string, {\n code: A2A_ERROR_CODE.METHOD_NOT_FOUND,\n message: `Method not found: ${method}`,\n });\n }\n }\n\n return;\n }\n\n // JSON-RPC Notification (no id — no response expected)\n switch (method) {\n case AGUI_METHOD.EVENT:\n this._handleAGUIEventNotification(remotePeerId, msg.params);\n\n break;\n case A2A_STREAM_METHOD.STATUS_UPDATE:\n this._handleTaskStatusNotification(remotePeerId, msg.params);\n\n break;\n case A2A_STREAM_METHOD.ARTIFACT_UPDATE:\n // Future: handle artifact streaming notifications\n\n break;\n case \"message/send\":\n // Legacy notification format (no id)\n {\n const params = msg.params as any;\n if (params?.message?.parts && Array.isArray(params.message.parts)) {\n this._processInboundA2AEnvelope(\n remotePeerId,\n params.message.parts,\n ).catch((err) =>\n console.error(\n \"PeerJsChannel: failed to process inbound A2A envelope\",\n err,\n ),\n );\n }\n }\n\n break;\n }\n }\n\n /**\n * Handle A2A SendMessage request — route through task manager.\n */\n private _handleA2ASendMessage(\n remotePeerId: string,\n request: A2AJsonRpcRequest,\n ): void {\n const params = request.params as SendMessageRequest | undefined;\n if (!params?.message) {\n this._sendJsonRpcError(remotePeerId, request.id, {\n code: A2A_ERROR_CODE.INVALID_PARAMS,\n message: \"Missing message in SendMessage params\",\n });\n\n return;\n }\n\n // Get or create task manager for this peer\n let taskManager = this._taskManagers.get(remotePeerId);\n if (!taskManager) {\n taskManager = new PeerTaskManager();\n this._taskManagers.set(remotePeerId, taskManager);\n\n // Wire up task events to emit over the DataChannel\n taskManager.on((event) => {\n this._forwardTaskEvent(remotePeerId, event);\n });\n }\n\n // Process through task manager\n const response = taskManager.handleSendMessage(params);\n\n // Send JSON-RPC response with task state\n const conn = this.connections.get(remotePeerId);\n if (conn) {\n const rpcResponse: A2AJsonRpcResponse = {\n jsonrpc: \"2.0\",\n id: request.id,\n result: response,\n };\n conn.send(rpcResponse);\n }\n\n // Also deliver the message content to the existing chat UI\n if (params.message.parts && Array.isArray(params.message.parts)) {\n this._processInboundA2AEnvelope(\n remotePeerId,\n params.message.parts,\n response.task?.id,\n response.task?.contextId,\n ).catch((err) =>\n console.error(\"PeerJsChannel: failed to process A2A SendMessage\", err),\n );\n }\n }\n\n /**\n * Handle an inbound AG-UI event notification from a remote peer.\n */\n private _handleAGUIEventNotification(\n remotePeerId: string,\n params: unknown,\n ): void {\n if (!params || typeof params !== \"object\") {\n return;\n }\n\n const event = params as AGUIEvent;\n\n // Dispatch a DOM event so UI components can react\n window.dispatchEvent(\n new CustomEvent(\"shadow-claw-agui-event\", {\n detail: { remotePeerId, event },\n }),\n );\n }\n\n /**\n * Handle GetAgentCard request — respond with our local card.\n */\n private _handleGetAgentCard(\n remotePeerId: string,\n request: A2AJsonRpcRequest,\n ): void {\n if (!this._localCard) {\n this._sendJsonRpcError(remotePeerId, request.id, {\n code: A2A_ERROR_CODE.INTERNAL_ERROR,\n message: \"Agent card not available\",\n });\n\n return;\n }\n\n const response = createGetAgentCardResponse(request.id, this._localCard);\n const conn = this.connections.get(remotePeerId);\n if (conn) {\n conn.send(response);\n }\n }\n\n private _handleInboundData(remotePeerId: string, data: unknown): void {\n if (data instanceof ArrayBuffer || data instanceof Uint8Array) {\n if (this._pendingInboundFile) {\n const canonicalName = this._pendingInboundFile.name;\n const bytes = new Uint8Array(data as ArrayBuffer);\n this._saveInboundFile(remotePeerId, canonicalName, bytes);\n this._pendingInboundFile = null;\n }\n\n return;\n }\n\n if (!data || typeof data !== \"object\") {\n return;\n }\n\n const msg = data as Record<string, unknown>;\n\n if (msg.type === \"__file_header\") {\n const transferId = (msg.id as string) || (msg.name as string);\n const totalChunks = (msg.totalChunks as number) || 1;\n const existing = this._inboundTransfers.get(transferId);\n\n this._inboundTransfers.set(transferId, {\n transferId,\n name: msg.name as string,\n mimeType: (msg.mimeType as string) || \"application/octet-stream\",\n size: (msg.size as number) || 0,\n totalChunks,\n receivedChunks: existing?.receivedChunks || new Map(),\n receivedBytes: existing?.receivedBytes || 0,\n targetGroupId:\n typeof msg.groupId === \"string\" ? msg.groupId : undefined,\n });\n\n this._pendingInboundFile = {\n name: msg.name as string,\n mimeType: msg.mimeType as string,\n size: msg.size as number,\n };\n\n updateTransferProgress({\n count: 0,\n total: totalChunks,\n direction: \"receive\",\n });\n\n return;\n }\n\n if (msg.type === \"__file_chunk\") {\n const transferId = (msg.id as string) || (msg.name as string);\n let transfer = this._inboundTransfers.get(transferId);\n if (!transfer) {\n const totalChunks = (msg.totalChunks as number) || 1;\n transfer = {\n transferId,\n name: msg.name as string,\n mimeType: \"application/octet-stream\",\n size: 0,\n totalChunks,\n receivedChunks: new Map(),\n receivedBytes: 0,\n };\n this._inboundTransfers.set(transferId, transfer);\n }\n\n const index = typeof msg.index === \"number\" ? msg.index : 0;\n const chunkData =\n msg.data instanceof ArrayBuffer\n ? new Uint8Array(msg.data)\n : msg.data instanceof Uint8Array\n ? msg.data\n : new Uint8Array((msg.data as any) || []);\n\n if (!transfer.receivedChunks.has(index)) {\n transfer.receivedChunks.set(index, chunkData);\n transfer.receivedBytes += chunkData.byteLength;\n }\n\n updateTransferProgress({\n count: transfer.receivedChunks.size,\n total: transfer.totalChunks,\n direction: \"receive\",\n });\n\n if (transfer.receivedChunks.size >= transfer.totalChunks) {\n const completeBytes = new Uint8Array(\n transfer.size || transfer.receivedBytes,\n );\n let offset = 0;\n for (let i = 0; i < transfer.totalChunks; i++) {\n const part = transfer.receivedChunks.get(i);\n if (part) {\n completeBytes.set(part, offset);\n offset += part.byteLength;\n }\n }\n\n const targetGroupId = transfer.targetGroupId || `peer:${remotePeerId}`;\n this._saveInboundFile(targetGroupId, transfer.name, completeBytes);\n this._inboundTransfers.delete(transferId);\n this._pendingInboundFile = null;\n\n clearTransferProgressDelayed(1500);\n }\n\n return;\n }\n\n if (msg.type === \"typing\") {\n this.typingCallback?.(`peer:${remotePeerId}`, !!msg.typing);\n\n return;\n }\n\n // Support legacy { type: \"chat\", text }\n if (msg.type === \"chat\") {\n const text = typeof msg.text === \"string\" ? msg.text.trim() : \"\";\n if (text) {\n this.messageCallback?.({\n id: ulid(),\n groupId: `peer:${remotePeerId}`,\n sender: remotePeerId,\n content: text,\n timestamp: Date.now(),\n channel: \"peerjs\",\n });\n }\n\n return;\n }\n\n // A2A JSON-RPC 2.0 dispatch\n if (msg.jsonrpc === \"2.0\") {\n this._handleA2AJsonRpc(remotePeerId, msg as Record<string, unknown>);\n\n return;\n }\n\n // Control-plane command execution over WebRTC DataChannel\n if (msg.type === \"command:execute\") {\n const payload = (msg.payload || {}) as {\n commandId?: string;\n action?: string;\n args?: any;\n };\n const action = payload.action || \"\";\n const args = payload.args || {};\n const commandId = payload.commandId || \"\";\n\n import(\"../../core/utils/initControlPlane.js\")\n .then(({ executeClientControlCommand }) =>\n executeClientControlCommand(action, args),\n )\n .then((result) => {\n const conn = this.connections.get(remotePeerId);\n if (conn) {\n const hasError = Boolean(result?.error);\n conn.send({\n id: ulid(),\n type: \"command:result\",\n payload: {\n commandId,\n action,\n success: !hasError,\n data: result,\n ...(hasError ? { error: result.error } : {}),\n },\n });\n }\n })\n .catch((err) => {\n const conn = this.connections.get(remotePeerId);\n if (conn) {\n conn.send({\n id: ulid(),\n type: \"command:result\",\n payload: {\n commandId,\n action,\n success: false,\n error: err?.message || String(err),\n },\n });\n }\n });\n\n return;\n }\n }\n\n private _isTrustedPeer(remotePeerId: string): boolean {\n if (this.trustedPeerIds.size === 0) {\n return true;\n }\n if (this.trustedPeerIds.has(remotePeerId)) {\n return true;\n }\n for (const trusted of this.trustedPeerIds) {\n const clean = trusted.trim();\n if (clean.endsWith(\"*\") && remotePeerId.startsWith(clean.slice(0, -1))) {\n return true;\n }\n if (clean === \"cli\" && remotePeerId.startsWith(\"cli-\")) {\n return true;\n }\n }\n return false;\n }\n\n private _handleIncomingConnection(conn: DataConnection): void {\n const remotePeerId = conn.peer;\n\n // Reject untrusted peers when a trusted list is configured\n if (!this._isTrustedPeer(remotePeerId)) {\n console.warn(\n `PeerJsChannel: rejecting connection from untrusted peer: ${remotePeerId}`,\n );\n try {\n conn.close();\n } catch {\n // ignore\n }\n\n return;\n }\n\n // Attach chunk progress interceptor to track inbound file transfers\n this._attachChunkProgressTracker(conn);\n\n // Register the connection\n this.connections.set(remotePeerId, conn);\n this._updateConnectedPeersSignal();\n\n conn.on(\"open\", () => {\n console.log(`PeerJsChannel: connection opened with ${remotePeerId}`);\n this._exchangeAgentCards(remotePeerId, conn);\n });\n\n conn.on(\"data\", (data: unknown) => {\n this._handleInboundData(remotePeerId, data);\n });\n\n conn.on(\"close\", () => {\n console.log(`PeerJsChannel: connection closed with ${remotePeerId}`);\n this.connections.delete(remotePeerId);\n this.peerCards.delete(remotePeerId);\n this._taskManagers.delete(remotePeerId);\n this._updateConnectedPeersSignal();\n });\n\n conn.on(\"error\", (err: Error) => {\n console.error(\n `PeerJsChannel: connection error with ${remotePeerId}:`,\n err,\n );\n this.connections.delete(remotePeerId);\n this._updateConnectedPeersSignal();\n window.dispatchEvent(\n new CustomEvent(\"shadow-claw-peer-error\", {\n detail: {\n remotePeerId,\n error: err.message,\n },\n }),\n );\n });\n\n conn.on(\"iceStateChanged\", (state: string) => {\n if (\n state === \"failed\" ||\n state === \"disconnected\" ||\n state === \"closed\"\n ) {\n console.warn(\n `PeerJsChannel: ICE state changed to ${state} for ${remotePeerId}`,\n );\n this.connections.delete(remotePeerId);\n this._updateConnectedPeersSignal();\n }\n });\n }\n\n /**\n * Intercept incoming BinaryPack chunk handling on DataConnection to track\n * file reception progress without requiring a custom PeerJS fork.\n */\n private _attachChunkProgressTracker(conn: DataConnection): void {\n const connAny = conn as any;\n if (connAny._chunkProgressPatched) {\n return;\n }\n connAny._chunkProgressPatched = true;\n\n const self = this;\n const origHandleChunk = connAny._handleChunk;\n if (typeof origHandleChunk === \"function\") {\n connAny._handleChunk = function (data: any) {\n if (data && typeof data === \"object\" && \"__peerData\" in data) {\n // If an application-level multi-chunk file transfer is in progress, ignore\n // raw PeerJS binarypack frame chunks to prevent fighting/flickering.\n if (self._inboundTransfers.size === 0) {\n const id = data.__peerData;\n const currentCount = this._chunkedData?.[id]?.count ?? 0;\n const total = data.total;\n\n if (\n typeof globalThis.dispatchEvent === \"function\" &&\n typeof CustomEvent === \"function\"\n ) {\n globalThis.dispatchEvent(\n new CustomEvent(\"peerjs-dc-handle-chunk\", {\n detail: {\n chunkInfo: {\n count: currentCount,\n total,\n },\n },\n }),\n );\n } else {\n const received = currentCount + 1;\n updateTransferProgress({\n count: received,\n total,\n direction: \"receive\",\n });\n\n if (received >= total) {\n clearTransferProgressDelayed(1500);\n }\n }\n }\n }\n\n return origHandleChunk.call(this, data);\n };\n }\n }\n\n /**\n * Handle an inbound task status update notification.\n */\n private _handleTaskStatusNotification(\n remotePeerId: string,\n params: unknown,\n ): void {\n if (!params || typeof params !== \"object\") {\n return;\n }\n\n const statusUpdate = params as TaskStatusUpdateEvent;\n\n // If the remote peer signaled a terminal state, notify the orchestrator\n // so it can suppress further auto-triggers for this conversation.\n if (\n statusUpdate.status?.state &&\n TERMINAL_STATES.has(statusUpdate.status.state as any)\n ) {\n const groupId = `peer:${remotePeerId}`;\n this._onTaskCompleteCallback?.(groupId);\n }\n\n window.dispatchEvent(\n new CustomEvent(\"shadow-claw-task-status\", {\n detail: { remotePeerId, ...statusUpdate },\n }),\n );\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private async _initPeer(): Promise<void> {\n const { Peer } = await import(\"peerjs\");\n const opts: Record<string, unknown> = {};\n\n // Only override defaults when explicitly configured\n const host = this.serverConfig.host ?? PEERJS_DEFAULT_HOST;\n const port = this.serverConfig.port ?? PEERJS_DEFAULT_PORT;\n const path = this.serverConfig.path ?? PEERJS_DEFAULT_PATH;\n const secure = this.serverConfig.secure ?? PEERJS_DEFAULT_SECURE;\n\n opts.host = host;\n opts.port = port;\n opts.path = path;\n opts.secure = secure;\n opts.debug = 3; // Verbose PeerJS logging for connection diagnostics\n\n // ICE servers for WebRTC connectivity (STUN for NAT traversal)\n const iceServers: RTCIceServer[] = this.serverConfig.iceServers ?? [\n { urls: \"stun:stun.l.google.com:19302\" },\n { urls: \"stun:stun1.l.google.com:19302\" },\n ];\n opts.config = { iceServers };\n\n this.peer = new Peer(this.myPeerId, opts);\n\n this.peer.on(\"open\", (id) => {\n console.log(\n `PeerJsChannel: connected to signaling server, peer ID: ${id}`,\n );\n // Reset backoff on successful connection\n this._reconnectAttempts = 0;\n });\n\n this.peer.on(\"connection\", (conn: DataConnection) => {\n this._handleIncomingConnection(conn);\n });\n\n this.peer.on(\"error\", (err: PeerError<string>) => {\n console.error(`PeerJsChannel: peer error [${err.type}]:`, err.message);\n\n if (err.type === \"peer-unavailable\" || err.type === \"unavailable-id\") {\n window.dispatchEvent(\n new CustomEvent(\"shadow-claw-peer-error\", {\n detail: {\n error: err.message,\n },\n }),\n );\n }\n\n // Recoverable errors — don't stop the channel\n if (\n err.type === \"peer-unavailable\" ||\n err.type === \"network\" ||\n err.type === \"disconnected\"\n ) {\n return;\n }\n\n // Non-recoverable\n if (err.type === \"unavailable-id\") {\n console.warn(\n \"PeerJsChannel: peer ID is already in use. Stop the channel and reconfigure.\",\n );\n }\n });\n\n this.peer.on(\"disconnected\", () => {\n if (this.running) {\n this._scheduleReconnect();\n }\n });\n\n this.peer.on(\"close\", () => {\n console.log(\"PeerJsChannel: peer closed\");\n });\n }\n\n /**\n * Register a pending JSON-RPC request (with 10s timeout).\n */\n private _registerPendingRequest(\n requestId: string,\n callback: (response: A2AJsonRpcResponse) => void,\n ): void {\n const timer = setTimeout(() => {\n this._pendingRequests.delete(requestId);\n console.warn(\n `PeerJsChannel: JSON-RPC request ${requestId} timed out (10s)`,\n );\n }, 10_000);\n\n this._pendingRequests.set(requestId, {\n resolve: callback,\n timer,\n });\n }\n\n /**\n * Schedule a reconnection attempt with exponential backoff.\n * Delay doubles each attempt: 1s, 2s, 4s, 8s, ... up to 60s max.\n */\n private _scheduleReconnect(): void {\n if (this._reconnectTimer !== null) {\n return; // Already scheduled\n }\n\n const delay = Math.min(\n PeerJsChannel._RECONNECT_BASE_MS * Math.pow(2, this._reconnectAttempts),\n PeerJsChannel._RECONNECT_MAX_MS,\n );\n\n this._reconnectAttempts++;\n\n console.log(\n `PeerJsChannel: disconnected from signaling server, reconnecting in ${(delay / 1000).toFixed(1)}s (attempt ${this._reconnectAttempts})`,\n );\n\n this._reconnectTimer = setTimeout(() => {\n this._reconnectTimer = null;\n if (!this.running) {\n return;\n }\n\n try {\n (this.peer as any)?.reconnect?.();\n } catch {\n // If reconnect throws, schedule another attempt\n this._scheduleReconnect();\n }\n }, delay);\n }\n\n // ---------------------------------------------------------------------------\n // JSON-RPC Helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Send a JSON-RPC error response to a remote peer.\n */\n private _sendJsonRpcError(\n remotePeerId: string,\n requestId: string,\n error: { code: number; message: string; data?: unknown[] },\n ): void {\n const conn = this.connections.get(remotePeerId);\n if (!conn) {\n return;\n }\n\n const response: A2AJsonRpcResponse = {\n jsonrpc: \"2.0\",\n id: requestId,\n error,\n };\n\n try {\n conn.send(response);\n } catch {\n // Ignore send errors for error responses\n }\n }\n\n /**\n * Pause execution if the underlying WebRTC DataChannel send buffer\n * exceeds the drain threshold, preventing buffer bloat during large transfers.\n */\n private async _waitForBufferDrain(\n conn: DataConnection,\n threshold: number = FILE_BUFFER_DRAIN_THRESHOLD,\n ): Promise<void> {\n const rawDc =\n ((conn as any).dataChannel as RTCDataChannel | undefined) ||\n ((conn as any)._dc as RTCDataChannel | undefined);\n if (!rawDc || typeof rawDc.bufferedAmount !== \"number\") {\n return;\n }\n if (rawDc.bufferedAmount <= threshold) {\n return;\n }\n\n await new Promise<void>((resolve) => {\n const poll = setInterval(() => {\n if (!rawDc || rawDc.bufferedAmount <= threshold) {\n clearInterval(poll);\n resolve();\n }\n }, 20);\n\n if (typeof rawDc.addEventListener === \"function\") {\n const onLow = () => {\n clearInterval(poll);\n rawDc.removeEventListener(\"bufferedamountlow\", onLow);\n resolve();\n };\n try {\n rawDc.bufferedAmountLowThreshold = threshold;\n rawDc.addEventListener(\"bufferedamountlow\", onLow, { once: true });\n } catch {\n // Fall back to polling if bufferedAmountLowThreshold throws\n }\n }\n });\n }\n\n /**\n * Persist complete received file bytes into group storage, handling\n * duplicate filename incrementing and path remapping.\n */\n private _saveInboundFile(\n groupId: string,\n canonicalName: string,\n bytes: Uint8Array,\n ): void {\n getDb().then(async (db) => {\n let finalName = canonicalName;\n let counter = 1;\n\n while (await groupFileExists(db, groupId, finalName)) {\n const lastDotIndex = canonicalName.lastIndexOf(\".\");\n const hasExt =\n lastDotIndex > 0 && lastDotIndex < canonicalName.length - 1;\n\n if (hasExt) {\n const base = canonicalName.substring(0, lastDotIndex);\n const ext = canonicalName.substring(lastDotIndex);\n finalName = `${base} (${counter})${ext}`;\n } else {\n finalName = `${canonicalName} (${counter})`;\n }\n\n counter++;\n }\n\n if (finalName !== canonicalName) {\n this._inboundRemap.set(canonicalName, finalName);\n }\n\n writeGroupFileBytes(db, groupId, finalName, bytes).catch((err) => {\n console.error(\"PeerJsChannel: failed to write inbound file bytes\", err);\n });\n });\n }\n\n private _updateConnectedPeersSignal(): void {\n this.connectedPeersSignal.set(Array.from(this.connections.keys()));\n }\n\n /**\n * Waits up to 5s for a DataConnection to open. Resolves immediately if\n * already open. Rejects if the connection errors or the timeout fires\n * without the connection opening.\n */\n private _waitForOpen(conn: DataConnection): Promise<void> {\n if ((conn as any).open) {\n return Promise.resolve();\n }\n\n return new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error(\"Connection open timeout (5s)\"));\n }, 5000);\n\n const openHandler = () => {\n clearTimeout(timeout);\n resolve();\n };\n\n const errorHandler = (err: Error) => {\n clearTimeout(timeout);\n reject(err);\n };\n\n conn.on(\"open\", openHandler);\n conn.on(\"error\", errorHandler);\n });\n }\n\n private async _processInboundA2AEnvelope(\n remotePeerId: string,\n parts: any[],\n taskId?: string,\n contextId?: string,\n ): Promise<void> {\n const groupId = `peer:${remotePeerId}`;\n\n let text = \"\";\n const inboundAttachments: MessageAttachment[] = [];\n const a2uiEnvelopes: A2UIEnvelope[] = [];\n let a2uiAction: A2UIAction | undefined;\n\n // The sender has already transmitted the raw binary buffers sequentially and\n // saved them into OPFS in `_handleInboundData`. Here we just compile the metadata\n // for the chat UI.\n for (const part of parts) {\n if (part.kind === \"text\" && typeof part.text === \"string\") {\n text += part.text;\n } else if (part.kind === \"file\") {\n let rawPath = part.name || \"attachment\";\n\n if (this._inboundRemap.has(rawPath)) {\n const remappedName = this._inboundRemap.get(rawPath)!;\n\n // Rewrite the text to use the remapped name\n const escapedOld = rawPath.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n text = text.replace(\n new RegExp(`(!?\\\\[.*?\\\\])\\\\(${escapedOld}\\\\)`, \"g\"),\n `$1(${remappedName})`,\n );\n\n this._inboundRemap.delete(rawPath);\n rawPath = remappedName;\n }\n\n const fileName = rawPath.split(\"/\").pop() || \"attachment\";\n\n inboundAttachments.push({\n fileName,\n mimeType: part.mimeType,\n path: rawPath,\n size: part.size || 0,\n });\n } else if (part.kind === \"a2ui\" && part.envelope) {\n a2uiEnvelopes.push(part.envelope as A2UIEnvelope);\n } else if (part.kind === \"a2ui-action\" && part.action) {\n a2uiAction = part.action as A2UIAction;\n }\n }\n\n text = text.trim();\n\n // Only suppress the callback if there is truly nothing to deliver.\n if (\n !text &&\n inboundAttachments.length === 0 &&\n a2uiEnvelopes.length === 0 &&\n !a2uiAction\n ) {\n return;\n }\n\n this.messageCallback?.({\n id: ulid(),\n groupId,\n sender: remotePeerId,\n content: text,\n timestamp: Date.now(),\n channel: \"peerjs\",\n attachments:\n inboundAttachments.length > 0 ? inboundAttachments : undefined,\n a2uiEnvelopes: a2uiEnvelopes.length > 0 ? a2uiEnvelopes : undefined,\n a2uiAction,\n taskId,\n contextId,\n });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction extractMarkdownAttachments(text: string): {\n remainingText: string;\n attachments: { alt: string; path: string }[];\n} {\n const attachments: { alt: string; path: string }[] = [];\n const regex = /!?\\[([^\\]]*)\\]\\(([^)]+)\\)/g;\n\n let match;\n let remainingText = text;\n\n // Find all matches\n while ((match = regex.exec(text)) !== null) {\n const alt = match[1];\n const path = (match[2] || \"\").trim();\n\n const normalizedPath = normalizeAttachmentPath(path);\n\n if (normalizedPath) {\n attachments.push({ alt, path: normalizedPath });\n }\n }\n\n return { remainingText, attachments };\n}\n\nfunction normalizeAttachmentPath(path: string): string | null {\n if (!path) {\n return null;\n }\n\n const trimmed = path.trim();\n\n // Ignore URI schemes (https:, data:, mailto:, etc.) and protocol-relative URLs.\n if (/^[a-zA-Z][a-zA-Z\\d+.-]*:/.test(trimmed) || trimmed.startsWith(\"//\")) {\n return null;\n }\n\n const normalized = trimmed\n .replace(/\\\\/g, \"/\")\n .replace(/^\\/+/, \"\")\n .replace(/^\\.\\//, \"\");\n\n if (!normalized) {\n return null;\n }\n\n const segments = normalized.split(\"/\").filter(Boolean);\n if (segments.some((seg) => seg === \"..\")) {\n return null;\n }\n\n return segments.join(\"/\");\n}\n"],"mappings":"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"}
|