shadow-claw 1.40.0 → 1.40.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/.well-known/mcp/server-card.json +2 -2
  2. package/.well-known/mcp/servers.json +1 -1
  3. package/.well-known/mcp.json +2 -2
  4. package/dist/cli/cli.js +2 -2
  5. package/dist/lib/components/index.js +2 -2
  6. package/dist/lib/components/shadow-claw-file-viewer/shadow-claw-file-viewer.d.ts +1 -1
  7. package/dist/lib/components/shadow-claw-file-viewer.js +1 -1
  8. package/dist/lib/components/shadow-claw.js +1 -1
  9. package/dist/lib/core/orchestrator/orchestrator-state.d.ts +2 -1
  10. package/dist/lib/core/orchestrator/orchestrator.d.ts +2 -1
  11. package/dist/lib/core/orchestrator/utils/operations/task.d.ts +1 -0
  12. package/dist/lib/index.js +2 -2
  13. package/dist/lib/{orchestrator-Bq9ft3uG.js → orchestrator-CMN43L0F.js} +9 -13
  14. package/dist/lib/orchestrator-CMN43L0F.js.map +1 -0
  15. package/dist/lib/orchestrator-D9f5fDCb.js.map +1 -1
  16. package/dist/lib/{shadow-claw-MumteAJy.js → shadow-claw-4x3LqlII.js} +2 -2
  17. package/dist/lib/{shadow-claw-MumteAJy.js.map → shadow-claw-4x3LqlII.js.map} +1 -1
  18. package/dist/lib/{shadow-claw-file-viewer-CMOnFmcP.js → shadow-claw-file-viewer-CuDhkVcL.js} +21 -21
  19. package/dist/lib/{shadow-claw-file-viewer-CMOnFmcP.js.map → shadow-claw-file-viewer-CuDhkVcL.js.map} +1 -1
  20. package/dist/lib/syncWebMcpRegistration-Bbph0XZl.js.map +1 -1
  21. package/dist/public/.well-known/mcp/server-card.json +2 -2
  22. package/dist/public/.well-known/mcp/servers.json +1 -1
  23. package/dist/public/.well-known/mcp.json +2 -2
  24. package/dist/public/docs/decisions/native-web-components-and-signals.md +1 -1
  25. package/dist/public/docs/example/article/index.html +2 -2
  26. package/dist/public/docs/publishing/index.html +2 -2
  27. package/dist/public/docs/skill-creator/index.html +2 -2
  28. package/dist/public/index.html +2 -2
  29. package/dist/public/index.js +1 -1
  30. package/dist/public/main/index.html +2 -2
  31. package/dist/public/main/memory/index.html +2 -2
  32. package/dist/public/{orchestrator-BLkS_jpm.js → orchestrator-Dc_Q73La.js} +1 -1
  33. package/dist/public/service-worker.js +1 -1
  34. package/dist/public/{shadow-claw-DmrxnX3Q.js → shadow-claw-Dabb2AEp.js} +2 -2
  35. package/dist/public/{shadow-claw-file-viewer-a_uRA30F.js → shadow-claw-file-viewer-CDs1QGXk.js} +1 -1
  36. package/dist/server.js +1 -1
  37. package/package.json +1 -1
  38. package/src/cli/cli.ts +2 -2
  39. package/src/components/shadow-claw-file-viewer/shadow-claw-file-viewer.ts +31 -31
  40. package/src/core/effect.test.ts +19 -0
  41. package/src/core/orchestrator/orchestrator-state.ts +2 -1
  42. package/src/core/orchestrator/orchestrator.test.ts +686 -5
  43. package/src/core/orchestrator/orchestrator.ts +3 -10
  44. package/src/core/orchestrator/utils/compactContext.test.ts +423 -121
  45. package/src/core/orchestrator/utils/configurePeerJs.test.ts +27 -0
  46. package/src/core/orchestrator/utils/deliverResponse.test.ts +127 -0
  47. package/src/core/orchestrator/utils/dispatchSubagentInvoke.test.ts +23 -0
  48. package/src/core/orchestrator/utils/enqueue.test.ts +520 -86
  49. package/src/core/orchestrator/utils/handleWorkerMessage.test.ts +664 -144
  50. package/src/core/orchestrator/utils/initTasks.node.test.ts +147 -0
  51. package/src/core/orchestrator/utils/initTasks.test.ts +926 -191
  52. package/src/core/orchestrator/utils/initTasks.ts +5 -4
  53. package/src/core/orchestrator/utils/invokeAgent.test.ts +563 -110
  54. package/src/core/orchestrator/utils/invokeAgent.ts +8 -10
  55. package/src/core/orchestrator/utils/loadChannelConfigurations.test.ts +50 -0
  56. package/src/core/orchestrator/utils/operations/channel.test.ts +377 -170
  57. package/src/core/orchestrator/utils/operations/provider.test.ts +663 -85
  58. package/src/core/orchestrator/utils/operations/room.test.ts +74 -11
  59. package/src/core/orchestrator/utils/operations/task.test.ts +452 -56
  60. package/src/core/orchestrator/utils/operations/task.ts +1 -1
  61. package/src/core/orchestrator/utils/operations/vm.test.ts +66 -7
  62. package/src/core/orchestrator/utils/parseDirectToolCommand.test.ts +6 -0
  63. package/src/core/orchestrator/utils/settings.test.ts +248 -81
  64. package/src/core/orchestrator/utils/setupPushTaskListener.test.ts +58 -0
  65. package/src/core/orchestrator/utils/syncWebMcpRegistration.test.ts +341 -65
  66. package/src/core/orchestrator/utils/syncWebMcpRegistration.ts +4 -2
  67. package/src/server/routes/mcp.ts +2 -2
  68. package/src/stores/file-viewer.test.ts +11 -0
  69. package/src/stores/theme.test.ts +41 -2
  70. package/src/stores/toast.test.ts +25 -0
  71. package/src/worker/tools/bash/native-bash-executor.test.ts +31 -1
  72. package/src/worker/tools/git/utils/extractConflictPaths.test.ts +24 -0
  73. package/src/worker/tools/git/utils/parseConflictRegions.test.ts +46 -0
  74. package/src/worker/tools/git/utils/resolveCorsProxy.test.ts +26 -5
  75. package/src/worker/tools/git/utils/truncateSnippet.test.ts +16 -0
  76. package/src/worker/tools/node-transformers-executor.test.ts +105 -6
  77. package/src/worker/tools/remote-mcp/remote-mcp.test.ts +172 -47
  78. package/src/worker/tools/remote-mcp/utils/formatListToolsOutput.test.ts +19 -0
  79. package/src/worker/tools/remote-mcp/utils/isMcpReauthError.test.ts +45 -0
  80. package/src/worker/tools/remote-mcp/utils/resolveMcpReauth.test.ts +48 -0
  81. package/src/worker/tools/rooms/list-room-members.test.ts +24 -10
  82. package/src/worker/tools/tasks/list-tasks.test.ts +39 -8
  83. package/src/worker/tools/tasks/update-task.test.ts +78 -14
  84. package/src/worker/tools/ui/javascript.test.ts +70 -17
  85. package/src/worker/tools/ui/list-tool-profiles.test.ts +31 -9
  86. package/dist/lib/orchestrator-Bq9ft3uG.js.map +0 -1
@@ -713,4 +713,4 @@ pre {
713
713
  `+e.content+"\n```"}updateEditorHighlight(e){let t=this.shadowRoot;if(!t)return;let n=t.querySelector(`.file-editor-overlay code`);if(!n)return;let r=j.file,i=this.getLanguageFromFilename(r?.name||``),a=``;try{a=i&&k.getLanguage(i)?k.highlight(e,{language:i}).value:k.highlightAuto(e).value}catch{a=e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`)}n.className=i?`hljs language-${i}`:`hljs`,n.innerHTML=h(a+`<br>`)}wrapCodeLines(e){e.querySelectorAll(`pre code`).forEach(e=>{let t=e.innerHTML.split(/\r?\n/u);t.length>1&&t[t.length-1]===``&&t.pop(),d(e,t.map((e,t)=>`<span class="code-line" data-line="${t+1}">${e||`&nbsp;`}</span>`).join(`
714
714
  `))})}async buildIframePreviewSrcdoc(e,t=``){if(/\.svg$/i.test(e.name))return e.content;let n=e.path||e.name||``,r=this.stripHtmlFrontmatter(e.content||``),o=this.rewriteWorkspacePreviewHtml(r,n),s=_(await this.resolveRelativeImagesInHtml(o,n),Y),c=crypto.randomUUID().replace(/-/g,``),u=this.getIframeBridgeScriptUrl(),d=i(`/assets/iframe-storage-bridge.js`),f=m(),p=g(c),h=typeof document<`u`?document.getElementById(`shadow-claw-site-config`):null,v=h&&h.textContent?`<script id="shadow-claw-site-config" type="application/json">${h.textContent}<\/script>`:``,y=t?`<script nonce="${c}">(function(){try{Object.defineProperty(globalThis.location,"search",{get:function(){return ${JSON.stringify(t)};},configurable:true});}catch(e){}})();<\/script>`:``,b=f.length>0&&l(s)?f.map(({src:e,hasInit:t})=>{let n=e.startsWith(`http://`)||e.startsWith(`https://`)||e.startsWith(`//`)?e:i(e.startsWith(`/`)?e:`/${e.replace(/^pages\/main\//,``)}`),r=[`<script type="module" src="${n}" nonce="${c}"><\/script>`];return t&&r.push(`<script type="module" nonce="${c}">import("${n}").then((m) => { try { if (typeof m?.init === "function") m.init(); } catch (e) { console.error("[ShadowClaw] Error executing init for " + ${JSON.stringify(n)}, e); } }).catch(() => {});<\/script>`),r.join(`
715
715
  `)}).join(`
716
- `):``,S=F();return[`<!doctype html>`,`<html class="${z()}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">`,`<meta http-equiv="Content-Security-Policy" content="${p}">`,`<base href="${i(a(x.activeGroupId,n))}" target="_blank">`,y,v,`<script src="${d}" nonce="${c}"><\/script>`,`<script src="${u}" nonce="${c}"><\/script>`,N(),S,b,`</head><body>`,s,`</body></html>`].join(``)}async canDismissViewer(){if(!this.hasUnsavedChanges())return!0;let e=await this.requestConfirmation({title:`Discard Unsaved Changes`,message:`You have unsaved changes. Discard them and close?`,confirmLabel:`Discard`,cancelLabel:`Keep Editing`});return e&&(this.isEditorDirty=!1,this.editorDraftContent=null),e}async exitFullscreenIfActive(e){let t=this.shadowRoot,n=e||t?.querySelector(`.file-modal`);if(!n)return;let r=this.getFullscreenTarget(n);if(!(!r||!this.isTargetInFullscreen(r)))try{await this.exitNativeFullscreen()}catch{}}async exitNativeFullscreen(){let e=document.exitFullscreen||document.webkitExitFullscreen;if(typeof e!=`function`)throw Error(`Native fullscreen exit unavailable`);await Promise.resolve(e.call(document))}async handlePreviewLinkClick(e){if(e.defaultPrevented||e.button!==0||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey)return;let r=e.target;if(!(r instanceof Element))return;let o=r.closest(`a`);if(!(o instanceof HTMLAnchorElement)||!this.db)return;let s=j.file,c=s?.path||s?.name||``,l=o.getAttribute(`href`)||``,u=n(l,i(a(x.activeGroupId,c)),window.location.origin);if(u&&u.origin===window.location.origin&&(t(u.pathname)||this.resolveWorkspaceLinkPath(l,c))&&u){e.preventDefault();let t=`${u.pathname}${u.search}${u.hash}`,n=window.navigation;n&&typeof n.navigate==`function`?n.navigate(t):(window.history.pushState({},``,t),window.dispatchEvent(new PopStateEvent(`popstate`)));return}let d=l.trim();if(d&&!d.startsWith(`#`)&&!d.startsWith(`javascript:`)){let t=o.getAttribute(`target`)||`_blank`,n=t===`_self`||t===`_top`||t===`_parent`?`_blank`:t;try{new URL(d,window.location.href).host!==window.location.host&&(e.preventDefault(),window.open(d,n,`noopener,noreferrer`))}catch{/^[a-zA-Z][a-zA-Z\d+.-]*:/u.test(d)&&(e.preventDefault(),window.open(d,n,`noopener,noreferrer`))}}}async handleSave(){let e=j.file;if(!e||!this.db)return;let t=this.shadowRoot,n=t?.querySelector(`.modal-save-btn`),r=t?.querySelector(`.file-editor`);if(r instanceof HTMLTextAreaElement)try{n instanceof HTMLButtonElement&&(n.disabled=!0,n.textContent=`⏳ saving...`);let t=r.value,i=e.path||(x.currentPath===`.`?e.name:`${x.currentPath}/${e.name}`),a=e.groupId||x.activeGroupId;await S(this.db,a,i,t),w(`Saved ${e.name}`),document.dispatchEvent(new CustomEvent(`shadow-claw-file-saved`,{detail:{groupId:a,path:i},bubbles:!0,composed:!0})),await x.loadFiles(this.db),e.content=t,this.isFileEditMode=!1,this.isEditorDirty=!1,this.editorDraftContent=null,await this.updateView()}catch(e){T(`Failed to save file: ${e instanceof Error?e.message:String(e)}`)}finally{n instanceof HTMLButtonElement&&(n.disabled=!1,n.textContent=`💾 Save`)}}async handleShareFile(){let e=j.file;if(!e||!this.canShareCurrentFile(e)){T(`Sharing is not supported for this file on this device.`,4500);return}try{if(e.kind===`text`)await navigator.share({title:e.name,text:e.content||``});else{let t=this.buildWebShareFile(e);if(!t||!navigator.canShare?.({files:[t]})){T(`File sharing is not supported on this device.`,4500);return}await navigator.share({title:e.name,files:[t]})}w(`Shared ${e.name}`)}catch(e){if(e instanceof DOMException&&e.name===`AbortError`)return;T(`Failed to share file: ${e instanceof Error?e.message:String(e)}`,5e3)}}async handleSendFileToPeer(){let e=j.file;if(!e||!e.path){T(`No file is currently open.`,4500);return}let t=e.groupId||x.activeGroupId||``,n=t.startsWith(`peer:`),r=t.startsWith(`room:`);if(!n&&!r){T(`Can only send files to peers in a peer or room conversation.`,4500);return}try{await x.sendFileToPeer(e.path,t,{fileName:e.name,mimeType:e.mimeType})}catch{}}async openFolderInFilesView(e){if(!this.db)return;let t=e.replace(/^\/+|\/+$/g,``);if(t)try{await x.setCurrentPath(this.db,t),j.closeFile();let e=window?.shadowclaw?.ui;e&&typeof e.showPage==`function`&&e.showPage(`files`)}catch(e){T(`Failed to open linked folder: ${e instanceof Error?e.message:String(e)}`,5e3)}}async openWorkspaceLink(e,t){if(!this.db)return;let n=this.resolveWorkspaceLinkPath(e,t);if(!n)return;let r=n.split(`/`).filter(Boolean).pop()||``;if(!/\.[^./]+$/u.test(r)){try{await j.openFile(this.db,n,x.activeGroupId);return}catch(e){let t=e instanceof DOMException&&e.name===`NotFoundError`,n=e instanceof DOMException&&e.name===`TypeMismatchError`;if(!t&&!n){T(`Failed to open linked file: ${e instanceof Error?e.message:String(e)}`,5e3);return}}await this.openFolderInFilesView(n);return}try{await j.openFile(this.db,n,x.activeGroupId)}catch(e){T(`Failed to open linked file: ${e instanceof Error?e.message:String(e)}`,5e3)}}async renderPreview(t,n,r=this.viewRenderToken){if(!this.isRenderTokenCurrent(r))return;if(this.revokeObjectUrl(),this.previewFrameWindow=null,n.kind===`pdf`){t.classList.remove(`file-content--raw`,`file-content--preview`,`file-content--iframe`),import(`./shadow-claw-pdf-viewer-gOiW-_Bh.js`).then(()=>{let e=document.createElement(`shadow-claw-pdf-viewer`);e.file=n,t.replaceChildren(e)}).catch(console.error);return}if(n.kind===`binary`){this.renderBinaryPreview(t,n);return}if(this.isIframePreviewFile(n.name)){t.classList.remove(`file-content--raw`,`file-content--preview`),t.classList.add(`file-content--iframe`);let e=document.createElement(`iframe`);e.className=`file-content-iframe`,e.setAttribute(`title`,`Preview: ${n.name}`),e.setAttribute(`sandbox`,this.getIframeSandboxPermissions(n.name)),e.setAttribute(`allow`,`fullscreen`),e.setAttribute(`referrerpolicy`,`no-referrer`),f(e,await this.buildIframePreviewSrcdoc(n)),e.addEventListener(`load`,()=>{this.previewFrameWindow=e.contentWindow,this.syncIframeTheme()}),t.replaceChildren(e);return}t.classList.remove(`file-content--raw`),t.classList.add(`file-content--preview`);let i=j.file,a=i?.path||i?.name||``,o=this.toPreviewMarkdown(n),s=X(this.db,e.MARKDOWN_FRONTMATTER_FILE_VIEWER),c=await A(o,{renderFrontmatter:typeof s==`boolean`?s:await s});if(!this.isRenderTokenCurrent(r))return;let l=this.rewriteWorkspacePreviewHtml(c,a);this.isRenderTokenCurrent(r)&&(d(t,l,Y),this.wrapCodeLines(t),await this.resolveMarkdownImages(t,a))}async requestCloseViewer(){return await this.canDismissViewer()?(await this.exitFullscreenIfActive(),j.closeFile(),!0):!1}async requestConfirmation(e){let t=document.querySelector(`shadow-claw`);return t&&typeof t.requestDialog==`function`?await t.requestDialog({mode:`confirm`,...e}):!1}async requestNativeFullscreen(e){let t=e.requestFullscreen||e.webkitRequestFullscreen;if(typeof t!=`function`)throw Error(`Native fullscreen unavailable`);await Promise.resolve(t.call(e))}async resolveMarkdownImages(e,t){if(!this.db)return;let n=Array.from(e.querySelectorAll(`img`));n.length!==0&&await Promise.all(n.map(async e=>{let n=e.getAttribute(`src`)||``;if(!n||/^(?:blob:|data:|#)/u.test(n))return;let r=this.getWorkspaceRouteTarget(n,{allowCrossGroup:!0})||(()=>{let e=this.resolveWorkspaceLinkPath(n,t);return e?{groupId:x.activeGroupId,path:e}:null})();if(r)try{let t=await b(this.db,r.groupId,r.path),n=r.path.split(`.`).pop()?.toLowerCase()||``,i=this.mimeTypeForImageExt(n),a=new Uint8Array(t.byteLength);a.set(t),e.src=await new Promise((e,t)=>{let n=new FileReader;n.onload=()=>e(n.result),n.onerror=t,n.readAsDataURL(new Blob([a],{type:i}))})}catch{}}))}async resolveRelativeImagesInHtml(e,t){if(!this.db||!e)return e;let n=new DOMParser().parseFromString(e,`text/html`),r=Array.from(n.querySelectorAll(`img`));return r.length===0?e:(await Promise.all(r.map(async e=>{let n=e.getAttribute(`src`)||``;if(!n||/^(?:blob:|data:|#)/u.test(n))return;let r=this.getWorkspaceRouteTarget(n,{allowCrossGroup:!0})||(()=>{let e=this.resolveWorkspaceLinkPath(n,t);return e?{groupId:x.activeGroupId,path:e}:null})();if(r)try{let t=await b(this.db,r.groupId,r.path),n=r.path.split(`.`).pop()?.toLowerCase()||``,i=this.mimeTypeForImageExt(n),a=new Uint8Array(t.byteLength);a.set(t);let o=await new Promise((e,t)=>{let n=new FileReader;n.onload=()=>e(n.result),n.onerror=t,n.readAsDataURL(new Blob([a],{type:i}))});e.setAttribute(`src`,o)}catch{}})),n.body.innerHTML)}async toggleFullscreenMode(e){let t=this.getFullscreenTarget(e);if(t){if(this.canUseNativeFullscreen(t)){let n=this.isTargetInFullscreen(t);try{n?(await this.exitNativeFullscreen(),this.isFullscreenMode=!1):(await this.requestNativeFullscreen(t),this.isFullscreenMode=!0)}catch{this.isFullscreenMode=!this.isFullscreenMode}this.applyFullscreenMode(e);return}this.isFullscreenMode=!this.isFullscreenMode,this.applyFullscreenMode(e)}}async updateView(e=this.viewRenderToken){let t=j.file,n=this.shadowRoot;if(!n||!t)return;let r=n.querySelector(`.file-modal`);if(!(r instanceof HTMLElement))return;this.applyFullscreenMode(r);let i=r.querySelector(`.file-content`),a=r.querySelector(`.modal-preview-btn`),o=r.querySelector(`.modal-body`);if(!(i instanceof HTMLElement))return;i.classList.remove(`file-content--iframe`);let s=this.getWorkingSourceFile(t,r),c=t.kind===`text`;a instanceof HTMLButtonElement&&(a.setAttribute(`aria-pressed`,String(this.isFilePreviewMode)),a.setAttribute(`aria-label`,this.isFilePreviewMode?`Switch to raw text view`:`Switch to preview mode`));let l=r.querySelector(`.file-editor-container`),u=r.querySelector(`.modal-edit-btn`),d=r.querySelector(`.modal-save-btn`),f=r.querySelector(`.modal-share-btn`),p=r.querySelector(`.modal-close-btn`),m=r.querySelector(`.modal-cancel-btn`),h=t?.groupId||x.activeGroupId||``,g=h.startsWith(`peer:`),_=h.startsWith(`room:`),v=g||_,y=this.canShareCurrentFile(t),b=r.querySelector(`.modal-share-dropdown`),S=r.querySelector(`.modal-share-peer-label`),C=r.querySelector(`.modal-share-device-btn`);if(b instanceof HTMLElement&&(v?(b.classList.remove(`hidden`),S&&(S.textContent=_?`Send to room peers`:`Send to peer`),C instanceof HTMLButtonElement&&(C.classList.toggle(`hidden`,!y),C.disabled=!y)):b.classList.add(`hidden`)),f instanceof HTMLButtonElement&&(v?(f.classList.add(`hidden`),f.disabled=!0):(f.classList.toggle(`hidden`,!y),f.disabled=!y)),p instanceof HTMLButtonElement){let e=this.hasUnsavedChanges();p.disabled=!1,p.setAttribute(`aria-label`,e?`Close file viewer (unsaved changes)`:`Close file viewer`),p.title=e?`Close (you have unsaved changes)`:`Close`}let w=this.hasUnsavedChanges();if(d instanceof HTMLButtonElement&&d.classList.toggle(`hidden`,!w),m instanceof HTMLButtonElement&&m.classList.toggle(`hidden`,!w),this.isFilePreviewMode){o?.classList.remove(`modal-body--editing`),i.classList.remove(`hidden`),l?.classList.remove(`active`),u instanceof HTMLButtonElement&&(u.setAttribute(`aria-pressed`,`false`),u.setAttribute(`aria-label`,`Edit file`),u.classList.toggle(`hidden`,!c)),await this.renderPreview(i,s,e);return}if(this.isRenderTokenCurrent(e))if(this.isFileEditMode&&c){o?.classList.add(`modal-body--editing`),i.classList.add(`hidden`),l?.classList.add(`active`),u instanceof HTMLButtonElement&&(u.setAttribute(`aria-pressed`,`true`),u.setAttribute(`aria-label`,`Switch to raw text view`),u.classList.remove(`hidden`));let e=l?.querySelector(`.file-editor`);if(e instanceof HTMLTextAreaElement){e.setAttribute(`tab-size`,`2`);let n=this.getLanguageFromFilename(t.name);if(n?e.setAttribute(`language`,n):e.removeAttribute(`language`),this.isEditorDirty)typeof s?.content==`string`&&(e.value!==s.content&&(e.value=s.content),this.updateEditorHighlight(e.value));else{let n=t.content||``;e.value!==n&&(e.value=n),this.updateEditorHighlight(e.value)}e.dispatchEvent(new Event(`scroll`))}}else o?.classList.remove(`modal-body--editing`),i.classList.remove(`hidden`),l?.classList.remove(`active`),u instanceof HTMLButtonElement&&(u.setAttribute(`aria-pressed`,`false`),u.setAttribute(`aria-label`,`Edit file`),u.classList.toggle(`hidden`,!c)),i.classList.add(`file-content--raw`),i.classList.remove(`file-content--preview`,`file-content--iframe`),t.kind===`binary`?i.textContent=`Binary file (${t.mimeType||`application/octet-stream`}). Switch to Preview to view.`:i.textContent=s.content||``}syncIframeTheme(){if(!this.previewFrameWindow)return;let e=document.documentElement.classList.contains(`dark-mode`),t=getComputedStyle(document.documentElement),n={};for(let e=0;e<t.length;e++){let r=t[e];r.startsWith(`--`)&&(n[r]=t.getPropertyValue(r))}this.previewFrameWindow.postMessage({type:`shadow-claw-theme-update`,theme:e?`dark`:`light`,customProperties:n},`*`)}async handleStorageProxyRequest(e,t,n,r){if(!t)return;let i=j.file,a=i?.path||i?.name||`__default__`;try{let i;switch(n){case`setItem`:await M(a,String(r.key||``),r.value);break;case`removeItem`:await I(a,String(r.key||``));break;case`clear`:await B(a);break;case`getAllItems`:i=await P(a);break;case`idb-get`:i=await R(`${a}::idb::${r.dbName}::${r.storeName}`,String(r.key||``));break;case`idb-getAll`:i=await P(`${a}::idb::${r.dbName}::${r.storeName}`);break;case`idb-put`:{let e=r.key==null?`__auto_${Date.now()}`:String(r.key);await M(`${a}::idb::${r.dbName}::${r.storeName}`,e,r.value),i=e;break}case`idb-delete`:await I(`${a}::idb::${r.dbName}::${r.storeName}`,String(r.key||``));break;case`idb-clear`:await B(`${a}::idb::${r.dbName}::${r.storeName}`);break;case`idb-deleteDatabase`:await B(`${a}::idb::${r.dbName}::__default__`);break;default:throw Error(`Unknown storage proxy method: ${n}`)}e.postMessage({type:`shadow-claw-storage-proxy-result`,requestId:t,result:i??null},`*`)}catch(n){e.postMessage({type:`shadow-claw-storage-proxy-result`,requestId:t,error:n instanceof Error?n.message:String(n)},`*`)}}async reloadPreviewWithSearchParams(e){let t=j.file;if(!t)return;let n=this.shadowRoot?.querySelector(`.file-viewer__iframe`);n&&(this.previewFrameWindow=null,f(n,await this.buildIframePreviewSrcdoc(t,e)))}};customElements.get(K)||customElements.define(K,Z);export{Z as ShadowClawFileViewer};
716
+ `):``,S=F();return[`<!doctype html>`,`<html class="${z()}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">`,`<meta http-equiv="Content-Security-Policy" content="${p}">`,`<base href="${i(a(x.activeGroupId,n))}" target="_blank">`,y,v,`<script src="${d}" nonce="${c}"><\/script>`,`<script src="${u}" nonce="${c}"><\/script>`,N(),S,b,`</head><body>`,s,`</body></html>`].join(``)}async canDismissViewer(){if(!this.hasUnsavedChanges())return!0;let e=await this.requestConfirmation({title:`Discard Unsaved Changes`,message:`You have unsaved changes. Discard them and close?`,confirmLabel:`Discard`,cancelLabel:`Keep Editing`});return e&&(this.isEditorDirty=!1,this.editorDraftContent=null),e}async exitFullscreenIfActive(e){let t=this.shadowRoot,n=e||t?.querySelector(`.file-modal`);if(!n)return;let r=this.getFullscreenTarget(n);if(!(!r||!this.isTargetInFullscreen(r)))try{await this.exitNativeFullscreen()}catch{}}async exitNativeFullscreen(){let e=document.exitFullscreen||document.webkitExitFullscreen;if(typeof e!=`function`)throw Error(`Native fullscreen exit unavailable`);await Promise.resolve(e.call(document))}async handlePreviewLinkClick(e){if(e.defaultPrevented||e.button!==0||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey)return;let r=e.target;if(!(r instanceof Element))return;let o=r.closest(`a`);if(!(o instanceof HTMLAnchorElement)||!this.db)return;let s=j.file,c=s?.path||s?.name||``,l=o.getAttribute(`href`)||``,u=n(l,i(a(x.activeGroupId,c)),window.location.origin);if(u&&u.origin===window.location.origin&&(t(u.pathname)||this.resolveWorkspaceLinkPath(l,c))&&u){e.preventDefault();let t=`${u.pathname}${u.search}${u.hash}`,n=window.navigation;n&&typeof n.navigate==`function`?n.navigate(t):(window.history.pushState({},``,t),window.dispatchEvent(new PopStateEvent(`popstate`)));return}let d=l.trim();if(d&&!d.startsWith(`#`)&&!d.startsWith(`javascript:`)){let t=o.getAttribute(`target`)||`_blank`,n=t===`_self`||t===`_top`||t===`_parent`?`_blank`:t;try{new URL(d,window.location.href).host!==window.location.host&&(e.preventDefault(),window.open(d,n,`noopener,noreferrer`))}catch{/^[a-zA-Z][a-zA-Z\d+.-]*:/u.test(d)&&(e.preventDefault(),window.open(d,n,`noopener,noreferrer`))}}}async handleSave(){let e=j.file;if(!e||!this.db)return;let t=this.shadowRoot,n=t?.querySelector(`.modal-save-btn`),r=t?.querySelector(`.file-editor`);if(r instanceof HTMLTextAreaElement)try{n instanceof HTMLButtonElement&&(n.disabled=!0,n.textContent=`⏳ saving...`);let t=r.value,i=e.path||(x.currentPath===`.`?e.name:`${x.currentPath}/${e.name}`),a=e.groupId||x.activeGroupId;await S(this.db,a,i,t),w(`Saved ${e.name}`),document.dispatchEvent(new CustomEvent(`shadow-claw-file-saved`,{detail:{groupId:a,path:i},bubbles:!0,composed:!0})),await x.loadFiles(this.db),e.content=t,this.isFileEditMode=!1,this.isEditorDirty=!1,this.editorDraftContent=null,await this.updateView()}catch(e){T(`Failed to save file: ${e instanceof Error?e.message:String(e)}`)}finally{n instanceof HTMLButtonElement&&(n.disabled=!1,n.textContent=`💾 Save`)}}async handleSendFileToPeer(){let e=j.file;if(!e||!e.path){T(`No file is currently open.`,4500);return}let t=e.groupId||x.activeGroupId||``,n=t.startsWith(`peer:`),r=t.startsWith(`room:`);if(!n&&!r){T(`Can only send files to peers in a peer or room conversation.`,4500);return}try{await x.sendFileToPeer(e.path,t,{fileName:e.name,mimeType:e.mimeType})}catch{}}async handleShareFile(){let e=j.file;if(!e||!this.canShareCurrentFile(e)){T(`Sharing is not supported for this file on this device.`,4500);return}try{if(e.kind===`text`)await navigator.share({title:e.name,text:e.content||``});else{let t=this.buildWebShareFile(e);if(!t||!navigator.canShare?.({files:[t]})){T(`File sharing is not supported on this device.`,4500);return}await navigator.share({title:e.name,files:[t]})}w(`Shared ${e.name}`)}catch(e){if(e instanceof DOMException&&e.name===`AbortError`)return;T(`Failed to share file: ${e instanceof Error?e.message:String(e)}`,5e3)}}async openFolderInFilesView(e){if(!this.db)return;let t=e.replace(/^\/+|\/+$/g,``);if(t)try{await x.setCurrentPath(this.db,t),j.closeFile();let e=window?.shadowclaw?.ui;e&&typeof e.showPage==`function`&&e.showPage(`files`)}catch(e){T(`Failed to open linked folder: ${e instanceof Error?e.message:String(e)}`,5e3)}}async openWorkspaceLink(e,t){if(!this.db)return;let n=this.resolveWorkspaceLinkPath(e,t);if(!n)return;let r=n.split(`/`).filter(Boolean).pop()||``;if(!/\.[^./]+$/u.test(r)){try{await j.openFile(this.db,n,x.activeGroupId);return}catch(e){let t=e instanceof DOMException&&e.name===`NotFoundError`,n=e instanceof DOMException&&e.name===`TypeMismatchError`;if(!t&&!n){T(`Failed to open linked file: ${e instanceof Error?e.message:String(e)}`,5e3);return}}await this.openFolderInFilesView(n);return}try{await j.openFile(this.db,n,x.activeGroupId)}catch(e){T(`Failed to open linked file: ${e instanceof Error?e.message:String(e)}`,5e3)}}async renderPreview(t,n,r=this.viewRenderToken){if(!this.isRenderTokenCurrent(r))return;if(this.revokeObjectUrl(),this.previewFrameWindow=null,n.kind===`pdf`){t.classList.remove(`file-content--raw`,`file-content--preview`,`file-content--iframe`),import(`./shadow-claw-pdf-viewer-gOiW-_Bh.js`).then(()=>{let e=document.createElement(`shadow-claw-pdf-viewer`);e.file=n,t.replaceChildren(e)}).catch(console.error);return}if(n.kind===`binary`){this.renderBinaryPreview(t,n);return}if(this.isIframePreviewFile(n.name)){t.classList.remove(`file-content--raw`,`file-content--preview`),t.classList.add(`file-content--iframe`);let e=document.createElement(`iframe`);e.className=`file-content-iframe`,e.setAttribute(`title`,`Preview: ${n.name}`),e.setAttribute(`sandbox`,this.getIframeSandboxPermissions(n.name)),e.setAttribute(`allow`,`fullscreen`),e.setAttribute(`referrerpolicy`,`no-referrer`),f(e,await this.buildIframePreviewSrcdoc(n)),e.addEventListener(`load`,()=>{this.previewFrameWindow=e.contentWindow,this.syncIframeTheme()}),t.replaceChildren(e);return}t.classList.remove(`file-content--raw`),t.classList.add(`file-content--preview`);let i=j.file,a=i?.path||i?.name||``,o=this.toPreviewMarkdown(n),s=X(this.db,e.MARKDOWN_FRONTMATTER_FILE_VIEWER),c=await A(o,{renderFrontmatter:typeof s==`boolean`?s:await s});if(!this.isRenderTokenCurrent(r))return;let l=this.rewriteWorkspacePreviewHtml(c,a);this.isRenderTokenCurrent(r)&&(d(t,l,Y),this.wrapCodeLines(t),await this.resolveMarkdownImages(t,a))}async requestCloseViewer(){return await this.canDismissViewer()?(await this.exitFullscreenIfActive(),j.closeFile(),!0):!1}async requestConfirmation(e){let t=document.querySelector(`shadow-claw`);return t&&typeof t.requestDialog==`function`?await t.requestDialog({mode:`confirm`,...e}):!1}async requestNativeFullscreen(e){let t=e.requestFullscreen||e.webkitRequestFullscreen;if(typeof t!=`function`)throw Error(`Native fullscreen unavailable`);await Promise.resolve(t.call(e))}async resolveMarkdownImages(e,t){if(!this.db)return;let n=Array.from(e.querySelectorAll(`img`));n.length!==0&&await Promise.all(n.map(async e=>{let n=e.getAttribute(`src`)||``;if(!n||/^(?:blob:|data:|#)/u.test(n))return;let r=this.getWorkspaceRouteTarget(n,{allowCrossGroup:!0})||(()=>{let e=this.resolveWorkspaceLinkPath(n,t);return e?{groupId:x.activeGroupId,path:e}:null})();if(r)try{let t=await b(this.db,r.groupId,r.path),n=r.path.split(`.`).pop()?.toLowerCase()||``,i=this.mimeTypeForImageExt(n),a=new Uint8Array(t.byteLength);a.set(t),e.src=await new Promise((e,t)=>{let n=new FileReader;n.onload=()=>e(n.result),n.onerror=t,n.readAsDataURL(new Blob([a],{type:i}))})}catch{}}))}async resolveRelativeImagesInHtml(e,t){if(!this.db||!e)return e;let n=new DOMParser().parseFromString(e,`text/html`),r=Array.from(n.querySelectorAll(`img`));return r.length===0?e:(await Promise.all(r.map(async e=>{let n=e.getAttribute(`src`)||``;if(!n||/^(?:blob:|data:|#)/u.test(n))return;let r=this.getWorkspaceRouteTarget(n,{allowCrossGroup:!0})||(()=>{let e=this.resolveWorkspaceLinkPath(n,t);return e?{groupId:x.activeGroupId,path:e}:null})();if(r)try{let t=await b(this.db,r.groupId,r.path),n=r.path.split(`.`).pop()?.toLowerCase()||``,i=this.mimeTypeForImageExt(n),a=new Uint8Array(t.byteLength);a.set(t);let o=await new Promise((e,t)=>{let n=new FileReader;n.onload=()=>e(n.result),n.onerror=t,n.readAsDataURL(new Blob([a],{type:i}))});e.setAttribute(`src`,o)}catch{}})),n.body.innerHTML)}async toggleFullscreenMode(e){let t=this.getFullscreenTarget(e);if(t){if(this.canUseNativeFullscreen(t)){let n=this.isTargetInFullscreen(t);try{n?(await this.exitNativeFullscreen(),this.isFullscreenMode=!1):(await this.requestNativeFullscreen(t),this.isFullscreenMode=!0)}catch{this.isFullscreenMode=!this.isFullscreenMode}this.applyFullscreenMode(e);return}this.isFullscreenMode=!this.isFullscreenMode,this.applyFullscreenMode(e)}}async updateView(e=this.viewRenderToken){let t=j.file,n=this.shadowRoot;if(!n||!t)return;let r=n.querySelector(`.file-modal`);if(!(r instanceof HTMLElement))return;this.applyFullscreenMode(r);let i=r.querySelector(`.file-content`),a=r.querySelector(`.modal-preview-btn`),o=r.querySelector(`.modal-body`);if(!(i instanceof HTMLElement))return;i.classList.remove(`file-content--iframe`);let s=this.getWorkingSourceFile(t,r),c=t.kind===`text`;a instanceof HTMLButtonElement&&(a.setAttribute(`aria-pressed`,String(this.isFilePreviewMode)),a.setAttribute(`aria-label`,this.isFilePreviewMode?`Switch to raw text view`:`Switch to preview mode`));let l=r.querySelector(`.file-editor-container`),u=r.querySelector(`.modal-edit-btn`),d=r.querySelector(`.modal-save-btn`),f=r.querySelector(`.modal-share-btn`),p=r.querySelector(`.modal-close-btn`),m=r.querySelector(`.modal-cancel-btn`),h=t?.groupId||x.activeGroupId||``,g=h.startsWith(`peer:`),_=h.startsWith(`room:`),v=g||_,y=this.canShareCurrentFile(t),b=r.querySelector(`.modal-share-dropdown`),S=r.querySelector(`.modal-share-peer-label`),C=r.querySelector(`.modal-share-device-btn`);if(b instanceof HTMLElement&&(v?(b.classList.remove(`hidden`),S&&(S.textContent=_?`Send to room peers`:`Send to peer`),C instanceof HTMLButtonElement&&(C.classList.toggle(`hidden`,!y),C.disabled=!y)):b.classList.add(`hidden`)),f instanceof HTMLButtonElement&&(v?(f.classList.add(`hidden`),f.disabled=!0):(f.classList.toggle(`hidden`,!y),f.disabled=!y)),p instanceof HTMLButtonElement){let e=this.hasUnsavedChanges();p.disabled=!1,p.setAttribute(`aria-label`,e?`Close file viewer (unsaved changes)`:`Close file viewer`),p.title=e?`Close (you have unsaved changes)`:`Close`}let w=this.hasUnsavedChanges();if(d instanceof HTMLButtonElement&&d.classList.toggle(`hidden`,!w),m instanceof HTMLButtonElement&&m.classList.toggle(`hidden`,!w),this.isFilePreviewMode){o?.classList.remove(`modal-body--editing`),i.classList.remove(`hidden`),l?.classList.remove(`active`),u instanceof HTMLButtonElement&&(u.setAttribute(`aria-pressed`,`false`),u.setAttribute(`aria-label`,`Edit file`),u.classList.toggle(`hidden`,!c)),await this.renderPreview(i,s,e);return}if(this.isRenderTokenCurrent(e))if(this.isFileEditMode&&c){o?.classList.add(`modal-body--editing`),i.classList.add(`hidden`),l?.classList.add(`active`),u instanceof HTMLButtonElement&&(u.setAttribute(`aria-pressed`,`true`),u.setAttribute(`aria-label`,`Switch to raw text view`),u.classList.remove(`hidden`));let e=l?.querySelector(`.file-editor`);if(e instanceof HTMLTextAreaElement){e.setAttribute(`tab-size`,`2`);let n=this.getLanguageFromFilename(t.name);if(n?e.setAttribute(`language`,n):e.removeAttribute(`language`),this.isEditorDirty)typeof s?.content==`string`&&(e.value!==s.content&&(e.value=s.content),this.updateEditorHighlight(e.value));else{let n=t.content||``;e.value!==n&&(e.value=n),this.updateEditorHighlight(e.value)}e.dispatchEvent(new Event(`scroll`))}}else o?.classList.remove(`modal-body--editing`),i.classList.remove(`hidden`),l?.classList.remove(`active`),u instanceof HTMLButtonElement&&(u.setAttribute(`aria-pressed`,`false`),u.setAttribute(`aria-label`,`Edit file`),u.classList.toggle(`hidden`,!c)),i.classList.add(`file-content--raw`),i.classList.remove(`file-content--preview`,`file-content--iframe`),t.kind===`binary`?i.textContent=`Binary file (${t.mimeType||`application/octet-stream`}). Switch to Preview to view.`:i.textContent=s.content||``}syncIframeTheme(){if(!this.previewFrameWindow)return;let e=document.documentElement.classList.contains(`dark-mode`),t=getComputedStyle(document.documentElement),n={};for(let e=0;e<t.length;e++){let r=t[e];r.startsWith(`--`)&&(n[r]=t.getPropertyValue(r))}this.previewFrameWindow.postMessage({type:`shadow-claw-theme-update`,theme:e?`dark`:`light`,customProperties:n},`*`)}async handleStorageProxyRequest(e,t,n,r){if(!t)return;let i=j.file,a=i?.path||i?.name||`__default__`;try{let i;switch(n){case`setItem`:await M(a,String(r.key||``),r.value);break;case`removeItem`:await I(a,String(r.key||``));break;case`clear`:await B(a);break;case`getAllItems`:i=await P(a);break;case`idb-get`:i=await R(`${a}::idb::${r.dbName}::${r.storeName}`,String(r.key||``));break;case`idb-getAll`:i=await P(`${a}::idb::${r.dbName}::${r.storeName}`);break;case`idb-put`:{let e=r.key==null?`__auto_${Date.now()}`:String(r.key);await M(`${a}::idb::${r.dbName}::${r.storeName}`,e,r.value),i=e;break}case`idb-delete`:await I(`${a}::idb::${r.dbName}::${r.storeName}`,String(r.key||``));break;case`idb-clear`:await B(`${a}::idb::${r.dbName}::${r.storeName}`);break;case`idb-deleteDatabase`:await B(`${a}::idb::${r.dbName}::__default__`);break;default:throw Error(`Unknown storage proxy method: ${n}`)}e.postMessage({type:`shadow-claw-storage-proxy-result`,requestId:t,result:i??null},`*`)}catch(n){e.postMessage({type:`shadow-claw-storage-proxy-result`,requestId:t,error:n instanceof Error?n.message:String(n)},`*`)}}async reloadPreviewWithSearchParams(e){let t=j.file;if(!t)return;let n=this.shadowRoot?.querySelector(`.file-viewer__iframe`);n&&(this.previewFrameWindow=null,f(n,await this.buildIframePreviewSrcdoc(t,e)))}};customElements.get(K)||customElements.define(K,Z);export{Z as ShadowClawFileViewer};
package/dist/server.js CHANGED
@@ -989,7 +989,7 @@ Invalid`)}},FromEmailAddress:`invalid@invalid`,Destination:{ToAddresses:[`invali
989
989
  </body>
990
990
  </html>`)}),e.get(`/docs`,(e,t)=>{t.redirect(`/api/docs`)})}function dxe(e){let t=k(),r=rr(e.verbose),{verbose:i}=e;t.use(nee(r,i)),t.use(Ka(r,i)),t.use(ar(e,r,i)),t.use(Ga({rootPath:e.rootPath})),t.use(O({filter(e,t){return t.getHeader(`Content-Type`)!==`text/event-stream`&&O.filter(e,t)}})),t.use(k.json({limit:`1000mb`})),f.existsSync(e.databaseDir)||f.mkdirSync(e.databaseDir,{recursive:!0}),gn(c.join(e.databaseDir,`push-subscriptions.db`)),kn(c.join(e.databaseDir,`clients.db`)),Kn(c.join(e.databaseDir,`scheduled-tasks.db`)),Lbe(t,{verbose:i,allowPrivateProxy:e.allowPrivateProxy}),Xbe(t);let a=e.cacheDir||(n.env.SHADOWCLAW_CACHE_DIR||``).trim()||(c.basename(e.databaseDir)===`database`?c.dirname(e.databaseDir):c.resolve(e.databaseDir,`..`));Vbe(t,{logsDir:c.resolve(a,`logs`)}),$be(t,{backupsDir:c.resolve(a,`backups`),token:e.controlToken,allowedOrigins:e.allowedOrigins,corsMode:e.corsMode}),Hbe(t,{logsDir:c.resolve(a,`logs`),logger:r}),En(t),$n(t),uxe(t);let o=new nr({getEnabledTasks:Zn,updateLastRun:Qn,broadcastTaskTrigger:e=>Tn({type:`scheduled-task`,taskId:e.id,groupId:e.groupId,prompt:e.prompt,taskType:e.type,tools:e.tools,channel:e.channel})});return e.serveStatic!==!1&&(aee(t,e.rootPath),t.use((e,t,n)=>{e.method===`GET`&&e.headers.accept?.includes(`text/html`)?t.redirect(e.baseUrl||`/`):n()})),{app:t,scheduler:o}}nc();function fxe(e){return e&&e.__esModule?e.default:e}var pxe={host:`::`,port:9e3,expire_timeout:5e3,alive_timeout:9e4,key:`peerjs`,path:`/`,concurrent_limit:5e3,allow_discovery:!1,proxied:!1,cleanup_out_msgs:1e3,corsOptions:{origin:!0}},mxe=class{lastReadAt=new Date().getTime();messages=[];getLastReadAt(){return this.lastReadAt}addMessage(e){this.messages.push(e)}readMessage(){if(this.messages.length>0)return this.lastReadAt=new Date().getTime(),this.messages.shift()}getMessages(){return this.messages}},hxe=class{clients=new Map;messageQueues=new Map;getClientsIds(){return[...this.clients.keys()]}getClientById(e){return this.clients.get(e)}getClientsIdsWithQueue(){return[...this.messageQueues.keys()]}setClient(e,t){this.clients.set(t,e)}removeClientById(e){return this.getClientById(e)?(this.clients.delete(e),!0):!1}getMessageQueueById(e){return this.messageQueues.get(e)}addMessageToQueue(e,t){this.getMessageQueueById(e)||this.messageQueues.set(e,new mxe),this.getMessageQueueById(e)?.addMessage(t)}clearMessageQueue(e){this.messageQueues.delete(e)}generateClientId(e){let t=e||te,n=t();for(;this.getClientById(n);)n=t();return n}},gxe=class{timeoutId=null;constructor({realm:e,config:t,checkInterval:n=300,onClose:r}){this.realm=e,this.config=t,this.onClose=r,this.checkInterval=n}start(){this.timeoutId&&clearTimeout(this.timeoutId),this.timeoutId=setTimeout(()=>{this.checkConnections(),this.timeoutId=null,this.start()},this.checkInterval)}stop(){this.timeoutId&&=(clearTimeout(this.timeoutId),null)}checkConnections(){let e=this.realm.getClientsIds(),t=new Date().getTime(),{alive_timeout:n}=this.config;for(let r of e){let e=this.realm.getClientById(r);if(e&&!(t-e.getLastPing()<n))try{e.getSocket()?.close()}finally{this.realm.clearMessageQueue(r),this.realm.removeClientById(r),e.setSocket(null),this.onClose?.(e)}}}};let pp;(function(e){e.INVALID_KEY=`Invalid key provided`,e.INVALID_TOKEN=`Invalid token provided`,e.INVALID_WS_PARAMETERS=`No id, token, or key supplied to websocket server`,e.CONNECTION_LIMIT_EXCEED=`Server has reached its concurrent user limit`})(pp||={});let mp;(function(e){e.OPEN=`OPEN`,e.LEAVE=`LEAVE`,e.CANDIDATE=`CANDIDATE`,e.OFFER=`OFFER`,e.ANSWER=`ANSWER`,e.EXPIRE=`EXPIRE`,e.HEARTBEAT=`HEARTBEAT`,e.ID_TAKEN=`ID-TAKEN`,e.ERROR=`ERROR`})(mp||={});var _xe=class{timeoutId=null;constructor({realm:e,config:t,messageHandler:n}){this.realm=e,this.config=t,this.messageHandler=n}startMessagesExpiration(){this.timeoutId&&clearTimeout(this.timeoutId),this.timeoutId=setTimeout(()=>{this.pruneOutstanding(),this.timeoutId=null,this.startMessagesExpiration()},this.config.cleanup_out_msgs)}stopMessagesExpiration(){this.timeoutId&&=(clearTimeout(this.timeoutId),null)}pruneOutstanding(){let e=this.realm.getClientsIdsWithQueue(),t=new Date().getTime(),n=this.config.expire_timeout,r={};for(let i of e){let e=this.realm.getMessageQueueById(i);if(!e||t-e.getLastReadAt()<n)continue;let a=e.getMessages();for(let e of a){let t=`${e.src}_${e.dst}`;r[t]||(this.messageHandler.handle(void 0,{type:mp.EXPIRE,src:e.dst,dst:e.src}),r[t]=!0)}this.realm.clearMessageQueue(i)}}},vxe=class{socket=null;lastPing=new Date().getTime();constructor({id:e,token:t}){this.id=e,this.token=t}getId(){return this.id}getToken(){return this.token}getSocket(){return this.socket}setSocket(e){this.socket=e}getLastPing(){return this.lastPing}setLastPing(e){this.lastPing=e}send(e){this.socket?.send(JSON.stringify(e))}},yxe=class extends Ye{constructor({server:e,realm:t,config:n}){super(),this.setMaxListeners(0),this.realm=t,this.config=n;let r=this.config.path;this.path=`${r}${r.endsWith(`/`)?``:`/`}peerjs`;let i={path:this.path,server:e};this.socketServer=n.createWebSocketServer?n.createWebSocketServer(i):new tc.default(i),this.socketServer.on(`connection`,(e,t)=>{this._onSocketConnection(e,t)}),this.socketServer.on(`error`,e=>{this._onSocketError(e)})}_onSocketConnection(e,t){e.on(`error`,e=>{this._onSocketError(e)});let{searchParams:n}=new URL(t.url??``,`https://peerjs`),{id:r,token:i,key:a}=Object.fromEntries(n.entries());if(!r||!i||!a){this._sendErrorAndClose(e,pp.INVALID_WS_PARAMETERS);return}if(a!==this.config.key){this._sendErrorAndClose(e,pp.INVALID_KEY);return}let o=this.realm.getClientById(r);if(o){if(i!==o.getToken()){e.send(JSON.stringify({type:mp.ID_TAKEN,payload:{msg:`ID is taken`}})),e.close();return}this._configureWS(e,o);return}this._registerClient({socket:e,id:r,token:i})}_onSocketError(e){this.emit(`error`,e)}_registerClient({socket:e,id:t,token:n}){if(this.realm.getClientsIds().length>=this.config.concurrent_limit){this._sendErrorAndClose(e,pp.CONNECTION_LIMIT_EXCEED);return}let r=new vxe({id:t,token:n});this.realm.setClient(r,t),e.send(JSON.stringify({type:mp.OPEN})),this._configureWS(e,r)}_configureWS(e,t){t.setSocket(e),e.on(`close`,()=>{t.getSocket()===e&&(this.realm.removeClientById(t.getId()),this.emit(`close`,t))}),e.on(`message`,e=>{try{let n=JSON.parse(e.toString());n.src=t.getId(),this.emit(`message`,t,n)}catch(e){this.emit(`error`,e)}}),this.emit(`connection`,t)}_sendErrorAndClose(e,t){e.send(JSON.stringify({type:mp.ERROR,payload:{msg:t}})),e.close()}};const bxe=e=>{if(e){let t=new Date().getTime();e.setLastPing(t)}return!0},xxe=({realm:e})=>{let t=(n,r)=>{let i=r.type,a=r.src,o=r.dst,s=e.getClientById(o);if(s){let i=s.getSocket();try{if(i){let e=JSON.stringify(r);i.send(e)}else throw Error(`Peer dead`)}catch{i?i.close():e.removeClientById(s.getId()),t(n,{type:mp.LEAVE,src:o,dst:a})}}else![mp.LEAVE,mp.EXPIRE].includes(i)&&o?e.addMessageToQueue(o,r):i===mp.LEAVE&&!o&&e.removeClientById(a);return!0};return t};var Sxe=class{handlers=new Map;registerHandler(e,t){this.handlers.has(e)||this.handlers.set(e,t)}handle(e,t){let{type:n}=t,r=this.handlers.get(n);return r?r(e,t):!1}},Cxe=class{constructor(e,t=new Sxe){this.handlersRegistry=t;let n=xxe({realm:e}),r=bxe,i=(e,{type:t,src:r,dst:i,payload:a})=>n(e,{type:t,src:r,dst:i,payload:a});this.handlersRegistry.registerHandler(mp.HEARTBEAT,(e,t)=>r(e,t)),this.handlersRegistry.registerHandler(mp.OFFER,i),this.handlersRegistry.registerHandler(mp.ANSWER,i),this.handlersRegistry.registerHandler(mp.CANDIDATE,i),this.handlersRegistry.registerHandler(mp.LEAVE,i),this.handlersRegistry.registerHandler(mp.EXPIRE,i)}handle(e,t){return this.handlersRegistry.handle(e,t)}},wxe={};wxe=JSON.parse(`{"name":"PeerJS Server","description":"A server side element to broker connections between PeerJS clients.","website":"https://peerjs.com/"}`);var Txe=({config:e,realm:t})=>{let n=k.Router();return n.get(`/id`,(n,r)=>{r.contentType(`html`),r.send(t.generateClientId(e.generateClientId))}),n.get(`/peers`,(n,r)=>{if(e.allow_discovery){let e=t.getClientsIds();return r.send(e)}return r.sendStatus(401)}),n};const Exe=({config:e,realm:t,corsOptions:n})=>{let r=k.Router();return r.use(ne(n)),r.get(`/`,(e,t)=>{t.send(fxe(wxe))}),r.use(`/:key`,Txe({config:e,realm:t})),r},Dxe=({app:e,server:t,options:n})=>{let r=n,i=new hxe,a=new Cxe(i),o=Exe({config:r,realm:i,corsOptions:n.corsOptions}),s=new _xe({realm:i,config:r,messageHandler:a}),l=new gxe({realm:i,config:r,onClose:t=>{e.emit(`disconnect`,t)}});e.use(n.path,o);let u=new yxe({server:t,realm:i,config:{...r,path:c.posix.join(e.path(),n.path,`/`)}});u.on(`connection`,t=>{let n=i.getMessageQueueById(t.getId());if(n){let e;for(;e=n.readMessage();)a.handle(t,e);i.clearMessageQueue(t.getId())}e.emit(`connection`,t)}),u.on(`message`,(t,n)=>{e.emit(`message`,t,n),a.handle(t,n)}),u.on(`close`,t=>{e.emit(`disconnect`,t)}),u.on(`error`,t=>{e.emit(`error`,t)}),s.startMessagesExpiration(),l.start()};function Oxe(e,t){let n=k(),r={...pxe,...t};return r.proxied&&n.set(`trust proxy`,r.proxied!==`false`&&!!r.proxied),n.on(`mount`,()=>{if(!e)throw Error(`Server is not passed to constructor - can't start PeerServer`);Dxe({app:n,server:e,options:r})}),n}function kxe(e,t){let n=Oxe(e,{path:`/`,allow_discovery:!1});t.use(n),n.on(`connection`,e=>{console.log(`PeerJS: client connected — ${e.getId()}`)}),n.on(`disconnect`,e=>{console.log(`PeerJS: client disconnected — ${e.getId()}`)})}function hp(){let e=Date.now();if(e===yp)for(let e=bp.length-1;e>=0;e--){if(bp[e]<_p-1){bp[e]++;break}bp[e]=0}else yp=e,bp=Array.from(crypto.getRandomValues(new Uint8Array(Axe)),e=>e%_p);let t=e,n=Array(vp);for(let e=vp-1;e>=0;e--)n[e]=gp[t%_p],t=Math.floor(t/_p);let r=bp.map(e=>gp[e]);return n.join(``)+r.join(``)}var gp,_p,vp,Axe,yp,bp,xp=V((()=>{gp=`0123456789ABCDEFGHJKMNPQRSTVWXYZ`,_p=32,vp=10,Axe=16,yp=0,bp=[]}));nc(),xp();function jxe(e){let{httpServer:t,app:n,heartbeatTimeoutMs:r=9e4,verbose:i=!1}=e,a=e.token||Bn(void 0,e.cacheDir),o=new tc.default({noServer:!0}),s=new Map,c=new Map,l=new Map,u=new Map,d=new Set,f=setInterval(()=>{Fn(r)},Math.max(1e4,Math.floor(r/2)));typeof f.unref==`function`&&f.unref();function p(e){i&&console.log(`[control-plane] ${e}`)}function m(t){if(!t)return!1;if(t===a)return!0;try{let n=Bn(void 0,e.cacheDir);if(n&&t===n)return!0}catch{}return!1}function h(t){let n=t.headers.host||`127.0.0.1`,r=t.headers.origin,i=t.headers.referer,a=t=>{try{let r=new C(t);if(r.host===n)return!0;let i=r.hostname.toLowerCase();if(i===`127.0.0.1`||i===`localhost`||i===`::1`||i===`[::1]`||i===`github.com`||i.endsWith(`.github.io`)||i.endsWith(`.pages.dev`)||e.corsMode===`all`||e.allowedOrigins&&e.allowedOrigins.has(r.origin)||e.corsMode===`private`&&/^(127\.|10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.)/.test(i))return!0}catch{}return!1};if(r&&a(r)||i&&a(i))return!0;let o=t.headers[`sec-fetch-site`];return o===`same-origin`||o===`same-site`}function g(e,t){let n=t.searchParams.get(`token`);if(n)return n;let r=e.headers[`x-control-token`];if(typeof r==`string`)return r;let i=e.headers.authorization;return i&&i.startsWith(`Bearer `)?i.slice(7).trim():null}let _=(e,t,n)=>{let r=e.headers.host||`127.0.0.1`,i=new C(e.url||`/`,`http://${r}`);if(i.pathname===`/ws/control`){let r=g(e,i);if(!(r?m(r):h(e))){p(`Rejected unauthorized WebSocket connection from ${e.socket.remoteAddress}`),o.handleUpgrade(e,t,n,e=>{e.close(4001,`Unauthorized`)});return}o.handleUpgrade(e,t,n,t=>{o.emit(`connection`,t,e)})}};t.on(`upgrade`,_);function v(e,t){let{id:n,type:r,payload:i}=t;if(r===`client:register`){let t=i;if(t?.clientId&&typeof t.clientId==`string`&&t.clientId.trim()){let r=t.clientId.trim();An({clientId:r,deviceLabel:t.deviceLabel||`Unknown device`,capabilities:t.capabilities||[],version:t.version||`1.0.0`,peerId:t.peerId}),e&&(s.set(r,e),c.set(e,r)),p(`Client registered: ${r} (${t.deviceLabel})`);let i={id:hp(),type:`server:registered`,replyTo:n,payload:{clientId:r,status:`ok`,serverTime:Date.now()}};return e&&e.readyState===ec.default.OPEN&&e.send(JSON.stringify(i)),i}else p(`Warning: received client:register without valid clientId`)}else if(r===`client:heartbeat`){let e=i;e?.clientId&&(jn(e.clientId),p(`Heartbeat from client: ${e.clientId}`))}else if(r===`client:unregister`){let t=i,n=t?.clientId&&typeof t.clientId==`string`&&t.clientId.trim()||(e?c.get(e):void 0);n&&(Mn(n),e&&(s.delete(n),c.delete(e)),l.delete(n),p(`Client explicitly unregistered: ${n}`))}else if(r===`command:result`){let e=i;if(e?.commandId&&u.has(e.commandId)){let t=u.get(e.commandId);clearTimeout(t.timeout),u.delete(e.commandId),t.resolve(e),p(`Command ${e.commandId} resolved: success=${e.success}`)}}}if(o.on(`connection`,e=>{p(`WebSocket client connected`),e.on(`message`,t=>{try{v(e,JSON.parse(t.toString()))}catch(e){p(`Error parsing WebSocket message: ${e.message}`)}}),e.on(`close`,()=>{let t=c.get(e);t&&(s.delete(t),c.delete(e),p(`Client disconnected: ${t}`),x(t)||Mn(t))}),e.on(`error`,e=>{p(`WebSocket error: ${e.message}`)})}),n){let e=(e,t,n)=>{let r=e.headers.host||`127.0.0.1`;if(!m(g(e,new C(e.url,`http://${r}`)))){t.status(401).json({error:`Unauthorized: Invalid control token`});return}n()},t=(e,t,n)=>{let r=e.headers.host||`127.0.0.1`,i=g(e,new C(e.url,`http://${r}`));if(!(i?m(i):h(e))){t.status(401).json({error:`Unauthorized: Invalid control token`});return}n()};n.get(`/api/control/health`,(e,t)=>{t.json({status:`ok`,controlPlane:!0})}),n.get(`/api/control/clients`,e,(e,t)=>{let n=e.query.all===`true`||e.query.all===`1`?Pn():w();t.json({clients:n})}),n.post(`/api/control/command`,e,async(e,t)=>{let{clientId:n,action:r,args:i,timeoutMs:a}=e.body||{};if(!n||!r){t.status(400).json({error:`clientId and action are required`});return}try{let e=await y(n,r,i,a);t.json(e)}catch(e){t.status(e.message?.includes(`not connected`)?404:500).json({error:e.message})}}),n.post(`/api/control/messages`,t,(e,t)=>{let n=e.body;if(!n||!n.type){t.status(400).json({error:`Invalid control message payload`});return}let r=v(null,n);t.json({status:`received`,reply:r})}),n.get(`/api/control/events`,t,(e,t)=>{let n=e.headers.host||`127.0.0.1`,r=new C(e.url,`http://${n}`).searchParams.get(`clientId`)||e.headers[`x-client-id`]||void 0;t.setHeader(`Content-Type`,`text/event-stream`),t.setHeader(`Cache-Control`,`no-cache`),t.setHeader(`Connection`,`keep-alive`),t.flushHeaders?.(),d.add(t),r&&(l.set(r,t),p(`SSE client connected: ${r}`)),t.write(`event: ready\ndata: ${JSON.stringify({status:`ok`,serverTime:Date.now()})}\n\n`);let i=setInterval(()=>{t.writableEnded||t.write(`: ping
991
991
 
992
- `)},15e3);e.on(`close`,()=>{clearInterval(i),d.delete(t),r&&l.get(r)===t&&(l.delete(r),p(`SSE client disconnected: ${r}`),x(r)||Mn(r))})})}function y(e,t,n={},r=3e4){let i=s.get(e),a=l.get(e),o=i&&i.readyState===ec.default.OPEN,c=a&&!a.writableEnded;if(!o&&!c)return Promise.reject(Error(`Client not connected: ${e}`));let d=hp(),f={commandId:d,action:t,args:n},p={id:hp(),type:`command:execute`,payload:f};return new Promise((n,s)=>{let l=setTimeout(()=>{u.delete(d),s(Error(`Command ${t} to client ${e} timed out after ${r}ms`))},r);u.set(d,{resolve:n,reject:s,timeout:l});try{o?i.send(JSON.stringify(p)):c&&a.write(`event: command:execute\ndata: ${JSON.stringify(p)}\n\n`)}catch(e){clearTimeout(l),u.delete(d),s(e)}})}async function b(e,t={},n=3e4){let r=new Set([...s.keys(),...l.keys()]),i=[];for(let a of r)x(a)&&i.push(y(a,e,t,n).catch(e=>({commandId:``,success:!1,error:e.message})));return Promise.all(i)}function x(e){let t=s.get(e);if(t&&t.readyState===ec.default.OPEN)return!0;let n=l.get(e);return!!(n&&!n.writableEnded)}let S=``;function w(){return Pn().filter(e=>x(e.clientId))}function T(){if(S&&x(S))return S;let e=w();return e.length>0?e[0].clientId:``}function E(e){S=e}function D(){clearInterval(f),t.removeListener(`upgrade`,_);for(let[,e]of u)clearTimeout(e.timeout),e.reject(Error(`Control plane closed`));u.clear();for(let e of s.values())try{e.close()}catch{}s.clear(),c.clear();for(let e of d)try{e.end()}catch{}d.clear(),l.clear();try{o.close()}catch{}}return{sendCommand:y,broadcastCommand:b,isClientConnected:x,getConnectedClients:w,getActiveClientId:T,setActiveClientId:E,getToken:()=>a,close:D}}const Sp=`2026-07-28`,Cp=[Sp,`2025-11-25`,`2024-11-05`],wp={ParseError:-32700,InvalidRequest:-32600,MethodNotFound:-32601,InvalidParams:-32602,InternalError:-32603,HeaderMismatch:-32020,MissingRequiredClientCapability:-32021,UnsupportedProtocolVersion:-32022};var Mxe=class{_name;_version;_tools=new Map;_handlers=new Map;_toolProvider;constructor(e={}){if(this._name=e.name||`shadow-claw`,this._version=e.version||fp(),this._toolProvider=e.toolProvider,e.tools)for(let t of e.tools)this.registerTool(t)}get serverInfo(){return{name:this._name,version:this._version}}get capabilities(){return{tools:{listChanged:!0},extensions:{"io.modelcontextprotocol/tasks":{}}}}registerTool(e,t){this._tools.set(e.name,e),t&&this._handlers.set(e.name,t)}registerToolHandler(e,t){this._handlers.set(e,t)}setToolProvider(e){this._toolProvider=e}async getTools(){let e=new Map(this._tools);if(this._toolProvider)try{let t=await this._toolProvider();if(Array.isArray(t))for(let n of t)e.set(n.name,n)}catch(e){console.warn(`[McpServer] Error fetching dynamic tools:`,e)}return Array.from(e.values()).sort((e,t)=>e.name.localeCompare(t.name))}async handleRequest(e,t){let n=e.id===void 0||e.id===null,r=e.id??null;if(t){let n=t[`mcp-protocol-version`];if(n&&!Cp.includes(n))return this._makeError(r,wp.UnsupportedProtocolVersion,`Unsupported protocol version: '${n}'. Supported versions: ${Cp.join(`, `)}`);let i=t[`mcp-method`];if(i&&i!==e.method)return this._makeError(r,wp.HeaderMismatch,`Mcp-Method header '${i}' does not match body method '${e.method}'`);let a=t[`mcp-name`];if(a&&e.method===`tools/call`&&e.params?.name&&a!==e.params.name)return this._makeError(r,wp.HeaderMismatch,`Mcp-Name header '${a}' does not match params.name '${e.params.name}'`)}switch(e.method){case`server/discover`:{let e={protocolVersion:Sp,supportedProtocolVersions:[...Cp],capabilities:this.capabilities,serverInfo:this.serverInfo,_meta:{"io.modelcontextprotocol/serverInfo":this.serverInfo}};return this._makeSuccess(r,e)}case`initialize`:{let t={protocolVersion:e.params?.protocolVersion||`2024-11-05`,capabilities:this.capabilities,serverInfo:this.serverInfo};return this._makeSuccess(r,t)}case`notifications/initialized`:return null;case`tools/list`:{let e={resultType:`complete`,ttlMs:5e3,cacheScope:`private`,tools:await this.getTools(),_meta:{"io.modelcontextprotocol/serverInfo":this.serverInfo}};return this._makeSuccess(r,e)}case`tools/call`:{let t=e.params?.name;if(!t||typeof t!=`string`)return this._makeError(r,wp.InvalidParams,`Missing required parameter 'name'`);let n=this._handlers.get(t);if(!n&&this._toolProvider)try{await this.getTools(),n=this._handlers.get(t)}catch{}if(!n)return this._makeError(r,wp.InvalidParams,`Tool not found: '${t}'`);try{let t=await n(e.params?.arguments||{},e.params?._meta,e.params?.inputResponses);if(typeof t==`object`&&t&&t.resultType===`input_required`){let e=t;return e._meta={"io.modelcontextprotocol/serverInfo":this.serverInfo,...e._meta||{}},this._makeSuccess(r,e)}let i={resultType:`complete`,content:t.content||[],isError:t.isError||!1,_meta:{"io.modelcontextprotocol/serverInfo":this.serverInfo}};return this._makeSuccess(r,i)}catch(e){return this._makeSuccess(r,{resultType:`complete`,content:[{type:`text`,text:`Error executing tool '${t}': ${e.message||String(e)}`}],isError:!0,_meta:{"io.modelcontextprotocol/serverInfo":this.serverInfo}})}}case`tasks/get`:{let t=e.params?.taskId;return t?this._makeSuccess(r,{resultType:`complete`,task:{taskId:t,status:`completed`},_meta:{"io.modelcontextprotocol/serverInfo":this.serverInfo}}):this._makeError(r,wp.InvalidParams,`Missing taskId parameter`)}case`tasks/update`:{let t=e.params?.taskId;return this._makeSuccess(r,{resultType:`complete`,task:{taskId:t||`unknown`,status:`running`},_meta:{"io.modelcontextprotocol/serverInfo":this.serverInfo}})}default:return n?null:this._makeError(r,wp.MethodNotFound,`Method not found: '${e.method}'`)}}_makeSuccess(e,t){return{jsonrpc:`2.0`,id:e,result:t}}_makeError(e,t,n,r){return{jsonrpc:`2.0`,id:e,error:{code:t,message:n,...r===void 0?{}:{data:r}}}}};const Nxe=[{name:`shadowclaw_server_list_clients`,description:`List connected browser and Electron clients, including device type, ID, and active capabilities.`,inputSchema:{type:`object`,properties:{}}},{name:`shadowclaw_server_send_message`,description:`Send a message or prompt to a connected ShadowClaw client's active AI orchestrator queue.`,inputSchema:{type:`object`,properties:{text:{type:`string`,description:`The prompt or message text to dispatch.`},clientId:{type:`string`,description:`Target client ID. If omitted, targets the first available connected client.`},groupId:{type:`string`,description:`Target conversation group ID (e.g. 'br:main'). If omitted, targets the active group.`}},required:[`text`]}},{name:`shadowclaw_server_read_state`,description:`Read the current orchestrator state (idle, responding, etc.), active group ID, and capabilities from a connected client.`,inputSchema:{type:`object`,properties:{clientId:{type:`string`,description:`Target client ID (defaults to first available connected client).`}}}},{name:`shadowclaw_server_list_tasks`,description:`List scheduled background tasks configured on a connected client (optionally filtered by conversation group).`,inputSchema:{type:`object`,properties:{clientId:{type:`string`,description:`Target client ID (defaults to first available connected client).`},groupId:{type:`string`,description:`Optional conversation group ID filter.`}}}},{name:`shadowclaw_server_set_active_client`,description:`Set the active default connected client used when no clientId is explicitly provided in tool calls.`,inputSchema:{type:`object`,properties:{clientId:{type:`string`,description:`Target client ID (or index '0', '1', prefix, or device label) to make active.`}},required:[`clientId`]}},{name:`shadowclaw_server_manage_backup`,description:`Trigger or manage OPFS workspace file backups for a connected client (trigger, list, or delete).`,inputSchema:{type:`object`,properties:{action:{type:`string`,enum:[`trigger`,`list`,`delete`],description:`Backup action to perform (default: 'trigger').`,default:`trigger`},clientId:{type:`string`,description:`Target client ID.`},backupId:{type:`string`,description:`Backup snapshot ID (required for 'delete').`},groupId:{type:`string`,description:`Optional workspace conversation group ID.`}}}},{name:`shadowclaw_server_status`,description:`Query ShadowClaw Node server status, version, and active client count.`,inputSchema:{type:`object`,properties:{}}},{name:`shadowclaw_server_send_notification`,description:`Broadcast an OS-level push notification to subscribed devices via Web Push (VAPID), or send to a specific registered client. Works even when the client browser tab is closed, asleep, or running in the background.`,inputSchema:{type:`object`,properties:{title:{type:`string`,description:`Notification title (default: 'ShadowClaw').`},body:{type:`string`,description:`The notification body message text.`},clientId:{type:`string`,description:`Target client ID, prefix, or device label of a specific client that has registered in the past. If omitted, broadcasts to all subscribed devices.`}},required:[`body`]}}];function Tp(e,t){try{let n=typeof e.getConnectedClients==`function`?e.getConnectedClients():typeof e.listClients==`function`?e.listClients():[];if(Array.isArray(n)&&n.length>0){if(typeof t==`string`&&t.trim()){let e=t.trim(),r=n.find(t=>(t.clientId||t.id)===e);if(r)return r.clientId||r.id||``;let i=parseInt(e,10);if(!isNaN(i)&&i>=0&&i<n.length)return n[i].clientId||n[i].id||``;let a=n.find(t=>(t.clientId||t.id||``).startsWith(e)||(t.clientId||t.id||``).replace(/^client-/,``).startsWith(e));if(a)return a.clientId||a.id||``;let o=n.find(t=>t.deviceLabel?.toLowerCase().includes(e.toLowerCase()));return o?o.clientId||o.id||``:e}if(typeof e.getActiveClientId==`function`){let t=e.getActiveClientId();if(t)return t}return n[0].clientId||n[0].id||``}}catch{}return typeof t==`string`?t.trim():``}function Pxe(e=[],t=`shadowclaw_server_send_notification`){let n=[...e].sort((e,t)=>e.clientId.localeCompare(t.clientId)),r=n.map(e=>e.clientId).filter(Boolean),i={type:`string`,description:r.length>0?`Target client ID, prefix, or device label of a specific client registered for push notifications (optional; if omitted, broadcasts to all subscribed devices). Available on: ${n.map(e=>`${e.clientId} (${e.deviceLabel||`Client`})`).join(`, `)}`:`Target client ID, prefix, or device label of a specific client that has registered in the past. If omitted, broadcasts to all subscribed devices.`};return r.length>0&&(i.enum=r),{name:t,description:`Broadcast an OS-level push notification to subscribed devices via Web Push (VAPID), or send to a specific registered client. Works even when the client browser tab is closed, asleep, or running in the background.`,inputSchema:{type:`object`,properties:{title:{type:`string`,description:`Notification title (default: 'ShadowClaw').`},body:{type:`string`,description:`Notification body message text.`},clientId:i},required:[`body`]}}}function Fxe(e,t=`shadowclaw_server_send_notification`){let n=[];try{n=wn()}catch{}if(e&&Array.isArray(n)&&n.length>0)try{let t=typeof e.getConnectedClients==`function`?e.getConnectedClients():typeof e.listClients==`function`?e.listClients():[];if(Array.isArray(t)){for(let e of n)if(!e.deviceLabel){let n=t.find(t=>(t.clientId||t.id)===e.clientId);n&&n.deviceLabel&&(e.deviceLabel=n.deviceLabel)}}}catch{}return Pxe(n,t)}const Ixe=Nxe;async function Lxe(e){let t=typeof e.getConnectedClients==`function`?e.getConnectedClients():typeof e.listClients==`function`?await e.listClients():[];return{content:[{type:`text`,text:JSON.stringify({clients:t},null,2)}]}}async function Rxe(e,t){let n=String(t.text||``).trim();if(!n)return{isError:!0,content:[{type:`text`,text:`Error: Message 'text' parameter cannot be empty.`}]};let r=Tp(e,typeof t.clientId==`string`?t.clientId:void 0);if(!r)return{isError:!0,content:[{type:`text`,text:`Error: No active ShadowClaw browser or Electron clients connected.`}]};let i=await e.sendCommand?.(r,`send-message`,{text:n,groupId:t.groupId});return{content:[{type:`text`,text:JSON.stringify(i?.data||i,null,2)}],isError:!i?.success}}async function zxe(e,t){let n=Tp(e,typeof t.clientId==`string`?t.clientId:void 0);if(!n)return{isError:!0,content:[{type:`text`,text:`Error: No active ShadowClaw clients connected.`}]};let r=await e.sendCommand?.(n,`read-state`,{});return{content:[{type:`text`,text:JSON.stringify(r?.data||r,null,2)}],isError:!r?.success}}async function Bxe(e,t){let n=Tp(e,typeof t.clientId==`string`?t.clientId:void 0);if(!n)return{isError:!0,content:[{type:`text`,text:`Error: No active ShadowClaw clients connected.`}]};let r=await e.sendCommand?.(n,`list-tasks`,{groupId:t.groupId});return{content:[{type:`text`,text:JSON.stringify(r?.data||r,null,2)}],isError:!r?.success}}async function Vxe(e,t){let n=String(t.action||`trigger`).toLowerCase(),r=Tp(e,typeof t.clientId==`string`?t.clientId:void 0);if(n===`trigger`){if(!r)return{isError:!0,content:[{type:`text`,text:`Error: No active ShadowClaw clients connected.`}]};let t=await e.sendCommand?.(r,`trigger-backup`,{});return{content:[{type:`text`,text:JSON.stringify(t?.data||t,null,2)}],isError:!t?.success}}if(n===`list`){if(typeof e.listBackups==`function`){let t=await e.listBackups();return{content:[{type:`text`,text:JSON.stringify({backups:t},null,2)}]}}if(!r)return{isError:!0,content:[{type:`text`,text:`Error: No active ShadowClaw clients connected.`}]};let t=await e.sendCommand?.(r,`list-backups`,{});return{content:[{type:`text`,text:JSON.stringify(t?.data||t,null,2)}],isError:!t?.success}}if(n===`delete`){if(!t.backupId)return{isError:!0,content:[{type:`text`,text:`Error: 'backupId' required for delete action.`}]};if(typeof e.deleteBackup==`function`){let n=await e.deleteBackup(t.backupId,r);return{content:[{type:`text`,text:JSON.stringify(n,null,2)}]}}if(!r)return{isError:!0,content:[{type:`text`,text:`Error: No active ShadowClaw clients connected.`}]};let n=await e.sendCommand?.(r,`delete-backup`,{backupId:t.backupId});return{content:[{type:`text`,text:JSON.stringify(n?.data||n,null,2)}],isError:!n?.success}}if(n===`status`){if(typeof e.getBackupStatus==`function`){let t=await e.getBackupStatus();return{content:[{type:`text`,text:JSON.stringify(t,null,2)}]}}if(!r)return{isError:!0,content:[{type:`text`,text:`Error: No active ShadowClaw clients connected.`}]};let t=await e.sendCommand?.(r,`get-backup-status`,{});return{content:[{type:`text`,text:JSON.stringify(t?.data||t,null,2)}],isError:!t?.success}}return{isError:!0,content:[{type:`text`,text:`Unsupported backup action: '${n}'`}]}}async function Hxe(e,t){let n=Tp(e,typeof t.clientId==`string`?t.clientId:void 0);return n?(typeof e.setActiveClientId==`function`&&e.setActiveClientId(n),{content:[{type:`text`,text:`Active default client set to: ${n}`}],_meta:{activeClientId:n}}):{isError:!0,content:[{type:`text`,text:`Error: Client '${t.clientId}' not found among connected clients.`}]}}async function Uxe(e){let t=typeof e.getConnectedClients==`function`?e.getConnectedClients():[];return{content:[{type:`text`,text:JSON.stringify({server:`ShadowClaw`,version:fp(),connectedClients:t?.length||0,status:`healthy`},null,2)}]}}async function Ep(e,t){let n=String(t.body||``).trim();if(!n)return{isError:!0,content:[{type:`text`,text:`Error: Notification 'body' parameter cannot be empty.`}]};let r=String(t.title||`ShadowClaw`).trim(),i=typeof t.clientId==`string`&&t.clientId.trim()?t.clientId.trim():void 0;try{let e=await Tn({title:r,body:n},i?{clientId:i}:void 0),t=e?.sent??0,a=e?.failed??0,o;return o=e?.notFound?`Warning: No push subscriptions found for client '${i}'. Ensure push notifications were registered by this client in ShadowClaw Settings.`:e?.noSubscribers?`Warning: Push notification broadcast completed, but no devices are currently subscribed to push notifications. Enable push notifications in ShadowClaw Settings on the client first.`:i?`Push notification sent to client '${i}': ${t} recipient(s) delivered, ${a} failed.`:`Push notification broadcast sent: ${t} recipient(s) delivered, ${a} failed.`,{content:[{type:`text`,text:o}],_meta:{...e,...i?{targetClientId:i}:{}}}}catch(e){return{isError:!0,content:[{type:`text`,text:`Failed to send push notification: ${e instanceof Error?e.message:String(e)}`}]}}}const Wxe=new Map([[`shadowclaw_server_list_clients`,Lxe],[`shadowclaw_list_clients`,Lxe],[`shadowclaw_server_send_message`,Rxe],[`shadowclaw_send_message`,Rxe],[`shadowclaw_server_read_state`,zxe],[`shadowclaw_read_state`,zxe],[`shadowclaw_server_list_tasks`,Bxe],[`shadowclaw_list_tasks`,Bxe],[`shadowclaw_server_manage_backup`,Vxe],[`shadowclaw_manage_backup`,Vxe],[`shadowclaw_server_set_active_client`,Hxe],[`shadowclaw_set_active_client`,Hxe],[`shadowclaw_server_status`,Uxe],[`shadowclaw_status`,Uxe],[`shadowclaw_server_send_notification`,Ep],[`shadowclaw_send_notification`,Ep],[`send_notification`,Ep]]);function Gxe(e,t){e.setToolProvider(async()=>[Fxe(t)]);for(let n of Ixe){let r=async e=>{let r=Wxe.get(n.name);return r?await r(t,e):{isError:!0,content:[{type:`text`,text:`Unknown tool: '${n.name}'`}]}};if(e.registerTool(n,r),n.name.startsWith(`shadowclaw_server_`)){let t=`shadowclaw_${n.name.slice(18)}`;e.registerToolHandler(t,r)}(n.name===`shadowclaw_server_send_notification`||n.name===`shadowclaw_send_notification`)&&(e.registerToolHandler(`shadowclaw_send_notification`,r),e.registerToolHandler(`send_notification`,r))}}function Kxe(e,t){return typeof e==`string`?t===`raw`?e.startsWith(`shadowclaw_client_`)?e.slice(18):e:e.startsWith(`shadowclaw_client_`)?e:`shadowclaw_client_${e}`:e}function Dp(e){return Kxe(e,`raw`)}function qxe(e){return Kxe(e,`exposed`)}function Jxe(e,t={}){let{targetClientId:n,cacheTtlMs:r=3e3}=t,i=[],a=0,o=n||``,s=new Set,c=new Map,l=new Map;async function u(){let t=Date.now();if(i.length>0&&t-a<r)return i;let s=[];try{s=typeof e.getConnectedClients==`function`?e.getConnectedClients():typeof e.listClients==`function`?await e.listClients():[]}catch{}if(c.clear(),l.clear(),Array.isArray(s)&&s.length>0)for(let t of s){let n=t.clientId||t.id;if(n)try{let r=await e.sendCommand(n,`list-tools`,{});if(r&&r.success&&r.data?.tools&&Array.isArray(r.data.tools))for(let e of r.data.tools){let n=Dp(e.name);n===`send_notification`||n.startsWith(`shadowclaw_`)&&!n.startsWith(`shadowclaw_client_`)||(l.has(n)||(l.set(n,e),c.set(n,[])),c.get(n).push(t))}}catch(e){console.warn(`[ClientToolRelay] Failed to query tools from client ${n}:`,e)}}let u=Tp(e,o||n),d=new Map;for(let[e,t]of l.entries()){let n=c.get(e)||[],r=n.map(e=>e.clientId||e.id).filter(Boolean),i=n.find(e=>(e.clientId||e.id)===u)||n[0],a=i?.clientId||i?.id||``,o=i?.deviceLabel||`Client`,l=t.inputSchema&&typeof t.inputSchema==`object`?t.inputSchema:{type:`object`,properties:{}},f={...l.properties||{},clientId:{type:`string`,description:`Target ShadowClaw client ID (optional; defaults to ${a} [${o}]). Available on: ${n.map(e=>`${e.clientId||e.id} (${e.deviceLabel||`Client`})`).join(`, `)}`,enum:r}},p=s.length>1?n.length>1?` [Default: ${o} (${a.slice(0,14)}...)]`:` [Client: ${o} (${a.slice(0,14)}...)]`:``,m=qxe(e);d.set(m,{name:m,description:(t.description||`Relayed tool '${e}' from connected client.`)+p,inputSchema:{...l,type:`object`,properties:f},annotations:t.annotations})}let f=Fxe(e);return d.set(f.name,f),i=Array.from(d.values()),a=t,i}function d(e){e.setToolProvider(async()=>{let t=await u();for(let n of t){s.has(n.name)||(s.add(n.name),e.registerToolHandler(n.name,async(e,t,r)=>f(n.name,e,t,r)));let t=Dp(n.name);s.has(t)||(s.add(t),e.registerToolHandler(t,async(e,n,r)=>f(t,e,n,r)))}return t})}async function f(t,r,i,a){let s=typeof e.getConnectedClients==`function`?e.getConnectedClients():typeof e.listClients==`function`?await e.listClients():[];if(!Array.isArray(s)||s.length===0)return{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: No connected ShadowClaw client available to execute tool.`}]};l.size===0&&await u();let d=Dp(t),f=(c.get(d)||c.get(t)||[]).map(e=>e.clientId||e.id).filter(Boolean),p=r.clientId;if(!p){let t=Tp(e,o||n);f.includes(t)?p=t:f.length>0&&(p=f[0])}let m=Tp(e,p);if(!m)return{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: No connected ShadowClaw client available to execute tool.`}]};if(f.length>0&&!f.includes(m))return{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: Tool '${t}' is not enabled or available on client '${m}'. (Available on: ${f.join(`, `)})`}],_meta:{clientId:m}};if(d===`ask_user`||t===`ask_user`){if(!a||!a.response)return{resultType:`input_required`,inputRequests:[{id:`response`,type:`prompt`,message:r.question||r.prompt||`Please provide user response:`,requestedSchema:{type:`object`,properties:{response:{type:`string`,description:`Your answer`}}}}]};let e=a.response;return{resultType:`complete`,content:[{type:`text`,text:typeof e==`string`?e:JSON.stringify(e)}],_meta:{clientId:m}}}try{let t={...r};delete t.clientId;let n=await e.sendCommand(m,`invoke-tool`,{toolName:d,input:t});if(!n.success)return{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Tool execution error: ${n.error||`Unknown client execution error`}`}],_meta:{clientId:m}};let i=n.data?.result===void 0?n.data:n.data.result;return{resultType:`complete`,content:[{type:`text`,text:typeof i==`string`?i:JSON.stringify(i,null,2)}],_meta:{clientId:m}}}catch(e){return{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Failed to dispatch tool '${t}' to client: ${e.message||String(e)}`}],_meta:{clientId:m}}}}return{discoverTools:u,attachToServer:d,getActiveClientId:()=>o||Tp(e,n),setActiveClientId:e=>{o=e}}}function Yxe(e,t){let{controlPlane:n,allowedOrigins:r,corsMode:i}=t,a=t.token||Bn(),o=t.mcpServer||new Mxe({name:`shadow-claw`});n&&(Gxe(o,n),Jxe(n).attachToServer(o));function s(e){if(!e)return!1;if(e===a)return!0;try{let t=Bn();if(t&&e===t)return!0}catch{}return!1}function c(e,t){try{let n=new C(e),a=n.hostname.toLowerCase();if(a===`127.0.0.1`||a===`localhost`||a===`::1`||a===`[::1]`||a===`github.com`||a.endsWith(`.github.io`)||a.endsWith(`.pages.dev`)||t&&n.host===t||i===`all`||r&&r.has(n.origin)||i===`private`&&/^(127\.|10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.)/.test(a))return!0}catch{}return!1}function l(e){let t=e.query.token;if(typeof t==`string`)return t.trim();let n=e.headers[`x-control-token`];if(typeof n==`string`)return n.trim();let r=e.headers.authorization;return r&&r.startsWith(`Bearer `)?r.slice(7).trim():null}function u(e){let t=(e.headers.host||``).split(`:`)[0].toLowerCase(),n=t===`127.0.0.1`||t===`localhost`||t===`::1`||t===`[::1]`,r=e.headers.origin;return r?c(r,e.headers.host):n}if(e&&typeof e.post==`function`){let t=async(e,t)=>{let n=e.headers.origin;if(n&&!c(n,e.headers.host)){t.status(403).json({jsonrpc:`2.0`,id:e.body?.id??null,error:{code:wp.InvalidRequest,message:`Forbidden: Origin validation failed`}});return}let r=l(e);if(!(r?s(r):u(e))){let n=e.secure||e.headers[`x-forwarded-proto`]===`https`?`https`:`http`,r=e.headers.host||`127.0.0.1`;t.setHeader(`WWW-Authenticate`,`Bearer resource_metadata="${n}://${r}/.well-known/oauth-protected-resource"`),t.status(401).json({jsonrpc:`2.0`,id:e.body?.id??null,error:{code:wp.InvalidRequest,message:`Unauthorized: Invalid or missing control token`}});return}let i={"mcp-protocol-version":e.headers[`mcp-protocol-version`]||void 0,"mcp-method":e.headers[`mcp-method`]||void 0,"mcp-name":e.headers[`mcp-name`]||void 0},a=e.body;if(!a||typeof a!=`object`||!a.method){t.status(400).json({jsonrpc:`2.0`,id:null,error:{code:wp.InvalidRequest,message:`Invalid JSON-RPC request payload`}});return}let d=await o.handleRequest(a,i);if(d===null){t.status(202).end();return}t.setHeader(`MCP-Protocol-Version`,Sp);let f=200;if(`error`in d){let e=d.error.code;(e===wp.HeaderMismatch||e===wp.UnsupportedProtocolVersion||e===wp.InvalidRequest)&&(f=400)}t.status(f).json(d)};e.post(`/mcp`,t),e.post(`/.well-known/mcp`,t)}if(e&&typeof e.get==`function`){let t=e=>`${e.secure||e.headers[`x-forwarded-proto`]===`https`?`https`:`http`}://${e.headers.host||`127.0.0.1`}`,n=(e,n)=>{let r=t(e);n.setHeader(`Content-Type`,`application/json; charset=utf-8`),n.json({$schema:`https://modelcontextprotocol.io/schemas/server-card/v1.json`,name:`shadow-claw`,version:fp(),description:`Browser-native personal AI assistant with local and remote LLM orchestration, Web Workers, OPFS storage, and agentic tool execution.`,title:`ShadowClaw MCP Server`,websiteUrl:`${r}/shadow-claw/`,repository:{url:`https://github.com/xt-ml/shadow-claw`,source:`github`},icons:[{src:`${r}/assets/icons/favicon.svg`,mimeType:`image/svg+xml`,sizes:[`any`]},{src:`${r}/assets/icons/512.png`,mimeType:`image/png`,sizes:[`512x512`]}],remotes:[{type:`streamable-http`,url:`${r}/mcp`,supportedProtocolVersions:[`2026-07-28`,`2025-11-25`,`2024-11-05`],headers:[{name:`MCP-Protocol-Version`,default:`2026-07-28`,isRequired:!1},{name:`x-control-token`,description:`Control plane token for authorized client access`,isSecret:!0,isRequired:!1}]}]})};e.get(`/.well-known/mcp`,n),e.get(`/.well-known/mcp.json`,n),e.get(`/mcp/server-card`,n),e.get(`/.well-known/ai-catalog.json`,(e,n)=>{let r=t(e);n.setHeader(`Content-Type`,`application/json; charset=utf-8`),n.json({$schema:`https://agent-card.github.io/schemas/ai-catalog/v1.json`,version:`1.0`,name:`ShadowClaw AI Catalog`,servers:[{name:`shadow-claw`,card:`${r}/.well-known/mcp.json`}]})}),e.get(`/.well-known/mcp/servers.json`,(e,n)=>{let r=t(e);n.setHeader(`Content-Type`,`application/json; charset=utf-8`),n.json({version:`1.0`,servers:[{name:`shadow-claw`,description:`ShadowClaw Browser-Native AI Assistant MCP Server`,endpoint:`${r}/mcp`,capabilities:[`tools`,`extensions`],card:`${r}/.well-known/mcp.json`}]})});let r=(e,n)=>{let r=t(e);n.setHeader(`Content-Type`,`application/json; charset=utf-8`),n.json({resource:`${r}/mcp`,authorization_servers:[r],bearer_methods_supported:[`header`],resource_documentation:`https://xt-ml.github.io/shadow-claw/docs/subsystems/mcp-server.md`})};e.get(`/.well-known/oauth-protected-resource`,r),e.get(`/.well-known/oauth-protected-resource.json`,r)}return o}function Xxe(e,t){let{httpServer:n,token:r}=t;function i(e,t){let n=e.headers.origin;t.setHeader(`Access-Control-Allow-Origin`,n||`*`),t.setHeader(`Access-Control-Allow-Methods`,`GET, POST, OPTIONS`),t.setHeader(`Access-Control-Allow-Headers`,`Content-Type, Authorization, x-control-token, Accept`),t.setHeader(`Access-Control-Allow-Private-Network`,`true`)}function a(e,t,n){if(!r)return n();let i=e.headers[`x-control-token`];if(i&&i===r)return n();let a=e.headers.authorization;if(a){let e=a.match(/^Bearer\s+(.+)$/i);if(e&&e[1]===r)return n()}t.status(401).json({error:`Unauthorized`,message:`Valid control token required for A2A communication`})}e.options(`/.well-known/agent-card.json`,(e,t)=>{i(e,t),t.status(204).end()}),e.options(`/a2a`,(e,t)=>{i(e,t),t.status(204).end()}),e.options(`/a2a/tasks/:taskId`,(e,t)=>{i(e,t),t.status(204).end()}),e.get(`/.well-known/agent-card.json`,(e,t)=>{i(e,t),t.setHeader(`Content-Type`,`application/json`),t.status(200).json(n.agentCard)}),e.post(`/a2a`,a,async(e,t)=>{i(e,t),t.setHeader(`Content-Type`,`application/json`);try{let r=await n.handleRequest(e.body);t.status(200).json(r)}catch(n){t.status(500).json({jsonrpc:`2.0`,id:e.body?.id??null,error:{code:-32603,message:n?.message??`Internal server error`}})}}),e.get(`/a2a/tasks/:taskId`,a,(e,t)=>{i(e,t);let r=e.params.taskId,a=n.taskStore.getTask(r);if(!a){t.status(404).json({error:`Task not found`});return}t.setHeader(`Content-Type`,`text/event-stream`),t.setHeader(`Cache-Control`,`no-cache, no-transform`),t.setHeader(`Connection`,`keep-alive`),t.setHeader(`X-Accel-Buffering`,`no`),t.flushHeaders(),t.write(`data: ${JSON.stringify({task:a})}\n\n`);let o=n.taskStore.subscribe(r,e=>{t.write(`data: ${JSON.stringify(e)}\n\n`)});e.on(`close`,()=>{o()})})}const Zxe=new Set([`TASK_STATE_COMPLETED`,`TASK_STATE_FAILED`,`TASK_STATE_CANCELED`,`TASK_STATE_REJECTED`]),Op={SEND_MESSAGE:`SendMessage`,SEND_STREAMING_MESSAGE:`SendStreamingMessage`,GET_TASK:`GetTask`,CANCEL_TASK:`CancelTask`,GET_AGENT_CARD:`GetAgentCard`},kp={TASK_NOT_FOUND:-32001,TASK_NOT_CANCELABLE:-32002,PUSH_NOTIFICATION_NOT_SUPPORTED:-32003,UNSUPPORTED_OPERATION:-32004,CONTENT_TYPE_NOT_SUPPORTED:-32005,INVALID_AGENT_RESPONSE:-32006,PARSE_ERROR:-32700,INVALID_REQUEST:-32600,METHOD_NOT_FOUND:-32601,INVALID_PARAMS:-32602,INTERNAL_ERROR:-32603};function Qxe(e){return typeof e==`object`&&!!e&&e.jsonrpc===`2.0`&&(e.id===null||typeof e.id==`string`||typeof e.id==`number`)&&typeof e.method==`string`}function $xe(e){return Zxe.has(e)}xp();var eSe=class{_maxTasks;_maxHistoryPerTask;_tasks=new Map;_listeners=new Map;constructor(e){this._maxTasks=e?.maxTasks??500,this._maxHistoryPerTask=e?.maxHistoryPerTask??100}createTask(e){let t=hp(),n=e.message.contextId??hp(),r=[];e.message&&r.push({...e.message,taskId:e.message.taskId??t,contextId:e.message.contextId??n});let i={id:t,contextId:n,status:{state:`TASK_STATE_SUBMITTED`,timestamp:new Date().toISOString()},history:r,artifacts:[],metadata:e.metadata?{...e.metadata}:void 0};if(this._tasks.size>=this._maxTasks){let e=this._tasks.keys().next().value;e!==void 0&&(this._tasks.delete(e),this._listeners.delete(e))}return this._tasks.set(t,i),i}getTask(e){let t=this._tasks.get(e);return t?structuredClone(t):void 0}updateTaskStatus(e,t,n){let r=this._tasks.get(e);if(r){if($xe(r.status.state))throw Error(`Cannot transition task ${e} from terminal state ${r.status.state}`);return r.status.state=t,r.status.timestamp=new Date().toISOString(),n&&(r.status.message=n,r.history||=[],r.history.push(n),r.history.length>this._maxHistoryPerTask&&r.history.shift()),this._emit(e,{type:`statusUpdate`,taskId:e,contextId:r.contextId??e,payload:{taskId:e,contextId:r.contextId??e,status:{...r.status}}}),structuredClone(r)}}addArtifact(e,t){let n=this._tasks.get(e);if(n)return n.artifacts||=[],n.artifacts.push(t),this._emit(e,{type:`artifactUpdate`,taskId:e,contextId:n.contextId??e,payload:{taskId:e,contextId:n.contextId??e,artifact:t}}),structuredClone(n)}cancelTask(e,t){let n=this._tasks.get(e);if(!n)throw Error(`Task ${e} not found`);if($xe(n.status.state))throw Error(`Task ${e} is not cancelable (state: ${n.status.state})`);return n.status.state=`TASK_STATE_CANCELED`,n.status.timestamp=new Date().toISOString(),t&&(n.metadata={...n.metadata,cancelReason:t}),this._emit(e,{type:`statusUpdate`,taskId:e,contextId:n.contextId??e,payload:{taskId:e,contextId:n.contextId??e,status:{...n.status}}}),structuredClone(n)}subscribe(e,t){let n=this._listeners.get(e);return n||(n=new Set,this._listeners.set(e,n)),n.add(t),()=>{let n=this._listeners.get(e);n&&(n.delete(t),n.size===0&&this._listeners.delete(e))}}listTasks(e){let t=e?.limit??50,n=Array.from(this._tasks.values()),r=e?.state?n.filter(t=>t.status.state===e.state):n,i=0;if(e?.cursor){let t=r.findIndex(t=>t.id===e.cursor);t!==-1&&(i=t+1)}let a=r.slice(i,i+t),o=i+t<r.length&&a.length>0?a[a.length-1].id:void 0;return{tasks:a.map(e=>structuredClone(e)),nextCursor:o}}_emit(e,t){let n=this._listeners.get(e);if(n)for(let r of n)try{r(t)}catch(t){console.error(`Error in A2ATaskStore listener for task ${e}:`,t)}}};xp();var tSe=class{agentCard;taskStore;_taskExecutor;constructor(e){this.agentCard=e.agentCard,this.taskStore=e.taskStore??new eSe,this._taskExecutor=e.taskExecutor}async handleRequest(e){if(!Qxe(e))return{jsonrpc:`2.0`,id:e?.id??`0`,error:{code:kp.INVALID_REQUEST,message:`Invalid JSON-RPC 2.0 request`}};let{id:t,method:n,params:r}=e;try{switch(n){case Op.GET_AGENT_CARD:return{jsonrpc:`2.0`,id:t,result:this.agentCard};case Op.SEND_MESSAGE:{let e=r;if(!e?.message)return{jsonrpc:`2.0`,id:t,error:{code:kp.INVALID_PARAMS,message:`Missing 'message' in SendMessage parameters`}};let n=this.taskStore.createTask(e);if(this._taskExecutor)await this._taskExecutor(n,(e,t)=>{this.taskStore.updateTaskStatus(n.id,e,t)});else{this.taskStore.updateTaskStatus(n.id,`TASK_STATE_WORKING`);let e={messageId:hp(),role:`ROLE_AGENT`,parts:[{text:`A2A task ${n.id} acknowledged and processed.`}],taskId:n.id,contextId:n.contextId};this.taskStore.updateTaskStatus(n.id,`TASK_STATE_COMPLETED`,e)}let i=this.taskStore.getTask(n.id)??n;return{jsonrpc:`2.0`,id:t,result:{task:i,message:i.status.message}}}case Op.GET_TASK:{let e=r,n=e?.taskId??e?.id;if(!n)return{jsonrpc:`2.0`,id:t,error:{code:kp.INVALID_PARAMS,message:`Missing 'taskId' parameter`}};let i=this.taskStore.getTask(n);return i?{jsonrpc:`2.0`,id:t,result:i}:{jsonrpc:`2.0`,id:t,error:{code:kp.TASK_NOT_FOUND,message:`Task ${n} not found`}}}case Op.CANCEL_TASK:{let e=r,n=e?.taskId??e?.id;if(!n)return{jsonrpc:`2.0`,id:t,error:{code:kp.INVALID_PARAMS,message:`Missing 'taskId' parameter`}};if(!this.taskStore.getTask(n))return{jsonrpc:`2.0`,id:t,error:{code:kp.TASK_NOT_FOUND,message:`Task ${n} not found`}};try{return{jsonrpc:`2.0`,id:t,result:this.taskStore.cancelTask(n,e?.reason)}}catch(e){return{jsonrpc:`2.0`,id:t,error:{code:kp.TASK_NOT_CANCELABLE,message:e?.message??`Task ${n} is not cancelable`}}}}case`ListTasks`:{let e=r;return{jsonrpc:`2.0`,id:t,result:this.taskStore.listTasks(e)}}default:return{jsonrpc:`2.0`,id:t,error:{code:kp.METHOD_NOT_FOUND,message:`Method ${n} not found`}}}}catch(e){return{jsonrpc:`2.0`,id:t,error:{code:kp.INTERNAL_ERROR,message:e?.message??`Internal error processing A2A request`}}}}};function nSe(e){let t={url:`${e.baseUrl.replace(/\/+$/,``)}/a2a`,protocolBinding:`JSONRPC`,protocolVersion:`1.0`},n={streaming:e.streaming??!0,pushNotifications:e.pushNotifications??!1};return{name:e.name,description:e.description??`AI assistant agent (${e.name})`,version:e.version??`1.0.0`,supportedInterfaces:[t],capabilities:n,defaultInputModes:[`text/plain`,`application/json`],defaultOutputModes:[`text/plain`,`application/json`],skills:e.skills??[],iconUrl:e.iconUrl,documentationUrl:e.documentationUrl}}var Ap=H(((e,t)=>{var n=Object.prototype.toString;t.exports=function(e){if(e===void 0)return`undefined`;if(e===null)return`null`;var t=typeof e;if(t===`boolean`)return`boolean`;if(t===`string`)return`string`;if(t===`number`)return`number`;if(t===`symbol`)return`symbol`;if(t===`function`)return c(e)?`generatorfunction`:`function`;if(i(e))return`array`;if(d(e))return`buffer`;if(u(e))return`arguments`;if(o(e))return`date`;if(a(e))return`error`;if(s(e))return`regexp`;switch(r(e)){case`Symbol`:return`symbol`;case`Promise`:return`promise`;case`WeakMap`:return`weakmap`;case`WeakSet`:return`weakset`;case`Map`:return`map`;case`Set`:return`set`;case`Int8Array`:return`int8array`;case`Uint8Array`:return`uint8array`;case`Uint8ClampedArray`:return`uint8clampedarray`;case`Int16Array`:return`int16array`;case`Uint16Array`:return`uint16array`;case`Int32Array`:return`int32array`;case`Uint32Array`:return`uint32array`;case`Float32Array`:return`float32array`;case`Float64Array`:return`float64array`}if(l(e))return`generator`;switch(t=n.call(e),t){case`[object Object]`:return`object`;case`[object Map Iterator]`:return`mapiterator`;case`[object Set Iterator]`:return`setiterator`;case`[object String Iterator]`:return`stringiterator`;case`[object Array Iterator]`:return`arrayiterator`}return t.slice(8,-1).toLowerCase().replace(/\s/g,``)};function r(e){return typeof e.constructor==`function`?e.constructor.name:null}function i(e){return Array.isArray?Array.isArray(e):e instanceof Array}function a(e){return e instanceof Error||typeof e.message==`string`&&e.constructor&&typeof e.constructor.stackTraceLimit==`number`}function o(e){return e instanceof Date||typeof e.toDateString==`function`&&typeof e.getDate==`function`&&typeof e.setDate==`function`}function s(e){return e instanceof RegExp||typeof e.flags==`string`&&typeof e.ignoreCase==`boolean`&&typeof e.multiline==`boolean`&&typeof e.global==`boolean`}function c(e,t){return r(e)===`GeneratorFunction`}function l(e){return typeof e.throw==`function`&&typeof e.return==`function`&&typeof e.next==`function`}function u(e){try{if(typeof e.length==`number`&&typeof e.callee==`function`)return!0}catch(e){if(e.message.indexOf(`callee`)!==-1)return!0}return!1}function d(e){return e.constructor&&typeof e.constructor.isBuffer==`function`?e.constructor.isBuffer(e):!1}})),rSe=H(((e,t)=>{
992
+ `)},15e3);e.on(`close`,()=>{clearInterval(i),d.delete(t),r&&l.get(r)===t&&(l.delete(r),p(`SSE client disconnected: ${r}`),x(r)||Mn(r))})})}function y(e,t,n={},r=3e4){let i=s.get(e),a=l.get(e),o=i&&i.readyState===ec.default.OPEN,c=a&&!a.writableEnded;if(!o&&!c)return Promise.reject(Error(`Client not connected: ${e}`));let d=hp(),f={commandId:d,action:t,args:n},p={id:hp(),type:`command:execute`,payload:f};return new Promise((n,s)=>{let l=setTimeout(()=>{u.delete(d),s(Error(`Command ${t} to client ${e} timed out after ${r}ms`))},r);u.set(d,{resolve:n,reject:s,timeout:l});try{o?i.send(JSON.stringify(p)):c&&a.write(`event: command:execute\ndata: ${JSON.stringify(p)}\n\n`)}catch(e){clearTimeout(l),u.delete(d),s(e)}})}async function b(e,t={},n=3e4){let r=new Set([...s.keys(),...l.keys()]),i=[];for(let a of r)x(a)&&i.push(y(a,e,t,n).catch(e=>({commandId:``,success:!1,error:e.message})));return Promise.all(i)}function x(e){let t=s.get(e);if(t&&t.readyState===ec.default.OPEN)return!0;let n=l.get(e);return!!(n&&!n.writableEnded)}let S=``;function w(){return Pn().filter(e=>x(e.clientId))}function T(){if(S&&x(S))return S;let e=w();return e.length>0?e[0].clientId:``}function E(e){S=e}function D(){clearInterval(f),t.removeListener(`upgrade`,_);for(let[,e]of u)clearTimeout(e.timeout),e.reject(Error(`Control plane closed`));u.clear();for(let e of s.values())try{e.close()}catch{}s.clear(),c.clear();for(let e of d)try{e.end()}catch{}d.clear(),l.clear();try{o.close()}catch{}}return{sendCommand:y,broadcastCommand:b,isClientConnected:x,getConnectedClients:w,getActiveClientId:T,setActiveClientId:E,getToken:()=>a,close:D}}const Sp=`2026-07-28`,Cp=[Sp,`2025-11-25`,`2024-11-05`],wp={ParseError:-32700,InvalidRequest:-32600,MethodNotFound:-32601,InvalidParams:-32602,InternalError:-32603,HeaderMismatch:-32020,MissingRequiredClientCapability:-32021,UnsupportedProtocolVersion:-32022};var Mxe=class{_name;_version;_tools=new Map;_handlers=new Map;_toolProvider;constructor(e={}){if(this._name=e.name||`shadow-claw`,this._version=e.version||fp(),this._toolProvider=e.toolProvider,e.tools)for(let t of e.tools)this.registerTool(t)}get serverInfo(){return{name:this._name,version:this._version}}get capabilities(){return{tools:{listChanged:!0},extensions:{"io.modelcontextprotocol/tasks":{}}}}registerTool(e,t){this._tools.set(e.name,e),t&&this._handlers.set(e.name,t)}registerToolHandler(e,t){this._handlers.set(e,t)}setToolProvider(e){this._toolProvider=e}async getTools(){let e=new Map(this._tools);if(this._toolProvider)try{let t=await this._toolProvider();if(Array.isArray(t))for(let n of t)e.set(n.name,n)}catch(e){console.warn(`[McpServer] Error fetching dynamic tools:`,e)}return Array.from(e.values()).sort((e,t)=>e.name.localeCompare(t.name))}async handleRequest(e,t){let n=e.id===void 0||e.id===null,r=e.id??null;if(t){let n=t[`mcp-protocol-version`];if(n&&!Cp.includes(n))return this._makeError(r,wp.UnsupportedProtocolVersion,`Unsupported protocol version: '${n}'. Supported versions: ${Cp.join(`, `)}`);let i=t[`mcp-method`];if(i&&i!==e.method)return this._makeError(r,wp.HeaderMismatch,`Mcp-Method header '${i}' does not match body method '${e.method}'`);let a=t[`mcp-name`];if(a&&e.method===`tools/call`&&e.params?.name&&a!==e.params.name)return this._makeError(r,wp.HeaderMismatch,`Mcp-Name header '${a}' does not match params.name '${e.params.name}'`)}switch(e.method){case`server/discover`:{let e={protocolVersion:Sp,supportedProtocolVersions:[...Cp],capabilities:this.capabilities,serverInfo:this.serverInfo,_meta:{"io.modelcontextprotocol/serverInfo":this.serverInfo}};return this._makeSuccess(r,e)}case`initialize`:{let t={protocolVersion:e.params?.protocolVersion||`2024-11-05`,capabilities:this.capabilities,serverInfo:this.serverInfo};return this._makeSuccess(r,t)}case`notifications/initialized`:return null;case`tools/list`:{let e={resultType:`complete`,ttlMs:5e3,cacheScope:`private`,tools:await this.getTools(),_meta:{"io.modelcontextprotocol/serverInfo":this.serverInfo}};return this._makeSuccess(r,e)}case`tools/call`:{let t=e.params?.name;if(!t||typeof t!=`string`)return this._makeError(r,wp.InvalidParams,`Missing required parameter 'name'`);let n=this._handlers.get(t);if(!n&&this._toolProvider)try{await this.getTools(),n=this._handlers.get(t)}catch{}if(!n)return this._makeError(r,wp.InvalidParams,`Tool not found: '${t}'`);try{let t=await n(e.params?.arguments||{},e.params?._meta,e.params?.inputResponses);if(typeof t==`object`&&t&&t.resultType===`input_required`){let e=t;return e._meta={"io.modelcontextprotocol/serverInfo":this.serverInfo,...e._meta||{}},this._makeSuccess(r,e)}let i={resultType:`complete`,content:t.content||[],isError:t.isError||!1,_meta:{"io.modelcontextprotocol/serverInfo":this.serverInfo}};return this._makeSuccess(r,i)}catch(e){return this._makeSuccess(r,{resultType:`complete`,content:[{type:`text`,text:`Error executing tool '${t}': ${e.message||String(e)}`}],isError:!0,_meta:{"io.modelcontextprotocol/serverInfo":this.serverInfo}})}}case`tasks/get`:{let t=e.params?.taskId;return t?this._makeSuccess(r,{resultType:`complete`,task:{taskId:t,status:`completed`},_meta:{"io.modelcontextprotocol/serverInfo":this.serverInfo}}):this._makeError(r,wp.InvalidParams,`Missing taskId parameter`)}case`tasks/update`:{let t=e.params?.taskId;return this._makeSuccess(r,{resultType:`complete`,task:{taskId:t||`unknown`,status:`running`},_meta:{"io.modelcontextprotocol/serverInfo":this.serverInfo}})}default:return n?null:this._makeError(r,wp.MethodNotFound,`Method not found: '${e.method}'`)}}_makeSuccess(e,t){return{jsonrpc:`2.0`,id:e,result:t}}_makeError(e,t,n,r){return{jsonrpc:`2.0`,id:e,error:{code:t,message:n,...r===void 0?{}:{data:r}}}}};const Nxe=[{name:`shadowclaw_server_list_clients`,description:`List connected browser and Electron clients, including device type, ID, and active capabilities.`,inputSchema:{type:`object`,properties:{}}},{name:`shadowclaw_server_send_message`,description:`Send a message or prompt to a connected ShadowClaw client's active AI orchestrator queue.`,inputSchema:{type:`object`,properties:{text:{type:`string`,description:`The prompt or message text to dispatch.`},clientId:{type:`string`,description:`Target client ID. If omitted, targets the first available connected client.`},groupId:{type:`string`,description:`Target conversation group ID (e.g. 'br:main'). If omitted, targets the active group.`}},required:[`text`]}},{name:`shadowclaw_server_read_state`,description:`Read the current orchestrator state (idle, responding, etc.), active group ID, and capabilities from a connected client.`,inputSchema:{type:`object`,properties:{clientId:{type:`string`,description:`Target client ID (defaults to first available connected client).`}}}},{name:`shadowclaw_server_list_tasks`,description:`List scheduled background tasks configured on a connected client (optionally filtered by conversation group).`,inputSchema:{type:`object`,properties:{clientId:{type:`string`,description:`Target client ID (defaults to first available connected client).`},groupId:{type:`string`,description:`Optional conversation group ID filter.`}}}},{name:`shadowclaw_server_set_active_client`,description:`Set the active default connected client used when no clientId is explicitly provided in tool calls.`,inputSchema:{type:`object`,properties:{clientId:{type:`string`,description:`Target client ID (or index '0', '1', prefix, or device label) to make active.`}},required:[`clientId`]}},{name:`shadowclaw_server_manage_backup`,description:`Trigger or manage OPFS workspace file backups for a connected client (trigger, list, or delete).`,inputSchema:{type:`object`,properties:{action:{type:`string`,enum:[`trigger`,`list`,`delete`],description:`Backup action to perform (default: 'trigger').`,default:`trigger`},clientId:{type:`string`,description:`Target client ID.`},backupId:{type:`string`,description:`Backup snapshot ID (required for 'delete').`},groupId:{type:`string`,description:`Optional workspace conversation group ID.`}}}},{name:`shadowclaw_server_status`,description:`Query ShadowClaw Node server status, version, and active client count.`,inputSchema:{type:`object`,properties:{}}},{name:`shadowclaw_server_send_notification`,description:`Broadcast an OS-level push notification to subscribed devices via Web Push (VAPID), or send to a specific registered client. Works even when the client browser tab is closed, asleep, or running in the background.`,inputSchema:{type:`object`,properties:{title:{type:`string`,description:`Notification title (default: 'ShadowClaw').`},body:{type:`string`,description:`The notification body message text.`},clientId:{type:`string`,description:`Target client ID, prefix, or device label of a specific client that has registered in the past. If omitted, broadcasts to all subscribed devices.`}},required:[`body`]}}];function Tp(e,t){try{let n=typeof e.getConnectedClients==`function`?e.getConnectedClients():typeof e.listClients==`function`?e.listClients():[];if(Array.isArray(n)&&n.length>0){if(typeof t==`string`&&t.trim()){let e=t.trim(),r=n.find(t=>(t.clientId||t.id)===e);if(r)return r.clientId||r.id||``;let i=parseInt(e,10);if(!isNaN(i)&&i>=0&&i<n.length)return n[i].clientId||n[i].id||``;let a=n.find(t=>(t.clientId||t.id||``).startsWith(e)||(t.clientId||t.id||``).replace(/^client-/,``).startsWith(e));if(a)return a.clientId||a.id||``;let o=n.find(t=>t.deviceLabel?.toLowerCase().includes(e.toLowerCase()));return o?o.clientId||o.id||``:e}if(typeof e.getActiveClientId==`function`){let t=e.getActiveClientId();if(t)return t}return n[0].clientId||n[0].id||``}}catch{}return typeof t==`string`?t.trim():``}function Pxe(e=[],t=`shadowclaw_server_send_notification`){let n=[...e].sort((e,t)=>e.clientId.localeCompare(t.clientId)),r=n.map(e=>e.clientId).filter(Boolean),i={type:`string`,description:r.length>0?`Target client ID, prefix, or device label of a specific client registered for push notifications (optional; if omitted, broadcasts to all subscribed devices). Available on: ${n.map(e=>`${e.clientId} (${e.deviceLabel||`Client`})`).join(`, `)}`:`Target client ID, prefix, or device label of a specific client that has registered in the past. If omitted, broadcasts to all subscribed devices.`};return r.length>0&&(i.enum=r),{name:t,description:`Broadcast an OS-level push notification to subscribed devices via Web Push (VAPID), or send to a specific registered client. Works even when the client browser tab is closed, asleep, or running in the background.`,inputSchema:{type:`object`,properties:{title:{type:`string`,description:`Notification title (default: 'ShadowClaw').`},body:{type:`string`,description:`Notification body message text.`},clientId:i},required:[`body`]}}}function Fxe(e,t=`shadowclaw_server_send_notification`){let n=[];try{n=wn()}catch{}if(e&&Array.isArray(n)&&n.length>0)try{let t=typeof e.getConnectedClients==`function`?e.getConnectedClients():typeof e.listClients==`function`?e.listClients():[];if(Array.isArray(t)){for(let e of n)if(!e.deviceLabel){let n=t.find(t=>(t.clientId||t.id)===e.clientId);n&&n.deviceLabel&&(e.deviceLabel=n.deviceLabel)}}}catch{}return Pxe(n,t)}const Ixe=Nxe;async function Lxe(e){let t=typeof e.getConnectedClients==`function`?e.getConnectedClients():typeof e.listClients==`function`?await e.listClients():[];return{content:[{type:`text`,text:JSON.stringify({clients:t},null,2)}]}}async function Rxe(e,t){let n=String(t.text||``).trim();if(!n)return{isError:!0,content:[{type:`text`,text:`Error: Message 'text' parameter cannot be empty.`}]};let r=Tp(e,typeof t.clientId==`string`?t.clientId:void 0);if(!r)return{isError:!0,content:[{type:`text`,text:`Error: No active ShadowClaw browser or Electron clients connected.`}]};let i=await e.sendCommand?.(r,`send-message`,{text:n,groupId:t.groupId});return{content:[{type:`text`,text:JSON.stringify(i?.data||i,null,2)}],isError:!i?.success}}async function zxe(e,t){let n=Tp(e,typeof t.clientId==`string`?t.clientId:void 0);if(!n)return{isError:!0,content:[{type:`text`,text:`Error: No active ShadowClaw clients connected.`}]};let r=await e.sendCommand?.(n,`read-state`,{});return{content:[{type:`text`,text:JSON.stringify(r?.data||r,null,2)}],isError:!r?.success}}async function Bxe(e,t){let n=Tp(e,typeof t.clientId==`string`?t.clientId:void 0);if(!n)return{isError:!0,content:[{type:`text`,text:`Error: No active ShadowClaw clients connected.`}]};let r=await e.sendCommand?.(n,`list-tasks`,{groupId:t.groupId});return{content:[{type:`text`,text:JSON.stringify(r?.data||r,null,2)}],isError:!r?.success}}async function Vxe(e,t){let n=String(t.action||`trigger`).toLowerCase(),r=Tp(e,typeof t.clientId==`string`?t.clientId:void 0);if(n===`trigger`){if(!r)return{isError:!0,content:[{type:`text`,text:`Error: No active ShadowClaw clients connected.`}]};let t=await e.sendCommand?.(r,`trigger-backup`,{});return{content:[{type:`text`,text:JSON.stringify(t?.data||t,null,2)}],isError:!t?.success}}if(n===`list`){if(typeof e.listBackups==`function`){let t=await e.listBackups();return{content:[{type:`text`,text:JSON.stringify({backups:t},null,2)}]}}if(!r)return{isError:!0,content:[{type:`text`,text:`Error: No active ShadowClaw clients connected.`}]};let t=await e.sendCommand?.(r,`list-backups`,{});return{content:[{type:`text`,text:JSON.stringify(t?.data||t,null,2)}],isError:!t?.success}}if(n===`delete`){if(!t.backupId)return{isError:!0,content:[{type:`text`,text:`Error: 'backupId' required for delete action.`}]};if(typeof e.deleteBackup==`function`){let n=await e.deleteBackup(t.backupId,r);return{content:[{type:`text`,text:JSON.stringify(n,null,2)}]}}if(!r)return{isError:!0,content:[{type:`text`,text:`Error: No active ShadowClaw clients connected.`}]};let n=await e.sendCommand?.(r,`delete-backup`,{backupId:t.backupId});return{content:[{type:`text`,text:JSON.stringify(n?.data||n,null,2)}],isError:!n?.success}}if(n===`status`){if(typeof e.getBackupStatus==`function`){let t=await e.getBackupStatus();return{content:[{type:`text`,text:JSON.stringify(t,null,2)}]}}if(!r)return{isError:!0,content:[{type:`text`,text:`Error: No active ShadowClaw clients connected.`}]};let t=await e.sendCommand?.(r,`get-backup-status`,{});return{content:[{type:`text`,text:JSON.stringify(t?.data||t,null,2)}],isError:!t?.success}}return{isError:!0,content:[{type:`text`,text:`Unsupported backup action: '${n}'`}]}}async function Hxe(e,t){let n=Tp(e,typeof t.clientId==`string`?t.clientId:void 0);return n?(typeof e.setActiveClientId==`function`&&e.setActiveClientId(n),{content:[{type:`text`,text:`Active default client set to: ${n}`}],_meta:{activeClientId:n}}):{isError:!0,content:[{type:`text`,text:`Error: Client '${t.clientId}' not found among connected clients.`}]}}async function Uxe(e){let t=typeof e.getConnectedClients==`function`?e.getConnectedClients():[];return{content:[{type:`text`,text:JSON.stringify({server:`ShadowClaw`,version:fp(),connectedClients:t?.length||0,status:`healthy`},null,2)}]}}async function Ep(e,t){let n=String(t.body||``).trim();if(!n)return{isError:!0,content:[{type:`text`,text:`Error: Notification 'body' parameter cannot be empty.`}]};let r=String(t.title||`ShadowClaw`).trim(),i=typeof t.clientId==`string`&&t.clientId.trim()?t.clientId.trim():void 0;try{let e=await Tn({title:r,body:n},i?{clientId:i}:void 0),t=e?.sent??0,a=e?.failed??0,o;return o=e?.notFound?`Warning: No push subscriptions found for client '${i}'. Ensure push notifications were registered by this client in ShadowClaw Settings.`:e?.noSubscribers?`Warning: Push notification broadcast completed, but no devices are currently subscribed to push notifications. Enable push notifications in ShadowClaw Settings on the client first.`:i?`Push notification sent to client '${i}': ${t} recipient(s) delivered, ${a} failed.`:`Push notification broadcast sent: ${t} recipient(s) delivered, ${a} failed.`,{content:[{type:`text`,text:o}],_meta:{...e,...i?{targetClientId:i}:{}}}}catch(e){return{isError:!0,content:[{type:`text`,text:`Failed to send push notification: ${e instanceof Error?e.message:String(e)}`}]}}}const Wxe=new Map([[`shadowclaw_server_list_clients`,Lxe],[`shadowclaw_list_clients`,Lxe],[`shadowclaw_server_send_message`,Rxe],[`shadowclaw_send_message`,Rxe],[`shadowclaw_server_read_state`,zxe],[`shadowclaw_read_state`,zxe],[`shadowclaw_server_list_tasks`,Bxe],[`shadowclaw_list_tasks`,Bxe],[`shadowclaw_server_manage_backup`,Vxe],[`shadowclaw_manage_backup`,Vxe],[`shadowclaw_server_set_active_client`,Hxe],[`shadowclaw_set_active_client`,Hxe],[`shadowclaw_server_status`,Uxe],[`shadowclaw_status`,Uxe],[`shadowclaw_server_send_notification`,Ep],[`shadowclaw_send_notification`,Ep],[`send_notification`,Ep]]);function Gxe(e,t){e.setToolProvider(async()=>[Fxe(t)]);for(let n of Ixe){let r=async e=>{let r=Wxe.get(n.name);return r?await r(t,e):{isError:!0,content:[{type:`text`,text:`Unknown tool: '${n.name}'`}]}};if(e.registerTool(n,r),n.name.startsWith(`shadowclaw_server_`)){let t=`shadowclaw_${n.name.slice(18)}`;e.registerToolHandler(t,r)}(n.name===`shadowclaw_server_send_notification`||n.name===`shadowclaw_send_notification`)&&(e.registerToolHandler(`shadowclaw_send_notification`,r),e.registerToolHandler(`send_notification`,r))}}function Kxe(e,t){return typeof e==`string`?t===`raw`?e.startsWith(`shadowclaw_client_`)?e.slice(18):e:e.startsWith(`shadowclaw_client_`)?e:`shadowclaw_client_${e}`:e}function Dp(e){return Kxe(e,`raw`)}function qxe(e){return Kxe(e,`exposed`)}function Jxe(e,t={}){let{targetClientId:n,cacheTtlMs:r=3e3}=t,i=[],a=0,o=n||``,s=new Set,c=new Map,l=new Map;async function u(){let t=Date.now();if(i.length>0&&t-a<r)return i;let s=[];try{s=typeof e.getConnectedClients==`function`?e.getConnectedClients():typeof e.listClients==`function`?await e.listClients():[]}catch{}if(c.clear(),l.clear(),Array.isArray(s)&&s.length>0)for(let t of s){let n=t.clientId||t.id;if(n)try{let r=await e.sendCommand(n,`list-tools`,{});if(r&&r.success&&r.data?.tools&&Array.isArray(r.data.tools))for(let e of r.data.tools){let n=Dp(e.name);n===`send_notification`||n.startsWith(`shadowclaw_`)&&!n.startsWith(`shadowclaw_client_`)||(l.has(n)||(l.set(n,e),c.set(n,[])),c.get(n).push(t))}}catch(e){console.warn(`[ClientToolRelay] Failed to query tools from client ${n}:`,e)}}let u=Tp(e,o||n),d=new Map;for(let[e,t]of l.entries()){let n=c.get(e)||[],r=n.map(e=>e.clientId||e.id).filter(Boolean),i=n.find(e=>(e.clientId||e.id)===u)||n[0],a=i?.clientId||i?.id||``,o=i?.deviceLabel||`Client`,l=t.inputSchema&&typeof t.inputSchema==`object`?t.inputSchema:{type:`object`,properties:{}},f={...l.properties||{},clientId:{type:`string`,description:`Target ShadowClaw client ID (optional; defaults to ${a} [${o}]). Available on: ${n.map(e=>`${e.clientId||e.id} (${e.deviceLabel||`Client`})`).join(`, `)}`,enum:r}},p=s.length>1?n.length>1?` [Default: ${o} (${a.slice(0,14)}...)]`:` [Client: ${o} (${a.slice(0,14)}...)]`:``,m=qxe(e);d.set(m,{name:m,description:(t.description||`Relayed tool '${e}' from connected client.`)+p,inputSchema:{...l,type:`object`,properties:f},annotations:t.annotations})}let f=Fxe(e);return d.set(f.name,f),i=Array.from(d.values()),a=t,i}function d(e){e.setToolProvider(async()=>{let t=await u();for(let n of t){s.has(n.name)||(s.add(n.name),e.registerToolHandler(n.name,async(e,t,r)=>f(n.name,e,t,r)));let t=Dp(n.name);s.has(t)||(s.add(t),e.registerToolHandler(t,async(e,n,r)=>f(t,e,n,r)))}return t})}async function f(t,r,i,a){let s=typeof e.getConnectedClients==`function`?e.getConnectedClients():typeof e.listClients==`function`?await e.listClients():[];if(!Array.isArray(s)||s.length===0)return{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: No connected ShadowClaw client available to execute tool.`}]};l.size===0&&await u();let d=Dp(t),f=(c.get(d)||c.get(t)||[]).map(e=>e.clientId||e.id).filter(Boolean),p=r.clientId;if(!p){let t=Tp(e,o||n);f.includes(t)?p=t:f.length>0&&(p=f[0])}let m=Tp(e,p);if(!m)return{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: No connected ShadowClaw client available to execute tool.`}]};if(f.length>0&&!f.includes(m))return{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: Tool '${t}' is not enabled or available on client '${m}'. (Available on: ${f.join(`, `)})`}],_meta:{clientId:m}};if(d===`ask_user`||t===`ask_user`){if(!a||!a.response)return{resultType:`input_required`,inputRequests:[{id:`response`,type:`prompt`,message:r.question||r.prompt||`Please provide user response:`,requestedSchema:{type:`object`,properties:{response:{type:`string`,description:`Your answer`}}}}]};let e=a.response;return{resultType:`complete`,content:[{type:`text`,text:typeof e==`string`?e:JSON.stringify(e)}],_meta:{clientId:m}}}try{let t={...r};delete t.clientId;let n=await e.sendCommand(m,`invoke-tool`,{toolName:d,input:t});if(!n.success)return{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Tool execution error: ${n.error||`Unknown client execution error`}`}],_meta:{clientId:m}};let i=n.data?.result===void 0?n.data:n.data.result;return{resultType:`complete`,content:[{type:`text`,text:typeof i==`string`?i:JSON.stringify(i,null,2)}],_meta:{clientId:m}}}catch(e){return{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Failed to dispatch tool '${t}' to client: ${e.message||String(e)}`}],_meta:{clientId:m}}}}return{discoverTools:u,attachToServer:d,getActiveClientId:()=>o||Tp(e,n),setActiveClientId:e=>{o=e}}}function Yxe(e,t){let{controlPlane:n,allowedOrigins:r,corsMode:i}=t,a=t.token||Bn(),o=t.mcpServer||new Mxe({name:`shadow-claw`});n&&(Gxe(o,n),Jxe(n).attachToServer(o));function s(e){if(!e)return!1;if(e===a)return!0;try{let t=Bn();if(t&&e===t)return!0}catch{}return!1}function c(e,t){try{let n=new C(e),a=n.hostname.toLowerCase();if(a===`127.0.0.1`||a===`localhost`||a===`::1`||a===`[::1]`||a===`github.com`||a.endsWith(`.github.io`)||a.endsWith(`.pages.dev`)||t&&n.host===t||i===`all`||r&&r.has(n.origin)||i===`private`&&/^(127\.|10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.)/.test(a))return!0}catch{}return!1}function l(e){let t=e.query.token;if(typeof t==`string`)return t.trim();let n=e.headers[`x-control-token`];if(typeof n==`string`)return n.trim();let r=e.headers.authorization;return r&&r.startsWith(`Bearer `)?r.slice(7).trim():null}function u(e){let t=(e.headers.host||``).split(`:`)[0].toLowerCase(),n=t===`127.0.0.1`||t===`localhost`||t===`::1`||t===`[::1]`,r=e.headers.origin;return r?c(r,e.headers.host):n}if(e&&typeof e.post==`function`){let t=async(e,t)=>{let n=e.headers.origin;if(n&&!c(n,e.headers.host)){t.status(403).json({jsonrpc:`2.0`,id:e.body?.id??null,error:{code:wp.InvalidRequest,message:`Forbidden: Origin validation failed`}});return}let r=l(e);if(!(r?s(r):u(e))){let n=e.secure||e.headers[`x-forwarded-proto`]===`https`?`https`:`http`,r=e.headers.host||`127.0.0.1`;t.setHeader(`WWW-Authenticate`,`Bearer resource_metadata="${n}://${r}/.well-known/oauth-protected-resource"`),t.status(401).json({jsonrpc:`2.0`,id:e.body?.id??null,error:{code:wp.InvalidRequest,message:`Unauthorized: Invalid or missing control token`}});return}let i={"mcp-protocol-version":e.headers[`mcp-protocol-version`]||void 0,"mcp-method":e.headers[`mcp-method`]||void 0,"mcp-name":e.headers[`mcp-name`]||void 0},a=e.body;if(!a||typeof a!=`object`||!a.method){t.status(400).json({jsonrpc:`2.0`,id:null,error:{code:wp.InvalidRequest,message:`Invalid JSON-RPC request payload`}});return}let d=await o.handleRequest(a,i);if(d===null){t.status(202).end();return}t.setHeader(`MCP-Protocol-Version`,Sp);let f=200;if(`error`in d){let e=d.error.code;(e===wp.HeaderMismatch||e===wp.UnsupportedProtocolVersion||e===wp.InvalidRequest)&&(f=400)}t.status(f).json(d)};e.post(`/mcp`,t),e.post(`/.well-known/mcp`,t)}if(e&&typeof e.get==`function`){let t=e=>`${e.secure||e.headers[`x-forwarded-proto`]===`https`?`https`:`http`}://${e.headers.host||`127.0.0.1`}`,n=(e,n)=>{let r=t(e);n.setHeader(`Content-Type`,`application/json; charset=utf-8`),n.json({$schema:`https://modelcontextprotocol.io/schemas/server-card/v1.json`,name:`shadow-claw`,version:fp(),description:`Multi-runtime AI assistant with local and remote LLM orchestration, Web Workers, OPFS storage, and agentic tool execution.`,title:`ShadowClaw MCP Server`,websiteUrl:`${r}/shadow-claw/`,repository:{url:`https://github.com/xt-ml/shadow-claw`,source:`github`},icons:[{src:`${r}/assets/icons/favicon.svg`,mimeType:`image/svg+xml`,sizes:[`any`]},{src:`${r}/assets/icons/512.png`,mimeType:`image/png`,sizes:[`512x512`]}],remotes:[{type:`streamable-http`,url:`${r}/mcp`,supportedProtocolVersions:[`2026-07-28`,`2025-11-25`,`2024-11-05`],headers:[{name:`MCP-Protocol-Version`,default:`2026-07-28`,isRequired:!1},{name:`x-control-token`,description:`Control plane token for authorized client access`,isSecret:!0,isRequired:!1}]}]})};e.get(`/.well-known/mcp`,n),e.get(`/.well-known/mcp.json`,n),e.get(`/mcp/server-card`,n),e.get(`/.well-known/ai-catalog.json`,(e,n)=>{let r=t(e);n.setHeader(`Content-Type`,`application/json; charset=utf-8`),n.json({$schema:`https://agent-card.github.io/schemas/ai-catalog/v1.json`,version:`1.0`,name:`ShadowClaw AI Catalog`,servers:[{name:`shadow-claw`,card:`${r}/.well-known/mcp.json`}]})}),e.get(`/.well-known/mcp/servers.json`,(e,n)=>{let r=t(e);n.setHeader(`Content-Type`,`application/json; charset=utf-8`),n.json({version:`1.0`,servers:[{name:`shadow-claw`,description:`ShadowClaw Multi-Runtime AI Assistant MCP Server`,endpoint:`${r}/mcp`,capabilities:[`tools`,`extensions`],card:`${r}/.well-known/mcp.json`}]})});let r=(e,n)=>{let r=t(e);n.setHeader(`Content-Type`,`application/json; charset=utf-8`),n.json({resource:`${r}/mcp`,authorization_servers:[r],bearer_methods_supported:[`header`],resource_documentation:`https://xt-ml.github.io/shadow-claw/docs/subsystems/mcp-server.md`})};e.get(`/.well-known/oauth-protected-resource`,r),e.get(`/.well-known/oauth-protected-resource.json`,r)}return o}function Xxe(e,t){let{httpServer:n,token:r}=t;function i(e,t){let n=e.headers.origin;t.setHeader(`Access-Control-Allow-Origin`,n||`*`),t.setHeader(`Access-Control-Allow-Methods`,`GET, POST, OPTIONS`),t.setHeader(`Access-Control-Allow-Headers`,`Content-Type, Authorization, x-control-token, Accept`),t.setHeader(`Access-Control-Allow-Private-Network`,`true`)}function a(e,t,n){if(!r)return n();let i=e.headers[`x-control-token`];if(i&&i===r)return n();let a=e.headers.authorization;if(a){let e=a.match(/^Bearer\s+(.+)$/i);if(e&&e[1]===r)return n()}t.status(401).json({error:`Unauthorized`,message:`Valid control token required for A2A communication`})}e.options(`/.well-known/agent-card.json`,(e,t)=>{i(e,t),t.status(204).end()}),e.options(`/a2a`,(e,t)=>{i(e,t),t.status(204).end()}),e.options(`/a2a/tasks/:taskId`,(e,t)=>{i(e,t),t.status(204).end()}),e.get(`/.well-known/agent-card.json`,(e,t)=>{i(e,t),t.setHeader(`Content-Type`,`application/json`),t.status(200).json(n.agentCard)}),e.post(`/a2a`,a,async(e,t)=>{i(e,t),t.setHeader(`Content-Type`,`application/json`);try{let r=await n.handleRequest(e.body);t.status(200).json(r)}catch(n){t.status(500).json({jsonrpc:`2.0`,id:e.body?.id??null,error:{code:-32603,message:n?.message??`Internal server error`}})}}),e.get(`/a2a/tasks/:taskId`,a,(e,t)=>{i(e,t);let r=e.params.taskId,a=n.taskStore.getTask(r);if(!a){t.status(404).json({error:`Task not found`});return}t.setHeader(`Content-Type`,`text/event-stream`),t.setHeader(`Cache-Control`,`no-cache, no-transform`),t.setHeader(`Connection`,`keep-alive`),t.setHeader(`X-Accel-Buffering`,`no`),t.flushHeaders(),t.write(`data: ${JSON.stringify({task:a})}\n\n`);let o=n.taskStore.subscribe(r,e=>{t.write(`data: ${JSON.stringify(e)}\n\n`)});e.on(`close`,()=>{o()})})}const Zxe=new Set([`TASK_STATE_COMPLETED`,`TASK_STATE_FAILED`,`TASK_STATE_CANCELED`,`TASK_STATE_REJECTED`]),Op={SEND_MESSAGE:`SendMessage`,SEND_STREAMING_MESSAGE:`SendStreamingMessage`,GET_TASK:`GetTask`,CANCEL_TASK:`CancelTask`,GET_AGENT_CARD:`GetAgentCard`},kp={TASK_NOT_FOUND:-32001,TASK_NOT_CANCELABLE:-32002,PUSH_NOTIFICATION_NOT_SUPPORTED:-32003,UNSUPPORTED_OPERATION:-32004,CONTENT_TYPE_NOT_SUPPORTED:-32005,INVALID_AGENT_RESPONSE:-32006,PARSE_ERROR:-32700,INVALID_REQUEST:-32600,METHOD_NOT_FOUND:-32601,INVALID_PARAMS:-32602,INTERNAL_ERROR:-32603};function Qxe(e){return typeof e==`object`&&!!e&&e.jsonrpc===`2.0`&&(e.id===null||typeof e.id==`string`||typeof e.id==`number`)&&typeof e.method==`string`}function $xe(e){return Zxe.has(e)}xp();var eSe=class{_maxTasks;_maxHistoryPerTask;_tasks=new Map;_listeners=new Map;constructor(e){this._maxTasks=e?.maxTasks??500,this._maxHistoryPerTask=e?.maxHistoryPerTask??100}createTask(e){let t=hp(),n=e.message.contextId??hp(),r=[];e.message&&r.push({...e.message,taskId:e.message.taskId??t,contextId:e.message.contextId??n});let i={id:t,contextId:n,status:{state:`TASK_STATE_SUBMITTED`,timestamp:new Date().toISOString()},history:r,artifacts:[],metadata:e.metadata?{...e.metadata}:void 0};if(this._tasks.size>=this._maxTasks){let e=this._tasks.keys().next().value;e!==void 0&&(this._tasks.delete(e),this._listeners.delete(e))}return this._tasks.set(t,i),i}getTask(e){let t=this._tasks.get(e);return t?structuredClone(t):void 0}updateTaskStatus(e,t,n){let r=this._tasks.get(e);if(r){if($xe(r.status.state))throw Error(`Cannot transition task ${e} from terminal state ${r.status.state}`);return r.status.state=t,r.status.timestamp=new Date().toISOString(),n&&(r.status.message=n,r.history||=[],r.history.push(n),r.history.length>this._maxHistoryPerTask&&r.history.shift()),this._emit(e,{type:`statusUpdate`,taskId:e,contextId:r.contextId??e,payload:{taskId:e,contextId:r.contextId??e,status:{...r.status}}}),structuredClone(r)}}addArtifact(e,t){let n=this._tasks.get(e);if(n)return n.artifacts||=[],n.artifacts.push(t),this._emit(e,{type:`artifactUpdate`,taskId:e,contextId:n.contextId??e,payload:{taskId:e,contextId:n.contextId??e,artifact:t}}),structuredClone(n)}cancelTask(e,t){let n=this._tasks.get(e);if(!n)throw Error(`Task ${e} not found`);if($xe(n.status.state))throw Error(`Task ${e} is not cancelable (state: ${n.status.state})`);return n.status.state=`TASK_STATE_CANCELED`,n.status.timestamp=new Date().toISOString(),t&&(n.metadata={...n.metadata,cancelReason:t}),this._emit(e,{type:`statusUpdate`,taskId:e,contextId:n.contextId??e,payload:{taskId:e,contextId:n.contextId??e,status:{...n.status}}}),structuredClone(n)}subscribe(e,t){let n=this._listeners.get(e);return n||(n=new Set,this._listeners.set(e,n)),n.add(t),()=>{let n=this._listeners.get(e);n&&(n.delete(t),n.size===0&&this._listeners.delete(e))}}listTasks(e){let t=e?.limit??50,n=Array.from(this._tasks.values()),r=e?.state?n.filter(t=>t.status.state===e.state):n,i=0;if(e?.cursor){let t=r.findIndex(t=>t.id===e.cursor);t!==-1&&(i=t+1)}let a=r.slice(i,i+t),o=i+t<r.length&&a.length>0?a[a.length-1].id:void 0;return{tasks:a.map(e=>structuredClone(e)),nextCursor:o}}_emit(e,t){let n=this._listeners.get(e);if(n)for(let r of n)try{r(t)}catch(t){console.error(`Error in A2ATaskStore listener for task ${e}:`,t)}}};xp();var tSe=class{agentCard;taskStore;_taskExecutor;constructor(e){this.agentCard=e.agentCard,this.taskStore=e.taskStore??new eSe,this._taskExecutor=e.taskExecutor}async handleRequest(e){if(!Qxe(e))return{jsonrpc:`2.0`,id:e?.id??`0`,error:{code:kp.INVALID_REQUEST,message:`Invalid JSON-RPC 2.0 request`}};let{id:t,method:n,params:r}=e;try{switch(n){case Op.GET_AGENT_CARD:return{jsonrpc:`2.0`,id:t,result:this.agentCard};case Op.SEND_MESSAGE:{let e=r;if(!e?.message)return{jsonrpc:`2.0`,id:t,error:{code:kp.INVALID_PARAMS,message:`Missing 'message' in SendMessage parameters`}};let n=this.taskStore.createTask(e);if(this._taskExecutor)await this._taskExecutor(n,(e,t)=>{this.taskStore.updateTaskStatus(n.id,e,t)});else{this.taskStore.updateTaskStatus(n.id,`TASK_STATE_WORKING`);let e={messageId:hp(),role:`ROLE_AGENT`,parts:[{text:`A2A task ${n.id} acknowledged and processed.`}],taskId:n.id,contextId:n.contextId};this.taskStore.updateTaskStatus(n.id,`TASK_STATE_COMPLETED`,e)}let i=this.taskStore.getTask(n.id)??n;return{jsonrpc:`2.0`,id:t,result:{task:i,message:i.status.message}}}case Op.GET_TASK:{let e=r,n=e?.taskId??e?.id;if(!n)return{jsonrpc:`2.0`,id:t,error:{code:kp.INVALID_PARAMS,message:`Missing 'taskId' parameter`}};let i=this.taskStore.getTask(n);return i?{jsonrpc:`2.0`,id:t,result:i}:{jsonrpc:`2.0`,id:t,error:{code:kp.TASK_NOT_FOUND,message:`Task ${n} not found`}}}case Op.CANCEL_TASK:{let e=r,n=e?.taskId??e?.id;if(!n)return{jsonrpc:`2.0`,id:t,error:{code:kp.INVALID_PARAMS,message:`Missing 'taskId' parameter`}};if(!this.taskStore.getTask(n))return{jsonrpc:`2.0`,id:t,error:{code:kp.TASK_NOT_FOUND,message:`Task ${n} not found`}};try{return{jsonrpc:`2.0`,id:t,result:this.taskStore.cancelTask(n,e?.reason)}}catch(e){return{jsonrpc:`2.0`,id:t,error:{code:kp.TASK_NOT_CANCELABLE,message:e?.message??`Task ${n} is not cancelable`}}}}case`ListTasks`:{let e=r;return{jsonrpc:`2.0`,id:t,result:this.taskStore.listTasks(e)}}default:return{jsonrpc:`2.0`,id:t,error:{code:kp.METHOD_NOT_FOUND,message:`Method ${n} not found`}}}}catch(e){return{jsonrpc:`2.0`,id:t,error:{code:kp.INTERNAL_ERROR,message:e?.message??`Internal error processing A2A request`}}}}};function nSe(e){let t={url:`${e.baseUrl.replace(/\/+$/,``)}/a2a`,protocolBinding:`JSONRPC`,protocolVersion:`1.0`},n={streaming:e.streaming??!0,pushNotifications:e.pushNotifications??!1};return{name:e.name,description:e.description??`AI assistant agent (${e.name})`,version:e.version??`1.0.0`,supportedInterfaces:[t],capabilities:n,defaultInputModes:[`text/plain`,`application/json`],defaultOutputModes:[`text/plain`,`application/json`],skills:e.skills??[],iconUrl:e.iconUrl,documentationUrl:e.documentationUrl}}var Ap=H(((e,t)=>{var n=Object.prototype.toString;t.exports=function(e){if(e===void 0)return`undefined`;if(e===null)return`null`;var t=typeof e;if(t===`boolean`)return`boolean`;if(t===`string`)return`string`;if(t===`number`)return`number`;if(t===`symbol`)return`symbol`;if(t===`function`)return c(e)?`generatorfunction`:`function`;if(i(e))return`array`;if(d(e))return`buffer`;if(u(e))return`arguments`;if(o(e))return`date`;if(a(e))return`error`;if(s(e))return`regexp`;switch(r(e)){case`Symbol`:return`symbol`;case`Promise`:return`promise`;case`WeakMap`:return`weakmap`;case`WeakSet`:return`weakset`;case`Map`:return`map`;case`Set`:return`set`;case`Int8Array`:return`int8array`;case`Uint8Array`:return`uint8array`;case`Uint8ClampedArray`:return`uint8clampedarray`;case`Int16Array`:return`int16array`;case`Uint16Array`:return`uint16array`;case`Int32Array`:return`int32array`;case`Uint32Array`:return`uint32array`;case`Float32Array`:return`float32array`;case`Float64Array`:return`float64array`}if(l(e))return`generator`;switch(t=n.call(e),t){case`[object Object]`:return`object`;case`[object Map Iterator]`:return`mapiterator`;case`[object Set Iterator]`:return`setiterator`;case`[object String Iterator]`:return`stringiterator`;case`[object Array Iterator]`:return`arrayiterator`}return t.slice(8,-1).toLowerCase().replace(/\s/g,``)};function r(e){return typeof e.constructor==`function`?e.constructor.name:null}function i(e){return Array.isArray?Array.isArray(e):e instanceof Array}function a(e){return e instanceof Error||typeof e.message==`string`&&e.constructor&&typeof e.constructor.stackTraceLimit==`number`}function o(e){return e instanceof Date||typeof e.toDateString==`function`&&typeof e.getDate==`function`&&typeof e.setDate==`function`}function s(e){return e instanceof RegExp||typeof e.flags==`string`&&typeof e.ignoreCase==`boolean`&&typeof e.multiline==`boolean`&&typeof e.global==`boolean`}function c(e,t){return r(e)===`GeneratorFunction`}function l(e){return typeof e.throw==`function`&&typeof e.return==`function`&&typeof e.next==`function`}function u(e){try{if(typeof e.length==`number`&&typeof e.callee==`function`)return!0}catch(e){if(e.message.indexOf(`callee`)!==-1)return!0}return!1}function d(e){return e.constructor&&typeof e.constructor.isBuffer==`function`?e.constructor.isBuffer(e):!1}})),rSe=H(((e,t)=>{
993
993
  /*!
994
994
  * is-extendable <https://github.com/jonschlinkert/is-extendable>
995
995
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shadow-claw",
3
- "version": "1.40.0",
3
+ "version": "1.40.1",
4
4
  "type": "module",
5
5
  "license": "AGPL-3.0",
6
6
  "description": "ShadowClaw - multi-runtime AI assistant.",
package/src/cli/cli.ts CHANGED
@@ -104,7 +104,7 @@ const program = new Command();
104
104
 
105
105
  program
106
106
  .name("shadow-claw")
107
- .description("Browser-native personal AI assistant and static site publisher")
107
+ .description("Multi-runtime AI assistant and static site publisher")
108
108
  .version(version, "-v, --version", "Output the current version");
109
109
 
110
110
  // ---------------------------------------------------------------------------
@@ -1154,7 +1154,7 @@ slug: "home"
1154
1154
 
1155
1155
  <article>
1156
1156
  <h1>Welcome to ShadowClaw</h1>
1157
- <p>Your browser-native personal AI assistant and static site publisher.</p>
1157
+ <p>Your multi-runtime AI assistant and static site publisher.</p>
1158
1158
  </article>
1159
1159
  `;
1160
1160
  await writeFile(indexPath, defaultIndexHtml, "utf8");
@@ -1667,6 +1667,37 @@ export class ShadowClawFileViewer extends ShadowClawElement {
1667
1667
  }
1668
1668
  }
1669
1669
 
1670
+ async handleSendFileToPeer() {
1671
+ const file = fileViewerStore.file;
1672
+ if (!file || !file.path) {
1673
+ showError("No file is currently open.", 4500);
1674
+
1675
+ return;
1676
+ }
1677
+
1678
+ const activeGroupId = file.groupId || orchestratorStore.activeGroupId || "";
1679
+ const isPeer = activeGroupId.startsWith("peer:");
1680
+ const isRoom = activeGroupId.startsWith("room:");
1681
+
1682
+ if (!isPeer && !isRoom) {
1683
+ showError(
1684
+ "Can only send files to peers in a peer or room conversation.",
1685
+ 4500,
1686
+ );
1687
+
1688
+ return;
1689
+ }
1690
+
1691
+ try {
1692
+ await orchestratorStore.sendFileToPeer(file.path, activeGroupId, {
1693
+ fileName: file.name,
1694
+ mimeType: file.mimeType,
1695
+ });
1696
+ } catch {
1697
+ // Toast error handled in sendFileToPeer
1698
+ }
1699
+ }
1700
+
1670
1701
  async handleShareFile() {
1671
1702
  const file = fileViewerStore.file;
1672
1703
  if (!file || !this.canShareCurrentFile(file)) {
@@ -1706,37 +1737,6 @@ export class ShadowClawFileViewer extends ShadowClawElement {
1706
1737
  }
1707
1738
  }
1708
1739
 
1709
- async handleSendFileToPeer() {
1710
- const file = fileViewerStore.file;
1711
- if (!file || !file.path) {
1712
- showError("No file is currently open.", 4500);
1713
-
1714
- return;
1715
- }
1716
-
1717
- const activeGroupId = file.groupId || orchestratorStore.activeGroupId || "";
1718
- const isPeer = activeGroupId.startsWith("peer:");
1719
- const isRoom = activeGroupId.startsWith("room:");
1720
-
1721
- if (!isPeer && !isRoom) {
1722
- showError(
1723
- "Can only send files to peers in a peer or room conversation.",
1724
- 4500,
1725
- );
1726
-
1727
- return;
1728
- }
1729
-
1730
- try {
1731
- await orchestratorStore.sendFileToPeer(file.path, activeGroupId, {
1732
- fileName: file.name,
1733
- mimeType: file.mimeType,
1734
- });
1735
- } catch {
1736
- // Toast error handled in sendFileToPeer
1737
- }
1738
- }
1739
-
1740
1740
  async openFolderInFilesView(path: string) {
1741
1741
  if (!this.db) {
1742
1742
  return;
@@ -80,6 +80,25 @@ describe("effect", () => {
80
80
  expect(cleanup).toHaveBeenCalledTimes(1);
81
81
  });
82
82
 
83
+ it("invokes cleanup before next execution when effect re-runs", () => {
84
+ const cleanup = jest.fn();
85
+ (globalThis as any).queueMicrotask = jest.fn((fn: any) => fn());
86
+
87
+ let runCount = 0;
88
+ effect(() => {
89
+ runCount++;
90
+ return cleanup as any;
91
+ });
92
+
93
+ // In effect, watcher.watch(computed) is called.
94
+ const lastWatched = watcherInstance.watch.mock.calls.slice(-1)[0][0];
95
+ watcherInstance.pending = [lastWatched];
96
+ watcherInstance.trigger();
97
+
98
+ expect(cleanup).toHaveBeenCalledTimes(1);
99
+ expect(runCount).toBe(2);
100
+ });
101
+
83
102
  it("processes pending signals and re-watches on watcher callback", () => {
84
103
  const pendingA: any = { get: jest.fn() };
85
104
  const pendingB: any = { get: jest.fn() };
@@ -12,6 +12,7 @@ import type { TaskScheduler } from "../../subsystems/tools/task-scheduler.js";
12
12
  import type { Router } from "../router.js";
13
13
  import type { EventBus } from "./utils/EventBus.js";
14
14
  import type { DirectToolCommandPolicy } from "./utils/types.js";
15
+ import type { InboundMessage } from "../../subsystems/channels/types.js";
15
16
 
16
17
  export interface OrchestratorState {
17
18
  // ── Core ──────────────────────────────────────────────────────────────────
@@ -77,7 +78,7 @@ export interface OrchestratorState {
77
78
  >;
78
79
  inFlightProviderRequestIds: Map<string, string>;
79
80
  inFlightTriggerByGroup: Map<string, string>;
80
- messageQueue: any[];
81
+ messageQueue: InboundMessage[];
81
82
  processing: boolean;
82
83
  promptControllers: Map<string, AbortController>;
83
84