shadow-claw 1.43.0 → 1.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.well-known/mcp/server-card.json +1 -1
- package/.well-known/mcp.json +1 -1
- package/dist/cli/chunk--nlZNQrZ2.js +1 -0
- package/dist/cli/{chunk-CbhVal4Q.js → chunk-2IASlfOI.js} +1 -1
- package/dist/cli/chunk-2zUw4dTY.js +1 -0
- package/dist/cli/{chunk-C_vLt0YP2.js → chunk-B2WxN9-12.js} +11 -11
- package/dist/cli/{chunk-Cweo3Jpw.js → chunk-B5hVBRV-.js} +1 -1
- package/dist/cli/chunk-B7vuMvBg.js +1 -0
- package/dist/cli/{chunk-C9b5a_Uy.js → chunk-B9Fx2rWZ.js} +1 -1
- package/dist/cli/chunk-BChoeGdY2.js +1 -0
- package/dist/cli/{chunk-CcWCWTJe.js → chunk-BJmbRsHN.js} +1 -1
- package/dist/cli/{chunk-BN0tqRNn.js → chunk-BQyGyg86.js} +1 -1
- package/dist/cli/chunk-B_FQjokZ.js +1 -0
- package/dist/cli/chunk-BaAL1yLC.js +1 -0
- package/dist/cli/{chunk-L61wFp4H2.js → chunk-BaSEVtTB2.js} +1 -1
- package/dist/cli/chunk-BckYclkX2.js +1 -0
- package/dist/cli/chunk-Bh0Uxjld.js +1 -0
- package/dist/cli/{chunk-D57WTK9e2.js → chunk-By9miObI2.js} +2 -2
- package/dist/cli/chunk-C0cwwqX52.js +1 -0
- package/dist/cli/{chunk-DJ1pR9f82.js → chunk-C0vTb5Ur2.js} +1 -1
- package/dist/cli/{chunk-BBCAo_6N2.js → chunk-C3iVPEyi2.js} +1 -1
- package/dist/cli/{chunk-D3NWfUvq2.js → chunk-CJpZQ6NS2.js} +1 -1
- package/dist/cli/{chunk-Dhh0lHO6.js → chunk-CKksk-lA.js} +1 -1
- package/dist/cli/chunk-CKm7-SCu.js +1 -0
- package/dist/cli/{chunk-BPcMKhha2.js → chunk-CLKlXl_32.js} +1 -1
- package/dist/cli/{chunk-rvRQOKXp.js → chunk-CQeDQc3C.js} +1 -1
- package/dist/cli/{chunk-DYGlH-un.js → chunk-CSMegkz6.js} +1 -1
- package/dist/cli/{chunk-B1TEXFG-2.js → chunk-CTnzEqW82.js} +1 -1
- package/dist/cli/chunk-CiHV_7H62.js +1 -0
- package/dist/cli/{chunk-D9F645K62.js → chunk-CimeIb1j2.js} +1 -1
- package/dist/cli/{chunk-D-lQkf5X.js → chunk-CjhfhiNM.js} +1 -1
- package/dist/cli/{chunk-BTe1dZD0.js → chunk-ClBaEe8W.js} +1 -1
- package/dist/cli/{chunk-BmDywCXL.js → chunk-Cvv2Fuue.js} +1 -1
- package/dist/cli/{chunk-DcYfXgpg2.js → chunk-Cx8_qww-2.js} +1 -1
- package/dist/cli/{chunk-CvKmsXS02.js → chunk-D0UlHLhC2.js} +1 -1
- package/dist/cli/chunk-D0jQVYRk.js +5 -0
- package/dist/cli/chunk-D0sHV-Z82.js +1 -0
- package/dist/cli/{chunk-DeMPVxlQ.js → chunk-D2FGpjOO.js} +1 -1
- package/dist/cli/chunk-D3cH54jW.js +1 -0
- package/dist/cli/{chunk-Di4LxQG-2.js → chunk-D9dG7jP92.js} +1 -1
- package/dist/cli/{chunk-qTCLBos1.js → chunk-DKw-oTLT.js} +1 -1
- package/dist/cli/{chunk-BHnjkiBp2.js → chunk-DOkl85Te2.js} +1 -1
- package/dist/cli/{chunk-XS0fMLl1.js → chunk-DPySd-KC.js} +1 -1
- package/dist/cli/{chunk-BkTdHRZ6.js → chunk-DSleWP3c.js} +1 -1
- package/dist/cli/chunk-DjKQO7aV.js +1 -0
- package/dist/cli/{chunk-CA8_jPwF2.js → chunk-Dk750_9R2.js} +11 -11
- package/dist/cli/{chunk-nsFY_QXf.js → chunk-Do2xLVwC.js} +1 -1
- package/dist/cli/{chunk-DcMyZrds.js → chunk-DoVkBeQv.js} +1 -1
- package/dist/cli/chunk-DrB5Gd6y2.js +1 -0
- package/dist/cli/chunk-DwKjgkq92.js +1 -0
- package/dist/cli/{chunk-DJU6hg1K2.js → chunk-DxZ6DcRo2.js} +63 -63
- package/dist/cli/chunk-IGlHHKOH.js +1 -0
- package/dist/cli/{chunk-CpoiOFRV.js → chunk-NclDuGcY.js} +1 -1
- package/dist/cli/{chunk-CeFei3f_2.js → chunk-TO5qzf3J2.js} +303 -303
- package/dist/cli/{chunk-swUMQyE2.js → chunk-TYwbIsK9.js} +9 -9
- package/dist/cli/{chunk-CWs_KY8q.js → chunk-Xz02ooJU.js} +1 -1
- package/dist/cli/{chunk-DfKXmvNq.js → chunk-e4ARaRhY.js} +1 -1
- package/dist/cli/{chunk-DuTr5h_-.js → chunk-g3j2rSPJ.js} +9 -9
- package/dist/cli/{chunk-JMI-k9_C.js → chunk-j0KG-6x9.js} +1 -1
- package/dist/cli/chunk-ud_DUk_f2.js +1 -0
- package/dist/cli/{chunk-BzqpsHxW2.js → chunk-zUKEZHmz2.js} +1 -1
- package/dist/cli/cli.js +2 -2
- package/dist/headless-agent.js +10 -10
- package/dist/public/.well-known/mcp/server-card.json +1 -1
- package/dist/public/.well-known/mcp.json +1 -1
- package/dist/public/docs/example/article/index.html +1 -1
- package/dist/public/docs/publishing/index.html +1 -1
- package/dist/public/docs/skill-creator/index.html +1 -1
- package/dist/public/docs/subsystems/cli.md +4 -0
- package/dist/public/index.html +1 -1
- package/dist/public/main/index.html +1 -1
- package/dist/public/main/memory/index.html +1 -1
- package/dist/public/service-worker.js +1 -1
- package/dist/server.js +761 -761
- package/package.json +1 -1
- package/src/cli/cli.ts +5 -1
- package/src/cli/commands/agent.test.ts +97 -4
- package/src/cli/commands/agent.ts +28 -2
- package/src/db/sqlite/openSqliteDatabase.test.ts +24 -0
- package/src/db/sqlite/openSqliteDatabase.ts +8 -1
- package/dist/cli/chunk-0WvYaMdi.js +0 -1
- package/dist/cli/chunk-BXNdnbwK.js +0 -1
- package/dist/cli/chunk-BlNmgi3c2.js +0 -1
- package/dist/cli/chunk-C7irE8d42.js +0 -1
- package/dist/cli/chunk-Cbbk_aex2.js +0 -1
- package/dist/cli/chunk-CdNTakxH2.js +0 -1
- package/dist/cli/chunk-Cqd6ZDkT.js +0 -1
- package/dist/cli/chunk-CvoMdhST2.js +0 -1
- package/dist/cli/chunk-DCRmnjTH.js +0 -1
- package/dist/cli/chunk-DFLqhyP_.js +0 -5
- package/dist/cli/chunk-DLUNHJGc.js +0 -1
- package/dist/cli/chunk-DfwnnpVo.js +0 -1
- package/dist/cli/chunk-DhJvrfsM.js +0 -1
- package/dist/cli/chunk-DhQQhCTL2.js +0 -1
- package/dist/cli/chunk-Drx4e34U.js +0 -1
- package/dist/cli/chunk-DwEMut0N.js +0 -1
- package/dist/cli/chunk-STsbFGCh2.js +0 -1
- /package/dist/cli/{chunk-Bb_85Mew.js → chunk-Bb_85Mew2.js} +0 -0
- /package/dist/cli/{chunk-CrWRlKmP.js → chunk-CrWRlKmP2.js} +0 -0
- /package/dist/cli/{chunk-D2vZJXHH2.js → chunk-D2vZJXHH.js} +0 -0
- /package/dist/cli/{chunk-D5U9WJ9X.js → chunk-D5U9WJ9X2.js} +0 -0
- /package/dist/cli/{chunk-DV5sRVN1.js → chunk-DV5sRVN12.js} +0 -0
- /package/dist/cli/{chunk-DXSwo4q72.js → chunk-DXSwo4q7.js} +0 -0
- /package/dist/cli/{chunk-Dv5oFrVy2.js → chunk-Dv5oFrVy.js} +0 -0
package/dist/cli/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{t as e}from"./chunk-uAI_Zi6n.js";import{d as t,f as n,n as r}from"./chunk-swUMQyE2.js";import{t as i}from"./chunk-B2vnlJ9A.js";import{c as a,i as o,o as s,s as c}from"./chunk-DHi40kQk.js";import{t as l}from"./chunk-DFh_pp_7.js";import{t as u}from"./chunk-BQCWtrzh.js";import{n as d}from"./chunk-DfKXmvNq.js";import{t as f}from"./chunk-JMI-k9_C.js";import{r as p}from"./chunk-C-5VcG3a.js";import m from"node:fs";import h from"node:path";import{fileURLToPath as g}from"node:url";import _ from"node:process";import{exec as v}from"node:child_process";import{mkdir as y,mkdtemp as b,readFile as x,stat as S,writeFile as C}from"node:fs/promises";import{Command as w}from"commander";import T from"process";import E from"node:http";import{tmpdir as D}from"node:os";import ee from"node:readline";async function O(e={}){let t=new l(e);try{let e=await t.listClients();if(!e||e.length===0){console.log(`No clients currently registered or connected.`);return}console.log(`Connected / registered clients (${e.length}):\n`),e.forEach((e,t)=>{let n=Math.max(0,Math.floor((Date.now()-e.lastSeen)/1e3)),r=n<60?`${n}s ago`:`${Math.floor(n/60)}m ago`;console.log(` ${t+1}. ${e.deviceLabel} (id: ${e.clientId})`),e.peerId&&console.log(` Peer ID: ${e.peerId}`),console.log(` Capabilities: ${e.capabilities.join(`, `)||`none`}`),console.log(` Version: ${e.version}`),console.log(` Last seen: ${r}\n`)})}catch(e){console.error(`Error fetching clients: ${e.message}`),T.exitCode=1}}async function te(e,t={}){if(!e||typeof e!=`string`||!e.trim()){console.error(`Error: Message cannot be empty.`),T.exitCode=1;return}let n=new l(t);try{let r=t.client;if(!r){let e=await n.listClients();if(!e||e.length===0){console.error(`Error: No clients are connected.`),T.exitCode=1;return}r=e[0].clientId,console.log(`Targeting client: ${e[0].deviceLabel||r} (${r})`)}let i=r||``,a=t.timeout?Number(t.timeout)*1e3:12e4,o;if(t.file?(console.log(`Sending message with file "${t.file}" to ${i}...`),o=await n.sendFile(i,t.file,{prompt:e.trim(),groupId:t.group,timeoutMs:a})):(console.log(`Sending message to ${i}...`),o=await n.sendCommand(i,`send-message`,{text:e.trim(),groupId:t.group},a)),o.success)if(console.log(`Message successfully dispatched.`),o.data?.reply||o.data?.text){let e=o.data.reply||o.data.text;console.log(``),console.log(`Response from ${i}:`),console.log(`----------------------------------------`),console.log(e),console.log(`----------------------------------------`)}else o.data&&(t.json,console.log(JSON.stringify(o.data,null,2)));else console.error(`Error from client: ${o.error||`Unknown error`}`),T.exitCode=1}catch(e){console.error(`Error sending message: ${e.message}`),T.exitCode=1}}async function k(e,t={}){if(!e||typeof e!=`string`||!e.trim()){console.error(`Error: File path cannot be empty.`),T.exitCode=1;return}let n=h.resolve(e.trim());if(!m.existsSync(n)){console.error(`Error: File not found: ${e}`),T.exitCode=1;return}let r=m.statSync(n);if(r.isDirectory()){console.error(`Error: Cannot send directory: ${e}`),T.exitCode=1;return}let i=new l(t);try{let e=t.client;if(!e){let t=await i.listClients();if(!t||t.length===0){console.error(`Error: No clients are connected.`),T.exitCode=1;return}e=t[0].clientId,console.log(`Targeting client: ${t[0].deviceLabel||e} (${e})`)}let a=e||``,o=t.name||h.basename(n);console.log(`Sending "${o}" (${r.size} bytes) to ${a}...`);let s=t.timeout?Number(t.timeout)*1e3:12e4,c=await i.sendFile(a,n,{prompt:t.prompt,name:t.name,groupId:t.group,timeoutMs:s});if(c.success)if(console.log(`File "${o}" successfully transferred to ${a}.`),c.data?.path&&console.log(`Remote location: ${c.data.path}`),c.data?.reply||c.data?.text){let e=c.data.reply||c.data.text;console.log(``),console.log(`Response from ${a}:`),console.log(`----------------------------------------`),console.log(e),console.log(`----------------------------------------`)}else t.json&&c.data&&console.log(JSON.stringify(c.data,null,2));else console.error(`Error from client: ${c.error||`Unknown error`}`),T.exitCode=1}catch(e){console.error(`Error sending file: ${e.message}`),T.exitCode=1}}async function A(e=`trigger`,t={}){let n=new l(t);try{if(e===`list`){let e=await n.listBackups(t.client);if(!e||e.length===0){console.log(`No backups found.`);return}console.log(`Available backups (${e.length}):\n`),e.forEach((e,t)=>{let n=new Date(e.timestamp).toISOString(),r=(e.totalBytes/(1024*1024)).toFixed(2);console.log(` ${t+1}. [${e.id}] Client: ${e.clientId}`),console.log(` Date: ${n}`),console.log(` Files: ${e.fileCount} (${r} MB)\n`)});return}if(e===`delete`){if(!t.backupId){console.error(`Error: --backup-id is required for delete action.`),T.exitCode=1;return}await n.deleteBackup(t.backupId,t.client),console.log(`Backup ${t.backupId} deleted.`);return}let r=t.client;if(!r){let e=await n.listClients();if(!e||e.length===0){console.error(`Error: No clients are connected to back up.`),T.exitCode=1;return}r=e[0].clientId}let i=r||``;console.log(`Requesting backup from client ${i}...`);let a=await n.sendCommand(i,`trigger-backup`,{groupId:t.group,token:n.token});a.success?(console.log(`Backup completed successfully.`),console.log(JSON.stringify(a.data,null,2))):(console.error(`Backup failed: ${a.error}`),T.exitCode=1)}catch(e){console.error(`Error executing backup command: ${e.message}`),T.exitCode=1}}async function j(e={}){let t=new l(e);try{let n=e.client;if(!n){let e=await t.listClients();if(!e||e.length===0){console.error(`Error: No clients connected.`),T.exitCode=1;return}n=e[0].clientId}let r=n||``;console.log(`Fetching tasks from client ${r}${e.group?` (group: ${e.group})`:``}...`);let i=await t.sendCommand(r,`list-tasks`,{groupId:e.group});if(i.success){let t=i.data?.tasks||[];if(t.length===0){console.log(e.group?`No tasks configured on client for group "${e.group}".`:`No tasks configured on client.`);return}console.log(`Tasks on ${n}${e.group?` (group: ${e.group})`:``} (${t.length}):\n`),t.forEach((e,t)=>{let n=e.enabled?`[enabled]`:`[disabled]`,r=e.name||e.prompt?.slice(0,30)||`Untitled task`;console.log(` ${t+1}. ${n} ${r} (${e.schedule||`manual`})`)})}else console.error(`Failed to list tasks: ${i.error}`),T.exitCode=1}catch(e){console.error(`Error executing tasks command: ${e.message}`),T.exitCode=1}}async function M(e=`get`,t={}){let n=t.cacheDir,r=o(n),i=!!(t.renew||e===`renew`||e===`generate`||e===`new`),l=t.set||(e===`set`&&t.id?t.id:null),u=``,d=!1;if(l)u=a(l,n),d=!0;else if(i)u=a(void 0,n),d=!0;else{let e=c(n);e?(u=e,d=!1):(u=s(void 0,n),d=!0)}return t.quiet?(console.log(u),{peerId:u,filePath:r,isRenewed:d}):t.json?(console.log(JSON.stringify({peerId:u,filePath:r,renewed:d},null,2)),{peerId:u,filePath:r,isRenewed:d}):(console.log(l?`WebRTC CLI Peer ID set to: ${u}`:d?`WebRTC CLI Peer ID created/renewed: ${u}`:`WebRTC CLI Peer ID: ${u}`),console.log(`Stored in: ${r}`),{peerId:u,filePath:r,isRenewed:d})}function N(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 P(e){return N(e,`raw`)}function F(e){return N(e,`exposed`)}const I=[{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 L(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():``}const ne=h.dirname(g(import.meta.url));function re(){try{let e=h.resolve(ne,`../../../package.json`);if(m.existsSync(e)){let t=JSON.parse(m.readFileSync(e,`utf8`));if(t.version)return t.version}}catch{}return`1.27.1`}const R=`shadowclaw_local_`,ie=I;function z(e,t=R){let n=e.inputSchema||e.input_schema,r=n&&typeof n==`object`?{...n,type:n.type||`object`,properties:n.properties||{}}:{type:`object`,properties:{}};return{name:t?`${t}${e.name}`:e.name,description:e.description||`CLI agent tool: ${e.name}`,inputSchema:r,annotations:e.annotations}}function B(e,t,n){let r=!1,i=[];return Array.isArray(e)?i=e.map(e=>e&&typeof e==`object`?e.type===`image`?{type:`image`,data:e.data||``,mimeType:e.media_type||e.mimeType||`image/png`}:e.type===`text`?{type:`text`,text:String(e.text??``)}:{type:`text`,text:JSON.stringify(e,null,2)}:{type:`text`,text:String(e??``)}):typeof e==`string`?((e.toLowerCase().startsWith(`error`)||e.toLowerCase().startsWith(`tool error`)||e.includes(`SecurityError`)||e.startsWith(`Tool "`)&&e.includes(`is not allowed`)||e.startsWith(`Tool "`)&&e.includes(`is not available`))&&(r=!0),i=[{type:`text`,text:e}]):e&&typeof e==`object`?((e.error||e.success===!1)&&(r=!0),i=[{type:`text`,text:JSON.stringify(e,null,2)}]):i=[{type:`text`,text:String(e??``)}],{jsonrpc:`2.0`,id:n,result:{resultType:`complete`,isError:r,content:i,_meta:{"io.modelcontextprotocol/serverInfo":t}}}}function V(e={}){let n=e.client||new l(e),r=e.relayClientTools!==!1,i=e.targetClientId||e.clientTarget,a=i||``,o={name:`shadow-claw`,version:e.version||re()},s={tools:{listChanged:!0},extensions:{"io.modelcontextprotocol/tasks":{}}};async function c(e){let t=e||a||i;try{let e=await n.listClients();return L({getConnectedClients:()=>e},t)}catch{}return L(n,t)}let d=new Map,p=new Map,m=e.localTools!==!1,g=e.toolPrefix??`local`,_=g===`none`||g===``?``:g===`shadowclaw`?`shadowclaw_`:R,v=new Map,x=null;async function S(){return x||=(async()=>{if(e.core&&e.db){let t;if(e.workspaceDir||e.workspace)t=e.workspaceDir||e.workspace;else{let e=h.join(D(),`shadow-claw`);await y(e,{recursive:!0}),t=await b(h.join(e,`workspace-`))}return{db:e.db,workspaceDir:t,core:e.core}}let n=e.core||await f(),r=e.workspaceDir||e.workspace,i=null,a=null,o=null;if(r)i=h.resolve(r),a=e.cacheDir?h.resolve(e.cacheDir):h.join(i,`.cache`),o=e.databaseDir?h.resolve(e.databaseDir):h.join(a,`database`);else try{let t=h.join(D(),`shadow-claw`);await y(t,{recursive:!0}),i=await b(h.join(t,`workspace-`)),a=e.cacheDir?h.resolve(e.cacheDir):await b(h.join(t,`cache-`)),o=e.databaseDir?h.resolve(e.databaseDir):h.join(a,`database`),await y(a,{recursive:!0}),await y(o,{recursive:!0})}catch(e){return console.error(`[ShadowClaw MCP] Warning: No --workspace provided and failed to initialize temporary fallback workspace (${e.message}). Local workspace tools are disabled.`),null}try{let r=await t({...e,workspace:i,cacheDir:a,databaseDir:o,yes:!0,quiet:!0,isTTY:!1,core:n});return{db:r.db,workspaceDir:r.workspaceDir,core:r.core}}catch(e){return console.error(`[ShadowClaw MCP] Warning: Failed to bootstrap headless agent context (${e.message}). Local workspace tools are disabled.`),null}})(),x}async function C(){if(!m)return[];let t;try{t=await S()}catch(e){return console.error(`[ShadowClaw MCP] Failed to initialize local agent context: ${e.message}`),[]}if(!t)return[];let{db:n,core:r}=t,i=e.group||r.DEFAULT_SERVER_GROUP_ID||`server:main`,a=null;if(e.toolsProfile||e.profile){let t=String(e.toolsProfile||e.profile).trim().toLowerCase(),i=r.DEFAULT_BUILTIN_PROFILE||null,o=[];if(typeof r.getConfig==`function`)try{let e=await r.getConfig(n,r.CONFIG_KEYS?.TOOL_PROFILES||`tool_profiles`);typeof e==`string`?o=JSON.parse(e):Array.isArray(e)&&(o=e)}catch{}let s=[i,...o].filter(Boolean).find(e=>e.id&&String(e.id).toLowerCase()===t||e.name&&String(e.name).toLowerCase()===t);s&&(a=new Set(s.enabledToolNames||[]))}let o=null;if(e.tools&&typeof e.tools==`string`&&e.tools.trim()){let t=e.tools.split(`,`).map(e=>e.trim()).filter(Boolean);o=new Set(t)}let s=[...r.TOOL_DEFINITIONS||[]];if(typeof r.loadDeclarativeTools==`function`)try{let e=await r.loadDeclarativeTools(n,i);if(e&&Array.isArray(e.tools))for(let t of e.tools)s.some(e=>e.name===t.name)||s.push(t)}catch{}let c=r.BROWSER_ONLY_TOOLS||u;v.clear();let l=[];for(let e of s){if(!e||!e.name||c&&c.has(e.name)||o&&!o.has(e.name)||a&&!a.has(e.name))continue;let t=z(e,_);v.set(e.name,e),v.set(`shadowclaw_local_${e.name}`,e),v.set(`shadowclaw_${e.name}`,e),l.push(t)}return l}async function w(t,n,r){try{let i=await S();if(!i)return{jsonrpc:`2.0`,id:r,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: Local workspace tools are not initialized.`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}};let a=e.group||i.core.DEFAULT_SERVER_GROUP_ID||`server:main`,s;try{let{resolveAgentProvider:t}=await import(`./chunk-BXNdnbwK.js`),n=await t(i.db,i.core,i.workspaceDir,{...e,interactive:!1});s={db:i.db,provider:n.providerId,model:n.model,apiKey:n.apiKey}}catch{}return console.error(`[ShadowClaw MCP] Executing local tool '${t.name}' in workspace: ${i.workspaceDir}`),B(await i.core.executeTool(i.db,t.name,n,a,{invokeContext:s}),o,r)}catch(e){return{jsonrpc:`2.0`,id:r,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error executing local tool '${t.name}': ${e.message||String(e)}`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}}async function T(){if(!r)return[];let e=[];try{e=await n.listClients()}catch{}if(!Array.isArray(e)||e.length===0)return d.clear(),p.clear(),[];d.clear(),p.clear();for(let t of e){let e=t.clientId||t.id;if(e)try{let r=await n.sendCommand(e,`list-tools`,{});if(r&&r.success&&r.data?.tools&&Array.isArray(r.data.tools))for(let e of r.data.tools){let n=P(e.name);n===`send_notification`||n.startsWith(`shadowclaw_`)&&!n.startsWith(`shadowclaw_client_`)||(p.has(n)||(p.set(n,e),d.set(n,[])),d.get(n).push(t))}}catch{}}let t=await c(),i=[];for(let[n,r]of p.entries()){let a=d.get(n)||[],o=a.map(e=>e.clientId||e.id).filter(Boolean),s=a.find(e=>(e.clientId||e.id)===t)||a[0],c=s?.clientId||s?.id||``,l=s?.deviceLabel||`Client`,u=r.inputSchema&&typeof r.inputSchema==`object`?r.inputSchema:{type:`object`,properties:{}},f={...u.properties||{},clientId:{type:`string`,description:`Target ShadowClaw client ID (optional; defaults to ${c} [${l}]). Available on: ${a.map(e=>`${e.clientId||e.id} (${e.deviceLabel||`Client`})`).join(`, `)}`,enum:o}},p=e.length>1?a.length>1?` [Default: ${l} (${c.slice(0,14)}...)]`:` [Client: ${l} (${c.slice(0,14)}...)]`:``,m=F(n);i.push({name:m,description:(r.description||`Relayed tool '${n}' from connected client.`)+p,inputSchema:{...u,type:`object`,properties:f},annotations:r.annotations})}return i}async function E(e,t={}){let i=e.id===void 0||e.id===null,l=e.id??null;if(t[`mcp-method`]&&t[`mcp-method`]!==e.method)return{jsonrpc:`2.0`,id:l,error:{code:-32020,message:`Mcp-Method header '${t[`mcp-method`]}' does not match '${e.method}'`}};switch(e.method){case`server/discover`:return{jsonrpc:`2.0`,id:l,result:{protocolVersion:`2026-07-28`,supportedProtocolVersions:[`2026-07-28`,`2025-11-25`,`2024-11-05`],capabilities:s,serverInfo:o,_meta:{"io.modelcontextprotocol/serverInfo":o}}};case`initialize`:return{jsonrpc:`2.0`,id:l,result:{protocolVersion:e.params?.protocolVersion||`2024-11-05`,capabilities:s,serverInfo:o}};case`notifications/initialized`:return null;case`tools/list`:{let e=[];try{if(typeof n.listPushClients==`function`)e=await n.listPushClients();else if(typeof n.listPushSubscriptions==`function`){let t=await n.listPushSubscriptions();if(Array.isArray(t)){let n=new Map;for(let e of t){let t=(e.client_id||``).trim()||(e.id?String(e.id):``);t&&!n.has(t)&&n.set(t,{clientId:t,deviceLabel:e.device_label||void 0})}e=Array.from(n.values())}}}catch{}let t=Array.isArray(e)?[...e].sort((e,t)=>(e.clientId||``).localeCompare(t.clientId||``)):[],r=t.map(e=>e.clientId).filter(Boolean),i=await T(),a=await C(),s=new Map;for(let e of ie)s.set(e.name,e);for(let e of a)s.has(e.name)||s.set(e.name,e);for(let e of i)s.has(e.name)||s.set(e.name,e);if(r.length>0)for(let e of[`shadowclaw_server_send_notification`,`shadowclaw_send_notification`]){let n=s.get(e);n&&s.set(e,{...n,inputSchema:{...n.inputSchema,type:`object`,properties:{...n.inputSchema?.properties||{},clientId:{type:`string`,description:`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: ${t.map(e=>`${e.clientId} (${e.deviceLabel||`Client`})`).join(`, `)}`,enum:r}}}})}return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,ttlMs:5e3,cacheScope:`private`,tools:Array.from(s.values()).sort((e,t)=>e.name.localeCompare(t.name)),_meta:{"io.modelcontextprotocol/serverInfo":o}}}}case`tools/call`:{let t=e.params?.name,i=e.params?.arguments||{},s=e.params?.inputResponses;if(!t)return{jsonrpc:`2.0`,id:l,error:{code:-32602,message:`Missing required parameter 'name'`}};if(t===`shadowclaw_server_list_clients`||t===`shadowclaw_list_clients`)try{let e=await n.listClients();return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,content:[{type:`text`,text:JSON.stringify({clients:e},null,2)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}catch(e){return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error listing clients: ${e.message}`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}if(t===`shadowclaw_server_set_active_client`||t===`shadowclaw_set_active_client`){let e=await c(i.clientId);return e?(a=e,console.error(`[ShadowClaw MCP] Active default client set to: ${a}`),{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,content:[{type:`text`,text:`Active default client set to: ${a}`}],_meta:{activeClientId:a,"io.modelcontextprotocol/serverInfo":o}}}):{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: Client '${i.clientId}' not found among connected clients.`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}if(t===`shadowclaw_server_send_message`||t===`shadowclaw_send_message`){let e=await c(i.clientId);if(!e)return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: No connected client available.`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}};try{let t=await n.sendCommand(e,`send-message`,{text:i.text,groupId:i.groupId});return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!t.success,content:[{type:`text`,text:JSON.stringify(t.data||t,null,2)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}catch(e){return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error sending message: ${e.message}`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}}if(t===`shadowclaw_server_read_state`||t===`shadowclaw_read_state`){let e=await c(i.clientId);try{let t=await n.sendCommand(e,`read-state`,{});return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!t.success,content:[{type:`text`,text:JSON.stringify(t.data||t,null,2)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}catch(e){return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error reading state: ${e.message}`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}}if(t===`shadowclaw_server_list_tasks`||t===`shadowclaw_list_tasks`){let e=await c(i.clientId);try{let t=await n.sendCommand(e,`list-tasks`,{groupId:i.groupId});return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!t.success,content:[{type:`text`,text:JSON.stringify(t.data||t,null,2)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}catch(e){return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error listing tasks: ${e.message}`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}}if(t===`shadowclaw_server_manage_backup`||t===`shadowclaw_manage_backup`){let e=i.action||`trigger`,t=await c(i.clientId);try{if(e===`list`){let e=await n.listBackups(t);return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,content:[{type:`text`,text:JSON.stringify({backups:e},null,2)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}if(e===`delete`){let e=await n.deleteBackup(i.backupId,t);return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,content:[{type:`text`,text:JSON.stringify(e,null,2)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}let r=await n.sendCommand(t,`trigger-backup`,{groupId:i.groupId});return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!r.success,content:[{type:`text`,text:JSON.stringify(r.data||r,null,2)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}catch(e){return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error managing backup: ${e.message}`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}}if(t===`shadowclaw_server_status`||t===`shadowclaw_status`)try{let e=await n.listClients();return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,content:[{type:`text`,text:JSON.stringify({server:`ShadowClaw`,version:o.version,connectedClients:e.length,status:`healthy`},null,2)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}catch(e){return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error querying server status: ${e.message}`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}if(t===`shadowclaw_server_send_notification`||t===`shadowclaw_send_notification`||t===`send_notification`){let e=String(i.body||``).trim();if(!e)return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: Notification 'body' parameter cannot be empty.`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}};let t=String(i.title||`ShadowClaw`).trim(),r=typeof i.clientId==`string`&&i.clientId.trim()?i.clientId.trim():void 0;try{let i=await n.broadcastNotification({title:t,body:e,...r?{clientId:r}:{}}),a=i?.sent??0,s=i?.failed??0,c;return c=i?.notFound?`Warning: No push subscriptions found for client '${r}'. Ensure push notifications were registered by this client in ShadowClaw Settings.`:i?.noSubscribers?`Warning: Push notification broadcast completed, but no devices are currently subscribed to push notifications. Ensure push notifications are enabled in ShadowClaw Settings on the client first.`:r?`Push notification sent to client '${r}': ${a} recipient(s) delivered, ${s} failed.`:`Push notification broadcast sent: ${a} recipient(s) delivered, ${s} failed.`,{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!1,content:[{type:`text`,text:c}],_meta:{...i,...r?{targetClientId:r}:{},"io.modelcontextprotocol/serverInfo":o}}}}catch(e){return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Failed to send push notification: ${e.message}`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}}let u=P(t);if((u===`ask_user`||t===`ask_user`)&&s&&s.response)return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,content:[{type:`text`,text:String(s.response)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}};m&&v.size===0&&await C();let f=t.startsWith(R),h=t.startsWith(`shadowclaw_client_`),_=v.get(t);if(!_&&f&&(_=v.get(t.slice(17))),!_&&t.startsWith(`shadowclaw_`)&&!h&&(_=v.get(t.slice(11))),f&&_){let e={...i};return delete e.clientId,await w(_,e,l)}r&&p.size===0&&await T();let y=(d.get(u)||d.get(t)||[]).map(e=>e.clientId||e.id).filter(Boolean),b=[];try{b=await n.listClients()}catch{}if(!h&&_){if(g===`none`&&!i.clientId){let e={...i};return delete e.clientId,await w(_,e,l)}if(!r||!Array.isArray(b)||b.length===0){let e={...i};return delete e.clientId,await w(_,e,l)}}let x=``;if(i.clientId)x=await c(i.clientId);else{let e=await c();x=y.includes(e)?e:y.length>0?y[0]:e}if(!x)return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: No connected client available.`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}};if(y.length>0&&!y.includes(x))return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: Tool '${t}' is not enabled or available on client '${x}'. (Available on: ${y.join(`, `)})`}],_meta:{clientId:x,"io.modelcontextprotocol/serverInfo":o}}};try{console.error(`[ShadowClaw MCP] Executing '${u}' on client: ${x}`);let e={...i};delete e.clientId;let t=u===`ask_user`?await n.sendCommand(x,`invoke-tool`,{toolName:u,input:e},3e5):await n.sendCommand(x,`invoke-tool`,{toolName:u,input:e}),r=t.data?.result===void 0?t.data:t.data.result,a=typeof r==`string`?r:JSON.stringify(r,null,2),s=t.error||t.data&&t.data.error||`Unknown tool execution error`;return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!t.success,content:[{type:`text`,text:t.success?a||``:a&&a!==`null`&&a!==`{}`?`${a}\n${s}`:`Tool execution error: ${s}`}],_meta:{clientId:x,"io.modelcontextprotocol/serverInfo":o}}}}catch(e){return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Tool error: ${e.message}`}],_meta:{clientId:x,"io.modelcontextprotocol/serverInfo":o}}}}}case`tasks/get`:return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,task:{taskId:e.params?.taskId||`task-1`,status:`completed`},_meta:{"io.modelcontextprotocol/serverInfo":o}}};default:return i?null:{jsonrpc:`2.0`,id:l,error:{code:-32601,message:`Method not found: '${e.method}'`}}}}return{handleMessage:E,getActiveClientId:()=>a,setActiveClientId:e=>{a=e},close:async()=>{if(x)try{let e=await x;typeof e?.core?.closeSqliteDatabase==`function`&&e.core.closeSqliteDatabase()}catch{}}}}async function H(e={}){if((e.mcpTransport||(e.http?`http`:`stdio`))===`http`){let t=parseInt(String(e.port||T.env.MCP_PORT||`8888`),10),n=e.host||`127.0.0.1`,r=V(e);E.createServer(async(e,t)=>{if(e.method!==`POST`||e.url?.split(`?`)[0]!==`/mcp`){t.writeHead(404,{"Content-Type":`application/json`}),t.end(JSON.stringify({error:`Not found`}));return}let n=``;e.on(`data`,e=>n+=e),e.on(`end`,async()=>{let i;try{i=JSON.parse(n)}catch{t.writeHead(400,{"Content-Type":`application/json`}),t.end(JSON.stringify({jsonrpc:`2.0`,id:null,error:{code:-32700,message:`Parse error`}}));return}try{let n={"mcp-protocol-version":e.headers[`mcp-protocol-version`],"mcp-method":e.headers[`mcp-method`],"mcp-name":e.headers[`mcp-name`]},a=await r.handleMessage(i,n);if(a===null){t.writeHead(202),t.end();return}t.writeHead(200,{"Content-Type":`application/json`,"MCP-Protocol-Version":`2026-07-28`}),t.end(JSON.stringify(a))}catch(e){t.writeHead(500,{"Content-Type":`application/json`}),t.end(JSON.stringify({jsonrpc:`2.0`,id:i?.id??null,error:{code:-32603,message:e?.message||`Internal error`}}))}})}).listen(t,n,()=>{console.error(`[ShadowClaw MCP] HTTP MCP server listening at http://${n}:${t}/mcp (2026-07-28)`)});return}console.log=(...e)=>console.error(...e),console.info=(...e)=>console.error(...e);let t=V(e),n=ee.createInterface({input:T.stdin,output:T.stdout,terminal:!1});n.on(`line`,async e=>{let n=e.trim();if(!n)return;let r;try{r=JSON.parse(n)}catch{T.stdout.write(JSON.stringify({jsonrpc:`2.0`,id:null,error:{code:-32700,message:`Parse error`}})+`
|
|
1
|
+
import{t as e}from"./chunk-uAI_Zi6n.js";import{f as t,p as n,r}from"./chunk-TYwbIsK9.js";import{t as i}from"./chunk-B2vnlJ9A.js";import{c as a,i as o,o as s,s as c}from"./chunk-DHi40kQk.js";import{t as l}from"./chunk-DFh_pp_7.js";import{t as u}from"./chunk-BQCWtrzh.js";import{n as d}from"./chunk-e4ARaRhY.js";import{t as f}from"./chunk-j0KG-6x9.js";import{r as p}from"./chunk-C-5VcG3a.js";import m from"node:fs";import h from"node:path";import{fileURLToPath as g}from"node:url";import _ from"node:process";import{exec as v}from"node:child_process";import{mkdir as y,mkdtemp as b,readFile as x,stat as S,writeFile as C}from"node:fs/promises";import{Command as w}from"commander";import T from"process";import E from"node:http";import{tmpdir as D}from"node:os";import ee from"node:readline";async function O(e={}){let t=new l(e);try{let e=await t.listClients();if(!e||e.length===0){console.log(`No clients currently registered or connected.`);return}console.log(`Connected / registered clients (${e.length}):\n`),e.forEach((e,t)=>{let n=Math.max(0,Math.floor((Date.now()-e.lastSeen)/1e3)),r=n<60?`${n}s ago`:`${Math.floor(n/60)}m ago`;console.log(` ${t+1}. ${e.deviceLabel} (id: ${e.clientId})`),e.peerId&&console.log(` Peer ID: ${e.peerId}`),console.log(` Capabilities: ${e.capabilities.join(`, `)||`none`}`),console.log(` Version: ${e.version}`),console.log(` Last seen: ${r}\n`)})}catch(e){console.error(`Error fetching clients: ${e.message}`),T.exitCode=1}}async function te(e,t={}){if(!e||typeof e!=`string`||!e.trim()){console.error(`Error: Message cannot be empty.`),T.exitCode=1;return}let n=new l(t);try{let r=t.client;if(!r){let e=await n.listClients();if(!e||e.length===0){console.error(`Error: No clients are connected.`),T.exitCode=1;return}r=e[0].clientId,console.log(`Targeting client: ${e[0].deviceLabel||r} (${r})`)}let i=r||``,a=t.timeout?Number(t.timeout)*1e3:12e4,o;if(t.file?(console.log(`Sending message with file "${t.file}" to ${i}...`),o=await n.sendFile(i,t.file,{prompt:e.trim(),groupId:t.group,timeoutMs:a})):(console.log(`Sending message to ${i}...`),o=await n.sendCommand(i,`send-message`,{text:e.trim(),groupId:t.group},a)),o.success)if(console.log(`Message successfully dispatched.`),o.data?.reply||o.data?.text){let e=o.data.reply||o.data.text;console.log(``),console.log(`Response from ${i}:`),console.log(`----------------------------------------`),console.log(e),console.log(`----------------------------------------`)}else o.data&&(t.json,console.log(JSON.stringify(o.data,null,2)));else console.error(`Error from client: ${o.error||`Unknown error`}`),T.exitCode=1}catch(e){console.error(`Error sending message: ${e.message}`),T.exitCode=1}}async function k(e,t={}){if(!e||typeof e!=`string`||!e.trim()){console.error(`Error: File path cannot be empty.`),T.exitCode=1;return}let n=h.resolve(e.trim());if(!m.existsSync(n)){console.error(`Error: File not found: ${e}`),T.exitCode=1;return}let r=m.statSync(n);if(r.isDirectory()){console.error(`Error: Cannot send directory: ${e}`),T.exitCode=1;return}let i=new l(t);try{let e=t.client;if(!e){let t=await i.listClients();if(!t||t.length===0){console.error(`Error: No clients are connected.`),T.exitCode=1;return}e=t[0].clientId,console.log(`Targeting client: ${t[0].deviceLabel||e} (${e})`)}let a=e||``,o=t.name||h.basename(n);console.log(`Sending "${o}" (${r.size} bytes) to ${a}...`);let s=t.timeout?Number(t.timeout)*1e3:12e4,c=await i.sendFile(a,n,{prompt:t.prompt,name:t.name,groupId:t.group,timeoutMs:s});if(c.success)if(console.log(`File "${o}" successfully transferred to ${a}.`),c.data?.path&&console.log(`Remote location: ${c.data.path}`),c.data?.reply||c.data?.text){let e=c.data.reply||c.data.text;console.log(``),console.log(`Response from ${a}:`),console.log(`----------------------------------------`),console.log(e),console.log(`----------------------------------------`)}else t.json&&c.data&&console.log(JSON.stringify(c.data,null,2));else console.error(`Error from client: ${c.error||`Unknown error`}`),T.exitCode=1}catch(e){console.error(`Error sending file: ${e.message}`),T.exitCode=1}}async function A(e=`trigger`,t={}){let n=new l(t);try{if(e===`list`){let e=await n.listBackups(t.client);if(!e||e.length===0){console.log(`No backups found.`);return}console.log(`Available backups (${e.length}):\n`),e.forEach((e,t)=>{let n=new Date(e.timestamp).toISOString(),r=(e.totalBytes/(1024*1024)).toFixed(2);console.log(` ${t+1}. [${e.id}] Client: ${e.clientId}`),console.log(` Date: ${n}`),console.log(` Files: ${e.fileCount} (${r} MB)\n`)});return}if(e===`delete`){if(!t.backupId){console.error(`Error: --backup-id is required for delete action.`),T.exitCode=1;return}await n.deleteBackup(t.backupId,t.client),console.log(`Backup ${t.backupId} deleted.`);return}let r=t.client;if(!r){let e=await n.listClients();if(!e||e.length===0){console.error(`Error: No clients are connected to back up.`),T.exitCode=1;return}r=e[0].clientId}let i=r||``;console.log(`Requesting backup from client ${i}...`);let a=await n.sendCommand(i,`trigger-backup`,{groupId:t.group,token:n.token});a.success?(console.log(`Backup completed successfully.`),console.log(JSON.stringify(a.data,null,2))):(console.error(`Backup failed: ${a.error}`),T.exitCode=1)}catch(e){console.error(`Error executing backup command: ${e.message}`),T.exitCode=1}}async function j(e={}){let t=new l(e);try{let n=e.client;if(!n){let e=await t.listClients();if(!e||e.length===0){console.error(`Error: No clients connected.`),T.exitCode=1;return}n=e[0].clientId}let r=n||``;console.log(`Fetching tasks from client ${r}${e.group?` (group: ${e.group})`:``}...`);let i=await t.sendCommand(r,`list-tasks`,{groupId:e.group});if(i.success){let t=i.data?.tasks||[];if(t.length===0){console.log(e.group?`No tasks configured on client for group "${e.group}".`:`No tasks configured on client.`);return}console.log(`Tasks on ${n}${e.group?` (group: ${e.group})`:``} (${t.length}):\n`),t.forEach((e,t)=>{let n=e.enabled?`[enabled]`:`[disabled]`,r=e.name||e.prompt?.slice(0,30)||`Untitled task`;console.log(` ${t+1}. ${n} ${r} (${e.schedule||`manual`})`)})}else console.error(`Failed to list tasks: ${i.error}`),T.exitCode=1}catch(e){console.error(`Error executing tasks command: ${e.message}`),T.exitCode=1}}async function M(e=`get`,t={}){let n=t.cacheDir,r=o(n),i=!!(t.renew||e===`renew`||e===`generate`||e===`new`),l=t.set||(e===`set`&&t.id?t.id:null),u=``,d=!1;if(l)u=a(l,n),d=!0;else if(i)u=a(void 0,n),d=!0;else{let e=c(n);e?(u=e,d=!1):(u=s(void 0,n),d=!0)}return t.quiet?(console.log(u),{peerId:u,filePath:r,isRenewed:d}):t.json?(console.log(JSON.stringify({peerId:u,filePath:r,renewed:d},null,2)),{peerId:u,filePath:r,isRenewed:d}):(console.log(l?`WebRTC CLI Peer ID set to: ${u}`:d?`WebRTC CLI Peer ID created/renewed: ${u}`:`WebRTC CLI Peer ID: ${u}`),console.log(`Stored in: ${r}`),{peerId:u,filePath:r,isRenewed:d})}function N(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 P(e){return N(e,`raw`)}function F(e){return N(e,`exposed`)}const I=[{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 L(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():``}const ne=h.dirname(g(import.meta.url));function re(){try{let e=h.resolve(ne,`../../../package.json`);if(m.existsSync(e)){let t=JSON.parse(m.readFileSync(e,`utf8`));if(t.version)return t.version}}catch{}return`1.27.1`}const R=`shadowclaw_local_`,ie=I;function z(e,t=R){let n=e.inputSchema||e.input_schema,r=n&&typeof n==`object`?{...n,type:n.type||`object`,properties:n.properties||{}}:{type:`object`,properties:{}};return{name:t?`${t}${e.name}`:e.name,description:e.description||`CLI agent tool: ${e.name}`,inputSchema:r,annotations:e.annotations}}function B(e,t,n){let r=!1,i=[];return Array.isArray(e)?i=e.map(e=>e&&typeof e==`object`?e.type===`image`?{type:`image`,data:e.data||``,mimeType:e.media_type||e.mimeType||`image/png`}:e.type===`text`?{type:`text`,text:String(e.text??``)}:{type:`text`,text:JSON.stringify(e,null,2)}:{type:`text`,text:String(e??``)}):typeof e==`string`?((e.toLowerCase().startsWith(`error`)||e.toLowerCase().startsWith(`tool error`)||e.includes(`SecurityError`)||e.startsWith(`Tool "`)&&e.includes(`is not allowed`)||e.startsWith(`Tool "`)&&e.includes(`is not available`))&&(r=!0),i=[{type:`text`,text:e}]):e&&typeof e==`object`?((e.error||e.success===!1)&&(r=!0),i=[{type:`text`,text:JSON.stringify(e,null,2)}]):i=[{type:`text`,text:String(e??``)}],{jsonrpc:`2.0`,id:n,result:{resultType:`complete`,isError:r,content:i,_meta:{"io.modelcontextprotocol/serverInfo":t}}}}function V(e={}){let n=e.client||new l(e),r=e.relayClientTools!==!1,i=e.targetClientId||e.clientTarget,a=i||``,o={name:`shadow-claw`,version:e.version||re()},s={tools:{listChanged:!0},extensions:{"io.modelcontextprotocol/tasks":{}}};async function c(e){let t=e||a||i;try{let e=await n.listClients();return L({getConnectedClients:()=>e},t)}catch{}return L(n,t)}let d=new Map,p=new Map,m=e.localTools!==!1,g=e.toolPrefix??`local`,_=g===`none`||g===``?``:g===`shadowclaw`?`shadowclaw_`:R,v=new Map,x=null;async function S(){return x||=(async()=>{if(e.core&&e.db){let t;if(e.workspaceDir||e.workspace)t=e.workspaceDir||e.workspace;else{let e=h.join(D(),`shadow-claw`);await y(e,{recursive:!0}),t=await b(h.join(e,`workspace-`))}return{db:e.db,workspaceDir:t,core:e.core}}let n=e.core||await f(),r=e.workspaceDir||e.workspace,i=null,a=null,o=null;if(r)i=h.resolve(r),a=e.cacheDir?h.resolve(e.cacheDir):h.join(i,`.cache`),o=e.databaseDir?h.resolve(e.databaseDir):h.join(a,`database`);else try{let t=h.join(D(),`shadow-claw`);await y(t,{recursive:!0}),i=await b(h.join(t,`workspace-`)),a=e.cacheDir?h.resolve(e.cacheDir):await b(h.join(t,`cache-`)),o=e.databaseDir?h.resolve(e.databaseDir):h.join(a,`database`),await y(a,{recursive:!0}),await y(o,{recursive:!0})}catch(e){return console.error(`[ShadowClaw MCP] Warning: No --workspace provided and failed to initialize temporary fallback workspace (${e.message}). Local workspace tools are disabled.`),null}try{let r=await t({...e,workspace:i,cacheDir:a,databaseDir:o,yes:!0,quiet:!0,isTTY:!1,core:n});return{db:r.db,workspaceDir:r.workspaceDir,core:r.core}}catch(e){return console.error(`[ShadowClaw MCP] Warning: Failed to bootstrap headless agent context (${e.message}). Local workspace tools are disabled.`),null}})(),x}async function C(){if(!m)return[];let t;try{t=await S()}catch(e){return console.error(`[ShadowClaw MCP] Failed to initialize local agent context: ${e.message}`),[]}if(!t)return[];let{db:n,core:r}=t,i=e.group||r.DEFAULT_SERVER_GROUP_ID||`server:main`,a=null;if(e.toolsProfile||e.profile){let t=String(e.toolsProfile||e.profile).trim().toLowerCase(),i=r.DEFAULT_BUILTIN_PROFILE||null,o=[];if(typeof r.getConfig==`function`)try{let e=await r.getConfig(n,r.CONFIG_KEYS?.TOOL_PROFILES||`tool_profiles`);typeof e==`string`?o=JSON.parse(e):Array.isArray(e)&&(o=e)}catch{}let s=[i,...o].filter(Boolean).find(e=>e.id&&String(e.id).toLowerCase()===t||e.name&&String(e.name).toLowerCase()===t);s&&(a=new Set(s.enabledToolNames||[]))}let o=null;if(e.tools&&typeof e.tools==`string`&&e.tools.trim()){let t=e.tools.split(`,`).map(e=>e.trim()).filter(Boolean);o=new Set(t)}let s=[...r.TOOL_DEFINITIONS||[]];if(typeof r.loadDeclarativeTools==`function`)try{let e=await r.loadDeclarativeTools(n,i);if(e&&Array.isArray(e.tools))for(let t of e.tools)s.some(e=>e.name===t.name)||s.push(t)}catch{}let c=r.BROWSER_ONLY_TOOLS||u;v.clear();let l=[];for(let e of s){if(!e||!e.name||c&&c.has(e.name)||o&&!o.has(e.name)||a&&!a.has(e.name))continue;let t=z(e,_);v.set(e.name,e),v.set(`shadowclaw_local_${e.name}`,e),v.set(`shadowclaw_${e.name}`,e),l.push(t)}return l}async function w(t,n,r){try{let i=await S();if(!i)return{jsonrpc:`2.0`,id:r,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: Local workspace tools are not initialized.`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}};let a=e.group||i.core.DEFAULT_SERVER_GROUP_ID||`server:main`,s;try{let{resolveAgentProvider:t}=await import(`./chunk-CKm7-SCu.js`),n=await t(i.db,i.core,i.workspaceDir,{...e,interactive:!1});s={db:i.db,provider:n.providerId,model:n.model,apiKey:n.apiKey}}catch{}return console.error(`[ShadowClaw MCP] Executing local tool '${t.name}' in workspace: ${i.workspaceDir}`),B(await i.core.executeTool(i.db,t.name,n,a,{invokeContext:s}),o,r)}catch(e){return{jsonrpc:`2.0`,id:r,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error executing local tool '${t.name}': ${e.message||String(e)}`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}}async function T(){if(!r)return[];let e=[];try{e=await n.listClients()}catch{}if(!Array.isArray(e)||e.length===0)return d.clear(),p.clear(),[];d.clear(),p.clear();for(let t of e){let e=t.clientId||t.id;if(e)try{let r=await n.sendCommand(e,`list-tools`,{});if(r&&r.success&&r.data?.tools&&Array.isArray(r.data.tools))for(let e of r.data.tools){let n=P(e.name);n===`send_notification`||n.startsWith(`shadowclaw_`)&&!n.startsWith(`shadowclaw_client_`)||(p.has(n)||(p.set(n,e),d.set(n,[])),d.get(n).push(t))}}catch{}}let t=await c(),i=[];for(let[n,r]of p.entries()){let a=d.get(n)||[],o=a.map(e=>e.clientId||e.id).filter(Boolean),s=a.find(e=>(e.clientId||e.id)===t)||a[0],c=s?.clientId||s?.id||``,l=s?.deviceLabel||`Client`,u=r.inputSchema&&typeof r.inputSchema==`object`?r.inputSchema:{type:`object`,properties:{}},f={...u.properties||{},clientId:{type:`string`,description:`Target ShadowClaw client ID (optional; defaults to ${c} [${l}]). Available on: ${a.map(e=>`${e.clientId||e.id} (${e.deviceLabel||`Client`})`).join(`, `)}`,enum:o}},p=e.length>1?a.length>1?` [Default: ${l} (${c.slice(0,14)}...)]`:` [Client: ${l} (${c.slice(0,14)}...)]`:``,m=F(n);i.push({name:m,description:(r.description||`Relayed tool '${n}' from connected client.`)+p,inputSchema:{...u,type:`object`,properties:f},annotations:r.annotations})}return i}async function E(e,t={}){let i=e.id===void 0||e.id===null,l=e.id??null;if(t[`mcp-method`]&&t[`mcp-method`]!==e.method)return{jsonrpc:`2.0`,id:l,error:{code:-32020,message:`Mcp-Method header '${t[`mcp-method`]}' does not match '${e.method}'`}};switch(e.method){case`server/discover`:return{jsonrpc:`2.0`,id:l,result:{protocolVersion:`2026-07-28`,supportedProtocolVersions:[`2026-07-28`,`2025-11-25`,`2024-11-05`],capabilities:s,serverInfo:o,_meta:{"io.modelcontextprotocol/serverInfo":o}}};case`initialize`:return{jsonrpc:`2.0`,id:l,result:{protocolVersion:e.params?.protocolVersion||`2024-11-05`,capabilities:s,serverInfo:o}};case`notifications/initialized`:return null;case`tools/list`:{let e=[];try{if(typeof n.listPushClients==`function`)e=await n.listPushClients();else if(typeof n.listPushSubscriptions==`function`){let t=await n.listPushSubscriptions();if(Array.isArray(t)){let n=new Map;for(let e of t){let t=(e.client_id||``).trim()||(e.id?String(e.id):``);t&&!n.has(t)&&n.set(t,{clientId:t,deviceLabel:e.device_label||void 0})}e=Array.from(n.values())}}}catch{}let t=Array.isArray(e)?[...e].sort((e,t)=>(e.clientId||``).localeCompare(t.clientId||``)):[],r=t.map(e=>e.clientId).filter(Boolean),i=await T(),a=await C(),s=new Map;for(let e of ie)s.set(e.name,e);for(let e of a)s.has(e.name)||s.set(e.name,e);for(let e of i)s.has(e.name)||s.set(e.name,e);if(r.length>0)for(let e of[`shadowclaw_server_send_notification`,`shadowclaw_send_notification`]){let n=s.get(e);n&&s.set(e,{...n,inputSchema:{...n.inputSchema,type:`object`,properties:{...n.inputSchema?.properties||{},clientId:{type:`string`,description:`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: ${t.map(e=>`${e.clientId} (${e.deviceLabel||`Client`})`).join(`, `)}`,enum:r}}}})}return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,ttlMs:5e3,cacheScope:`private`,tools:Array.from(s.values()).sort((e,t)=>e.name.localeCompare(t.name)),_meta:{"io.modelcontextprotocol/serverInfo":o}}}}case`tools/call`:{let t=e.params?.name,i=e.params?.arguments||{},s=e.params?.inputResponses;if(!t)return{jsonrpc:`2.0`,id:l,error:{code:-32602,message:`Missing required parameter 'name'`}};if(t===`shadowclaw_server_list_clients`||t===`shadowclaw_list_clients`)try{let e=await n.listClients();return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,content:[{type:`text`,text:JSON.stringify({clients:e},null,2)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}catch(e){return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error listing clients: ${e.message}`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}if(t===`shadowclaw_server_set_active_client`||t===`shadowclaw_set_active_client`){let e=await c(i.clientId);return e?(a=e,console.error(`[ShadowClaw MCP] Active default client set to: ${a}`),{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,content:[{type:`text`,text:`Active default client set to: ${a}`}],_meta:{activeClientId:a,"io.modelcontextprotocol/serverInfo":o}}}):{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: Client '${i.clientId}' not found among connected clients.`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}if(t===`shadowclaw_server_send_message`||t===`shadowclaw_send_message`){let e=await c(i.clientId);if(!e)return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: No connected client available.`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}};try{let t=await n.sendCommand(e,`send-message`,{text:i.text,groupId:i.groupId});return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!t.success,content:[{type:`text`,text:JSON.stringify(t.data||t,null,2)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}catch(e){return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error sending message: ${e.message}`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}}if(t===`shadowclaw_server_read_state`||t===`shadowclaw_read_state`){let e=await c(i.clientId);try{let t=await n.sendCommand(e,`read-state`,{});return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!t.success,content:[{type:`text`,text:JSON.stringify(t.data||t,null,2)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}catch(e){return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error reading state: ${e.message}`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}}if(t===`shadowclaw_server_list_tasks`||t===`shadowclaw_list_tasks`){let e=await c(i.clientId);try{let t=await n.sendCommand(e,`list-tasks`,{groupId:i.groupId});return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!t.success,content:[{type:`text`,text:JSON.stringify(t.data||t,null,2)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}catch(e){return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error listing tasks: ${e.message}`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}}if(t===`shadowclaw_server_manage_backup`||t===`shadowclaw_manage_backup`){let e=i.action||`trigger`,t=await c(i.clientId);try{if(e===`list`){let e=await n.listBackups(t);return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,content:[{type:`text`,text:JSON.stringify({backups:e},null,2)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}if(e===`delete`){let e=await n.deleteBackup(i.backupId,t);return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,content:[{type:`text`,text:JSON.stringify(e,null,2)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}let r=await n.sendCommand(t,`trigger-backup`,{groupId:i.groupId});return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!r.success,content:[{type:`text`,text:JSON.stringify(r.data||r,null,2)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}catch(e){return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error managing backup: ${e.message}`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}}if(t===`shadowclaw_server_status`||t===`shadowclaw_status`)try{let e=await n.listClients();return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,content:[{type:`text`,text:JSON.stringify({server:`ShadowClaw`,version:o.version,connectedClients:e.length,status:`healthy`},null,2)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}catch(e){return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error querying server status: ${e.message}`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}if(t===`shadowclaw_server_send_notification`||t===`shadowclaw_send_notification`||t===`send_notification`){let e=String(i.body||``).trim();if(!e)return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: Notification 'body' parameter cannot be empty.`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}};let t=String(i.title||`ShadowClaw`).trim(),r=typeof i.clientId==`string`&&i.clientId.trim()?i.clientId.trim():void 0;try{let i=await n.broadcastNotification({title:t,body:e,...r?{clientId:r}:{}}),a=i?.sent??0,s=i?.failed??0,c;return c=i?.notFound?`Warning: No push subscriptions found for client '${r}'. Ensure push notifications were registered by this client in ShadowClaw Settings.`:i?.noSubscribers?`Warning: Push notification broadcast completed, but no devices are currently subscribed to push notifications. Ensure push notifications are enabled in ShadowClaw Settings on the client first.`:r?`Push notification sent to client '${r}': ${a} recipient(s) delivered, ${s} failed.`:`Push notification broadcast sent: ${a} recipient(s) delivered, ${s} failed.`,{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!1,content:[{type:`text`,text:c}],_meta:{...i,...r?{targetClientId:r}:{},"io.modelcontextprotocol/serverInfo":o}}}}catch(e){return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Failed to send push notification: ${e.message}`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}}}}let u=P(t);if((u===`ask_user`||t===`ask_user`)&&s&&s.response)return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,content:[{type:`text`,text:String(s.response)}],_meta:{"io.modelcontextprotocol/serverInfo":o}}};m&&v.size===0&&await C();let f=t.startsWith(R),h=t.startsWith(`shadowclaw_client_`),_=v.get(t);if(!_&&f&&(_=v.get(t.slice(17))),!_&&t.startsWith(`shadowclaw_`)&&!h&&(_=v.get(t.slice(11))),f&&_){let e={...i};return delete e.clientId,await w(_,e,l)}r&&p.size===0&&await T();let y=(d.get(u)||d.get(t)||[]).map(e=>e.clientId||e.id).filter(Boolean),b=[];try{b=await n.listClients()}catch{}if(!h&&_){if(g===`none`&&!i.clientId){let e={...i};return delete e.clientId,await w(_,e,l)}if(!r||!Array.isArray(b)||b.length===0){let e={...i};return delete e.clientId,await w(_,e,l)}}let x=``;if(i.clientId)x=await c(i.clientId);else{let e=await c();x=y.includes(e)?e:y.length>0?y[0]:e}if(!x)return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: No connected client available.`}],_meta:{"io.modelcontextprotocol/serverInfo":o}}};if(y.length>0&&!y.includes(x))return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Error: Tool '${t}' is not enabled or available on client '${x}'. (Available on: ${y.join(`, `)})`}],_meta:{clientId:x,"io.modelcontextprotocol/serverInfo":o}}};try{console.error(`[ShadowClaw MCP] Executing '${u}' on client: ${x}`);let e={...i};delete e.clientId;let t=u===`ask_user`?await n.sendCommand(x,`invoke-tool`,{toolName:u,input:e},3e5):await n.sendCommand(x,`invoke-tool`,{toolName:u,input:e}),r=t.data?.result===void 0?t.data:t.data.result,a=typeof r==`string`?r:JSON.stringify(r,null,2),s=t.error||t.data&&t.data.error||`Unknown tool execution error`;return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!t.success,content:[{type:`text`,text:t.success?a||``:a&&a!==`null`&&a!==`{}`?`${a}\n${s}`:`Tool execution error: ${s}`}],_meta:{clientId:x,"io.modelcontextprotocol/serverInfo":o}}}}catch(e){return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,isError:!0,content:[{type:`text`,text:`Tool error: ${e.message}`}],_meta:{clientId:x,"io.modelcontextprotocol/serverInfo":o}}}}}case`tasks/get`:return{jsonrpc:`2.0`,id:l,result:{resultType:`complete`,task:{taskId:e.params?.taskId||`task-1`,status:`completed`},_meta:{"io.modelcontextprotocol/serverInfo":o}}};default:return i?null:{jsonrpc:`2.0`,id:l,error:{code:-32601,message:`Method not found: '${e.method}'`}}}}return{handleMessage:E,getActiveClientId:()=>a,setActiveClientId:e=>{a=e},close:async()=>{if(x)try{let e=await x;typeof e?.core?.closeSqliteDatabase==`function`&&e.core.closeSqliteDatabase()}catch{}}}}async function H(e={}){if((e.mcpTransport||(e.http?`http`:`stdio`))===`http`){let t=parseInt(String(e.port||T.env.MCP_PORT||`8888`),10),n=e.host||`127.0.0.1`,r=V(e);E.createServer(async(e,t)=>{if(e.method!==`POST`||e.url?.split(`?`)[0]!==`/mcp`){t.writeHead(404,{"Content-Type":`application/json`}),t.end(JSON.stringify({error:`Not found`}));return}let n=``;e.on(`data`,e=>n+=e),e.on(`end`,async()=>{let i;try{i=JSON.parse(n)}catch{t.writeHead(400,{"Content-Type":`application/json`}),t.end(JSON.stringify({jsonrpc:`2.0`,id:null,error:{code:-32700,message:`Parse error`}}));return}try{let n={"mcp-protocol-version":e.headers[`mcp-protocol-version`],"mcp-method":e.headers[`mcp-method`],"mcp-name":e.headers[`mcp-name`]},a=await r.handleMessage(i,n);if(a===null){t.writeHead(202),t.end();return}t.writeHead(200,{"Content-Type":`application/json`,"MCP-Protocol-Version":`2026-07-28`}),t.end(JSON.stringify(a))}catch(e){t.writeHead(500,{"Content-Type":`application/json`}),t.end(JSON.stringify({jsonrpc:`2.0`,id:i?.id??null,error:{code:-32603,message:e?.message||`Internal error`}}))}})}).listen(t,n,()=>{console.error(`[ShadowClaw MCP] HTTP MCP server listening at http://${n}:${t}/mcp (2026-07-28)`)});return}console.log=(...e)=>console.error(...e),console.info=(...e)=>console.error(...e);let t=V(e),n=ee.createInterface({input:T.stdin,output:T.stdout,terminal:!1});n.on(`line`,async e=>{let n=e.trim();if(!n)return;let r;try{r=JSON.parse(n)}catch{T.stdout.write(JSON.stringify({jsonrpc:`2.0`,id:null,error:{code:-32700,message:`Parse error`}})+`
|
|
2
2
|
`);return}try{let e=await t.handleMessage(r);e!==null&&T.stdout.write(JSON.stringify(e)+`
|
|
3
3
|
`)}catch(e){let t={jsonrpc:`2.0`,id:r?.id??null,error:{code:-32603,message:e?.message||`Internal error`}};T.stdout.write(JSON.stringify(t)+`
|
|
4
4
|
`)}}),n.on(`close`,async()=>{await t.close?.()}),console.error(`[ShadowClaw MCP] STDIO MCP server active (2026-07-28)`)}const U=e(import.meta.url),W=new Set;function G(e){return typeof e==`function`?(W.add(e),()=>W.delete(e)):()=>!1}let K=!1;const q=(e,t)=>{K&&_.exit(t),K=!0;for(let t of W)try{t(e)}catch{}_.stderr.write(`\nProcess interrupted (${e}).\n`),_.exit(t)};_.on(`SIGINT`,()=>q(`SIGINT`,130)),_.on(`SIGTERM`,()=>q(`SIGTERM`,143)),_.on(`exit`,()=>{for(let e of W)try{e(`exit`)}catch{}});async function J(){try{let e=await x(h.join(U,`package.json`),`utf8`);return JSON.parse(e).version||`1.0.0`}catch{return`1.0.0`}}async function Y(e){try{return await S(e),!0}catch{return!1}}function X(e){return!!(e.a2a||[`1`,`true`,`yes`].includes((_.env.SHADOWCLAW_A2A||``).toLowerCase().trim()))}function Z(e){let t=_.platform===`darwin`?`open`:_.platform===`win32`?`start`:`xdg-open`;try{v(`${t} ${e}`)}catch{}}const ae=await J(),Q=new w;Q.name(`shadow-claw`).description(`Multi-runtime AI assistant and static site publisher`).version(ae,`-v, --version`,`Output the current version`),Q.commandsGroup(`Development:`),Q.command(`build`).description(`Build the static site bundle for production or staging`).optionsGroup(`Build Mode Options:`).option(`--prod, --production`,`Build in production mode with minification and optimizations`,!1).option(`--prerender-pages <mode>`,`Prerender page mode (all, auto, none)`,`auto`).option(`--copy-all-assets`,`Copy entire assets/ directory into output`,!1).optionsGroup(`Path & Routing Options:`).option(`--origin <url>`,`Canonical origin URL (e.g. https://user.github.io/repo/)`).option(`--base-path <path>`,`URL base path prefix (e.g. /repo/)`).option(`--out-dir <dir>`,`Output directory relative to content root`,`dist/public`).option(`--content-root <dir>`,`Content root directory`,_.cwd()).action(async e=>{try{let t=h.resolve(e.contentRoot||_.cwd()),n=!!(e.prod||e.production||_.env.NODE_ENV===`production`);console.log(`Building ShadowClaw site from ${t}...`),await i({contentRoot:t,toolchainRoot:U,outDir:e.outDir||`dist/public`,isProduction:n,pagesOrigin:e.origin||_.env.PAGES_ORIGIN,basePath:e.basePath||_.env.PAGES_BASE_PATH,prerenderPages:e.prerenderPages,copyAllAssets:e.copyAllAssets})}catch(e){console.error(`Build failed:`,e),_.exit(1)}});async function $(e,t){try{let r=h.resolve(t.contentRoot||_.cwd()),a=parseInt(e||t.port||_.env.PORT||`8888`,10),o=t.host||t.ip||_.env.SHADOWCLAW_DEV_IP||`127.0.0.1`,s=t.outDir||`dist/public`,c=h.resolve(r,s),l=await n({contentRoot:r,cacheDir:t.cacheDir,databaseDir:t.databaseDir,tmp:t.tmp||t.temp,yes:t.yes}),u=l.cacheDir,d=l.databaseDir;console.log(`Preparing ShadowClaw dev build for ${r}...`),await i({contentRoot:r,toolchainRoot:U,outDir:s,isProduction:!1,pagesOrigin:t.origin||_.env.PAGES_ORIGIN,basePath:t.basePath||_.env.PAGES_BASE_PATH,prerenderPages:t.prerenderPages||`auto`,copyAllAssets:t.copyAllAssets});let f=await Y(h.join(U,`dist/server.js`))?h.join(U,`dist/server.js`):h.join(U,`src/server/server.ts`);_.env.SHADOWCLAW_ROOT_PATH=c,_.env.SHADOWCLAW_CACHE_DIR=u,_.env.SHADOWCLAW_DATABASE_DIR=d,_.env.SHADOWCLAW_DEV_IP=o;let{startServer:p}=await import(f),m=new Set((t.corsAllowOrigin||_.env.SHADOWCLAW_CORS_ALLOWED_ORIGINS||`https://xt-ml.github.io`).split(`,`).map(e=>e.trim()).filter(Boolean)),g=!!(t.https||[`1`,`true`,`yes`].includes((_.env.SHADOWCLAW_HTTPS||``).toLowerCase().trim())),v=t.cert||(_.env.SHADOWCLAW_TLS_CERT||_.env.SHADOWCLAW_CERT||``).trim()||void 0,y=t.key||(_.env.SHADOWCLAW_TLS_KEY||_.env.SHADOWCLAW_KEY||``).trim()||void 0,b=h.resolve(r,t.sslDir||_.env.SHADOWCLAW_SSL_DIR||_.env.SHADOWCLAW_TLS_DIR||h.join(u,`tls`));await p({port:a,bindHost:o,corsMode:t.corsMode||`localhost`,allowedOrigins:m,verbose:!!t.verbose,peerjs:!!t.peerjs,a2aEnabled:X(t),rootPath:c,cacheDir:u,databaseDir:d,allowPrivateProxy:!!t.allowPrivateProxy,https:g,certPath:v,keyPath:y,sslDir:b});let x=`${g?`https`:`http`}://${o}:${a}`;t.open&&Z(x)}catch(e){console.error(`Dev server error:`,e),_.exit(1)}}Q.command(`dev [port]`).description(`Build and launch the development server`).optionsGroup(`Server & Network Options:`).option(`-p, --port <port>`,`Port to listen on (default: 8888)`).option(`--host <host>`,`Bind host/IP`,`127.0.0.1`).option(`--ip <host>`,`Bind host/IP (alias)`).option(`--open`,`Automatically open default browser`,!1).option(`-v, --verbose`,`Enable verbose request/proxy logging`,!1).optionsGroup(`Site & Build Options:`).option(`--content-root <dir>`,`Content root directory`,_.cwd()).option(`--out-dir <dir>`,`Output directory relative to content root`,`dist/public`).optionsGroup(`Security & Proxy Options:`).option(`--cors-mode <mode>`,`CORS policy: localhost | private | all`,`localhost`).option(`--allow-private-proxy`,`Allow proxy to reach private/loopback addresses`,!1).option(`--peerjs`,`Enable built-in PeerJS signaling server`,!1).option(`--a2a`,`Enable A2A v1.0 agent card, JSON-RPC, and SSE endpoints`,!1).optionsGroup(`TLS / HTTPS Options:`).option(`--https`,`Enable HTTPS dev server`,!1).option(`--cert <path>`,`Path to existing TLS certificate file`).option(`--key <path>`,`Path to existing TLS private key file`).option(`--ssl-dir <path>`,`Directory for TLS certificate generation/storage`).optionsGroup(`Storage & Database Options:`).option(`--database-dir <dir>`,`Directory where SQLite databases are stored`).option(`--cache-dir <dir>`,`Custom cache directory for databases, tokens, and logs`).option(`--tmp, --temp`,`Store cache and databases in system temporary directory`,!1).option(`-y, --yes`,`Skip interactive cache directory prompt and use default .cache`,!1).action($),Q.command(`run [port]`).description(`Alias for dev: build and launch the development server`).optionsGroup(`Server & Network Options:`).option(`-p, --port <port>`,`Port to listen on (default: 8888)`).option(`--host <host>`,`Bind host/IP`,`127.0.0.1`).option(`--ip <host>`,`Bind host/IP (alias)`).option(`--open`,`Automatically open default browser`,!1).option(`-v, --verbose`,`Enable verbose request/proxy logging`,!1).optionsGroup(`Site & Build Options:`).option(`--content-root <dir>`,`Content root directory`,_.cwd()).option(`--out-dir <dir>`,`Output directory relative to content root`,`dist/public`).optionsGroup(`Security & Proxy Options:`).option(`--cors-mode <mode>`,`CORS policy: localhost | private | all`,`localhost`).option(`--allow-private-proxy`,`Allow proxy to reach private/loopback addresses`,!1).option(`--peerjs`,`Enable built-in PeerJS signaling server`,!1).option(`--a2a`,`Enable A2A v1.0 agent card, JSON-RPC, and SSE endpoints`,!1).optionsGroup(`TLS / HTTPS Options:`).option(`--https`,`Enable HTTPS dev server`,!1).option(`--cert <path>`,`Path to existing TLS certificate file`).option(`--key <path>`,`Path to existing TLS private key file`).option(`--ssl-dir <path>`,`Directory for TLS certificate generation/storage`).optionsGroup(`Storage & Database Options:`).option(`--database-dir <dir>`,`Directory where SQLite databases are stored`).option(`--cache-dir <dir>`,`Custom cache directory for databases, tokens, and logs`).option(`--tmp, --temp`,`Store cache and databases in system temporary directory`,!1).option(`-y, --yes`,`Skip interactive cache directory prompt and use default .cache`,!1).action($),Q.commandsGroup(`Server:`),Q.command(`serve [port]`).description(`Serve static files and start backend services (optional: --peerjs, --a2a)`).optionsGroup(`Server & Network Options:`).option(`-p, --port <port>`,`Port to listen on (default: 8888)`).option(`--host <host>`,`Bind host/IP`,`127.0.0.1`).option(`--no-static`,`Disable static file and UI serving (services-only mode)`).option(`--open`,`Automatically open default browser`,!1).option(`-v, --verbose`,`Enable verbose request/proxy logging`,!1).optionsGroup(`Site Options:`).option(`--content-root <dir>`,`Content root directory`,_.cwd()).option(`--out-dir <dir>`,`Output directory relative to content root`,`dist/public`).optionsGroup(`Security & Proxy Options:`).option(`--cors-mode <mode>`,`CORS policy: localhost | private | all`,`localhost`).option(`--allow-private-proxy`,`Allow proxy to reach private/loopback addresses`,!1).option(`--peerjs`,`Enable built-in PeerJS signaling server`,!1).option(`--a2a`,`Enable A2A v1.0 agent card, JSON-RPC, and SSE endpoints`,!1).optionsGroup(`TLS / HTTPS Options:`).option(`--https`,`Enable HTTPS dev server`,!1).option(`--cert <path>`,`Path to existing TLS certificate file`).option(`--key <path>`,`Path to existing TLS private key file`).option(`--ssl-dir <path>`,`Directory for TLS certificate generation/storage`).optionsGroup(`Storage & Database Options:`).option(`--database-dir <dir>`,`Directory where SQLite databases are stored`).option(`--cache-dir <dir>`,`Custom cache directory for databases, tokens, and logs`).option(`--tmp, --temp`,`Store cache and databases in system temporary directory`,!1).option(`-y, --yes`,`Skip interactive cache directory prompt and use default .cache`,!1).action(async(e,t)=>{try{let r=h.resolve(t.contentRoot||_.cwd()),i=parseInt(e||t.port||_.env.PORT||`8888`,10),a=t.host||t.ip||_.env.SHADOWCLAW_DEV_IP||`127.0.0.1`,o=t.outDir||`dist/public`,s=h.resolve(r,o),c=await n({contentRoot:r,cacheDir:t.cacheDir,databaseDir:t.databaseDir,tmp:t.tmp||t.temp,yes:t.yes}),l=c.cacheDir,u=c.databaseDir,d=t.static!==!1;d&&!await Y(h.join(s,`index.html`))&&(console.error(`Error: No index.html found in ${s}. Run "shadow-claw build" first.`),_.exit(1));let f=await Y(h.join(U,`dist/server.js`))?h.join(U,`dist/server.js`):h.join(U,`src/server/server.ts`);_.env.SHADOWCLAW_ROOT_PATH=s,_.env.SHADOWCLAW_CACHE_DIR=l,_.env.SHADOWCLAW_DATABASE_DIR=u,_.env.SHADOWCLAW_DEV_IP=a;let{startServer:p}=await import(f),m=new Set((t.corsAllowOrigin||_.env.SHADOWCLAW_CORS_ALLOWED_ORIGINS||`https://xt-ml.github.io`).split(`,`).map(e=>e.trim()).filter(Boolean)),g=!!(t.https||[`1`,`true`,`yes`].includes((_.env.SHADOWCLAW_HTTPS||``).toLowerCase().trim())),v=t.cert||(_.env.SHADOWCLAW_TLS_CERT||_.env.SHADOWCLAW_CERT||``).trim()||void 0,y=t.key||(_.env.SHADOWCLAW_TLS_KEY||_.env.SHADOWCLAW_KEY||``).trim()||void 0,b=h.resolve(r,t.sslDir||_.env.SHADOWCLAW_SSL_DIR||_.env.SHADOWCLAW_TLS_DIR||h.join(l,`tls`));await p({port:i,bindHost:a,corsMode:t.corsMode||`localhost`,allowedOrigins:m,verbose:!!t.verbose,peerjs:!!t.peerjs,a2aEnabled:X(t),rootPath:s,cacheDir:l,databaseDir:u,allowPrivateProxy:!!t.allowPrivateProxy,https:g,certPath:v,keyPath:y,sslDir:b,serveStatic:d});let x=`${g?`https`:`http`}://${a}:${i}`;d&&t.open&&Z(x)}catch(e){console.error(`Serve error:`,e),_.exit(1)}});async function oe(e,t){try{let r=h.resolve(t.contentRoot||_.cwd()),i=parseInt(e||t.port||_.env.PORT||`8888`,10),a=t.host||t.ip||_.env.SHADOWCLAW_DEV_IP||`127.0.0.1`,o=await n({contentRoot:r,cacheDir:t.cacheDir,databaseDir:t.databaseDir,tmp:t.tmp||t.temp,yes:t.yes}),s=o.cacheDir,c=o.databaseDir,l=await Y(h.join(U,`dist/server.js`))?h.join(U,`dist/server.js`):h.join(U,`src/server/server.ts`);_.env.SHADOWCLAW_CACHE_DIR=s,_.env.SHADOWCLAW_DATABASE_DIR=c,_.env.SHADOWCLAW_DEV_IP=a,_.env.SHADOWCLAW_SERVE_STATIC=`false`;let{startServer:u}=await import(l),d=new Set((t.corsAllowOrigin||_.env.SHADOWCLAW_CORS_ALLOWED_ORIGINS||`https://xt-ml.github.io`).split(`,`).map(e=>e.trim()).filter(Boolean)),f=!!(t.https||[`1`,`true`,`yes`].includes((_.env.SHADOWCLAW_HTTPS||``).toLowerCase().trim())),p=t.cert||(_.env.SHADOWCLAW_TLS_CERT||_.env.SHADOWCLAW_CERT||``).trim()||void 0,m=t.key||(_.env.SHADOWCLAW_TLS_KEY||_.env.SHADOWCLAW_KEY||``).trim()||void 0,g=h.resolve(r,t.sslDir||_.env.SHADOWCLAW_SSL_DIR||_.env.SHADOWCLAW_TLS_DIR||h.join(s,`tls`));await u({port:i,bindHost:a,corsMode:t.corsMode||`localhost`,allowedOrigins:d,verbose:!!t.verbose,peerjs:!!t.peerjs,a2aEnabled:X(t),rootPath:``,cacheDir:s,databaseDir:c,controlToken:t.controlToken||_.env.SHADOWCLAW_CONTROL_TOKEN||void 0,allowPrivateProxy:!!t.allowPrivateProxy,https:f,certPath:p,keyPath:m,sslDir:g,serveStatic:!1})}catch(e){console.error(`Server error:`,e),_.exit(1)}}Q.command(`server [port]`).aliases([`services`,`api`]).description(`Start backend services (HTTP MCP, control plane, scheduler, and proxy) without serving static files (optional: --peerjs, --a2a; aliases: services, api)`).optionsGroup(`Server & Network Options:`).option(`-p, --port <port>`,`Port to listen on (default: 8888)`).option(`--host <host>`,`Bind host/IP`,`127.0.0.1`).option(`--ip <host>`,`Bind host/IP (alias)`).option(`-v, --verbose`,`Enable verbose request/proxy logging`,!1).optionsGroup(`Security & Proxy Options:`).option(`--cors-mode <mode>`,`CORS policy: localhost | private | all`,`localhost`).option(`--cors-allow-origin <origin>`,`Explicit allowed origins (comma-separated)`).option(`--control-token <token>`,`Secret token for control-plane authentication`).option(`--peerjs`,`Enable built-in PeerJS signaling server`,!1).option(`--a2a`,`Enable A2A v1.0 agent card, JSON-RPC, and SSE endpoints`,!1).option(`--allow-private-proxy`,`Allow proxy to reach private/loopback addresses`,!1).optionsGroup(`TLS / HTTPS Options:`).option(`--https`,`Enable HTTPS server`,!1).option(`--cert <path>`,`Path to existing TLS certificate file`).option(`--key <path>`,`Path to existing TLS private key file`).option(`--ssl-dir <path>`,`Directory for TLS certificate generation/storage`).optionsGroup(`Storage & Database Options:`).option(`--content-root <dir>`,`Content root directory`,_.cwd()).option(`--database-dir <dir>`,`Directory where SQLite databases are stored`).option(`--cache-dir <dir>`,`Custom cache directory for databases, tokens, and logs`).option(`--tmp, --temp`,`Store cache and databases in system temporary directory`,!1).option(`-y, --yes`,`Skip interactive cache directory prompt and use default .cache`,!1).action(oe),Q.command(`mcp`).description(`Start the standalone MCP server only (does not start backend services, PeerJS, or A2A)`).optionsGroup(`MCP Protocol Options:`).option(`--mcp-transport <transport>`,`MCP transport: stdio | http`,`stdio`).option(`--relay-client-tools`,`Discover and relay tools from connected browser clients`,!0).option(`--no-relay-client-tools`,`Disable relaying browser client tools`).optionsGroup(`Target Client Options:`).option(`--client <id>`,`Target client ID (defaults to first active client)`).optionsGroup(`Control Plane Connection Options:`).option(`--host <host>`,`Control plane host`).option(`--port <port>`,`Control plane port or HTTP MCP port`).option(`--token <token>`,`Control token`).option(`--https`,`Connect to server via HTTPS`,!1).option(`-k, --insecure`,`Allow self-signed TLS certificates`,!0).optionsGroup(`Transport & Peer Options:`).option(`--transport <transport>`,`Control plane client transport: http | webrtc`,`http`).option(`--peer-id <id>`,`Custom WebRTC CLI peer ID`).option(`--local-tools`,`Expose headless CLI agent tools (read_file, write_file, bash, git_*, etc.)`,!0).option(`--no-local-tools`,`Disable exposing headless CLI agent tools`).option(`--tool-prefix <prefix>`,`Tool prefix style for local tools: local | none | shadowclaw (default: local)`,`local`).optionsGroup(`Workspace & Local Agent Tools Options:`).option(`--workspace <dir>`,`Workspace directory for local tools (default: current working directory)`).option(`--database-dir <dir>`,`Directory where SQLite databases are stored`).option(`--group <groupId>`,`Conversation group ID for local tools (default: server:main)`).option(`--tools <tools>`,`Comma-separated list of local agent tools to expose (default: all headless-safe tools)`).option(`--tools-profile <name>`,`Tools profile to activate for local tools`).option(`--allow-internet, --internet-access`,`Allow full internet access for local Bash and JavaScript tools`).action(async e=>{await H(e)}),Q.commandsGroup(`Control Plane & Client Bridge:`),Q.command(`clients`).description(`List connected / registered browser and Electron clients`).optionsGroup(`Control Plane Connection Options:`).option(`--host <host>`,`Control plane host`).option(`--port <port>`,`Control plane port`).option(`--token <token>`,`Control token`).option(`--https`,`Connect to server via HTTPS`,!1).option(`-k, --insecure`,`Allow self-signed TLS certificates`,!0).optionsGroup(`Transport & Peer Options:`).option(`--transport <transport>`,`Transport to use: http | webrtc`,`http`).option(`--peer-id <id>`,`Custom WebRTC CLI peer ID`).option(`--renew-peer-id`,`Renew WebRTC CLI peer ID before connecting`,!1).option(`--cache-dir <dir>`,`Custom cache directory`).action(async e=>{await O(e)}),Q.command(`send <message>`).description(`Send a message/prompt to a connected client or peer agent`).optionsGroup(`Target Options:`).option(`--client <id>`,`Target client ID (defaults to first available)`).option(`--group <groupId>`,`Target conversation group ID`).option(`-f, --file <path>`,`Attach a local file to send with the message`).optionsGroup(`Control Plane Connection Options:`).option(`--host <host>`,`Control plane host`).option(`--port <port>`,`Control plane port`).option(`--token <token>`,`Control token`).option(`--https`,`Connect to server via HTTPS`,!1).option(`-k, --insecure`,`Allow self-signed TLS certificates`,!0).optionsGroup(`Transport & Peer Options:`).option(`--transport <transport>`,`Transport to use: http | webrtc`,`http`).option(`--peer-id <id>`,`Custom WebRTC CLI peer ID`).option(`--renew-peer-id`,`Renew WebRTC CLI peer ID before sending`,!1).option(`--cache-dir <dir>`,`Custom cache directory`).option(`--timeout <seconds>`,`Timeout in seconds to wait for response`,`120`).option(`--json`,`Output response payload as JSON`,!1).action(async(e,t)=>{await te(e,t)}),Q.command(`send-file <file>`).description(`Transfer a file to a connected peer or client over WebRTC or HTTP`).optionsGroup(`Target Options:`).option(`--client <id>`,`Target client ID (defaults to first available)`).option(`--prompt <prompt>`,`Accompanying prompt or instructions for the receiving agent`).option(`--name <fileName>`,`Override remote file name`).option(`--group <groupId>`,`Target conversation group ID`).optionsGroup(`Control Plane Connection Options:`).option(`--host <host>`,`Control plane host`).option(`--port <port>`,`Control plane port`).option(`--token <token>`,`Control token`).option(`--https`,`Connect to server via HTTPS`,!1).option(`-k, --insecure`,`Allow self-signed TLS certificates`,!0).optionsGroup(`Transport & Peer Options:`).option(`--transport <transport>`,`Transport to use: http | webrtc`,`webrtc`).option(`--peer-id <id>`,`Custom WebRTC CLI peer ID`).option(`--renew-peer-id`,`Renew WebRTC CLI peer ID before sending`,!1).option(`--cache-dir <dir>`,`Custom cache directory`).option(`--timeout <seconds>`,`Transfer and execution timeout in seconds`,`120`).option(`--json`,`Output response payload as JSON`,!1).action(async(e,t)=>{await k(e,t)}),Q.command(`tasks`).description(`List scheduled tasks on a connected client`).optionsGroup(`Target Options:`).option(`--client <id>`,`Target client ID`).option(`--group <groupId>`,`Filter tasks by conversation group ID`).optionsGroup(`Control Plane Connection Options:`).option(`--host <host>`,`Control plane host`).option(`--port <port>`,`Control plane port`).option(`--token <token>`,`Control token`).option(`--https`,`Connect to server via HTTPS`,!1).option(`-k, --insecure`,`Allow self-signed TLS certificates`,!0).optionsGroup(`Transport & Peer Options:`).option(`--transport <transport>`,`Transport to use: http | webrtc`,`http`).option(`--peer-id <id>`,`Custom WebRTC CLI peer ID`).option(`--renew-peer-id`,`Renew WebRTC CLI peer ID before connecting`,!1).option(`--cache-dir <dir>`,`Custom cache directory`).action(async e=>{await j(e)}),Q.command(`backup [action]`).description(`Trigger or manage client workspace backups (trigger | list | delete)`).optionsGroup(`Target Options:`).option(`--client <id>`,`Client ID`).option(`--backup-id <id>`,`Backup ID (for delete)`).option(`--group <groupId>`,`Specific workspace group ID`).optionsGroup(`Control Plane Connection Options:`).option(`--host <host>`,`Control plane host`).option(`--port <port>`,`Control plane port`).option(`--token <token>`,`Control token`).option(`--https`,`Connect to server via HTTPS`,!1).option(`-k, --insecure`,`Allow self-signed TLS certificates`,!0).optionsGroup(`Transport & Peer Options:`).option(`--transport <transport>`,`Transport to use: http | webrtc`,`http`).option(`--peer-id <id>`,`Custom WebRTC CLI peer ID`).option(`--renew-peer-id`,`Renew WebRTC CLI peer ID before connecting`,!1).option(`--cache-dir <dir>`,`Custom cache directory`).action(async(e,t)=>{await A(e||`trigger`,t)}),Q.commandsGroup(`WebRTC:`),Q.command(`webrtc [action] [customId]`).summary(`Manage WebRTC CLI configuration and peer identity (.cache/cli-peer-id)`).description(`Manage WebRTC CLI configuration and peer identity (.cache/cli-peer-id)
|
|
@@ -22,4 +22,4 @@ slug: "home"
|
|
|
22
22
|
.cache/
|
|
23
23
|
node_modules/
|
|
24
24
|
`,`utf8`),console.log(`Created ${o}`)),console.log(`\nShadowClaw template successfully initialized in ${t}`),console.log(`To start developing, run:`),console.log(` npx shadow-claw dev
|
|
25
|
-
`)}catch(e){console.error(`Init failed:`,e),_.exit(1)}}),Q.command(`skills:index [dir]`).alias(`agent-skills`).description(`Generate or update .well-known/agent-skills/index.json per the Agent Skills Discovery RFC`).optionsGroup(`Output & Path Options:`).option(`--out-dir <dir>`,`Output directory relative to content root (default: .well-known/agent-skills)`).option(`--out-file <file>`,`Explicit destination path for index.json`).option(`--metadata-root <dir>`,`Directory to read site metadata from (default: content root)`).option(`--config <file>`,`Explicit path to shadow-claw.config.json or site-config.json`).optionsGroup(`Generation Options:`).option(`--bundled`,`Include and materialize bundled ShadowClaw skills in index and .agents/skills`,!1).option(`--no-bundled`,`Exclude bundled ShadowClaw skills from index`).option(`--stdout`,`Print generated index.json to stdout`,!1).option(`--no-write`,`Skip writing file to disk`).action(async(e,t)=>{try{await p(e,t)}catch(e){console.error(`Failed to generate skills index:`,e),_.exit(1)}}),Q.commandsGroup(`Headless Agent:`),Q.command(`agent [action] [args...]`).description(`Run the headless CLI agent (init | model | skills | tools | tool | skill | import | run | listen)`).optionsGroup(`Agent Options:`).option(`--workspace <dir>`,`Workspace directory (default: isolated sandbox in temporary directory)`).option(`--database-dir <dir>`,`Directory where SQLite databases are stored`).option(`--cache-dir <dir>`,`Custom cache directory for databases and logs`).option(`--tmp, --temp`,`Store cache, token, and databases in OS temporary directory`).option(`-y, --yes`,`Skip interactive cache directory prompt and accept defaults`).option(`--group <groupId>`,`Conversation group ID`,`server:main`).option(`--provider <provider>`,`LLM provider ID`).option(`--model <model>`,`Model name`).option(`--download`,`Prewarm and download the model during agent init or execution`,!1).option(`--api-key <key>`,`API key`).option(`-v, --verbose`,`Enable verbose execution logging`,!1).option(`--allow-internet, --internet-access`,`Allow full internet access for Bash and JavaScript tools (sets vm_bash_full_internet_access)`).option(`-o, --output <file>`,`Write command output to a file instead of stdout`).option(`-f, --file <path>`,"Attach a local file to the prompt for `agent run` (repeatable)",(e,t=[])=>[...t,e]).option(`--stream`,`Stream response tokens to stdout as they arrive (default: true)`,!0).option(`--no-stream`,`Disable streaming response tokens to stdout`).option(`--progress`,`Show progress bar during model downloads (default: true)`,!0).option(`--no-progress`,`Disable download progress bar`).option(`--system-prompt <text>`,`Override system prompt with inline text`).option(`--system-prompt-file <file>`,`Load system prompt from a text or markdown file`).option(`--tools <tools>`,`Comma-separated list of tools to enable or import (e.g. bash,read_file)`).option(`--skills <skills>`,`Comma-separated list of skills to filter or import`).option(`--scripts <scripts>`,`Comma-separated list of scripts to import`).option(`--all`,`Import all tools, skills, and scripts from discovery manifest`,!1).option(`--overwrite`,`Overwrite existing skills, tools, or scripts during import`,!1).option(`--auto-enable`,`Automatically enable imported declarative tools (default: true)`,!0).option(`--no-auto-enable`,`Do not automatically enable imported declarative tools`).option(`--tools-profile <name>`,`Tools profile to activate (e.g. __builtin_default)`).option(`-r, --remote`,`List or search available models from Hugging Face onnx-community repository`,!1).option(`--huggingface, --hf`,`Alias for --remote to query Hugging Face`,!1).option(`--query <query>`,`Filter models by search query`).option(`-q, --quiet`,`Suppress all non-error output`,!1).action(async(e,t,n)=>{await r(e,t,n)}),Q.commandsGroup(`Help & Utility:`),Q.helpCommand(`help [command]`,`display help for command`);async function se(e=_.argv){await Q.parseAsync(e)}export{se as main,Q as program,G as registerTerminationCleanup};
|
|
25
|
+
`)}catch(e){console.error(`Init failed:`,e),_.exit(1)}}),Q.command(`skills:index [dir]`).alias(`agent-skills`).description(`Generate or update .well-known/agent-skills/index.json per the Agent Skills Discovery RFC`).optionsGroup(`Output & Path Options:`).option(`--out-dir <dir>`,`Output directory relative to content root (default: .well-known/agent-skills)`).option(`--out-file <file>`,`Explicit destination path for index.json`).option(`--metadata-root <dir>`,`Directory to read site metadata from (default: content root)`).option(`--config <file>`,`Explicit path to shadow-claw.config.json or site-config.json`).optionsGroup(`Generation Options:`).option(`--bundled`,`Include and materialize bundled ShadowClaw skills in index and .agents/skills`,!1).option(`--no-bundled`,`Exclude bundled ShadowClaw skills from index`).option(`--stdout`,`Print generated index.json to stdout`,!1).option(`--no-write`,`Skip writing file to disk`).action(async(e,t)=>{try{await p(e,t)}catch(e){console.error(`Failed to generate skills index:`,e),_.exit(1)}}),Q.commandsGroup(`Headless Agent:`),Q.command(`agent [action] [args...]`).description(`Run the headless CLI agent (init | model | skills | tools | tool | skill | import | run | clear | listen)`).optionsGroup(`Agent Options:`).option(`--workspace <dir>`,`Workspace directory (default: isolated sandbox in temporary directory)`).option(`--database-dir <dir>`,`Directory where SQLite databases are stored`).option(`--cache-dir <dir>`,`Custom cache directory for databases and logs`).option(`--tmp, --temp`,`Store cache, token, and databases in OS temporary directory`).option(`-y, --yes`,`Skip interactive cache directory prompt and accept defaults`).option(`--group <groupId>`,`Conversation group ID`,`server:main`).option(`--provider <provider>`,`LLM provider ID`).option(`--model <model>`,`Model name`).option(`--download`,`Prewarm and download the model during agent init or execution`,!1).option(`--api-key <key>`,`API key`).option(`-v, --verbose`,`Enable verbose execution logging`,!1).option(`--allow-internet, --internet-access`,`Allow full internet access for Bash and JavaScript tools (sets vm_bash_full_internet_access)`).option(`-o, --output <file>`,`Write command output to a file instead of stdout`).option(`-f, --file <path>`,"Attach a local file to the prompt for `agent run` (repeatable)",(e,t=[])=>[...t,e]).option(`--stream`,`Stream response tokens to stdout as they arrive (default: true)`,!0).option(`--no-stream`,`Disable streaming response tokens to stdout`).option(`--no-history`,"Do not load prior conversation history for `agent run`").option(`--progress`,`Show progress bar during model downloads (default: true)`,!0).option(`--no-progress`,`Disable download progress bar`).option(`--system-prompt <text>`,`Override system prompt with inline text`).option(`--system-prompt-file <file>`,`Load system prompt from a text or markdown file`).option(`--tools <tools>`,`Comma-separated list of tools to enable or import (e.g. bash,read_file)`).option(`--skills <skills>`,`Comma-separated list of skills to filter or import`).option(`--scripts <scripts>`,`Comma-separated list of scripts to import`).option(`--all`,`Import all tools, skills, and scripts from discovery manifest`,!1).option(`--overwrite`,`Overwrite existing skills, tools, or scripts during import`,!1).option(`--auto-enable`,`Automatically enable imported declarative tools (default: true)`,!0).option(`--no-auto-enable`,`Do not automatically enable imported declarative tools`).option(`--tools-profile <name>`,`Tools profile to activate (e.g. __builtin_default)`).option(`-r, --remote`,`List or search available models from Hugging Face onnx-community repository`,!1).option(`--huggingface, --hf`,`Alias for --remote to query Hugging Face`,!1).option(`--query <query>`,`Filter models by search query`).option(`-q, --quiet`,`Suppress all non-error output`,!1).action(async(e,t,n)=>{await r(e,t,n)}),Q.commandsGroup(`Help & Utility:`),Q.helpCommand(`help [command]`,`display help for command`);async function se(e=_.argv){await Q.parseAsync(e)}export{se as main,Q as program,G as registerTerminationCleanup};
|
package/dist/headless-agent.js
CHANGED
|
@@ -3523,7 +3523,7 @@ a=extmap-allow-mixed`)!==-1){var r=t.sdp.split(`
|
|
|
3523
3523
|
isBrowserSupported:${this.isBrowserSupported()}
|
|
3524
3524
|
isUnifiedPlanSupported:${this.isUnifiedPlanSupported()}`}constructor(){this.isIOS=typeof navigator<`u`&&[`iPad`,`iPhone`,`iPod`].includes(navigator.platform),this.supportedBrowsers=[`firefox`,`chrome`,`safari`],this.minFirefoxVersion=59,this.minChromeVersion=72,this.minSafariVersion=605}},m=e=>!e||/^[A-Za-z0-9]+(?:[ _-][A-Za-z0-9]+)*$/.test(e),h=()=>Math.random().toString(36).slice(2),g={iceServers:[{urls:`stun:stun.l.google.com:19302`},{urls:[`turn:eu-0.turn.peerjs.com:3478`,`turn:us-0.turn.peerjs.com:3478`],username:`peerjs`,credential:`peerjsp`}],sdpSemantics:`unified-plan`},_=new class extends u{noop(){}blobToArrayBuffer(e,t){let n=new FileReader;return n.onload=function(e){e.target&&t(e.target.result)},n.readAsArrayBuffer(e),n}binaryStringToArrayBuffer(e){let t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n)&255;return t.buffer}isSecure(){return location.protocol===`https:`}constructor(...e){super(...e),this.CLOUD_HOST=`0.peerjs.com`,this.CLOUD_PORT=443,this.chunkedBrowsers={Chrome:1,chrome:1},this.defaultConfig=g,this.browser=p.getBrowser(),this.browserVersion=p.getVersion(),this.pack=n.pack,this.unpack=n.unpack,this.supports=function(){let e={browser:p.isBrowserSupported(),webRTC:p.isWebRTCSupported(),audioVideo:!1,data:!1,binaryBlob:!1,reliable:!1};if(!e.webRTC)return e;let t;try{t=new RTCPeerConnection(g),e.audioVideo=!0;let n;try{n=t.createDataChannel(`_PEERJSTEST`,{ordered:!0}),e.data=!0,e.reliable=!!n.ordered;try{n.binaryType=`blob`,e.binaryBlob=!p.isIOS}catch{}}catch{}finally{n&&n.close()}}catch{}finally{t&&t.close()}return e}(),this.validateId=m,this.randomToken=h}};var v=new class{get logLevel(){return this._logLevel}set logLevel(e){this._logLevel=e}log(...e){this._logLevel>=3&&this._print(3,...e)}warn(...e){this._logLevel>=2&&this._print(2,...e)}error(...e){this._logLevel>=1&&this._print(1,...e)}setLogFunction(e){this._print=e}_print(e,...t){let n=[`PeerJS: `,...t];for(let e in n)n[e]instanceof Error&&(n[e]=`(`+n[e].name+`) `+n[e].message);e>=3?console.log(...n):e>=2?console.warn(`WARNING`,...n):e>=1&&console.error(`ERROR`,...n)}constructor(){this._logLevel=0}},y={};c(y,`ConnectionType`,()=>b),c(y,`PeerErrorType`,()=>x),c(y,`BaseConnectionErrorType`,()=>S),c(y,`DataConnectionErrorType`,()=>C),c(y,`SerializationType`,()=>w),c(y,`SocketEventType`,()=>ee),c(y,`ServerMessageType`,()=>te);var b=function(e){return e.Data=`data`,e.Media=`media`,e}({}),x=function(e){return e.BrowserIncompatible=`browser-incompatible`,e.Disconnected=`disconnected`,e.InvalidID=`invalid-id`,e.InvalidKey=`invalid-key`,e.Network=`network`,e.PeerUnavailable=`peer-unavailable`,e.SslUnavailable=`ssl-unavailable`,e.ServerError=`server-error`,e.SocketError=`socket-error`,e.SocketClosed=`socket-closed`,e.UnavailableID=`unavailable-id`,e.WebRTC=`webrtc`,e}({}),S=function(e){return e.NegotiationFailed=`negotiation-failed`,e.ConnectionClosed=`connection-closed`,e}({}),C=function(e){return e.NotOpenYet=`not-open-yet`,e.MessageToBig=`message-too-big`,e}({}),w=function(e){return e.Binary=`binary`,e.BinaryUTF8=`binary-utf8`,e.JSON=`json`,e.None=`raw`,e}({}),ee=function(e){return e.Message=`message`,e.Disconnected=`disconnected`,e.Error=`error`,e.Close=`close`,e}({}),te=function(e){return e.Heartbeat=`HEARTBEAT`,e.Candidate=`CANDIDATE`,e.Offer=`OFFER`,e.Answer=`ANSWER`,e.Open=`OPEN`,e.Error=`ERROR`,e.IdTaken=`ID-TAKEN`,e.InvalidKey=`INVALID-KEY`,e.Leave=`LEAVE`,e.Expire=`EXPIRE`,e}({}),T=class extends i.EventEmitter{constructor(e,t,n,r,i,a=5e3){super(),this.pingInterval=a,this._disconnected=!0,this._messagesQueue=[];let o=e?`wss://`:`ws://`;this._baseUrl=o+t+`:`+n+r+`peerjs?key=`+i}start(e,t){this._id=e;let n=`${this._baseUrl}&id=${e}&token=${t}`;this._socket||!this._disconnected||(this._socket=new WebSocket(n+`&version=1.5.5`),this._disconnected=!1,this._socket.onmessage=e=>{let t;try{t=JSON.parse(e.data),v.log(`Server message received:`,t)}catch{v.log(`Invalid server message`,e.data);return}this.emit(ee.Message,t)},this._socket.onclose=e=>{this._disconnected||(v.log(`Socket closed.`,e),this._cleanup(),this._disconnected=!0,this.emit(ee.Disconnected))},this._socket.onopen=()=>{this._disconnected||(this._sendQueuedMessages(),v.log(`Socket open`),this._scheduleHeartbeat())})}_scheduleHeartbeat(){this._wsPingTimer=setTimeout(()=>{this._sendHeartbeat()},this.pingInterval)}_sendHeartbeat(){if(!this._wsOpen()){v.log(`Cannot send heartbeat, because socket closed`);return}let e=JSON.stringify({type:te.Heartbeat});this._socket.send(e),this._scheduleHeartbeat()}_wsOpen(){return!!this._socket&&this._socket.readyState===1}_sendQueuedMessages(){let e=[...this._messagesQueue];this._messagesQueue=[];for(let t of e)this.send(t)}send(e){if(this._disconnected)return;if(!this._id){this._messagesQueue.push(e);return}if(!e.type){this.emit(ee.Error,`Invalid message`);return}if(!this._wsOpen())return;let t=JSON.stringify(e);this._socket.send(t)}close(){this._disconnected||=(this._cleanup(),!0)}_cleanup(){this._socket&&=(this._socket.onopen=this._socket.onmessage=this._socket.onclose=null,this._socket.close(),void 0),clearTimeout(this._wsPingTimer)}},E=class{constructor(e){this.connection=e}startConnection(e){let t=this._startPeerConnection();if(this.connection.peerConnection=t,this.connection.type===b.Media&&e._stream&&this._addTracksToConnection(e._stream,t),e.originator){let n=this.connection,r={ordered:!!e.reliable},i=t.createDataChannel(n.label,r);n._initializeDataChannel(i),this._makeOffer()}else this.handleSDP(`OFFER`,e.sdp)}_startPeerConnection(){v.log(`Creating RTCPeerConnection.`);let e=new RTCPeerConnection(this.connection.provider.options.config);return this._setupListeners(e),e}_setupListeners(e){let t=this.connection.peer,n=this.connection.connectionId,r=this.connection.type,i=this.connection.provider;v.log(`Listening for ICE candidates.`),e.onicecandidate=e=>{!e.candidate||!e.candidate.candidate||(v.log(`Received ICE candidates for ${t}:`,e.candidate),i.socket.send({type:te.Candidate,payload:{candidate:e.candidate,type:r,connectionId:n},dst:t}))},e.oniceconnectionstatechange=()=>{switch(e.iceConnectionState){case`failed`:v.log(`iceConnectionState is failed, closing connections to `+t),this.connection.emitError(S.NegotiationFailed,`Negotiation of connection to `+t+` failed.`),this.connection.close();break;case`closed`:v.log(`iceConnectionState is closed, closing connections to `+t),this.connection.emitError(S.ConnectionClosed,`Connection to `+t+` closed.`),this.connection.close();break;case`disconnected`:v.log(`iceConnectionState changed to disconnected on the connection with `+t);break;case`completed`:e.onicecandidate=()=>{};break}this.connection.emit(`iceStateChanged`,e.iceConnectionState)},v.log(`Listening for data channel`),e.ondatachannel=e=>{v.log(`Received data channel`);let r=e.channel;i.getConnection(t,n)._initializeDataChannel(r)},v.log(`Listening for remote stream`),e.ontrack=e=>{v.log(`Received remote stream`);let r=e.streams[0],a=i.getConnection(t,n);if(a.type===b.Media){let e=a;this._addStreamToMediaConnection(r,e)}}}cleanup(){v.log(`Cleaning up PeerConnection to `+this.connection.peer);let e=this.connection.peerConnection;if(!e)return;this.connection.peerConnection=null,e.onicecandidate=e.oniceconnectionstatechange=e.ondatachannel=e.ontrack=()=>{};let t=e.signalingState!==`closed`,n=!1,r=this.connection.dataChannel;r&&(n=!!r.readyState&&r.readyState!==`closed`),(t||n)&&e.close()}async _makeOffer(){let e=this.connection.peerConnection,t=this.connection.provider;try{let n=await e.createOffer(this.connection.options.constraints);v.log(`Created offer.`),this.connection.options.sdpTransform&&typeof this.connection.options.sdpTransform==`function`&&(n.sdp=this.connection.options.sdpTransform(n.sdp)||n.sdp);try{await e.setLocalDescription(n),v.log(`Set localDescription:`,n,`for:${this.connection.peer}`);let r={sdp:n,type:this.connection.type,connectionId:this.connection.connectionId,metadata:this.connection.metadata};if(this.connection.type===b.Data){let e=this.connection;r={...r,label:e.label,reliable:e.reliable,serialization:e.serialization}}t.socket.send({type:te.Offer,payload:r,dst:this.connection.peer})}catch(e){e!=`OperationError: Failed to set local offer sdp: Called in wrong state: kHaveRemoteOffer`&&(t.emitError(x.WebRTC,e),v.log(`Failed to setLocalDescription, `,e))}}catch(e){t.emitError(x.WebRTC,e),v.log(`Failed to createOffer, `,e)}}async _makeAnswer(){let e=this.connection.peerConnection,t=this.connection.provider;try{let n=await e.createAnswer();v.log(`Created answer.`),this.connection.options.sdpTransform&&typeof this.connection.options.sdpTransform==`function`&&(n.sdp=this.connection.options.sdpTransform(n.sdp)||n.sdp);try{await e.setLocalDescription(n),v.log(`Set localDescription:`,n,`for:${this.connection.peer}`),t.socket.send({type:te.Answer,payload:{sdp:n,type:this.connection.type,connectionId:this.connection.connectionId},dst:this.connection.peer})}catch(e){t.emitError(x.WebRTC,e),v.log(`Failed to setLocalDescription, `,e)}}catch(e){t.emitError(x.WebRTC,e),v.log(`Failed to create answer, `,e)}}async handleSDP(e,t){t=new RTCSessionDescription(t);let n=this.connection.peerConnection,r=this.connection.provider;v.log(`Setting remote description`,t);let i=this;try{await n.setRemoteDescription(t),v.log(`Set remoteDescription:${e} for:${this.connection.peer}`),e===`OFFER`&&await i._makeAnswer()}catch(e){r.emitError(x.WebRTC,e),v.log(`Failed to setRemoteDescription, `,e)}}async handleCandidate(e){v.log(`handleCandidate:`,e);try{await this.connection.peerConnection.addIceCandidate(e),v.log(`Added ICE candidate for:${this.connection.peer}`)}catch(e){this.connection.provider.emitError(x.WebRTC,e),v.log(`Failed to handleCandidate, `,e)}}_addTracksToConnection(e,t){if(v.log(`add tracks from stream ${e.id} to peer connection`),!t.addTrack)return v.error(`Your browser does't support RTCPeerConnection#addTrack. Ignored.`);e.getTracks().forEach(n=>{t.addTrack(n,e)})}_addStreamToMediaConnection(e,t){v.log(`add stream ${e.id} to media connection ${t.connectionId}`),t.addStream(e)}},D=class extends i.EventEmitter{emitError(e,t){v.error(`Error:`,t),this.emit(`error`,new O(`${e}`,t))}},O=class extends Error{constructor(e,t){typeof t==`string`?super(t):(super(),Object.assign(this,t)),this.type=e}},ne=class extends D{get open(){return this._open}constructor(e,t,n){super(),this.peer=e,this.provider=t,this.options=n,this._open=!1,this.metadata=n.metadata}},k=class e extends ne{static#e=this.ID_PREFIX=`mc_`;get type(){return b.Media}get localStream(){return this._localStream}get remoteStream(){return this._remoteStream}constructor(t,n,r){super(t,n,r),this._localStream=this.options._stream,this.connectionId=this.options.connectionId||e.ID_PREFIX+_.randomToken(),this._negotiator=new E(this),this._localStream&&this._negotiator.startConnection({_stream:this._localStream,originator:!0})}_initializeDataChannel(e){this.dataChannel=e,this.dataChannel.onopen=()=>{v.log(`DC#${this.connectionId} dc connection success`),this.emit(`willCloseOnRemote`)},this.dataChannel.onclose=()=>{v.log(`DC#${this.connectionId} dc closed for:`,this.peer),this.close()}}addStream(e){v.log(`Receiving stream`,e),this._remoteStream=e,super.emit(`stream`,e)}handleMessage(e){let t=e.type,n=e.payload;switch(e.type){case te.Answer:this._negotiator.handleSDP(t,n.sdp),this._open=!0;break;case te.Candidate:this._negotiator.handleCandidate(n.candidate);break;default:v.warn(`Unrecognized message type:${t} from peer:${this.peer}`);break}}answer(e,t={}){if(this._localStream){v.warn(`Local stream already exists on this MediaConnection. Are you answering a call twice?`);return}this._localStream=e,t&&t.sdpTransform&&(this.options.sdpTransform=t.sdpTransform),this._negotiator.startConnection({...this.options._payload,_stream:e});let n=this.provider._getMessages(this.connectionId);for(let e of n)this.handleMessage(e);this._open=!0}close(){this._negotiator&&=(this._negotiator.cleanup(),null),this._localStream=null,this._remoteStream=null,this.provider&&=(this.provider._removeConnection(this),null),this.options&&this.options._stream&&(this.options._stream=null),this.open&&(this._open=!1,super.emit(`close`))}},A=class{constructor(e){this._options=e}_buildRequest(e){let t=this._options.secure?`https`:`http`,{host:n,port:r,path:i,key:a}=this._options,o=new URL(`${t}://${n}:${r}${i}${a}/${e}`);return o.searchParams.set(`ts`,`${Date.now()}${Math.random()}`),o.searchParams.set(`version`,`1.5.5`),fetch(o.href,{referrerPolicy:this._options.referrerPolicy})}async retrieveId(){try{let e=await this._buildRequest(`id`);if(e.status!==200)throw Error(`Error. Status:${e.status}`);return e.text()}catch(e){v.error(`Error retrieving ID`,e);let t=``;throw this._options.path===`/`&&this._options.host!==_.CLOUD_HOST&&(t=" If you passed in a `path` to your self-hosted PeerServer, you'll also need to pass in that same path when creating a new Peer."),Error(`Could not get an ID from the server.`+t)}}async listAllPeers(){try{let e=await this._buildRequest(`peers`);if(e.status!==200){if(e.status===401){let e=``;throw e=this._options.host===_.CLOUD_HOST?`It looks like you're using the cloud server. You can email team@peerjs.com to enable peer listing for your API key.`:"You need to enable `allow_discovery` on your self-hosted PeerServer to use this feature.",Error(`It doesn't look like you have permission to list peers IDs. `+e)}throw Error(`Error. Status:${e.status}`)}return e.json()}catch(e){throw v.error(`Error retrieving list peers`,e),Error(`Could not get list peers from the server.`+e)}}},re=class e extends ne{static#e=this.ID_PREFIX=`dc_`;static#t=this.MAX_BUFFERED_AMOUNT=8388608;get type(){return b.Data}constructor(t,n,r){super(t,n,r),this.connectionId=this.options.connectionId||e.ID_PREFIX+h(),this.label=this.options.label||this.connectionId,this.reliable=!!this.options.reliable,this._negotiator=new E(this),this._negotiator.startConnection(this.options._payload||{originator:!0,reliable:this.reliable})}_initializeDataChannel(e){this.dataChannel=e,this.dataChannel.onopen=()=>{v.log(`DC#${this.connectionId} dc connection success`),this._open=!0,this.emit(`open`)},this.dataChannel.onmessage=e=>{v.log(`DC#${this.connectionId} dc onmessage:`,e.data)},this.dataChannel.onclose=()=>{v.log(`DC#${this.connectionId} dc closed for:`,this.peer),this.close()}}close(e){if(e?.flush){this.send({__peerData:{type:`close`}});return}this._negotiator&&=(this._negotiator.cleanup(),null),this.provider&&=(this.provider._removeConnection(this),null),this.dataChannel&&=(this.dataChannel.onopen=null,this.dataChannel.onmessage=null,this.dataChannel.onclose=null,null),this.open&&(this._open=!1,super.emit(`close`))}send(e,t=!1){if(!this.open){this.emitError(C.NotOpenYet,"Connection is not open. You should listen for the `open` event before sending messages.");return}return this._send(e,t)}async handleMessage(e){let t=e.payload;switch(e.type){case te.Answer:await this._negotiator.handleSDP(e.type,t.sdp);break;case te.Candidate:await this._negotiator.handleCandidate(t.candidate);break;default:v.warn(`Unrecognized message type:`,e.type,`from peer:`,this.peer);break}}},ie=class extends re{get bufferSize(){return this._bufferSize}_initializeDataChannel(e){super._initializeDataChannel(e),this.dataChannel.binaryType=`arraybuffer`,this.dataChannel.addEventListener(`message`,e=>this._handleDataMessage(e))}_bufferedSend(e){(this._buffering||!this._trySend(e))&&(this._buffer.push(e),this._bufferSize=this._buffer.length)}_trySend(e){if(!this.open)return!1;if(this.dataChannel.bufferedAmount>re.MAX_BUFFERED_AMOUNT)return this._buffering=!0,setTimeout(()=>{this._buffering=!1,this._tryBuffer()},50),!1;try{this.dataChannel.send(e)}catch(e){return v.error(`DC#:${this.connectionId} Error when sending:`,e),this._buffering=!0,this.close(),!1}return!0}_tryBuffer(){if(!this.open||this._buffer.length===0)return;let e=this._buffer[0];this._trySend(e)&&(this._buffer.shift(),this._bufferSize=this._buffer.length,this._tryBuffer())}close(e){if(e?.flush){this.send({__peerData:{type:`close`}});return}this._buffer=[],this._bufferSize=0,super.close()}constructor(...e){super(...e),this._buffer=[],this._bufferSize=0,this._buffering=!1}},ae=class extends ie{close(e){super.close(e),this._chunkedData={}}constructor(e,t,n){super(e,t,n),this.chunker=new u,this.serialization=w.Binary,this._chunkedData={}}_handleDataMessage({data:e}){let t=(0,n.unpack)(e),r=t.__peerData;if(r){if(r.type===`close`){this.close();return}this._handleChunk(t);return}this.emit(`data`,t)}_handleChunk(e){let t=e.__peerData,n=this._chunkedData[t]||{data:[],count:0,total:e.total};if(n.data[e.n]=new Uint8Array(e.data),n.count++,this._chunkedData[t]=n,n.total===n.count){delete this._chunkedData[t];let e=d(n.data);this._handleDataMessage({data:e})}}_send(e,t){let r=(0,n.pack)(e);if(r instanceof Promise)return this._send_blob(r);if(!t&&r.byteLength>this.chunker.chunkedMTU){this._sendChunks(r);return}this._bufferedSend(r)}async _send_blob(e){let t=await e;if(t.byteLength>this.chunker.chunkedMTU){this._sendChunks(t);return}this._bufferedSend(t)}_sendChunks(e){let t=this.chunker.chunk(e);v.log(`DC#${this.connectionId} Try to send ${t.length} chunks...`);for(let e of t)this.send(e,!0)}},oe=class extends ie{_handleDataMessage({data:e}){super.emit(`data`,e)}_send(e,t){this._bufferedSend(e)}constructor(...e){super(...e),this.serialization=w.None}},se=class extends ie{_handleDataMessage({data:e}){let t=this.parse(this.decoder.decode(e)),n=t.__peerData;if(n&&n.type===`close`){this.close();return}this.emit(`data`,t)}_send(e,t){let n=this.encoder.encode(this.stringify(e));if(n.byteLength>=_.chunkedMTU){this.emitError(C.MessageToBig,`Message too big for JSON channel`);return}this._bufferedSend(n)}constructor(...e){super(...e),this.serialization=w.JSON,this.encoder=new TextEncoder,this.decoder=new TextDecoder,this.stringify=JSON.stringify,this.parse=JSON.parse}},ce=class e extends D{static#e=this.DEFAULT_KEY=`peerjs`;get id(){return this._id}get options(){return this._options}get open(){return this._open}get socket(){return this._socket}get connections(){let e=Object.create(null);for(let[t,n]of this._connections)e[t]=n;return e}get destroyed(){return this._destroyed}get disconnected(){return this._disconnected}constructor(t,n){super(),this._serializers={raw:oe,json:se,binary:ae,"binary-utf8":ae,default:ae},this._id=null,this._lastServerId=null,this._destroyed=!1,this._disconnected=!1,this._open=!1,this._connections=new Map,this._lostMessages=new Map;let r;if(t&&t.constructor==Object?n=t:t&&(r=t.toString()),n={debug:0,host:_.CLOUD_HOST,port:_.CLOUD_PORT,path:`/`,key:e.DEFAULT_KEY,token:_.randomToken(),config:_.defaultConfig,referrerPolicy:`strict-origin-when-cross-origin`,serializers:{},...n},this._options=n,this._serializers={...this._serializers,...this.options.serializers},this._options.host===`/`&&(this._options.host=window.location.hostname),this._options.path&&(this._options.path[0]!==`/`&&(this._options.path=`/`+this._options.path),this._options.path[this._options.path.length-1]!==`/`&&(this._options.path+=`/`)),this._options.secure===void 0&&this._options.host!==_.CLOUD_HOST?this._options.secure=_.isSecure():this._options.host==_.CLOUD_HOST&&(this._options.secure=!0),this._options.logFunction&&v.setLogFunction(this._options.logFunction),v.logLevel=this._options.debug||0,this._api=new A(n),this._socket=this._createServerConnection(),!_.supports.audioVideo&&!_.supports.data){this._delayedAbort(x.BrowserIncompatible,`The current browser does not support WebRTC`);return}if(r&&!_.validateId(r)){this._delayedAbort(x.InvalidID,`ID "${r}" is invalid`);return}r?this._initialize(r):this._api.retrieveId().then(e=>this._initialize(e)).catch(e=>this._abort(x.ServerError,e))}_createServerConnection(){let e=new T(this._options.secure,this._options.host,this._options.port,this._options.path,this._options.key,this._options.pingInterval);return e.on(ee.Message,e=>{this._handleMessage(e)}),e.on(ee.Error,e=>{this._abort(x.SocketError,e)}),e.on(ee.Disconnected,()=>{this.disconnected||(this.emitError(x.Network,`Lost connection to server.`),this.disconnect())}),e.on(ee.Close,()=>{this.disconnected||this._abort(x.SocketClosed,`Underlying socket is already closed.`)}),e}_initialize(e){this._id=e,this.socket.start(e,this._options.token)}_handleMessage(e){let t=e.type,n=e.payload,r=e.src;switch(t){case te.Open:this._lastServerId=this.id,this._open=!0,this.emit(`open`,this.id);break;case te.Error:this._abort(x.ServerError,n.msg);break;case te.IdTaken:this._abort(x.UnavailableID,`ID "${this.id}" is taken`);break;case te.InvalidKey:this._abort(x.InvalidKey,`API KEY "${this._options.key}" is invalid`);break;case te.Leave:v.log(`Received leave message from ${r}`),this._cleanupPeer(r),this._connections.delete(r);break;case te.Expire:this.emitError(x.PeerUnavailable,`Could not connect to peer ${r}`);break;case te.Offer:{let e=n.connectionId,t=this.getConnection(r,e);if(t&&(t.close(),v.warn(`Offer received for existing Connection ID:${e}`)),n.type===b.Media){let i=new k(r,this,{connectionId:e,_payload:n,metadata:n.metadata});t=i,this._addConnection(r,t),this.emit(`call`,i)}else if(n.type===b.Data){let i=new this._serializers[n.serialization](r,this,{connectionId:e,_payload:n,metadata:n.metadata,label:n.label,serialization:n.serialization,reliable:n.reliable});t=i,this._addConnection(r,t),this.emit(`connection`,i)}else{v.warn(`Received malformed connection type:${n.type}`);return}let i=this._getMessages(e);for(let e of i)t.handleMessage(e);break}default:{if(!n){v.warn(`You received a malformed message from ${r} of type ${t}`);return}let i=n.connectionId,a=this.getConnection(r,i);a&&a.peerConnection?a.handleMessage(e):i?this._storeMessage(i,e):v.warn(`You received an unrecognized message:`,e);break}}}_storeMessage(e,t){this._lostMessages.has(e)||this._lostMessages.set(e,[]),this._lostMessages.get(e).push(t)}_getMessages(e){let t=this._lostMessages.get(e);return t?(this._lostMessages.delete(e),t):[]}connect(e,t={}){if(t={serialization:`default`,...t},this.disconnected){v.warn(`You cannot connect to a new Peer because you called .disconnect() on this Peer and ended your connection with the server. You can create a new Peer to reconnect, or call reconnect on this peer if you believe its ID to still be available.`),this.emitError(x.Disconnected,`Cannot connect to new Peer after disconnecting from server.`);return}let n=new this._serializers[t.serialization](e,this,t);return this._addConnection(e,n),n}call(e,t,n={}){if(this.disconnected){v.warn(`You cannot connect to a new Peer because you called .disconnect() on this Peer and ended your connection with the server. You can create a new Peer to reconnect.`),this.emitError(x.Disconnected,`Cannot connect to new Peer after disconnecting from server.`);return}if(!t){v.error("To call a peer, you must provide a stream from your browser's `getUserMedia`.");return}let r=new k(e,this,{...n,_stream:t});return this._addConnection(e,r),r}_addConnection(e,t){v.log(`add connection ${t.type}:${t.connectionId} to peerId:${e}`),this._connections.has(e)||this._connections.set(e,[]),this._connections.get(e).push(t)}_removeConnection(e){let t=this._connections.get(e.peer);if(t){let n=t.indexOf(e);n!==-1&&t.splice(n,1)}this._lostMessages.delete(e.connectionId)}getConnection(e,t){let n=this._connections.get(e);if(!n)return null;for(let e of n)if(e.connectionId===t)return e;return null}_delayedAbort(e,t){setTimeout(()=>{this._abort(e,t)},0)}_abort(e,t){v.error(`Aborting!`),this.emitError(e,t),this._lastServerId?this.disconnect():this.destroy()}destroy(){this.destroyed||(v.log(`Destroy peer with ID:${this.id}`),this.disconnect(),this._cleanup(),this._destroyed=!0,this.emit(`close`))}_cleanup(){for(let e of this._connections.keys())this._cleanupPeer(e),this._connections.delete(e);this.socket.removeAllListeners()}_cleanupPeer(e){let t=this._connections.get(e);if(t)for(let e of t)e.close()}disconnect(){if(this.disconnected)return;let e=this.id;v.log(`Disconnect peer with ID:${e}`),this._disconnected=!0,this._open=!1,this.socket.close(),this._lastServerId=e,this._id=null,this.emit(`disconnected`,e)}reconnect(){if(this.disconnected&&!this.destroyed)v.log(`Attempting reconnection to server with ID ${this._lastServerId}`),this._disconnected=!1,this._initialize(this._lastServerId);else if(this.destroyed)throw Error(`This peer cannot reconnect to the server. It has already been destroyed.`);else if(!this.disconnected&&!this.open)v.error(`In a hurry? We're still trying to make the initial connection!`);else throw Error(`Peer ${this.id} cannot reconnect because it is not disconnected from the server!`)}listAllPeers(e=e=>{}){this._api.listAllPeers().then(t=>e(t)).catch(e=>this._abort(x.ServerError,e))}},le=class extends re{constructor(e,t,n){super(e,t,{...n,reliable:!0}),this._CHUNK_SIZE=32768,this._splitStream=new TransformStream({transform:(e,t)=>{for(let n=0;n<e.length;n+=this._CHUNK_SIZE)t.enqueue(e.subarray(n,n+this._CHUNK_SIZE))}}),this._rawSendStream=new WritableStream({write:async(e,t)=>{let n=new Promise(e=>this.dataChannel.addEventListener(`bufferedamountlow`,e,{once:!0}));await(this.dataChannel.bufferedAmount<=re.MAX_BUFFERED_AMOUNT-e.byteLength||n);try{this.dataChannel.send(e)}catch(e){v.error(`DC#:${this.connectionId} Error when sending:`,e),t.error(e),this.close()}}}),this.writer=this._splitStream.writable.getWriter(),this._rawReadStream=new ReadableStream({start:e=>{this.once(`open`,()=>{this.dataChannel.addEventListener(`message`,t=>{e.enqueue(t.data)})})}}),this._splitStream.readable.pipeTo(this._rawSendStream)}_initializeDataChannel(e){super._initializeDataChannel(e),this.dataChannel.binaryType=`arraybuffer`,this.dataChannel.bufferedAmountLowThreshold=re.MAX_BUFFERED_AMOUNT/2}},ue=class extends le{constructor(e,t,n){super(e,t,n),this.serialization=`MsgPack`,this._encoder=new a.Encoder,(async()=>{for await(let e of(0,a.decodeMultiStream)(this._rawReadStream)){if(e.__peerData?.type===`close`){this.close();return}this.emit(`data`,e)}})()}_send(e){return this.writer.write(this._encoder.encode(e))}},de=class extends ce{constructor(...e){super(...e),this._serializers={MsgPack:ue,default:ue}}},fe=ce;s(t.exports,y)}));kc();function OQ(e){let t=e||(i.env.SHADOWCLAW_CACHE_DIR||``).trim()||T.join(i.cwd(),`.cache`);return T.join(t,`webrtc-ipc.sock`)}async function kQ(e){let t=OQ(e);try{return w.existsSync(t)?(await new Promise((e,n)=>{let r=re.request({socketPath:t,path:`/ping`,method:`GET`},t=>{t.resume(),t.statusCode===200?e():n(Error(`status ${t.statusCode}`))});r.setTimeout(1e3,()=>{r.destroy(),n(Error(`timeout`))}),r.on(`error`,n),r.end()}),{socketPath:t}):null}catch{return null}}function AQ(e,t,n,r,i){let a=e.socketPath||e.port;return new Promise((e,o)=>{let c=JSON.stringify({targetPeerId:t,action:n,args:r,timeoutMs:i}),l=re.request({socketPath:a,path:`/command`,method:`POST`,headers:{"Content-Type":`application/json`,"Content-Length":s.byteLength(c)}},t=>{let n=``;t.on(`data`,e=>n+=e),t.on(`end`,()=>{try{let r=JSON.parse(n);t.statusCode&&t.statusCode>=200&&t.statusCode<300?e(r):o(Error(r?.error||`IPC error ${t.statusCode}`))}catch{o(Error(`Bad IPC response: ${n}`))}})});l.setTimeout(i+2e3,()=>{l.destroy(),o(Error(`IPC request timed out`))}),l.on(`error`,e=>o(Error(`IPC connection failed: ${e.message}`))),l.write(c),l.end()})}function jQ(e){let t=e||(i.env.SHADOWCLAW_CACHE_DIR||``).trim()||T.join(i.cwd(),`.cache`);return T.join(t,`cli-peer-id`)}function MQ(e){if(i.env.SHADOWCLAW_CLI_PEER_ID)return i.env.SHADOWCLAW_CLI_PEER_ID.trim();let t=jQ(e);try{if(w.existsSync(t)){let e=w.readFileSync(t,`utf8`).trim();if(e)return e}}catch{}return``}function NQ(e,t){let n=jQ(t),r=T.dirname(n),i=e&&typeof e==`string`&&e.trim()?e.trim():`cli-${Sc().toLowerCase()}`;try{w.existsSync(r)||w.mkdirSync(r,{recursive:!0}),w.writeFileSync(n,i+`
|
|
3525
3525
|
`,`utf8`)}catch{}return i}function PQ(e,t){return e&&typeof e==`string`&&e.trim()?e.trim():i.env.SHADOWCLAW_CLI_PEER_ID?i.env.SHADOWCLAW_CLI_PEER_ID.trim():MQ(t)||NQ(void 0,t)}async function FQ(){if(typeof globalThis<`u`&&globalThis.RTCPeerConnection!==void 0)return!0;try{let e=await Promise.resolve().then(()=>(ZZ(),YZ));if(e&&e.RTCPeerConnection)return Object.assign(globalThis,{RTCPeerConnection:e.RTCPeerConnection,RTCSessionDescription:e.RTCSessionDescription,RTCIceCandidate:e.RTCIceCandidate}),!0}catch(e){console.warn(`[webrtc-cli] Failed to load node-datachannel polyfill:`,e?.message||String(e))}return!1}var IQ=class{host;port;path;secure;rejectUnauthorized;peer;cacheDir;cliPeerId;constructor(e={}){this.host=e.host||i.env.SHADOWCLAW_HOST||`127.0.0.1`,this.port=e.port||parseInt(i.env.SHADOWCLAW_PORT||`8888`,10),this.path=e.path||`/`,this.secure=e.secure??!1,this.rejectUnauthorized=e.rejectUnauthorized??!1,this.peer=null,this.cacheDir=e.cacheDir,this.cliPeerId=e.peerId&&e.peerId.trim()?e.peerId.trim():PQ(void 0,e.cacheDir)}async _getPeer(){if(this.peer&&!this.peer.destroyed)return this.peer;await FQ();let e=await Promise.resolve().then(()=>ye(DQ(),1)),t=e.default?.Peer||e.default||e.Peer;return new Promise((e,n)=>{let r={host:this.host,port:this.port,path:this.path,secure:this.secure};this.secure&&(r.config={iceServers:[]},r.wsOptions={rejectUnauthorized:this.rejectUnauthorized});let i=new t(this.cliPeerId,r);this.peer=i,i.on(`open`,()=>{e(i)}),i.on(`error`,e=>{n(Error(`PeerJS error: ${e.type||e.message||e}`))})})}async sendCommand(e,t,n={},r=3e4){let i=await kQ(this.cacheDir);if(i)return AQ(i,e,t,n,r);let a=await this._getPeer();return new Promise((i,o)=>{let s=null,c=null,l=()=>{if(s&&clearTimeout(s),c)try{c.close()}catch{}if(this.peer){try{this.peer.destroy()}catch{}this.peer=null}};s=setTimeout(()=>{l(),o(Error(`WebRTC command '${t}' to peer '${e}' timed out after ${r}ms`))},r);try{c=a.connect(e,{reliable:!0,serialization:`binary`}),c.on(`open`,()=>{let e=Sc(),r={id:Sc(),type:`command:execute`,payload:{commandId:e,action:t,args:n}};c.send(r)}),c.on(`data`,e=>{let t=e;if(typeof e==`string`)try{t=JSON.parse(e)}catch{}if(t&&t.method===`GetAgentCard`&&t.id){try{c.send({jsonrpc:`2.0`,id:t.id,result:{name:`ShadowClaw CLI`,description:`ShadowClaw Command Line Interface`,version:`1.0.0`}})}catch{}return}t&&t.type===`command:result`&&(l(),t.payload?.error?o(Error(t.payload.error)):i(t.payload))}),c.on(`error`,t=>{l(),o(Error(`WebRTC connection error to peer '${e}': ${t.message||String(t)}`))})}catch(e){l(),o(e)}})}async listClients(){let e=await kQ(this.cacheDir);if(!e)return[];let t=e.socketPath;return new Promise(e=>{let n=re.request({socketPath:t,path:`/clients`,method:`GET`},t=>{let n=``;t.on(`data`,e=>n+=e),t.on(`end`,()=>{try{e(JSON.parse(n).clients||[])}catch{e([])}})});n.setTimeout(2e3,()=>{n.destroy(),e([])}),n.on(`error`,()=>e([])),n.end()})}async sendFile(e,t,n={}){let r=T.resolve(t);if(!w.existsSync(r))throw Error(`File not found: ${t}`);let i=w.statSync(r);if(i.isDirectory())throw Error(`Cannot send directory: ${t}`);let a=n.name||T.basename(r),o=w.readFileSync(r).toString(`base64`),s=n.timeoutMs||12e4;return this.sendCommand(e,`send-file`,{fileName:a,data:o,fileSize:i.size,prompt:n.prompt,groupId:n.groupId},s)}close(){if(this.peer){try{this.peer.destroy()}catch{}this.peer=null}}};function LQ(e,t,n){if(e&&typeof e==`string`&&e.trim())return[e.trim()];if(i.env.SHADOWCLAW_CONTROL_TOKEN)return[i.env.SHADOWCLAW_CONTROL_TOKEN.trim()];let r=t||(i.env.SHADOWCLAW_CACHE_DIR||``).trim(),a=T.join(ae(),`shadow-claw`),o=typeof i.env.HOME==`string`?i.env.HOME:``,s=[],c=e=>{try{if(e&&w.existsSync(e)){let t=w.statSync(e),n=w.readFileSync(e,`utf8`),r=JSON.parse(n);if(r&&typeof r.token==`string`&&r.token.trim()){let n=Number(r.createdAt)||t.mtimeMs||0;s.push({token:r.token.trim(),timestamp:n,filePath:e})}}}catch{}},l=e=>{try{let t;if(typeof i.getBuiltinModule==`function`&&(t=i.getBuiltinModule(`node:sqlite`)),t&&t.DatabaseSync&&w.existsSync(e)){let n=w.statSync(e),r=new t.DatabaseSync(e),i=r.prepare(`SELECT value FROM metadata WHERE key = 'control_token'`).get();r.close(),i&&i.value&&s.push({token:`${i.value}`.trim(),timestamp:n.mtimeMs||0,filePath:e})}}catch{}};if(r)c(T.join(r,`control-token.json`)),l(T.join(r,`database`,`clients.db`)),l(T.join(r,`clients.db`));else{n&&c(T.join(a,`control-token-${n}.json`)),c(T.join(a,`control-token.json`)),l(T.join(a,`database`,`clients.db`)),c(T.join(i.cwd(),`.cache`,`control-token.json`)),c(T.join(i.cwd(),`control-token.json`)),l(T.join(i.cwd(),`.cache`,`database`,`clients.db`)),l(T.join(i.cwd(),`database`,`clients.db`));try{let e=w.readdirSync(i.cwd(),{withFileTypes:!0});for(let t of e)if(t.isDirectory()&&!t.name.startsWith(`node_modules`)&&!t.name.startsWith(`.`)){let e=T.join(i.cwd(),t.name);c(T.join(e,`.cache`,`control-token.json`)),c(T.join(e,`control-token.json`)),l(T.join(e,`.cache`,`database`,`clients.db`))}}catch{}try{let e=i.cwd();for(let t=0;t<4;t++){let t=T.dirname(e);if(!t||t===e)break;c(T.join(t,`.cache`,`control-token.json`)),c(T.join(t,`control-token.json`)),l(T.join(t,`.cache`,`database`,`clients.db`));try{let e=w.readdirSync(t,{withFileTypes:!0});for(let n of e)if(n.isDirectory()&&!n.name.startsWith(`node_modules`)&&!n.name.startsWith(`.`)){let e=T.join(t,n.name);c(T.join(e,`.cache`,`control-token.json`)),c(T.join(e,`control-token.json`)),l(T.join(e,`.cache`,`database`,`clients.db`))}}catch{}e=t}}catch{}o&&(c(T.join(o,`.config`,`shadow-claw`,`control-token.json`)),c(T.join(o,`.cache`,`shadow-claw`,`control-token.json`)))}s.sort((e,t)=>t.timestamp-e.timestamp);let u=new Set,d=[];for(let e of s)e.token&&!u.has(e.token)&&(u.add(e.token),d.push(e.token));return d}var RQ=class{host;port;candidateTokens;token;protocol;rejectUnauthorized;transport;cacheDir;_webrtcClient;constructor(e={}){this.host=e.host||i.env.SHADOWCLAW_HOST||`127.0.0.1`,this.port=e.port||parseInt(i.env.SHADOWCLAW_PORT||`8888`,10),this.candidateTokens=LQ(e.token,e.cacheDir,this.port),this.token=e.token||this.candidateTokens[0]||``,this.cacheDir=e.cacheDir;let t=!!(e.https||[`1`,`true`,`yes`].includes((i.env.SHADOWCLAW_HTTPS||``).toLowerCase().trim()));this.protocol=e.protocol||(t?`https`:`http`),this.rejectUnauthorized=e.rejectUnauthorized===void 0?e.insecure===!1:!!e.rejectUnauthorized,this.transport=e.transport||`http`,this._webrtcClient=this.transport===`webrtc`?new IQ({host:this.host,port:this.port,path:e.peerPath||`/`,secure:this.protocol===`https`,rejectUnauthorized:this.rejectUnauthorized,peerId:e.peerId,cacheDir:e.cacheDir,renewPeerId:!!e.renewPeerId}):null}async _request({method:e=`GET`,path:t,body:n=null,timeout:r=3e4}){let i=i=>new Promise((a,o)=>{let s=this.protocol===`https`?ie:re,c={"Content-Type":`application/json`};i&&(c[`x-control-token`]=i);let l={hostname:this.host,port:this.port,path:t,method:e,headers:c,timeout:r};this.protocol===`https`&&(l.rejectUnauthorized=this.rejectUnauthorized);let u=s.request(l,e=>{let t=``;e.on(`data`,e=>t+=e),e.on(`end`,()=>{let n=t;try{n=JSON.parse(t)}catch{}if(e.statusCode&&e.statusCode>=200&&e.statusCode<300)a({ok:!0,statusCode:e.statusCode,data:n});else{let r=n?.error||`HTTP request failed with status ${e.statusCode}: ${t}`;a({ok:!1,statusCode:e.statusCode,error:r,data:n})}})});u.on(`error`,e=>{o(Error(`Failed to connect to ShadowClaw server at ${this.host}:${this.port}: ${e.message}`))}),u.on(`timeout`,()=>{u.destroy(),o(Error(`Request timed out after ${r}ms`))}),n&&u.write(typeof n==`string`?n:JSON.stringify(n)),u.end()}),a=await i(this.token);if(a.ok)return a.data;if(a.statusCode===401&&Array.isArray(this.candidateTokens)&&this.candidateTokens.length>1)for(let e of this.candidateTokens){if(e===this.token)continue;let t=await i(e);if(t.ok)return this.token=e,t.data}throw Error(a.error||`HTTP request failed with status ${a.statusCode}`)}async listClients(){if(this._webrtcClient){try{let e=await this._webrtcClient.listClients();if(e&&e.length>0)return e}catch{}try{return(await this._request({path:`/api/control/clients`,method:`GET`})).clients||[]}catch{return[]}}return(await this._request({path:`/api/control/clients`,method:`GET`})).clients||[]}async sendCommand(e,t,n={},r=3e4){if(this._webrtcClient){let i=e;if(e&&e.startsWith(`client-`))try{let t=(await this.listClients()).find(t=>t.clientId===e);t&&t.peerId?i=t.peerId:t&&!t.peerId&&console.warn(`Warning: client "${e}" has no PeerJS peer ID registered.\nEnsure the browser has PeerJS enabled in Settings → WebRTC/PeerJS and has connected to the signaling server at least once.\nAlternatively, pass the browser's PeerJS peer ID directly with --client <peerId>.`)}catch{}return this._webrtcClient.sendCommand(i,t,n,r)}return await this._request({path:`/api/control/command`,method:`POST`,body:{clientId:e,action:t,args:n,timeoutMs:r},timeout:r+5e3})}async sendFile(e,t,n={}){let r=T.resolve(t);if(!w.existsSync(r))throw Error(`File not found: ${t}`);let i=w.statSync(r);if(i.isDirectory())throw Error(`Cannot send directory: ${t}`);let a=n.name||T.basename(r),o=w.readFileSync(r).toString(`base64`),s=n.timeoutMs||12e4;return this.sendCommand(e,`send-file`,{fileName:a,data:o,fileSize:i.size,prompt:n.prompt,groupId:n.groupId},s)}async listBackups(e){let t=e?`?clientId=${encodeURIComponent(e)}`:``;return(await this._request({path:`/api/backup/list${t}`,method:`GET`})).backups||[]}async deleteBackup(e,t){let n=t?`?clientId=${encodeURIComponent(t)}`:``;return await this._request({path:`/api/backup/${encodeURIComponent(e)}${n}`,method:`DELETE`})}async broadcastNotification({title:e=`ShadowClaw`,body:t,clientId:n}={}){return await this._request({path:`/push/broadcast`,method:`POST`,body:{title:e,body:t,...n?{clientId:n}:{}}})}async sendNotification(e){return this.broadcastNotification(e)}async listPushSubscriptions(){try{let e=await this._request({path:`/push/subscriptions`,method:`GET`});return Array.isArray(e)?e:[]}catch{return[]}}async listPushClients(){try{let e=await this._request({path:`/push/clients`,method:`GET`});if(e&&Array.isArray(e.clients))return e.clients}catch{}try{let e=await this.listPushSubscriptions();if(Array.isArray(e)&&e.length>0){let t=new Map;for(let n of e){let e=(n.client_id||``).trim()||(n.id?String(n.id):``);if(!e)continue;let r=t.get(e);r?!r.deviceLabel&&n.device_label&&(r.deviceLabel=n.device_label):t.set(e,{clientId:e,deviceLabel:n.device_label||void 0})}return Array.from(t.values())}}catch{}try{let e;if(typeof i.getBuiltinModule==`function`&&(e=i.getBuiltinModule(`node:sqlite`)),e&&e.DatabaseSync){let t=[T.join(i.cwd(),`.cache`,`database`,`push-subscriptions.db`),T.join(i.cwd(),`database`,`push-subscriptions.db`),T.join(ae(),`shadow-claw`,`database`,`push-subscriptions.db`),T.join(ae(),`shadow-claw`,`push-subscriptions.db`)];this.cacheDir&&t.unshift(T.join(this.cacheDir,`database`,`push-subscriptions.db`),T.join(this.cacheDir,`push-subscriptions.db`));for(let n of t)if(w.existsSync(n)){let t=new e.DatabaseSync(n),r=t.prepare(`SELECT client_id, device_label, id FROM subscriptions ORDER BY created_at DESC, id DESC`).all();if(t.close(),r&&r.length>0){let e=new Map;for(let t of r){let n=(t.client_id?`${t.client_id}`.trim():``)||(t.id?String(t.id):``);n&&(e.has(n)||e.set(n,{clientId:n,deviceLabel:t.device_label?`${t.device_label}`.trim():void 0}))}return Array.from(e.values())}}}}catch{}return[]}};Im();const zQ=()=>new RQ({transport:`webrtc`});jm(zQ),globalThis.__peerClientFactory=zQ,pz();async function BQ(e,t,n,r={}){let i=[],a=[];for(let o of n)try{r.onStep?.(o);let s=VQ(o.input||{},a,n),c=await uz(e,o.name,s,t,{isScheduledTask:!r.isManual,isTaskExecution:r.isTaskExecution});a.push(c),o.suppressOutput||i.push(`**Tool \`${o.name}\`**: ${c}`)}catch(e){let t=e.message||String(e);a.push(t),o.suppressOutput||i.push(`**Tool \`${o.name}\` failed**: ${t}`)}return{rawOutputs:a,results:i}}function VQ(e,t,n){if(e&&typeof e==`object`){if(Array.isArray(e))return e.map(e=>VQ(e,t,n));if(`$pipe`in e){let r=e.$pipe,i=``;if(r===`prev`)i=t[t.length-1]??``;else if(typeof r==`number`)i=t[r]??``;else if(typeof r==`string`){for(let e=t.length-1;e>=0;e--)if(n[e]?.name===r){i=t[e];break}}return HQ(i)}let r={};for(let[i,a]of Object.entries(e))r[i]=VQ(a,t,n);return r}return e}function HQ(e){return typeof e==`string`?e:Array.isArray(e)?e.map(e=>e&&typeof e==`object`?`text`in e?String(e.text):`data`in e?String(e.data):JSON.stringify(e):String(e??``)).join(`
|
|
3526
|
-
`):e&&typeof e==`object`?e:e??``}Tt();let UQ=null;const
|
|
3526
|
+
`):e&&typeof e==`object`?e:e??``}Tt();let UQ=null,WQ=null;const GQ=(e,t,n,r)=>{try{e.exec(`ALTER TABLE ${t} ADD COLUMN ${n} ${r}`)}catch{}};function KQ(e=`database/agent.db`){let t=e===`:memory:`?e:T.resolve(e);if(UQ&&WQ===t)return UQ;qQ();let n=new le(e);return n.exec(`
|
|
3527
3527
|
CREATE TABLE IF NOT EXISTS messages (
|
|
3528
3528
|
id TEXT PRIMARY KEY,
|
|
3529
3529
|
groupId TEXT NOT NULL,
|
|
@@ -3539,19 +3539,19 @@ a=extmap-allow-mixed`)!==-1){var r=t.sdp.split(`
|
|
|
3539
3539
|
freshContext INTEGER,
|
|
3540
3540
|
subagent INTEGER
|
|
3541
3541
|
)
|
|
3542
|
-
`),
|
|
3542
|
+
`),n.exec(`
|
|
3543
3543
|
CREATE INDEX IF NOT EXISTS messages_by_group_time
|
|
3544
3544
|
ON messages (groupId, timestamp)
|
|
3545
|
-
`),
|
|
3545
|
+
`),n.exec(`
|
|
3546
3546
|
CREATE INDEX IF NOT EXISTS messages_by_group
|
|
3547
3547
|
ON messages (groupId)
|
|
3548
|
-
`),
|
|
3548
|
+
`),n.exec(`
|
|
3549
3549
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
3550
3550
|
groupId TEXT PRIMARY KEY,
|
|
3551
3551
|
messages TEXT NOT NULL DEFAULT '[]',
|
|
3552
3552
|
updatedAt INTEGER NOT NULL DEFAULT 0
|
|
3553
3553
|
)
|
|
3554
|
-
`),
|
|
3554
|
+
`),n.exec(`
|
|
3555
3555
|
CREATE TABLE IF NOT EXISTS tasks (
|
|
3556
3556
|
id TEXT PRIMARY KEY,
|
|
3557
3557
|
groupId TEXT NOT NULL,
|
|
@@ -3567,21 +3567,21 @@ a=extmap-allow-mixed`)!==-1){var r=t.sdp.split(`
|
|
|
3567
3567
|
name TEXT,
|
|
3568
3568
|
task_order INTEGER
|
|
3569
3569
|
)
|
|
3570
|
-
`),
|
|
3570
|
+
`),n.exec(`
|
|
3571
3571
|
CREATE INDEX IF NOT EXISTS tasks_by_group
|
|
3572
3572
|
ON tasks (groupId)
|
|
3573
|
-
`),
|
|
3573
|
+
`),n.exec(`
|
|
3574
3574
|
CREATE INDEX IF NOT EXISTS tasks_by_enabled
|
|
3575
3575
|
ON tasks (enabled)
|
|
3576
|
-
`),
|
|
3576
|
+
`),n.exec(`
|
|
3577
3577
|
CREATE TABLE IF NOT EXISTS config (
|
|
3578
3578
|
key TEXT PRIMARY KEY,
|
|
3579
3579
|
value TEXT NOT NULL
|
|
3580
3580
|
)
|
|
3581
|
-
`),
|
|
3581
|
+
`),n.exec(`
|
|
3582
3582
|
CREATE TABLE IF NOT EXISTS pendingShares (
|
|
3583
3583
|
id TEXT PRIMARY KEY,
|
|
3584
3584
|
createdAt INTEGER NOT NULL,
|
|
3585
3585
|
data TEXT
|
|
3586
3586
|
)
|
|
3587
|
-
`),
|
|
3587
|
+
`),GQ(n,`tasks`,`type`,`TEXT`),GQ(n,`tasks`,`freshContext`,`INTEGER`),GQ(n,`tasks`,`subagent`,`INTEGER`),GQ(n,`tasks`,`name`,`TEXT`),GQ(n,`tasks`,`task_order`,`INTEGER`),GQ(n,`messages`,`freshContext`,`INTEGER`),GQ(n,`messages`,`subagent`,`INTEGER`),UQ=wt(n),WQ=t,UQ}function qQ(){UQ&&=(UQ.db.close(),null),WQ=null}sG(),yF(),Im(),pz(),Hr(),Rt(),St(),Tt(),dn(),BI(),Fu(),Ru(),Uu(),Xu(),ld(),_t(),vL(),jt(),bo(),aH(),mc(),CL(),PL(),iG(pG),Iq(dJ),Rq(BJ),dF(VJ),jm(zQ);export{Lt as BROWSER_ONLY_TOOLS,L as CONFIG_KEYS,Lu as DEFAULT_BUILTIN_PROFILE,Ye as DEFAULT_MAX_TOKENS,rt as DEFAULT_SERVER_GROUP_ID,lG as NodeFsDirectoryHandle,cG as NodeFsFileHandle,Pu as TOOL_DEFINITIONS,_t as a,j as c,CJ as cleanupAllLlamafileProcesses,qQ as closeSqliteDatabase,iJ as createTransformersRuntimeService,II as discoverSkills,AL as executeDetectLanguage,ML as executeEmbedText,SL as executeNativeAiTask,dJ as executeNodeTransformersCompletion,kL as executeProofreadText,OL as executeRewriteText,EL as executeSummarizeText,uz as executeTool,BQ as executeToolChain,jL as executeTranslateText,DL as executeWriteText,Ju as fetchDiscoveryManifest,Nt as filterHeadlessTools,We as getAvailableProviders,B as getConfig,dL as getContextLimit,vt as getDb,Ue as getDefaultProvider,Be as getModelMaxTokens,He as getProvider,fc as getRecentMessages,an as getStorageRoot,zq as handleInvoke,St as i,od as importRemoteArtifacts,id as importRemoteScript,ad as importRemoteSkill,rd as importRemoteTool,sn as invalidateStorageRoot,Pt as isHeadlessMode,Ct as isSqliteDatabase,Mt as isToolHeadlessSafe,Bu as loadDeclarativeTools,LI as loadSkill,kc as n,pG as nativeBashExecutor,VJ as nativeEvalExecutor,zQ as nativePeerClientFactory,Ne as o,KQ as openSqliteDatabase,zr as post,Sc as r,R as resetDB,Wu as resolveDiscoveryUrl,Re as s,iH as saveMessage,U as setConfig,yt as setDB,iG as setHeadlessBashExecutor,dF as setHeadlessEvalExecutor,Ft as setHeadlessMode,wL as setNativeAiTaskHandler,jm as setPeerClientFactory,Ir as setPostHandler,on as setStorageRoot,fG as setStorageRootFromPath,WP as t,wt as wrapSqliteDatabase};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://modelcontextprotocol.io/schemas/server-card/v1.json",
|
|
3
3
|
"name": "shadow-claw",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.44.0",
|
|
5
5
|
"description": "Multi-runtime AI assistant with local and remote LLM orchestration, Web Workers, OPFS storage, and agentic tool execution.",
|
|
6
6
|
"title": "ShadowClaw MCP Server",
|
|
7
7
|
"websiteUrl": "https://xt-ml.github.io/shadow-claw/",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://modelcontextprotocol.io/schemas/server-card/v1.json",
|
|
3
3
|
"name": "shadow-claw",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.44.0",
|
|
5
5
|
"description": "Multi-runtime AI assistant with local and remote LLM orchestration, Web Workers, OPFS storage, and agentic tool execution.",
|
|
6
6
|
"title": "ShadowClaw MCP Server",
|
|
7
7
|
"websiteUrl": "https://xt-ml.github.io/shadow-claw/",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!doctype html><html lang="en"><head><title>ShadowClaw</title><meta charset="utf-8"><meta name="revision" content="
|
|
1
|
+
<!doctype html><html lang="en"><head><title>ShadowClaw</title><meta charset="utf-8"><meta name="revision" content="6fd038c992eb684e7eca8ec9c8c3ce35519a511b" /><meta name="version" content="1.44.0" /><meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"><meta name="description" content="ShadowClaw - multi-runtime AI assistant." /><link rel="canonical" href="https://xt-ml.github.io/shadow-claw/"><meta property="og:title" content="ShadowClaw"><meta property="og:description" content="Multi-runtime AI assistant with local and remote LLM orchestration, Web Workers, OPFS storage, and agentic tool execution."><meta property="og:type" content="website"><meta property="og:url" content="https://xt-ml.github.io/shadow-claw/"><meta property="og:image" content="https://xt-ml.github.io/shadow-claw/assets/icons/512.png"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="ShadowClaw"><meta name="twitter:description" content="Multi-runtime AI assistant with local and remote LLM orchestration, Web Workers, OPFS storage, and agentic tool execution."><meta name="twitter:image" content="https://xt-ml.github.io/shadow-claw/assets/icons/512.png"><script type="application/ld+json">{"@context":"https://schema.org","@graph":[{"@type":"SoftwareApplication","@id":"https://xt-ml.github.io/shadow-claw/#software","name":"ShadowClaw","description":"Multi-runtime AI assistant with local and remote LLM orchestration, Web Workers, OPFS storage, and agentic tool execution.","url":"https://xt-ml.github.io/shadow-claw/","applicationCategory":"DeveloperApplication","operatingSystem":"Web, Browser, Desktop","offers":{"@type":"Offer","price":"0","priceCurrency":"USD"},"author":{"@type":"Organization","name":"xt-ml","url":"https://github.com/xt-ml"},"codeRepository":"https://github.com/xt-ml/shadow-claw","license":"https://github.com/xt-ml/shadow-claw/blob/main/LICENSE"},{"@type":"WebSite","@id":"https://xt-ml.github.io/shadow-claw/#website","url":"https://xt-ml.github.io/shadow-claw/","name":"ShadowClaw","description":"Official website and live deployment of ShadowClaw multi-runtime AI assistant.","publisher":{"@type":"Organization","name":"xt-ml","url":"https://github.com/xt-ml"}},{"@type":"Organization","@id":"https://xt-ml.github.io/shadow-claw/#organization","name":"xt-ml","url":"https://github.com/xt-ml","sameAs":["https://github.com/xt-ml"]}]}</script><meta name="theme-color" content="#fff" /><meta http-equiv="origin-trial" content="A88uTgESYWcVgREKVReKB6jom41uP8TzW6ei3jNdidf+Xl6ONqKRjKNBphsxhrZmdkakLK3oXDgkGq53rtZYSAMAAAB2eyJvcmlnaW4iOiJodHRwczovL3h0LW1sLmdpdGh1Yi5pbzo0NDMiLCJmZWF0dXJlIjoiV2ViTUNQIiwiZXhwaXJ5IjoxNzk0ODczNjAwLCJpc1N1YmRvbWFpbiI6dHJ1ZSwiaXNUaGlyZFBhcnR5Ijp0cnVlfQ=="><base href="/shadow-claw/" /><script id="shadow-claw-site-config" type="application/json">{"$schema":"https:\u002f\u002fjson-schema.org\u002fdraft\u002f2020-12\u002fschema","site":{"title":"ShadowClaw","description":"ShadowClaw - multi-runtime AI assistant.","themeColor":"#fff"},"branding":{"faviconPath":"assets\u002ficons\u002ffavicon.ico","appleTouchIconPath":"assets\u002ficons\u002f180.png","notFoundPath":"404.html"},"pwa":{"manifestPath":"manifest.json","themeColor":"#000000"},"sitemapPath":"sitemap.xml","assets":["assets"],"sidebar":{"pagesHidden":false,"chatHidden":false,"tasksHidden":false,"filesHidden":false,"defaultPage":"pages"},"pages":{"allowList":[],"denyList":[]},"settings":{"defaultToolsProfile":"__builtin_default"},"agent":{"defaultProvider":"transformers_js_local","defaultModel":"onnx-community\u002fgemma-3-1b-it-ONNX-GQA"},"customElements":{"allowedElements":["block-garden","block-garden-option","block-garden-select"],"allowedDomains":["kherrick.github.io","cdn.jsdelivr.net"]},"security":{"connectSrc":["'self'","blob:","data:","https:\u002f\u002fkherrick.github.io","https:\u002f\u002fcdn.jsdelivr.net"]}}</script>
|
|
2
2
|
<script>var ShadowClawThemeInit=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports);function n(){if(globalThis.trustedTypes)return;let e=new Map;globalThis.trustedTypes={createPolicy:(t,n)=>{if(e.has(t))throw TypeError(`Policy with name "${t}" already exists.`);let r={createHTML:n.createHTML?e=>n.createHTML(e):void 0,createScriptURL:n.createScriptURL?e=>n.createScriptURL(e):void 0,createScript:n.createScript?e=>n.createScript(e):void 0};return e.set(t,r),r},getPolicy:t=>e.get(t)??null,isHTML:e=>typeof e==`string`||e instanceof Object&&`toString`in e,isScriptURL:e=>typeof e==`string`||e instanceof Object&&`toString`in e,isScript:e=>typeof e==`string`||e instanceof Object&&`toString`in e}}let r=`__shadowClawDefaultTrustedTypesPolicyState`,i=`default`,a=`shadowclaw-sandbox`;function o(){let e=globalThis;return e[r]||(e[r]={initialized:!1,policy:null}),e[r]}function s(){let e=o();if(e.initialized)return;let t=Reflect.get(globalThis,`trustedTypes`);if(!(!t||typeof t.createPolicy!=`function`)){e.initialized=!0;try{if(typeof t.getPolicy==`function`){let n=t.getPolicy(i);if(n){e.policy=n;return}}let n=!1;if(typeof t.getPolicyNames==`function`){let e=t.getPolicyNames();Array.isArray(e)&&e.includes(i)&&(n=!0)}if(n){if(typeof t.getPolicy==`function`){let n=t.getPolicy(a);if(n){e.policy=n;return}}e.policy=t.createPolicy(a,{createHTML:e=>e,createScriptURL:e=>e});return}e.policy=t.createPolicy(i,{createHTML:e=>e,createScriptURL:e=>e})}catch{typeof t.getPolicy==`function`&&(e.policy=t.getPolicy(i)??t.getPolicy(a)??null)}}}new class{loading=!1;models=new Map;getModelInfo(e){if(!e||typeof e!=`string`)return null;let t=e.toLowerCase().trim(),n=this.models.get(t);if(n)return n;if(t.includes(`/`)){let e=t.split(`/`).pop();if(e&&this.models.has(e))return this.models.get(e)}else for(let[e,n]of this.models.entries())if(e.endsWith(`/${t}`))return n;if(t.includes(`:`)){let e=t.split(`:`)[0],n=this.getModelInfo(e);if(n)return n}return null}registerModelInfo(e,t){this.models.set(e.toLowerCase(),t)}clear(){this.models.clear()}async fetchModelInfo(e,t,n){if(e.modelsUrl){this.loading=!0;try{let r=new Headers;if(r.set(`Content-Type`,`application/json`),e.headers)for(let[t,n]of Object.entries(e.headers))r.set(t,n);if(n)for(let[e,t]of Object.entries(n))r.set(e,t);if(t&&e.apiKeyHeader){let n=e.apiKeyHeaderFormat;r.set(e.apiKeyHeader,n?n.replace(`{key}`,t):t)}let i=await fetch(e.modelsUrl,{headers:r});if(!i.ok)throw Error(`HTTP ${i.status} ${i.statusText}`);let a=await i.json(),o=Array.isArray(a.data)?a.data:Array.isArray(a.models)?a.models:[];for(let e of o){if(!e.id)continue;let t=e.context_length??e.context_window??0,n=e.max_completion_tokens||e.per_request_limits?.completion_tokens||e.top_provider?.max_completion_tokens||null,r=typeof e.supports_tools==`boolean`?e.supports_tools:typeof e.supportsTools==`boolean`?e.supportsTools:void 0,i=this.extractModalities(e,`input`),a=this.extractModalities(e,`output`),o=this.modalitiesInclude(i,`image`,`vision`),s=this.modalitiesInclude(i,`audio`,`voice`,`hearing`),c=this.modalitiesInclude(i,`video`),l=e.id===`openrouter/free`||this.supportedParametersInclude(e,`image`,`vision`,`audio`,`tool`,`structured`),u=this.extractReasoning(e),d=typeof e.supports_prompt_caching==`boolean`?e.supports_prompt_caching:typeof e.supportsPromptCaching==`boolean`?e.supportsPromptCaching:this.supportedParametersInclude(e,`cache_control`,`prompt_caching`)?!0:void 0;!t&&Array.isArray(e.providers)&&e.providers.length>0&&(t=e.providers[0]?.context_length||0),this.registerModelInfo(e.id,{contextWindow:t,maxOutput:n,...r!==void 0&&{supportsTools:r},...i.length>0&&{inputModalities:i},...a.length>0&&{outputModalities:a},...o!==void 0&&{supportsImageInput:o},...s!==void 0&&{supportsAudioInput:s},...c!==void 0&&{supportsVideoInput:c},...u&&{reasoning:u},...l&&{routesByRequestFeatures:l},...d!==void 0&&{supportsPromptCaching:d}})}o.length>0&&console.log(`[ModelRegistry] Registered ${o.length} models for provider "${e.id}"`)}catch(t){console.error(`[ModelRegistry] Error fetching models for ${e.id}:`,t)}finally{this.loading=!1}}}extractModalities(e,t){let n=t===`input`?e.input_modalities||e.inputModalities:e.output_modalities||e.outputModalities,r=e.architecture||{},i=t===`input`?r.input_modalities||r.inputModalities:r.output_modalities||r.outputModalities,a=typeof r.modality==`string`?r.modality:``,o=this.parseArchitectureModality(a,t),s=[...this.normalizeStringArray(n),...this.normalizeStringArray(i),...o];return Array.from(new Set(s))}extractReasoning(e){let t=e?.reasoning;if(!t||typeof t!=`object`)return;let n=this.normalizeStringArray(t.supported_efforts),r=typeof t.default_effort==`string`?t.default_effort.toLowerCase():void 0,i=typeof t.default_enabled==`boolean`?t.default_enabled:void 0,a=typeof t.supports_max_tokens==`boolean`?t.supports_max_tokens:void 0,o=typeof t.mandatory==`boolean`?t.mandatory:void 0;if(!(n.length===0&&r===void 0&&i===void 0&&a===void 0&&o===void 0))return{...n.length>0&&{supportedEfforts:n},...r!==void 0&&{defaultEffort:r},...i!==void 0&&{defaultEnabled:i},...a!==void 0&&{supportsMaxTokens:a},...o!==void 0&&{mandatory:o}}}modalitiesInclude(e,...t){if(e.length!==0)return t.some(t=>e.some(e=>e.includes(t)))}normalizeStringArray(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`).map(e=>e.toLowerCase()):[]}parseArchitectureModality(e,t){if(!e)return[];let[n=``,r=``]=e.toLowerCase().split(`->`).map(e=>e.trim());return(t===`input`?n:r).split(/[+,/\s]+/).map(e=>e.trim()).filter(Boolean)}supportedParametersInclude(e,...t){let n=this.normalizeStringArray(e.supported_parameters||e.supportedParameters);return t.some(e=>n.some(t=>t.includes(e)))}};function c(e){return e.replace(/^\/+|\/+$/g,``)}function l(e){let t=c(e);return t.endsWith(`/index.html`)?t=t.slice(0,-11):t.endsWith(`index.html`)&&(t=t.slice(0,-10)),c(t)}function u(e){let t=c(e),n=t.split(`/`).filter(Boolean);if(n.length===0)return null;let r=n[0].toLowerCase();if(r===`pages`){if(n.length>=3){let e=n[1];return{page:`pages`,groupId:e===`main`?`br:main`:e.startsWith(`br-`)?`br:${e.slice(3)}`:e,path:n.slice(2).join(`/`)}}return{page:`pages`,groupId:`br:main`,path:n.slice(1).join(`/`)}}if(r===`files`){let e=n[1]||`main`;return{page:`files`,groupId:e===`main`?`br:main`:e.startsWith(`br-`)?`br:${e.slice(3)}`:e,path:n.slice(2).join(`/`)||void 0}}if(r===`chat`){let e=n[1]||`main`;return{page:`chat`,groupId:e===`main`?`br:main`:e.startsWith(`br-`)?`br:${e.slice(3)}`:e}}if(r===`tasks`){let e=n[1]||`main`;return{page:`tasks`,groupId:e===`main`?`br:main`:e.startsWith(`br-`)?`br:${e.slice(3)}`:e}}return r===`main`?{page:`pages`,groupId:`br:main`,path:n.slice(1).join(`/`)}:{page:`pages`,groupId:`br:main`,path:t}}function d(){if(typeof document<`u`){let e=document.getElementById(`shadow-claw-static-routing`);if(e&&e.textContent)try{let t=JSON.parse(e.textContent);if(t&&typeof t==`object`&&t.routes)return t}catch(e){console.warn(`Failed to parse embedded static routing manifest:`,e)}}return null}function f(e,t){let n=t||d();if(!n||!n.routes)return null;let r=l(e);for(let[e,t]of Object.entries(n.routes))if(!(!t||!t.prettyPath)&&l(t.prettyPath)===r)return u(e);return null}let p=null,ee=new Set([`chat`,`files`,`tasks`,`pages`,`settings`,`tools`,`channels`]);function m(){p=null}typeof globalThis<`u`&&(globalThis.__applyBasePathCacheReset=m);function h(){let e=typeof window<`u`?window:typeof self<`u`?self:globalThis;if(e&&e.__SHADOWCLAW_DEPLOY_ID__){let t=String(e.__SHADOWCLAW_DEPLOY_ID__).trim();if(t)return t.replace(/[^a-zA-Z0-9_-]/g,`-`)}let t=globalThis.process;if(t&&t.env&&t.env.SHADOWCLAW_DEPLOY_ID){let e=String(t.env.SHADOWCLAW_DEPLOY_ID).trim();if(e)return e.replace(/[^a-zA-Z0-9_-]/g,`-`)}let n=te();return!n||n===`/`?``:n.replace(/^\/+|\/+$/g,``).replace(/[^a-zA-Z0-9_-]/g,`-`)}function te(){if(p!==null)return p;if((typeof window>`u`||globalThis.WorkerGlobalScope!==void 0&&typeof self<`u`&&self instanceof globalThis.WorkerGlobalScope)&&typeof self<`u`&&self.location){let e=(self.location.pathname||`/`).split(`/`).filter(Boolean);if(e.length<=1)return p=`/`,p;let t=e[0].toLowerCase(),n=t===`service-worker.js`||t===`sw.js`||t===`manifest.json`||t===`sitemap.xml`||t===`favicon.ico`||t===`index.html`||t===`service-worker`||t===`assets`||t===`dist`||t===`public`;if(n&&e.length===2)return p=`/`,p;if(!n)return p=`/`+e[0]+`/`,p}let e=typeof window<`u`&&window.location?window.location:typeof self<`u`&&self.location?self.location:null;if(!e)return`/`;if(typeof document<`u`&&typeof document.querySelector==`function`){let t=document.querySelector(`base[href]`);if(t){let n=t.getAttribute(`href`);if(n)try{let t=new URL(n,e.origin).pathname;return t.endsWith(`/`)||(t+=`/`),p=t,p}catch{}}}let t=e.pathname||`/`;if(t===`/`)return p=`/`,p;let n=t.split(`/`).filter(Boolean),r=n.findIndex(e=>ee.has(e.toLowerCase()));return r>=0?r===0?(p=`/`,p):(p=`/`+n.slice(0,r).join(`/`)+`/`,p):f(t)?(p=`/`,p):n.length===1&&!t.includes(`.`)?(p=`/`+n[0]+`/`,p):(p=`/`,p)}function ne(e){let t=e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`);return RegExp(`(^|\\s)@${t}\\b`,`i`)}ne(`ShadowClaw`);function g(){let e=h();return e?`shadowclaw-${e}`:`shadowclaw`}g();let _={github:{providerId:`github`,name:`GitHub`,aliases:[`github`,`api.github.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`,`git_remote`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`token `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://github.com/login/oauth/authorize`,tokenUrl:`https://github.com/login/oauth/access_token`,defaultScopes:[`repo`,`read:user`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},gitlab:{providerId:`gitlab`,name:`GitLab`,aliases:[`gitlab`,`gitlab.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`,`git_remote`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`PRIVATE-TOKEN`,headerPrefix:``},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},tokenAuthByServiceType:{git_remote:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}}},oauth:{authorizeUrl:`https://gitlab.com/oauth/authorize`,tokenUrl:`https://gitlab.com/oauth/token`,defaultScopes:[`read_api`,`read_user`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},figma:{providerId:`figma`,name:`Figma`,aliases:[`figma`,`api.figma.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`X-Figma-Token`,headerPrefix:``},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://www.figma.com/oauth`,tokenUrl:`https://api.figma.com/v1/oauth/token`,refreshUrl:`https://api.figma.com/v1/oauth/refresh`,defaultScopes:[],usePkce:!0,clientAuthMethod:`basic_header`,scopeSeparator:`space`}},notion:{providerId:`notion`,name:`Notion`,aliases:[`notion`,`api.notion.com`,`notion.so`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://api.notion.com/v1/oauth/authorize`,tokenUrl:`https://api.notion.com/v1/oauth/token`,defaultScopes:[],usePkce:!0,clientAuthMethod:`basic_header`,scopeSeparator:`space`}},microsoft_graph:{providerId:`microsoft_graph`,name:`Microsoft Graph`,aliases:[`microsoft`,`graph.microsoft.com`,`microsoft_graph`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://login.microsoftonline.com/common/oauth2/v2.0/authorize`,tokenUrl:`https://login.microsoftonline.com/common/oauth2/v2.0/token`,defaultScopes:[`openid`,`profile`,`offline_access`,`User.Read`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},yahoo_mail:{providerId:`yahoo_mail`,name:`Yahoo Mail`,aliases:[`yahoo`,`yahoo_mail`,`mail.yahoo.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://api.login.yahoo.com/oauth2/request_auth`,tokenUrl:`https://api.login.yahoo.com/oauth2/get_token`,defaultScopes:[`mail-r`,`mail-w`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},google:{providerId:`google`,name:`Google`,aliases:[`google`,`googleapis.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://accounts.google.com/o/oauth2/v2/auth`,tokenUrl:`https://oauth2.googleapis.com/token`,defaultScopes:[`openid`,`profile`,`email`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},atlassian:{providerId:`atlassian`,name:`Atlassian`,aliases:[`atlassian`,`api.atlassian.com`],modes:[`oauth`,`token`,`basic`],defaultMode:`basic`,serviceTypes:[`http_api`,`git_remote`],authTypes:[`token`,`oauth`,`basic_userpass`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `},basic:{headerName:`Authorization`,headerPrefix:`Basic `}},oauth:{authorizeUrl:`https://auth.atlassian.com/authorize`,tokenUrl:`https://auth.atlassian.com/oauth/token`,defaultScopes:[],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},slack:{providerId:`slack`,name:`Slack`,aliases:[`slack`,`slack.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://slack.com/oauth/v2/authorize`,tokenUrl:`https://slack.com/api/oauth.v2.access`,defaultScopes:[],usePkce:!1,clientAuthMethod:`request_body`,scopeSeparator:`comma`}},linear:{providerId:`linear`,name:`Linear`,aliases:[`linear`,`api.linear.app`,`linear.app`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://linear.app/oauth/authorize`,tokenUrl:`https://api.linear.app/oauth/token`,defaultScopes:[],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},azure_devops:{providerId:`azure_devops`,name:`Azure DevOps`,aliases:[`azure_devops`,`dev.azure.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`,`git_remote`],authTypes:[`token`,`oauth`,`basic_userpass`,`ssh_key`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},tokenAuthByServiceType:{git_remote:{token:{headerName:`Authorization`,headerPrefix:`Basic `},oauth:{headerName:`Authorization`,headerPrefix:`Basic `}}},oauth:{authorizeUrl:`https://app.vssps.visualstudio.com/oauth2/authorize`,tokenUrl:`https://app.vssps.visualstudio.com/oauth2/token`,defaultScopes:[`vso.code`,`vso.profile`,`offline_access`],usePkce:!1,clientAuthMethod:`request_body`,scopeSeparator:`space`}},custom_mcp:{providerId:`custom_mcp`,name:`Custom MCP`,aliases:[`custom_mcp`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`mcp_remote`,`webmcp_local`],authTypes:[`none`,`token`,`oauth`,`custom_header`,`ssh_key`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://example.com/oauth/authorize`,tokenUrl:`https://example.com/oauth/token`,defaultScopes:[],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}}};Object.fromEntries(Object.values(_).filter(e=>!!e.oauth).map(e=>{let t=e.oauth;return[e.providerId,{id:e.providerId,name:e.name,authorizeUrl:t.authorizeUrl,tokenUrl:t.tokenUrl,redirectUri:t.redirectUri,defaultScopes:t.defaultScopes,usePkce:t.usePkce,clientAuthMethod:t.clientAuthMethod,scopeSeparator:t.scopeSeparator}]})),Object.fromEntries(Object.values(_).map(e=>[e.providerId,{providerId:e.providerId,modes:e.modes,defaultMode:e.defaultMode}])),new Promise(e=>{});
|
|
3
3
|
/*! @license DOMPurify 3.4.13 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.13/LICENSE */
|
|
4
4
|
function v(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}function y(e){if(Array.isArray(e))return e}function b(e,t){var n=e==null?null:typeof Symbol<`u`&&e[Symbol.iterator]||e[`@@iterator`];if(n!=null){var r,i,a,o,s=[],c=!0,l=!1;try{if(a=(n=n.call(e)).next,t!==0)for(;!(c=(r=a.call(n)).done)&&(s.push(r.value),s.length!==t);c=!0);}catch(e){l=!0,i=e}finally{try{if(!c&&n.return!=null&&(o=n.return(),Object(o)!==o))return}finally{if(l)throw i}}return s}}function re(){throw TypeError(`Invalid attempt to destructure non-iterable instance.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!doctype html><html lang="en"><head><title>ShadowClaw</title><meta charset="utf-8"><meta name="revision" content="
|
|
1
|
+
<!doctype html><html lang="en"><head><title>ShadowClaw</title><meta charset="utf-8"><meta name="revision" content="6fd038c992eb684e7eca8ec9c8c3ce35519a511b" /><meta name="version" content="1.44.0" /><meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"><meta name="description" content="ShadowClaw - multi-runtime AI assistant." /><link rel="canonical" href="https://xt-ml.github.io/shadow-claw/"><meta property="og:title" content="ShadowClaw"><meta property="og:description" content="Multi-runtime AI assistant with local and remote LLM orchestration, Web Workers, OPFS storage, and agentic tool execution."><meta property="og:type" content="website"><meta property="og:url" content="https://xt-ml.github.io/shadow-claw/"><meta property="og:image" content="https://xt-ml.github.io/shadow-claw/assets/icons/512.png"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="ShadowClaw"><meta name="twitter:description" content="Multi-runtime AI assistant with local and remote LLM orchestration, Web Workers, OPFS storage, and agentic tool execution."><meta name="twitter:image" content="https://xt-ml.github.io/shadow-claw/assets/icons/512.png"><script type="application/ld+json">{"@context":"https://schema.org","@graph":[{"@type":"SoftwareApplication","@id":"https://xt-ml.github.io/shadow-claw/#software","name":"ShadowClaw","description":"Multi-runtime AI assistant with local and remote LLM orchestration, Web Workers, OPFS storage, and agentic tool execution.","url":"https://xt-ml.github.io/shadow-claw/","applicationCategory":"DeveloperApplication","operatingSystem":"Web, Browser, Desktop","offers":{"@type":"Offer","price":"0","priceCurrency":"USD"},"author":{"@type":"Organization","name":"xt-ml","url":"https://github.com/xt-ml"},"codeRepository":"https://github.com/xt-ml/shadow-claw","license":"https://github.com/xt-ml/shadow-claw/blob/main/LICENSE"},{"@type":"WebSite","@id":"https://xt-ml.github.io/shadow-claw/#website","url":"https://xt-ml.github.io/shadow-claw/","name":"ShadowClaw","description":"Official website and live deployment of ShadowClaw multi-runtime AI assistant.","publisher":{"@type":"Organization","name":"xt-ml","url":"https://github.com/xt-ml"}},{"@type":"Organization","@id":"https://xt-ml.github.io/shadow-claw/#organization","name":"xt-ml","url":"https://github.com/xt-ml","sameAs":["https://github.com/xt-ml"]}]}</script><meta name="theme-color" content="#fff" /><meta http-equiv="origin-trial" content="A88uTgESYWcVgREKVReKB6jom41uP8TzW6ei3jNdidf+Xl6ONqKRjKNBphsxhrZmdkakLK3oXDgkGq53rtZYSAMAAAB2eyJvcmlnaW4iOiJodHRwczovL3h0LW1sLmdpdGh1Yi5pbzo0NDMiLCJmZWF0dXJlIjoiV2ViTUNQIiwiZXhwaXJ5IjoxNzk0ODczNjAwLCJpc1N1YmRvbWFpbiI6dHJ1ZSwiaXNUaGlyZFBhcnR5Ijp0cnVlfQ=="><base href="/shadow-claw/" /><script id="shadow-claw-site-config" type="application/json">{"$schema":"https:\u002f\u002fjson-schema.org\u002fdraft\u002f2020-12\u002fschema","site":{"title":"ShadowClaw","description":"ShadowClaw - multi-runtime AI assistant.","themeColor":"#fff"},"branding":{"faviconPath":"assets\u002ficons\u002ffavicon.ico","appleTouchIconPath":"assets\u002ficons\u002f180.png","notFoundPath":"404.html"},"pwa":{"manifestPath":"manifest.json","themeColor":"#000000"},"sitemapPath":"sitemap.xml","assets":["assets"],"sidebar":{"pagesHidden":false,"chatHidden":false,"tasksHidden":false,"filesHidden":false,"defaultPage":"pages"},"pages":{"allowList":[],"denyList":[]},"settings":{"defaultToolsProfile":"__builtin_default"},"agent":{"defaultProvider":"transformers_js_local","defaultModel":"onnx-community\u002fgemma-3-1b-it-ONNX-GQA"},"customElements":{"allowedElements":["block-garden","block-garden-option","block-garden-select"],"allowedDomains":["kherrick.github.io","cdn.jsdelivr.net"]},"security":{"connectSrc":["'self'","blob:","data:","https:\u002f\u002fkherrick.github.io","https:\u002f\u002fcdn.jsdelivr.net"]}}</script>
|
|
2
2
|
<script>var ShadowClawThemeInit=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports);function n(){if(globalThis.trustedTypes)return;let e=new Map;globalThis.trustedTypes={createPolicy:(t,n)=>{if(e.has(t))throw TypeError(`Policy with name "${t}" already exists.`);let r={createHTML:n.createHTML?e=>n.createHTML(e):void 0,createScriptURL:n.createScriptURL?e=>n.createScriptURL(e):void 0,createScript:n.createScript?e=>n.createScript(e):void 0};return e.set(t,r),r},getPolicy:t=>e.get(t)??null,isHTML:e=>typeof e==`string`||e instanceof Object&&`toString`in e,isScriptURL:e=>typeof e==`string`||e instanceof Object&&`toString`in e,isScript:e=>typeof e==`string`||e instanceof Object&&`toString`in e}}let r=`__shadowClawDefaultTrustedTypesPolicyState`,i=`default`,a=`shadowclaw-sandbox`;function o(){let e=globalThis;return e[r]||(e[r]={initialized:!1,policy:null}),e[r]}function s(){let e=o();if(e.initialized)return;let t=Reflect.get(globalThis,`trustedTypes`);if(!(!t||typeof t.createPolicy!=`function`)){e.initialized=!0;try{if(typeof t.getPolicy==`function`){let n=t.getPolicy(i);if(n){e.policy=n;return}}let n=!1;if(typeof t.getPolicyNames==`function`){let e=t.getPolicyNames();Array.isArray(e)&&e.includes(i)&&(n=!0)}if(n){if(typeof t.getPolicy==`function`){let n=t.getPolicy(a);if(n){e.policy=n;return}}e.policy=t.createPolicy(a,{createHTML:e=>e,createScriptURL:e=>e});return}e.policy=t.createPolicy(i,{createHTML:e=>e,createScriptURL:e=>e})}catch{typeof t.getPolicy==`function`&&(e.policy=t.getPolicy(i)??t.getPolicy(a)??null)}}}new class{loading=!1;models=new Map;getModelInfo(e){if(!e||typeof e!=`string`)return null;let t=e.toLowerCase().trim(),n=this.models.get(t);if(n)return n;if(t.includes(`/`)){let e=t.split(`/`).pop();if(e&&this.models.has(e))return this.models.get(e)}else for(let[e,n]of this.models.entries())if(e.endsWith(`/${t}`))return n;if(t.includes(`:`)){let e=t.split(`:`)[0],n=this.getModelInfo(e);if(n)return n}return null}registerModelInfo(e,t){this.models.set(e.toLowerCase(),t)}clear(){this.models.clear()}async fetchModelInfo(e,t,n){if(e.modelsUrl){this.loading=!0;try{let r=new Headers;if(r.set(`Content-Type`,`application/json`),e.headers)for(let[t,n]of Object.entries(e.headers))r.set(t,n);if(n)for(let[e,t]of Object.entries(n))r.set(e,t);if(t&&e.apiKeyHeader){let n=e.apiKeyHeaderFormat;r.set(e.apiKeyHeader,n?n.replace(`{key}`,t):t)}let i=await fetch(e.modelsUrl,{headers:r});if(!i.ok)throw Error(`HTTP ${i.status} ${i.statusText}`);let a=await i.json(),o=Array.isArray(a.data)?a.data:Array.isArray(a.models)?a.models:[];for(let e of o){if(!e.id)continue;let t=e.context_length??e.context_window??0,n=e.max_completion_tokens||e.per_request_limits?.completion_tokens||e.top_provider?.max_completion_tokens||null,r=typeof e.supports_tools==`boolean`?e.supports_tools:typeof e.supportsTools==`boolean`?e.supportsTools:void 0,i=this.extractModalities(e,`input`),a=this.extractModalities(e,`output`),o=this.modalitiesInclude(i,`image`,`vision`),s=this.modalitiesInclude(i,`audio`,`voice`,`hearing`),c=this.modalitiesInclude(i,`video`),l=e.id===`openrouter/free`||this.supportedParametersInclude(e,`image`,`vision`,`audio`,`tool`,`structured`),u=this.extractReasoning(e),d=typeof e.supports_prompt_caching==`boolean`?e.supports_prompt_caching:typeof e.supportsPromptCaching==`boolean`?e.supportsPromptCaching:this.supportedParametersInclude(e,`cache_control`,`prompt_caching`)?!0:void 0;!t&&Array.isArray(e.providers)&&e.providers.length>0&&(t=e.providers[0]?.context_length||0),this.registerModelInfo(e.id,{contextWindow:t,maxOutput:n,...r!==void 0&&{supportsTools:r},...i.length>0&&{inputModalities:i},...a.length>0&&{outputModalities:a},...o!==void 0&&{supportsImageInput:o},...s!==void 0&&{supportsAudioInput:s},...c!==void 0&&{supportsVideoInput:c},...u&&{reasoning:u},...l&&{routesByRequestFeatures:l},...d!==void 0&&{supportsPromptCaching:d}})}o.length>0&&console.log(`[ModelRegistry] Registered ${o.length} models for provider "${e.id}"`)}catch(t){console.error(`[ModelRegistry] Error fetching models for ${e.id}:`,t)}finally{this.loading=!1}}}extractModalities(e,t){let n=t===`input`?e.input_modalities||e.inputModalities:e.output_modalities||e.outputModalities,r=e.architecture||{},i=t===`input`?r.input_modalities||r.inputModalities:r.output_modalities||r.outputModalities,a=typeof r.modality==`string`?r.modality:``,o=this.parseArchitectureModality(a,t),s=[...this.normalizeStringArray(n),...this.normalizeStringArray(i),...o];return Array.from(new Set(s))}extractReasoning(e){let t=e?.reasoning;if(!t||typeof t!=`object`)return;let n=this.normalizeStringArray(t.supported_efforts),r=typeof t.default_effort==`string`?t.default_effort.toLowerCase():void 0,i=typeof t.default_enabled==`boolean`?t.default_enabled:void 0,a=typeof t.supports_max_tokens==`boolean`?t.supports_max_tokens:void 0,o=typeof t.mandatory==`boolean`?t.mandatory:void 0;if(!(n.length===0&&r===void 0&&i===void 0&&a===void 0&&o===void 0))return{...n.length>0&&{supportedEfforts:n},...r!==void 0&&{defaultEffort:r},...i!==void 0&&{defaultEnabled:i},...a!==void 0&&{supportsMaxTokens:a},...o!==void 0&&{mandatory:o}}}modalitiesInclude(e,...t){if(e.length!==0)return t.some(t=>e.some(e=>e.includes(t)))}normalizeStringArray(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`).map(e=>e.toLowerCase()):[]}parseArchitectureModality(e,t){if(!e)return[];let[n=``,r=``]=e.toLowerCase().split(`->`).map(e=>e.trim());return(t===`input`?n:r).split(/[+,/\s]+/).map(e=>e.trim()).filter(Boolean)}supportedParametersInclude(e,...t){let n=this.normalizeStringArray(e.supported_parameters||e.supportedParameters);return t.some(e=>n.some(t=>t.includes(e)))}};function c(e){return e.replace(/^\/+|\/+$/g,``)}function l(e){let t=c(e);return t.endsWith(`/index.html`)?t=t.slice(0,-11):t.endsWith(`index.html`)&&(t=t.slice(0,-10)),c(t)}function u(e){let t=c(e),n=t.split(`/`).filter(Boolean);if(n.length===0)return null;let r=n[0].toLowerCase();if(r===`pages`){if(n.length>=3){let e=n[1];return{page:`pages`,groupId:e===`main`?`br:main`:e.startsWith(`br-`)?`br:${e.slice(3)}`:e,path:n.slice(2).join(`/`)}}return{page:`pages`,groupId:`br:main`,path:n.slice(1).join(`/`)}}if(r===`files`){let e=n[1]||`main`;return{page:`files`,groupId:e===`main`?`br:main`:e.startsWith(`br-`)?`br:${e.slice(3)}`:e,path:n.slice(2).join(`/`)||void 0}}if(r===`chat`){let e=n[1]||`main`;return{page:`chat`,groupId:e===`main`?`br:main`:e.startsWith(`br-`)?`br:${e.slice(3)}`:e}}if(r===`tasks`){let e=n[1]||`main`;return{page:`tasks`,groupId:e===`main`?`br:main`:e.startsWith(`br-`)?`br:${e.slice(3)}`:e}}return r===`main`?{page:`pages`,groupId:`br:main`,path:n.slice(1).join(`/`)}:{page:`pages`,groupId:`br:main`,path:t}}function d(){if(typeof document<`u`){let e=document.getElementById(`shadow-claw-static-routing`);if(e&&e.textContent)try{let t=JSON.parse(e.textContent);if(t&&typeof t==`object`&&t.routes)return t}catch(e){console.warn(`Failed to parse embedded static routing manifest:`,e)}}return null}function f(e,t){let n=t||d();if(!n||!n.routes)return null;let r=l(e);for(let[e,t]of Object.entries(n.routes))if(!(!t||!t.prettyPath)&&l(t.prettyPath)===r)return u(e);return null}let p=null,ee=new Set([`chat`,`files`,`tasks`,`pages`,`settings`,`tools`,`channels`]);function m(){p=null}typeof globalThis<`u`&&(globalThis.__applyBasePathCacheReset=m);function h(){let e=typeof window<`u`?window:typeof self<`u`?self:globalThis;if(e&&e.__SHADOWCLAW_DEPLOY_ID__){let t=String(e.__SHADOWCLAW_DEPLOY_ID__).trim();if(t)return t.replace(/[^a-zA-Z0-9_-]/g,`-`)}let t=globalThis.process;if(t&&t.env&&t.env.SHADOWCLAW_DEPLOY_ID){let e=String(t.env.SHADOWCLAW_DEPLOY_ID).trim();if(e)return e.replace(/[^a-zA-Z0-9_-]/g,`-`)}let n=te();return!n||n===`/`?``:n.replace(/^\/+|\/+$/g,``).replace(/[^a-zA-Z0-9_-]/g,`-`)}function te(){if(p!==null)return p;if((typeof window>`u`||globalThis.WorkerGlobalScope!==void 0&&typeof self<`u`&&self instanceof globalThis.WorkerGlobalScope)&&typeof self<`u`&&self.location){let e=(self.location.pathname||`/`).split(`/`).filter(Boolean);if(e.length<=1)return p=`/`,p;let t=e[0].toLowerCase(),n=t===`service-worker.js`||t===`sw.js`||t===`manifest.json`||t===`sitemap.xml`||t===`favicon.ico`||t===`index.html`||t===`service-worker`||t===`assets`||t===`dist`||t===`public`;if(n&&e.length===2)return p=`/`,p;if(!n)return p=`/`+e[0]+`/`,p}let e=typeof window<`u`&&window.location?window.location:typeof self<`u`&&self.location?self.location:null;if(!e)return`/`;if(typeof document<`u`&&typeof document.querySelector==`function`){let t=document.querySelector(`base[href]`);if(t){let n=t.getAttribute(`href`);if(n)try{let t=new URL(n,e.origin).pathname;return t.endsWith(`/`)||(t+=`/`),p=t,p}catch{}}}let t=e.pathname||`/`;if(t===`/`)return p=`/`,p;let n=t.split(`/`).filter(Boolean),r=n.findIndex(e=>ee.has(e.toLowerCase()));return r>=0?r===0?(p=`/`,p):(p=`/`+n.slice(0,r).join(`/`)+`/`,p):f(t)?(p=`/`,p):n.length===1&&!t.includes(`.`)?(p=`/`+n[0]+`/`,p):(p=`/`,p)}function ne(e){let t=e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`);return RegExp(`(^|\\s)@${t}\\b`,`i`)}ne(`ShadowClaw`);function g(){let e=h();return e?`shadowclaw-${e}`:`shadowclaw`}g();let _={github:{providerId:`github`,name:`GitHub`,aliases:[`github`,`api.github.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`,`git_remote`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`token `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://github.com/login/oauth/authorize`,tokenUrl:`https://github.com/login/oauth/access_token`,defaultScopes:[`repo`,`read:user`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},gitlab:{providerId:`gitlab`,name:`GitLab`,aliases:[`gitlab`,`gitlab.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`,`git_remote`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`PRIVATE-TOKEN`,headerPrefix:``},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},tokenAuthByServiceType:{git_remote:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}}},oauth:{authorizeUrl:`https://gitlab.com/oauth/authorize`,tokenUrl:`https://gitlab.com/oauth/token`,defaultScopes:[`read_api`,`read_user`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},figma:{providerId:`figma`,name:`Figma`,aliases:[`figma`,`api.figma.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`X-Figma-Token`,headerPrefix:``},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://www.figma.com/oauth`,tokenUrl:`https://api.figma.com/v1/oauth/token`,refreshUrl:`https://api.figma.com/v1/oauth/refresh`,defaultScopes:[],usePkce:!0,clientAuthMethod:`basic_header`,scopeSeparator:`space`}},notion:{providerId:`notion`,name:`Notion`,aliases:[`notion`,`api.notion.com`,`notion.so`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://api.notion.com/v1/oauth/authorize`,tokenUrl:`https://api.notion.com/v1/oauth/token`,defaultScopes:[],usePkce:!0,clientAuthMethod:`basic_header`,scopeSeparator:`space`}},microsoft_graph:{providerId:`microsoft_graph`,name:`Microsoft Graph`,aliases:[`microsoft`,`graph.microsoft.com`,`microsoft_graph`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://login.microsoftonline.com/common/oauth2/v2.0/authorize`,tokenUrl:`https://login.microsoftonline.com/common/oauth2/v2.0/token`,defaultScopes:[`openid`,`profile`,`offline_access`,`User.Read`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},yahoo_mail:{providerId:`yahoo_mail`,name:`Yahoo Mail`,aliases:[`yahoo`,`yahoo_mail`,`mail.yahoo.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://api.login.yahoo.com/oauth2/request_auth`,tokenUrl:`https://api.login.yahoo.com/oauth2/get_token`,defaultScopes:[`mail-r`,`mail-w`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},google:{providerId:`google`,name:`Google`,aliases:[`google`,`googleapis.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://accounts.google.com/o/oauth2/v2/auth`,tokenUrl:`https://oauth2.googleapis.com/token`,defaultScopes:[`openid`,`profile`,`email`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},atlassian:{providerId:`atlassian`,name:`Atlassian`,aliases:[`atlassian`,`api.atlassian.com`],modes:[`oauth`,`token`,`basic`],defaultMode:`basic`,serviceTypes:[`http_api`,`git_remote`],authTypes:[`token`,`oauth`,`basic_userpass`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `},basic:{headerName:`Authorization`,headerPrefix:`Basic `}},oauth:{authorizeUrl:`https://auth.atlassian.com/authorize`,tokenUrl:`https://auth.atlassian.com/oauth/token`,defaultScopes:[],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},slack:{providerId:`slack`,name:`Slack`,aliases:[`slack`,`slack.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://slack.com/oauth/v2/authorize`,tokenUrl:`https://slack.com/api/oauth.v2.access`,defaultScopes:[],usePkce:!1,clientAuthMethod:`request_body`,scopeSeparator:`comma`}},linear:{providerId:`linear`,name:`Linear`,aliases:[`linear`,`api.linear.app`,`linear.app`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://linear.app/oauth/authorize`,tokenUrl:`https://api.linear.app/oauth/token`,defaultScopes:[],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},azure_devops:{providerId:`azure_devops`,name:`Azure DevOps`,aliases:[`azure_devops`,`dev.azure.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`,`git_remote`],authTypes:[`token`,`oauth`,`basic_userpass`,`ssh_key`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},tokenAuthByServiceType:{git_remote:{token:{headerName:`Authorization`,headerPrefix:`Basic `},oauth:{headerName:`Authorization`,headerPrefix:`Basic `}}},oauth:{authorizeUrl:`https://app.vssps.visualstudio.com/oauth2/authorize`,tokenUrl:`https://app.vssps.visualstudio.com/oauth2/token`,defaultScopes:[`vso.code`,`vso.profile`,`offline_access`],usePkce:!1,clientAuthMethod:`request_body`,scopeSeparator:`space`}},custom_mcp:{providerId:`custom_mcp`,name:`Custom MCP`,aliases:[`custom_mcp`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`mcp_remote`,`webmcp_local`],authTypes:[`none`,`token`,`oauth`,`custom_header`,`ssh_key`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://example.com/oauth/authorize`,tokenUrl:`https://example.com/oauth/token`,defaultScopes:[],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}}};Object.fromEntries(Object.values(_).filter(e=>!!e.oauth).map(e=>{let t=e.oauth;return[e.providerId,{id:e.providerId,name:e.name,authorizeUrl:t.authorizeUrl,tokenUrl:t.tokenUrl,redirectUri:t.redirectUri,defaultScopes:t.defaultScopes,usePkce:t.usePkce,clientAuthMethod:t.clientAuthMethod,scopeSeparator:t.scopeSeparator}]})),Object.fromEntries(Object.values(_).map(e=>[e.providerId,{providerId:e.providerId,modes:e.modes,defaultMode:e.defaultMode}])),new Promise(e=>{});
|
|
3
3
|
/*! @license DOMPurify 3.4.13 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.13/LICENSE */
|
|
4
4
|
function v(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}function y(e){if(Array.isArray(e))return e}function b(e,t){var n=e==null?null:typeof Symbol<`u`&&e[Symbol.iterator]||e[`@@iterator`];if(n!=null){var r,i,a,o,s=[],c=!0,l=!1;try{if(a=(n=n.call(e)).next,t!==0)for(;!(c=(r=a.call(n)).done)&&(s.push(r.value),s.length!==t);c=!0);}catch(e){l=!0,i=e}finally{try{if(!c&&n.return!=null&&(o=n.return(),Object(o)!==o))return}finally{if(l)throw i}}return s}}function re(){throw TypeError(`Invalid attempt to destructure non-iterable instance.
|