sliccy 1.34.2 → 1.35.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.
@@ -1,4 +1,4 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/sql-wasm-BM0NbefL.js","assets/chunk-zsgVPwQN.js","assets/__vite-browser-external-RyPUarNg.js","assets/pyodide-CBYrCcoc.js","assets/preload-helper-ca-nBW7U.js","assets/es-DoVXtjfC.js","assets/dist-BWlKscHB.js","assets/provider-settings-BmUXXAz8.js","assets/provider-settings-CtInkgMU.js","assets/env-api-keys-DlVZ9FrG.js","assets/simple-options-B20EpYQT.js","assets/json-parse-JW3qhabb.js","assets/tray-follower-status-M8dOhnzY.js","assets/logger-B-No_qN_.js","assets/providers-C08JtA_W.js","assets/skills-Ke92WMkl.js","assets/skills-CTi4XTwR.js","assets/fs-f8JZDPIF.js","assets/browser-DHa7-69Q.js","assets/xterm-BmfB5bmM.css","assets/offscreen-client-ABShEPNe.js","assets/cdp-DNK51gjc.js","assets/bsh-watchdog-By5z523c.js"])))=>i.map(i=>d[i]);
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/sql-wasm-BM0NbefL.js","assets/chunk-zsgVPwQN.js","assets/__vite-browser-external-RyPUarNg.js","assets/pyodide-CBYrCcoc.js","assets/preload-helper-ca-nBW7U.js","assets/es-CztekvDk.js","assets/dist-BWlKscHB.js","assets/provider-settings-BmUXXAz8.js","assets/provider-settings-CtInkgMU.js","assets/env-api-keys-DlVZ9FrG.js","assets/simple-options-B20EpYQT.js","assets/json-parse-JW3qhabb.js","assets/tray-follower-status-M8dOhnzY.js","assets/logger-B-No_qN_.js","assets/providers-C08JtA_W.js","assets/skills-Ke92WMkl.js","assets/skills-CTi4XTwR.js","assets/fs-f8JZDPIF.js","assets/browser-DHa7-69Q.js","assets/xterm-BmfB5bmM.css","assets/offscreen-client-ABShEPNe.js","assets/cdp-DNK51gjc.js","assets/bsh-watchdog-By5z523c.js"])))=>i.map(i=>d[i]);
2
2
  import{i as e,o as t,t as n}from"./chunk-zsgVPwQN.js";import{t as r}from"./logger-B-No_qN_.js";import{c as i,f as a,h as o,i as s,l as c,m as l,n as u,o as d,p as f,r as p,s as m,t as h,u as g,v as _,y as v}from"./tray-follower-status-M8dOhnzY.js";import{t as y}from"./preload-helper-ca-nBW7U.js";import{A as b,D as x,E as S,O as C,S as w,_ as T,c as E,g as D,h as O,k as ee,n as te,o as ne,p as k,r as re,s as ie,v as ae,x as oe,y as se}from"./provider-settings-CtInkgMU.js";import{n as ce,t as le}from"./browser-DHa7-69Q.js";import{a as ue,i as de,n as fe,r as A,s as pe}from"./fs-f8JZDPIF.js";import{b as me,d as he,n as ge}from"./skills-CTi4XTwR.js";import{a as _e,c as ve,d as ye,i as be,l as xe,n as j,o as M,r as Se,s as Ce,u as we}from"./cdp-DNK51gjc.js";import{_ as Te,a as N,b as Ee,c as P,d as F,f as De,g as Oe,h as ke,i as Ae,l as je,m as Me,n as Ne,o as Pe,p as Fe,r as Ie,s as Le,t as Re,u as ze,v as Be,x as Ve,y as I}from"./db-CogIG09c.js";import{t as He}from"./magick-wasm-BR29mZjN.js";(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();function Ue(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}var We=Ue();function Ge(e){We=e}var Ke={exec:()=>null};function qe(e,t=``){let n=typeof e==`string`?e:e.source,r={replace:(e,t)=>{let i=typeof t==`string`?t:t.source;return i=i.replace(Ye.caret,`$1`),n=n.replace(e,i),r},getRegex:()=>new RegExp(n,t)};return r}var Je=(()=>{try{return!0}catch{return!1}})(),Ye={codeRemoveIndent:/^(?: {1,4}| {0,3}\t)/gm,outputLinkReplace:/\\([\[\]])/g,indentCodeCompensation:/^(\s+)(?:```)/,beginningSpace:/^\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\n/g,tabCharGlobal:/\t/g,multipleSpaceGlobal:/\s+/g,blankLine:/^[ \t]*$/,doubleBlankLine:/\n[ \t]*\n[ \t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \t]?/gm,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\[[ xX]\] +\S/,listReplaceTask:/^\[[ xX]\] +/,listTaskCheckbox:/\[[ xX]\]/,anyLine:/\n.*\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\||\| *$/g,tableRowBlankLine:/\n[ \t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^<a /i,endATag:/^<\/a>/i,startPreScriptTag:/^<(pre|code|kbd|script)(\s|>)/i,endPreScriptTag:/^<\/(pre|code|kbd|script)(\s|>)/i,startAngleBracket:/^</,endAngleBracket:/>$/,pedanticHrefTitle:/^([^'"]*[^\s])\s+(['"])(.*)\2/,unicodeAlphaNumeric:/[\p{L}\p{N}]/u,escapeTest:/[&<>"']/,escapeReplace:/[&<>"']/g,escapeTestNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,caret:/(^|[^\[])\^/g,percentDecode:/%25/g,findPipe:/\|/g,splitPipe:/ \|/,slashPipe:/\\\|/g,carriageReturn:/\r\n|\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\S*/,endingNewline:/\n$/,listItemRegex:e=>RegExp(`^( {0,3}${e})((?:[ ][^\\n]*)?(?:\\n|$))`),nextBulletRegex:e=>RegExp(`^ {0,${Math.min(3,e-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`),hrRegex:e=>RegExp(`^ {0,${Math.min(3,e-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),fencesBeginRegex:e=>RegExp(`^ {0,${Math.min(3,e-1)}}(?:\`\`\`|~~~)`),headingBeginRegex:e=>RegExp(`^ {0,${Math.min(3,e-1)}}#`),htmlBeginRegex:e=>RegExp(`^ {0,${Math.min(3,e-1)}}<(?:[a-z].*>|!--)`,`i`),blockquoteBeginRegex:e=>RegExp(`^ {0,${Math.min(3,e-1)}}>`)},Xe=/^(?:[ \t]*(?:\n|$))+/,Ze=/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,Qe=/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,$e=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,et=/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,tt=/ {0,3}(?:[*+-]|\d{1,9}[.)])/,nt=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,rt=qe(nt).replace(/bull/g,tt).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/\|table/g,``).getRegex(),it=qe(nt).replace(/bull/g,tt).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/table/g,/ {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(),at=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,ot=/^[^\n]+/,st=/(?!\s*\])(?:\\[\s\S]|[^\[\]\\])+/,ct=qe(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace(`label`,st).replace(`title`,/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),lt=qe(/^(bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,tt).getRegex(),ut=`address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul`,dt=/<!--(?:-?>|[\s\S]*?(?:-->|$))/,ft=qe(`^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))`,`i`).replace(`comment`,dt).replace(`tag`,ut).replace(`attribute`,/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),pt=qe(at).replace(`hr`,$e).replace(`heading`,` {0,3}#{1,6}(?:\\s|$)`).replace(`|lheading`,``).replace(`|table`,``).replace(`blockquote`,` {0,3}>`).replace(`fences`," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace(`list`,` {0,3}(?:[*+-]|1[.)])[ \\t]`).replace(`html`,`</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)`).replace(`tag`,ut).getRegex(),mt={blockquote:qe(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace(`paragraph`,pt).getRegex(),code:Ze,def:ct,fences:Qe,heading:et,hr:$e,html:ft,lheading:rt,list:lt,newline:Xe,paragraph:pt,table:Ke,text:ot},ht=qe(`^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)`).replace(`hr`,$e).replace(`heading`,` {0,3}#{1,6}(?:\\s|$)`).replace(`blockquote`,` {0,3}>`).replace(`code`,`(?: {4}| {0,3} )[^\\n]`).replace(`fences`," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace(`list`,` {0,3}(?:[*+-]|1[.)])[ \\t]`).replace(`html`,`</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)`).replace(`tag`,ut).getRegex(),gt={...mt,lheading:it,table:ht,paragraph:qe(at).replace(`hr`,$e).replace(`heading`,` {0,3}#{1,6}(?:\\s|$)`).replace(`|lheading`,``).replace(`table`,ht).replace(`blockquote`,` {0,3}>`).replace(`fences`," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace(`list`,` {0,3}(?:[*+-]|1[.)])[ \\t]`).replace(`html`,`</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)`).replace(`tag`,ut).getRegex()},_t={...mt,html:qe(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace(`comment`,dt).replace(/tag/g,`(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b`).getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:Ke,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:qe(at).replace(`hr`,$e).replace(`heading`,` *#{1,6} *[^
3
3
  ]`).replace(`lheading`,rt).replace(`|table`,``).replace(`blockquote`,` {0,3}>`).replace(`|fences`,``).replace(`|list`,``).replace(`|html`,``).replace(`|tag`,``).getRegex()},vt=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,yt=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,bt=/^( {2,}|\\)\n(?!\s*$)/,xt=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,St=/[\p{P}\p{S}]/u,Ct=/[\s\p{P}\p{S}]/u,wt=/[^\s\p{P}\p{S}]/u,Tt=qe(/^((?![*_])punctSpace)/,`u`).replace(/punctSpace/g,Ct).getRegex(),Et=/(?!~)[\p{P}\p{S}]/u,Dt=/(?!~)[\s\p{P}\p{S}]/u,Ot=/(?:[^\s\p{P}\p{S}]|~)/u,kt=qe(/link|precode-code|html/,`g`).replace(`link`,/\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace(`precode-`,Je?"(?<!`)()":"(^^|[^`])").replace(`code`,/(?<b>`+)[^`]+\k<b>(?!`)/).replace(`html`,/<(?! )[^<>]*?>/).getRegex(),At=/^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/,jt=qe(At,`u`).replace(/punct/g,St).getRegex(),Mt=qe(At,`u`).replace(/punct/g,Et).getRegex(),Nt=`^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)`,Pt=qe(Nt,`gu`).replace(/notPunctSpace/g,wt).replace(/punctSpace/g,Ct).replace(/punct/g,St).getRegex(),Ft=qe(Nt,`gu`).replace(/notPunctSpace/g,Ot).replace(/punctSpace/g,Dt).replace(/punct/g,Et).getRegex(),It=qe(`^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)`,`gu`).replace(/notPunctSpace/g,wt).replace(/punctSpace/g,Ct).replace(/punct/g,St).getRegex(),Lt=qe(/^~~?(?:((?!~)punct)|[^\s~])/,`u`).replace(/punct/g,St).getRegex(),Rt=qe(`^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)`,`gu`).replace(/notPunctSpace/g,wt).replace(/punctSpace/g,Ct).replace(/punct/g,St).getRegex(),zt=qe(/\\(punct)/,`gu`).replace(/punct/g,St).getRegex(),Bt=qe(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace(`scheme`,/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace(`email`,/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),Vt=qe(dt).replace(`(?:-->|$)`,`-->`).getRegex(),Ht=qe(`^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>`).replace(`comment`,Vt).replace(`attribute`,/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),Ut=/(?:\[(?:\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\])|[^\[\]\\`])*?/,Wt=qe(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]+(?:\n[ \t]*)?|\n[ \t]*)(title))?\s*\)/).replace(`label`,Ut).replace(`href`,/<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]*/).replace(`title`,/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),Gt=qe(/^!?\[(label)\]\[(ref)\]/).replace(`label`,Ut).replace(`ref`,st).getRegex(),Kt=qe(/^!?\[(ref)\](?:\[\])?/).replace(`ref`,st).getRegex(),qt=qe(`reflink|nolink(?!\\()`,`g`).replace(`reflink`,Gt).replace(`nolink`,Kt).getRegex(),Jt=/[hH][tT][tT][pP][sS]?|[fF][tT][pP]/,Yt={_backpedal:Ke,anyPunctuation:zt,autolink:Bt,blockSkip:kt,br:bt,code:yt,del:Ke,delLDelim:Ke,delRDelim:Ke,emStrongLDelim:jt,emStrongRDelimAst:Pt,emStrongRDelimUnd:It,escape:vt,link:Wt,nolink:Kt,punctuation:Tt,reflink:Gt,reflinkSearch:qt,tag:Ht,text:xt,url:Ke},Xt={...Yt,link:qe(/^!?\[(label)\]\((.*?)\)/).replace(`label`,Ut).getRegex(),reflink:qe(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace(`label`,Ut).getRegex()},Zt={...Yt,emStrongRDelimAst:Ft,emStrongLDelim:Mt,delLDelim:Lt,delRDelim:Rt,url:qe(/^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace(`protocol`,Jt).replace(`email`,/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/,text:qe(/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/).replace(`protocol`,Jt).getRegex()},Qt={...Zt,br:qe(bt).replace(`{2,}`,`*`).getRegex(),text:qe(Zt.text).replace(`\\b_`,`\\b_| {2,}\\n`).replace(/\{2,\}/g,`*`).getRegex()},$t={normal:mt,gfm:gt,pedantic:_t},en={normal:Yt,gfm:Zt,breaks:Qt,pedantic:Xt},tn={"&":`&amp;`,"<":`&lt;`,">":`&gt;`,'"':`&quot;`,"'":`&#39;`},nn=e=>tn[e];function rn(e,t){if(t){if(Ye.escapeTest.test(e))return e.replace(Ye.escapeReplace,nn)}else if(Ye.escapeTestNoEncode.test(e))return e.replace(Ye.escapeReplaceNoEncode,nn);return e}function an(e){try{e=encodeURI(e).replace(Ye.percentDecode,`%`)}catch{return null}return e}function on(e,t){let n=e.replace(Ye.findPipe,(e,t,n)=>{let r=!1,i=t;for(;--i>=0&&n[i]===`\\`;)r=!r;return r?`|`:` |`}).split(Ye.splitPipe),r=0;if(n[0].trim()||n.shift(),n.length>0&&!n.at(-1)?.trim()&&n.pop(),t)if(n.length>t)n.splice(t);else for(;n.length<t;)n.push(``);for(;r<n.length;r++)n[r]=n[r].trim().replace(Ye.slashPipe,`|`);return n}function sn(e,t,n){let r=e.length;if(r===0)return``;let i=0;for(;i<r;){let a=e.charAt(r-i-1);if(a===t&&!n)i++;else if(a!==t&&n)i++;else break}return e.slice(0,r-i)}function cn(e,t){if(e.indexOf(t[1])===-1)return-1;let n=0;for(let r=0;r<e.length;r++)if(e[r]===`\\`)r++;else if(e[r]===t[0])n++;else if(e[r]===t[1]&&(n--,n<0))return r;return n>0?-2:-1}function ln(e,t=0){let n=t,r=``;for(let t of e)if(t===` `){let e=4-n%4;r+=` `.repeat(e),n+=e}else r+=t,n++;return r}function un(e,t,n,r,i){let a=t.href,o=t.title||null,s=e[1].replace(i.other.outputLinkReplace,`$1`);r.state.inLink=!0;let c={type:e[0].charAt(0)===`!`?`image`:`link`,raw:n,href:a,title:o,text:s,tokens:r.inlineTokens(s)};return r.state.inLink=!1,c}function dn(e,t,n){let r=e.match(n.other.indentCodeCompensation);if(r===null)return t;let i=r[1];return t.split(`
4
4
  `).map(e=>{let t=e.match(n.other.beginningSpace);if(t===null)return e;let[r]=t;return r.length>=i.length?e.slice(i.length):e}).join(`
@@ -175,7 +175,7 @@ mark{background:color-mix(in srgb,var(--s2-accent) 25%,transparent);color:inheri
175
175
  </style>
176
176
  <script>${ri}<\/script>
177
177
  </head>
178
- <body class="sprinkle-inline">${t}</body></html>`;if(ni)return si(e,r,n);let i=document.createElement(`iframe`);i.setAttribute(`sandbox`,`allow-scripts allow-same-origin`),i.style.cssText=`width:100%;border:none;overflow:hidden;display:block;`,i.srcdoc=r,e.appendChild(i);let a=e=>{if(e.source!==i.contentWindow)return;let t=e.data;t?.type&&(t.type===`inline-sprinkle-lick`?n(t.action,t.data):t.type===`inline-sprinkle-height`&&(i.style.height=t.height+`px`))};return window.addEventListener(`message`,a),{dispose(){window.removeEventListener(`message`,a),i.remove()}}}function ai(e,t){let n=e.querySelectorAll(`pre > code.language-shtml`);if(n.length===0)return[];let r=[];for(let e of n){let n=e.parentElement,i=e.textContent??``,a=document.createElement(`div`);a.className=`msg__inline-sprinkle`,n.replaceWith(a),r.push(ii(a,i,t))}return r}function oi(e){for(let t of e)try{t.dispose()}catch{}e.length=0}function si(e,t,n){let r=document.createElement(`iframe`);r.src=chrome.runtime.getURL(`sprinkle-sandbox.html`),r.style.cssText=`width:100%;border:none;overflow:hidden;display:block;`,e.appendChild(r);let i=e=>{if(e.source!==r.contentWindow)return;let t=e.data;t?.type&&(t.type===`inline-sprinkle-lick`?n(t.action,t.data):t.type===`inline-sprinkle-height`&&(r.style.height=t.height+`px`))};return window.addEventListener(`message`,i),r.addEventListener(`load`,()=>{r.contentWindow?.postMessage({type:`inline-sprinkle-render`,srcdoc:t},`*`)},{once:!0}),{dispose(){window.removeEventListener(`message`,i),r.remove()}}}var ci=r(`tool-ui-renderer`),li=typeof chrome<`u`&&!!chrome?.runtime?.id,ui=class{container;iframe=null;inlineSprinkle=null;messageHandler=null;requestId;nonce;constructor(e,t){this.container=e,this.requestId=t,this.nonce=crypto.randomUUID()}async render(e){li?await this.renderInSandbox(e):this.renderWithInlineSprinkle(e)}async renderInSandbox(e){let t=document.createElement(`iframe`);t.src=chrome.runtime.getURL(`tool-ui-sandbox.html`),t.style.cssText=`width: 100%; border: none; min-height: 60px;`,this.iframe=t,await new Promise((e,n)=>{let r=setTimeout(()=>{ci.error(`Tool UI iframe load timed out`),t.remove(),this.iframe=null,n(Error(`tool-ui sandbox iframe load timed out`))},5e3);t.addEventListener(`load`,()=>{clearTimeout(r),e()},{once:!0}),t.addEventListener(`error`,()=>{clearTimeout(r),t.remove(),this.iframe=null,n(Error(`tool-ui sandbox iframe failed to load`))},{once:!0}),this.container.appendChild(t)}),this.messageHandler=e=>{if(e.source!==t.contentWindow)return;let n=e.data;if(n?.type){if(n.nonce!==this.nonce){ci.warn(`Tool UI message nonce mismatch`,{expected:this.nonce,received:n.nonce});return}n.type===`tool-ui-action`&&n.id===this.requestId?(ci.info(`Tool UI action received`,{id:n.id,action:n.action}),v.handleAction(n.id,{action:n.action,data:n.data})):n.type===`tool-ui-rendered`&&n.id===this.requestId?n.height&&this.iframe&&(this.iframe.style.height=`${Math.max(60,n.height)}px`):n.type===`tool-ui-resize`&&n.id===this.requestId&&n.height&&this.iframe&&(this.iframe.style.height=`${Math.max(60,n.height)}px`)}},window.addEventListener(`message`,this.messageHandler);let{collectThemeCSS:n}=await y(async()=>{let{collectThemeCSS:e}=await import(`./sprinkle-renderer-Deu5t635.js`);return{collectThemeCSS:e}},[]),r=n();t.contentWindow.postMessage({type:`tool-ui-render`,id:this.requestId,nonce:this.nonce,html:e,themeCSS:r},`*`)}renderWithInlineSprinkle(e){let t=document.createElement(`div`);t.className=`msg__inline-sprinkle`,this.container.appendChild(t),this.inlineSprinkle=ii(t,e,(e,t)=>{ci.info(`Tool UI action (inline sprinkle)`,{id:this.requestId,action:e}),v.handleAction(this.requestId,{action:e,data:t})})}dispose(){this.messageHandler&&=(window.removeEventListener(`message`,this.messageHandler),null),this.iframe&&=(this.iframe.remove(),null),this.inlineSprinkle&&=(this.inlineSprinkle.dispose(),null)}},di=new Map;function fi(e,t,n){let r=di.get(t);r&&r.dispose();let i=new ui(e,t);return di.set(t,i),i.render(n).catch(e=>{ci.error(`Failed to render tool UI`,{requestId:t,error:e.message})}),i}function pi(e){let t=di.get(e);t&&(t.dispose(),di.delete(e))}var mi=r(`chat-panel`);function hi(){return Date.now().toString(36)+Math.random().toString(36).slice(2,8)}var gi={bash:`$`,browser:`B`,read_file:`R`,write_file:`W`,edit_file:`E`,javascript:`JS`,delegate_to_scoop:`D`,send_message:`M`,schedule_task:`T`,list_scoops:`LS`,list_tasks:`LT`,register_scoop:`RS`,update_global_memory:`GM`};function _i(e){return gi[e]??`?`}function vi(e){return e.role===`assistant`?Rr(e.content):Lr(e.content)}var yi=class{container;messagesEl;messagesInner;inputArea;textarea;sendBtn;stopBtn;micBtn;voiceInput=null;voiceMode=!1;keydownListener=null;messages=[];agent=null;unsubscribe=null;isStreaming=!1;currentStreamId=null;sessionStore;sessionId;readOnly=!1;terminalOutputCallback=null;currentScoopName=null;autoScrollAttached=!0;lastScrollTop=0;jumpPill;onDeleteQueuedMessage=null;pendingDeltaText=``;streamingRafId=null;inlineSprinkles=new Map;onInlineSprinkleLick;modelSelectorEl;onModelChange;constructor(e){this.container=e,this.sessionStore=new Wr,this.sessionId=`default`,this.render()}setAgent(e){this.unsubscribe?.(),this.agent=e,this.unsubscribe=e.onEvent(e=>this.handleAgentEvent(e))}onTerminalOutput(e){this.terminalOutputCallback=e}setDeleteQueuedMessageCallback(e){this.onDeleteQueuedMessage=e}async initSession(e){await this.sessionStore.init(),this.sessionId=e??`default`;let t=await this.sessionStore.load(this.sessionId);t&&t.messages.length>0&&(this.messages=t.messages.map(e=>({...e,isStreaming:!1})),this.renderMessages())}async clearSession(){this.messages=[],this.renderMessages(),await this.sessionStore.delete(this.sessionId)}async deleteSessionById(e){await this.sessionStore.delete(e)}async switchToContext(e,t,n){await this.persistSessionAsync(),this.setStreamingState(!1),this.currentStreamId=null,this.cancelPendingDelta(),this.sessionId=e,this.currentScoopName=n??null,this.setReadOnly(t);let r=await this.sessionStore.load(this.sessionId);r&&r.messages.length>0?this.messages=r.messages.map(e=>({...e,isStreaming:!1})):this.messages=[],this.renderMessages()}setReadOnly(e){this.readOnly=e,this.inputArea&&(this.inputArea.style.display=e?`none`:``)}async persistSessionAsync(){try{await this.sessionStore.saveMessages(this.sessionId,this.messages)}catch{}}setProcessing(e){e?this.setStreamingState(!0):this.setStreamingState(!1)}addSystemMessage(e){let t={id:hi(),role:`assistant`,content:e,timestamp:Date.now()};this.messages.push(t),this.appendMessageEl(t),this.persistSession()}addLickMessage(e,t,n){let r={id:e,role:`user`,content:t,timestamp:Date.now(),source:`lick`,channel:n};this.messages.push(r),this.appendMessageEl(r),this.persistSession()}getMessages(){return[...this.messages]}loadMessages(e){this.messages=e.map(e=>({...e,isStreaming:!1})),this.renderMessages(),this.persistSession(),this.renderModelSelector()}clear(){this.messages=[],this.renderMessages(),this.renderModelSelector()}addUserMessage(e){let t={id:hi(),role:`user`,content:e,timestamp:Date.now()};this.messages.push(t),this.appendMessageEl(t)}deleteQueuedMessage(e){let t=this.messages.findIndex(t=>t.id===e);if(t===-1)return;this.messages.splice(t,1);let n=this.messagesEl.querySelector(`[data-msg-id="${e}"]`);n&&n.remove(),this.persistSession(),this.onDeleteQueuedMessage?.(e)}render(){this.container.innerHTML=``,this.container.classList.add(`chat`),this.messagesEl=document.createElement(`div`),this.messagesEl.className=`chat__messages`,this.messagesInner=document.createElement(`div`),this.messagesInner.className=`chat__messages-inner`,this.messagesEl.appendChild(this.messagesInner),this.container.appendChild(this.messagesEl),this.messagesEl.addEventListener(`scroll`,()=>{let{scrollTop:e,scrollHeight:t,clientHeight:n}=this.messagesEl;t-e-n<=250?(this.autoScrollAttached=!0,this.hideJumpPill()):e<this.lastScrollTop&&(this.autoScrollAttached=!1),this.lastScrollTop=e},{passive:!0}),this.inputArea=document.createElement(`div`);let e=this.inputArea;e.className=`chat__input-area`;let t=document.createElement(`div`);t.className=`chat__input-area-inner`,this.textarea=document.createElement(`textarea`),this.textarea.className=`chat__textarea`,this.textarea.placeholder=`What shall we build?`,this.textarea.rows=1,this.sendBtn=document.createElement(`button`),this.sendBtn.className=`chat__send-btn`,this.sendBtn.innerHTML=`<svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor"><path d="M10 1.25C5.167 1.25 1.25 5.167 1.25 10s3.917 8.75 8.75 8.75 8.75-3.918 8.75-8.75S14.833 1.25 10 1.25zm3.527 8.284a.75.75 0 0 1-1.06 0L10.75 7.82v6.172a.75.75 0 0 1-1.5 0V7.812L7.527 9.534a.75.75 0 1 1-1.06-1.06l2.998-2.998a.75.75 0 0 1 1.06-.001l3.002 2.998a.75.75 0 0 1 0 1.061z"/></svg>`,this.sendBtn.dataset.tooltip=`Send message`,this.sendBtn.dataset.tooltipPos=`top`,this.stopBtn=document.createElement(`button`),this.stopBtn.className=`chat__stop-btn`,this.stopBtn.innerHTML=`<svg width="16" height="16" viewBox="0 0 20 20" fill="currentColor"><path d="M13.75 4H6.25A2.25 2.25 0 0 0 4 6.25v7.5A2.25 2.25 0 0 0 6.25 16h7.5A2.25 2.25 0 0 0 16 13.75v-7.5A2.25 2.25 0 0 0 13.75 4z"/></svg>`,this.stopBtn.dataset.tooltip=`Stop generation`,this.stopBtn.style.display=`none`,this.micBtn=document.createElement(`button`),this.micBtn.className=`chat__mic-btn`;let n=`http://www.w3.org/2000/svg`,r=document.createElementNS(n,`svg`);r.setAttribute(`width`,`16`),r.setAttribute(`height`,`16`),r.setAttribute(`viewBox`,`0 0 24 24`),r.setAttribute(`fill`,`none`),r.setAttribute(`stroke`,`currentColor`),r.setAttribute(`stroke-width`,`2`),r.setAttribute(`stroke-linecap`,`round`),r.setAttribute(`stroke-linejoin`,`round`);let i=document.createElementNS(n,`path`);i.setAttribute(`d`,`M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z`);let a=document.createElementNS(n,`path`);a.setAttribute(`d`,`M19 10v2a7 7 0 0 1-14 0v-2`);let o=document.createElementNS(n,`line`);o.setAttribute(`x1`,`12`),o.setAttribute(`y1`,`19`),o.setAttribute(`x2`,`12`),o.setAttribute(`y2`,`23`);let s=document.createElementNS(n,`line`);s.setAttribute(`x1`,`8`),s.setAttribute(`y1`,`23`),s.setAttribute(`x2`,`16`),s.setAttribute(`y2`,`23`),r.append(i,a,o,s),this.micBtn.appendChild(r),this.micBtn.dataset.tooltip=`Voice (Ctrl+Shift+V)`;let c=document.createElement(`div`);c.className=`chat__input-wrapper`,c.appendChild(this.textarea);let l=document.createElement(`div`);l.className=`chat__action-bar`;let u=document.createElement(`div`);u.className=`chat__action-bar-left`,u.appendChild(this.micBtn),l.appendChild(u),this.modelSelectorEl=document.createElement(`div`),this.modelSelectorEl.className=`chat__model-selector`,this.renderModelSelector(),l.appendChild(this.modelSelectorEl);let d=document.createElement(`div`);d.className=`chat__action-bar-right`,d.appendChild(this.sendBtn),d.appendChild(this.stopBtn),l.appendChild(d),c.appendChild(l),t.appendChild(c),e.appendChild(t),this.container.appendChild(e),this.jumpPill=document.createElement(`button`),this.jumpPill.className=`chat__jump-pill`,this.jumpPill.textContent=`↓ New activity`,this.jumpPill.addEventListener(`click`,()=>{this.autoScrollAttached=!0,this.hideJumpPill(),this.scrollToBottom(!0)}),this.container.appendChild(this.jumpPill),this.textarea.addEventListener(`keydown`,e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),this.sendMessage())}),this.textarea.addEventListener(`input`,()=>{this.textarea.style.height=`auto`,this.textarea.style.height=Math.min(this.textarea.scrollHeight,120)+`px`}),this.sendBtn.addEventListener(`click`,()=>this.sendMessage()),this.stopBtn.addEventListener(`click`,()=>{this.agent?.stop();for(let e of this.messages)e.queued&&(e.queued=!1,this.updateMessageEl(e.id));this.setStreamingState(!1)}),this.voiceInput=new Jr({onTranscript:(e,t)=>{this.textarea.value=e,this.textarea.style.height=`auto`,this.textarea.style.height=Math.min(this.textarea.scrollHeight,120)+`px`},onStateChange:e=>{e===`error`?(this.voiceMode=!1,this.micBtn.classList.remove(`chat__mic-btn--active`,`chat__mic-btn--listening`)):this.voiceMode?e===`listening`&&this.micBtn.classList.add(`chat__mic-btn--listening`):this.micBtn.classList.toggle(`chat__mic-btn--listening`,e===`listening`)},onError:e=>{mi.debug(`Voice input error`,{error:e}),!(this.voiceMode&&e.includes(`No speech detected`))&&this.addSystemMessage(e)},autoSend:!0,onAutoSend:e=>{this.textarea.value=e,this.sendMessage()},onAutoDisable:()=>{this.voiceMode=!1,this.micBtn.classList.remove(`chat__mic-btn--active`,`chat__mic-btn--listening`),this.addSystemMessage(`Voice mode disabled after 2 minutes of inactivity.`)},lang:Xr()}),this.micBtn.addEventListener(`click`,()=>{this.toggleVoiceMode()}),this.keydownListener=e=>{e.shiftKey&&(e.ctrlKey||e.metaKey)&&e.key===`V`&&(e.preventDefault(),this.toggleVoiceMode())},document.addEventListener(`keydown`,this.keydownListener)}toggleVoiceMode(){this.voiceMode=!this.voiceMode,this.micBtn.classList.toggle(`chat__mic-btn--active`,this.voiceMode),this.voiceMode?this.voiceInput?.start():this.voiceInput?.stop()}sendMessage(){let e=this.textarea.value.trim();if(!e)return;this.autoScrollAttached=!0,this.hideJumpPill();let t=this.isStreaming,n={id:hi(),role:`user`,content:e,timestamp:Date.now(),queued:t||void 0};this.messages.push(n),this.appendMessageEl(n),this.persistSession(),this.textarea.value=``,this.textarea.style.height=`auto`,this.isStreaming||this.setStreamingState(!0),this.agent?.sendMessage(e,n.id)}handleAgentEvent(e){switch(mi.debug(`Agent event`,{type:e.type}),e.type){case`message_start`:this.handleMessageStart(e.messageId);break;case`content_delta`:this.handleContentDelta(e.messageId,e.text);break;case`content_done`:this.handleContentDone(e.messageId);break;case`tool_use_start`:this.handleToolUseStart(e.messageId,e.toolName,e.toolInput);break;case`tool_result`:this.handleToolResult(e.messageId,e.toolName,e.result,e.isError);break;case`tool_ui`:this.handleToolUI(e.messageId,e.toolName,e.requestId,e.html);break;case`tool_ui_done`:this.handleToolUIDone(e.messageId,e.requestId);break;case`turn_end`:this.handleTurnEnd(e.messageId);break;case`error`:this.handleError(e.error);break;case`screenshot`:break;case`terminal_output`:this.terminalOutputCallback?.(e.text);break}}handleMessageStart(e){this.setStreamingState(!0),this.currentStreamId=e;let t={id:e,role:`assistant`,content:``,timestamp:Date.now(),isStreaming:!0,toolCalls:[]};this.messages.push(t),this.appendMessageEl(t)}handleContentDelta(e,t){this.findMessage(e)&&(this.pendingDeltaText+=t,this.streamingRafId===null&&(this.streamingRafId=requestAnimationFrame(()=>this.flushPendingDelta())))}handleContentDone(e){if(this.pendingDeltaText&&this.currentStreamId===e){let t=this.findMessage(e);t&&(t.content+=this.pendingDeltaText)}this.cancelPendingDelta();let t=this.findMessage(e);t&&(t.isStreaming=!1,this.updateMessageEl(e))}handleToolUseStart(e,t,n){let r=this.findMessage(e);r&&(r.toolCalls||=[],r.toolCalls.push({id:hi(),name:t,input:n}),this.updateMessageEl(e))}handleToolResult(e,t,n,r){let i=this.findMessage(e);if(!i||!i.toolCalls)return;let a=[...i.toolCalls].reverse().find(e=>e.name===t&&e.result===void 0);if(a){let e=n.match(/<img:(data:image\/[^>]+)>/);a.result=n.replace(/<img:data:image\/[^>]+>/g,``).trim(),e&&(a._screenshotDataUrl=e[1]),a.isError=r}this.updateMessageEl(e)}handleToolUI(e,t,n,r,i=0){let a=this.findMessage(e);if(!a||!a.toolCalls){if(i<10){setTimeout(()=>this.handleToolUI(e,t,n,r,i+1),100);return}mi.warn(`handleToolUI: message or toolCalls not found after retries`,{messageId:e});return}let o=[...a.toolCalls].reverse().find(e=>e.name===t&&e.result===void 0);if(!o){mi.warn(`handleToolUI: no matching tool call found`,{messageId:e,toolName:t});return}o._toolUIRequestId=n;let s=this.messagesEl.querySelector(`[data-msg-id="${e}"]`);if(!s){if(i<10){setTimeout(()=>this.handleToolUI(e,t,n,r,i+1),100);return}mi.warn(`handleToolUI: wrapper element not found after retries`,{messageId:e});return}let c=[...s.querySelectorAll(`.tool-call`)].reverse().find(e=>e.querySelector(`.tool-call__name`)?.textContent===t);if(c){c instanceof HTMLDetailsElement&&(c.open=!0);let e=c.querySelector(`.tool-call__ui`);e||(e=document.createElement(`div`),e.className=`tool-call__ui`,c.appendChild(e)),fi(e,n,r)}else i<10?setTimeout(()=>this.handleToolUI(e,t,n,r,i+1),100):mi.warn(`handleToolUI: tool call element not found in DOM after retries`,{toolName:t})}handleToolUIDone(e,t){pi(t)}handleTurnEnd(e){this.setStreamingState(!1),this.currentStreamId=null,this.persistSession()}handleError(e){this.setStreamingState(!1),this.currentStreamId=null;let t=this.messages[this.messages.length-1];if(t?.role===`assistant`&&t.isStreaming)t.isStreaming=!1,t.content+=`\n\n**Error:** ${e}`,this.updateMessageEl(t.id);else{let t={id:hi(),role:`assistant`,content:`**Error:** ${e}`,timestamp:Date.now()};this.messages.push(t),this.appendMessageEl(t)}this.persistSession()}setStreamingState(e){this.isStreaming=e;try{this.renderModelSelector()}catch{}if(this.stopBtn.style.display=e?`flex`:`none`,this.sendBtn.style.display=e?`none`:`flex`,this.textarea.disabled=!1,e){this.voiceInput?.isListening()&&this.voiceInput.stop(),this.micBtn.classList.remove(`chat__mic-btn--listening`);let e=this.messages.find(e=>e.queued);e&&(e.queued=!1,this.updateMessageEl(e.id))}e||(this.voiceMode?(this.micBtn.classList.add(`chat__mic-btn--listening`),this.voiceInput?.start()):this.textarea.focus())}renderModelSelector(){let e=this.modelSelectorEl;if(!e)return;for(;e.firstChild;)e.removeChild(e.firstChild);let t=ie(),n=O(),r=D(),i=[];for(let e of t)for(let t of e.models)i.push({providerId:e.providerId,id:t.id,name:t.name,reasoning:t.reasoning});i.sort((e,t)=>e.reasoning===t.reasoning?e.name.localeCompare(t.name):e.reasoning?-1:1);let a=i.find(e=>e.id===n&&e.providerId===r)||i[0];if(!a)return;let o=this.isStreaming,s=document.createElement(`button`);if(s.className=`chat__model-btn chat__model-btn--compact`,o&&s.classList.add(`chat__model-btn--disabled`),s.textContent=a.name,!o){let e=document.createElement(`span`);e.className=`chat__model-chevron`,e.innerHTML=`<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor"><path d="M4.5 6l3.5 4 3.5-4z"/></svg>`,s.appendChild(e)}if(o)e.appendChild(s);else{let t=!1,a=document.createElement(`div`);a.className=`chat__model-menu`;let o=()=>{for(a.style.display=t?`block`:`none`;a.firstChild;)a.removeChild(a.firstChild);if(t)for(let e of i){let i=document.createElement(`div`);i.className=`chat__model-menu-item`;let o=e.id===n&&e.providerId===r;o&&i.classList.add(`chat__model-menu-item--active`);let s=document.createElement(`span`);if(s.textContent=e.name,i.appendChild(s),o){let e=document.createElement(`span`);e.className=`chat__model-check`,e.innerHTML=`<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor"><path d="M6.5 12.5l-4-4 1.4-1.4 2.6 2.6 5.6-5.6 1.4 1.4z"/></svg>`,i.appendChild(e)}i.addEventListener(`click`,()=>{let n=`${e.providerId}:${e.id}`;oe(n),this.onModelChange?.(n),t=!1,this.renderModelSelector()}),a.appendChild(i)}};s.addEventListener(`click`,e=>{e.stopPropagation(),t=!t,o()}),document.addEventListener(`click`,()=>{t=!1,o()},{once:!0}),e.appendChild(s),e.appendChild(a),o()}}refreshModelSelector(){this.renderModelSelector()}findMessage(e){return this.messages.find(t=>t.id===e)}flushPendingDelta(){if(this.streamingRafId=null,!this.pendingDeltaText||!this.currentStreamId)return;let e=this.findMessage(this.currentStreamId);if(!e){this.pendingDeltaText=``;return}e.content+=this.pendingDeltaText,this.pendingDeltaText=``,this.updateStreamingContent(this.currentStreamId)}cancelPendingDelta(){this.streamingRafId!==null&&(cancelAnimationFrame(this.streamingRafId),this.streamingRafId=null),this.pendingDeltaText=``}updateStreamingContent(e){let t=this.findMessage(e);if(!t)return;let n=this.messagesEl.querySelector(`[data-msg-id="${e}"]`);if(!n)return;let r=n.querySelector(`.msg__content`);if(r){if(r.innerHTML=vi(t),t.isStreaming){let e=document.createElement(`span`);e.className=`streaming-cursor`,r.appendChild(e)}}else if(t.content.trim().length>0){this.updateMessageEl(e);return}this.scrollToBottom()}renderMessages(){this.disposeAllInlineSprinkles(),this.messagesInner.innerHTML=``;let e=null,t=0,n=-1;for(let e=this.messages.length-1;e>=0;e--)if(this.messages[e].role===`assistant`){n=e;break}for(let r=0;r<this.messages.length;r++){let i=this.messages[r],a=this.shouldShowLabel(i,e,t),o=this.createMessageEl(i,a,r===n);this.messagesInner.appendChild(o),e=i.role,t=i.timestamp}this.autoScrollAttached=!0,this.hideJumpPill(),this.scrollToBottom(!0)}appendMessageEl(e){let t=this.messagesInner.querySelector(`.msg__feedback`);t&&t.remove();let n=this.messages.length>=2?this.messages[this.messages.length-2]:null,r=this.shouldShowLabel(e,n?.role??null,n?.timestamp??0),i=e.role===`assistant`,a=this.createMessageEl(e,r,i);this.messagesInner.appendChild(a),this.scrollToBottom()}shouldShowLabel(e,t,n){return e.source===`lick`||e.channel===`webhook`||e.channel===`cron`||e.role!==t||e.timestamp-n>12e4}updateMessageEl(e){let t=this.findMessage(e);if(!t)return;let n=this.messagesEl.querySelector(`[data-msg-id="${e}"]`);if(n){this.disposeInlineSprinklesForMessage(e);let r=this.messages.indexOf(t),i=r>0?this.messages[r-1]:null,a=this.shouldShowLabel(t,i?.role??null,i?.timestamp??0),o=!1;if(t.role===`assistant`){let e=-1;for(let t=this.messages.length-1;t>=0;t--)if(this.messages[t].role===`assistant`){e=t;break}o=r===e}let s=this.createMessageEl(t,a,o);n.replaceWith(s)}this.scrollToBottom()}createMessageEl(e,t=!0,n=!1){if(e.source===`lick`||e.channel===`webhook`||e.channel===`cron`){let t=document.createElement(`div`);return t.className=`msg-group`,t.setAttribute(`data-msg-id`,e.id),t.appendChild(this.createLickEl(e)),t}let r=document.createElement(`div`);r.className=`msg-group${t?``:` msg-group--continuation`}`,r.setAttribute(`data-msg-id`,e.id);let i=document.createElement(`div`);if(i.className=`msg msg--${e.role}${e.queued?` msg--queued`:``}`,t){let t,n,r=this.currentScoopName!==null;e.role===`user`?e.source===`delegation`||e.channel===`delegation`?(t=`S`,n=`sliccy`):(t=`U`,n=`You`):r?(t=(this.currentScoopName||`S`).charAt(0).toUpperCase(),n=`@${this.currentScoopName}`):e.source&&e.source!==`cone`?(t=e.source.charAt(0).toUpperCase(),n=e.source):(t=`S`,n=`sliccy`);let a=document.createElement(`div`);a.className=`msg__role`;let o=document.createElement(`span`);if(o.className=`msg__icon`,o.textContent=t,a.appendChild(o),a.appendChild(document.createTextNode(` ${n}`)),e.queued){let t=document.createElement(`span`);t.className=`msg__queued-badge`,t.textContent=`queued`,a.appendChild(t);let n=document.createElement(`button`);n.className=`msg__queued-delete`,n.textContent=`×`,n.title=`Remove queued message`,n.addEventListener(`click`,t=>{t.stopPropagation(),this.deleteQueuedMessage(e.id)}),a.appendChild(n)}i.appendChild(a)}let a=(e.source===`lick`||e.channel===`webhook`||e.channel===`cron`)&&this.sessionId===`session-cone`,o=e.source&&e.source!==`cone`&&e.source!==`lick`&&e.role===`assistant`&&this.sessionId===`session-cone`;if(a||o){let t=document.createElement(`details`);t.className=`msg__collapsible`;let n=document.createElement(`summary`);n.className=`msg__summary`,n.textContent=e.content.slice(0,60).replace(/\n/g,` `)+(e.content.length>60?`...`:``),t.appendChild(n);let r=document.createElement(`div`);r.className=`msg__content`,r.innerHTML=vi(e),e.isStreaming||this.hydrateInlineSprinklesInEl(r,e.id),t.appendChild(r),i.appendChild(t)}else{let t=document.createElement(`div`);if(t.className=`msg__content`,t.innerHTML=vi(e),e.isStreaming){let e=document.createElement(`span`);e.className=`streaming-cursor`,t.appendChild(e)}else this.hydrateInlineSprinklesInEl(t,e.id);i.appendChild(t)}let s=e.content.trim().length>0;if(s&&r.appendChild(i),e.toolCalls)for(let t of e.toolCalls)r.appendChild(this.createToolCallEl(t));return e.role===`assistant`&&!e.isStreaming&&!e.queued&&s&&n&&r.appendChild(this.createFeedbackRow()),r}createFeedbackRow(){let e=document.createElement(`div`);e.className=`msg__feedback`;let t=document.createElement(`button`);return t.className=`msg__feedback-btn`,t.dataset.tooltip=`Copy chat`,t.setAttribute(`aria-label`,`Copy chat`),t.innerHTML=`<svg width="16" height="16" viewBox="0 0 20 20" fill="currentColor"><path d="m11.75,18h-7.5c-1.24,0-2.25-1.01-2.25-2.25v-7.5c0-1.24,1.01-2.25,2.25-2.25.41,0,.75.34.75.75s-.34.75-.75.75c-.41,0-.75.34-.75.75v7.5c0,.41.34.75.75.75h7.5c.41,0,.75-.34.75-.75,0-.41.34-.75.75-.75s.75.34.75.75c0,1.24-1.01,2.25-2.25,2.25Z"/><path d="m6.75,5c-.41,0-.75-.34-.75-.75,0-1.24,1.01-2.25,2.25-2.25.41,0,.75.34.75.75s-.34.75-.75.75c-.41,0-.75.34-.75.75,0,.41-.34.75-.75.75Z"/><path d="m13,3.5h-2c-.41,0-.75-.34-.75-.75s.34-.75.75-.75h2c.41,0,.75.34.75.75s-.34.75-.75.75Z"/><path d="m13,14h-2c-.41,0-.75-.34-.75-.75s.34-.75.75-.75h2c.41,0,.75.34.75.75s-.34.75-.75.75Z"/><path d="m15.75,14c-.41,0-.75-.34-.75-.75s.34-.75.75-.75c.41,0,.75-.34.75-.75,0-.41.34-.75.75-.75s.75.34.75.75c0,1.24-1.01,2.25-2.25,2.25Z"/><path d="m17.25,5c-.41,0-.75-.34-.75-.75,0-.41-.34-.75-.75-.75-.41,0-.75-.34-.75-.75s.34-.75.75-.75c1.24,0,2.25,1.01,2.25,2.25,0,.41-.34.75-.75.75Z"/><path d="m17.25,9.75c-.41,0-.75-.34-.75-.75v-2c0-.41.34-.75.75-.75s.75.34.75.75v2c0,.41-.34.75-.75.75Z"/><path d="m6.75,9.75c-.41,0-.75-.34-.75-.75v-2c0-.41.34-.75.75-.75s.75.34.75.75v2c0,.41-.34.75-.75.75Z"/><path d="m8.25,14c-1.24,0-2.25-1.01-2.25-2.25,0-.41.34-.75.75-.75s.75.34.75.75c0,.41.34.75.75.75.41,0,.75.34.75.75s-.34.75-.75.75Z"/></svg>`,t.addEventListener(`click`,async()=>{let e=this.getMessages(),n=``;for(let t of e){let e=t.role===`user`?`User`:`Assistant`;if(n+=`## ${e}\n${t.content}\n\n`,t.toolCalls)for(let e of t.toolCalls)n+=`### Tool: ${e.name}\nInput: ${JSON.stringify(e.input,null,2)}\nResult: ${e.result??``}\n\n`}await navigator.clipboard.writeText(n),t.style.color=`var(--s2-positive)`,setTimeout(()=>{t.style.color=``},1500)}),e.appendChild(t),e}createLickEl(e){let t=document.createElement(`details`);t.className=`lick`;let n=e.channel===`webhook`?`Webhook`:e.channel===`cron`?`Cron`:`Event`,r=document.createElement(`summary`);r.className=`lick__header`,r.innerHTML=`<span class="lick__icon">E</span> <span class="lick__type">${n}</span>`;let i=document.createElement(`span`);i.className=`lick__preview`;let a=e.content.replace(/\[Webhook Event:.*?\]\n```json\n?/s,``).slice(0,50);i.textContent=a.replace(/\n/g,` `)+(a.length>=50?`...`:``),r.appendChild(i),t.appendChild(r);let o=document.createElement(`div`);return o.className=`lick__details`,o.innerHTML=Lr(e.content),t.appendChild(o),t}createToolCallEl(e){_i(e.name);let t=document.createElement(`details`);t.className=`tool-call`;let n=document.createElement(`summary`);if(n.className=`tool-call__header`,n.innerHTML=`<span class="tool-call__icon"><svg width="10" height="10" viewBox="0 0 10 10" fill="currentColor"><path d="M2 3.5L5 6.5L8 3.5" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg></span> <span class="tool-call__name">${Tr(e.name)}</span>`,e.input!==void 0){let t=document.createElement(`span`);t.className=`tool-call__preview`;let r=typeof e.input==`string`?e.input:JSON.stringify(e.input);t.textContent=r.slice(0,40)+(r.length>40?`...`:``),n.appendChild(t)}let r=document.createElement(`span`);e.result===void 0?r.className=`tool-call__status tool-call__status--running`:e.isError?(r.className=`tool-call__status tool-call__status--error`,r.textContent=`failed`):(r.className=`tool-call__status tool-call__status--success`,r.textContent=`✓`),n.appendChild(r),t.appendChild(n);let i=document.createElement(`div`);if(i.className=`tool-call__details`,e.input!==void 0){let t=document.createElement(`div`);t.className=`tool-call__input`;let n=document.createElement(`div`);n.className=`tool-call__label`,n.textContent=`Input:`,t.appendChild(n);let r=document.createElement(`pre`);r.innerHTML=zr(e.input),t.appendChild(r),i.appendChild(t)}if(e.result!==void 0){let t=document.createElement(`div`);t.className=`tool-call__result${e.isError?` tool-call__result--error`:``}`;let n=document.createElement(`div`);n.className=`tool-call__label`,n.textContent=e.isError?`Error:`:`Result:`,t.appendChild(n);let r=document.createElement(`pre`);r.textContent=e.result,t.appendChild(r),i.appendChild(t)}let a=e._screenshotDataUrl;if(a){let e=document.createElement(`img`);e.src=a,e.className=`tool-call__screenshot`,e.title=`Click to view full size`,e.addEventListener(`click`,e=>{e.stopPropagation();let t=window.open(`about:blank`);if(t){let e=t.document.createElement(`img`);e.src=a,t.document.title=`Screenshot`,t.document.body.style.margin=`0`,t.document.body.style.background=document.documentElement.classList.contains(`theme-light`)?`#f0f0f0`:`#141414`,t.document.body.appendChild(e)}}),i.appendChild(e)}return t.appendChild(i),t}scrollToBottom(e=!1){if(!e&&!this.autoScrollAttached){this.showJumpPill();return}requestAnimationFrame(()=>{this.messagesEl.scrollTop=this.messagesEl.scrollHeight,this.lastScrollTop=this.messagesEl.scrollTop})}showJumpPill(){this.jumpPill.classList.add(`chat__jump-pill--visible`)}hideJumpPill(){this.jumpPill.classList.remove(`chat__jump-pill--visible`)}persistSession(){this.sessionStore.saveMessages(this.sessionId,this.messages).catch(()=>{})}disposeInlineSprinklesForMessage(e){let t=this.inlineSprinkles.get(e);t&&(oi(t),this.inlineSprinkles.delete(e))}disposeAllInlineSprinkles(){for(let[,e]of this.inlineSprinkles)oi(e);this.inlineSprinkles.clear()}hydrateInlineSprinklesInEl(e,t){let n=ai(e,(e,t)=>this.onInlineSprinkleLick?.(e,t));n.length&&this.inlineSprinkles.set(t,n)}dispose(){this.cancelPendingDelta(),this.disposeAllInlineSprinkles(),this.unsubscribe?.(),this.voiceInput?.destroy(),this.keydownListener&&=(document.removeEventListener(`keydown`,this.keydownListener),null),this.container.innerHTML=``}},bi=class{container;terminalViewEl;previewViewEl;previewEmptyEl;previewBtn;shell=null;activeView=`terminal`;onClearTerminal;constructor(e,t={}){this.container=e,this.onClearTerminal=t.onClearTerminal??null,this.render()}async mountShell(e){this.shell?.setPreviewStateListener(null),this.shell=e;let t=document.createElement(`div`);t.className=`terminal-panel__mount`,this.terminalViewEl.appendChild(t),await e.mount(t);let n=t.querySelector(`.terminal-panel__terminal-host`),r=t.querySelector(`.terminal-panel__preview`);if(!n||!r)throw Error(`terminal mount did not create expected hosts`);this.terminalViewEl.replaceChildren(n),this.previewViewEl.replaceChildren(this.previewEmptyEl),this.previewViewEl.appendChild(r),e.setPreviewStateListener(e=>this.handlePreviewStateChange(e))}clearTerminal(){this.shell?.clearTerminal()}async runCommand(e){return this.shell?(/^\s*imgcat(?:\s|$)/.test(e)||this.setActiveView(`terminal`),this.shell.executeCommandInTerminal(e)):{stdout:``,stderr:`terminal is unavailable
178
+ <body class="sprinkle-inline">${t}</body></html>`;if(ni)return si(e,r,n);let i=document.createElement(`iframe`);i.setAttribute(`sandbox`,`allow-scripts allow-same-origin`),i.style.cssText=`width:100%;border:none;overflow:hidden;display:block;`,i.srcdoc=r,e.appendChild(i);let a=e=>{if(e.source!==i.contentWindow)return;let t=e.data;t?.type&&(t.type===`inline-sprinkle-lick`?n(t.action,t.data):t.type===`inline-sprinkle-height`&&(i.style.height=t.height+`px`))};return window.addEventListener(`message`,a),{dispose(){window.removeEventListener(`message`,a),i.remove()}}}function ai(e,t){let n=e.querySelectorAll(`pre > code.language-shtml`);if(n.length===0)return[];let r=[];for(let e of n){let n=e.parentElement,i=e.textContent??``,a=document.createElement(`div`);a.className=`msg__inline-sprinkle`,n.replaceWith(a),r.push(ii(a,i,t))}return r}function oi(e){for(let t of e)try{t.dispose()}catch{}e.length=0}function si(e,t,n){let r=document.createElement(`iframe`);r.src=chrome.runtime.getURL(`sprinkle-sandbox.html`),r.style.cssText=`width:100%;border:none;overflow:hidden;display:block;`,e.appendChild(r);let i=e=>{if(e.source!==r.contentWindow)return;let t=e.data;t?.type&&(t.type===`inline-sprinkle-lick`?n(t.action,t.data):t.type===`inline-sprinkle-height`&&(r.style.height=t.height+`px`))};return window.addEventListener(`message`,i),r.addEventListener(`load`,()=>{r.contentWindow?.postMessage({type:`inline-sprinkle-render`,srcdoc:t},`*`)},{once:!0}),{dispose(){window.removeEventListener(`message`,i),r.remove()}}}var ci=r(`tool-ui-renderer`),li=typeof chrome<`u`&&!!chrome?.runtime?.id,ui=class{container;iframe=null;inlineSprinkle=null;messageHandler=null;requestId;nonce;constructor(e,t){this.container=e,this.requestId=t,this.nonce=crypto.randomUUID()}async render(e){li?await this.renderInSandbox(e):this.renderWithInlineSprinkle(e)}async renderInSandbox(e){let t=document.createElement(`iframe`);t.src=chrome.runtime.getURL(`tool-ui-sandbox.html`),t.style.cssText=`width: 100%; border: none; min-height: 60px;`,this.iframe=t,await new Promise((e,n)=>{let r=setTimeout(()=>{ci.error(`Tool UI iframe load timed out`),t.remove(),this.iframe=null,n(Error(`tool-ui sandbox iframe load timed out`))},5e3);t.addEventListener(`load`,()=>{clearTimeout(r),e()},{once:!0}),t.addEventListener(`error`,()=>{clearTimeout(r),t.remove(),this.iframe=null,n(Error(`tool-ui sandbox iframe failed to load`))},{once:!0}),this.container.appendChild(t)}),this.messageHandler=e=>{if(e.source!==t.contentWindow)return;let n=e.data;if(n?.type){if(n.nonce!==this.nonce){ci.warn(`Tool UI message nonce mismatch`,{expected:this.nonce,received:n.nonce});return}n.type===`tool-ui-action`&&n.id===this.requestId?(ci.info(`Tool UI action received`,{id:n.id,action:n.action}),v.handleAction(n.id,{action:n.action,data:n.data})):n.type===`tool-ui-rendered`&&n.id===this.requestId?n.height&&this.iframe&&(this.iframe.style.height=`${Math.max(60,n.height)}px`):n.type===`tool-ui-resize`&&n.id===this.requestId&&n.height&&this.iframe&&(this.iframe.style.height=`${Math.max(60,n.height)}px`)}},window.addEventListener(`message`,this.messageHandler);let{collectThemeCSS:n}=await y(async()=>{let{collectThemeCSS:e}=await import(`./sprinkle-renderer-Cg5i8nNh.js`);return{collectThemeCSS:e}},[]),r=n();t.contentWindow.postMessage({type:`tool-ui-render`,id:this.requestId,nonce:this.nonce,html:e,themeCSS:r},`*`)}renderWithInlineSprinkle(e){let t=document.createElement(`div`);t.className=`msg__inline-sprinkle`,this.container.appendChild(t),this.inlineSprinkle=ii(t,e,(e,t)=>{ci.info(`Tool UI action (inline sprinkle)`,{id:this.requestId,action:e}),v.handleAction(this.requestId,{action:e,data:t})})}dispose(){this.messageHandler&&=(window.removeEventListener(`message`,this.messageHandler),null),this.iframe&&=(this.iframe.remove(),null),this.inlineSprinkle&&=(this.inlineSprinkle.dispose(),null)}},di=new Map;function fi(e,t,n){let r=di.get(t);r&&r.dispose();let i=new ui(e,t);return di.set(t,i),i.render(n).catch(e=>{ci.error(`Failed to render tool UI`,{requestId:t,error:e.message})}),i}function pi(e){let t=di.get(e);t&&(t.dispose(),di.delete(e))}var mi=r(`chat-panel`);function hi(){return Date.now().toString(36)+Math.random().toString(36).slice(2,8)}var gi={bash:`$`,browser:`B`,read_file:`R`,write_file:`W`,edit_file:`E`,javascript:`JS`,delegate_to_scoop:`D`,send_message:`M`,schedule_task:`T`,list_scoops:`LS`,list_tasks:`LT`,register_scoop:`RS`,update_global_memory:`GM`};function _i(e){return gi[e]??`?`}function vi(e){return e.role===`assistant`?Rr(e.content):Lr(e.content)}var yi=class{container;messagesEl;messagesInner;inputArea;textarea;sendBtn;stopBtn;micBtn;voiceInput=null;voiceMode=!1;keydownListener=null;messages=[];agent=null;unsubscribe=null;isStreaming=!1;currentStreamId=null;sessionStore;sessionId;readOnly=!1;terminalOutputCallback=null;currentScoopName=null;autoScrollAttached=!0;lastScrollTop=0;jumpPill;onDeleteQueuedMessage=null;pendingDeltaText=``;streamingRafId=null;inlineSprinkles=new Map;onInlineSprinkleLick;modelSelectorEl;onModelChange;constructor(e){this.container=e,this.sessionStore=new Wr,this.sessionId=`default`,this.render()}setAgent(e){this.unsubscribe?.(),this.agent=e,this.unsubscribe=e.onEvent(e=>this.handleAgentEvent(e))}onTerminalOutput(e){this.terminalOutputCallback=e}setDeleteQueuedMessageCallback(e){this.onDeleteQueuedMessage=e}async initSession(e){await this.sessionStore.init(),this.sessionId=e??`default`;let t=await this.sessionStore.load(this.sessionId);t&&t.messages.length>0&&(this.messages=t.messages.map(e=>({...e,isStreaming:!1})),this.renderMessages())}async clearSession(){this.messages=[],this.renderMessages(),await this.sessionStore.delete(this.sessionId)}async deleteSessionById(e){await this.sessionStore.delete(e)}async switchToContext(e,t,n){await this.persistSessionAsync(),this.setStreamingState(!1),this.currentStreamId=null,this.cancelPendingDelta(),this.sessionId=e,this.currentScoopName=n??null,this.setReadOnly(t);let r=await this.sessionStore.load(this.sessionId);r&&r.messages.length>0?this.messages=r.messages.map(e=>({...e,isStreaming:!1})):this.messages=[],this.renderMessages()}setReadOnly(e){this.readOnly=e,this.inputArea&&(this.inputArea.style.display=e?`none`:``)}async persistSessionAsync(){try{await this.sessionStore.saveMessages(this.sessionId,this.messages)}catch{}}setProcessing(e){e?this.setStreamingState(!0):this.setStreamingState(!1)}addSystemMessage(e){let t={id:hi(),role:`assistant`,content:e,timestamp:Date.now()};this.messages.push(t),this.appendMessageEl(t),this.persistSession()}addLickMessage(e,t,n){let r={id:e,role:`user`,content:t,timestamp:Date.now(),source:`lick`,channel:n};this.messages.push(r),this.appendMessageEl(r),this.persistSession()}getMessages(){return[...this.messages]}loadMessages(e){this.messages=e.map(e=>({...e,isStreaming:!1})),this.renderMessages(),this.persistSession(),this.renderModelSelector()}clear(){this.messages=[],this.renderMessages(),this.renderModelSelector()}addUserMessage(e){let t={id:hi(),role:`user`,content:e,timestamp:Date.now()};this.messages.push(t),this.appendMessageEl(t)}deleteQueuedMessage(e){let t=this.messages.findIndex(t=>t.id===e);if(t===-1)return;this.messages.splice(t,1);let n=this.messagesEl.querySelector(`[data-msg-id="${e}"]`);n&&n.remove(),this.persistSession(),this.onDeleteQueuedMessage?.(e)}render(){this.container.innerHTML=``,this.container.classList.add(`chat`),this.messagesEl=document.createElement(`div`),this.messagesEl.className=`chat__messages`,this.messagesInner=document.createElement(`div`),this.messagesInner.className=`chat__messages-inner`,this.messagesEl.appendChild(this.messagesInner),this.container.appendChild(this.messagesEl),this.messagesEl.addEventListener(`scroll`,()=>{let{scrollTop:e,scrollHeight:t,clientHeight:n}=this.messagesEl;t-e-n<=250?(this.autoScrollAttached=!0,this.hideJumpPill()):e<this.lastScrollTop&&(this.autoScrollAttached=!1),this.lastScrollTop=e},{passive:!0}),this.inputArea=document.createElement(`div`);let e=this.inputArea;e.className=`chat__input-area`;let t=document.createElement(`div`);t.className=`chat__input-area-inner`,this.textarea=document.createElement(`textarea`),this.textarea.className=`chat__textarea`,this.textarea.placeholder=`What shall we build?`,this.textarea.rows=1,this.sendBtn=document.createElement(`button`),this.sendBtn.className=`chat__send-btn`,this.sendBtn.innerHTML=`<svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor"><path d="M10 1.25C5.167 1.25 1.25 5.167 1.25 10s3.917 8.75 8.75 8.75 8.75-3.918 8.75-8.75S14.833 1.25 10 1.25zm3.527 8.284a.75.75 0 0 1-1.06 0L10.75 7.82v6.172a.75.75 0 0 1-1.5 0V7.812L7.527 9.534a.75.75 0 1 1-1.06-1.06l2.998-2.998a.75.75 0 0 1 1.06-.001l3.002 2.998a.75.75 0 0 1 0 1.061z"/></svg>`,this.sendBtn.dataset.tooltip=`Send message`,this.sendBtn.dataset.tooltipPos=`top`,this.stopBtn=document.createElement(`button`),this.stopBtn.className=`chat__stop-btn`,this.stopBtn.innerHTML=`<svg width="16" height="16" viewBox="0 0 20 20" fill="currentColor"><path d="M13.75 4H6.25A2.25 2.25 0 0 0 4 6.25v7.5A2.25 2.25 0 0 0 6.25 16h7.5A2.25 2.25 0 0 0 16 13.75v-7.5A2.25 2.25 0 0 0 13.75 4z"/></svg>`,this.stopBtn.dataset.tooltip=`Stop generation`,this.stopBtn.style.display=`none`,this.micBtn=document.createElement(`button`),this.micBtn.className=`chat__mic-btn`;let n=`http://www.w3.org/2000/svg`,r=document.createElementNS(n,`svg`);r.setAttribute(`width`,`16`),r.setAttribute(`height`,`16`),r.setAttribute(`viewBox`,`0 0 24 24`),r.setAttribute(`fill`,`none`),r.setAttribute(`stroke`,`currentColor`),r.setAttribute(`stroke-width`,`2`),r.setAttribute(`stroke-linecap`,`round`),r.setAttribute(`stroke-linejoin`,`round`);let i=document.createElementNS(n,`path`);i.setAttribute(`d`,`M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z`);let a=document.createElementNS(n,`path`);a.setAttribute(`d`,`M19 10v2a7 7 0 0 1-14 0v-2`);let o=document.createElementNS(n,`line`);o.setAttribute(`x1`,`12`),o.setAttribute(`y1`,`19`),o.setAttribute(`x2`,`12`),o.setAttribute(`y2`,`23`);let s=document.createElementNS(n,`line`);s.setAttribute(`x1`,`8`),s.setAttribute(`y1`,`23`),s.setAttribute(`x2`,`16`),s.setAttribute(`y2`,`23`),r.append(i,a,o,s),this.micBtn.appendChild(r),this.micBtn.dataset.tooltip=`Voice (Ctrl+Shift+V)`;let c=document.createElement(`div`);c.className=`chat__input-wrapper`,c.appendChild(this.textarea);let l=document.createElement(`div`);l.className=`chat__action-bar`;let u=document.createElement(`div`);u.className=`chat__action-bar-left`,u.appendChild(this.micBtn),l.appendChild(u),this.modelSelectorEl=document.createElement(`div`),this.modelSelectorEl.className=`chat__model-selector`,this.renderModelSelector(),l.appendChild(this.modelSelectorEl);let d=document.createElement(`div`);d.className=`chat__action-bar-right`,d.appendChild(this.sendBtn),d.appendChild(this.stopBtn),l.appendChild(d),c.appendChild(l),t.appendChild(c),e.appendChild(t),this.container.appendChild(e),this.jumpPill=document.createElement(`button`),this.jumpPill.className=`chat__jump-pill`,this.jumpPill.textContent=`↓ New activity`,this.jumpPill.addEventListener(`click`,()=>{this.autoScrollAttached=!0,this.hideJumpPill(),this.scrollToBottom(!0)}),this.container.appendChild(this.jumpPill),this.textarea.addEventListener(`keydown`,e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),this.sendMessage())}),this.textarea.addEventListener(`input`,()=>{this.textarea.style.height=`auto`,this.textarea.style.height=Math.min(this.textarea.scrollHeight,120)+`px`}),this.sendBtn.addEventListener(`click`,()=>this.sendMessage()),this.stopBtn.addEventListener(`click`,()=>{this.agent?.stop();for(let e of this.messages)e.queued&&(e.queued=!1,this.updateMessageEl(e.id));this.setStreamingState(!1)}),this.voiceInput=new Jr({onTranscript:(e,t)=>{this.textarea.value=e,this.textarea.style.height=`auto`,this.textarea.style.height=Math.min(this.textarea.scrollHeight,120)+`px`},onStateChange:e=>{e===`error`?(this.voiceMode=!1,this.micBtn.classList.remove(`chat__mic-btn--active`,`chat__mic-btn--listening`)):this.voiceMode?e===`listening`&&this.micBtn.classList.add(`chat__mic-btn--listening`):this.micBtn.classList.toggle(`chat__mic-btn--listening`,e===`listening`)},onError:e=>{mi.debug(`Voice input error`,{error:e}),!(this.voiceMode&&e.includes(`No speech detected`))&&this.addSystemMessage(e)},autoSend:!0,onAutoSend:e=>{this.textarea.value=e,this.sendMessage()},onAutoDisable:()=>{this.voiceMode=!1,this.micBtn.classList.remove(`chat__mic-btn--active`,`chat__mic-btn--listening`),this.addSystemMessage(`Voice mode disabled after 2 minutes of inactivity.`)},lang:Xr()}),this.micBtn.addEventListener(`click`,()=>{this.toggleVoiceMode()}),this.keydownListener=e=>{e.shiftKey&&(e.ctrlKey||e.metaKey)&&e.key===`V`&&(e.preventDefault(),this.toggleVoiceMode())},document.addEventListener(`keydown`,this.keydownListener)}toggleVoiceMode(){this.voiceMode=!this.voiceMode,this.micBtn.classList.toggle(`chat__mic-btn--active`,this.voiceMode),this.voiceMode?this.voiceInput?.start():this.voiceInput?.stop()}sendMessage(){let e=this.textarea.value.trim();if(!e)return;this.autoScrollAttached=!0,this.hideJumpPill();let t=this.isStreaming,n={id:hi(),role:`user`,content:e,timestamp:Date.now(),queued:t||void 0};this.messages.push(n),this.appendMessageEl(n),this.persistSession(),this.textarea.value=``,this.textarea.style.height=`auto`,this.isStreaming||this.setStreamingState(!0),this.agent?.sendMessage(e,n.id)}handleAgentEvent(e){switch(mi.debug(`Agent event`,{type:e.type}),e.type){case`message_start`:this.handleMessageStart(e.messageId);break;case`content_delta`:this.handleContentDelta(e.messageId,e.text);break;case`content_done`:this.handleContentDone(e.messageId);break;case`tool_use_start`:this.handleToolUseStart(e.messageId,e.toolName,e.toolInput);break;case`tool_result`:this.handleToolResult(e.messageId,e.toolName,e.result,e.isError);break;case`tool_ui`:this.handleToolUI(e.messageId,e.toolName,e.requestId,e.html);break;case`tool_ui_done`:this.handleToolUIDone(e.messageId,e.requestId);break;case`turn_end`:this.handleTurnEnd(e.messageId);break;case`error`:this.handleError(e.error);break;case`screenshot`:break;case`terminal_output`:this.terminalOutputCallback?.(e.text);break}}handleMessageStart(e){this.setStreamingState(!0),this.currentStreamId=e;let t={id:e,role:`assistant`,content:``,timestamp:Date.now(),isStreaming:!0,toolCalls:[]};this.messages.push(t),this.appendMessageEl(t)}handleContentDelta(e,t){this.findMessage(e)&&(this.pendingDeltaText+=t,this.streamingRafId===null&&(this.streamingRafId=requestAnimationFrame(()=>this.flushPendingDelta())))}handleContentDone(e){if(this.pendingDeltaText&&this.currentStreamId===e){let t=this.findMessage(e);t&&(t.content+=this.pendingDeltaText)}this.cancelPendingDelta();let t=this.findMessage(e);t&&(t.isStreaming=!1,this.updateMessageEl(e))}handleToolUseStart(e,t,n){let r=this.findMessage(e);r&&(r.toolCalls||=[],r.toolCalls.push({id:hi(),name:t,input:n}),this.updateMessageEl(e))}handleToolResult(e,t,n,r){let i=this.findMessage(e);if(!i||!i.toolCalls)return;let a=[...i.toolCalls].reverse().find(e=>e.name===t&&e.result===void 0);if(a){let e=n.match(/<img:(data:image\/[^>]+)>/);a.result=n.replace(/<img:data:image\/[^>]+>/g,``).trim(),e&&(a._screenshotDataUrl=e[1]),a.isError=r}this.updateMessageEl(e)}handleToolUI(e,t,n,r,i=0){let a=this.findMessage(e);if(!a||!a.toolCalls){if(i<10){setTimeout(()=>this.handleToolUI(e,t,n,r,i+1),100);return}mi.warn(`handleToolUI: message or toolCalls not found after retries`,{messageId:e});return}let o=[...a.toolCalls].reverse().find(e=>e.name===t&&e.result===void 0);if(!o){mi.warn(`handleToolUI: no matching tool call found`,{messageId:e,toolName:t});return}o._toolUIRequestId=n;let s=this.messagesEl.querySelector(`[data-msg-id="${e}"]`);if(!s){if(i<10){setTimeout(()=>this.handleToolUI(e,t,n,r,i+1),100);return}mi.warn(`handleToolUI: wrapper element not found after retries`,{messageId:e});return}let c=[...s.querySelectorAll(`.tool-call`)].reverse().find(e=>e.querySelector(`.tool-call__name`)?.textContent===t);if(c){c instanceof HTMLDetailsElement&&(c.open=!0);let e=c.querySelector(`.tool-call__ui`);e||(e=document.createElement(`div`),e.className=`tool-call__ui`,c.appendChild(e)),fi(e,n,r)}else i<10?setTimeout(()=>this.handleToolUI(e,t,n,r,i+1),100):mi.warn(`handleToolUI: tool call element not found in DOM after retries`,{toolName:t})}handleToolUIDone(e,t){pi(t)}handleTurnEnd(e){this.setStreamingState(!1),this.currentStreamId=null,this.persistSession()}handleError(e){this.setStreamingState(!1),this.currentStreamId=null;let t=this.messages[this.messages.length-1];if(t?.role===`assistant`&&t.isStreaming)t.isStreaming=!1,t.content+=`\n\n**Error:** ${e}`,this.updateMessageEl(t.id);else{let t={id:hi(),role:`assistant`,content:`**Error:** ${e}`,timestamp:Date.now()};this.messages.push(t),this.appendMessageEl(t)}this.persistSession()}setStreamingState(e){this.isStreaming=e;try{this.renderModelSelector()}catch{}if(this.stopBtn.style.display=e?`flex`:`none`,this.sendBtn.style.display=e?`none`:`flex`,this.textarea.disabled=!1,e){this.voiceInput?.isListening()&&this.voiceInput.stop(),this.micBtn.classList.remove(`chat__mic-btn--listening`);let e=this.messages.find(e=>e.queued);e&&(e.queued=!1,this.updateMessageEl(e.id))}e||(this.voiceMode?(this.micBtn.classList.add(`chat__mic-btn--listening`),this.voiceInput?.start()):this.textarea.focus())}renderModelSelector(){let e=this.modelSelectorEl;if(!e)return;for(;e.firstChild;)e.removeChild(e.firstChild);let t=ie(),n=O(),r=D(),i=[];for(let e of t)for(let t of e.models)i.push({providerId:e.providerId,id:t.id,name:t.name,reasoning:t.reasoning});i.sort((e,t)=>e.reasoning===t.reasoning?e.name.localeCompare(t.name):e.reasoning?-1:1);let a=i.find(e=>e.id===n&&e.providerId===r)||i[0];if(!a)return;let o=this.isStreaming,s=document.createElement(`button`);if(s.className=`chat__model-btn chat__model-btn--compact`,o&&s.classList.add(`chat__model-btn--disabled`),s.textContent=a.name,!o){let e=document.createElement(`span`);e.className=`chat__model-chevron`,e.innerHTML=`<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor"><path d="M4.5 6l3.5 4 3.5-4z"/></svg>`,s.appendChild(e)}if(o)e.appendChild(s);else{let t=!1,a=document.createElement(`div`);a.className=`chat__model-menu`;let o=()=>{for(a.style.display=t?`block`:`none`;a.firstChild;)a.removeChild(a.firstChild);if(t)for(let e of i){let i=document.createElement(`div`);i.className=`chat__model-menu-item`;let o=e.id===n&&e.providerId===r;o&&i.classList.add(`chat__model-menu-item--active`);let s=document.createElement(`span`);if(s.textContent=e.name,i.appendChild(s),o){let e=document.createElement(`span`);e.className=`chat__model-check`,e.innerHTML=`<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor"><path d="M6.5 12.5l-4-4 1.4-1.4 2.6 2.6 5.6-5.6 1.4 1.4z"/></svg>`,i.appendChild(e)}i.addEventListener(`click`,()=>{let n=`${e.providerId}:${e.id}`;oe(n),this.onModelChange?.(n),t=!1,this.renderModelSelector()}),a.appendChild(i)}};s.addEventListener(`click`,e=>{e.stopPropagation(),t=!t,o()}),document.addEventListener(`click`,()=>{t=!1,o()},{once:!0}),e.appendChild(s),e.appendChild(a),o()}}refreshModelSelector(){this.renderModelSelector()}findMessage(e){return this.messages.find(t=>t.id===e)}flushPendingDelta(){if(this.streamingRafId=null,!this.pendingDeltaText||!this.currentStreamId)return;let e=this.findMessage(this.currentStreamId);if(!e){this.pendingDeltaText=``;return}e.content+=this.pendingDeltaText,this.pendingDeltaText=``,this.updateStreamingContent(this.currentStreamId)}cancelPendingDelta(){this.streamingRafId!==null&&(cancelAnimationFrame(this.streamingRafId),this.streamingRafId=null),this.pendingDeltaText=``}updateStreamingContent(e){let t=this.findMessage(e);if(!t)return;let n=this.messagesEl.querySelector(`[data-msg-id="${e}"]`);if(!n)return;let r=n.querySelector(`.msg__content`);if(r){if(r.innerHTML=vi(t),t.isStreaming){let e=document.createElement(`span`);e.className=`streaming-cursor`,r.appendChild(e)}}else if(t.content.trim().length>0){this.updateMessageEl(e);return}this.scrollToBottom()}renderMessages(){this.disposeAllInlineSprinkles(),this.messagesInner.innerHTML=``;let e=null,t=0,n=-1;for(let e=this.messages.length-1;e>=0;e--)if(this.messages[e].role===`assistant`){n=e;break}for(let r=0;r<this.messages.length;r++){let i=this.messages[r],a=this.shouldShowLabel(i,e,t),o=this.createMessageEl(i,a,r===n);this.messagesInner.appendChild(o),e=i.role,t=i.timestamp}this.autoScrollAttached=!0,this.hideJumpPill(),this.scrollToBottom(!0)}appendMessageEl(e){let t=this.messagesInner.querySelector(`.msg__feedback`);t&&t.remove();let n=this.messages.length>=2?this.messages[this.messages.length-2]:null,r=this.shouldShowLabel(e,n?.role??null,n?.timestamp??0),i=e.role===`assistant`,a=this.createMessageEl(e,r,i);this.messagesInner.appendChild(a),this.scrollToBottom()}shouldShowLabel(e,t,n){return e.source===`lick`||e.channel===`webhook`||e.channel===`cron`||e.role!==t||e.timestamp-n>12e4}updateMessageEl(e){let t=this.findMessage(e);if(!t)return;let n=this.messagesEl.querySelector(`[data-msg-id="${e}"]`);if(n){this.disposeInlineSprinklesForMessage(e);let r=this.messages.indexOf(t),i=r>0?this.messages[r-1]:null,a=this.shouldShowLabel(t,i?.role??null,i?.timestamp??0),o=!1;if(t.role===`assistant`){let e=-1;for(let t=this.messages.length-1;t>=0;t--)if(this.messages[t].role===`assistant`){e=t;break}o=r===e}let s=this.createMessageEl(t,a,o);n.replaceWith(s)}this.scrollToBottom()}createMessageEl(e,t=!0,n=!1){if(e.source===`lick`||e.channel===`webhook`||e.channel===`cron`){let t=document.createElement(`div`);return t.className=`msg-group`,t.setAttribute(`data-msg-id`,e.id),t.appendChild(this.createLickEl(e)),t}let r=document.createElement(`div`);r.className=`msg-group${t?``:` msg-group--continuation`}`,r.setAttribute(`data-msg-id`,e.id);let i=document.createElement(`div`);if(i.className=`msg msg--${e.role}${e.queued?` msg--queued`:``}`,t){let t,n,r=this.currentScoopName!==null;e.role===`user`?e.source===`delegation`||e.channel===`delegation`?(t=`S`,n=`sliccy`):(t=`U`,n=`You`):r?(t=(this.currentScoopName||`S`).charAt(0).toUpperCase(),n=`@${this.currentScoopName}`):e.source&&e.source!==`cone`?(t=e.source.charAt(0).toUpperCase(),n=e.source):(t=`S`,n=`sliccy`);let a=document.createElement(`div`);a.className=`msg__role`;let o=document.createElement(`span`);if(o.className=`msg__icon`,o.textContent=t,a.appendChild(o),a.appendChild(document.createTextNode(` ${n}`)),e.queued){let t=document.createElement(`span`);t.className=`msg__queued-badge`,t.textContent=`queued`,a.appendChild(t);let n=document.createElement(`button`);n.className=`msg__queued-delete`,n.textContent=`×`,n.title=`Remove queued message`,n.addEventListener(`click`,t=>{t.stopPropagation(),this.deleteQueuedMessage(e.id)}),a.appendChild(n)}i.appendChild(a)}let a=(e.source===`lick`||e.channel===`webhook`||e.channel===`cron`)&&this.sessionId===`session-cone`,o=e.source&&e.source!==`cone`&&e.source!==`lick`&&e.role===`assistant`&&this.sessionId===`session-cone`;if(a||o){let t=document.createElement(`details`);t.className=`msg__collapsible`;let n=document.createElement(`summary`);n.className=`msg__summary`,n.textContent=e.content.slice(0,60).replace(/\n/g,` `)+(e.content.length>60?`...`:``),t.appendChild(n);let r=document.createElement(`div`);r.className=`msg__content`,r.innerHTML=vi(e),e.isStreaming||this.hydrateInlineSprinklesInEl(r,e.id),t.appendChild(r),i.appendChild(t)}else{let t=document.createElement(`div`);if(t.className=`msg__content`,t.innerHTML=vi(e),e.isStreaming){let e=document.createElement(`span`);e.className=`streaming-cursor`,t.appendChild(e)}else this.hydrateInlineSprinklesInEl(t,e.id);i.appendChild(t)}let s=e.content.trim().length>0;if(s&&r.appendChild(i),e.toolCalls)for(let t of e.toolCalls)r.appendChild(this.createToolCallEl(t));return e.role===`assistant`&&!e.isStreaming&&!e.queued&&s&&n&&r.appendChild(this.createFeedbackRow()),r}createFeedbackRow(){let e=document.createElement(`div`);e.className=`msg__feedback`;let t=document.createElement(`button`);return t.className=`msg__feedback-btn`,t.dataset.tooltip=`Copy chat`,t.setAttribute(`aria-label`,`Copy chat`),t.innerHTML=`<svg width="16" height="16" viewBox="0 0 20 20" fill="currentColor"><path d="m11.75,18h-7.5c-1.24,0-2.25-1.01-2.25-2.25v-7.5c0-1.24,1.01-2.25,2.25-2.25.41,0,.75.34.75.75s-.34.75-.75.75c-.41,0-.75.34-.75.75v7.5c0,.41.34.75.75.75h7.5c.41,0,.75-.34.75-.75,0-.41.34-.75.75-.75s.75.34.75.75c0,1.24-1.01,2.25-2.25,2.25Z"/><path d="m6.75,5c-.41,0-.75-.34-.75-.75,0-1.24,1.01-2.25,2.25-2.25.41,0,.75.34.75.75s-.34.75-.75.75c-.41,0-.75.34-.75.75,0,.41-.34.75-.75.75Z"/><path d="m13,3.5h-2c-.41,0-.75-.34-.75-.75s.34-.75.75-.75h2c.41,0,.75.34.75.75s-.34.75-.75.75Z"/><path d="m13,14h-2c-.41,0-.75-.34-.75-.75s.34-.75.75-.75h2c.41,0,.75.34.75.75s-.34.75-.75.75Z"/><path d="m15.75,14c-.41,0-.75-.34-.75-.75s.34-.75.75-.75c.41,0,.75-.34.75-.75,0-.41.34-.75.75-.75s.75.34.75.75c0,1.24-1.01,2.25-2.25,2.25Z"/><path d="m17.25,5c-.41,0-.75-.34-.75-.75,0-.41-.34-.75-.75-.75-.41,0-.75-.34-.75-.75s.34-.75.75-.75c1.24,0,2.25,1.01,2.25,2.25,0,.41-.34.75-.75.75Z"/><path d="m17.25,9.75c-.41,0-.75-.34-.75-.75v-2c0-.41.34-.75.75-.75s.75.34.75.75v2c0,.41-.34.75-.75.75Z"/><path d="m6.75,9.75c-.41,0-.75-.34-.75-.75v-2c0-.41.34-.75.75-.75s.75.34.75.75v2c0,.41-.34.75-.75.75Z"/><path d="m8.25,14c-1.24,0-2.25-1.01-2.25-2.25,0-.41.34-.75.75-.75s.75.34.75.75c0,.41.34.75.75.75.41,0,.75.34.75.75s-.34.75-.75.75Z"/></svg>`,t.addEventListener(`click`,async()=>{let e=this.getMessages(),n=``;for(let t of e){let e=t.role===`user`?`User`:`Assistant`;if(n+=`## ${e}\n${t.content}\n\n`,t.toolCalls)for(let e of t.toolCalls)n+=`### Tool: ${e.name}\nInput: ${JSON.stringify(e.input,null,2)}\nResult: ${e.result??``}\n\n`}await navigator.clipboard.writeText(n),t.style.color=`var(--s2-positive)`,setTimeout(()=>{t.style.color=``},1500)}),e.appendChild(t),e}createLickEl(e){let t=document.createElement(`details`);t.className=`lick`;let n=e.channel===`webhook`?`Webhook`:e.channel===`cron`?`Cron`:`Event`,r=document.createElement(`summary`);r.className=`lick__header`,r.innerHTML=`<span class="lick__icon">E</span> <span class="lick__type">${n}</span>`;let i=document.createElement(`span`);i.className=`lick__preview`;let a=e.content.replace(/\[Webhook Event:.*?\]\n```json\n?/s,``).slice(0,50);i.textContent=a.replace(/\n/g,` `)+(a.length>=50?`...`:``),r.appendChild(i),t.appendChild(r);let o=document.createElement(`div`);return o.className=`lick__details`,o.innerHTML=Lr(e.content),t.appendChild(o),t}createToolCallEl(e){_i(e.name);let t=document.createElement(`details`);t.className=`tool-call`;let n=document.createElement(`summary`);if(n.className=`tool-call__header`,n.innerHTML=`<span class="tool-call__icon"><svg width="10" height="10" viewBox="0 0 10 10" fill="currentColor"><path d="M2 3.5L5 6.5L8 3.5" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg></span> <span class="tool-call__name">${Tr(e.name)}</span>`,e.input!==void 0){let t=document.createElement(`span`);t.className=`tool-call__preview`;let r=typeof e.input==`string`?e.input:JSON.stringify(e.input);t.textContent=r.slice(0,40)+(r.length>40?`...`:``),n.appendChild(t)}let r=document.createElement(`span`);e.result===void 0?r.className=`tool-call__status tool-call__status--running`:e.isError?(r.className=`tool-call__status tool-call__status--error`,r.textContent=`failed`):(r.className=`tool-call__status tool-call__status--success`,r.textContent=`✓`),n.appendChild(r),t.appendChild(n);let i=document.createElement(`div`);if(i.className=`tool-call__details`,e.input!==void 0){let t=document.createElement(`div`);t.className=`tool-call__input`;let n=document.createElement(`div`);n.className=`tool-call__label`,n.textContent=`Input:`,t.appendChild(n);let r=document.createElement(`pre`);r.innerHTML=zr(e.input),t.appendChild(r),i.appendChild(t)}if(e.result!==void 0){let t=document.createElement(`div`);t.className=`tool-call__result${e.isError?` tool-call__result--error`:``}`;let n=document.createElement(`div`);n.className=`tool-call__label`,n.textContent=e.isError?`Error:`:`Result:`,t.appendChild(n);let r=document.createElement(`pre`);r.textContent=e.result,t.appendChild(r),i.appendChild(t)}let a=e._screenshotDataUrl;if(a){let e=document.createElement(`img`);e.src=a,e.className=`tool-call__screenshot`,e.title=`Click to view full size`,e.addEventListener(`click`,e=>{e.stopPropagation();let t=window.open(`about:blank`);if(t){let e=t.document.createElement(`img`);e.src=a,t.document.title=`Screenshot`,t.document.body.style.margin=`0`,t.document.body.style.background=document.documentElement.classList.contains(`theme-light`)?`#f0f0f0`:`#141414`,t.document.body.appendChild(e)}}),i.appendChild(e)}return t.appendChild(i),t}scrollToBottom(e=!1){if(!e&&!this.autoScrollAttached){this.showJumpPill();return}requestAnimationFrame(()=>{this.messagesEl.scrollTop=this.messagesEl.scrollHeight,this.lastScrollTop=this.messagesEl.scrollTop})}showJumpPill(){this.jumpPill.classList.add(`chat__jump-pill--visible`)}hideJumpPill(){this.jumpPill.classList.remove(`chat__jump-pill--visible`)}persistSession(){this.sessionStore.saveMessages(this.sessionId,this.messages).catch(()=>{})}disposeInlineSprinklesForMessage(e){let t=this.inlineSprinkles.get(e);t&&(oi(t),this.inlineSprinkles.delete(e))}disposeAllInlineSprinkles(){for(let[,e]of this.inlineSprinkles)oi(e);this.inlineSprinkles.clear()}hydrateInlineSprinklesInEl(e,t){let n=ai(e,(e,t)=>this.onInlineSprinkleLick?.(e,t));n.length&&this.inlineSprinkles.set(t,n)}dispose(){this.cancelPendingDelta(),this.disposeAllInlineSprinkles(),this.unsubscribe?.(),this.voiceInput?.destroy(),this.keydownListener&&=(document.removeEventListener(`keydown`,this.keydownListener),null),this.container.innerHTML=``}},bi=class{container;terminalViewEl;previewViewEl;previewEmptyEl;previewBtn;shell=null;activeView=`terminal`;onClearTerminal;constructor(e,t={}){this.container=e,this.onClearTerminal=t.onClearTerminal??null,this.render()}async mountShell(e){this.shell?.setPreviewStateListener(null),this.shell=e;let t=document.createElement(`div`);t.className=`terminal-panel__mount`,this.terminalViewEl.appendChild(t),await e.mount(t);let n=t.querySelector(`.terminal-panel__terminal-host`),r=t.querySelector(`.terminal-panel__preview`);if(!n||!r)throw Error(`terminal mount did not create expected hosts`);this.terminalViewEl.replaceChildren(n),this.previewViewEl.replaceChildren(this.previewEmptyEl),this.previewViewEl.appendChild(r),e.setPreviewStateListener(e=>this.handlePreviewStateChange(e))}clearTerminal(){this.shell?.clearTerminal()}async runCommand(e){return this.shell?(/^\s*imgcat(?:\s|$)/.test(e)||this.setActiveView(`terminal`),this.shell.executeCommandInTerminal(e)):{stdout:``,stderr:`terminal is unavailable
179
179
  `,exitCode:1}}refit(){this.shell?.refit()}getBodyElement(){return this.container}render(){this.container.innerHTML=``,this.container.classList.add(`terminal-panel`);let e=document.createElement(`div`);e.className=`file-browser__header`;let t=document.createElement(`span`);if(t.className=`file-browser__header-title`,t.textContent=`Terminal`,e.appendChild(t),this.onClearTerminal){let t=document.createElement(`button`);t.className=`file-browser__header-btn`,t.dataset.tooltip=`Clear Terminal`,t.setAttribute(`aria-label`,`Clear Terminal`),t.innerHTML=`<svg width="14" height="14" viewBox="0 0 20 20" fill="none"><path d="m8.249,15.021c-.4,0-.733-.317-.748-.72l-.25-6.5c-.017-.414.307-.763.72-.778.01-.001.021-.001.03-.001.4,0,.733.317.748.72l.25,6.5c.017.414-.307.763-.72.778-.01.001-.021.001-.03.001Z" fill="currentColor"/><path d="m11.751,15.021c-.01,0-.02,0-.03-.001-.413-.016-.736-.364-.72-.778l.25-6.5c.015-.403.348-.72.748-.72.01,0,.02,0,.03.001.413.016.736.364.72.778l-.25,6.5c-.015.403-.348.72-.748.72Z" fill="currentColor"/><path d="m17,4h-3.5v-.75c0-1.24-1.01-2.25-2.25-2.25h-2.5c-1.24,0-2.25,1.01-2.25,2.25v.75h-3.5c-.414,0-.75.336-.75.75s.336.75.75.75h.52l.422,10.342c.048,1.21,1.036,2.158,2.248,2.158h7.619c1.212,0,2.2-.948,2.248-2.158l.422-10.342h.52c.414,0,.75-.336.75-.75s-.336-.75-.75-.75Zm-9-.75c0-.413.337-.75.75-.75h2.5c.413,0,.75.337.75.75v.75h-4v-.75Zm6.56,12.531c-.017.403-.346.719-.75.719h-7.619c-.404,0-.733-.316-.75-.719l-.42-10.281h9.959l-.42,10.281Z" fill="currentColor"/></svg>`,t.addEventListener(`click`,()=>this.onClearTerminal()),e.appendChild(t)}this.previewBtn=document.createElement(`button`),this.previewBtn.className=`file-browser__header-btn`,this.previewBtn.setAttribute(`aria-label`,`Toggle preview`),this.previewBtn.dataset.tooltip=`Preview`,this.previewBtn.disabled=!0;let n=`http://www.w3.org/2000/svg`,r=document.createElementNS(n,`svg`);r.setAttribute(`width`,`16`),r.setAttribute(`height`,`16`),r.setAttribute(`viewBox`,`0 0 20 20`),r.setAttribute(`fill`,`none`),r.setAttribute(`stroke`,`currentColor`),r.setAttribute(`stroke-width`,`1.5`),r.setAttribute(`stroke-linecap`,`round`),r.setAttribute(`stroke-linejoin`,`round`);let i=document.createElementNS(n,`path`);i.setAttribute(`d`,`M2 10s3-6 8-6 8 6 8 6-3 6-8 6-8-6-8-6z`),r.appendChild(i);let a=document.createElementNS(n,`circle`);a.setAttribute(`cx`,`10`),a.setAttribute(`cy`,`10`),a.setAttribute(`r`,`2.5`),r.appendChild(a),this.previewBtn.appendChild(r),this.previewBtn.addEventListener(`click`,()=>{this.previewBtn.disabled||this.setActiveView(this.activeView===`preview`?`terminal`:`preview`)}),e.appendChild(this.previewBtn),this.container.appendChild(e),this.terminalViewEl=document.createElement(`div`),this.terminalViewEl.className=`terminal-panel__view`,this.container.appendChild(this.terminalViewEl),this.previewViewEl=document.createElement(`div`),this.previewViewEl.className=`terminal-panel__view`,this.container.appendChild(this.previewViewEl),this.previewEmptyEl=document.createElement(`div`),this.previewEmptyEl.className=`terminal-panel__empty-state`,this.previewEmptyEl.textContent=`Run imgcat to preview media here.`,this.previewViewEl.appendChild(this.previewEmptyEl),this.setActiveView(`terminal`)}dispose(){this.shell?.setPreviewStateListener(null),this.shell?.dispose(),this.container.innerHTML=``}setActiveView(e){this.activeView=e,this.previewBtn.classList.toggle(`file-browser__header-btn--active`,e===`preview`),this.terminalViewEl.style.display=e===`terminal`?`flex`:`none`,this.previewViewEl.style.display=e===`preview`?`flex`:`none`,e===`terminal`&&this.refit()}handlePreviewStateChange(e){this.previewBtn.disabled=!e,this.previewEmptyEl.style.display=e?`none`:`flex`,e?this.setActiveView(`preview`):this.activeView===`preview`&&this.setActiveView(`terminal`)}};function xi(e){return e<1024?e+` B`:e<1024*1024?(e/1024).toFixed(1)+`K`:e<1024*1024*1024?(e/(1024*1024)).toFixed(1)+`M`:(e/(1024*1024*1024)).toFixed(1)+`G`}function Si(e){let t=`http://www.w3.org/2000/svg`,n=document.createElementNS(t,`svg`);n.setAttribute(`width`,`14`),n.setAttribute(`height`,`14`),n.setAttribute(`viewBox`,`0 0 20 20`),n.setAttribute(`fill`,`none`),n.setAttribute(`stroke`,`currentColor`),n.setAttribute(`stroke-width`,`1.5`),n.setAttribute(`stroke-linecap`,`round`),n.setAttribute(`stroke-linejoin`,`round`),n.style.flexShrink=`0`;for(let r of e){let e=document.createElementNS(t,`path`);e.setAttribute(`d`,r),n.appendChild(e)}return n}function Ci(){return Si([`M2 6V5a1 1 0 0 1 1-1h4l2 2h8a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V6z`])}function wi(){return Si([`M6 2h5l5 5v9a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1z`,`M11 2v5h5`])}function Ti(e){let t=`http://www.w3.org/2000/svg`,n=document.createElementNS(t,`svg`);n.setAttribute(`width`,`10`),n.setAttribute(`height`,`10`),n.setAttribute(`viewBox`,`0 0 20 20`),n.setAttribute(`fill`,`none`),n.setAttribute(`stroke`,`currentColor`),n.setAttribute(`stroke-width`,`2`),n.setAttribute(`stroke-linecap`,`round`),n.setAttribute(`stroke-linejoin`,`round`),n.style.flexShrink=`0`,n.style.transition=`transform 130ms ease`,e&&(n.style.transform=`rotate(90deg)`);let r=document.createElementNS(t,`path`);return r.setAttribute(`d`,`M7 5l5 5-5 5`),n.appendChild(r),n}function Ei(e){return`'${e.replace(/'/g,`'\\''`)}'`}function Di(e){return`${f(e)?`imgcat`:`cat`} ${Ei(e)}`}var Oi=class{container;bodyEl;fs=null;expandedDirs=new Set([`/`]);refreshTimer=null;onRunCommand;selectedPath=null;keydownHandler=null;constructor(e,t={}){this.container=e,this.onRunCommand=t.onRunCommand??null,this.render()}setFs(e){this.fs=e,this.refresh(),this.refreshTimer=setInterval(()=>this.refresh(),3e3)}async refresh(){if(!this.fs)return;let e=document.createElement(`div`);try{await this.renderDir(`/`,e,0)}catch(e){console.warn(`[FileBrowser] Refresh failed:`,e instanceof Error?e.message:String(e));return}if(e.innerHTML===this.bodyEl.innerHTML){this.applySelection();return}let t=this.container.contains(document.activeElement);for(;this.bodyEl.firstChild;)this.bodyEl.removeChild(this.bodyEl.firstChild);for(;e.firstChild;)this.bodyEl.appendChild(e.firstChild);this.applySelection(),t&&this.selectedPath&&this.bodyEl.querySelector(`.file-browser__item--selected`)?.focus()}render(){for(;this.container.firstChild;)this.container.removeChild(this.container.firstChild);this.container.classList.add(`file-browser`);let e=document.createElement(`div`);e.className=`file-browser__header`;let t=document.createElement(`span`);t.className=`file-browser__header-title`,t.textContent=`Files`,e.appendChild(t),this.container.appendChild(e),this.bodyEl=document.createElement(`div`),this.bodyEl.className=`file-browser__body`,this.container.appendChild(this.bodyEl),this.setupKeydown()}async renderDir(e,t,n){if(!this.fs)return;let r;try{r=await this.fs.readDir(e)}catch(t){console.warn(`[FileBrowser] readDir failed:`,e,t instanceof Error?t.message:String(t));return}let i=r.filter(e=>e.type===`directory`).sort((e,t)=>e.name.localeCompare(t.name)),a=r.filter(e=>e.type===`file`).sort((e,t)=>e.name.localeCompare(t.name));for(let r of[...i,...a]){let i=e===`/`?`/`+r.name:e+`/`+r.name,a=document.createElement(`div`);if(a.className=`file-browser__item`,a.style.paddingLeft=12+n*16+`px`,a.dataset.path=r.type===`directory`&&!i.endsWith(`/`)?i+`/`:i,r.type===`directory`){let e=this.expandedDirs.has(i),o=document.createElement(`span`);o.className=`file-browser__arrow`,o.appendChild(Ti(e)),a.appendChild(o);let s=document.createElement(`span`);s.className=`file-browser__icon`,s.appendChild(Ci()),a.appendChild(s);let c=document.createElement(`span`);c.className=`file-browser__name`,c.textContent=r.name,a.appendChild(c);let l=document.createElement(`button`);l.className=`file-browser__action-btn`,l.style.marginLeft=`auto`,l.textContent=`ZIP`,l.title=`Download as ZIP`,l.addEventListener(`click`,e=>{e.stopPropagation(),this.downloadDirAsZip(i,r.name)}),a.appendChild(l),a.style.cursor=`pointer`,a.addEventListener(`click`,()=>{this.selectPath(i,`directory`),this.expandedDirs.has(i)?this.expandedDirs.delete(i):this.expandedDirs.add(i),this.refresh()}),t.appendChild(a),e&&await this.renderDir(i,t,n+1)}else{let e=document.createElement(`span`);e.className=`file-browser__arrow`,a.appendChild(e);let n=document.createElement(`span`);n.className=`file-browser__icon`,n.appendChild(wi()),a.appendChild(n);let o=document.createElement(`span`);o.className=`file-browser__name`,o.textContent=r.name,a.appendChild(o);try{let e=await this.fs.stat(i),t=document.createElement(`span`);t.className=`file-browser__size`,t.textContent=xi(e.size),a.appendChild(t)}catch(e){console.warn(`[FileBrowser] stat failed:`,i,e instanceof Error?e.message:String(e))}let s=document.createElement(`button`);s.className=`file-browser__action-btn`,s.style.marginLeft=`8px`,s.textContent=`CAT`,s.title=this.onRunCommand?f(i)?`Preview media in terminal`:`Preview in terminal`:`Terminal unavailable`,s.disabled=!this.onRunCommand,s.addEventListener(`click`,e=>{e.stopPropagation(),this.previewFile(i)}),a.appendChild(s),a.addEventListener(`click`,()=>{this.selectPath(i,`file`)}),t.appendChild(a)}}}async collectFiles(e,t){if(!this.fs)return{};let n={},r=await this.fs.readDir(e);for(let i of r){let r=e===`/`?`/`+i.name:e+`/`+i.name,a=t?t+`/`+i.name:i.name;if(i.type===`directory`){let e=await this.collectFiles(r,a);Object.assign(n,e)}else{let e=await this.fs.readFile(r,{encoding:`binary`});n[a]=e instanceof Uint8Array?e:new TextEncoder().encode(e)}}return n}async downloadDirAsZip(e,t){if(this.fs)try{let n=ce(await this.collectFiles(e,``)),r=new Blob([n.buffer],{type:`application/zip`}),i=URL.createObjectURL(r),a=document.createElement(`a`);a.href=i,a.download=t+`.zip`,a.click(),URL.revokeObjectURL(i)}catch(t){console.error(`[FileBrowser] ZIP download failed:`,e,t instanceof Error?t.message:String(t))}}previewFile(e){if(!this.onRunCommand)return;let t=Di(e);Promise.resolve(this.onRunCommand(t)).catch(t=>{console.error(`[FileBrowser] Preview command failed:`,e,t instanceof Error?t.message:String(t))})}selectPath(e,t){this.selectedPath=t===`directory`&&!e.endsWith(`/`)?e+`/`:e,this.applySelection(),this.bodyEl.querySelector(`.file-browser__item--selected`)?.focus()}applySelection(){let e=this.bodyEl.querySelector(`.file-browser__item--selected`);if(e&&(e.classList.remove(`file-browser__item--selected`),e.removeAttribute(`tabindex`)),!this.selectedPath)return;let t=this.bodyEl.querySelectorAll(`.file-browser__item`);for(let e of t)if(e.dataset.path===this.selectedPath){e.classList.add(`file-browser__item--selected`),e.tabIndex=0;break}}setupKeydown(){this.keydownHandler=e=>{!(e.metaKey||e.ctrlKey)||e.key!==`c`||this.selectedPath&&window.getSelection()?.isCollapsed!==!1&&(e.preventDefault(),navigator.clipboard.writeText(this.selectedPath).then(()=>{this.flashCopyFeedback()}).catch(e=>{console.warn(`[FileBrowser] Clipboard write failed:`,e instanceof Error?e.message:String(e))}))},this.container.addEventListener(`keydown`,this.keydownHandler)}flashCopyFeedback(){let e=this.bodyEl.querySelector(`.file-browser__item--selected`);e&&(e.classList.add(`file-browser__item--copy-flash`),setTimeout(()=>{e.classList.remove(`file-browser__item--copy-flash`)},300))}dispose(){for(this.keydownHandler&&=(this.container.removeEventListener(`keydown`,this.keydownHandler),null),this.refreshTimer&&=(clearInterval(this.refreshTimer),null);this.container.firstChild;)this.container.removeChild(this.container.firstChild)}},ki=class{container;bodyEl;orchestrator=null;selectedScoopJid=null;refreshTimer=null;constructor(e){this.container=e,this.render()}setOrchestrator(e){this.orchestrator=e,this.refresh(),this.refreshTimer=setInterval(()=>this.refresh(),5e3)}setSelectedScoop(e){this.selectedScoopJid=e,this.refresh()}async refresh(){if(!this.orchestrator)return;let e=document.createElement(`div`);e.className=`memory-panel__content`;let t=document.createElement(`div`);t.className=`memory-panel__section`;let n=document.createElement(`div`);n.className=`memory-panel__section-header`,n.textContent=`Global Memory (/shared/CLAUDE.md)`,t.appendChild(n);let r=document.createElement(`div`);r.className=`memory-panel__memory-content`;try{r.textContent=await this.orchestrator.getGlobalMemory()||`(empty)`}catch{r.textContent=`(not available)`}if(t.appendChild(r),e.appendChild(t),this.selectedScoopJid){let t=this.orchestrator.getScoopContext(this.selectedScoopJid),n=this.orchestrator.getScoop(this.selectedScoopJid);if(t&&n){let r=document.createElement(`div`);r.className=`memory-panel__section`;let i=document.createElement(`div`);i.className=`memory-panel__section-header`,i.textContent=`${n.isCone?`Cone`:`Scoop`}: ${n.assistantLabel}`,r.appendChild(i);let a=document.createElement(`div`);a.className=`memory-panel__memory-content`;try{let e=t.getFS();if(e){let t=n.isCone?`/workspace/CLAUDE.md`:`/scoops/${n.folder}/CLAUDE.md`,r=await e.readFile(t,{encoding:`utf-8`});a.textContent=typeof r==`string`?r:new TextDecoder().decode(r)}else a.textContent=`(filesystem not ready)`}catch{a.textContent=`(no memory file yet)`}r.appendChild(a),e.appendChild(r)}}if(e.innerHTML!==this.bodyEl.innerHTML){for(;this.bodyEl.firstChild;)this.bodyEl.removeChild(this.bodyEl.firstChild);for(;e.firstChild;)this.bodyEl.appendChild(e.firstChild)}}render(){for(;this.container.firstChild;)this.container.removeChild(this.container.firstChild);this.container.classList.add(`memory-panel`),this.bodyEl=document.createElement(`div`),this.bodyEl.className=`memory-panel__body`,this.container.appendChild(this.bodyEl)}dispose(){this.refreshTimer&&=(clearInterval(this.refreshTimer),null)}},Ai=r(`scoops-panel`),ji=class{container;orchestrator=null;callbacks;selectedScoopJid=null;scoopStatuses=new Map;expanded=!1;constructor(e,t){this.container=e,this.callbacks=t,this.render()}toggleExpanded(){this.expanded=!this.expanded,this.container.classList.toggle(`layout__scoops--expanded`,this.expanded);let e=this.container.querySelector(`.scoops-hamburger`);e&&(e.innerHTML=this.expanded?`<svg width="16" height="16" viewBox="0 0 20 20" fill="currentColor"><path d="M9.86241 16.4551C9.66612 16.4551 9.46886 16.3779 9.32237 16.2246L3.83507 10.5215C3.5548 10.2315 3.5548 9.77247 3.83507 9.48243L9.33507 3.76563C9.62218 3.4668 10.0978 3.45801 10.3946 3.74512C10.6935 4.03223 10.7032 4.50684 10.4151 4.80469L5.41613 10.002L10.4025 15.1855C10.6906 15.4834 10.6808 15.958 10.382 16.2451C10.2374 16.3857 10.0499 16.4551 9.86241 16.4551Z"/><path d="M15.6124 16.4551C15.4161 16.4551 15.2189 16.3779 15.0724 16.2246L9.58507 10.5215C9.3048 10.2315 9.3048 9.77247 9.58507 9.48243L15.0851 3.76563C15.3722 3.4668 15.8478 3.45801 16.1446 3.74512C16.4435 4.03223 16.4532 4.50684 16.1652 4.80469L11.1661 10.002L16.1525 15.1855C16.4406 15.4834 16.4308 15.958 16.132 16.2451C15.9874 16.3857 15.7999 16.4551 15.6124 16.4551Z"/></svg>`:`<svg width="16" height="16" viewBox="0 0 20 20" fill="currentColor"><path d="M9.61805 16.2451C9.31922 15.958 9.30945 15.4834 9.59754 15.1855L14.5839 10.002L9.58485 4.80469C9.29677 4.50684 9.30653 4.03223 9.60536 3.74512C9.90223 3.45801 10.3778 3.4668 10.6649 3.76563L16.1649 9.48243C16.4452 9.77247 16.4452 10.2315 16.1649 10.5215L10.6776 16.2246C10.5311 16.3779 10.3339 16.4551 10.1376 16.4551C9.95008 16.4551 9.76258 16.3857 9.61805 16.2451Z"/><path d="M3.86805 16.2451C3.56922 15.958 3.55945 15.4834 3.84754 15.1855L8.83387 10.002L3.83485 4.80469C3.54677 4.50684 3.55653 4.03223 3.85536 3.74512C4.15223 3.45801 4.62782 3.4668 4.91493 3.76563L10.4149 9.48243C10.6952 9.77247 10.6952 10.2315 10.4149 10.5215L4.92763 16.2246C4.78114 16.3779 4.58388 16.4551 4.38759 16.4551C4.20008 16.4551 4.01258 16.3857 3.86805 16.2451Z"/></svg>`)}setOrchestrator(e){this.orchestrator=e,this.refreshScoops()}updateScoopStatus(e,t){this.scoopStatuses.set(e,t),this.refreshScoops()}refreshScoops(){if(!this.orchestrator)return;document.querySelectorAll(`.scoop-fixed-tooltip`).forEach(e=>e.remove());let e=this.orchestrator.getScoops(),t=e.find(e=>e.isCone),n=e.filter(e=>!e.isCone),r=`http://www.w3.org/2000/svg`,i=[`#e8457a`,`#f08c5a`,`#9b6dd7`,`#42b8a0`,`#d4953e`],a=[`#fde4ec`,`#fef0e4`,`#efe4f8`,`#e0f5ef`,`#fef3e0`],o=this.container.querySelector(`.scoop-cone-header`);if(o){for(;o.firstChild;)o.removeChild(o.firstChild);if(t){let e=this.scoopStatuses.get(t.jid)??`inactive`,n=t.jid===this.selectedScoopJid,i=`#e07030`,a=`#fef0e0`,s=document.createElement(`div`);s.className=`scoop-item scoop-item--cone ${n?`selected`:``} status-${e}`,s.dataset.jid=t.jid,s.setAttribute(`aria-label`,t.assistantLabel),s.style.setProperty(`--scoop-accent`,i),s.style.setProperty(`--scoop-accent-bg`,a);let c=document.createElement(`div`);c.className=`scoop-icon-wrap scoop-icon-wrap--cone`,c.style.background=a,c.style.width=`40px`,c.style.height=`40px`;let l=document.createElementNS(r,`svg`);l.setAttribute(`width`,`24`),l.setAttribute(`height`,`24`),l.setAttribute(`fill`,i),l.setAttribute(`viewBox`,`100 195 230 235`);let u=document.createElementNS(r,`path`);if(u.setAttribute(`d`,`M331.2,128.8c1.6-4.8,2.4-11.2,2.4-16.8c0-20.8-12.8-40-31.2-48.8c-8-36-47.2-63.2-92.8-63.2c-48,0-88,29.6-93.6,68.8C102.4,79.2,94.4,95.2,94.4,112c0,4.8,0.8,9.6,1.6,13.6c-7.2,9.6-10.4,20.8-10.4,32C85.6,180,100,200,120,208l85.6,212.8c1.6,3.2,4,4.8,7.2,4.8s6.4-1.6,7.2-4.8L305.6,208c20-8,34.4-27.2,34.4-50.4C340,147.2,336.8,136.8,331.2,128.8z M139.2,216l-1.6-3.2h0.8c1.6,0,2.4,0,4,0L139.2,216z M145.6,232.8l23.2-24.8c4.8,6.4,11.2,11.2,18.4,14.4l12,12l-28.8,30.4l-20.8-22.4L145.6,232.8z M210.4,246.4l28.8,30.4L210.4,308l-28.8-31.2L210.4,246.4z M168.8,289.6l1.6-1.6l28.8,32l-12.8,13.6L168.8,289.6z M212,396.8l-18.4-46.4l16.8-18.4l19.2,21.6L212,396.8z M236.8,336l-15.2-16.8l28.8-31.2l4,4L236.8,336z M250.4,264.8l-28.8-30.4l11.2-12c8-3.2,14.4-8,19.2-14.4l25.6,27.2L250.4,264.8z M284,218.4l-6.4-6.4c2.4,0,4.8,0.8,8,0.8h0.8L284,218.4z M285.6,196c-9.6,0-19.2-4-26.4-11.2c-1.6-1.6-4.8-2.4-7.2-2.4c-2.4,0.8-4.8,2.4-5.6,4.8c-6.4,13.6-20,23.2-35.2,23.2c-14.4,0-28-8.8-34.4-21.6c-0.8-2.4-3.2-4-5.6-4.8c-0.8,0-0.8,0-1.6,0c-1.6,0-4,0.8-5.6,2.4c-7.2,6.4-16,9.6-25.6,9.6c-20.8,0-38.4-16.8-38.4-38.4c0-9.6,3.2-18.4,9.6-24.8c1.6-2.4,2.4-5.6,1.6-8c-1.6-4-2.4-8.8-2.4-12.8c0-12.8,6.4-24.8,17.6-32c2.4-1.6,3.2-4,4-6.4c2.4-32,36.8-57.6,78.4-57.6c39.2,0,72.8,23.2,77.6,54.4c0.8,3.2,2.4,5.6,4.8,6.4c15.2,5.6,24.8,20,24.8,36c0,4.8-0.8,10.4-3.2,15.2c-0.8,2.4-0.8,5.6,0.8,8c4.8,6.4,8,14.4,8,23.2C323.2,179.2,306.4,196,285.6,196z`),l.appendChild(u),c.appendChild(l),e===`processing`||e===`ready`||e===`error`){let t=document.createElement(`span`);t.className=`scoop-dot scoop-dot--${e}`,c.appendChild(t)}s.appendChild(c);let d=document.createElement(`div`);d.className=`scoop-info`;let f=document.createElement(`div`);if(f.className=`scoop-name`,f.textContent=t.assistantLabel,d.appendChild(f),e===`processing`||e===`error`){let t=document.createElement(`div`);t.className=`scoop-subtitle`,t.textContent=e===`processing`?`Working…`:`Error`,d.appendChild(t)}s.appendChild(d);let p=document.createElement(`div`);if(p.className=`scoop-actions`,e===`processing`){let e=document.createElement(`span`);e.className=`scoop-spin-dot`,p.appendChild(e)}else if(e===`error`){let e=document.createElement(`span`);e.className=`scoop-err-dot`,p.appendChild(e)}s.appendChild(p),s.addEventListener(`click`,()=>this.selectScoop(t));let m=t.assistantLabel;s.addEventListener(`mouseenter`,()=>{if(this.expanded)return;let e=document.createElement(`div`);e.className=`scoop-fixed-tooltip`,e.textContent=m,document.body.appendChild(e);let t=s.getBoundingClientRect();e.style.top=`${t.top+t.height/2}px`,e.style.left=`${t.right+8}px`,s.__tip=e}),s.addEventListener(`mouseleave`,()=>{let e=s.__tip;e&&(e.remove(),s.__tip=null)}),o.appendChild(s)}}let s=this.container.querySelector(`.scoops-list`);if(s){for(;s.firstChild;)s.removeChild(s.firstChild);if(n.length===0){this.callbacks.onScoopsChanged?.(e);return}for(let e=0;e<n.length;e++){let t=n[e],o=this.scoopStatuses.get(t.jid)??`inactive`,c=t.jid===this.selectedScoopJid,l=i[e%i.length],u=a[e%a.length],d=document.createElement(`div`);d.className=`scoop-item ${c?`selected`:``} status-${o}`,d.dataset.jid=t.jid;let f=t.assistantLabel.replace(/-scoop$/,``);d.setAttribute(`aria-label`,f),d.style.setProperty(`--scoop-accent`,l),d.style.setProperty(`--scoop-accent-bg`,u);let p=document.createElement(`div`);p.className=`scoop-icon-wrap`,p.style.background=u;let m=document.createElementNS(r,`svg`);m.setAttribute(`width`,`20`),m.setAttribute(`height`,`20`),m.setAttribute(`fill`,l),m.setAttribute(`viewBox`,`70 0 290 210`);let h=document.createElementNS(r,`path`);if(h.setAttribute(`d`,`M331.2,128.8c1.6-4.8,2.4-11.2,2.4-16.8c0-20.8-12.8-40-31.2-48.8c-8-36-47.2-63.2-92.8-63.2c-48,0-88,29.6-93.6,68.8C102.4,79.2,94.4,95.2,94.4,112c0,4.8,0.8,9.6,1.6,13.6c-7.2,9.6-10.4,20.8-10.4,32C85.6,180,100,200,120,208l85.6,212.8c1.6,3.2,4,4.8,7.2,4.8s6.4-1.6,7.2-4.8L305.6,208c20-8,34.4-27.2,34.4-50.4C340,147.2,336.8,136.8,331.2,128.8z M285.6,196c-9.6,0-19.2-4-26.4-11.2c-1.6-1.6-4.8-2.4-7.2-2.4c-2.4,0.8-4.8,2.4-5.6,4.8c-6.4,13.6-20,23.2-35.2,23.2c-14.4,0-28-8.8-34.4-21.6c-0.8-2.4-3.2-4-5.6-4.8c-0.8,0-0.8,0-1.6,0c-1.6,0-4,0.8-5.6,2.4c-7.2,6.4-16,9.6-25.6,9.6c-20.8,0-38.4-16.8-38.4-38.4c0-9.6,3.2-18.4,9.6-24.8c1.6-2.4,2.4-5.6,1.6-8c-1.6-4-2.4-8.8-2.4-12.8c0-12.8,6.4-24.8,17.6-32c2.4-1.6,3.2-4,4-6.4c2.4-32,36.8-57.6,78.4-57.6c39.2,0,72.8,23.2,77.6,54.4c0.8,3.2,2.4,5.6,4.8,6.4c15.2,5.6,24.8,20,24.8,36c0,4.8-0.8,10.4-3.2,15.2c-0.8,2.4-0.8,5.6,0.8,8c4.8,6.4,8,14.4,8,23.2C323.2,179.2,306.4,196,285.6,196z`),m.appendChild(h),p.appendChild(m),o===`processing`||o===`ready`||o===`error`){let e=document.createElement(`span`);e.className=`scoop-dot scoop-dot--${o}`,p.appendChild(e)}d.appendChild(p);let g=document.createElement(`div`);g.className=`scoop-info`;let _=document.createElement(`div`);if(_.className=`scoop-name`,_.textContent=f,g.appendChild(_),o===`processing`||o===`error`){let e=document.createElement(`div`);e.className=`scoop-subtitle`,e.textContent=o===`processing`?`Working…`:`Error`,g.appendChild(e)}d.appendChild(g);let v=document.createElement(`div`);if(v.className=`scoop-actions`,o===`processing`){let e=document.createElement(`span`);e.className=`scoop-spin-dot`,v.appendChild(e)}else if(o===`error`){let e=document.createElement(`span`);e.className=`scoop-err-dot`,v.appendChild(e)}d.appendChild(v),d.addEventListener(`click`,()=>{this.selectScoop(t)}),d.addEventListener(`mouseenter`,()=>{if(this.expanded)return;let e=document.createElement(`div`);e.className=`scoop-fixed-tooltip`,e.textContent=f,document.body.appendChild(e);let t=d.getBoundingClientRect();e.style.top=`${t.top+t.height/2}px`,e.style.left=`${t.right+8}px`,d.__tip=e}),d.addEventListener(`mouseleave`,()=>{let e=d.__tip;e&&(e.remove(),d.__tip=null)}),s.appendChild(d)}this.callbacks.onScoopsChanged?.(e)}}selectScoop(e){this.selectedScoopJid=e.jid,this.refreshScoops(),this.callbacks.onScoopSelect(e);let t=new URL(window.location.href);e.isCone?t.searchParams.delete(`scoop`):t.searchParams.set(`scoop`,e.folder),history.replaceState(null,``,t.toString())}selectScoopByFolder(e){if(!this.orchestrator)return;let t=this.orchestrator.getScoops().find(t=>t.folder===e);t&&this.selectScoop(t)}setSelectedJid(e){this.selectedScoopJid=e,this.refreshScoops()}getSelectedScoopJid(){return this.selectedScoopJid}async deleteScoop(e){if(!this.orchestrator)return;let t=this.orchestrator.getScoop(e);if(t){if(t.isCone){alert(`Cannot delete the cone`);return}if(confirm(`Delete scoop "${t.name}"? This cannot be undone.`)){try{await this.orchestrator.unregisterScoop(e)}catch(e){let t=e instanceof Error?e.message:String(e);alert(t);return}this.selectedScoopJid===e&&(this.selectedScoopJid=null),this.refreshScoops(),Ai.info(`Scoop deleted`,{jid:e,name:t.name})}}}async createScoop(e,t=!1){if(!this.orchestrator)throw Error(`Orchestrator not set`);let n=t?`cone`:this.sanitizeFolderName(e)+`-scoop`,r=t?`cone_${Date.now()}`:`scoop_${n}_${Date.now()}`,i={jid:r,name:e,folder:n,trigger:t?void 0:`@${n}`,requiresTrigger:!t,isCone:t,type:t?`cone`:`scoop`,assistantLabel:t?`sliccy`:n,addedAt:new Date().toISOString()};return await this.orchestrator.registerScoop(i),this.refreshScoops(),Ai.info(`Scoop created`,{jid:r,name:e,isCone:t}),i}sanitizeFolderName(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``).slice(0,50)||`scoop`}render(){for(;this.container.firstChild;)this.container.removeChild(this.container.firstChild);let e=document.createElement(`div`);e.className=`scoops-panel`;let t=document.createElement(`button`);t.className=`scoops-hamburger`,t.dataset.tooltip=`Toggle navigation`,t.dataset.tooltipPos=`right`,t.setAttribute(`aria-label`,`Toggle navigation`),t.innerHTML=`<svg width="16" height="16" viewBox="0 0 20 20" fill="currentColor"><path d="M9.61805 16.2451C9.31922 15.958 9.30945 15.4834 9.59754 15.1855L14.5839 10.002L9.58485 4.80469C9.29677 4.50684 9.30653 4.03223 9.60536 3.74512C9.90223 3.45801 10.3778 3.4668 10.6649 3.76563L16.1649 9.48243C16.4452 9.77247 16.4452 10.2315 16.1649 10.5215L10.6776 16.2246C10.5311 16.3779 10.3339 16.4551 10.1376 16.4551C9.95008 16.4551 9.76258 16.3857 9.61805 16.2451Z"/><path d="M3.86805 16.2451C3.56922 15.958 3.55945 15.4834 3.84754 15.1855L8.83387 10.002L3.83485 4.80469C3.54677 4.50684 3.55653 4.03223 3.85536 3.74512C4.15223 3.45801 4.62782 3.4668 4.91493 3.76563L10.4149 9.48243C10.6952 9.77247 10.6952 10.2315 10.4149 10.5215L4.92763 16.2246C4.78114 16.3779 4.58388 16.4551 4.38759 16.4551C4.20008 16.4551 4.01258 16.3857 3.86805 16.2451Z"/></svg>`,t.addEventListener(`click`,()=>this.toggleExpanded()),e.appendChild(t);let n=document.createElement(`div`);n.className=`scoop-cone-header`,e.appendChild(n);let r=document.createElement(`div`);r.className=`scoops-list`,e.appendChild(r),this.container.appendChild(e);let i=document.createElement(`style`);i.textContent=`
180
180
  .scoops-panel {
181
181
  display: flex;
@@ -2638,7 +2638,7 @@ Aliases: ${eU.filter(t=>t!==e).join(`, `)}`}function UU(e){let t=[],n={};for(let
2638
2638
  `,exitCode:1};break}let e=WU(l);if(`error`in e){u={stdout:``,stderr:e.error,exitCode:1};break}await t.withTab(e.targetId,async()=>{await t.evaluate(`sessionStorage.setItem(${JSON.stringify(c[0])}, ${JSON.stringify(c.slice(1).join(` `))})`)}),u={stdout:`sessionStorage "${c[0]}" set\n`,stderr:``,exitCode:0};break}case`sessionstorage-delete`:{if(c.length===0){u={stdout:``,stderr:`sessionstorage-delete requires a key
2639
2639
  `,exitCode:1};break}let e=WU(l);if(`error`in e){u={stdout:``,stderr:e.error,exitCode:1};break}await t.withTab(e.targetId,async()=>{await t.evaluate(`sessionStorage.removeItem(${JSON.stringify(c[0])})`)}),u={stdout:`sessionStorage "${c[0]}" deleted\n`,stderr:``,exitCode:0};break}case`sessionstorage-clear`:{let e=WU(l);if(`error`in e){u={stdout:``,stderr:e.error,exitCode:1};break}await t.withTab(e.targetId,async()=>{await t.evaluate(`sessionStorage.clear()`)}),u={stdout:`sessionStorage cleared
2640
2640
  `,stderr:``,exitCode:0};break}case`record`:{let e=c[0]||`about:blank`,r=l.filter;await gU(t,i);let a=await t.createPage(e),o=t.getTransport(),s=(await o.send(`Target.attachToTarget`,{targetId:a,flatten:!0})).sessionId;i.harRecorder||=new xe(o,n);let d=await i.harRecorder.startRecording(a,s,r);u={stdout:`Recording started (targetId: ${a}, recordingId: ${d}) at ${e}\nHAR saved to /recordings/${d}/\n`,stderr:``,exitCode:0};break}case`stop-recording`:{if(c.length===0){u={stdout:``,stderr:`stop-recording requires a recordingId
2641
- `,exitCode:1};break}let e=c[0];if(!i.harRecorder){u={stdout:``,stderr:`Recording not found: ${e}\n`,exitCode:1};break}u={stdout:`Recording stopped. HAR files saved to ${await i.harRecorder.stopRecording(e)}\n`,stderr:``,exitCode:0};break}default:u={stdout:``,stderr:`Unknown command: ${o}\nRun "playwright-cli help" for usage.\n`,exitCode:1};break}}catch(e){u={stdout:``,stderr:`Error: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}let d=l.tab??null,f=null;nU.has(o)&&u.exitCode===0&&d&&(f=await dU(t,n,i,d));try{await fU(n,i,{command:o,args:s,result:u,snapshotPath:f,targetId:d})}catch{}return u})}var KU=new Map([[`File operations`,[`ls`,`cat`,`head`,`tail`,`wc`,`touch`,`mkdir`,`rm`,`cp`,`mv`,`ln`,`chmod`,`stat`,`readlink`]],[`Text processing`,[`grep`,`sed`,`awk`,`sort`,`uniq`,`cut`,`tr`,`tee`,`diff`]],[`Search`,[`find`,`rg`]],[`Navigation & paths`,[`pwd`,`basename`,`dirname`,`tree`,`du`,`cd`]],[`Archives`,[`zip`,`unzip`,`pdftk`,`pdf`]],[`Media`,[`convert`,`magick`]],[`Audio`,[`say`,`afplay`,`chime`]],[`Environment & shell`,[`echo`,`printf`,`env`,`printenv`,`export`,`alias`,`unalias`,`history`,`clear`,`true`,`false`,`bash`,`sh`,`commands`,`which`,`uname`,`host`,`oauth-token`,`nuke`]],[`Data processing`,[`xargs`,`jq`,`base64`,`date`]],[`Network`,[`curl`,`wget`,`html-to-markdown`]],[`Version control`,[`git`]],[`Languages`,[`node`,`python`,`python3`,`sqlite3`]],[`Skills`,[`skill`,`upskill`]],[`Browser & UI`,[`serve`,`open`,`imgcat`,...eU,`webhook`]],[`Filesystem`,[`mount`]]]);function qU(e,t=[]){let n=[],r=new Set(e);n.push(`Available commands:
2641
+ `,exitCode:1};break}let e=c[0];if(!i.harRecorder){u={stdout:``,stderr:`Recording not found: ${e}\n`,exitCode:1};break}u={stdout:`Recording stopped. HAR files saved to ${await i.harRecorder.stopRecording(e)}\n`,stderr:``,exitCode:0};break}default:u={stdout:``,stderr:`Unknown command: ${o}\nRun "playwright-cli help" for usage.\n`,exitCode:1};break}}catch(e){u={stdout:``,stderr:`Error: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}let d=l.tab??null,f=null;nU.has(o)&&u.exitCode===0&&d&&(f=await dU(t,n,i,d));try{await fU(n,i,{command:o,args:s,result:u,snapshotPath:f,targetId:d})}catch{}return u})}var KU=new Map([[`File operations`,[`ls`,`cat`,`head`,`tail`,`wc`,`touch`,`mkdir`,`rm`,`cp`,`mv`,`ln`,`chmod`,`stat`,`readlink`]],[`Text processing`,[`grep`,`sed`,`awk`,`sort`,`uniq`,`cut`,`tr`,`tee`,`diff`]],[`Search`,[`find`,`rg`]],[`Navigation & paths`,[`pwd`,`basename`,`dirname`,`tree`,`du`,`cd`]],[`Archives`,[`zip`,`unzip`,`pdftk`,`pdf`]],[`Media`,[`convert`,`magick`]],[`Audio`,[`say`,`afplay`,`chime`]],[`Environment & shell`,[`echo`,`printf`,`env`,`printenv`,`export`,`alias`,`unalias`,`history`,`clear`,`true`,`false`,`bash`,`sh`,`commands`,`which`,`uname`,`man`,`host`,`oauth-token`,`nuke`]],[`Data processing`,[`xargs`,`jq`,`base64`,`date`]],[`Network`,[`curl`,`wget`,`html-to-markdown`]],[`Version control`,[`git`]],[`Languages`,[`node`,`python`,`python3`,`sqlite3`]],[`Skills`,[`skill`,`upskill`]],[`Browser & UI`,[`serve`,`open`,`imgcat`,...eU,`webhook`]],[`Filesystem`,[`mount`]]]);function qU(e,t=[]){let n=[],r=new Set(e);n.push(`Available commands:
2642
2642
  `);let i=[];for(let[e,t]of KU){let i=t.filter(e=>r.has(e));if(i.length>0){n.push(` ${e}:`),n.push(` ${i.join(`, `)}\n`);for(let e of i)r.delete(e)}}for(let e of r)i.push(e);return i.length>0&&(n.push(` Other:`),n.push(` ${i.sort().join(`, `)}\n`)),t.length>0&&(n.push(` User scripts (.jsh):`),n.push(` ${t.sort().join(`, `)}\n`)),n.push(`Use '<command> --help' for details on a specific command.`),n.join(`
2643
2643
  `)+`
2644
2644
  `}function JU(e={}){return qP(`commands`,async(t,n)=>{if(t.includes(`--help`)||t.includes(`-h`))return{stdout:`commands - display available commands
@@ -2766,7 +2766,7 @@ except BaseException:
2766
2766
  `,stderr:``,exitCode:0}}function tG(e){let t=``,n=8192;for(let r=0;r<e.length;r+=n)t+=String.fromCharCode(...e.subarray(r,r+n));return btoa(t)}function nG(){return qP(`open`,async(e,t)=>{if(e.length===0||e.includes(`--help`)||e.includes(`-h`))return eG();if(typeof window>`u`||typeof document>`u`)return{stdout:``,stderr:`open: browser APIs are unavailable in this environment
2767
2767
  `,exitCode:1};let n=e.includes(`--download`)||e.includes(`-d`),r=e.includes(`--view`)||e.includes(`-v`),i=e.filter(e=>!$W.includes(e));if(i.length===0)return eG();let a=[];for(let e of i){if(LW(e)){window.open(e,`_blank`,`noopener,noreferrer`),a.push(`opened ${e}`);continue}let i=t.fs.resolvePath(t.cwd,e);if(i.endsWith(`.shtml`)){let e=typeof window<`u`?window.__slicc_sprinkleManager:void 0;if(e){let t=(i.split(`/`).pop()??``).replace(/\.shtml$/,``);try{await e.open(t),a.push(`opened sprinkle ${t} from ${i}`)}catch(e){return{stdout:``,stderr:`open: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}}else{let e=HW(i);window.open(e,`_blank`,`noopener,noreferrer`),a.push(`opened ${i} → ${e}`)}continue}if(r){let n;try{n=await t.fs.stat(i)}catch{return{stdout:``,stderr:`open: no such file: ${e}\n`,exitCode:1}}if(!n.isFile)return{stdout:``,stderr:`open: not a file: ${e}\n`,exitCode:1};let r;try{r=await t.fs.readFileBuffer(i)}catch{return{stdout:``,stderr:`open: failed to read: ${e}\n`,exitCode:1}}let o=VW(i),s=tG(new Uint8Array(r));a.push(`${i} (${Math.round(r.byteLength/1024)} KB)\n<img:data:${o};base64,${s}>`)}else if(n){let n;try{n=await t.fs.stat(i)}catch{return{stdout:``,stderr:`open: no such file: ${e}\n`,exitCode:1}}if(!n.isFile)return{stdout:``,stderr:`open: not a file: ${e}\n`,exitCode:1};let r;try{r=await t.fs.readFileBuffer(i)}catch{return{stdout:``,stderr:`open: failed to read: ${e}\n`,exitCode:1}}let o=new Uint8Array(r.byteLength);o.set(r);let s=new Blob([o.buffer],{type:VW(i)}),c=URL.createObjectURL(s),l=document.createElement(`a`);l.href=c,l.download=PW(i)||`download`,l.style.display=`none`,document.body.appendChild(l),l.click(),document.body.removeChild(l),setTimeout(()=>URL.revokeObjectURL(c),0),a.push(`downloaded ${i}`)}else{let e=HW(i);window.open(e,`_blank`,`noopener,noreferrer`),a.push(`opened ${i} → ${e}`)}}return{stdout:a.join(`
2768
2768
  `)+`
2769
- `,stderr:``,exitCode:0}})}var rG=null,iG=null;async function aG(){return rG||=y(()=>import(`./es-DoVXtjfC.js`),__vite__mapDeps([5,1,2])),rG}async function oG(){return iG||=y(()=>import(`./dist-BWlKscHB.js`),__vite__mapDeps([6,4])),iG}function sG(e){return e.endsWith(`right`)?{range:e.slice(0,-5),rotation:90}:e.endsWith(`left`)?{range:e.slice(0,-4),rotation:270}:e.endsWith(`down`)?{range:e.slice(0,-4),rotation:180}:{range:e}}function cG(e){let{range:t,rotation:n}=sG(e);if(/^\d+$/.test(t)){let e=parseInt(t,10);return{start:e,end:e,rotation:n}}let r=t.match(/^(\d+)-(\d+|end)$/);if(r)return{start:parseInt(r[1],10),end:r[2]===`end`?`end`:parseInt(r[2],10),rotation:n};throw Error(`Invalid page range: ${e}`)}function lG(e,t){let n=e.start,r=e.end;if(n<1||n>t)throw Error(`Page ${n} out of range (1-${t})`);let i=r===`end`?t:r;if(i<1||i>t)throw Error(`Page ${i} out of range (1-${t})`);if(i<n)throw Error(`Invalid range: ${n}-${i}`);let a=[];for(let e=n;e<=i;e++)a.push(e);return a}function uG(){return{stdout:`usage: pdftk <input.pdf> <operation> [args...]
2769
+ `,stderr:``,exitCode:0}})}var rG=null,iG=null;async function aG(){return rG||=y(()=>import(`./es-CztekvDk.js`),__vite__mapDeps([5,1,2])),rG}async function oG(){return iG||=y(()=>import(`./dist-BWlKscHB.js`),__vite__mapDeps([6,4])),iG}function sG(e){return e.endsWith(`right`)?{range:e.slice(0,-5),rotation:90}:e.endsWith(`left`)?{range:e.slice(0,-4),rotation:270}:e.endsWith(`down`)?{range:e.slice(0,-4),rotation:180}:{range:e}}function cG(e){let{range:t,rotation:n}=sG(e);if(/^\d+$/.test(t)){let e=parseInt(t,10);return{start:e,end:e,rotation:n}}let r=t.match(/^(\d+)-(\d+|end)$/);if(r)return{start:parseInt(r[1],10),end:r[2]===`end`?`end`:parseInt(r[2],10),rotation:n};throw Error(`Invalid page range: ${e}`)}function lG(e,t){let n=e.start,r=e.end;if(n<1||n>t)throw Error(`Page ${n} out of range (1-${t})`);let i=r===`end`?t:r;if(i<1||i>t)throw Error(`Page ${i} out of range (1-${t})`);if(i<n)throw Error(`Invalid range: ${n}-${i}`);let a=[];for(let e=n;e<=i;e++)a.push(e);return a}function uG(){return{stdout:`usage: pdftk <input.pdf> <operation> [args...]
2770
2770
 
2771
2771
  Operations:
2772
2772
  dump_data Print metadata (page count, title, author, etc.)
@@ -2814,9 +2814,15 @@ Page ranges:
2814
2814
  `)}\n`:``,stderr:``,exitCode:0}}catch(t){return{stdout:``,stderr:`${e}: ${t instanceof Error?t.message:String(t)}\n`,exitCode:1}}})}function SG(){return{stdout:`usage: uname
2815
2815
  `,stderr:``,exitCode:0}}function CG(){return qP(`uname`,async e=>{if(e.includes(`--help`)||e.includes(`-h`))return SG();if(e.length>0)return{stdout:``,stderr:`uname: unsupported arguments
2816
2816
  `,exitCode:1};let t=globalThis.navigator?.userAgent;return typeof t!=`string`||t.length===0?{stdout:``,stderr:`uname: navigator.userAgent is unavailable
2817
- `,exitCode:1}:{stdout:`${t}\n`,stderr:``,exitCode:0}})}function wG(){return{stdout:`usage: unzip <archive.zip> [-d <destination>]
2818
- `,stderr:``,exitCode:0}}function TG(){return qP(`unzip`,async(e,t)=>{if(e.length===0||e.includes(`--help`)||e.includes(`-h`))return wG();let n=`.`,r=[];for(let t=0;t<e.length;t++){let i=e[t];if(i===`-d`){n=e[t+1]??``,t++;continue}if(i.startsWith(`-`))return{stdout:``,stderr:`unzip: unsupported option ${i}\n`,exitCode:1};r.push(i)}if(r.length<1)return{stdout:``,stderr:`unzip: expected archive path
2819
- `,exitCode:1};let i=t.fs.resolvePath(t.cwd,r[0]),a=t.fs.resolvePath(t.cwd,n||`.`);await t.fs.mkdir(a,{recursive:!0});let o=le(await t.fs.readFileBuffer(i)),s=0;for(let[e,n]of Object.entries(o)){let r=e.replace(/\\/g,`/`);if(!r||r.endsWith(`/`))continue;let i=t.fs.resolvePath(a,r);if(!RW(a,i))return{stdout:``,stderr:`unzip: blocked suspicious path ${e}\n`,exitCode:1};let o=FW(i);o!==`/`&&await t.fs.mkdir(o,{recursive:!0}),await t.fs.writeFile(i,n),s++}return{stdout:`extracted ${s} file(s) to ${a}\n`,stderr:``,exitCode:0}})}function EG(){return{stdout:`usage: webhook <command> [options]
2817
+ `,exitCode:1}:{stdout:`${t}\n`,stderr:``,exitCode:0}})}function wG(){return{stdout:`usage: man <topic>
2818
+
2819
+ Fetches documentation for a given topic from sliccy.com.
2820
+ `,stderr:``,exitCode:0}}function TG(e){return e.replace(/<[^>]*>/g,``).replace(/&amp;/g,`&`).replace(/&lt;/g,`<`).replace(/&gt;/g,`>`).replace(/&quot;/g,`"`).replace(/&#39;/g,`'`).replace(/&nbsp;/g,` `).trimEnd()}function EG(){return qP(`man`,async e=>{if(e.includes(`--help`)||e.includes(`-h`))return wG();if(e.length===0)return{stdout:``,stderr:`What manual page do you want?
2821
+ For example, try 'man commands'.
2822
+ `,exitCode:1};let t=e.join(`-`),n=`https://www.sliccy.com/man/${t}.plain.html`;try{let e=await fetch(n);return e.status===404?{stdout:``,stderr:`No manual entry for ${t}\n`,exitCode:1}:e.ok?{stdout:TG(await e.text())+`
2823
+ `,stderr:``,exitCode:0}:{stdout:``,stderr:`man: failed to fetch manual page for ${t}: ${e.status} ${e.statusText}\n`,exitCode:1}}catch(e){return{stdout:``,stderr:`man: ${e.message||String(e)}\n`,exitCode:1}}})}function DG(){return{stdout:`usage: unzip <archive.zip> [-d <destination>]
2824
+ `,stderr:``,exitCode:0}}function OG(){return qP(`unzip`,async(e,t)=>{if(e.length===0||e.includes(`--help`)||e.includes(`-h`))return DG();let n=`.`,r=[];for(let t=0;t<e.length;t++){let i=e[t];if(i===`-d`){n=e[t+1]??``,t++;continue}if(i.startsWith(`-`))return{stdout:``,stderr:`unzip: unsupported option ${i}\n`,exitCode:1};r.push(i)}if(r.length<1)return{stdout:``,stderr:`unzip: expected archive path
2825
+ `,exitCode:1};let i=t.fs.resolvePath(t.cwd,r[0]),a=t.fs.resolvePath(t.cwd,n||`.`);await t.fs.mkdir(a,{recursive:!0});let o=le(await t.fs.readFileBuffer(i)),s=0;for(let[e,n]of Object.entries(o)){let r=e.replace(/\\/g,`/`);if(!r||r.endsWith(`/`))continue;let i=t.fs.resolvePath(a,r);if(!RW(a,i))return{stdout:``,stderr:`unzip: blocked suspicious path ${e}\n`,exitCode:1};let o=FW(i);o!==`/`&&await t.fs.mkdir(o,{recursive:!0}),await t.fs.writeFile(i,n),s++}return{stdout:`extracted ${s} file(s) to ${a}\n`,stderr:``,exitCode:0}})}function kG(){return{stdout:`usage: webhook <command> [options]
2820
2826
 
2821
2827
  Commands:
2822
2828
  create --scoop <name> [--name <name>] [--filter <code>] Create a new webhook endpoint
@@ -2834,12 +2840,12 @@ Examples:
2834
2840
  webhook create --scoop slack-relay --name slack --filter "(e) => ({ text: e.body.text, user: e.body.user })"
2835
2841
  webhook list
2836
2842
  webhook delete abc123
2837
- `,stderr:``,exitCode:0}}async function DG(e,t,n){if(typeof chrome<`u`&&chrome?.runtime?.id)throw Error(`Webhooks are only available in CLI mode (npm run dev:full)`);let r={method:e,headers:{"Content-Type":`application/json`}};n&&(r.body=JSON.stringify(n));let i=await fetch(`/api/webhooks${t}`,r),a=await i.json().catch(()=>({}));return{ok:i.ok,status:i.status,data:a}}function OG(){return qP(`webhook`,async e=>{if(e.length===0||e.includes(`--help`)||e.includes(`-h`))return EG();let t=e[0];try{switch(t){case`create`:{let t=`default`,n,r,i=e.indexOf(`--name`);i!==-1&&e[i+1]&&(t=e[i+1]);let a=e.indexOf(`--filter`);a!==-1&&e[a+1]&&(n=e[a+1]);let o=e.indexOf(`--scoop`);if(o!==-1&&e[o+1]&&(r=e[o+1]),!r)return{stdout:``,stderr:`webhook: --scoop is required (every webhook must route to a scoop)
2838
- `,exitCode:1};let{ok:s,data:c}=await DG(`POST`,``,{name:t,filter:n,scoop:r});if(!s)return{stdout:``,stderr:`webhook: failed to create webhook: ${c.error??`unknown error`}\n`,exitCode:1};let l=c,u=`Created webhook "${l.name}"\nID: ${l.id}\nURL: ${l.url}\n`;return l.scoop&&(u+=`Scoop: ${l.scoop}\n`),l.filter&&(u+=`Filter: ${l.filter}\n`),{stdout:u,stderr:``,exitCode:0}}case`list`:{let{ok:e,data:t}=await DG(`GET`,``);if(!e)return{stdout:``,stderr:`webhook: failed to list webhooks: ${t.error??`unknown error`}\n`,exitCode:1};let n=t;if(n.length===0)return{stdout:`No active webhooks
2843
+ `,stderr:``,exitCode:0}}async function AG(e,t,n){if(typeof chrome<`u`&&chrome?.runtime?.id)throw Error(`Webhooks are only available in CLI mode (npm run dev:full)`);let r={method:e,headers:{"Content-Type":`application/json`}};n&&(r.body=JSON.stringify(n));let i=await fetch(`/api/webhooks${t}`,r),a=await i.json().catch(()=>({}));return{ok:i.ok,status:i.status,data:a}}function jG(){return qP(`webhook`,async e=>{if(e.length===0||e.includes(`--help`)||e.includes(`-h`))return kG();let t=e[0];try{switch(t){case`create`:{let t=`default`,n,r,i=e.indexOf(`--name`);i!==-1&&e[i+1]&&(t=e[i+1]);let a=e.indexOf(`--filter`);a!==-1&&e[a+1]&&(n=e[a+1]);let o=e.indexOf(`--scoop`);if(o!==-1&&e[o+1]&&(r=e[o+1]),!r)return{stdout:``,stderr:`webhook: --scoop is required (every webhook must route to a scoop)
2844
+ `,exitCode:1};let{ok:s,data:c}=await AG(`POST`,``,{name:t,filter:n,scoop:r});if(!s)return{stdout:``,stderr:`webhook: failed to create webhook: ${c.error??`unknown error`}\n`,exitCode:1};let l=c,u=`Created webhook "${l.name}"\nID: ${l.id}\nURL: ${l.url}\n`;return l.scoop&&(u+=`Scoop: ${l.scoop}\n`),l.filter&&(u+=`Filter: ${l.filter}\n`),{stdout:u,stderr:``,exitCode:0}}case`list`:{let{ok:e,data:t}=await AG(`GET`,``);if(!e)return{stdout:``,stderr:`webhook: failed to list webhooks: ${t.error??`unknown error`}\n`,exitCode:1};let n=t;if(n.length===0)return{stdout:`No active webhooks
2839
2845
  `,stderr:``,exitCode:0};let r=`Active webhooks:
2840
2846
  `;for(let e of n)r+=` ${e.id} ${e.name.padEnd(20)} ${e.url}`,e.scoop&&(r+=` -> ${e.scoop}`),e.filter&&(r+=` [filtered]`),r+=`
2841
2847
  `;return{stdout:r,stderr:``,exitCode:0}}case`delete`:{let t=e[1];if(!t)return{stdout:``,stderr:`webhook: delete requires an ID
2842
- `,exitCode:1};let{ok:n,status:r,data:i}=await DG(`DELETE`,`/${t}`);return n?{stdout:`Deleted webhook "${t}"\n`,stderr:``,exitCode:0}:r===404?{stdout:``,stderr:`webhook: webhook "${t}" not found\n`,exitCode:1}:{stdout:``,stderr:`webhook: failed to delete webhook: ${i.error??`unknown error`}\n`,exitCode:1}}default:return{stdout:``,stderr:`webhook: unknown command "${t}"\n`,exitCode:1}}}catch(e){return{stdout:``,stderr:`webhook: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}})}function kG(){return{stdout:`usage: crontask <command> [options]
2848
+ `,exitCode:1};let{ok:n,status:r,data:i}=await AG(`DELETE`,`/${t}`);return n?{stdout:`Deleted webhook "${t}"\n`,stderr:``,exitCode:0}:r===404?{stdout:``,stderr:`webhook: webhook "${t}" not found\n`,exitCode:1}:{stdout:``,stderr:`webhook: failed to delete webhook: ${i.error??`unknown error`}\n`,exitCode:1}}default:return{stdout:``,stderr:`webhook: unknown command "${t}"\n`,exitCode:1}}}catch(e){return{stdout:``,stderr:`webhook: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}})}function MG(){return{stdout:`usage: crontask <command> [options]
2843
2849
 
2844
2850
  Commands:
2845
2851
  create [options] Create a new cron task
@@ -2871,16 +2877,16 @@ Examples:
2871
2877
  crontask create --name every-5min --scoop poller --cron "*/5 * * * *" --filter "() => ({ time: Date.now() })"
2872
2878
  crontask list
2873
2879
  crontask delete abc123
2874
- `,stderr:``,exitCode:0}}var AG=typeof chrome<`u`&&!!chrome?.runtime?.id;function jG(){return globalThis.__slicc_lickManager??null}var MG=null;async function NG(){if(MG)return MG;let{createLickManagerProxy:e}=await y(async()=>{let{createLickManagerProxy:e}=await import(`./lick-manager-proxy-BZUMVDTP.js`);return{createLickManagerProxy:e}},[]);return MG=e(),MG}async function PG(e,t,n){let r={method:e,headers:{"Content-Type":`application/json`}};n&&(r.body=JSON.stringify(n));let i=await fetch(`/api/crontasks${t}`,r),a=await i.json().catch(()=>({}));return{ok:i.ok,status:i.status,data:a}}function FG(){return qP(`crontask`,async e=>{if(e.length===0||e.includes(`--help`)||e.includes(`-h`))return kG();let t=e[0];try{switch(t){case`create`:{let t,n,r,i,a=e.indexOf(`--name`);a!==-1&&e[a+1]&&(t=e[a+1]);let o=e.indexOf(`--cron`);o!==-1&&e[o+1]&&(n=e[o+1]);let s=e.indexOf(`--filter`);s!==-1&&e[s+1]&&(r=e[s+1]);let c=e.indexOf(`--scoop`);if(c!==-1&&e[c+1]&&(i=e[c+1]),!t)return{stdout:``,stderr:`crontask: --name is required
2880
+ `,stderr:``,exitCode:0}}var NG=typeof chrome<`u`&&!!chrome?.runtime?.id;function PG(){return globalThis.__slicc_lickManager??null}var FG=null;async function IG(){if(FG)return FG;let{createLickManagerProxy:e}=await y(async()=>{let{createLickManagerProxy:e}=await import(`./lick-manager-proxy-BZUMVDTP.js`);return{createLickManagerProxy:e}},[]);return FG=e(),FG}async function LG(e,t,n){let r={method:e,headers:{"Content-Type":`application/json`}};n&&(r.body=JSON.stringify(n));let i=await fetch(`/api/crontasks${t}`,r),a=await i.json().catch(()=>({}));return{ok:i.ok,status:i.status,data:a}}function RG(){return qP(`crontask`,async e=>{if(e.length===0||e.includes(`--help`)||e.includes(`-h`))return MG();let t=e[0];try{switch(t){case`create`:{let t,n,r,i,a=e.indexOf(`--name`);a!==-1&&e[a+1]&&(t=e[a+1]);let o=e.indexOf(`--cron`);o!==-1&&e[o+1]&&(n=e[o+1]);let s=e.indexOf(`--filter`);s!==-1&&e[s+1]&&(r=e[s+1]);let c=e.indexOf(`--scoop`);if(c!==-1&&e[c+1]&&(i=e[c+1]),!t)return{stdout:``,stderr:`crontask: --name is required
2875
2881
  `,exitCode:1};if(!n)return{stdout:``,stderr:`crontask: --cron is required
2876
- `,exitCode:1};if(AG){if(r)return{stdout:``,stderr:`crontask: --filter is not supported in extension mode (CSP restriction)
2877
- `,exitCode:1};let e=jG(),a=e?await e.createCronTask(t,n,i):await(await NG()).createCronTask(t,n,i),o=`Created cron task "${a.name}"\n`;return o+=`ID: ${a.id}\n`,o+=`Cron: ${a.cron}\n`,a.scoop&&(o+=`Scoop: ${a.scoop}\n`),a.nextRun&&(o+=`Next run: ${new Date(a.nextRun).toLocaleString()}\n`),{stdout:o,stderr:``,exitCode:0}}let{ok:l,data:u}=await PG(`POST`,``,{name:t,cron:n,filter:r,scoop:i});if(!l)return{stdout:``,stderr:`crontask: failed to create: ${u.error??`unknown error`}\n`,exitCode:1};let d=u,f=`Created cron task "${d.name}"\n`;return f+=`ID: ${d.id}\n`,f+=`Cron: ${d.cron}\n`,d.scoop&&(f+=`Scoop: ${d.scoop}\n`),d.filter&&(f+=`Filter: ${d.filter}\n`),d.nextRun&&(f+=`Next run: ${new Date(d.nextRun).toLocaleString()}\n`),{stdout:f,stderr:``,exitCode:0}}case`list`:{if(AG){let e=jG(),t=e?e.listCronTasks():await(async()=>{let{listCronTasksAsync:e}=await y(async()=>{let{listCronTasksAsync:e}=await import(`./lick-manager-proxy-BZUMVDTP.js`);return{listCronTasksAsync:e}},[]);return e()})();if(t.length===0)return{stdout:`No active cron tasks
2882
+ `,exitCode:1};if(NG){if(r)return{stdout:``,stderr:`crontask: --filter is not supported in extension mode (CSP restriction)
2883
+ `,exitCode:1};let e=PG(),a=e?await e.createCronTask(t,n,i):await(await IG()).createCronTask(t,n,i),o=`Created cron task "${a.name}"\n`;return o+=`ID: ${a.id}\n`,o+=`Cron: ${a.cron}\n`,a.scoop&&(o+=`Scoop: ${a.scoop}\n`),a.nextRun&&(o+=`Next run: ${new Date(a.nextRun).toLocaleString()}\n`),{stdout:o,stderr:``,exitCode:0}}let{ok:l,data:u}=await LG(`POST`,``,{name:t,cron:n,filter:r,scoop:i});if(!l)return{stdout:``,stderr:`crontask: failed to create: ${u.error??`unknown error`}\n`,exitCode:1};let d=u,f=`Created cron task "${d.name}"\n`;return f+=`ID: ${d.id}\n`,f+=`Cron: ${d.cron}\n`,d.scoop&&(f+=`Scoop: ${d.scoop}\n`),d.filter&&(f+=`Filter: ${d.filter}\n`),d.nextRun&&(f+=`Next run: ${new Date(d.nextRun).toLocaleString()}\n`),{stdout:f,stderr:``,exitCode:0}}case`list`:{if(NG){let e=PG(),t=e?e.listCronTasks():await(async()=>{let{listCronTasksAsync:e}=await y(async()=>{let{listCronTasksAsync:e}=await import(`./lick-manager-proxy-BZUMVDTP.js`);return{listCronTasksAsync:e}},[]);return e()})();if(t.length===0)return{stdout:`No active cron tasks
2878
2884
  `,stderr:``,exitCode:0};let n=`Active cron tasks:
2879
2885
  `;for(let e of t)n+=` ${e.id} ${e.name.padEnd(20)} ${e.cron.padEnd(15)}`,e.scoop&&(n+=` -> ${e.scoop}`),e.filter&&(n+=` [filtered]`),n+=` (${e.status})`,e.nextRun&&(n+=` next: ${new Date(e.nextRun).toLocaleString()}`),n+=`
2880
- `;return{stdout:n,stderr:``,exitCode:0}}let{ok:e,data:t}=await PG(`GET`,``);if(!e)return{stdout:``,stderr:`crontask: failed to list: ${t.error??`unknown error`}\n`,exitCode:1};let n=t;if(n.length===0)return{stdout:`No active cron tasks
2886
+ `;return{stdout:n,stderr:``,exitCode:0}}let{ok:e,data:t}=await LG(`GET`,``);if(!e)return{stdout:``,stderr:`crontask: failed to list: ${t.error??`unknown error`}\n`,exitCode:1};let n=t;if(n.length===0)return{stdout:`No active cron tasks
2881
2887
  `,stderr:``,exitCode:0};let r=`Active cron tasks:
2882
2888
  `;for(let e of n)r+=` ${e.id} ${e.name.padEnd(20)} ${e.cron.padEnd(15)}`,e.scoop&&(r+=` -> ${e.scoop}`),e.filter&&(r+=` [filtered]`),r+=` (${e.status})`,e.nextRun&&(r+=` next: ${new Date(e.nextRun).toLocaleString()}`),r+=`
2883
- `;return{stdout:r,stderr:``,exitCode:0}}case`delete`:case`kill`:{let n=e[1];if(!n)return{stdout:``,stderr:`crontask: ${t} requires an ID\n`,exitCode:1};if(AG){let e=jG();return(e?await e.deleteCronTask(n):await(await NG()).deleteCronTask(n))?{stdout:`Deleted cron task "${n}"\n`,stderr:``,exitCode:0}:{stdout:``,stderr:`crontask: task "${n}" not found\n`,exitCode:1}}let{ok:r,status:i,data:a}=await PG(`DELETE`,`/${n}`);return r?{stdout:`Deleted cron task "${n}"\n`,stderr:``,exitCode:0}:i===404?{stdout:``,stderr:`crontask: task "${n}" not found\n`,exitCode:1}:{stdout:``,stderr:`crontask: failed to delete: ${a.error??`unknown error`}\n`,exitCode:1}}default:return{stdout:``,stderr:`crontask: unknown command "${t}"\n`,exitCode:1}}}catch(e){return{stdout:``,stderr:`crontask: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}})}function IG(){return{stdout:`usage: sprinkle <subcommand> [args]
2889
+ `;return{stdout:r,stderr:``,exitCode:0}}case`delete`:case`kill`:{let n=e[1];if(!n)return{stdout:``,stderr:`crontask: ${t} requires an ID\n`,exitCode:1};if(NG){let e=PG();return(e?await e.deleteCronTask(n):await(await IG()).deleteCronTask(n))?{stdout:`Deleted cron task "${n}"\n`,stderr:``,exitCode:0}:{stdout:``,stderr:`crontask: task "${n}" not found\n`,exitCode:1}}let{ok:r,status:i,data:a}=await LG(`DELETE`,`/${n}`);return r?{stdout:`Deleted cron task "${n}"\n`,stderr:``,exitCode:0}:i===404?{stdout:``,stderr:`crontask: task "${n}" not found\n`,exitCode:1}:{stdout:``,stderr:`crontask: failed to delete: ${a.error??`unknown error`}\n`,exitCode:1}}default:return{stdout:``,stderr:`crontask: unknown command "${t}"\n`,exitCode:1}}}catch(e){return{stdout:``,stderr:`crontask: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}})}function zG(){return{stdout:`usage: sprinkle <subcommand> [args]
2884
2890
 
2885
2891
  list List available .shtml sprinkles
2886
2892
  open <name> Open a sprinkle by name
@@ -2890,10 +2896,10 @@ Examples:
2890
2896
  chat <html> Show inline HTML in chat (Tool UI)
2891
2897
  Use data-action="name" on buttons for callbacks
2892
2898
  Pipe HTML: echo "<div>...</div>" | sprinkle chat
2893
- `,stderr:``,exitCode:0}}function LG(){return typeof window>`u`?null:window.__slicc_sprinkleManager??null}function RG(){return qP(`sprinkle`,async(e,t)=>{if(e.length===0||e[0]===`--help`||e[0]===`-h`)return IG();let n=e[0];if(n===`chat`){let n=e.slice(1).join(` `);if(!n&&t.stdin&&(n=t.stdin),!n)return{stdout:``,stderr:`sprinkle chat: HTML content required
2899
+ `,stderr:``,exitCode:0}}function BG(){return typeof window>`u`?null:window.__slicc_sprinkleManager??null}function VG(){return qP(`sprinkle`,async(e,t)=>{if(e.length===0||e[0]===`--help`||e[0]===`-h`)return zG();let n=e[0];if(n===`chat`){let n=e.slice(1).join(` `);if(!n&&t.stdin&&(n=t.stdin),!n)return{stdout:``,stderr:`sprinkle chat: HTML content required
2894
2900
  `,exitCode:1};let r=await _({html:n,onAction:async(e,t)=>({action:e,data:t})});return r===null?{stdout:``,stderr:`sprinkle chat: not in tool execution context
2895
2901
  `,exitCode:1}:{stdout:JSON.stringify(r)+`
2896
- `,stderr:``,exitCode:0}}let r=LG();if(!r)return{stdout:``,stderr:`sprinkle: sprinkle manager not initialized
2902
+ `,stderr:``,exitCode:0}}let r=BG();if(!r)return{stdout:``,stderr:`sprinkle: sprinkle manager not initialized
2897
2903
  `,exitCode:1};switch(n){case`list`:{await r.refresh();let e=r.available();if(e.length===0)return{stdout:`No .shtml sprinkles found.
2898
2904
  `,stderr:``,exitCode:0};let t=new Set(r.opened());return{stdout:e.map(e=>{let n=t.has(e.name)?` [open]`:``;return` ${e.name}${n} ${e.title} (${e.path})`}).join(`
2899
2905
  `)+`
@@ -2902,7 +2908,7 @@ Examples:
2902
2908
  `,exitCode:1}}case`refresh`:{await r.refresh();let e=r.available().length;return{stdout:`Found ${e} sprinkle${e===1?``:`s`}.\n`,stderr:``,exitCode:0}}case`send`:{let t=e[1];if(!t)return{stdout:``,stderr:`sprinkle send: name required
2903
2909
  `,exitCode:1};let n=e.slice(2).join(` `);if(!n)return{stdout:``,stderr:`sprinkle send: JSON data required
2904
2910
  `,exitCode:1};let i;try{i=JSON.parse(n)}catch{return{stdout:``,stderr:`sprinkle send: invalid JSON
2905
- `,exitCode:1}}return r.sendToSprinkle(t,i),{stdout:`Data sent to sprinkle "${t}".\n`,stderr:``,exitCode:0}}default:return{stdout:``,stderr:`sprinkle: unknown subcommand "${n}"\n`,exitCode:1}}})}function zG(){return`oauth-token — get an OAuth access token for a provider
2911
+ `,exitCode:1}}return r.sendToSprinkle(t,i),{stdout:`Data sent to sprinkle "${t}".\n`,stderr:``,exitCode:0}}default:return{stdout:``,stderr:`sprinkle: unknown subcommand "${n}"\n`,exitCode:1}}})}function HG(){return`oauth-token — get an OAuth access token for a provider
2906
2912
 
2907
2913
  Usage:
2908
2914
  oauth-token <providerId> Get token for a specific provider
@@ -2918,13 +2924,13 @@ on success.
2918
2924
  Examples:
2919
2925
  oauth-token adobe
2920
2926
  curl -H "Authorization: Bearer $(oauth-token adobe)" https://api.corp.com/data
2921
- `}function BG(){return qP(`oauth-token`,async e=>{let{getOAuthAccountInfo:t,getSelectedProvider:n,getAccounts:r}=await y(async()=>{let{getOAuthAccountInfo:e,getSelectedProvider:t,getAccounts:n}=await import(`./provider-settings-BmUXXAz8.js`);return{getOAuthAccountInfo:e,getSelectedProvider:t,getAccounts:n}},__vite__mapDeps([7,8,1,4,9,10,11,12,13])),{getRegisteredProviderConfig:i,getRegisteredProviderIds:a}=await y(async()=>{let{getRegisteredProviderConfig:e,getRegisteredProviderIds:t}=await import(`./providers-C08JtA_W.js`);return{getRegisteredProviderConfig:e,getRegisteredProviderIds:t}},__vite__mapDeps([14,8,1,4,9,10,11,12,13]));if(e.includes(`--help`)||e.includes(`-h`))return{stdout:zG(),stderr:``,exitCode:0};if(e.includes(`--list`))return VG(r,a,i,t);let o,s=e.indexOf(`--provider`);if(s>=0){if(o=e[s+1],!o)return{stdout:``,stderr:`oauth-token: --provider requires a value
2927
+ `}function UG(){return qP(`oauth-token`,async e=>{let{getOAuthAccountInfo:t,getSelectedProvider:n,getAccounts:r}=await y(async()=>{let{getOAuthAccountInfo:e,getSelectedProvider:t,getAccounts:n}=await import(`./provider-settings-BmUXXAz8.js`);return{getOAuthAccountInfo:e,getSelectedProvider:t,getAccounts:n}},__vite__mapDeps([7,8,1,4,9,10,11,12,13])),{getRegisteredProviderConfig:i,getRegisteredProviderIds:a}=await y(async()=>{let{getRegisteredProviderConfig:e,getRegisteredProviderIds:t}=await import(`./providers-C08JtA_W.js`);return{getRegisteredProviderConfig:e,getRegisteredProviderIds:t}},__vite__mapDeps([14,8,1,4,9,10,11,12,13]));if(e.includes(`--help`)||e.includes(`-h`))return{stdout:HG(),stderr:``,exitCode:0};if(e.includes(`--list`))return WG(r,a,i,t);let o,s=e.indexOf(`--provider`);if(s>=0){if(o=e[s+1],!o)return{stdout:``,stderr:`oauth-token: --provider requires a value
2922
2928
  `,exitCode:1}}else if(e.length>0)o=e[0];else{let e=n(),t=i(e);if(t?.isOAuth&&t.onOAuthLogin)o=e;else if(o=a().find(e=>{let t=i(e);return t?.isOAuth&&t.onOAuthLogin}),!o)return{stdout:``,stderr:`oauth-token: no OAuth providers configured
2923
2929
  `,exitCode:1}}let c=i(o);if(!c)return{stdout:``,stderr:`oauth-token: unknown provider "${o}"\n`,exitCode:1};if(!c.isOAuth||!c.onOAuthLogin)return{stdout:``,stderr:`oauth-token: provider "${o}" is not an OAuth provider\n`,exitCode:1};let l=t(o);if(l&&!l.expired)return{stdout:`${l.token}\n`,stderr:``,exitCode:0};try{let{createOAuthLauncher:e}=await y(async()=>{let{createOAuthLauncher:e}=await import(`./oauth-service-CKR4S63v.js`);return{createOAuthLauncher:e}},[]),n=e();await c.onOAuthLogin(n,()=>{});let r=t(o);return r&&r.token?{stdout:`${r.token}\n`,stderr:``,exitCode:0}:(console.error(`[oauth-token] Provider ${o}: login completed but no token was saved`),{stdout:``,stderr:`oauth-token: login completed but no token was saved
2924
- `,exitCode:1})}catch(e){let t=e instanceof Error?e.message:String(e);return console.error(`[oauth-token] Provider ${o}: login failed:`,t),{stdout:``,stderr:`oauth-token: login failed: ${t}\n`,exitCode:1}}})}function VG(e,t,n,r){let i=t().filter(e=>n(e)?.isOAuth);if(i.length===0)return{stdout:`No OAuth providers configured.
2930
+ `,exitCode:1})}catch(e){let t=e instanceof Error?e.message:String(e);return console.error(`[oauth-token] Provider ${o}: login failed:`,t),{stdout:``,stderr:`oauth-token: login failed: ${t}\n`,exitCode:1}}})}function WG(e,t,n,r){let i=t().filter(e=>n(e)?.isOAuth);if(i.length===0)return{stdout:`No OAuth providers configured.
2925
2931
  `,stderr:``,exitCode:0};let a=[];for(let e of i){let t=r(e);if(!t)a.push(`${e} (no token)`);else if(t.expired){let n=t.userName?` as ${t.userName}`:``;a.push(`${e} (expired${n})`)}else{let n=[];if(t.userName?n.push(`logged in as ${t.userName}`):n.push(`logged in`),t.expiresAt){let e=t.expiresAt-Date.now();if(e>0){let t=Math.floor(e/36e5),r=Math.floor(e%36e5/6e4);t>0?n.push(`expires in ${t}h`):n.push(`expires in ${r}m`)}}a.push(`${e} (${n.join(`, `)})`)}}return{stdout:a.join(`
2926
2932
  `)+`
2927
- `,stderr:``,exitCode:0}}function HG(e,t,n={}){let r=new Map;for(let e of t)r.set(e.path,e);let i=new Set,a=[],o=[],s=[];for(let t of e){i.add(t.path);let e=r.get(t.path);e?e.size===t.size&&e.mtimeMs===t.mtimeMs?s.push(t.path):o.push(t.path):a.push(t.path)}let c=[];if(n.delete)for(let e of t)i.has(e.path)||c.push(e.path);return{toAdd:a,toUpdate:o,toDelete:c,toSkip:s}}var UG=null;function WG(e){UG=e}function GG(){return UG?.()??null}function KG(e){let t={dryRun:!1,delete:!1,verbose:!1},n=[];for(let r of e)if(r===`--dry-run`||r===`-n`)t.dryRun=!0;else if(r===`--delete`)t.delete=!0;else if(r===`--verbose`||r===`-v`)t.verbose=!0;else if(r===`--help`||r===`-h`)return{error:`__help__`};else if(r.startsWith(`-`))return{error:`Unknown flag: ${r}`};else n.push(r);if(n.length!==2)return{error:`Expected exactly 2 arguments: <source> <dest>`};let[r,i]=n,a=qG(r),o=qG(i);return a&&o?{error:`Cannot sync between two remote paths — one side must be local`}:!a&&!o?{error:`One argument must be a remote path (runtime-id:/path)`}:o?{direction:`push`,localPath:r,remotePath:o.path,runtimeId:o.runtimeId,...t}:{direction:`pull`,localPath:i,remotePath:a.path,runtimeId:a.runtimeId,...t}}function qG(e){let t=e.indexOf(`:`);if(t<=0)return null;let n=e.slice(0,t),r=e.slice(t+1);return r.startsWith(`/`)?{runtimeId:n,path:r}:null}function JG(){return{stdout:`rsync — sync files between local VFS and a remote tray runtime
2933
+ `,stderr:``,exitCode:0}}function GG(e,t,n={}){let r=new Map;for(let e of t)r.set(e.path,e);let i=new Set,a=[],o=[],s=[];for(let t of e){i.add(t.path);let e=r.get(t.path);e?e.size===t.size&&e.mtimeMs===t.mtimeMs?s.push(t.path):o.push(t.path):a.push(t.path)}let c=[];if(n.delete)for(let e of t)i.has(e.path)||c.push(e.path);return{toAdd:a,toUpdate:o,toDelete:c,toSkip:s}}var KG=null;function qG(e){KG=e}function JG(){return KG?.()??null}function YG(e){let t={dryRun:!1,delete:!1,verbose:!1},n=[];for(let r of e)if(r===`--dry-run`||r===`-n`)t.dryRun=!0;else if(r===`--delete`)t.delete=!0;else if(r===`--verbose`||r===`-v`)t.verbose=!0;else if(r===`--help`||r===`-h`)return{error:`__help__`};else if(r.startsWith(`-`))return{error:`Unknown flag: ${r}`};else n.push(r);if(n.length!==2)return{error:`Expected exactly 2 arguments: <source> <dest>`};let[r,i]=n,a=XG(r),o=XG(i);return a&&o?{error:`Cannot sync between two remote paths — one side must be local`}:!a&&!o?{error:`One argument must be a remote path (runtime-id:/path)`}:o?{direction:`push`,localPath:r,remotePath:o.path,runtimeId:o.runtimeId,...t}:{direction:`pull`,localPath:i,remotePath:a.path,runtimeId:a.runtimeId,...t}}function XG(e){let t=e.indexOf(`:`);if(t<=0)return null;let n=e.slice(0,t),r=e.slice(t+1);return r.startsWith(`/`)?{runtimeId:n,path:r}:null}function ZG(){return{stdout:`rsync — sync files between local VFS and a remote tray runtime
2928
2934
 
2929
2935
  Usage:
2930
2936
  rsync [flags] <local-path> <runtime-id>:<remote-path> # push
@@ -2940,21 +2946,21 @@ Examples:
2940
2946
  rsync /workspace follower-abc123:/workspace
2941
2947
  rsync --delete /shared leader:/shared
2942
2948
  rsync follower-abc123:/workspace/project /workspace/project
2943
- `,stderr:``,exitCode:0}}async function YG(e,t){if(!await e.exists(t))return[];let n=[];for await(let r of e.walk(t)){let i=r.slice(t.length).replace(/^\//,``);if(!i)continue;let a=await e.stat(r);n.push({path:i,size:a.size,mtimeMs:a.mtime})}return n}async function XG(e,t,n){let r=(await e(t,{op:`walk`,path:n}))[0];if(!r.ok){if(r.code===`ENOENT`)return[];throw Error(`Remote walk failed: ${r.error}`)}if(r.data.type!==`paths`)throw Error(`Unexpected walk response type`);let i=r.data.paths,a=[];for(let r of i){let i=r.slice(n.length).replace(/^\//,``);if(!i)continue;let o=(await e(t,{op:`stat`,path:r}))[0];o.ok&&o.data.type===`stat`&&a.push({path:i,size:o.data.stat.size,mtimeMs:o.data.stat.mtime})}return a}async function ZG(e,t,n){let r=await e(t,{op:`readFile`,path:n,encoding:`binary`}),i=``;for(let e of r){if(!e.ok)throw Error(`Remote read failed: ${e.error}`);e.data.type===`file`&&(i+=e.data.content)}return i}async function QG(e,t,n){let r=await e(t,{op:`mkdir`,path:n,recursive:!0});if(!r[0].ok)throw Error(`Remote mkdir failed: ${r[0].error}`)}function $G(e){let t=e.lastIndexOf(`/`);return t<=0?`/`:e.slice(0,t)}async function eK(e,t,n){let r=[],{localPath:i,remotePath:a,runtimeId:o,verbose:s,dryRun:c}=n,l=HG(await YG(e,i),await XG(t,o,a),{delete:n.delete});if(s||c){for(let e of l.toAdd)r.push(`+ ${e}`);for(let e of l.toUpdate)r.push(`~ ${e}`);for(let e of l.toDelete)r.push(`- ${e}`);if(s)for(let e of l.toSkip)r.push(` ${e} (up to date)`)}let u=l.toAdd.length+l.toUpdate.length+l.toDelete.length;if(c)return r.push(`\n(dry run) ${u} file(s) would be transferred, ${l.toSkip.length} up to date`),{stdout:r.join(`
2949
+ `,stderr:``,exitCode:0}}async function QG(e,t){if(!await e.exists(t))return[];let n=[];for await(let r of e.walk(t)){let i=r.slice(t.length).replace(/^\//,``);if(!i)continue;let a=await e.stat(r);n.push({path:i,size:a.size,mtimeMs:a.mtime})}return n}async function $G(e,t,n){let r=(await e(t,{op:`walk`,path:n}))[0];if(!r.ok){if(r.code===`ENOENT`)return[];throw Error(`Remote walk failed: ${r.error}`)}if(r.data.type!==`paths`)throw Error(`Unexpected walk response type`);let i=r.data.paths,a=[];for(let r of i){let i=r.slice(n.length).replace(/^\//,``);if(!i)continue;let o=(await e(t,{op:`stat`,path:r}))[0];o.ok&&o.data.type===`stat`&&a.push({path:i,size:o.data.stat.size,mtimeMs:o.data.stat.mtime})}return a}async function eK(e,t,n){let r=await e(t,{op:`readFile`,path:n,encoding:`binary`}),i=``;for(let e of r){if(!e.ok)throw Error(`Remote read failed: ${e.error}`);e.data.type===`file`&&(i+=e.data.content)}return i}async function tK(e,t,n){let r=await e(t,{op:`mkdir`,path:n,recursive:!0});if(!r[0].ok)throw Error(`Remote mkdir failed: ${r[0].error}`)}function nK(e){let t=e.lastIndexOf(`/`);return t<=0?`/`:e.slice(0,t)}async function rK(e,t,n){let r=[],{localPath:i,remotePath:a,runtimeId:o,verbose:s,dryRun:c}=n,l=GG(await QG(e,i),await $G(t,o,a),{delete:n.delete});if(s||c){for(let e of l.toAdd)r.push(`+ ${e}`);for(let e of l.toUpdate)r.push(`~ ${e}`);for(let e of l.toDelete)r.push(`- ${e}`);if(s)for(let e of l.toSkip)r.push(` ${e} (up to date)`)}let u=l.toAdd.length+l.toUpdate.length+l.toDelete.length;if(c)return r.push(`\n(dry run) ${u} file(s) would be transferred, ${l.toSkip.length} up to date`),{stdout:r.join(`
2944
2950
  `)+`
2945
- `,stderr:``,exitCode:0};for(let n of[...l.toAdd,...l.toUpdate]){let s=i+`/`+n,c=a+`/`+n;await QG(t,o,$G(c));let l=await t(o,{op:`writeFile`,path:c,content:nK(await e.readFile(s,{encoding:`binary`})),encoding:`base64`});if(!l[0].ok)return{stdout:r.join(`
2951
+ `,stderr:``,exitCode:0};for(let n of[...l.toAdd,...l.toUpdate]){let s=i+`/`+n,c=a+`/`+n;await tK(t,o,nK(c));let l=await t(o,{op:`writeFile`,path:c,content:aK(await e.readFile(s,{encoding:`binary`})),encoding:`base64`});if(!l[0].ok)return{stdout:r.join(`
2946
2952
  `)+`
2947
2953
  `,stderr:`Error writing ${c}: ${l[0].error}\n`,exitCode:1}}for(let e of l.toDelete){let n=a+`/`+e,i=await t(o,{op:`rm`,path:n});if(!i[0].ok)return{stdout:r.join(`
2948
2954
  `)+`
2949
2955
  `,stderr:`Error deleting ${n}: ${i[0].error}\n`,exitCode:1}}return r.push(`${u} file(s) transferred, ${l.toSkip.length} up to date`),{stdout:r.join(`
2950
2956
  `)+`
2951
- `,stderr:``,exitCode:0}}async function tK(e,t,n){let r=[],{localPath:i,remotePath:a,runtimeId:o,verbose:s,dryRun:c}=n,l=HG(await XG(t,o,a),await YG(e,i),{delete:n.delete});if(s||c){for(let e of l.toAdd)r.push(`+ ${e}`);for(let e of l.toUpdate)r.push(`~ ${e}`);for(let e of l.toDelete)r.push(`- ${e}`);if(s)for(let e of l.toSkip)r.push(` ${e} (up to date)`)}let u=l.toAdd.length+l.toUpdate.length+l.toDelete.length;if(c)return r.push(`\n(dry run) ${u} file(s) would be transferred, ${l.toSkip.length} up to date`),{stdout:r.join(`
2957
+ `,stderr:``,exitCode:0}}async function iK(e,t,n){let r=[],{localPath:i,remotePath:a,runtimeId:o,verbose:s,dryRun:c}=n,l=GG(await $G(t,o,a),await QG(e,i),{delete:n.delete});if(s||c){for(let e of l.toAdd)r.push(`+ ${e}`);for(let e of l.toUpdate)r.push(`~ ${e}`);for(let e of l.toDelete)r.push(`- ${e}`);if(s)for(let e of l.toSkip)r.push(` ${e} (up to date)`)}let u=l.toAdd.length+l.toUpdate.length+l.toDelete.length;if(c)return r.push(`\n(dry run) ${u} file(s) would be transferred, ${l.toSkip.length} up to date`),{stdout:r.join(`
2952
2958
  `)+`
2953
- `,stderr:``,exitCode:0};for(let n of[...l.toAdd,...l.toUpdate]){let r=a+`/`+n,s=i+`/`+n,c=$G(s);await e.exists(c)||await e.mkdir(c,{recursive:!0});let l=rK(await ZG(t,o,r));await e.writeFile(s,l)}for(let t of l.toDelete){let n=i+`/`+t;await e.rm(n)}return r.push(`${u} file(s) transferred, ${l.toSkip.length} up to date`),{stdout:r.join(`
2959
+ `,stderr:``,exitCode:0};for(let n of[...l.toAdd,...l.toUpdate]){let r=a+`/`+n,s=i+`/`+n,c=nK(s);await e.exists(c)||await e.mkdir(c,{recursive:!0});let l=oK(await eK(t,o,r));await e.writeFile(s,l)}for(let t of l.toDelete){let n=i+`/`+t;await e.rm(n)}return r.push(`${u} file(s) transferred, ${l.toSkip.length} up to date`),{stdout:r.join(`
2954
2960
  `)+`
2955
- `,stderr:``,exitCode:0}}function nK(e){let t=``;for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t)}function rK(e){let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e++)n[e]=t.charCodeAt(e);return n}function iK(e={}){let t=e.fs,n=e.getSendFsRequest??GG;return qP(`rsync`,async e=>{if(e.includes(`--help`)||e.includes(`-h`)||e.length===0)return JG();if(!t)return{stdout:``,stderr:`rsync: no filesystem available
2961
+ `,stderr:``,exitCode:0}}function aK(e){let t=``;for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t)}function oK(e){let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e++)n[e]=t.charCodeAt(e);return n}function sK(e={}){let t=e.fs,n=e.getSendFsRequest??JG;return qP(`rsync`,async e=>{if(e.includes(`--help`)||e.includes(`-h`)||e.length===0)return ZG();if(!t)return{stdout:``,stderr:`rsync: no filesystem available
2956
2962
  `,exitCode:1};let r=n();if(!r)return{stdout:``,stderr:`rsync: not connected to a tray — rsync requires a tray connection
2957
- `,exitCode:1};let i=KG(e);if(`error`in i)return i.error===`__help__`?JG():{stdout:``,stderr:`rsync: ${i.error}\n`,exitCode:1};try{return i.direction===`push`?await eK(t,r,i):await tK(t,r,i)}catch(e){return{stdout:``,stderr:`rsync: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}})}var aK=[`/workspace/skills`];async function oK(e){let t=new Map;for(let n of aK)await e.exists(n)&&await sK(e,n,t);return await sK(e,`/`,t),t}async function sK(e,t,n){for await(let r of e.walk(t)){if(!r.endsWith(`.jsh`))continue;let e=cK(r);n.has(e)||n.set(e,r)}}function cK(e){let t=e.split(`/`).pop()??e;return t.endsWith(`.jsh`)?t.slice(0,-4):t}function lK(e){return qP(`which`,async(t,n)=>{if(t.includes(`--help`)||t.includes(`-h`))return{stdout:`which - locate a command
2963
+ `,exitCode:1};let i=YG(e);if(`error`in i)return i.error===`__help__`?ZG():{stdout:``,stderr:`rsync: ${i.error}\n`,exitCode:1};try{return i.direction===`push`?await rK(t,r,i):await iK(t,r,i)}catch(e){return{stdout:``,stderr:`rsync: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}})}var cK=[`/workspace/skills`];async function lK(e){let t=new Map;for(let n of cK)await e.exists(n)&&await uK(e,n,t);return await uK(e,`/`,t),t}async function uK(e,t,n){for await(let r of e.walk(t)){if(!r.endsWith(`.jsh`))continue;let e=dK(r);n.has(e)||n.set(e,r)}}function dK(e){let t=e.split(`/`).pop()??e;return t.endsWith(`.jsh`)?t.slice(0,-4):t}function fK(e){return qP(`which`,async(t,n)=>{if(t.includes(`--help`)||t.includes(`-h`))return{stdout:`which - locate a command
2958
2964
 
2959
2965
  Usage: which <command> [command...]
2960
2966
 
@@ -2964,12 +2970,12 @@ Prints the path of the given command(s).
2964
2970
 
2965
2971
  Exit code 0 if all commands found, 1 if any not found.
2966
2972
  `,stderr:``,exitCode:0};if(t.length===0)return{stdout:``,stderr:`which: missing argument
2967
- `,exitCode:1};let r=n.getRegisteredCommands?.()??[],i=new Set(r),a=e?await oK(e):new Map,o=[],s=!0;for(let e of t)if(i.has(e))o.push(`/usr/bin/${e}`);else{let t=a.get(e);t?o.push(t):s=!1}return{stdout:o.length>0?o.join(`
2973
+ `,exitCode:1};let r=n.getRegisteredCommands?.()??[],i=new Set(r),a=e?await lK(e):new Map,o=[],s=!0;for(let e of t)if(i.has(e))o.push(`/usr/bin/${e}`);else{let t=a.get(e);t?o.push(t):s=!1}return{stdout:o.length>0?o.join(`
2968
2974
  `)+`
2969
- `:``,stderr:``,exitCode:s?0:1}})}async function uK(e,t,n,r){if((await e.fs.stat(t)).isFile)return r[n]=await e.fs.readFileBuffer(t),1;let i=await e.fs.readdir(t),a=0;for(let o of i){let i=IW(t,o),s=n?`${n}/${o}`:o;a+=await uK(e,i,s,r)}return a}function dK(){return{stdout:`usage: zip [-r] <archive.zip> <path> [path...]
2970
- `,stderr:``,exitCode:0}}function fK(){return qP(`zip`,async(e,t)=>{if(e.length===0||e.includes(`--help`)||e.includes(`-h`))return dK();let n=!1,r=[];for(let t of e){if(t===`-r`){n=!0;continue}if(t.startsWith(`-`))return{stdout:``,stderr:`zip: unsupported option ${t}\n`,exitCode:1};r.push(t)}if(r.length<2)return{stdout:``,stderr:`zip: expected archive path and at least one input path
2971
- `,exitCode:1};let i=t.fs.resolvePath(t.cwd,r[0]),a=r.slice(1),o={},s=0;for(let e of a){let r=t.fs.resolvePath(t.cwd,e),i=await t.fs.stat(r),a=(e.startsWith(`/`)?e.slice(1):e.replace(/^\.\//,``))||PW(r);if(i.isDirectory&&!n)return{stdout:``,stderr:`zip: ${e} is a directory (use -r)\n`,exitCode:1};s+=await uK(t,r,a,o)}if(s===0)return{stdout:``,stderr:`zip: nothing to do
2972
- `,exitCode:1};let c=ce(o);return await t.fs.writeFile(i,c),{stdout:`created ${i} (${s} file(s))\n`,stderr:``,exitCode:0}})}function pK(){return{stdout:`screencapture - capture screen, window, or tab using browser screen sharing
2975
+ `:``,stderr:``,exitCode:s?0:1}})}async function pK(e,t,n,r){if((await e.fs.stat(t)).isFile)return r[n]=await e.fs.readFileBuffer(t),1;let i=await e.fs.readdir(t),a=0;for(let o of i){let i=IW(t,o),s=n?`${n}/${o}`:o;a+=await pK(e,i,s,r)}return a}function mK(){return{stdout:`usage: zip [-r] <archive.zip> <path> [path...]
2976
+ `,stderr:``,exitCode:0}}function hK(){return qP(`zip`,async(e,t)=>{if(e.length===0||e.includes(`--help`)||e.includes(`-h`))return mK();let n=!1,r=[];for(let t of e){if(t===`-r`){n=!0;continue}if(t.startsWith(`-`))return{stdout:``,stderr:`zip: unsupported option ${t}\n`,exitCode:1};r.push(t)}if(r.length<2)return{stdout:``,stderr:`zip: expected archive path and at least one input path
2977
+ `,exitCode:1};let i=t.fs.resolvePath(t.cwd,r[0]),a=r.slice(1),o={},s=0;for(let e of a){let r=t.fs.resolvePath(t.cwd,e),i=await t.fs.stat(r),a=(e.startsWith(`/`)?e.slice(1):e.replace(/^\.\//,``))||PW(r);if(i.isDirectory&&!n)return{stdout:``,stderr:`zip: ${e} is a directory (use -r)\n`,exitCode:1};s+=await pK(t,r,a,o)}if(s===0)return{stdout:``,stderr:`zip: nothing to do
2978
+ `,exitCode:1};let c=ce(o);return await t.fs.writeFile(i,c),{stdout:`created ${i} (${s} file(s))\n`,stderr:``,exitCode:0}})}function gK(){return{stdout:`screencapture - capture screen, window, or tab using browser screen sharing
2973
2979
 
2974
2980
  Usage: screencapture [options] <output-file>
2975
2981
 
@@ -2985,57 +2991,57 @@ Examples:
2985
2991
  screencapture screenshot.png # Capture to file
2986
2992
  screencapture -c # Capture to clipboard
2987
2993
  screencapture -v capture.png # Capture and return for agent vision
2988
- `,stderr:``,exitCode:0}}function mK(e){let t=``,n=8192;for(let r=0;r<e.length;r+=n)t+=String.fromCharCode(...e.subarray(r,r+n));return btoa(t)}function hK(e){switch(e.split(`.`).pop()?.toLowerCase()){case`jpg`:case`jpeg`:return`image/jpeg`;case`webp`:return`image/webp`;default:return`image/png`}}async function gK(e,t){let n=await navigator.mediaDevices.getDisplayMedia({video:!0,audio:!1});try{let r=document.createElement(`video`);r.srcObject=n,r.muted=!0,r.playsInline=!0,await new Promise((e,t)=>{r.onloadedmetadata=()=>{r.play().then(()=>e()).catch(t)},r.onerror=()=>t(Error(`Failed to load video stream`))}),await new Promise(e=>requestAnimationFrame(e));let i=r.videoWidth,a=r.videoHeight,o=document.createElement(`canvas`);o.width=i,o.height=a;let s=o.getContext(`2d`);if(!s)throw Error(`Failed to get canvas context`);return s.drawImage(r,0,0,i,a),new Promise((n,r)=>{o.toBlob(e=>{e?n(e):r(Error(`Failed to create image blob`))},e,t)})}finally{n.getTracks().forEach(e=>e.stop())}}function _K(){return qP(`screencapture`,async(e,t)=>{if(e.includes(`--help`)||e.includes(`-h`))return pK();if(typeof window>`u`||typeof navigator>`u`||typeof document>`u`)return{stdout:``,stderr:`screencapture: browser APIs are unavailable in this environment
2994
+ `,stderr:``,exitCode:0}}function _K(e){let t=``,n=8192;for(let r=0;r<e.length;r+=n)t+=String.fromCharCode(...e.subarray(r,r+n));return btoa(t)}function vK(e){switch(e.split(`.`).pop()?.toLowerCase()){case`jpg`:case`jpeg`:return`image/jpeg`;case`webp`:return`image/webp`;default:return`image/png`}}async function yK(e,t){let n=await navigator.mediaDevices.getDisplayMedia({video:!0,audio:!1});try{let r=document.createElement(`video`);r.srcObject=n,r.muted=!0,r.playsInline=!0,await new Promise((e,t)=>{r.onloadedmetadata=()=>{r.play().then(()=>e()).catch(t)},r.onerror=()=>t(Error(`Failed to load video stream`))}),await new Promise(e=>requestAnimationFrame(e));let i=r.videoWidth,a=r.videoHeight,o=document.createElement(`canvas`);o.width=i,o.height=a;let s=o.getContext(`2d`);if(!s)throw Error(`Failed to get canvas context`);return s.drawImage(r,0,0,i,a),new Promise((n,r)=>{o.toBlob(e=>{e?n(e):r(Error(`Failed to create image blob`))},e,t)})}finally{n.getTracks().forEach(e=>e.stop())}}function bK(){return qP(`screencapture`,async(e,t)=>{if(e.includes(`--help`)||e.includes(`-h`))return gK();if(typeof window>`u`||typeof navigator>`u`||typeof document>`u`)return{stdout:``,stderr:`screencapture: browser APIs are unavailable in this environment
2989
2995
  `,exitCode:1};if(!navigator.mediaDevices?.getDisplayMedia)return{stdout:``,stderr:`screencapture: screen capture is not supported in this browser
2990
2996
  `,exitCode:1};let n=e.includes(`--clipboard`)||e.includes(`-c`),r=e.includes(`--view`)||e.includes(`-v`),i=[`--clipboard`,`-c`,`--view`,`-v`,`--help`,`-h`],a=e.indexOf(`--`),o=(a>=0?e.slice(a+1):e.filter(e=>!i.includes(e)))[0];if(!n&&!o)return{stdout:``,stderr:`screencapture: output file required (or use -c for clipboard)
2991
- `,exitCode:1};let s=o||`screenshot.png`,c=hK(s),l=c===`image/png`?1:.92,u;try{u=await gK(c,l)}catch(e){let t=e instanceof Error?e.message:String(e);return t.includes(`Permission denied`)||t.includes(`NotAllowedError`)?{stdout:``,stderr:`screencapture: user cancelled or permission denied
2992
- `,exitCode:1}:{stdout:``,stderr:`screencapture: ${t}\n`,exitCode:1}}let d=await u.arrayBuffer(),f=new Uint8Array(d);if(n)try{let e;if(c===`image/png`)e=u;else{let t=new Image,n=URL.createObjectURL(u);try{await new Promise((e,r)=>{t.onload=()=>e(),t.onerror=()=>r(Error(`Failed to load image for conversion`)),t.src=n})}finally{URL.revokeObjectURL(n)}let r=document.createElement(`canvas`);r.width=t.width,r.height=t.height;let i=r.getContext(`2d`);if(!i)throw Error(`Failed to get canvas context`);i.drawImage(t,0,0),e=await new Promise((e,t)=>{r.toBlob(n=>{n?e(n):t(Error(`Failed to create PNG blob`))},`image/png`)})}return await navigator.clipboard.write([new ClipboardItem({"image/png":e})]),{stdout:`captured ${Math.round(e.size/1024)} KB to clipboard\n`,stderr:``,exitCode:0}}catch(e){return{stdout:``,stderr:`screencapture: failed to copy to clipboard: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}let p=t.fs.resolvePath(t.cwd,s);try{await t.fs.writeFile(p,f)}catch(e){return{stdout:``,stderr:`screencapture: failed to write file: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}let m=Math.round(f.length/1024);return r?{stdout:`${p} (${m} KB)\n<img:data:${c};base64,${mK(f)}>`,stderr:``,exitCode:0}:{stdout:`captured ${m} KB to ${PW(p)}\n`,stderr:``,exitCode:0}})}function vK(e){return e instanceof Error?e.message:String(e)}function yK(){return{stdout:`usage: pbcopy
2997
+ `,exitCode:1};let s=o||`screenshot.png`,c=vK(s),l=c===`image/png`?1:.92,u;try{u=await yK(c,l)}catch(e){let t=e instanceof Error?e.message:String(e);return t.includes(`Permission denied`)||t.includes(`NotAllowedError`)?{stdout:``,stderr:`screencapture: user cancelled or permission denied
2998
+ `,exitCode:1}:{stdout:``,stderr:`screencapture: ${t}\n`,exitCode:1}}let d=await u.arrayBuffer(),f=new Uint8Array(d);if(n)try{let e;if(c===`image/png`)e=u;else{let t=new Image,n=URL.createObjectURL(u);try{await new Promise((e,r)=>{t.onload=()=>e(),t.onerror=()=>r(Error(`Failed to load image for conversion`)),t.src=n})}finally{URL.revokeObjectURL(n)}let r=document.createElement(`canvas`);r.width=t.width,r.height=t.height;let i=r.getContext(`2d`);if(!i)throw Error(`Failed to get canvas context`);i.drawImage(t,0,0),e=await new Promise((e,t)=>{r.toBlob(n=>{n?e(n):t(Error(`Failed to create PNG blob`))},`image/png`)})}return await navigator.clipboard.write([new ClipboardItem({"image/png":e})]),{stdout:`captured ${Math.round(e.size/1024)} KB to clipboard\n`,stderr:``,exitCode:0}}catch(e){return{stdout:``,stderr:`screencapture: failed to copy to clipboard: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}let p=t.fs.resolvePath(t.cwd,s);try{await t.fs.writeFile(p,f)}catch(e){return{stdout:``,stderr:`screencapture: failed to write file: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}let m=Math.round(f.length/1024);return r?{stdout:`${p} (${m} KB)\n<img:data:${c};base64,${_K(f)}>`,stderr:``,exitCode:0}:{stdout:`captured ${m} KB to ${PW(p)}\n`,stderr:``,exitCode:0}})}function xK(e){return e instanceof Error?e.message:String(e)}function SK(){return{stdout:`usage: pbcopy
2993
2999
 
2994
3000
  Copy stdin to the clipboard.
2995
3001
  Example: echo hello | pbcopy
2996
- `,stderr:``,exitCode:0}}function bK(){return{stdout:`usage: pbpaste
3002
+ `,stderr:``,exitCode:0}}function CK(){return{stdout:`usage: pbpaste
2997
3003
 
2998
3004
  Paste clipboard contents to stdout.
2999
- `,stderr:``,exitCode:0}}function xK(e){return{stdout:`usage: ${e} [-i|-o]\n\n -i Force copy mode (read from stdin)
3005
+ `,stderr:``,exitCode:0}}function wK(e){return{stdout:`usage: ${e} [-i|-o]\n\n -i Force copy mode (read from stdin)
3000
3006
  -o Force paste mode (write to stdout)
3001
3007
  (default) Auto-detect: stdin present = copy, no stdin = paste
3002
- Example: echo hello | ${e}\n Example: ${e} -o > file.txt\n`,stderr:``,exitCode:0}}async function SK(e,t){if(!globalThis.navigator?.clipboard)return{stdout:``,stderr:`${t}: clipboard API is unavailable\n`,exitCode:1};try{return await navigator.clipboard.writeText(e),{stdout:``,stderr:``,exitCode:0}}catch(e){return{stdout:``,stderr:`${t}: failed to write to clipboard: ${vK(e)}\n`,exitCode:1}}}async function CK(e){if(!globalThis.navigator?.clipboard)return{stdout:``,stderr:`${e}: clipboard API is unavailable\n`,exitCode:1};try{return{stdout:await navigator.clipboard.readText(),stderr:``,exitCode:0}}catch(t){return{stdout:``,stderr:`${e}: failed to read from clipboard: ${vK(t)}\n`,exitCode:1}}}function wK(){return qP(`pbcopy`,async(e,t)=>e.includes(`--help`)||e.includes(`-h`)?yK():SK(t.stdin,`pbcopy`))}function TK(){return qP(`pbpaste`,async e=>e.includes(`--help`)||e.includes(`-h`)?bK():CK(`pbpaste`))}function EK(e){return qP(e,async(t,n)=>{if(t.includes(`--help`)||t.includes(`-h`))return xK(e);let r=t.includes(`-i`),i=t.includes(`-o`);return r&&i?{stdout:``,stderr:`${e}: cannot use both -i and -o\n`,exitCode:1}:i?CK(e):r||n.stdin.length>0?SK(n.stdin,e):CK(e)})}function DK(){return{stdout:`usage: say [-v voice] [-r rate] [-l lang] [--list] <text>
3008
+ Example: echo hello | ${e}\n Example: ${e} -o > file.txt\n`,stderr:``,exitCode:0}}async function TK(e,t){if(!globalThis.navigator?.clipboard)return{stdout:``,stderr:`${t}: clipboard API is unavailable\n`,exitCode:1};try{return await navigator.clipboard.writeText(e),{stdout:``,stderr:``,exitCode:0}}catch(e){return{stdout:``,stderr:`${t}: failed to write to clipboard: ${xK(e)}\n`,exitCode:1}}}async function EK(e){if(!globalThis.navigator?.clipboard)return{stdout:``,stderr:`${e}: clipboard API is unavailable\n`,exitCode:1};try{return{stdout:await navigator.clipboard.readText(),stderr:``,exitCode:0}}catch(t){return{stdout:``,stderr:`${e}: failed to read from clipboard: ${xK(t)}\n`,exitCode:1}}}function DK(){return qP(`pbcopy`,async(e,t)=>e.includes(`--help`)||e.includes(`-h`)?SK():TK(t.stdin,`pbcopy`))}function OK(){return qP(`pbpaste`,async e=>e.includes(`--help`)||e.includes(`-h`)?CK():EK(`pbpaste`))}function kK(e){return qP(e,async(t,n)=>{if(t.includes(`--help`)||t.includes(`-h`))return wK(e);let r=t.includes(`-i`),i=t.includes(`-o`);return r&&i?{stdout:``,stderr:`${e}: cannot use both -i and -o\n`,exitCode:1}:i?EK(e):r||n.stdin.length>0?TK(n.stdin,e):EK(e)})}function AK(){return{stdout:`usage: say [-v voice] [-r rate] [-l lang] [--list] <text>
3003
3009
 
3004
3010
  Speaks the given text using the Web Speech API.
3005
3011
  -v voice Voice name (partial match supported)
3006
3012
  -r rate Speech rate (0.1 to 10, default 1)
3007
3013
  -l lang Language tag (required, BCP 47, e.g. en-US, de-DE, fr-FR)
3008
3014
  --list List available voices
3009
- `,stderr:``,exitCode:0}}var OK=!1,kK=null;function AK(){return OK?Promise.resolve(speechSynthesis.getVoices()):(kK||=new Promise(e=>{let t=speechSynthesis.getVoices();if(t.length>0){OK=!0,e(t);return}let n=()=>{OK=!0,speechSynthesis.removeEventListener(`voiceschanged`,n),e(speechSynthesis.getVoices())};speechSynthesis.addEventListener(`voiceschanged`,n),setTimeout(()=>{speechSynthesis.removeEventListener(`voiceschanged`,n),OK=!0,e(speechSynthesis.getVoices())},1e3)}),kK)}function jK(){return qP(`say`,async e=>{if(e.includes(`--help`)||e.includes(`-h`))return DK();if(typeof window>`u`||typeof speechSynthesis>`u`)return{stdout:``,stderr:`say: Web Speech API unavailable in this environment
3010
- `,exitCode:1};if(e.includes(`--list`))return{stdout:(await AK()).map(e=>`${e.name} (${e.lang})${e.default?` [default]`:``}`).join(`
3015
+ `,stderr:``,exitCode:0}}var jK=!1,MK=null;function NK(){return jK?Promise.resolve(speechSynthesis.getVoices()):(MK||=new Promise(e=>{let t=speechSynthesis.getVoices();if(t.length>0){jK=!0,e(t);return}let n=()=>{jK=!0,speechSynthesis.removeEventListener(`voiceschanged`,n),e(speechSynthesis.getVoices())};speechSynthesis.addEventListener(`voiceschanged`,n),setTimeout(()=>{speechSynthesis.removeEventListener(`voiceschanged`,n),jK=!0,e(speechSynthesis.getVoices())},1e3)}),MK)}function PK(){return qP(`say`,async e=>{if(e.includes(`--help`)||e.includes(`-h`))return AK();if(typeof window>`u`||typeof speechSynthesis>`u`)return{stdout:``,stderr:`say: Web Speech API unavailable in this environment
3016
+ `,exitCode:1};if(e.includes(`--list`))return{stdout:(await NK()).map(e=>`${e.name} (${e.lang})${e.default?` [default]`:``}`).join(`
3011
3017
  `)+`
3012
3018
  `,stderr:``,exitCode:0};let t=null,n=1,r=null,i=[];for(let a=0;a<e.length;a++){let o=e[a];if(o===`-v`){if(a+1>=e.length||e[a+1].startsWith(`-`))return{stdout:``,stderr:`say: -v requires a voice name
3013
3019
  `,exitCode:1};t=e[++a]}else if(o===`-r`){if(a+1>=e.length||e[a+1].startsWith(`-`))return{stdout:``,stderr:`say: -r requires a rate value
3014
3020
  `,exitCode:1};if(n=parseFloat(e[++a]),isNaN(n)||n<.1||n>10)return{stdout:``,stderr:`say: rate must be between 0.1 and 10
3015
3021
  `,exitCode:1}}else if(o===`-l`){if(a+1>=e.length||e[a+1].startsWith(`-`))return{stdout:``,stderr:`say: -l requires a language tag
3016
- `,exitCode:1};r=e[++a]}else if(o.startsWith(`-`)&&o!==`--list`)return{stdout:``,stderr:`say: unknown option: ${o}\n`,exitCode:1};else o.startsWith(`-`)||i.push(o)}let a=i.join(` `);if(!a)return DK();if(!r)return{stdout:``,stderr:`say: -l language tag is required
3017
- `,exitCode:1};let o=new SpeechSynthesisUtterance(a);if(o.rate=n,o.lang=r,t){let e=(await AK()).find(e=>e.name.toLowerCase().includes(t.toLowerCase()));if(e)o.voice=e;else return{stdout:``,stderr:`say: voice "${t}" not found. Use --list to see available voices.\n`,exitCode:1}}return new Promise(e=>{o.onend=()=>{e({stdout:``,stderr:``,exitCode:0})},o.onerror=t=>{e({stdout:``,stderr:`say: speech synthesis error: ${t.error}\n`,exitCode:1})},speechSynthesis.speak(o)})})}function MK(){return{stdout:`usage: afplay [-v volume] [-r rate] <file>
3022
+ `,exitCode:1};r=e[++a]}else if(o.startsWith(`-`)&&o!==`--list`)return{stdout:``,stderr:`say: unknown option: ${o}\n`,exitCode:1};else o.startsWith(`-`)||i.push(o)}let a=i.join(` `);if(!a)return AK();if(!r)return{stdout:``,stderr:`say: -l language tag is required
3023
+ `,exitCode:1};let o=new SpeechSynthesisUtterance(a);if(o.rate=n,o.lang=r,t){let e=(await NK()).find(e=>e.name.toLowerCase().includes(t.toLowerCase()));if(e)o.voice=e;else return{stdout:``,stderr:`say: voice "${t}" not found. Use --list to see available voices.\n`,exitCode:1}}return new Promise(e=>{o.onend=()=>{e({stdout:``,stderr:``,exitCode:0})},o.onerror=t=>{e({stdout:``,stderr:`say: speech synthesis error: ${t.error}\n`,exitCode:1})},speechSynthesis.speak(o)})})}function FK(){return{stdout:`usage: afplay [-v volume] [-r rate] <file>
3018
3024
 
3019
3025
  Plays an audio file using the Web Audio API.
3020
3026
  -v volume Volume level (0 to 1, default 1)
3021
3027
  -r rate Playback rate (0.25 to 4, default 1)
3022
- `,stderr:``,exitCode:0}}var NK=null;function PK(){return(!NK||NK.state===`closed`)&&(NK=new AudioContext),NK}async function FK(e,t,n,r){if(typeof window>`u`||typeof AudioContext>`u`)return{stdout:``,stderr:`afplay: Web Audio API unavailable in this environment
3023
- `,exitCode:1};let i=r.fs.resolvePath(r.cwd,e),a;try{a=new Uint8Array(await r.fs.readFileBuffer(i))}catch{return{stdout:``,stderr:`afplay: cannot open ${e}: No such file\n`,exitCode:1}}if(!VW(i).startsWith(`audio/`))return{stdout:``,stderr:`afplay: ${e} is not an audio file\n`,exitCode:1};try{let e=PK();e.state===`suspended`&&await e.resume();let r=new ArrayBuffer(a.byteLength);new Uint8Array(r).set(a);let i=await e.decodeAudioData(r),o=e.createBufferSource();o.buffer=i,o.playbackRate.value=n;let s=e.createGain();return s.gain.value=t,o.connect(s),s.connect(e.destination),new Promise(e=>{o.onended=()=>{e({stdout:``,stderr:``,exitCode:0})},o.start()})}catch(t){return{stdout:``,stderr:`afplay: failed to play ${e}: ${t instanceof Error?t.message:String(t)}\n`,exitCode:1}}}function IK(){return qP(`afplay`,async(e,t)=>{if(e.length===0||e.includes(`--help`)||e.includes(`-h`))return MK();let n=1,r=1,i=null;for(let t=0;t<e.length;t++){let a=e[t];if(a===`-v`){if(t+1>=e.length||e[t+1].startsWith(`-`))return{stdout:``,stderr:`afplay: -v requires a volume value
3028
+ `,stderr:``,exitCode:0}}var IK=null;function LK(){return(!IK||IK.state===`closed`)&&(IK=new AudioContext),IK}async function RK(e,t,n,r){if(typeof window>`u`||typeof AudioContext>`u`)return{stdout:``,stderr:`afplay: Web Audio API unavailable in this environment
3029
+ `,exitCode:1};let i=r.fs.resolvePath(r.cwd,e),a;try{a=new Uint8Array(await r.fs.readFileBuffer(i))}catch{return{stdout:``,stderr:`afplay: cannot open ${e}: No such file\n`,exitCode:1}}if(!VW(i).startsWith(`audio/`))return{stdout:``,stderr:`afplay: ${e} is not an audio file\n`,exitCode:1};try{let e=LK();e.state===`suspended`&&await e.resume();let r=new ArrayBuffer(a.byteLength);new Uint8Array(r).set(a);let i=await e.decodeAudioData(r),o=e.createBufferSource();o.buffer=i,o.playbackRate.value=n;let s=e.createGain();return s.gain.value=t,o.connect(s),s.connect(e.destination),new Promise(e=>{o.onended=()=>{e({stdout:``,stderr:``,exitCode:0})},o.start()})}catch(t){return{stdout:``,stderr:`afplay: failed to play ${e}: ${t instanceof Error?t.message:String(t)}\n`,exitCode:1}}}function zK(){return qP(`afplay`,async(e,t)=>{if(e.length===0||e.includes(`--help`)||e.includes(`-h`))return FK();let n=1,r=1,i=null;for(let t=0;t<e.length;t++){let a=e[t];if(a===`-v`){if(t+1>=e.length||e[t+1].startsWith(`-`))return{stdout:``,stderr:`afplay: -v requires a volume value
3024
3030
  `,exitCode:1};if(n=parseFloat(e[++t]),isNaN(n)||n<0||n>1)return{stdout:``,stderr:`afplay: volume must be between 0 and 1
3025
3031
  `,exitCode:1}}else if(a===`-r`){if(t+1>=e.length||e[t+1].startsWith(`-`))return{stdout:``,stderr:`afplay: -r requires a rate value
3026
3032
  `,exitCode:1};if(r=parseFloat(e[++t]),isNaN(r)||r<.25||r>4)return{stdout:``,stderr:`afplay: rate must be between 0.25 and 4
3027
3033
  `,exitCode:1}}else if(a.startsWith(`-`))return{stdout:``,stderr:`afplay: unknown option: ${a}\n`,exitCode:1};else{if(i!==null)return{stdout:``,stderr:`afplay: only one file can be specified
3028
- `,exitCode:1};i=a}}return i?FK(i,n,r,t):MK()})}function LK(){return qP(`chime`,async(e,t)=>e.includes(`--help`)||e.includes(`-h`)?{stdout:`usage: chime
3034
+ `,exitCode:1};i=a}}return i?RK(i,n,r,t):FK()})}function BK(){return qP(`chime`,async(e,t)=>e.includes(`--help`)||e.includes(`-h`)?{stdout:`usage: chime
3029
3035
 
3030
3036
  Plays a notification chime sound.
3031
3037
  Alias for: afplay /shared/sounds/chime.mp3
3032
- `,stderr:``,exitCode:0}:FK(`/shared/sounds/chime.mp3`,1,1,t))}function RK(){return qP(`debug`,async e=>{if(e.includes(`--help`)||e.includes(`-h`))return{stdout:`usage: debug [on|off]
3038
+ `,stderr:``,exitCode:0}:RK(`/shared/sounds/chime.mp3`,1,1,t))}function VK(){return qP(`debug`,async e=>{if(e.includes(`--help`)||e.includes(`-h`))return{stdout:`usage: debug [on|off]
3033
3039
 
3034
3040
  Toggle debug tabs (Terminal, Memory) in extension mode.
3035
3041
  Without arguments, shows current state.
3036
3042
  `,stderr:``,exitCode:0};let t=e[0]?.toLowerCase();if(t!==`on`&&t!==`off`&&t!==void 0)return{stdout:``,stderr:`debug: unknown argument '${t}' (use 'on' or 'off')\n`,exitCode:1};if(!t)try{let e=localStorage.getItem(`slicc-hidden-tabs`);return{stdout:`Debug tabs: ${(e?JSON.parse(e):[`terminal`,`memory`]).includes(`terminal`)?`off`:`on`}\n`,stderr:``,exitCode:0}}catch{return{stdout:`Debug tabs: off
3037
3043
  `,stderr:``,exitCode:0}}let n=t===`on`,r=window.__slicc_debug_tabs;if(r)return r(n),{stdout:`Debug tabs ${n?`enabled`:`hidden`}\n`,stderr:``,exitCode:0};try{return chrome.runtime.sendMessage({source:`offscreen`,payload:{type:`debug-tabs`,show:n}}),{stdout:`Debug tabs ${n?`enabled`:`hidden`}\n`,stderr:``,exitCode:0}}catch{return{stdout:``,stderr:`debug: failed to send toggle message
3038
- `,exitCode:1}}})}function zK(){return qP(`nuke`,async e=>e.includes(`--help`)||e.includes(`-h`)?{stdout:`Usage: nuke <launch-code>
3044
+ `,exitCode:1}}})}function HK(){return qP(`nuke`,async e=>e.includes(`--help`)||e.includes(`-h`)?{stdout:`Usage: nuke <launch-code>
3039
3045
 
3040
3046
  Completely reset the environment by deleting all local data and reloading.
3041
3047
  Destroys the file system, chat history, and scoops database.
@@ -3043,12 +3049,12 @@ Requires the secret launch code to proceed.
3043
3049
  `,stderr:``,exitCode:0}:e.join(``).includes(`1234`)?(indexedDB.databases().then(e=>{for(let t of e)t.name&&indexedDB.deleteDatabase(t.name)}),setTimeout(()=>location.reload(),0),{stdout:`Nuking everything…
3044
3050
  `,stderr:``,exitCode:0}):{stdout:``,stderr:`⚠️ WARNING: this will reset the entire environment, file system, chats, and scoops.
3045
3051
  Run nuke again with the secret launch code to proceed.
3046
- `,exitCode:1})}function BK(e={}){let t=[JU({getJshCommands:e.getJshCommands}),SW(),yG(e.browserAPI,e.fs),nG(),TW(e),fK(),TG(),xG(`sqlite3`),xG(`sqllite`),QW(),gG(`python3`),gG(`python`),OG(),FG(),RG(),dG(`pdftk`),dG(`pdf`),ZU(`convert`),ZU(`magick`),lK(e.fs),CG(),BG(),iK({fs:e.fs}),_K(),wK(),TK(),EK(`xclip`),EK(`xsel`),jK(),IK(),LK(),zK()];return typeof chrome<`u`&&chrome?.runtime?.id&&t.push(RK()),e.fs&&t.push(...eU.map(t=>GU(t,e.browserAPI,e.fs))),t}var VK=`https://wry-manatee-359.convex.site/api/v1`,HK=`https://api.tessl.io`,UK=`/workspace/skills`,WK=`slicc-fs-global`,GK=`/workspace/.git/github-token`,KK=`application/vnd.github.v3+json`,qK={apps:3,tasks:2,role:1,purpose:1};function JK(e,t){return e.map(e=>{let n=0,r=[],i=(e.affinity.apps??[]).filter(e=>t.apps.includes(e));i.length&&(n+=i.length*qK.apps,r.push(`apps(${i.join(`, `)})`));let a=(e.affinity.tasks??[]).filter(e=>t.tasks.includes(e));return a.length&&(n+=a.length*qK.tasks,r.push(`tasks(${a.join(`, `)})`)),(e.affinity.role??[]).includes(t.role)&&(n+=qK.role,r.push(`role(${t.role})`)),(e.affinity.purpose??[]).includes(t.purpose)&&(n+=qK.purpose,r.push(`purpose(${t.purpose})`)),n*=e.priority??1,{entry:e,score:n,matchReasons:r}}).filter(e=>e.score>0).sort((e,t)=>t.score-e.score)}function YK(e){let t=`upskill ${e.repo}`;return e.path&&(t+=` --path ${e.path}`),e.skill&&(t+=` --skill ${e.skill}`),t}var XK;function ZK(){return XK||=A.create({dbName:WK}),XK}async function QK(){try{return(await(await ZK()).readTextFile(GK)).trim()||void 0}catch{return}}function $K(e,t=KK){let n={Accept:t,"User-Agent":`slicc-upskill`};return e&&(n.Authorization=`Bearer ${e}`),n}async function eq(e){let t=await QK();return{hasToken:!!t,request:(n,r=KK)=>e(n,{headers:$K(t,r)})}}function tq(e,t){if(!e)return;let n=t.toLowerCase();for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return r}function nq(e){if(!e)return;try{let t=JSON.parse(e);if(typeof t.message==`string`&&t.message.trim())return t.message.trim()}catch{}let t=e.trim();if(t)return t.slice(0,200)}function rq(e,t,n){let r=nq(e.body),i=r?` GitHub said: ${r}`:``,a=tq(e.headers,`retry-after`),o=tq(e.headers,`x-ratelimit-remaining`),s=r?.toLowerCase()??``;if(e.status===429||o===`0`||s.includes(`rate limit`))return n?`GitHub rate-limited access to ${t} (HTTP ${e.status}). The configured github.token was used, so retry later${a?` after about ${a} seconds`:``}.${i}`:`GitHub rate-limited anonymous access to ${t} (HTTP ${e.status}). This often happens on shared VPNs or corporate egress IPs because unauthenticated GitHub API requests are limited per IP. Configure a token with: git config github.token <PAT>, then retry. You can also retry off VPN or later.${i}`;if(e.status===401)return n?`GitHub rejected the configured github.token while accessing ${t} (HTTP 401). Update it with: git config github.token <PAT>, then retry.${i}`:`GitHub requires authentication to access ${t} (HTTP 401). Configure a token with: git config github.token <PAT>, then retry.${i}`;if(e.status===404)return`GitHub could not find ${t} (HTTP 404). Check the repository, path, and permissions.${i}`;if(e.status===403)return n?`GitHub denied access to ${t} (HTTP 403). Check that your github.token can access this repository or retry later if GitHub is throttling requests.${i}`:`GitHub denied anonymous access to ${t} (HTTP 403). If this repo is public on a shared VPN, you may have hit GitHub's shared IP limit; otherwise the repository or path may require authentication. Configure a token with: git config github.token <PAT>, then retry.${i}`;let c=e.statusText?` ${e.statusText}`:``;return`GitHub request for ${t} failed (HTTP ${e.status}${c}).${i}`}function iq(){return`Discovery roots: /workspace/skills plus accessible **/.agents/skills/* and **/.claude/skills/* anywhere in the VFS.
3047
- `}function aq(){return`Only native /workspace/skills entries are install-managed; compatibility-discovered .agents/.claude skills remain read-only.
3048
- `}function oq(e){switch(e){case`native`:return`native`;case`agents`:return`.agents`;case`claude`:return`.claude`}}function sq(e){return e.source===`native`}function cq(e){return sq(e)?e.installed&&e.installedVersion?`installed (v${e.installedVersion})`:`available`:e.installed&&e.installedVersion?`compatibility (state v${e.installedVersion})`:`compatibility (read-only)`}function lq(e){return sq(e)?`install-managed (/workspace/skills)`:`compatibility-only (read-only)`}function uq(e,t){let n=`${t}:\n\n`;n+=` NAME VERSION SOURCE STATUS
3052
+ `,exitCode:1})}function UK(e={}){let t=[JU({getJshCommands:e.getJshCommands}),SW(),yG(e.browserAPI,e.fs),nG(),TW(e),hK(),OG(),xG(`sqlite3`),xG(`sqllite`),QW(),gG(`python3`),gG(`python`),jG(),RG(),VG(),dG(`pdftk`),dG(`pdf`),ZU(`convert`),ZU(`magick`),fK(e.fs),CG(),EG(),UG(),sK({fs:e.fs}),bK(),DK(),OK(),kK(`xclip`),kK(`xsel`),PK(),zK(),BK(),HK()];return typeof chrome<`u`&&chrome?.runtime?.id&&t.push(VK()),e.fs&&t.push(...eU.map(t=>GU(t,e.browserAPI,e.fs))),t}var WK=`https://wry-manatee-359.convex.site/api/v1`,GK=`https://api.tessl.io`,KK=`/workspace/skills`,qK=`slicc-fs-global`,JK=`/workspace/.git/github-token`,YK=`application/vnd.github.v3+json`,XK=`https://www.sliccy.com/skills/catalog.json`;function ZK(e){if(!(!e||!e.trim()))return e.split(`,`).map(e=>e.trim()).filter(Boolean)}function QK(e){return e.map(e=>{let t=e.boost?parseFloat(e.boost):NaN,n=Number.isFinite(t)?t:void 0;return{name:e.name,displayName:e.displayName||e.name,description:e.description||``,source:{repo:e.repo,path:e.path||void 0,skill:e.skill||void 0},affinity:{apps:ZK(e.apps),tasks:ZK(e.tasks),role:ZK(e.role),purpose:ZK(e.purpose)},priority:n}})}var $K={apps:3,tasks:2,role:1,purpose:1};function eq(e,t){return e.map(e=>{let n=0,r=[],i=(e.affinity.apps??[]).filter(e=>t.apps.includes(e));i.length&&(n+=i.length*$K.apps,r.push(`apps(${i.join(`, `)})`));let a=(e.affinity.tasks??[]).filter(e=>t.tasks.includes(e));return a.length&&(n+=a.length*$K.tasks,r.push(`tasks(${a.join(`, `)})`)),(e.affinity.role??[]).includes(t.role)&&(n+=$K.role,r.push(`role(${t.role})`)),(e.affinity.purpose??[]).includes(t.purpose)&&(n+=$K.purpose,r.push(`purpose(${t.purpose})`)),n*=e.priority??1,{entry:e,score:n,matchReasons:r}}).filter(e=>e.score>0).sort((e,t)=>t.score-e.score)}function tq(e){let t=`upskill ${e.repo}`;return e.path&&(t+=` --path ${e.path}`),e.skill&&(t+=` --skill ${e.skill}`),t}var nq;function rq(){return nq||=A.create({dbName:qK}),nq}async function iq(){try{return(await(await rq()).readTextFile(JK)).trim()||void 0}catch{return}}function aq(e,t=YK){let n={Accept:t,"User-Agent":`slicc-upskill`};return e&&(n.Authorization=`Bearer ${e}`),n}async function oq(e){let t=await iq();return{hasToken:!!t,request:(n,r=YK)=>e(n,{headers:aq(t,r)})}}function sq(e,t){if(!e)return;let n=t.toLowerCase();for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return r}function cq(e){if(!e)return;try{let t=JSON.parse(e);if(typeof t.message==`string`&&t.message.trim())return t.message.trim()}catch{}let t=e.trim();if(t)return t.slice(0,200)}function lq(e,t,n){let r=cq(e.body),i=r?` GitHub said: ${r}`:``,a=sq(e.headers,`retry-after`),o=sq(e.headers,`x-ratelimit-remaining`),s=r?.toLowerCase()??``;if(e.status===429||o===`0`||s.includes(`rate limit`))return n?`GitHub rate-limited access to ${t} (HTTP ${e.status}). The configured github.token was used, so retry later${a?` after about ${a} seconds`:``}.${i}`:`GitHub rate-limited anonymous access to ${t} (HTTP ${e.status}). This often happens on shared VPNs or corporate egress IPs because unauthenticated GitHub API requests are limited per IP. Configure a token with: git config github.token <PAT>, then retry. You can also retry off VPN or later.${i}`;if(e.status===401)return n?`GitHub rejected the configured github.token while accessing ${t} (HTTP 401). Update it with: git config github.token <PAT>, then retry.${i}`:`GitHub requires authentication to access ${t} (HTTP 401). Configure a token with: git config github.token <PAT>, then retry.${i}`;if(e.status===404)return`GitHub could not find ${t} (HTTP 404). Check the repository, path, and permissions.${i}`;if(e.status===403)return n?`GitHub denied access to ${t} (HTTP 403). Check that your github.token can access this repository or retry later if GitHub is throttling requests.${i}`:`GitHub denied anonymous access to ${t} (HTTP 403). If this repo is public on a shared VPN, you may have hit GitHub's shared IP limit; otherwise the repository or path may require authentication. Configure a token with: git config github.token <PAT>, then retry.${i}`;let c=e.statusText?` ${e.statusText}`:``;return`GitHub request for ${t} failed (HTTP ${e.status}${c}).${i}`}function uq(){return`Discovery roots: /workspace/skills plus accessible **/.agents/skills/* and **/.claude/skills/* anywhere in the VFS.
3053
+ `}function dq(){return`Only native /workspace/skills entries are install-managed; compatibility-discovered .agents/.claude skills remain read-only.
3054
+ `}function fq(e){switch(e){case`native`:return`native`;case`agents`:return`.agents`;case`claude`:return`.claude`}}function pq(e){return e.source===`native`}function mq(e){return pq(e)?e.installed&&e.installedVersion?`installed (v${e.installedVersion})`:`available`:e.installed&&e.installedVersion?`compatibility (state v${e.installedVersion})`:`compatibility (read-only)`}function hq(e){return pq(e)?`install-managed (/workspace/skills)`:`compatibility-only (read-only)`}function gq(e,t){let n=`${t}:\n\n`;n+=` NAME VERSION SOURCE STATUS
3049
3055
  `,n+=` ─────────────────────────────────────────────────────────────
3050
- `;for(let t of e)n+=` ${t.name.padEnd(20)} ${t.manifest.version.padEnd(10)} ${oq(t.source).padEnd(9)} ${cq(t)}\n`;return n+=`\n${iq()}`,n+=aq(),n}function dq(e){let t=`Skill: ${e.manifest.skill}\n`;if(t+=`Version: ${e.manifest.version}\n`,t+=`Description: ${e.manifest.description||`(none)`}\n`,t+=`Source: ${oq(e.source)}\n`,t+=`Source root: ${e.sourceRoot}\n`,t+=`Management: ${lq(e)}\n`,t+=`Status: ${cq(e)}\n`,e.skillFilePath&&(t+=`Instructions: ${e.skillFilePath}\n`),e.shadowedPaths?.length){t+=`Shadowed paths:
3051
- `;for(let n of e.shadowedPaths)t+=` - ${n}\n`}return t}function fq(e,t){return`${e}: "${t.name}" is discoverable from ${t.sourceRoot} but remains compatibility-only/read-only. Only native /workspace/skills entries are install-managed.\n`}function pq(){return{stdout:`usage: upskill <command> [options]
3056
+ `;for(let t of e)n+=` ${t.name.padEnd(20)} ${t.manifest.version.padEnd(10)} ${fq(t.source).padEnd(9)} ${mq(t)}\n`;return n+=`\n${uq()}`,n+=dq(),n}function _q(e){let t=`Skill: ${e.manifest.skill}\n`;if(t+=`Version: ${e.manifest.version}\n`,t+=`Description: ${e.manifest.description||`(none)`}\n`,t+=`Source: ${fq(e.source)}\n`,t+=`Source root: ${e.sourceRoot}\n`,t+=`Management: ${hq(e)}\n`,t+=`Status: ${mq(e)}\n`,e.skillFilePath&&(t+=`Instructions: ${e.skillFilePath}\n`),e.shadowedPaths?.length){t+=`Shadowed paths:
3057
+ `;for(let n of e.shadowedPaths)t+=` - ${n}\n`}return t}function vq(e,t){return`${e}: "${t.name}" is discoverable from ${t.sourceRoot} but remains compatibility-only/read-only. Only native /workspace/skills entries are install-managed.\n`}function yq(){return{stdout:`usage: upskill <command> [options]
3052
3058
 
3053
3059
  Install skills from GitHub repositories, ClawHub, or Tessl registry.
3054
3060
 
@@ -3061,7 +3067,7 @@ Commands:
3061
3067
  <clawhub-url> Install skill from ClawHub URL
3062
3068
  tessl:<name> Install skill from Tessl registry
3063
3069
 
3064
- ${iq()}${aq()}
3070
+ ${uq()}${dq()}
3065
3071
 
3066
3072
  GitHub Installation:
3067
3073
  upskill owner/repo List available skills in repo
@@ -3102,21 +3108,20 @@ Examples:
3102
3108
  upskill aemcoder/skills@fix/stateless-tab-targeting --all
3103
3109
  upskill https://clawhub.ai/arun-8687/tavily-search
3104
3110
  upskill tessl:postgres-pro
3105
- `,stderr:``,exitCode:0}}async function mq(e,t){let n=await t(`${VK}/search?q=${encodeURIComponent(e)}`,{headers:{Accept:`application/json`}});if(n.status!==200)throw Error(`ClawHub returned HTTP ${n.status}`);let r=JSON.parse(n.body);return r.results?r.results.map(e=>({name:e.slug,displayName:e.displayName||e.slug,summary:e.summary||``,source:`clawhub`,qualityScore:null,installHint:`upskill clawhub:${e.slug}`})):[]}function hq(e){let t=e.match(/github\.com\/([^\/?#]+)\/([^\/?#]+)/);return t?{owner:t[1],repo:t[2].replace(/\.git$/,``)}:null}async function gq(e,t){let n=await t(`${HK}/experimental/search?q=${encodeURIComponent(e)}&contentType=skills&page%5Bsize%5D=20`,{headers:{Accept:`application/json`}});if(n.status!==200)throw Error(`Tessl returned HTTP ${n.status}`);let r=JSON.parse(n.body);if(!r.data)return[];let i=new Map;for(let e of r.data){if(e.type!==`skill`)continue;let t=e.attributes,n=hq(t.sourceUrl),r=n?`${n.owner}/${n.repo}`:void 0,a=t.scores.aggregate==null?null:Math.round(t.scores.aggregate*100),o=t.sourceUrl||e.id,s=i.get(o);if(s&&s.qualityScore!=null&&a!=null&&s.qualityScore>=a)continue;let c=t.path.replace(/\/SKILL\.md$/i,``),l=c.split(`/`).pop()||t.name,u=n?`upskill ${n.owner}/${n.repo} --path ${c.split(`/`).slice(0,-1).join(`/`)||`.`} --skill ${l}`:`upskill tessl:${t.name}`;i.set(o,{name:t.name,displayName:t.name,summary:t.description||``,source:`tessl`,qualityScore:a,installHint:u,featured:t.featured,sourceRepo:r})}return Array.from(i.values())}var _q=10;async function vq(e,t,n=1){let[r,i]=await Promise.allSettled([mq(e,t),gq(e,t)]),a=r.status===`fulfilled`?r.value:[],o=i.status===`fulfilled`?i.value:[];if(a.length===0&&o.length===0){let t=``;return r.status===`rejected`&&i.status===`rejected`&&(t=`upskill: both registries failed to respond
3106
- `),{stdout:`No skills found for "${e}"\n\nTry a different search term or browse https://clawhub.ai or https://tessl.io/registry\n`,stderr:t,exitCode:t?1:0}}let s=[],c=0,l=0;for(;c<o.length&&c<3;)s.push(o[c++]);for(;l<a.length||c<o.length;)l<a.length&&s.push(a[l++]),c<o.length&&s.push(o[c++]);let u=s.length,d=Math.ceil(u/_q),f=Math.max(1,Math.min(n,d)),p=(f-1)*_q,m=s.slice(p,p+_q),h=`Search results for "${e}" (page ${f}/${d}, ${u} total):\n\n`;for(let e of m){let t=e.qualityScore==null?` `:String(e.qualityScore).padStart(3),n=`[${e.source}]`,r=e.sourceRepo?` ${e.sourceRepo}`:``;h+=` ${e.name.padEnd(30)} ${t} ${n.padEnd(10)}${r}\n`,e.summary&&(h+=` ${e.summary}\n`),h+=`
3111
+ `,stderr:``,exitCode:0}}async function bq(e,t){let n=await t(`${WK}/search?q=${encodeURIComponent(e)}`,{headers:{Accept:`application/json`}});if(n.status!==200)throw Error(`ClawHub returned HTTP ${n.status}`);let r=JSON.parse(n.body);return r.results?r.results.map(e=>({name:e.slug,displayName:e.displayName||e.slug,summary:e.summary||``,source:`clawhub`,qualityScore:null,installHint:`upskill clawhub:${e.slug}`})):[]}function xq(e){let t=e.match(/github\.com\/([^\/?#]+)\/([^\/?#]+)/);return t?{owner:t[1],repo:t[2].replace(/\.git$/,``)}:null}async function Sq(e,t){let n=await t(`${GK}/experimental/search?q=${encodeURIComponent(e)}&contentType=skills&page%5Bsize%5D=20`,{headers:{Accept:`application/json`}});if(n.status!==200)throw Error(`Tessl returned HTTP ${n.status}`);let r=JSON.parse(n.body);if(!r.data)return[];let i=new Map;for(let e of r.data){if(e.type!==`skill`)continue;let t=e.attributes,n=xq(t.sourceUrl),r=n?`${n.owner}/${n.repo}`:void 0,a=t.scores.aggregate==null?null:Math.round(t.scores.aggregate*100),o=t.sourceUrl||e.id,s=i.get(o);if(s&&s.qualityScore!=null&&a!=null&&s.qualityScore>=a)continue;let c=t.path.replace(/\/SKILL\.md$/i,``),l=c.split(`/`).pop()||t.name,u=n?`upskill ${n.owner}/${n.repo} --path ${c.split(`/`).slice(0,-1).join(`/`)||`.`} --skill ${l}`:`upskill tessl:${t.name}`;i.set(o,{name:t.name,displayName:t.name,summary:t.description||``,source:`tessl`,qualityScore:a,installHint:u,featured:t.featured,sourceRepo:r})}return Array.from(i.values())}var Cq=10;async function wq(e,t,n=1){let[r,i]=await Promise.allSettled([bq(e,t),Sq(e,t)]),a=r.status===`fulfilled`?r.value:[],o=i.status===`fulfilled`?i.value:[];if(a.length===0&&o.length===0){let t=``;return r.status===`rejected`&&i.status===`rejected`&&(t=`upskill: both registries failed to respond
3112
+ `),{stdout:`No skills found for "${e}"\n\nTry a different search term or browse https://clawhub.ai or https://tessl.io/registry\n`,stderr:t,exitCode:t?1:0}}let s=[],c=0,l=0;for(;c<o.length&&c<3;)s.push(o[c++]);for(;l<a.length||c<o.length;)l<a.length&&s.push(a[l++]),c<o.length&&s.push(o[c++]);let u=s.length,d=Math.ceil(u/Cq),f=Math.max(1,Math.min(n,d)),p=(f-1)*Cq,m=s.slice(p,p+Cq),h=`Search results for "${e}" (page ${f}/${d}, ${u} total):\n\n`;for(let e of m){let t=e.qualityScore==null?` `:String(e.qualityScore).padStart(3),n=`[${e.source}]`,r=e.sourceRepo?` ${e.sourceRepo}`:``;h+=` ${e.name.padEnd(30)} ${t} ${n.padEnd(10)}${r}\n`,e.summary&&(h+=` ${e.summary}\n`),h+=`
3107
3113
  `}return f<d&&(h+=`Showing ${p+1}-${p+m.length} of ${u}. `,h+=`Next page: upskill search ${e} --page ${f+1}\n\n`),h+=`To install:
3108
3114
  `,a.length>0&&(h+=` From ClawHub: upskill clawhub:<slug>
3109
3115
  `),o.length>0&&(h+=` From Tessl: upskill <owner/repo> --skill <name>
3110
- `),{stdout:h,stderr:``,exitCode:0}}async function yq(e,t,n,r=!1,i){try{let a=`${UK}/${e}`;try{if(await t.stat(a),!r)return{stdout:``,stderr:`upskill: skill "${e}" already exists (use --force to overwrite)\n`,exitCode:1};await t.rm(a,{recursive:!0})}catch{}let o=`${VK}/download?slug=${encodeURIComponent(e)}`,s=await n(o,{});if(s.status===404)return{stdout:``,stderr:`upskill: skill "${e}" not found on ClawHub\n`,exitCode:1};if(s.status!==200)return{stdout:``,stderr:`upskill: failed to download skill (HTTP ${s.status})\n`,exitCode:1};let c=s.headers[`content-type`]||``,l=uV(o),u=-1,d=0;if(!l){l=new Uint8Array(s.body.length);for(let e=0;e<s.body.length;e++){let t=s.body.charCodeAt(e);t>255&&u<0&&(u=e,d=t),l[e]=t&255}}let f;try{f=le(l)}catch(e){let t=e instanceof Error?e.message:String(e),n=Array.from(l.slice(0,20)).map(e=>e.toString(16).padStart(2,`0`)).join(` `),r=u>=0?`\nBad char at ${u}: code ${d}`:``;return{stdout:``,stderr:`upskill: failed to unzip: ${t}\nContent-Type: ${c}\nBody: ${s.body.length} chars\nHex: ${n}${r}\n`,exitCode:1}}await t.mkdir(a,{recursive:!0});let p=0;for(let[e,n]of Object.entries(f)){let r=e.replace(/\\/g,`/`);if(!r||r.endsWith(`/`)||r===`_meta.json`)continue;let i=`${a}/${r}`,o=i.substring(0,i.lastIndexOf(`/`));o!==a&&await t.mkdir(o,{recursive:!0}),await t.writeFile(i,n),p++}let m=bq(f,i);return await Oq(),{stdout:`Installed skill "${e}" from ClawHub (${p} files)\n${m}`,stderr:``,exitCode:0}}catch(e){return{stdout:``,stderr:`upskill: failed to install from ClawHub: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}}function bq(e,t){let n;for(let[t,r]of Object.entries(e))if((t.split(`/`).pop()||``).toLowerCase()===`skill.md`){n=new TextDecoder().decode(r);break}if(!n)return``;let r=n.match(/^---\s*\n([\s\S]*?)\n---/);if(!r)return``;let i=r[1],a=xq(i);if(a.length===0)return``;if(!t||t.length===0)return` Requires: ${a.join(`, `)}\n`;let o=new Set(t),s=a.filter(e=>!o.has(e));return s.length===0?` Requires: ${a.join(`, `)} (all available)\n`:` Requires: ${a.join(`, `)}\n Missing: ${s.join(`, `)} -- this skill may not work in the SLICC shell\n`}function xq(e){let t=e.match(/metadata:\s*\n\s*(\{[\s\S]*\})/);if(t)try{let e=JSON.parse(t[1]);for(let t of[`openclaw`,`clawdis`,`clawdbot`]){let n=e[t];if(n?.requires&&typeof n.requires==`object`){let e=n.requires;if(Array.isArray(e.bins))return e.bins.filter(e=>typeof e==`string`)}}}catch{}let n=e.match(/"bins"\s*:\s*\[([^\]]*)\]/);return n?n[1].split(`,`).map(e=>e.trim().replace(/^["']|["']$/g,``)).filter(Boolean):[]}async function Sq(e,t){let n=await t(`${HK}/experimental/search?q=${encodeURIComponent(e)}&contentType=skills&page%5Bsize%5D=5`,{headers:{Accept:`application/json`}});if(n.status!==200)return{error:`Tessl search failed (HTTP ${n.status})`};let r=JSON.parse(n.body).data?.find(t=>t.type===`skill`&&t.attributes.name===e);if(!r)return{error:`skill "${e}" not found on Tessl registry`};let i=hq(r.attributes.sourceUrl);if(!i)return{error:`skill "${e}" has no GitHub source URL`};let a=r.attributes.path.replace(/\/SKILL\.md$/i,``);return{owner:i.owner,repo:i.repo,skillPath:a,skillName:e}}async function Cq(e,t,n,r=`main`){let i=`https://codeload.github.com/${e}/${t}/zip/refs/heads/${r}`,a=await n(i,{headers:{"User-Agent":`slicc-upskill`}});if(a.status===404)return r===`main`?Cq(e,t,n,`master`):{status:`not_found`};if(a.status!==200)return{status:`error`,message:`codeload returned HTTP ${a.status}`};let o=uV(i);if(!o){o=new Uint8Array(a.body.length);for(let e=0;e<a.body.length;e++)o[e]=a.body.charCodeAt(e)&255}try{return{status:`ok`,files:le(o)}}catch(e){return{status:`error`,message:`failed to unzip: ${e instanceof Error?e.message:String(e)}`}}}function wq(e){let t={};for(let[n,r]of Object.entries(e)){let e=n.indexOf(`/`);if(e<0)continue;let i=n.slice(e+1);i&&(t[i]=r)}return t}async function Tq(e,t,n,r,i,a){if(i){let n=await Cq(e,t,i,a);if(n.status===`ok`){let e=wq(n.files),t=[],i=r?r.replace(/^\/|\/$/g,``)+`/`:``;for(let n of Object.keys(e))if(n.startsWith(i)&&(n.split(`/`).pop()||``)===`SKILL.md`){let e=n.replace(/\/SKILL\.md$/,``),r=e.split(`/`).pop()||e;t.push({name:r,path:e})}return{skills:t}}if(n.status===`not_found`)return{skills:[],error:`${a?`branch "${a}" in ${e}/${t}`:`repository ${e}/${t}`} not found`}}let o=[];async function s(r){let i=`https://api.github.com/repos/${e}/${t}/contents/${r}`,c=a?`${i}?ref=${encodeURIComponent(a)}`:i,l=await n.request(c);if(l.status!==200)throw Error(rq(l,`${e}/${t}${r?`/${r}`:``}`,n.hasToken));let u=JSON.parse(l.body);for(let e of u)if(e.type===`file`&&e.name===`SKILL.md`){let t=e.path.replace(`/SKILL.md`,``),n=t.split(`/`).pop()||t;o.push({name:n,path:t})}else e.type===`dir`&&await s(e.path)}try{return await s(r||``),{skills:o}}catch(e){return{skills:[],error:e instanceof Error?e.message:String(e)}}}async function Eq(e,t,n,r,i,a,o=!1,s,c){try{let l=`${UK}/${r}`;try{if(await i.stat(l),!o)return{stdout:``,stderr:`upskill: skill "${r}" already exists (use --force to overwrite)\n`,exitCode:1};await i.rm(l,{recursive:!0})}catch{}if(s){let a=await Cq(e,t,s,c);if(a.status===`not_found`)return{stdout:``,stderr:`upskill: ${c?`branch "${c}" in ${e}/${t}`:`repository ${e}/${t}`} not found\n`,exitCode:1};if(a.status===`ok`){let o=wq(a.files),s=n.replace(/^\/|\/$/g,``)+`/`;await i.mkdir(l,{recursive:!0});let c=0;for(let[e,t]of Object.entries(o)){if(!e.startsWith(s))continue;let n=e.slice(s.length);if(!n||e.endsWith(`/`))continue;let r=`${l}/${n}`,a=r.substring(0,r.lastIndexOf(`/`));a!==l&&await i.mkdir(a,{recursive:!0}),await i.writeFile(r,t),c++}if(c>0)return await Mq(),await Aq(),{stdout:`Installed skill "${r}" from ${e}/${t}\n`,stderr:``,exitCode:0}}}let u=`https://api.github.com/repos/${e}/${t}/contents/${n}`,d=c?`${u}?ref=${encodeURIComponent(c)}`:u,f=await a.request(d);if(f.status!==200)return{stdout:``,stderr:`upskill: ${rq(f,`${e}/${t}/${n}`,a.hasToken)}\n`,exitCode:1};let p=JSON.parse(f.body);await i.mkdir(l,{recursive:!0});async function m(n,r){for(let o of n)if(o.type===`file`&&o.download_url){let n=await a.request(o.download_url,`*/*`);if(n.status!==200)throw Error(rq(n,`${e}/${t}/${o.path}`,a.hasToken));let s=uV(o.download_url);await i.writeFile(`${r}/${o.name}`,s??n.body)}else if(o.type===`dir`){let n=`https://api.github.com/repos/${e}/${t}/contents/${o.path}`,s=c?`${n}?ref=${encodeURIComponent(c)}`:n,l=await a.request(s);if(l.status!==200)throw Error(rq(l,`${e}/${t}/${o.path}`,a.hasToken));let u=JSON.parse(l.body);await i.mkdir(`${r}/${o.name}`,{recursive:!0}),await m(u,`${r}/${o.name}`)}}try{await m(p,l)}catch(e){try{await i.rm(l,{recursive:!0})}catch{}throw e}return await Oq(),{stdout:`Installed skill "${r}" from ${e}/${t}\n`,stderr:``,exitCode:0}}catch(e){return{stdout:``,stderr:`upskill: failed to install from GitHub: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}}function Dq(e){let t=e.match(/^https?:\/\/clawhub\.ai\/[^\/]+\/([^\/]+)/);if(t)return t[1];if(e.startsWith(`clawhub:`)){let t=e.slice(8);return t.includes(`/`)?t.split(`/`)[1]:t}return null}async function Oq(){await Mq(),await Aq()}async function kq(e,t,n,r,i=!1){let a=`${UK}/${t}`;try{if(await r.stat(a),!i)return{ok:!1,error:`skill "${t}" already exists (use --force to overwrite)`};await r.rm(a,{recursive:!0})}catch{}let o=e.replace(/^\/|\/$/g,``),s=o?o+`/`:``;await r.mkdir(a,{recursive:!0});let c=0;try{for(let[e,t]of Object.entries(n)){if(!e.startsWith(s))continue;let n=e.slice(s.length);if(!n||e.endsWith(`/`))continue;let i=`${a}/${n}`,o=i.replace(/\/+/g,`/`);if(o.includes(`/../`)||o.includes(`/..`)||!o.startsWith(a+`/`))continue;let l=i.substring(0,i.lastIndexOf(`/`));l!==a&&await r.mkdir(l,{recursive:!0}),await r.writeFile(i,t),c++}}catch(e){throw await r.rm(a,{recursive:!0}).catch(()=>{}),e}return c===0?(await r.rm(a,{recursive:!0}).catch(()=>{}),{ok:!1,error:`no files found for skill "${t}" in ZIP`}):{ok:!0}}async function Aq(){try{let e=(typeof window<`u`?window:globalThis).__slicc_reloadSkills;if(typeof e==`function`){await e();return}typeof chrome<`u`&&chrome?.runtime?.sendMessage&&chrome.runtime.sendMessage({source:`panel`,payload:{type:`reload-skills`}})}catch{}}function jq(e){let t=e.match(/^([a-zA-Z0-9_-]+)\/([a-zA-Z0-9_.-]+)(?:@([a-zA-Z0-9_./\-]+))?$/);return t?{owner:t[1],repo:t[2],branch:t[3]}:null}async function Mq(){try{if(typeof window>`u`)return;let e=window.__slicc_sprinkleManager;e&&typeof e.openNewAutoOpenSprinkles==`function`&&await e.openNewAutoOpenSprinkles()}catch{}}async function Nq(e,t,n){let r=null;try{let t=await e.readDir(`/home`);for(let n of t)try{let t=await e.readTextFile(`/home/${n.name}/.welcome.json`);r=JSON.parse(t);break}catch{}}catch{}if(!r)return{stdout:``,stderr:`upskill: no user profile found. Complete the welcome onboarding first, or create /home/<name>/.welcome.json manually.
3111
- `,exitCode:1};let i;try{let t=await e.readTextFile(`/shared/skill-catalog.json`);i=JSON.parse(t)}catch{return{stdout:``,stderr:`upskill: skill catalog not found at /shared/skill-catalog.json
3112
- `,exitCode:1}}let a=new Set;try{let t=await(await y(()=>import(`./skills-Ke92WMkl.js`),__vite__mapDeps([15,16,17,1,18]))).discoverSkills(e);for(let e of t)a.add(e.name)}catch{}let o=JK(i.skills,r).filter(e=>!a.has(e.entry.name));if(o.length===0)return{stdout:`No new skill recommendations all matching skills are already installed.
3113
- `,stderr:``,exitCode:0};if(n){let n=new Map;for(let e of o){let t=e.entry.source.repo,r=n.get(t);r?r.push(e):n.set(t,[e])}let r=o.length,i=0,a=Date.now(),s=``,c=``,l=0,u=await Promise.allSettled(Array.from(n.entries()).map(async([n,o])=>{let[c,l]=n.split(`/`),u=await Cq(c,l,t);if(u.status===`not_found`||u.status===`error`){let e=u.status===`not_found`?`upskill: repository ${n} not found\n`:`upskill: failed to fetch ${n}: ${u.message}\n`,t=[];for(let e of o){i++,((Date.now()-a)/1e3).toFixed(1);let o=i<r?` (~${Math.round((r-i)*(Date.now()-a)/i/1e3)}s remaining)`:``;s+=`[${i}/${r}] Failed "${e.entry.name}" from ${n}: repo fetch failed${o}\n`,t.push({ok:!1,name:e.entry.name,error:`repo fetch failed for ${n}`})}return{errors:e,results:t}}let d=wq(u.files),f=[],p=new Map;for(let e of Object.keys(d))if(e.endsWith(`/SKILL.md`)){let t=e.replace(/\/SKILL\.md$/,``),n=t.split(`/`).pop()||t;p.set(n,t)}for(let t of o){let o=t.entry.source,c,l;if(o.skill){let e=p.get(o.skill);if(!e){let e=`skill "${o.skill}" not found in ${n}`;f.push({ok:!1,name:t.entry.name,error:e}),i++,((Date.now()-a)/1e3).toFixed(1);let c=i<r?` (~${Math.round((r-i)*(Date.now()-a)/i/1e3)}s remaining)`:``;s+=`[${i}/${r}] Failed "${t.entry.name}" from ${n}: ${e}${c}\n`;continue}c=e,l=o.skill}else c=o.path?o.path.replace(/^\/|\/$/g,``):``,l=t.entry.name;let u=Date.now(),m=await kq(c,l,d,e,!1);i++;let h=((Date.now()-u)/1e3).toFixed(1),g=(Date.now()-a)/i,_=Math.round((r-i)*g/1e3),v=i<r?` (~${_}s remaining)`:``;m.ok?(f.push({ok:!0,name:l}),s+=`[${i}/${r}] Installed "${l}" from ${n} (${h}s)${v}\n`):(f.push({ok:!1,name:l,error:m.error}),s+=`[${i}/${r}] Failed "${l}" from ${n}: ${m.error}${v}\n`)}return{errors:``,results:f}}));for(let e of u){if(e.status===`rejected`){c+=`upskill: unexpected error: ${e.reason}\n`;continue}e.value.errors&&(c+=e.value.errors);for(let t of e.value.results)t.ok?l++:t.error&&(c+=`upskill: ${t.error}\n`)}let d=((Date.now()-a)/1e3).toFixed(1);return l>0&&(s+=`\nInstalled ${l} recommended skill(s) in ${d}s\n`,await Oq()),{stdout:s,stderr:c,exitCode:c?1:0}}let s=`Recommended skills for you:
3116
+ `),{stdout:h,stderr:``,exitCode:0}}async function Tq(e,t,n,r=!1,i){try{let a=`${KK}/${e}`;try{if(await t.stat(a),!r)return{stdout:``,stderr:`upskill: skill "${e}" already exists (use --force to overwrite)\n`,exitCode:1};await t.rm(a,{recursive:!0})}catch{}let o=`${WK}/download?slug=${encodeURIComponent(e)}`,s=await n(o,{});if(s.status===404)return{stdout:``,stderr:`upskill: skill "${e}" not found on ClawHub\n`,exitCode:1};if(s.status!==200)return{stdout:``,stderr:`upskill: failed to download skill (HTTP ${s.status})\n`,exitCode:1};let c=s.headers[`content-type`]||``,l=uV(o),u=-1,d=0;if(!l){l=new Uint8Array(s.body.length);for(let e=0;e<s.body.length;e++){let t=s.body.charCodeAt(e);t>255&&u<0&&(u=e,d=t),l[e]=t&255}}let f;try{f=le(l)}catch(e){let t=e instanceof Error?e.message:String(e),n=Array.from(l.slice(0,20)).map(e=>e.toString(16).padStart(2,`0`)).join(` `),r=u>=0?`\nBad char at ${u}: code ${d}`:``;return{stdout:``,stderr:`upskill: failed to unzip: ${t}\nContent-Type: ${c}\nBody: ${s.body.length} chars\nHex: ${n}${r}\n`,exitCode:1}}await t.mkdir(a,{recursive:!0});let p=0;for(let[e,n]of Object.entries(f)){let r=e.replace(/\\/g,`/`);if(!r||r.endsWith(`/`)||r===`_meta.json`)continue;let i=`${a}/${r}`,o=i.substring(0,i.lastIndexOf(`/`));o!==a&&await t.mkdir(o,{recursive:!0}),await t.writeFile(i,n),p++}let m=Eq(f,i);return await Pq(),{stdout:`Installed skill "${e}" from ClawHub (${p} files)\n${m}`,stderr:``,exitCode:0}}catch(e){return{stdout:``,stderr:`upskill: failed to install from ClawHub: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}}function Eq(e,t){let n;for(let[t,r]of Object.entries(e))if((t.split(`/`).pop()||``).toLowerCase()===`skill.md`){n=new TextDecoder().decode(r);break}if(!n)return``;let r=n.match(/^---\s*\n([\s\S]*?)\n---/);if(!r)return``;let i=r[1],a=Dq(i);if(a.length===0)return``;if(!t||t.length===0)return` Requires: ${a.join(`, `)}\n`;let o=new Set(t),s=a.filter(e=>!o.has(e));return s.length===0?` Requires: ${a.join(`, `)} (all available)\n`:` Requires: ${a.join(`, `)}\n Missing: ${s.join(`, `)} -- this skill may not work in the SLICC shell\n`}function Dq(e){let t=e.match(/metadata:\s*\n\s*(\{[\s\S]*\})/);if(t)try{let e=JSON.parse(t[1]);for(let t of[`openclaw`,`clawdis`,`clawdbot`]){let n=e[t];if(n?.requires&&typeof n.requires==`object`){let e=n.requires;if(Array.isArray(e.bins))return e.bins.filter(e=>typeof e==`string`)}}}catch{}let n=e.match(/"bins"\s*:\s*\[([^\]]*)\]/);return n?n[1].split(`,`).map(e=>e.trim().replace(/^["']|["']$/g,``)).filter(Boolean):[]}async function Oq(e,t){let n=await t(`${GK}/experimental/search?q=${encodeURIComponent(e)}&contentType=skills&page%5Bsize%5D=5`,{headers:{Accept:`application/json`}});if(n.status!==200)return{error:`Tessl search failed (HTTP ${n.status})`};let r=JSON.parse(n.body).data?.find(t=>t.type===`skill`&&t.attributes.name===e);if(!r)return{error:`skill "${e}" not found on Tessl registry`};let i=xq(r.attributes.sourceUrl);if(!i)return{error:`skill "${e}" has no GitHub source URL`};let a=r.attributes.path.replace(/\/SKILL\.md$/i,``);return{owner:i.owner,repo:i.repo,skillPath:a,skillName:e}}async function kq(e,t,n,r=`main`){let i=`https://codeload.github.com/${e}/${t}/zip/refs/heads/${r}`,a=await n(i,{headers:{"User-Agent":`slicc-upskill`}});if(a.status===404)return r===`main`?kq(e,t,n,`master`):{status:`not_found`};if(a.status!==200)return{status:`error`,message:`codeload returned HTTP ${a.status}`};let o=uV(i);if(!o){o=new Uint8Array(a.body.length);for(let e=0;e<a.body.length;e++)o[e]=a.body.charCodeAt(e)&255}try{return{status:`ok`,files:le(o)}}catch(e){return{status:`error`,message:`failed to unzip: ${e instanceof Error?e.message:String(e)}`}}}function Aq(e){let t={};for(let[n,r]of Object.entries(e)){let e=n.indexOf(`/`);if(e<0)continue;let i=n.slice(e+1);i&&(t[i]=r)}return t}async function jq(e,t,n,r,i,a){if(i){let n=await kq(e,t,i,a);if(n.status===`ok`){let e=Aq(n.files),t=[],i=r?r.replace(/^\/|\/$/g,``)+`/`:``;for(let n of Object.keys(e))if(n.startsWith(i)&&(n.split(`/`).pop()||``)===`SKILL.md`){let e=n.replace(/\/SKILL\.md$/,``),r=e.split(`/`).pop()||e;t.push({name:r,path:e})}return{skills:t}}if(n.status===`not_found`)return{skills:[],error:`${a?`branch "${a}" in ${e}/${t}`:`repository ${e}/${t}`} not found`}}let o=[];async function s(r){let i=`https://api.github.com/repos/${e}/${t}/contents/${r}`,c=a?`${i}?ref=${encodeURIComponent(a)}`:i,l=await n.request(c);if(l.status!==200)throw Error(lq(l,`${e}/${t}${r?`/${r}`:``}`,n.hasToken));let u=JSON.parse(l.body);for(let e of u)if(e.type===`file`&&e.name===`SKILL.md`){let t=e.path.replace(`/SKILL.md`,``),n=t.split(`/`).pop()||t;o.push({name:n,path:t})}else e.type===`dir`&&await s(e.path)}try{return await s(r||``),{skills:o}}catch(e){return{skills:[],error:e instanceof Error?e.message:String(e)}}}async function Mq(e,t,n,r,i,a,o=!1,s,c){try{let l=`${KK}/${r}`;try{if(await i.stat(l),!o)return{stdout:``,stderr:`upskill: skill "${r}" already exists (use --force to overwrite)\n`,exitCode:1};await i.rm(l,{recursive:!0})}catch{}if(s){let a=await kq(e,t,s,c);if(a.status===`not_found`)return{stdout:``,stderr:`upskill: ${c?`branch "${c}" in ${e}/${t}`:`repository ${e}/${t}`} not found\n`,exitCode:1};if(a.status===`ok`){let o=Aq(a.files),s=n.replace(/^\/|\/$/g,``)+`/`;await i.mkdir(l,{recursive:!0});let c=0;for(let[e,t]of Object.entries(o)){if(!e.startsWith(s))continue;let n=e.slice(s.length);if(!n||e.endsWith(`/`))continue;let r=`${l}/${n}`,a=r.substring(0,r.lastIndexOf(`/`));a!==l&&await i.mkdir(a,{recursive:!0}),await i.writeFile(r,t),c++}if(c>0)return await Rq(),await Iq(),{stdout:`Installed skill "${r}" from ${e}/${t}\n`,stderr:``,exitCode:0}}}let u=`https://api.github.com/repos/${e}/${t}/contents/${n}`,d=c?`${u}?ref=${encodeURIComponent(c)}`:u,f=await a.request(d);if(f.status!==200)return{stdout:``,stderr:`upskill: ${lq(f,`${e}/${t}/${n}`,a.hasToken)}\n`,exitCode:1};let p=JSON.parse(f.body);await i.mkdir(l,{recursive:!0});async function m(n,r){for(let o of n)if(o.type===`file`&&o.download_url){let n=await a.request(o.download_url,`*/*`);if(n.status!==200)throw Error(lq(n,`${e}/${t}/${o.path}`,a.hasToken));let s=uV(o.download_url);await i.writeFile(`${r}/${o.name}`,s??n.body)}else if(o.type===`dir`){let n=`https://api.github.com/repos/${e}/${t}/contents/${o.path}`,s=c?`${n}?ref=${encodeURIComponent(c)}`:n,l=await a.request(s);if(l.status!==200)throw Error(lq(l,`${e}/${t}/${o.path}`,a.hasToken));let u=JSON.parse(l.body);await i.mkdir(`${r}/${o.name}`,{recursive:!0}),await m(u,`${r}/${o.name}`)}}try{await m(p,l)}catch(e){try{await i.rm(l,{recursive:!0})}catch{}throw e}return await Pq(),{stdout:`Installed skill "${r}" from ${e}/${t}\n`,stderr:``,exitCode:0}}catch(e){return{stdout:``,stderr:`upskill: failed to install from GitHub: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}}function Nq(e){let t=e.match(/^https?:\/\/clawhub\.ai\/[^\/]+\/([^\/]+)/);if(t)return t[1];if(e.startsWith(`clawhub:`)){let t=e.slice(8);return t.includes(`/`)?t.split(`/`)[1]:t}return null}async function Pq(){await Rq(),await Iq()}async function Fq(e,t,n,r,i=!1){let a=`${KK}/${t}`;try{if(await r.stat(a),!i)return{ok:!1,error:`skill "${t}" already exists (use --force to overwrite)`};await r.rm(a,{recursive:!0})}catch{}let o=e.replace(/^\/|\/$/g,``),s=o?o+`/`:``;await r.mkdir(a,{recursive:!0});let c=0;try{for(let[e,t]of Object.entries(n)){if(!e.startsWith(s))continue;let n=e.slice(s.length);if(!n||e.endsWith(`/`))continue;let i=`${a}/${n}`,o=i.replace(/\/+/g,`/`);if(o.includes(`/../`)||o.includes(`/..`)||!o.startsWith(a+`/`))continue;let l=i.substring(0,i.lastIndexOf(`/`));l!==a&&await r.mkdir(l,{recursive:!0}),await r.writeFile(i,t),c++}}catch(e){throw await r.rm(a,{recursive:!0}).catch(()=>{}),e}return c===0?(await r.rm(a,{recursive:!0}).catch(()=>{}),{ok:!1,error:`no files found for skill "${t}" in ZIP`}):{ok:!0}}async function Iq(){try{let e=(typeof window<`u`?window:globalThis).__slicc_reloadSkills;if(typeof e==`function`){await e();return}typeof chrome<`u`&&chrome?.runtime?.sendMessage&&chrome.runtime.sendMessage({source:`panel`,payload:{type:`reload-skills`}})}catch{}}function Lq(e){let t=e.match(/^([a-zA-Z0-9_-]+)\/([a-zA-Z0-9_.-]+)(?:@([a-zA-Z0-9_./\-]+))?$/);return t?{owner:t[1],repo:t[2],branch:t[3]}:null}async function Rq(){try{if(typeof window>`u`)return;let e=window.__slicc_sprinkleManager;e&&typeof e.openNewAutoOpenSprinkles==`function`&&await e.openNewAutoOpenSprinkles()}catch{}}async function zq(e,t,n){let r=null;try{let t=await e.readDir(`/home`);for(let n of t)try{let t=await e.readTextFile(`/home/${n.name}/.welcome.json`);r=JSON.parse(t);break}catch{}}catch{}if(!r)return{stdout:``,stderr:`upskill: no user profile found. Complete the welcome onboarding first, or create /home/<name>/.welcome.json manually.
3117
+ `,exitCode:1};let i;try{let e=await t(XK,{headers:{Accept:`application/json`}});if(e.status!==200)throw Error(`HTTP ${e.status}`);i=QK(JSON.parse(e.body).data)}catch(e){return{stdout:``,stderr:`upskill: failed to fetch skill catalog from ${XK}: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}let a=new Set;try{let t=await(await y(()=>import(`./skills-Ke92WMkl.js`),__vite__mapDeps([15,16,17,1,18]))).discoverSkills(e);for(let e of t)a.add(e.name)}catch{}let o=eq(i,r).filter(e=>!a.has(e.entry.name));if(o.length===0)return{stdout:`No new skill recommendations — all matching skills are already installed.
3118
+ `,stderr:``,exitCode:0};if(n){let n=new Map;for(let e of o){let t=e.entry.source.repo,r=n.get(t);r?r.push(e):n.set(t,[e])}let r=o.length,i=0,a=Date.now(),s=``,c=``,l=0,u=await Promise.allSettled(Array.from(n.entries()).map(async([n,o])=>{let[c,l]=n.split(`/`),u=await kq(c,l,t);if(u.status===`not_found`||u.status===`error`){let e=u.status===`not_found`?`upskill: repository ${n} not found\n`:`upskill: failed to fetch ${n}: ${u.message}\n`,t=[];for(let e of o){i++,((Date.now()-a)/1e3).toFixed(1);let o=i<r?` (~${Math.round((r-i)*(Date.now()-a)/i/1e3)}s remaining)`:``;s+=`[${i}/${r}] Failed "${e.entry.name}" from ${n}: repo fetch failed${o}\n`,t.push({ok:!1,name:e.entry.name,error:`repo fetch failed for ${n}`})}return{errors:e,results:t}}let d=Aq(u.files),f=[],p=new Map;for(let e of Object.keys(d))if(e.endsWith(`/SKILL.md`)){let t=e.replace(/\/SKILL\.md$/,``),n=t.split(`/`).pop()||t;p.set(n,t)}for(let t of o){let o=t.entry.source,c,l;if(o.skill){let e=p.get(o.skill);if(!e){let e=`skill "${o.skill}" not found in ${n}`;f.push({ok:!1,name:t.entry.name,error:e}),i++,((Date.now()-a)/1e3).toFixed(1);let c=i<r?` (~${Math.round((r-i)*(Date.now()-a)/i/1e3)}s remaining)`:``;s+=`[${i}/${r}] Failed "${t.entry.name}" from ${n}: ${e}${c}\n`;continue}c=e,l=o.skill}else c=o.path?o.path.replace(/^\/|\/$/g,``):``,l=t.entry.name;let u=Date.now(),m=await Fq(c,l,d,e,!1);i++;let h=((Date.now()-u)/1e3).toFixed(1),g=(Date.now()-a)/i,_=Math.round((r-i)*g/1e3),v=i<r?` (~${_}s remaining)`:``;m.ok?(f.push({ok:!0,name:l}),s+=`[${i}/${r}] Installed "${l}" from ${n} (${h}s)${v}\n`):(f.push({ok:!1,name:l,error:m.error}),s+=`[${i}/${r}] Failed "${l}" from ${n}: ${m.error}${v}\n`)}return{errors:``,results:f}}));for(let e of u){if(e.status===`rejected`){c+=`upskill: unexpected error: ${e.reason}\n`;continue}e.value.errors&&(c+=e.value.errors);for(let t of e.value.results)t.ok?l++:t.error&&(c+=`upskill: ${t.error}\n`)}let d=((Date.now()-a)/1e3).toFixed(1);return l>0&&(s+=`\nInstalled ${l} recommended skill(s) in ${d}s\n`,await Pq()),{stdout:s,stderr:c,exitCode:c?1:0}}let s=`Recommended skills for you:
3114
3119
 
3115
- `,c=0;for(let e of o){c++;let t=YK(e.entry.source);s+=` ${c}. ${e.entry.displayName.padEnd(35)} score: ${Math.round(e.score)}\n`,s+=` ${e.entry.description}\n`,s+=` Match: ${e.matchReasons.join(`, `)}\n`,s+=` Install: ${t}\n\n`}return s+=`To install all recommended: upskill recommendations --install
3116
- `,{stdout:s,stderr:``,exitCode:0}}function Pq(e,t){return qP(`upskill`,async(n,r)=>{if(n.length===0||n.includes(`--help`)||n.includes(`-h`))return pq();let i=[],a,o=!1,s=!1,c=!1,l=``,u,d=``,f=1,p=0;for(;p<n.length;){let r=n[p];if(r===`search`){let e=n.slice(p+1),t=e.indexOf(`--page`);t>=0&&(f=parseInt(e[t+1],10)||1,e.splice(t,2)),d=e.join(` `);break}else if(r===`recommendations`)return Nq(e,t,n.includes(`--install`));else if(r===`list`){let t=await(await y(()=>import(`./skills-Ke92WMkl.js`),__vite__mapDeps([15,16,17,1,18]))).discoverSkills(e);return t.length===0?{stdout:`No discoverable local skills found.\n\n${iq()}${aq()}`,stderr:``,exitCode:0}:{stdout:uq(t,`Discoverable local skills`),stderr:``,exitCode:0}}else if(r===`info`||r===`read`){let t=n[p+1];if(!t)return{stdout:``,stderr:`upskill: ${r} requires a skill name\n`,exitCode:1};let i=await y(()=>import(`./skills-Ke92WMkl.js`),__vite__mapDeps([15,16,17,1,18]));if(r===`info`){let n=await i.getSkillInfo(e,t);return n?{stdout:dq(n),stderr:``,exitCode:0}:{stdout:``,stderr:`upskill: skill "${t}" not found\n`,exitCode:1}}else{let n=await i.readSkillInstructions(e,t);return n===null?{stdout:``,stderr:`upskill: no SKILL.md found for "${t}"\n`,exitCode:1}:{stdout:n+`
3120
+ `,c=0;for(let e of o){c++;let t=tq(e.entry.source);s+=` ${c}. ${e.entry.displayName.padEnd(35)} score: ${Math.round(e.score)}\n`,s+=` ${e.entry.description}\n`,s+=` Match: ${e.matchReasons.join(`, `)}\n`,s+=` Install: ${t}\n\n`}return s+=`To install all recommended: upskill recommendations --install
3121
+ `,{stdout:s,stderr:``,exitCode:0}}function Bq(e,t){return qP(`upskill`,async(n,r)=>{if(n.length===0||n.includes(`--help`)||n.includes(`-h`))return yq();let i=[],a,o=!1,s=!1,c=!1,l=``,u,d=``,f=1,p=0;for(;p<n.length;){let r=n[p];if(r===`search`){let e=n.slice(p+1),t=e.indexOf(`--page`);t>=0&&(f=parseInt(e[t+1],10)||1,e.splice(t,2)),d=e.join(` `);break}else if(r===`recommendations`)return zq(e,t,n.includes(`--install`));else if(r===`list`){let t=await(await y(()=>import(`./skills-Ke92WMkl.js`),__vite__mapDeps([15,16,17,1,18]))).discoverSkills(e);return t.length===0?{stdout:`No discoverable local skills found.\n\n${uq()}${dq()}`,stderr:``,exitCode:0}:{stdout:gq(t,`Discoverable local skills`),stderr:``,exitCode:0}}else if(r===`info`||r===`read`){let t=n[p+1];if(!t)return{stdout:``,stderr:`upskill: ${r} requires a skill name\n`,exitCode:1};let i=await y(()=>import(`./skills-Ke92WMkl.js`),__vite__mapDeps([15,16,17,1,18]));if(r===`info`){let n=await i.getSkillInfo(e,t);return n?{stdout:_q(n),stderr:``,exitCode:0}:{stdout:``,stderr:`upskill: skill "${t}" not found\n`,exitCode:1}}else{let n=await i.readSkillInstructions(e,t);return n===null?{stdout:``,stderr:`upskill: no SKILL.md found for "${t}"\n`,exitCode:1}:{stdout:n+`
3117
3122
  `,stderr:``,exitCode:0}}}else if(r===`--skill`)i.push(n[++p]);else if(r===`--path`||r===`-p`)a=n[++p];else if(r===`--list`)o=!0;else if(r===`--all`)s=!0;else if(r===`--force`)c=!0;else if(r===`--branch`||r===`-b`){let e=n[p+1];if(!e||e.startsWith(`-`))return{stdout:``,stderr:`upskill: --branch requires a value
3118
- `,exitCode:1};u=n[++p]}else r.startsWith(`-`)||(l=r);p++}if(d)return vq(d,t,f);if(!l)return pq();let m=Dq(l);if(m){let n=r.getRegisteredCommands?.()??[];return yq(m,e,t,c,n)}if(l.startsWith(`tessl:`)){let n=l.slice(6);if(!n)return{stdout:``,stderr:`upskill: tessl: requires a skill name
3119
- `,exitCode:1};let r=await Sq(n,t);if(`error`in r)return{stdout:``,stderr:`upskill: ${r.error}\n`,exitCode:1};let i=await eq(t);return Eq(r.owner,r.repo,r.skillPath,r.skillName,e,i,c,t)}let h=jq(l);if(h){let{owner:n,repo:r}=h,d=u??h.branch,f=await eq(t),p=await Tq(n,r,f,a,t,d);if(p.error)return{stdout:``,stderr:`upskill: failed to list skills: ${p.error}\n`,exitCode:1};if(p.skills.length===0)return{stdout:`No skills found in ${n}/${r}${a?`/`+a:``}\n`,stderr:``,exitCode:0};if(o){let e=`Available skills in ${n}/${r}:\n\n`;for(let t of p.skills)e+=` ${t.name.padEnd(30)} ${t.path}\n`;return e+=`\nFound ${p.skills.length} skill(s)\n`,e+=`\nTo install: upskill ${l} --skill <name>\n`,e+=`To install all: upskill ${l} --all\n`,{stdout:e,stderr:``,exitCode:0}}let m=p.skills;if(i.length>0){m=p.skills.filter(e=>i.includes(e.name));for(let e of i)if(!p.skills.find(t=>t.name===e))return{stdout:``,stderr:`upskill: skill "${e}" not found in ${n}/${r}\n`,exitCode:1}}else if(!s){let e=`Available skills in ${n}/${r}:\n\n`;for(let t of p.skills)e+=` ${t.name.padEnd(30)} ${t.path}\n`;return e+=`\nFound ${p.skills.length} skill(s)\n`,e+=`\nTo install specific skills: upskill ${l} --skill <name>\n`,e+=`To install all: upskill ${l} --all\n`,{stdout:e,stderr:``,exitCode:0}}let g=``,_=``,v=0,y=m.length,b=Date.now();if(y>1){let i=await Cq(n,r,t,d);if(i.status===`not_found`)return{stdout:``,stderr:`upskill: ${d?`branch "${d}" in ${n}/${r}`:`repository ${n}/${r}`} not found\n`,exitCode:1};if(i.status===`error`)return{stdout:``,stderr:`upskill: failed to fetch ${n}/${r}: ${i.message}\n`,exitCode:1};let a=wq(i.files);for(let t=0;t<m.length;t++){let i=m[t],o=await kq(i.path,i.name,a,e,c),s=t+1,l=((Date.now()-b)/1e3).toFixed(1),u=(Date.now()-b)/s,d=Math.round((y-s)*u/1e3),f=s<y?` (~${d}s remaining)`:``;o.ok?(g+=`[${s}/${y}] Installed "${i.name}" from ${n}/${r} (${l}s)${f}\n`,v++):(g+=`[${s}/${y}] Failed "${i.name}": ${o.error}${f}\n`,_+=`upskill: ${o.error}\n`)}}else for(let i of m){let a=await Eq(n,r,i.path,i.name,e,f,c,t,d);a.exitCode===0?(g+=a.stdout,v++):_+=a.stderr}let x=((Date.now()-b)/1e3).toFixed(1);return v>0&&(g+=`\nInstalled ${v} skill(s)${y>1?` in ${x}s`:``}\n`,await Oq()),{stdout:g,stderr:_,exitCode:_?1:0}}return{stdout:``,stderr:`upskill: unrecognized source "${l}"\n\nExpected: owner/repo, clawhub:<slug>, tessl:<name>, or https://clawhub.ai/user/skill\n`,exitCode:1}})}function Fq(e){return qP(`skill`,async(t,n)=>{if(t.length===0||t.includes(`--help`)||t.includes(`-h`))return{stdout:`usage: skill <command> [options]
3123
+ `,exitCode:1};u=n[++p]}else r.startsWith(`-`)||(l=r);p++}if(d)return wq(d,t,f);if(!l)return yq();let m=Nq(l);if(m){let n=r.getRegisteredCommands?.()??[];return Tq(m,e,t,c,n)}if(l.startsWith(`tessl:`)){let n=l.slice(6);if(!n)return{stdout:``,stderr:`upskill: tessl: requires a skill name
3124
+ `,exitCode:1};let r=await Oq(n,t);if(`error`in r)return{stdout:``,stderr:`upskill: ${r.error}\n`,exitCode:1};let i=await oq(t);return Mq(r.owner,r.repo,r.skillPath,r.skillName,e,i,c,t)}let h=Lq(l);if(h){let{owner:n,repo:r}=h,d=u??h.branch,f=await oq(t),p=await jq(n,r,f,a,t,d);if(p.error)return{stdout:``,stderr:`upskill: failed to list skills: ${p.error}\n`,exitCode:1};if(p.skills.length===0)return{stdout:`No skills found in ${n}/${r}${a?`/`+a:``}\n`,stderr:``,exitCode:0};if(o){let e=`Available skills in ${n}/${r}:\n\n`;for(let t of p.skills)e+=` ${t.name.padEnd(30)} ${t.path}\n`;return e+=`\nFound ${p.skills.length} skill(s)\n`,e+=`\nTo install: upskill ${l} --skill <name>\n`,e+=`To install all: upskill ${l} --all\n`,{stdout:e,stderr:``,exitCode:0}}let m=p.skills;if(i.length>0){m=p.skills.filter(e=>i.includes(e.name));for(let e of i)if(!p.skills.find(t=>t.name===e))return{stdout:``,stderr:`upskill: skill "${e}" not found in ${n}/${r}\n`,exitCode:1}}else if(!s){let e=`Available skills in ${n}/${r}:\n\n`;for(let t of p.skills)e+=` ${t.name.padEnd(30)} ${t.path}\n`;return e+=`\nFound ${p.skills.length} skill(s)\n`,e+=`\nTo install specific skills: upskill ${l} --skill <name>\n`,e+=`To install all: upskill ${l} --all\n`,{stdout:e,stderr:``,exitCode:0}}let g=``,_=``,v=0,y=m.length,b=Date.now();if(y>1){let i=await kq(n,r,t,d);if(i.status===`not_found`)return{stdout:``,stderr:`upskill: ${d?`branch "${d}" in ${n}/${r}`:`repository ${n}/${r}`} not found\n`,exitCode:1};if(i.status===`error`)return{stdout:``,stderr:`upskill: failed to fetch ${n}/${r}: ${i.message}\n`,exitCode:1};let a=Aq(i.files);for(let t=0;t<m.length;t++){let i=m[t],o=await Fq(i.path,i.name,a,e,c),s=t+1,l=((Date.now()-b)/1e3).toFixed(1),u=(Date.now()-b)/s,d=Math.round((y-s)*u/1e3),f=s<y?` (~${d}s remaining)`:``;o.ok?(g+=`[${s}/${y}] Installed "${i.name}" from ${n}/${r} (${l}s)${f}\n`,v++):(g+=`[${s}/${y}] Failed "${i.name}": ${o.error}${f}\n`,_+=`upskill: ${o.error}\n`)}}else for(let i of m){let a=await Mq(n,r,i.path,i.name,e,f,c,t,d);a.exitCode===0?(g+=a.stdout,v++):_+=a.stderr}let x=((Date.now()-b)/1e3).toFixed(1);return v>0&&(g+=`\nInstalled ${v} skill(s)${y>1?` in ${x}s`:``}\n`,await Pq()),{stdout:g,stderr:_,exitCode:_?1:0}}return{stdout:``,stderr:`upskill: unrecognized source "${l}"\n\nExpected: owner/repo, clawhub:<slug>, tessl:<name>, or https://clawhub.ai/user/skill\n`,exitCode:1}})}function Vq(e){return qP(`skill`,async(t,n)=>{if(t.length===0||t.includes(`--help`)||t.includes(`-h`))return{stdout:`usage: skill <command> [options]
3120
3125
 
3121
3126
  Commands:
3122
3127
  list List discoverable skills and management status
@@ -3125,7 +3130,7 @@ Commands:
3125
3130
  install <name> Install a native /workspace/skills skill (apply manifest)
3126
3131
  uninstall <name> Uninstall a native /workspace/skills skill
3127
3132
 
3128
- ${iq()}${aq()}
3133
+ ${uq()}${dq()}
3129
3134
 
3130
3135
  For installing skills from registries or GitHub, use 'upskill':
3131
3136
  upskill search "query" Search ClawHub + Tessl
@@ -3137,12 +3142,12 @@ Examples:
3137
3142
  skill list
3138
3143
  skill info bluebubbles
3139
3144
  skill read bluebubbles
3140
- `,stderr:``,exitCode:0};let r=t[0],i=await y(()=>import(`./skills-Ke92WMkl.js`),__vite__mapDeps([15,16,17,1,18]));try{switch(r){case`list`:{let t=await i.discoverSkills(e);return t.length===0?{stdout:`No discoverable skills found.\n\n${iq()}${aq()}\nInstall install-managed skills with: upskill owner/repo --all\n`,stderr:``,exitCode:0}:{stdout:uq(t,`Discoverable skills`),stderr:``,exitCode:0}}case`info`:{let n=t[1];if(!n)return{stdout:``,stderr:`skill: info requires a skill name
3141
- `,exitCode:1};let r=await i.getSkillInfo(e,n);return r?{stdout:dq(r),stderr:``,exitCode:0}:{stdout:``,stderr:`skill: "${n}" not found\n`,exitCode:1}}case`read`:{let n=t[1];if(!n)return{stdout:``,stderr:`skill: read requires a skill name
3145
+ `,stderr:``,exitCode:0};let r=t[0],i=await y(()=>import(`./skills-Ke92WMkl.js`),__vite__mapDeps([15,16,17,1,18]));try{switch(r){case`list`:{let t=await i.discoverSkills(e);return t.length===0?{stdout:`No discoverable skills found.\n\n${uq()}${dq()}\nInstall install-managed skills with: upskill owner/repo --all\n`,stderr:``,exitCode:0}:{stdout:gq(t,`Discoverable skills`),stderr:``,exitCode:0}}case`info`:{let n=t[1];if(!n)return{stdout:``,stderr:`skill: info requires a skill name
3146
+ `,exitCode:1};let r=await i.getSkillInfo(e,n);return r?{stdout:_q(r),stderr:``,exitCode:0}:{stdout:``,stderr:`skill: "${n}" not found\n`,exitCode:1}}case`read`:{let n=t[1];if(!n)return{stdout:``,stderr:`skill: read requires a skill name
3142
3147
  `,exitCode:1};let r=await i.readSkillInstructions(e,n);return r===null?{stdout:``,stderr:`skill: no SKILL.md found for "${n}"\n`,exitCode:1}:{stdout:r+`
3143
3148
  `,stderr:``,exitCode:0}}case`install`:{let n=t[1];if(!n)return{stdout:``,stderr:`skill: install requires a skill name
3144
- `,exitCode:1};let r=await i.getSkillInfo(e,n);if(r&&!sq(r))return{stdout:``,stderr:fq(`skill`,r),exitCode:1};let a=await i.applySkill(e,n);return a.success?(await Mq(),await Aq(),{stdout:`Installed skill "${a.skill}" v${a.version}\n`,stderr:``,exitCode:0}):{stdout:``,stderr:`skill: ${a.error}\n`,exitCode:1}}case`uninstall`:{let n=t[1];if(!n)return{stdout:``,stderr:`skill: uninstall requires a skill name
3145
- `,exitCode:1};let r=await i.getSkillInfo(e,n);if(r&&!sq(r))return{stdout:``,stderr:`skill: "${n}" is a compatibility skill discovered from ${r.sourceRoot} (read-only). Only native /workspace/skills entries can be uninstalled.\n`,exitCode:1};let a=await i.uninstallSkill(e,n);return a.success?{stdout:`Uninstalled skill "${a.skill}"\n`,stderr:``,exitCode:0}:{stdout:``,stderr:`skill: ${a.error}\n`,exitCode:1}}default:return{stdout:``,stderr:`skill: unknown command "${r}"\n`,exitCode:1}}}catch(e){return{stdout:``,stderr:`skill: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}})}function Iq(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`).replace(/'/g,`&#39;`)}var Lq=class{constructor(e){this.options=e}async execute(e,t){let n=e[0];if(n===`--help`||n===`-h`)return this.help();if(n===`unmount`||n===`-u`){let n=e[1];if(!n)return{stdout:``,stderr:`mount unmount: path required`,exitCode:1};let r=n.startsWith(`/`)?n:`${t.replace(/\/$/,``)}/${n}`;return this.options.fs.unmount(r),{stdout:`Unmounted ${r}\n`,stderr:``,exitCode:0}}if(n===`list`||n===`-l`){let e=this.options.fs.listMounts();return e.length===0?{stdout:`No active mounts
3149
+ `,exitCode:1};let r=await i.getSkillInfo(e,n);if(r&&!pq(r))return{stdout:``,stderr:vq(`skill`,r),exitCode:1};let a=await i.applySkill(e,n);return a.success?(await Rq(),await Iq(),{stdout:`Installed skill "${a.skill}" v${a.version}\n`,stderr:``,exitCode:0}):{stdout:``,stderr:`skill: ${a.error}\n`,exitCode:1}}case`uninstall`:{let n=t[1];if(!n)return{stdout:``,stderr:`skill: uninstall requires a skill name
3150
+ `,exitCode:1};let r=await i.getSkillInfo(e,n);if(r&&!pq(r))return{stdout:``,stderr:`skill: "${n}" is a compatibility skill discovered from ${r.sourceRoot} (read-only). Only native /workspace/skills entries can be uninstalled.\n`,exitCode:1};let a=await i.uninstallSkill(e,n);return a.success?{stdout:`Uninstalled skill "${a.skill}"\n`,stderr:``,exitCode:0}:{stdout:``,stderr:`skill: ${a.error}\n`,exitCode:1}}default:return{stdout:``,stderr:`skill: unknown command "${r}"\n`,exitCode:1}}}catch(e){return{stdout:``,stderr:`skill: ${e instanceof Error?e.message:String(e)}\n`,exitCode:1}}})}function Hq(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`).replace(/'/g,`&#39;`)}var Uq=class{constructor(e){this.options=e}async execute(e,t){let n=e[0];if(n===`--help`||n===`-h`)return this.help();if(n===`unmount`||n===`-u`){let n=e[1];if(!n)return{stdout:``,stderr:`mount unmount: path required`,exitCode:1};let r=n.startsWith(`/`)?n:`${t.replace(/\/$/,``)}/${n}`;return this.options.fs.unmount(r),{stdout:`Unmounted ${r}\n`,stderr:``,exitCode:0}}if(n===`list`||n===`-l`){let e=this.options.fs.listMounts();return e.length===0?{stdout:`No active mounts
3146
3151
  `,stderr:``,exitCode:0}:{stdout:e.map(e=>e).join(`
3147
3152
  `)+`
3148
3153
  `,stderr:``,exitCode:0}}if(!n)return{stdout:``,stderr:`mount: mount point required
@@ -3150,7 +3155,7 @@ Usage: mount <target-path>
3150
3155
  `,exitCode:1};if(typeof window>`u`||!(`showDirectoryPicker`in window))return{stdout:``,stderr:`mount: File System Access API not available in this environment`,exitCode:1};let r;r=n.startsWith(`/`)?n:`${t.replace(/\/$/,``)}/${n}`,r.length>1&&(r=r.replace(/\/+$/,``));let i=o(),a;if(i){let e=await _({html:`
3151
3156
  <div class="sprinkle-action-card">
3152
3157
  <div class="sprinkle-action-card__header">Mount local directory <span class="sprinkle-badge sprinkle-badge--notice">approval</span></div>
3153
- <div class="sprinkle-action-card__body">The agent wants to mount a local directory at <code>${Iq(r)}</code>. This will give the agent read/write access to files in the directory you select.</div>
3158
+ <div class="sprinkle-action-card__body">The agent wants to mount a local directory at <code>${Hq(r)}</code>. This will give the agent read/write access to files in the directory you select.</div>
3154
3159
  <div class="sprinkle-action-card__actions">
3155
3160
  <button class="sprinkle-btn sprinkle-btn--secondary" data-action="deny">Deny</button>
3156
3161
  <button class="sprinkle-btn sprinkle-btn--primary" data-action="approve">Select directory</button>
@@ -3158,7 +3163,7 @@ Usage: mount <target-path>
3158
3163
  </div>
3159
3164
  `,onAction:async e=>{if(e===`approve`)try{return{approved:!0,handle:await window.showDirectoryPicker({mode:`readwrite`})}}catch(e){return e instanceof Error&&e.name===`AbortError`?{cancelled:!0}:{error:e instanceof Error?e.message:String(e)}}return{denied:!0}}});if(!e)return{stdout:``,stderr:`mount: tool UI not available`,exitCode:1};let t=e;if(t.denied)return{stdout:``,stderr:`mount: denied by user`,exitCode:1};if(t.cancelled)return{stdout:``,stderr:`mount: cancelled`,exitCode:1};if(t.error)return{stdout:``,stderr:`mount: ${t.error}`,exitCode:1};if(!t.handle)return{stdout:``,stderr:`mount: no directory selected`,exitCode:1};a=t.handle}else try{a=await window.showDirectoryPicker({mode:`readwrite`})}catch(e){return e instanceof Error&&e.name===`AbortError`?{stdout:``,stderr:`mount: cancelled`,exitCode:1}:{stdout:``,stderr:`mount: ${e instanceof Error?e.message:String(e)}`,exitCode:1}}try{return await this.options.fs.mount(r,a),{stdout:`Mounted '${a.name}' → ${r} (live bridge — reads and writes go to the real filesystem)\n`,stderr:``,exitCode:0}}catch(e){return{stdout:``,stderr:`mount: ${e instanceof Error?e.message:String(e)}`,exitCode:1}}}help(){return{stdout:[`Usage: mount <target-path>`,` mount unmount <path>`,` mount list`,``,`Transparently bridge a real filesystem directory into the virtual filesystem.`,`Opens a directory picker; all reads and writes under <target-path> go directly`,`to the real directory — no copying occurs. Changes are immediately visible on`,`both sides.`,``,`Arguments:`,` <target-path> Mount point in the virtual filesystem (required).`,``,`Sub-commands:`,` unmount <path> Remove a mount point`,` list Show active mount points`,``,`Examples:`,` mount /workspace/myapp # Mount selected dir at /workspace/myapp`,` mount list # Show active mounts`,` mount unmount /workspace/myapp`].join(`
3160
3165
  `)+`
3161
- `,stderr:``,exitCode:0}}};async function Rq(e,t,n){return await n.fs.exists(e)?zq(await n.fs.readFile(e),[`node`,e,...t],n):{stdout:``,stderr:`jsh: cannot find script '${e}'\n`,exitCode:127}}async function zq(e,t,n){let r=[],i=[],a=e=>{r.push(typeof e==`string`?e:String(e))},o=e=>{i.push(typeof e==`string`?e:String(e))},s={log:(...e)=>a(`${e.map(GW).join(` `)}\n`),info:(...e)=>a(`${e.map(GW).join(` `)}\n`),warn:(...e)=>o(`${e.map(GW).join(` `)}\n`),error:(...e)=>o(`${e.map(GW).join(` `)}\n`)},c={argv:t,env:Object.fromEntries(n.env.entries()),cwd:()=>n.cwd,exit:e=>{throw new NW(Number.isFinite(e)?Number(e):0)},stdout:{write:a},stderr:{write:o}},l={readFile:async e=>{let t=n.fs.resolvePath(n.cwd,e);return n.fs.readFile(t)},readFileBinary:async e=>{let t=n.fs.resolvePath(n.cwd,e);return n.fs.readFileBuffer(t)},writeFile:async(e,t)=>{let r=n.fs.resolvePath(n.cwd,e);await n.fs.writeFile(r,t)},writeFileBinary:async(e,t)=>{let r=n.fs.resolvePath(n.cwd,e),i=new Uint8Array(t.byteLength);i.set(t),await n.fs.writeFile(r,i)},readDir:async e=>{let t=n.fs.resolvePath(n.cwd,e);return n.fs.readdir(t)},exists:async e=>{let t=n.fs.resolvePath(n.cwd,e);return n.fs.exists(t)},stat:async e=>{let t=n.fs.resolvePath(n.cwd,e),r=await n.fs.stat(t);return{isDirectory:r.isDirectory,isFile:r.isFile,size:r.size}},mkdir:async e=>{let t=n.fs.resolvePath(n.cwd,e);await n.fs.mkdir(t,{recursive:!0})},rm:async e=>{let t=n.fs.resolvePath(n.cwd,e);await n.fs.rm(t,{recursive:!0})},fetchToFile:async(e,t)=>{if(typeof fetch>`u`)throw Error(`fetch is not available in this runtime`);let r=await fetch(e);if(!r.ok)throw Error(`fetch ${r.status} ${r.statusText}`);let i=new Uint8Array(await r.arrayBuffer()),a=n.fs.resolvePath(n.cwd,t);return await n.fs.writeFile(a,i),i.byteLength}},u=async e=>{if(!n.exec)throw Error(`exec is not available in this runtime`);let t=await n.exec(e,{cwd:n.cwd});return{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode}},d=e=>{throw Error(`require('${e}') is not supported in node shim`)},f={exports:{},filename:t[1]||`<script>`};try{if(typeof chrome<`u`&&chrome?.runtime?.id){let r=`
3166
+ `,stderr:``,exitCode:0}}};async function Wq(e,t,n){return await n.fs.exists(e)?Gq(await n.fs.readFile(e),[`node`,e,...t],n):{stdout:``,stderr:`jsh: cannot find script '${e}'\n`,exitCode:127}}async function Gq(e,t,n){let r=[],i=[],a=e=>{r.push(typeof e==`string`?e:String(e))},o=e=>{i.push(typeof e==`string`?e:String(e))},s={log:(...e)=>a(`${e.map(GW).join(` `)}\n`),info:(...e)=>a(`${e.map(GW).join(` `)}\n`),warn:(...e)=>o(`${e.map(GW).join(` `)}\n`),error:(...e)=>o(`${e.map(GW).join(` `)}\n`)},c={argv:t,env:Object.fromEntries(n.env.entries()),cwd:()=>n.cwd,exit:e=>{throw new NW(Number.isFinite(e)?Number(e):0)},stdout:{write:a},stderr:{write:o}},l={readFile:async e=>{let t=n.fs.resolvePath(n.cwd,e);return n.fs.readFile(t)},readFileBinary:async e=>{let t=n.fs.resolvePath(n.cwd,e);return n.fs.readFileBuffer(t)},writeFile:async(e,t)=>{let r=n.fs.resolvePath(n.cwd,e);await n.fs.writeFile(r,t)},writeFileBinary:async(e,t)=>{let r=n.fs.resolvePath(n.cwd,e),i=new Uint8Array(t.byteLength);i.set(t),await n.fs.writeFile(r,i)},readDir:async e=>{let t=n.fs.resolvePath(n.cwd,e);return n.fs.readdir(t)},exists:async e=>{let t=n.fs.resolvePath(n.cwd,e);return n.fs.exists(t)},stat:async e=>{let t=n.fs.resolvePath(n.cwd,e),r=await n.fs.stat(t);return{isDirectory:r.isDirectory,isFile:r.isFile,size:r.size}},mkdir:async e=>{let t=n.fs.resolvePath(n.cwd,e);await n.fs.mkdir(t,{recursive:!0})},rm:async e=>{let t=n.fs.resolvePath(n.cwd,e);await n.fs.rm(t,{recursive:!0})},fetchToFile:async(e,t)=>{if(typeof fetch>`u`)throw Error(`fetch is not available in this runtime`);let r=await fetch(e);if(!r.ok)throw Error(`fetch ${r.status} ${r.statusText}`);let i=new Uint8Array(await r.arrayBuffer()),a=n.fs.resolvePath(n.cwd,t);return await n.fs.writeFile(a,i),i.byteLength}},u=async e=>{if(!n.exec)throw Error(`exec is not available in this runtime`);let t=await n.exec(e,{cwd:n.cwd});return{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode}},d=e=>{throw Error(`require('${e}') is not supported in node shim`)},f={exports:{},filename:t[1]||`<script>`};try{if(typeof chrome<`u`&&chrome?.runtime?.id){let r=`
3162
3167
  const __stdout = [];
3163
3168
  const __stderr = [];
3164
3169
  const __origConsole = { log: console.log, error: console.error, warn: console.warn, info: console.info };
@@ -3201,8 +3206,8 @@ Usage: mount <target-path>
3201
3206
  console.info = __origConsole.info;
3202
3207
  return { stdout: __stdout.join(''), stderr: __stderr.join('') };
3203
3208
  `,i=document.querySelector(`iframe[data-js-tool]`);i||(i=document.createElement(`iframe`),i.style.display=`none`,i.dataset.jsTool=`true`,i.src=chrome.runtime.getURL(`sandbox.html`),document.body.appendChild(i),await new Promise(e=>{i.addEventListener(`load`,()=>e(),{once:!0})}));let a=`jsh-${Date.now()}-${Math.random().toString(36).slice(2)}`,o=e=>{let t=e.data;!t||t.type!==`vfs`||(async()=>{try{let e,r=t.args?.[0]?n.fs.resolvePath(n.cwd,t.args[0]):t.args?.[0];switch(t.op){case`readFile`:e=await n.fs.readFile(r);break;case`readFileBinary`:e=await n.fs.readFileBuffer(r);break;case`writeFile`:await n.fs.writeFile(r,t.args[1]),e=!0;break;case`writeFileBinary`:await n.fs.writeFile(r,t.binaryData??new Uint8Array),e=!0;break;case`readDir`:e=await n.fs.readdir(r);break;case`exists`:e=await n.fs.exists(r);break;case`stat`:{let t=await n.fs.stat(r);e={isDirectory:t.isDirectory,isFile:t.isFile,size:t.size};break}case`mkdir`:await n.fs.mkdir(r,{recursive:!0}),e=!0;break;case`rm`:await n.fs.rm(r,{recursive:!0}),e=!0;break}i.contentWindow.postMessage({type:`vfs_response`,id:t.id,result:e},`*`)}catch(e){let n=e instanceof Error?e.message:String(e);i.contentWindow.postMessage({type:`vfs_response`,id:t.id,error:n},`*`)}})()};window.addEventListener(`message`,o);let s=e=>{let t=e.data;!t||t.type!==`shell_exec`||(async()=>{try{let e=await u(t.command);i.contentWindow.postMessage({type:`shell_exec_response`,id:t.id,result:e},`*`)}catch(e){let n=e instanceof Error?e.message:String(e);i.contentWindow.postMessage({type:`shell_exec_response`,id:t.id,error:n},`*`)}})()};window.addEventListener(`message`,s);let l=e=>{let t=e.data;!t||t.type!==`fetch_proxy`||(async()=>{try{let e={method:t.init?.method??`GET`,cache:`no-store`};t.init?.headers&&(e.headers=t.init.headers),t.init?.body&&![`GET`,`HEAD`].includes(e.method)&&(e.body=t.init.body);let n=await fetch(t.url,e),r=await n.arrayBuffer(),a={};n.headers.forEach((e,t)=>{a[t]=e}),i.contentWindow.postMessage({type:`fetch_proxy_response`,id:t.id,status:n.status,statusText:n.statusText,headers:a,body:new Uint8Array(r)},`*`)}catch(e){let n=e instanceof Error?e.message:String(e);i.contentWindow.postMessage({type:`fetch_proxy_response`,id:t.id,error:n},`*`)}})()};window.addEventListener(`message`,l);let d=await new Promise((e,t)=>{let n,o=t=>{if(t.data?.type===`exec_result`&&t.data.id===a)if(window.removeEventListener(`message`,o),clearTimeout(n),t.data.error)e({stdout:``,stderr:t.data.error+`
3204
- `});else try{let n=JSON.parse(t.data.result);e({stdout:n.stdout||``,stderr:n.stderr||``})}catch{e({stdout:t.data.result||``,stderr:``})}};n=setTimeout(()=>{window.removeEventListener(`message`,o),t(Error(`jsh eval timed out (30s)`))},3e4),window.addEventListener(`message`,o),i.contentWindow.postMessage({type:`exec`,id:a,code:r},`*`)});return window.removeEventListener(`message`,o),window.removeEventListener(`message`,s),window.removeEventListener(`message`,l),{stdout:d.stdout,stderr:d.stderr,exitCode:d.stderr?1:0}}let a=Object.getPrototypeOf(async function(){}).constructor;return await new a(`fs`,`process`,`console`,`require`,`module`,`exports`,`__state`,`exec`,`"use strict";\nconst globalThis = __state;\nconst global = __state;\n${e}`)(l,c,s,d,f,f.exports,MW,u),{stdout:r.join(``),stderr:i.join(``),exitCode:0}}catch(e){if(e instanceof NW)return{stdout:r.join(``),stderr:i.join(``),exitCode:e.code};let t=e instanceof Error?e.stack??e.message:String(e);return{stdout:r.join(``),stderr:`${i.join(``)}${t}\n`,exitCode:1}}}function Bq(e){let t=[],n=``,r=0;for(;r<e.length;){let i=e[r];if(i===`"`){for(r++;r<e.length&&e[r]!==`"`;)n+=e[r],r++;r++}else if(i===`'`){for(r++;r<e.length&&e[r]!==`'`;)n+=e[r],r++;r++}else i===`\\`&&r+1<e.length&&e[r+1]===` `?(n+=` `,r+=2):/\s/.test(i)?(n.length>0&&(t.push(n),n=``),r++):(n+=i,r++)}return n.length>0&&t.push(n),t}var Vq=null,Hq=!1;function Uq(){return typeof chrome<`u`&&chrome?.runtime?.id?`extension`:typeof document<`u`&&document.documentElement?.dataset?.electronOverlay?`electron`:`cli`}async function Wq(){if(!Hq&&!(typeof localStorage<`u`&&localStorage.getItem(`telemetry-disabled`)===`true`))try{typeof window<`u`&&(window.SAMPLE_PAGEVIEWS_AT_RATE=`high`),Vq=(await y(()=>import(`./src-CpO2JX79.js`),[])).sampleRUM,Hq=!0,Vq&&Vq(`navigate`,{source:typeof document<`u`?document.referrer:``,target:Uq()})}catch{}}function Gq(e,t){Vq?.(`formsubmit`,{source:e,target:t})}function Kq(e){Vq?.(`fill`,{source:e})}function qq(e){Vq?.(`viewblock`,{source:e})}function Jq(e){let t=e.length>1&&e.endsWith(`/`)?e.slice(0,-1):e,n=t.lastIndexOf(`/`);return n>=0?t.slice(n+1):t}function Yq(e){if(!e)return!0;let t=e.toLowerCase();return t.startsWith(`text/`)||t.includes(`json`)||t.includes(`xml`)||t.includes(`javascript`)||t.includes(`ecmascript`)||t.includes(`html`)||t.includes(`css`)||t.includes(`svg`)}async function Xq(e,t){if(Yq(e.headers.get(`content-type`)??``))return e.text();let n=await e.arrayBuffer(),r=new Uint8Array(n),i=new TextDecoder(`iso-8859-1`).decode(n);return cV(i,r),t&&lV(t,r),i}function Zq(e){if(e){if(e instanceof Headers){let t={};return e.forEach((e,n)=>{t[n]=e}),t}return e}}function Qq(e,t){if(e){if((t?.[`Content-Type`]??t?.[`content-type`]??``).includes(`multipart/form-data`)){let t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return t}return e}}function $q(e){if(!e)return{};let t={};for(let[n,r]of Object.entries(e)){let e=n.toLowerCase();e===`cookie`?t[`X-Proxy-Cookie`]=r:e===`origin`?t[`X-Proxy-Origin`]=r:e===`referer`?t[`X-Proxy-Referer`]=r:e.startsWith(`proxy-`)?t[`X-Proxy-${n}`]=r:t[n]=r}return t}function eJ(e){let t={};for(let[n,r]of Object.entries(e))n.toLowerCase()===`x-proxy-set-cookie`?t[`set-cookie`]=r:t[n]=r;return t}function tJ(){return typeof chrome<`u`&&chrome?.runtime?.id?async(e,t)=>{let n=Zq(t?.headers),r=await fetch(e,{method:t?.method??`GET`,headers:n,body:Qq(t?.body,n)}),i=await Xq(r,e),a={};return r.headers.forEach((e,t)=>{a[t]=e}),{status:r.status,statusText:r.statusText,headers:a,body:i,url:e}}:async(e,t)=>{let n=t?.method??`GET`,r={...$q(Zq(t?.headers)),"X-Target-URL":e},i={method:n,headers:r,cache:`no-store`};t?.body&&![`GET`,`HEAD`].includes(n)&&(i.body=Qq(t.body,r));let a=await fetch(`/api/fetch-proxy`,i);if(a.status===502||a.status===400){let e=await a.text(),t=`Proxy error ${a.status}`;try{t=JSON.parse(e).error??t}catch{}throw Error(t)}let o=await Xq(a,e),s={};a.headers.forEach((e,t)=>{s[t]=e});let c=eJ(s);return{status:a.status,statusText:a.statusText,headers:c,body:o,url:e}}}var nJ=class{bash;vfsAdapter;gitCommands;mountCommands;terminal=null;fitAddon=null;terminalHost=null;previewHost=null;previewUrls=[];previewStateListener=null;hasPreview=!1;resizeObserver=null;themeObserver=null;currentLine=``;cursorPos=0;history=[];historyIndex=-1;isExecuting=!1;continuationBuffer=``;lastEnv;cwd;builtinCommandNames;constructor(e){this.options=e,this.vfsAdapter=new fV(e.fs);let t=e.cwd??`/`,n={HOME:`/`,PATH:`/usr/bin`,USER:`user`,SHELL:`/bin/bash`,PWD:t,...e.env};this.gitCommands=new JH({fs:e.fs,authorName:n.GIT_AUTHOR_NAME??`User`,authorEmail:n.GIT_AUTHOR_EMAIL??`user@example.com`}),this.mountCommands=new Lq({fs:e.fs});let r=this.createGitCustomCommand(),i=BK({onMediaPreview:async e=>this.renderMediaPreview(e),getJshCommands:()=>this.getJshCommandNames(),fs:e.fs,browserAPI:e.browserAPI}),a=this.createMountCustomCommand(),o=tJ(),s=[r,a,Fq(e.fs),Pq(e.fs,o),...i];this.bash=new tV({fs:this.vfsAdapter,cwd:t,env:n,fetch:o,customCommands:s});let c=s.map(e=>e.name);this.builtinCommandNames=new Set([...BP(),...VP(),...c]),this.vfsAdapter.setRegisteredCommandsFn(()=>[...this.builtinCommandNames]),this.lastEnv={...n},this.cwd=t}createGitCustomCommand(){let e=this.gitCommands;return qP(`git`,async(t,n)=>{let r=n.cwd,i=await e.execute(t,r);return{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode}})}createMountCustomCommand(){let e=this.mountCommands;return qP(`mount`,async(t,n)=>{let r=n.cwd,i=await e.execute(t,r);return{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode}})}getBash(){return this.bash}getCwd(){return this.cwd}getEnv(){return{...this.lastEnv}}async getFilteredJshCommands(){let e=await oK(this.options.jshDiscoveryFs??this.options.fs),t=new Map;for(let[n,r]of e)this.builtinCommandNames.has(n)||t.set(n,r);return t}async getJshCommandNames(){return[...(await this.getFilteredJshCommands()).keys()]}async tryJshFallback(e){let t=e.trim(),n=t.indexOf(` `),r=n>=0?t.slice(0,n):t,i=n>=0?t.slice(n+1).trim():``,a=(await this.getFilteredJshCommands()).get(r);if(!a)return null;let o=i?Bq(i):[],s=this.options.jshDiscoveryFs??this.options.fs,c;try{let e=await s.readFile(a,{encoding:`utf-8`});c=typeof e==`string`?e:new TextDecoder().decode(e)}catch{return{stdout:``,stderr:`jsh: cannot read script '${a}'\n`,exitCode:127,env:this.lastEnv}}let l=[`node`,a,...o],u=await zq(c,l,{fs:this.vfsAdapter,cwd:this.cwd,env:new Map(Object.entries(this.lastEnv)),stdin:``,exec:(e,t)=>this.bash.exec(e,{env:this.lastEnv,cwd:t?.cwd??this.cwd})});return{stdout:u.stdout,stderr:u.stderr,exitCode:u.exitCode,env:this.lastEnv}}async runCommand(e){Kq(e.trim().split(/\s+/)[0]||`unknown`);let t=await this.bash.exec(e,{env:this.lastEnv,cwd:this.cwd});if(t.env&&(this.lastEnv={...t.env}),t.env?.PWD&&(this.cwd=t.env.PWD),t.exitCode===127){let t=await this.tryJshFallback(e);if(t)return t}return t}async mount(e){let t=e??this.options.container;if(!t)throw Error(`No container element provided`);let{Terminal:n}=await y(async()=>{let{Terminal:e}=await import(`./xterm-BdneTMM8.js`);return{Terminal:e}},[]),{FitAddon:r}=await y(async()=>{let{FitAddon:e}=await import(`./addon-fit-Dq6sROpn.js`);return{FitAddon:e}},[]);await y(()=>Promise.resolve({}),__vite__mapDeps([19]));let i=!document.documentElement.classList.contains(`theme-light`),a={background:`#141414`,foreground:`#cfcfcf`,cursor:`#3562ff`,cursorAccent:`#141414`,selectionBackground:`#3562ff40`,selectionForeground:`#ffffff`,black:`#1a1a1a`,red:`#e34850`,green:`#2d9d78`,yellow:`#e68619`,blue:`#3562ff`,magenta:`#a962e8`,cyan:`#2db9be`,white:`#cfcfcf`,brightBlack:`#5a5a5a`,brightRed:`#e34850`,brightGreen:`#2d9d78`,brightYellow:`#e68619`,brightBlue:`#4a75ff`,brightMagenta:`#a962e8`,brightCyan:`#2db9be`,brightWhite:`#ffffff`},o={background:`#f0f0f0`,foreground:`#1a1a1a`,cursor:`#2b54db`,cursorAccent:`#f0f0f0`,selectionBackground:`#2b54db30`,selectionForeground:`#000000`,black:`#1a1a1a`,red:`#d73220`,green:`#268e6c`,yellow:`#d17a00`,blue:`#2b54db`,magenta:`#8839ef`,cyan:`#1a9088`,white:`#e8e8e8`,brightBlack:`#6e6e6e`,brightRed:`#d73220`,brightGreen:`#268e6c`,brightYellow:`#d17a00`,brightBlue:`#1e44c4`,brightMagenta:`#8839ef`,brightCyan:`#1a9088`,brightWhite:`#ffffff`};this.terminal=new n({cursorBlink:!0,fontSize:11,fontFamily:`'Source Code Pro', 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace`,theme:i?a:o,convertEol:!0}),this.themeObserver?.disconnect(),this.themeObserver=new MutationObserver(()=>{if(!this.terminal)return;let e=document.documentElement.classList.contains(`theme-light`);this.terminal.options.theme=e?o:a}),this.themeObserver.observe(document.documentElement,{attributes:!0,attributeFilter:[`class`]}),this.fitAddon=new r,this.terminal.loadAddon(this.fitAddon),t.replaceChildren(),this.terminalHost=document.createElement(`div`),this.terminalHost.className=`terminal-panel__terminal-host`,t.appendChild(this.terminalHost),this.previewHost=document.createElement(`div`),this.previewHost.className=`terminal-panel__preview`,t.appendChild(this.previewHost),this.terminal.open(this.terminalHost),this.fitAddon.fit(),this.resizeObserver?.disconnect(),this.resizeObserver=new ResizeObserver(()=>this.refit()),this.resizeObserver.observe(this.terminalHost),this.terminal.writeln(`\x1B[1mslicc\x1B[0m \x1B[90mshell (powered by just-bash)\x1B[0m`),this.terminal.writeln(`\x1B[90mType "help" for available commands.\x1B[0m
3205
- `),this.showPrompt(),this.setupInputHandler()}async executeCommand(e){let t=await this.runCommand(e);return{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode}}async executeScriptFile(e,t=[]){return Rq(e,t,{fs:this.vfsAdapter,cwd:this.cwd,env:new Map(Object.entries(this.lastEnv)),stdin:``,exec:(e,t)=>this.bash.exec(e,{env:this.lastEnv,cwd:t?.cwd??this.cwd})})}refit(){this.fitAddon?.fit()}setPreviewStateListener(e){this.previewStateListener=e,this.previewStateListener?.(this.hasPreview)}async executeCommandInTerminal(e){let t=e.trim();if(!t)return{stdout:``,stderr:``,exitCode:0};if(!this.terminal)return this.executeCommand(t);if(this.isExecuting||this.currentLine.length>0||this.continuationBuffer.length>0)return{stdout:``,stderr:`terminal is busy; finish current input first
3209
+ `});else try{let n=JSON.parse(t.data.result);e({stdout:n.stdout||``,stderr:n.stderr||``})}catch{e({stdout:t.data.result||``,stderr:``})}};n=setTimeout(()=>{window.removeEventListener(`message`,o),t(Error(`jsh eval timed out (30s)`))},3e4),window.addEventListener(`message`,o),i.contentWindow.postMessage({type:`exec`,id:a,code:r},`*`)});return window.removeEventListener(`message`,o),window.removeEventListener(`message`,s),window.removeEventListener(`message`,l),{stdout:d.stdout,stderr:d.stderr,exitCode:d.stderr?1:0}}let a=Object.getPrototypeOf(async function(){}).constructor;return await new a(`fs`,`process`,`console`,`require`,`module`,`exports`,`__state`,`exec`,`"use strict";\nconst globalThis = __state;\nconst global = __state;\n${e}`)(l,c,s,d,f,f.exports,MW,u),{stdout:r.join(``),stderr:i.join(``),exitCode:0}}catch(e){if(e instanceof NW)return{stdout:r.join(``),stderr:i.join(``),exitCode:e.code};let t=e instanceof Error?e.stack??e.message:String(e);return{stdout:r.join(``),stderr:`${i.join(``)}${t}\n`,exitCode:1}}}function Kq(e){let t=[],n=``,r=0;for(;r<e.length;){let i=e[r];if(i===`"`){for(r++;r<e.length&&e[r]!==`"`;)n+=e[r],r++;r++}else if(i===`'`){for(r++;r<e.length&&e[r]!==`'`;)n+=e[r],r++;r++}else i===`\\`&&r+1<e.length&&e[r+1]===` `?(n+=` `,r+=2):/\s/.test(i)?(n.length>0&&(t.push(n),n=``),r++):(n+=i,r++)}return n.length>0&&t.push(n),t}var qq=null,Jq=!1;function Yq(){return typeof chrome<`u`&&chrome?.runtime?.id?`extension`:typeof document<`u`&&document.documentElement?.dataset?.electronOverlay?`electron`:`cli`}async function Xq(){if(!Jq&&!(typeof localStorage<`u`&&localStorage.getItem(`telemetry-disabled`)===`true`))try{typeof window<`u`&&(window.SAMPLE_PAGEVIEWS_AT_RATE=`high`),qq=(await y(()=>import(`./src-CpO2JX79.js`),[])).sampleRUM,Jq=!0,qq&&qq(`navigate`,{source:typeof document<`u`?document.referrer:``,target:Yq()})}catch{}}function Zq(e,t){qq?.(`formsubmit`,{source:e,target:t})}function Qq(e){qq?.(`fill`,{source:e})}function $q(e){qq?.(`viewblock`,{source:e})}function eJ(e){let t=e.length>1&&e.endsWith(`/`)?e.slice(0,-1):e,n=t.lastIndexOf(`/`);return n>=0?t.slice(n+1):t}function tJ(e){if(!e)return!0;let t=e.toLowerCase();return t.startsWith(`text/`)||t.includes(`json`)||t.includes(`xml`)||t.includes(`javascript`)||t.includes(`ecmascript`)||t.includes(`html`)||t.includes(`css`)||t.includes(`svg`)}async function nJ(e,t){if(tJ(e.headers.get(`content-type`)??``))return e.text();let n=await e.arrayBuffer(),r=new Uint8Array(n),i=new TextDecoder(`iso-8859-1`).decode(n);return cV(i,r),t&&lV(t,r),i}function rJ(e){if(e){if(e instanceof Headers){let t={};return e.forEach((e,n)=>{t[n]=e}),t}return e}}function iJ(e,t){if(e){if((t?.[`Content-Type`]??t?.[`content-type`]??``).includes(`multipart/form-data`)){let t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return t}return e}}function aJ(e){if(!e)return{};let t={};for(let[n,r]of Object.entries(e)){let e=n.toLowerCase();e===`cookie`?t[`X-Proxy-Cookie`]=r:e===`origin`?t[`X-Proxy-Origin`]=r:e===`referer`?t[`X-Proxy-Referer`]=r:e.startsWith(`proxy-`)?t[`X-Proxy-${n}`]=r:t[n]=r}return t}function oJ(e){let t={};for(let[n,r]of Object.entries(e))n.toLowerCase()===`x-proxy-set-cookie`?t[`set-cookie`]=r:t[n]=r;return t}function sJ(){return typeof chrome<`u`&&chrome?.runtime?.id?async(e,t)=>{let n=rJ(t?.headers),r=await fetch(e,{method:t?.method??`GET`,headers:n,body:iJ(t?.body,n)}),i=await nJ(r,e),a={};return r.headers.forEach((e,t)=>{a[t]=e}),{status:r.status,statusText:r.statusText,headers:a,body:i,url:e}}:async(e,t)=>{let n=t?.method??`GET`,r={...aJ(rJ(t?.headers)),"X-Target-URL":e},i={method:n,headers:r,cache:`no-store`};t?.body&&![`GET`,`HEAD`].includes(n)&&(i.body=iJ(t.body,r));let a=await fetch(`/api/fetch-proxy`,i);if(a.status===502||a.status===400){let e=await a.text(),t=`Proxy error ${a.status}`;try{t=JSON.parse(e).error??t}catch{}throw Error(t)}let o=await nJ(a,e),s={};a.headers.forEach((e,t)=>{s[t]=e});let c=oJ(s);return{status:a.status,statusText:a.statusText,headers:c,body:o,url:e}}}var cJ=class{bash;vfsAdapter;gitCommands;mountCommands;terminal=null;fitAddon=null;terminalHost=null;previewHost=null;previewUrls=[];previewStateListener=null;hasPreview=!1;resizeObserver=null;themeObserver=null;currentLine=``;cursorPos=0;history=[];historyIndex=-1;isExecuting=!1;continuationBuffer=``;lastEnv;cwd;builtinCommandNames;constructor(e){this.options=e,this.vfsAdapter=new fV(e.fs);let t=e.cwd??`/`,n={HOME:`/`,PATH:`/usr/bin`,USER:`user`,SHELL:`/bin/bash`,PWD:t,...e.env};this.gitCommands=new JH({fs:e.fs,authorName:n.GIT_AUTHOR_NAME??`User`,authorEmail:n.GIT_AUTHOR_EMAIL??`user@example.com`}),this.mountCommands=new Uq({fs:e.fs});let r=this.createGitCustomCommand(),i=UK({onMediaPreview:async e=>this.renderMediaPreview(e),getJshCommands:()=>this.getJshCommandNames(),fs:e.fs,browserAPI:e.browserAPI}),a=this.createMountCustomCommand(),o=sJ(),s=[r,a,Vq(e.fs),Bq(e.fs,o),...i];this.bash=new tV({fs:this.vfsAdapter,cwd:t,env:n,fetch:o,customCommands:s});let c=s.map(e=>e.name);this.builtinCommandNames=new Set([...BP(),...VP(),...c]),this.vfsAdapter.setRegisteredCommandsFn(()=>[...this.builtinCommandNames]),this.lastEnv={...n},this.cwd=t}createGitCustomCommand(){let e=this.gitCommands;return qP(`git`,async(t,n)=>{let r=n.cwd,i=await e.execute(t,r);return{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode}})}createMountCustomCommand(){let e=this.mountCommands;return qP(`mount`,async(t,n)=>{let r=n.cwd,i=await e.execute(t,r);return{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode}})}getBash(){return this.bash}getCwd(){return this.cwd}getEnv(){return{...this.lastEnv}}async getFilteredJshCommands(){let e=await lK(this.options.jshDiscoveryFs??this.options.fs),t=new Map;for(let[n,r]of e)this.builtinCommandNames.has(n)||t.set(n,r);return t}async getJshCommandNames(){return[...(await this.getFilteredJshCommands()).keys()]}async tryJshFallback(e){let t=e.trim(),n=t.indexOf(` `),r=n>=0?t.slice(0,n):t,i=n>=0?t.slice(n+1).trim():``,a=(await this.getFilteredJshCommands()).get(r);if(!a)return null;let o=i?Kq(i):[],s=this.options.jshDiscoveryFs??this.options.fs,c;try{let e=await s.readFile(a,{encoding:`utf-8`});c=typeof e==`string`?e:new TextDecoder().decode(e)}catch{return{stdout:``,stderr:`jsh: cannot read script '${a}'\n`,exitCode:127,env:this.lastEnv}}let l=[`node`,a,...o],u=await Gq(c,l,{fs:this.vfsAdapter,cwd:this.cwd,env:new Map(Object.entries(this.lastEnv)),stdin:``,exec:(e,t)=>this.bash.exec(e,{env:this.lastEnv,cwd:t?.cwd??this.cwd})});return{stdout:u.stdout,stderr:u.stderr,exitCode:u.exitCode,env:this.lastEnv}}async runCommand(e){Qq(e.trim().split(/\s+/)[0]||`unknown`);let t=await this.bash.exec(e,{env:this.lastEnv,cwd:this.cwd});if(t.env&&(this.lastEnv={...t.env}),t.env?.PWD&&(this.cwd=t.env.PWD),t.exitCode===127){let t=await this.tryJshFallback(e);if(t)return t}return t}async mount(e){let t=e??this.options.container;if(!t)throw Error(`No container element provided`);let{Terminal:n}=await y(async()=>{let{Terminal:e}=await import(`./xterm-BdneTMM8.js`);return{Terminal:e}},[]),{FitAddon:r}=await y(async()=>{let{FitAddon:e}=await import(`./addon-fit-Dq6sROpn.js`);return{FitAddon:e}},[]);await y(()=>Promise.resolve({}),__vite__mapDeps([19]));let i=!document.documentElement.classList.contains(`theme-light`),a={background:`#141414`,foreground:`#cfcfcf`,cursor:`#3562ff`,cursorAccent:`#141414`,selectionBackground:`#3562ff40`,selectionForeground:`#ffffff`,black:`#1a1a1a`,red:`#e34850`,green:`#2d9d78`,yellow:`#e68619`,blue:`#3562ff`,magenta:`#a962e8`,cyan:`#2db9be`,white:`#cfcfcf`,brightBlack:`#5a5a5a`,brightRed:`#e34850`,brightGreen:`#2d9d78`,brightYellow:`#e68619`,brightBlue:`#4a75ff`,brightMagenta:`#a962e8`,brightCyan:`#2db9be`,brightWhite:`#ffffff`},o={background:`#f0f0f0`,foreground:`#1a1a1a`,cursor:`#2b54db`,cursorAccent:`#f0f0f0`,selectionBackground:`#2b54db30`,selectionForeground:`#000000`,black:`#1a1a1a`,red:`#d73220`,green:`#268e6c`,yellow:`#d17a00`,blue:`#2b54db`,magenta:`#8839ef`,cyan:`#1a9088`,white:`#e8e8e8`,brightBlack:`#6e6e6e`,brightRed:`#d73220`,brightGreen:`#268e6c`,brightYellow:`#d17a00`,brightBlue:`#1e44c4`,brightMagenta:`#8839ef`,brightCyan:`#1a9088`,brightWhite:`#ffffff`};this.terminal=new n({cursorBlink:!0,fontSize:11,fontFamily:`'Source Code Pro', 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace`,theme:i?a:o,convertEol:!0}),this.themeObserver?.disconnect(),this.themeObserver=new MutationObserver(()=>{if(!this.terminal)return;let e=document.documentElement.classList.contains(`theme-light`);this.terminal.options.theme=e?o:a}),this.themeObserver.observe(document.documentElement,{attributes:!0,attributeFilter:[`class`]}),this.fitAddon=new r,this.terminal.loadAddon(this.fitAddon),t.replaceChildren(),this.terminalHost=document.createElement(`div`),this.terminalHost.className=`terminal-panel__terminal-host`,t.appendChild(this.terminalHost),this.previewHost=document.createElement(`div`),this.previewHost.className=`terminal-panel__preview`,t.appendChild(this.previewHost),this.terminal.open(this.terminalHost),this.fitAddon.fit(),this.resizeObserver?.disconnect(),this.resizeObserver=new ResizeObserver(()=>this.refit()),this.resizeObserver.observe(this.terminalHost),this.terminal.writeln(`\x1B[1mslicc\x1B[0m \x1B[90mshell (powered by just-bash)\x1B[0m`),this.terminal.writeln(`\x1B[90mType "help" for available commands.\x1B[0m
3210
+ `),this.showPrompt(),this.setupInputHandler()}async executeCommand(e){let t=await this.runCommand(e);return{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode}}async executeScriptFile(e,t=[]){return Wq(e,t,{fs:this.vfsAdapter,cwd:this.cwd,env:new Map(Object.entries(this.lastEnv)),stdin:``,exec:(e,t)=>this.bash.exec(e,{env:this.lastEnv,cwd:t?.cwd??this.cwd})})}refit(){this.fitAddon?.fit()}setPreviewStateListener(e){this.previewStateListener=e,this.previewStateListener?.(this.hasPreview)}async executeCommandInTerminal(e){let t=e.trim();if(!t)return{stdout:``,stderr:``,exitCode:0};if(!this.terminal)return this.executeCommand(t);if(this.isExecuting||this.currentLine.length>0||this.continuationBuffer.length>0)return{stdout:``,stderr:`terminal is busy; finish current input first
3206
3211
  `,exitCode:1};this.history[this.history.length-1]!==t&&this.history.push(t),this.historyIndex=-1,this.terminal.write(t),this.terminal.writeln(``),this.isExecuting=!0;try{let e=await this.runCommand(t);return e.stdout&&this.writeToTerminal(e.stdout),e.stderr&&this.writeToTerminal(e.stderr,!0),{stdout:e.stdout,stderr:e.stderr,exitCode:e.exitCode}}catch(e){let t=`Error: ${e instanceof Error?e.message:String(e)}\n`;return this.writeToTerminal(t,!0),{stdout:``,stderr:t,exitCode:1}}finally{this.isExecuting=!1,this.showPrompt()}}clearTerminal(){this.terminal?.clear(),this.clearMediaPreview()}dispose(){this.themeObserver?.disconnect(),this.themeObserver=null,this.resizeObserver?.disconnect(),this.resizeObserver=null,this.clearMediaPreview(),this.terminal?.dispose(),this.terminal=null,this.fitAddon=null,this.terminalHost=null,this.previewHost=null}showPrompt(){if(!this.terminal)return;let e=this.cwd===`/`?`/`:this.cwd.split(`/`).pop()??this.cwd;this.terminal.write(`\x1b[34m${e}\x1b[0m \x1b[90m$\x1b[0m `)}setupInputHandler(){this.terminal&&this.terminal.onData(e=>{if(!this.isExecuting){if(e.startsWith(`\x1B[`)||e.startsWith(`\x1BO`)){switch(e){case`\x1B[A`:this.handleHistoryUp();return;case`\x1B[B`:this.handleHistoryDown();return;case`\x1B[C`:this.handleArrowRight();return;case`\x1B[D`:this.handleArrowLeft();return;case`\x1B[H`:case`\x1BOH`:case`\x1B[1~`:this.handleHome();return;case`\x1B[F`:case`\x1BOF`:case`\x1B[4~`:this.handleEnd();return;case`\x1B[3~`:this.handleDelete();return}return}for(let t of e)switch(t){case`\r`:this.handleEnter();break;case``:this.handleBackspace();break;case``:this.handleCtrlC();break;case` `:this.handleTab();break;default:t>=` `&&this.insertChar(t)}}})}getPromptWidth(){return(this.cwd===`/`?`/`:this.cwd.split(`/`).pop()??this.cwd).length+3}getCursorVisualLine(){let e=0;for(let[t,n]of this.currentLine.split(`
3207
3212
  `).entries()){if(e+n.length>=this.cursorPos)return t;e+=n.length+1}return 0}positionTerminalCursor(){let e=this.currentLine.split(`
3208
3213
  `),t=0,n=0,r=0;for(let i=0;i<e.length;i++){if(r+e[i].length>=this.cursorPos){t=i,n=this.cursorPos-r;break}r+=e[i].length+1}let i=e.length-1-t;i>0&&this.terminal?.write(`\x1b[${i}A`);let a=t===0?this.getPromptWidth()+n:n;this.terminal?.write(`\r`),a>0&&this.terminal?.write(`\x1b[${a}C`)}redrawInput(e){e>0&&this.terminal?.write(`\x1b[${e}A`),this.terminal?.write(`\r\x1B[J`),this.showPrompt(),this.terminal?.write(this.currentLine),this.positionTerminalCursor()}insertChar(e){let t=this.currentLine.includes(`
@@ -3216,9 +3221,9 @@ Usage: mount <target-path>
3216
3221
  `,this.cursorPos);if(e===-1&&(e=this.currentLine.length),this.cursorPos===e)return;let t=e-this.cursorPos;this.cursorPos=e,this.terminal?.write(`\x1b[${t}C`)}handleCtrlC(){this.terminal?.writeln(`^C`),this.currentLine=``,this.cursorPos=0,this.continuationBuffer=``,this.showPrompt()}handleHistoryUp(){this.history.length!==0&&this.historyIndex<this.history.length-1&&(this.historyIndex++,this.continuationBuffer=``,this.replaceCurrentLine(this.history[this.history.length-1-this.historyIndex]))}handleHistoryDown(){this.historyIndex>0?(this.historyIndex--,this.continuationBuffer=``,this.replaceCurrentLine(this.history[this.history.length-1-this.historyIndex])):this.historyIndex===0&&(this.historyIndex=-1,this.continuationBuffer=``,this.replaceCurrentLine(``))}async handleTab(){if(!this.terminal)return;let e=this.currentLine.slice(0,this.cursorPos).split(/\s+/),t=e[e.length-1]||``,n=e.length<=1||e.length===2&&e[0]===``,r=t?`'`+t.replace(/'/g,`'\\''`)+`'`:`''`,i=n?`compgen -A command -- ${r}`:`compgen -f -- ${r}`;try{let e=(await this.bash.exec(i,{env:this.lastEnv,cwd:this.cwd})).stdout.split(`
3217
3222
  `).filter(Boolean);if(e.length===0)return;if(e.length===1){let i=e[0],a=i.slice(t.length);a&&(this.currentLine=this.currentLine.slice(0,this.cursorPos)+a+this.currentLine.slice(this.cursorPos),this.cursorPos+=a.length,this.terminal.write(a));let o=` `;n||(await this.bash.exec(`compgen -d -- ${r.slice(0,-1)}${a}'`,{env:this.lastEnv,cwd:this.cwd})).stdout.trim()===i&&(o=`/`),this.currentLine=this.currentLine.slice(0,this.cursorPos)+o+this.currentLine.slice(this.cursorPos),this.cursorPos+=1,this.terminal.write(o)}else{let n=e[0];for(let t of e)for(;!t.startsWith(n);)n=n.slice(0,-1);let r=n.slice(t.length);if(r)this.currentLine=this.currentLine.slice(0,this.cursorPos)+r+this.currentLine.slice(this.cursorPos),this.cursorPos+=r.length,this.terminal.write(r);else{this.terminal.writeln(``),this.terminal.writeln(e.map(e=>e.split(`/`).pop()??e).join(` `)),this.showPrompt(),this.terminal.write(this.currentLine);let t=this.currentLine.length-this.cursorPos;t>0&&this.terminal.write(`\x1b[${t}D`)}}}catch(e){console.warn(`[Shell] Tab completion failed:`,e instanceof Error?e.message:String(e))}}replaceCurrentLine(e){let t=this.getCursorVisualLine();t>0&&this.terminal?.write(`\x1b[${t}A`),this.terminal?.write(`\r\x1B[J`),this.showPrompt(),this.currentLine=e,this.cursorPos=e.length,this.terminal?.write(e)}isIncomplete(e){if(e.endsWith(`\\`))return!0;let t=!1,n=!1,r=!1;for(let i of e){if(r){r=!1;continue}if(i===`\\`&&!t){r=!0;continue}if(i===`'`&&!n){t=!t;continue}if(i===`"`&&!t){n=!n;continue}}return t||n}async handleEnter(){let e=this.currentLine.split(`
3218
3223
  `);if(e.length>1){let t=this.getCursorVisualLine(),n=e.length-1-t;n>0&&this.terminal?.write(`\x1b[${n}B`);let r=e[e.length-1].length;this.terminal?.write(`\r`),r>0&&this.terminal?.write(`\x1b[${r}C`)}this.terminal?.writeln(``);let t=this.currentLine;this.currentLine=``,this.cursorPos=0;let n=this.continuationBuffer?this.continuationBuffer+`
3219
- `+t:t;if(this.isIncomplete(n)){this.continuationBuffer=n,this.terminal?.write(`> `);return}this.continuationBuffer=``;let r=n.trim();if(this.historyIndex=-1,!r){this.showPrompt();return}if(this.history[this.history.length-1]!==r&&this.history.push(r),r===`clear`){this.clearTerminal(),this.showPrompt();return}this.isExecuting=!0;try{let e=await this.runCommand(r);e.stdout&&this.writeToTerminal(e.stdout),e.stderr&&this.writeToTerminal(e.stderr,!0)}catch(e){let t=e instanceof Error?e.message:String(e);this.writeToTerminal(`Error: ${t}\n`,!0)}this.isExecuting=!1,this.showPrompt()}writeToTerminal(e,t=!1){this.terminal&&(t?this.terminal.write(`\x1b[31m${e}\x1b[0m`):this.terminal.write(e))}clearMediaPreview(){for(let e of this.previewUrls)URL.revokeObjectURL(e);this.previewUrls=[],this.hasPreview=!1,this.previewHost&&(this.previewHost.replaceChildren(),this.previewHost.classList.remove(`terminal-panel__preview--visible`)),this.previewStateListener?.(!1)}async renderMediaPreview(e){if(!this.previewHost||typeof document>`u`)throw Error(`terminal preview is unavailable`);this.clearMediaPreview();for(let t of e){let e=new Uint8Array(t.bytes),n=URL.createObjectURL(new Blob([e],{type:t.mimeType}));this.previewUrls.push(n);let r=document.createElement(`div`);r.className=`terminal-panel__preview-item`;let i=document.createElement(`div`);if(i.className=`terminal-panel__preview-label`,i.textContent=`${Jq(t.path)} · ${t.mimeType}`,r.appendChild(i),t.mimeType.startsWith(`video/`)){let e=document.createElement(`video`);e.className=`terminal-panel__preview-media`,e.controls=!0,e.autoplay=!0,e.loop=!0,e.muted=!0,e.playsInline=!0,e.src=n,e.addEventListener(`loadedmetadata`,()=>this.refit(),{once:!0}),r.appendChild(e)}else{let e=document.createElement(`img`);e.className=`terminal-panel__preview-media`,e.alt=Jq(t.path),e.src=n,e.addEventListener(`load`,()=>this.refit(),{once:!0}),r.appendChild(e)}this.previewHost.appendChild(r)}this.previewHost.classList.add(`terminal-panel__preview--visible`),this.hasPreview=e.length>0,this.previewStateListener?.(this.hasPreview),requestAnimationFrame(()=>this.refit())}},rJ=r(`tool:fs`);function iJ(e){return[aJ(e),oJ(e),sJ(e)]}function aJ(e){return{name:`read_file`,description:`Read the contents of a file. Returns the file content as a string with line numbers.`,inputSchema:{type:`object`,properties:{path:{type:`string`,description:`Absolute path to the file to read.`},offset:{type:`number`,description:`Line number to start reading from (1-based). Optional.`},limit:{type:`number`,description:`Maximum number of lines to read. Optional.`}},required:[`path`]},async execute(t){let n=t.path,r=t.offset??1,i=t.limit;rJ.debug(`Read`,{path:n,offset:r,limit:i});try{let t=(await e.readTextFile(n)).split(`
3224
+ `+t:t;if(this.isIncomplete(n)){this.continuationBuffer=n,this.terminal?.write(`> `);return}this.continuationBuffer=``;let r=n.trim();if(this.historyIndex=-1,!r){this.showPrompt();return}if(this.history[this.history.length-1]!==r&&this.history.push(r),r===`clear`){this.clearTerminal(),this.showPrompt();return}this.isExecuting=!0;try{let e=await this.runCommand(r);e.stdout&&this.writeToTerminal(e.stdout),e.stderr&&this.writeToTerminal(e.stderr,!0)}catch(e){let t=e instanceof Error?e.message:String(e);this.writeToTerminal(`Error: ${t}\n`,!0)}this.isExecuting=!1,this.showPrompt()}writeToTerminal(e,t=!1){this.terminal&&(t?this.terminal.write(`\x1b[31m${e}\x1b[0m`):this.terminal.write(e))}clearMediaPreview(){for(let e of this.previewUrls)URL.revokeObjectURL(e);this.previewUrls=[],this.hasPreview=!1,this.previewHost&&(this.previewHost.replaceChildren(),this.previewHost.classList.remove(`terminal-panel__preview--visible`)),this.previewStateListener?.(!1)}async renderMediaPreview(e){if(!this.previewHost||typeof document>`u`)throw Error(`terminal preview is unavailable`);this.clearMediaPreview();for(let t of e){let e=new Uint8Array(t.bytes),n=URL.createObjectURL(new Blob([e],{type:t.mimeType}));this.previewUrls.push(n);let r=document.createElement(`div`);r.className=`terminal-panel__preview-item`;let i=document.createElement(`div`);if(i.className=`terminal-panel__preview-label`,i.textContent=`${eJ(t.path)} · ${t.mimeType}`,r.appendChild(i),t.mimeType.startsWith(`video/`)){let e=document.createElement(`video`);e.className=`terminal-panel__preview-media`,e.controls=!0,e.autoplay=!0,e.loop=!0,e.muted=!0,e.playsInline=!0,e.src=n,e.addEventListener(`loadedmetadata`,()=>this.refit(),{once:!0}),r.appendChild(e)}else{let e=document.createElement(`img`);e.className=`terminal-panel__preview-media`,e.alt=eJ(t.path),e.src=n,e.addEventListener(`load`,()=>this.refit(),{once:!0}),r.appendChild(e)}this.previewHost.appendChild(r)}this.previewHost.classList.add(`terminal-panel__preview--visible`),this.hasPreview=e.length>0,this.previewStateListener?.(this.hasPreview),requestAnimationFrame(()=>this.refit())}},lJ=r(`tool:fs`);function uJ(e){return[dJ(e),fJ(e),pJ(e)]}function dJ(e){return{name:`read_file`,description:`Read the contents of a file. Returns the file content as a string with line numbers.`,inputSchema:{type:`object`,properties:{path:{type:`string`,description:`Absolute path to the file to read.`},offset:{type:`number`,description:`Line number to start reading from (1-based). Optional.`},limit:{type:`number`,description:`Maximum number of lines to read. Optional.`}},required:[`path`]},async execute(t){let n=t.path,r=t.offset??1,i=t.limit;lJ.debug(`Read`,{path:n,offset:r,limit:i});try{let t=(await e.readTextFile(n)).split(`
3220
3225
  `),a=Math.max(0,r-1),o=i===void 0?t.length:a+i;return{content:t.slice(a,o).map((e,t)=>`${String(a+t+1).padStart(6)} | ${e}`).join(`
3221
- `)}}catch(e){let t=e instanceof Error?e.message:String(e);return rJ.error(`Read failed`,{path:n,error:t}),{content:t,isError:!0}}}}}function oJ(e){return{name:`write_file`,description:`Write content to a file. Creates the file if it does not exist, or overwrites it if it does. Parent directories are created automatically.`,inputSchema:{type:`object`,properties:{path:{type:`string`,description:`Absolute path to the file to write.`},content:{type:`string`,description:`The content to write to the file.`}},required:[`path`,`content`]},async execute(t){let n=t.path,r=t.content;rJ.debug(`Write`,{path:n,contentLength:r.length});try{return await e.writeFile(n,r),{content:`File written: ${n}`}}catch(e){let t=e instanceof Error?e.message:String(e);return rJ.error(`Write failed`,{path:n,error:t}),{content:t,isError:!0}}}}}function sJ(e){return{name:`edit_file`,description:`Edit a file by replacing an exact string match. The old_string must appear exactly once in the file. Use this instead of write_file when making targeted changes to existing files.`,inputSchema:{type:`object`,properties:{path:{type:`string`,description:`Absolute path to the file to edit.`},old_string:{type:`string`,description:`The exact string to find and replace. Must be unique in the file.`},new_string:{type:`string`,description:`The replacement string.`}},required:[`path`,`old_string`,`new_string`]},async execute(t){let n=t.path,r=t.old_string,i=t.new_string;rJ.debug(`Edit`,{path:n,oldLength:r.length,newLength:i.length});try{let t=await e.readTextFile(n),a=t.split(r).length-1;if(a===0)return{content:`old_string not found in ${n}`,isError:!0};if(a>1)return{content:`old_string found ${a} times in ${n}. It must be unique. Provide more context.`,isError:!0};let o=t.replace(r,i);return await e.writeFile(n,o),{content:`File edited: ${n}`}}catch(e){let t=e instanceof Error?e.message:String(e);return rJ.error(`Edit failed`,{path:n,error:t}),{content:t,isError:!0}}}}}var cJ=r(`tool:bash`),lJ=/^(?:[A-Za-z_][A-Za-z0-9_]*=[^\s]+\s+)*(?:command\s+)?(?:grep|egrep|fgrep|rg)\b/;function uJ(e){let t=``,n=null,r=!1;for(let i=0;i<e.length;i++){let a=e[i];if(r){t+=a,r=!1;continue}if(a===`\\`){t+=a,r=!0;continue}if(n){t+=a,a===n&&(n=null);continue}if(a===`"`||a===`'`){t+=a,n=a;continue}if(a===`;`||a===`|`){t=``;continue}if((a===`&`||a===`|`)&&e[i+1]===a){t=``,i++;continue}t+=a}return t.trim()}function dJ(e,t,n){return t!==1||n.trim()?!1:lJ.test(uJ(e))}function fJ(e){return{name:`bash`,description:`Execute a bash command in a full Unix-like shell (just-bash with 78+ commands). Shell features: pipes (|), redirects (>, >>, <, <<), chaining (&& ; ||), subshells, control flow (if/else, for, while, case), command substitution ($(...)), process substitution, shell functions, arrays, variable expansion, globs, brace expansion, here-docs. Text processing: grep, egrep, fgrep, rg (ripgrep), sed, awk, cut, tr, sort, uniq, wc, head, tail, fold, nl, rev, column, paste, join, comm, expand, strings, od. Data formats: jq (JSON), base64, md5sum, sha256sum. File operations: find, diff, tar, gzip, gunzip, cp, mv, rm, mkdir, touch, chmod, du, file, dirname, basename, tee, xargs, zip, unzip. Custom commands: git, open (serve VFS files in browser tab, --view for agent vision, --download for file save), sqlite3, node (-e shim with fs bridge), python3/python. Networking: curl (full HTTP client — GET, POST, PUT, DELETE with headers, data, auth). Utilities: seq, date, printf, expr, env, export, test/[, true, false, read.`,inputSchema:{type:`object`,properties:{command:{type:`string`,description:`The bash command to execute.`}},required:[`command`]},async execute(t){let n=t.command;cJ.debug(`Execute`,{command:n});try{let t=await e.executeCommand(n);cJ.debug(`Result`,{exitCode:t.exitCode,stdoutLength:t.stdout.length,stderrLength:t.stderr.length});let r=``;return t.stdout&&(r+=t.stdout),t.stderr&&(r+=t.stderr),r||=`(exit code: ${t.exitCode})`,{content:r,isError:t.exitCode!==0&&!dJ(n,t.exitCode,t.stderr)}}catch(e){let t=e instanceof Error?e.message:String(e);return cJ.error(`Error`,{command:n,error:t}),{content:`Shell error: ${t}`,isError:!0}}}}}r(`tool:search`);var pJ=r(`tool:javascript`),mJ=`<!DOCTYPE html><html><head><script>
3226
+ `)}}catch(e){let t=e instanceof Error?e.message:String(e);return lJ.error(`Read failed`,{path:n,error:t}),{content:t,isError:!0}}}}}function fJ(e){return{name:`write_file`,description:`Write content to a file. Creates the file if it does not exist, or overwrites it if it does. Parent directories are created automatically.`,inputSchema:{type:`object`,properties:{path:{type:`string`,description:`Absolute path to the file to write.`},content:{type:`string`,description:`The content to write to the file.`}},required:[`path`,`content`]},async execute(t){let n=t.path,r=t.content;lJ.debug(`Write`,{path:n,contentLength:r.length});try{return await e.writeFile(n,r),{content:`File written: ${n}`}}catch(e){let t=e instanceof Error?e.message:String(e);return lJ.error(`Write failed`,{path:n,error:t}),{content:t,isError:!0}}}}}function pJ(e){return{name:`edit_file`,description:`Edit a file by replacing an exact string match. The old_string must appear exactly once in the file. Use this instead of write_file when making targeted changes to existing files.`,inputSchema:{type:`object`,properties:{path:{type:`string`,description:`Absolute path to the file to edit.`},old_string:{type:`string`,description:`The exact string to find and replace. Must be unique in the file.`},new_string:{type:`string`,description:`The replacement string.`}},required:[`path`,`old_string`,`new_string`]},async execute(t){let n=t.path,r=t.old_string,i=t.new_string;lJ.debug(`Edit`,{path:n,oldLength:r.length,newLength:i.length});try{let t=await e.readTextFile(n),a=t.split(r).length-1;if(a===0)return{content:`old_string not found in ${n}`,isError:!0};if(a>1)return{content:`old_string found ${a} times in ${n}. It must be unique. Provide more context.`,isError:!0};let o=t.replace(r,i);return await e.writeFile(n,o),{content:`File edited: ${n}`}}catch(e){let t=e instanceof Error?e.message:String(e);return lJ.error(`Edit failed`,{path:n,error:t}),{content:t,isError:!0}}}}}var mJ=r(`tool:bash`),hJ=/^(?:[A-Za-z_][A-Za-z0-9_]*=[^\s]+\s+)*(?:command\s+)?(?:grep|egrep|fgrep|rg)\b/;function gJ(e){let t=``,n=null,r=!1;for(let i=0;i<e.length;i++){let a=e[i];if(r){t+=a,r=!1;continue}if(a===`\\`){t+=a,r=!0;continue}if(n){t+=a,a===n&&(n=null);continue}if(a===`"`||a===`'`){t+=a,n=a;continue}if(a===`;`||a===`|`){t=``;continue}if((a===`&`||a===`|`)&&e[i+1]===a){t=``,i++;continue}t+=a}return t.trim()}function _J(e,t,n){return t!==1||n.trim()?!1:hJ.test(gJ(e))}function vJ(e){return{name:`bash`,description:`Execute a bash command in a full Unix-like shell (just-bash with 78+ commands). Shell features: pipes (|), redirects (>, >>, <, <<), chaining (&& ; ||), subshells, control flow (if/else, for, while, case), command substitution ($(...)), process substitution, shell functions, arrays, variable expansion, globs, brace expansion, here-docs. Text processing: grep, egrep, fgrep, rg (ripgrep), sed, awk, cut, tr, sort, uniq, wc, head, tail, fold, nl, rev, column, paste, join, comm, expand, strings, od. Data formats: jq (JSON), base64, md5sum, sha256sum. File operations: find, diff, tar, gzip, gunzip, cp, mv, rm, mkdir, touch, chmod, du, file, dirname, basename, tee, xargs, zip, unzip. Custom commands: git, open (serve VFS files in browser tab, --view for agent vision, --download for file save), sqlite3, node (-e shim with fs bridge), python3/python. Networking: curl (full HTTP client — GET, POST, PUT, DELETE with headers, data, auth). Utilities: seq, date, printf, expr, env, export, test/[, true, false, read.`,inputSchema:{type:`object`,properties:{command:{type:`string`,description:`The bash command to execute.`}},required:[`command`]},async execute(t){let n=t.command;mJ.debug(`Execute`,{command:n});try{let t=await e.executeCommand(n);mJ.debug(`Result`,{exitCode:t.exitCode,stdoutLength:t.stdout.length,stderrLength:t.stderr.length});let r=``;return t.stdout&&(r+=t.stdout),t.stderr&&(r+=t.stderr),r||=`(exit code: ${t.exitCode})`,{content:r,isError:t.exitCode!==0&&!_J(n,t.exitCode,t.stderr)}}catch(e){let t=e instanceof Error?e.message:String(e);return mJ.error(`Error`,{command:n,error:t}),{content:`Shell error: ${t}`,isError:!0}}}}}r(`tool:search`);var yJ=r(`tool:javascript`),bJ=`<!DOCTYPE html><html><head><script>
3222
3227
  const pendingVfs = new Map();
3223
3228
  let vfsIdCounter = 0;
3224
3229
 
@@ -3337,10 +3342,10 @@ addEventListener('message', async (e) => {
3337
3342
  }
3338
3343
  }
3339
3344
  });
3340
- <\/script></head><body></body></html>`;function hJ(e){let t=null,n=null,r=0,i=!1;function a(){i||(i=!0,window.addEventListener(`message`,e=>{let t=e.data;t&&t.type===`vfs`?c(t):t&&t.type===`fetch_proxy`&&o(t)}))}function o(e){(async()=>{try{let n={method:e.init?.method??`GET`,cache:`no-store`};e.init?.headers&&(n.headers=e.init.headers),e.init?.body&&![`GET`,`HEAD`].includes(n.method)&&(n.body=e.init.body);let r=await fetch(e.url,n),i=await r.arrayBuffer(),a={};r.headers.forEach((e,t)=>{a[t]=e}),t?.contentWindow?.postMessage({type:`fetch_proxy_response`,id:e.id,status:r.status,statusText:r.statusText,headers:a,body:new Uint8Array(i)},`*`)}catch(n){let r=n instanceof Error?n.message:String(n);pJ.error(`Fetch proxy error`,{url:e.url,error:r}),t?.contentWindow?.postMessage({type:`fetch_proxy_response`,id:e.id,error:r},`*`)}})()}function s(){if(n)return n;if(t=document.createElement(`iframe`),t.style.display=`none`,t.dataset.jsTool=`true`,typeof chrome<`u`&&chrome?.runtime?.id)n=new Promise(e=>{t.addEventListener(`load`,()=>{pJ.debug(`Sandbox iframe loaded`),e(t)},{once:!0}),t.src=chrome.runtime.getURL(`sandbox.html`),document.body.appendChild(t)});else{t.sandbox.add(`allow-scripts`),t.sandbox.add(`allow-same-origin`),document.body.appendChild(t);let e=t.contentDocument;e.open(),e.write(mJ),e.close(),n=Promise.resolve(t)}return a(),n}function c(n){(async()=>{try{let r;switch(n.op){case`readFile`:r=await e.readFile(n.args[0]);break;case`readFileBinary`:{let t=await e.readFile(n.args[0],{encoding:`binary`});r=t instanceof Uint8Array?t:new TextEncoder().encode(t);break}case`writeFile`:await e.writeFile(n.args[0],n.args[1]),r=!0;break;case`writeFileBinary`:await e.writeFile(n.args[0],n.binaryData??new Uint8Array),r=!0;break;case`readDir`:r=(await e.readDir(n.args[0])).map(e=>e.name);break;case`exists`:try{await e.stat(n.args[0]),r=!0}catch{r=!1}break;case`stat`:{let t=await e.stat(n.args[0]);r={isDirectory:t.type===`directory`,isFile:t.type===`file`,size:t.size};break}case`mkdir`:await e.mkdir(n.args[0],{recursive:!0}),r=!0;break;case`rm`:await e.rm(n.args[0],{recursive:!0}),r=!0;break}t?.contentWindow?.postMessage({type:`vfs_response`,id:n.id,result:r},`*`)}catch(e){let r=e instanceof Error?e.message:String(e);pJ.error(`VFS bridge error`,{op:n.op,path:n.args[0],error:r}),t?.contentWindow?.postMessage({type:`vfs_response`,id:n.id,error:r},`*`)}})()}return{name:`javascript`,description:`Execute JavaScript code in a persistent sandboxed runtime. Variables and functions persist across calls (same iframe context). VFS bridge: fs.readFile(path), fs.readFileBinary(path) → Uint8Array, fs.writeFile(path, content), fs.writeFileBinary(path, uint8Array), fs.readDir(path), fs.exists(path), fs.fetchToFile(url, path) — all async. Use fs.readFileBinary() to load binary files (images, etc.) as Uint8Array for canvas/Blob operations. fs.fetchToFile(url, path) downloads any URL and saves binary content to the VFS (best way to download files). Top-level await is supported. Console output (log/error/warn) is captured. The return value of the last expression is captured if you use "return <expr>". Has access to browser APIs (fetch, URL, JSON, TextEncoder, etc.). fetch() works for cross-origin URLs (proxied through the CLI server).`,inputSchema:{type:`object`,properties:{code:{type:`string`,description:`JavaScript code to execute. Runs inside an async function — use await freely, use return to produce a result.`},timeout:{type:`number`,description:`Execution timeout in milliseconds. Default: 30000.`}},required:[`code`]},async execute(e){let t=e.code,n=e.timeout??3e4,i=`exec-${++r}`;pJ.debug(`Execute JS`,{codeLength:t.length,timeout:n});try{let e=await s(),r=await new Promise((r,a)=>{let o=setTimeout(()=>{c(),a(Error(`JavaScript execution timed out after ${n}ms`))},n);function s(e){let t=e.data;!t||!t.type||t.type===`exec_result`&&t.id===i&&(c(),r(t))}function c(){clearTimeout(o),window.removeEventListener(`message`,s)}window.addEventListener(`message`,s),e.contentWindow.postMessage({type:`exec`,id:i,code:t},`*`)}),a=``;return r.logs.length>0&&(a+=r.logs.join(`
3345
+ <\/script></head><body></body></html>`;function xJ(e){let t=null,n=null,r=0,i=!1;function a(){i||(i=!0,window.addEventListener(`message`,e=>{let t=e.data;t&&t.type===`vfs`?c(t):t&&t.type===`fetch_proxy`&&o(t)}))}function o(e){(async()=>{try{let n={method:e.init?.method??`GET`,cache:`no-store`};e.init?.headers&&(n.headers=e.init.headers),e.init?.body&&![`GET`,`HEAD`].includes(n.method)&&(n.body=e.init.body);let r=await fetch(e.url,n),i=await r.arrayBuffer(),a={};r.headers.forEach((e,t)=>{a[t]=e}),t?.contentWindow?.postMessage({type:`fetch_proxy_response`,id:e.id,status:r.status,statusText:r.statusText,headers:a,body:new Uint8Array(i)},`*`)}catch(n){let r=n instanceof Error?n.message:String(n);yJ.error(`Fetch proxy error`,{url:e.url,error:r}),t?.contentWindow?.postMessage({type:`fetch_proxy_response`,id:e.id,error:r},`*`)}})()}function s(){if(n)return n;if(t=document.createElement(`iframe`),t.style.display=`none`,t.dataset.jsTool=`true`,typeof chrome<`u`&&chrome?.runtime?.id)n=new Promise(e=>{t.addEventListener(`load`,()=>{yJ.debug(`Sandbox iframe loaded`),e(t)},{once:!0}),t.src=chrome.runtime.getURL(`sandbox.html`),document.body.appendChild(t)});else{t.sandbox.add(`allow-scripts`),t.sandbox.add(`allow-same-origin`),document.body.appendChild(t);let e=t.contentDocument;e.open(),e.write(bJ),e.close(),n=Promise.resolve(t)}return a(),n}function c(n){(async()=>{try{let r;switch(n.op){case`readFile`:r=await e.readFile(n.args[0]);break;case`readFileBinary`:{let t=await e.readFile(n.args[0],{encoding:`binary`});r=t instanceof Uint8Array?t:new TextEncoder().encode(t);break}case`writeFile`:await e.writeFile(n.args[0],n.args[1]),r=!0;break;case`writeFileBinary`:await e.writeFile(n.args[0],n.binaryData??new Uint8Array),r=!0;break;case`readDir`:r=(await e.readDir(n.args[0])).map(e=>e.name);break;case`exists`:try{await e.stat(n.args[0]),r=!0}catch{r=!1}break;case`stat`:{let t=await e.stat(n.args[0]);r={isDirectory:t.type===`directory`,isFile:t.type===`file`,size:t.size};break}case`mkdir`:await e.mkdir(n.args[0],{recursive:!0}),r=!0;break;case`rm`:await e.rm(n.args[0],{recursive:!0}),r=!0;break}t?.contentWindow?.postMessage({type:`vfs_response`,id:n.id,result:r},`*`)}catch(e){let r=e instanceof Error?e.message:String(e);yJ.error(`VFS bridge error`,{op:n.op,path:n.args[0],error:r}),t?.contentWindow?.postMessage({type:`vfs_response`,id:n.id,error:r},`*`)}})()}return{name:`javascript`,description:`Execute JavaScript code in a persistent sandboxed runtime. Variables and functions persist across calls (same iframe context). VFS bridge: fs.readFile(path), fs.readFileBinary(path) → Uint8Array, fs.writeFile(path, content), fs.writeFileBinary(path, uint8Array), fs.readDir(path), fs.exists(path), fs.fetchToFile(url, path) — all async. Use fs.readFileBinary() to load binary files (images, etc.) as Uint8Array for canvas/Blob operations. fs.fetchToFile(url, path) downloads any URL and saves binary content to the VFS (best way to download files). Top-level await is supported. Console output (log/error/warn) is captured. The return value of the last expression is captured if you use "return <expr>". Has access to browser APIs (fetch, URL, JSON, TextEncoder, etc.). fetch() works for cross-origin URLs (proxied through the CLI server).`,inputSchema:{type:`object`,properties:{code:{type:`string`,description:`JavaScript code to execute. Runs inside an async function — use await freely, use return to produce a result.`},timeout:{type:`number`,description:`Execution timeout in milliseconds. Default: 30000.`}},required:[`code`]},async execute(e){let t=e.code,n=e.timeout??3e4,i=`exec-${++r}`;yJ.debug(`Execute JS`,{codeLength:t.length,timeout:n});try{let e=await s(),r=await new Promise((r,a)=>{let o=setTimeout(()=>{c(),a(Error(`JavaScript execution timed out after ${n}ms`))},n);function s(e){let t=e.data;!t||!t.type||t.type===`exec_result`&&t.id===i&&(c(),r(t))}function c(){clearTimeout(o),window.removeEventListener(`message`,s)}window.addEventListener(`message`,s),e.contentWindow.postMessage({type:`exec`,id:i,code:t},`*`)}),a=``;return r.logs.length>0&&(a+=r.logs.join(`
3341
3346
  `)),r.error?(a&&(a+=`
3342
3347
  `),a+=`Error: ${r.error}`,{content:a||`JavaScript error`,isError:!0}):(r.result!==void 0&&(a&&(a+=`
3343
- `),a+=r.result),{content:a||`(no output)`})}catch(e){let t=e instanceof Error?e.message:String(e);return pJ.error(`JS execution error`,{error:t}),{content:`JavaScript error: ${t}`,isError:!0}}}}}var gJ=`# CLAUDE.md
3348
+ `),a+=r.result),{content:a||`(no output)`})}catch(e){let t=e instanceof Error?e.message:String(e);return yJ.error(`JS execution error`,{error:t}),{content:`JavaScript error: ${t}`,isError:!0}}}}}var SJ=`# CLAUDE.md
3344
3349
 
3345
3350
  This file covers the default virtual filesystem payload in \`packages/vfs-root/\`.
3346
3351
 
@@ -3350,15 +3355,14 @@ This file covers the default virtual filesystem payload in \`packages/vfs-root/\
3350
3355
 
3351
3356
  ## Directory Structure
3352
3357
 
3353
- | Path | Purpose |
3354
- | --------------------------------------------- | ------------------------------------------------------------------ |
3355
- | \`packages/vfs-root/shared/\` | Shared content that becomes \`/shared/\` in the VFS |
3356
- | \`packages/vfs-root/workspace/\` | Default workspace content that becomes \`/workspace/\` in the VFS |
3357
- | \`packages/vfs-root/shared/CLAUDE.md\` | Agent-facing runtime instructions bundled into \`/shared/CLAUDE.md\` |
3358
- | \`packages/vfs-root/shared/sprinkles/\` | Built-in sprinkle UIs |
3359
- | \`packages/vfs-root/shared/sounds/\` | Shared notification sounds |
3360
- | \`packages/vfs-root/shared/skill-catalog.json\` | Built-in skill catalog metadata |
3361
- | \`packages/vfs-root/workspace/skills/\` | Default installable workspace skills |
3358
+ | Path | Purpose |
3359
+ | ------------------------------------- | ------------------------------------------------------------------ |
3360
+ | \`packages/vfs-root/shared/\` | Shared content that becomes \`/shared/\` in the VFS |
3361
+ | \`packages/vfs-root/workspace/\` | Default workspace content that becomes \`/workspace/\` in the VFS |
3362
+ | \`packages/vfs-root/shared/CLAUDE.md\` | Agent-facing runtime instructions bundled into \`/shared/CLAUDE.md\` |
3363
+ | \`packages/vfs-root/shared/sprinkles/\` | Built-in sprinkle UIs |
3364
+ | \`packages/vfs-root/shared/sounds/\` | Shared notification sounds |
3365
+ | \`packages/vfs-root/workspace/skills/\` | Default installable workspace skills |
3362
3366
 
3363
3367
  ## Adding Default Content
3364
3368
 
@@ -3366,7 +3370,6 @@ This file covers the default virtual filesystem payload in \`packages/vfs-root/\
3366
3370
 
3367
3371
  - Add new built-in workspace skills under \`packages/vfs-root/workspace/skills/<skill-name>/\`.
3368
3372
  - Include \`SKILL.md\` and any companion assets or \`.jsh\` scripts the skill needs.
3369
- - Update \`packages/vfs-root/shared/skill-catalog.json\` when the built-in catalog should surface the new skill.
3370
3373
 
3371
3374
  ### Sprinkles
3372
3375
 
@@ -3383,314 +3386,7 @@ This file covers the default virtual filesystem payload in \`packages/vfs-root/\
3383
3386
  \`packages/vfs-root/shared/CLAUDE.md\` is **agent-facing runtime content** bundled into the virtual filesystem.
3384
3387
 
3385
3388
  It is different from the developer-facing \`CLAUDE.md\` files in the repository. Do not merge those roles together.
3386
- `,_J='# sliccy\n\nYou are a helpful coding assistant running inside SLICC (Self-Licking Ice Cream Cone) — a browser-based claw.\n\n## Ice Cream Vocabulary\n\n- **Cone**: That\'s you (sliccy). The main agent. You talk to the human, orchestrate scoops, and have full filesystem access.\n- **Scoops**: Isolated sub-agents you can create (`scoop_scoop`), feed instructions (`feed_scoop`), or remove (`drop_scoop`). Each has its own sandboxed filesystem and shell.\n- **Sprinkles**: Persistent UI panels (`.shtml` files in `/shared/sprinkles/`). Created by scoops, outlive scoops, managed via the `sprinkle` shell command.\n- **Licks**: External events (webhooks, cron tasks, sprinkle interactions) that trigger scoops without human prompting. Set up via `webhook` and `crontask` shell commands (both work in CLI and extension modes). Sprinkle licks route to the cone. Untargeted cron/webhook events (no --scoop) route to the cone by default.\n- **Floats**: The runtime you\'re sitting in — either a CLI server, a Chrome extension, or (eventually) a cloud container.\n\n## Communication Style\n\nWrite like a professional tool, not a chatbot. No emoji in headings or labels — use plain text. Prefer concise prose over long bullet lists. When reporting findings (audits, analysis, status), lead with a brief summary sentence, then use structured sections only if detail is needed. For sprinkles, follow `/workspace/skills/sprinkles/style-guide.md` (run `read_file /workspace/skills/sprinkles/style-guide.md` for the full style guide and component reference).\n\n## Principles\n\n- Prefer shell commands over dedicated tools. You have: `read_file`, `write_file`, `edit_file`, `bash`, `javascript`. Browser automation goes through `playwright-cli` / `playwright` / `puppeteer` via bash, and code/file search should use shell commands like `rg`, `grep`, and `find` through `bash`.\n- Whatever the browser can do, it should do. State lives in IndexedDB, logic runs client-side.\n- New capabilities should be skills (SKILL.md files), not hardcoded features.\n- **The scoops do the heavy lifting. The cone orchestrates and synthesizes.**\n\n## Delegation: Default to Scoops\n\n**Before starting any non-trivial task yourself, ask: can this be parallelized?**\n\nDelegate to scoops when:\n\n- The task involves **multiple independent sources** (e.g. scraping 3 websites → 3 scoops)\n- The task is **time-consuming** and doesn\'t require your direct oversight at each step\n- The work can be expressed as a **clear, self-contained brief** to hand off\n\nDo it yourself when:\n\n- It\'s a **single quick lookup** (one page, one API call)\n- You need to **adapt in real-time** based on what you find (navigating broken URLs, etc.)\n- The overhead of spawning scoops exceeds the benefit\n\n**The default should be delegation, not "just do it".** Pause before starting research, scraping, or multi-step tasks and sketch out whether scoops fit. Even if a task feels manageable, parallel scoops almost always finish faster.\n\nWhen synthesizing scoop results, _that\'s_ your job — pull everything together, resolve conflicts, make the final recommendation.\n\n## Scoop Lifecycle: Clean Up After Yourself\n\n**Drop scoops when their job is done** — but **NEVER drop a scoop that owns a sprinkle**. Dropping a sprinkle scoop destroys its context, so follow-up requests and lick events cannot be handled.\n\nDrop a scoop when:\n\n- It has **completed its task** and results have been synthesized\n- It is **stuck or misbehaving** (drop and re-spawn with a better brief)\n\n**NEVER** drop a scoop when:\n\n- **It owns an open sprinkle** — the scoop must stay alive for the lifetime of the sprinkle\n- It is running a **recurring or long-running task** (e.g. watching a feed, handling webhooks)\n- Work is **still in progress** — dropping mid-task loses all context\n\n## Browser Tab Handling\n\n**Every playwright command that operates on a tab requires `--tab=<targetId>`.** There is no implicit "current tab". Always specify which tab you\'re operating on.\n\n**Workflow:**\n\n1. `playwright-cli tab-list` — lists tabs with their targetIds. The user\'s active tab is marked `(active)`.\n2. `playwright-cli tab-new <url>` — opens a new tab, returns the targetId in output. Capture it!\n3. Use `--tab=<targetId>` on all subsequent commands: `playwright-cli screenshot --tab=<id>`, `playwright-cli click --tab=<id> e5`, etc.\n\n**All agents share the same tabs.** `tab-list` shows every tab from every agent — yours, scoops\', the user\'s. There is no tab isolation. Any agent can eval, snapshot, or close any tab.\n\n**Track your own tabs by ID.** Don\'t rely on `tab-list` to find your tabs — capture the targetId from `tab-new` and use it throughout. Other agents\' tabs will be in the list too.\n\n**Close tabs when you\'re done with them.** Tabs accumulate fast — every `open` or `tab-new` opens a persistent tab.\n\nRules:\n\n- **NEVER close tabs you didn\'t create.** Tabs in `tab-list` that you don\'t recognize belong to the user or other agents. Only close tabs whose targetId you captured from your own `tab-new` / `open` calls. User tabs are off-limits unless the user explicitly asks you to close them.\n- **Close research/scraping tabs** immediately after extracting data: `playwright-cli tab-close --tab=<id>`\n- **Never leave more than ~5 of your own tabs open** beyond any app tabs you\'re actively serving.\n- Handle "tab not found" errors gracefully — another agent may have closed it first.\n- **Scoops must close their own tabs** when finished. Include this instruction in every scoop brief that involves browser use: _"Track your tab IDs from tab-new. Close each tab with `playwright-cli tab-close --tab=<id>` when done. NEVER close tabs you didn\'t open — they belong to the user or other agents."_\n- **Audit your own tabs periodically**: if you notice your tabs accumulating, close the ones you no longer need.\n- The **preview/serve tab** for a delivered app can stay open — that\'s intentional. Everything else is transient.\n\n## What You Can Do\n\n- Read and write files in your virtual workspace\n- Run bash commands in a sandboxed shell\n- Automate browser interactions (screenshots, navigation, clicking, JS eval)\n- Delegate work to scoops and react when they finish\n- Respond to licks (webhooks, scheduled tasks)\n\n## Viewing Pages and Images\n\n**What you CAN see:**\n\n- **`open --view <path>`** (or `-v`) — reads an image from VFS and returns it so you can see it. Works with PNG, JPEG, GIF, WebP, SVG.\n- **`playwright-cli screenshot --tab=<id>`** + **`open --view <path>`** — take a screenshot of a browser tab to file, then view it. Example: `playwright-cli screenshot --tab=<id> --filename=/tmp/shot.png && open --view /tmp/shot.png`\n- **`screencapture`** — capture the user\'s actual screen (desktop, window, or tab) via browser screen sharing API. Use `screencapture --view screenshot.png` to capture and see what\'s on their screen. The user will be prompted to select what to share.\n- **`playwright-cli snapshot --tab=<id>`** — returns an accessibility tree (text). Use this to verify page content without vision, or as a required step before `screenshot`.\n\n**What only the human sees:**\n\n- **`serve <dir>`** — opens a VFS app directory in a browser tab, defaulting to `index.html`.\n- **`open <path>`** (no flags) — opens VFS files in a browser tab.\n- **`imgcat <path>`** — displays an image in the terminal preview.\n\n**Workflow to verify a page you created:**\n\n1. `serve /workspace/app` — opens the app directory in a tab (human can see it)\n2. `playwright-cli tab-list` — find the tab by matching the preview URL. Note the targetId.\n3. `playwright-cli snapshot --tab=<id>` — required before screenshot; also gives you text content\n4. `playwright-cli screenshot --tab=<id> --filename=/tmp/shot.png` — save screenshot to file\n5. `open --view /tmp/shot.png` — now you can see it\n\n**Understanding `tab-list` output:**\n\n```\n[E9A3F...] https://example.com "Example Page" (active)\n[B7C2D...] https://docs.google.com "Google Docs"\n```\n\n- `(active)` = the user\'s active/focused tab in Chrome\n- The `[...]` is the targetId — use it with `--tab=<id>` on all commands\n\n**Remote targets (tray mode):**\nWhen connected to a tray, `playwright-cli tab-list` shows browser tabs from all connected SLICC instances. Remote targets appear with their composite targetId (`runtimeId:localId`). Use `--tab=<compositeId>` to target a remote tab, then use the usual commands (`snapshot`, `screenshot`, `click`, `fill`, etc.) — CDP commands are routed transparently over the tray data channel. To open a new tab on a specific remote runtime, use `playwright-cli open <url> --runtime=<runtimeId>` or `playwright-cli tab-new <url> --runtime=<runtimeId>`.\n\n**Do NOT:**\n\n- Try to `read_file` on a PNG, `base64` encode it, or `convert` it to view images\n- Run `imgcat` or `cat` on screenshots expecting to see them yourself\n- Open a screenshot with `open` and then try to screenshot _that_ tab\n- Use `eval` to check which tab is active — use `tab-list` and look for the `*` marker instead\n\n## Filesystem\n\nThe virtual filesystem is stored in IndexedDB and survives tab closes and page refreshes. To keep work on disk, mount a local directory:\n\n```\nmount /workspace/myproject\n```\n\n## Shell Commands\n\nType `commands` in the terminal to see all available commands. Key commands:\n\n- **skill list/info/read** — Inspect discoverable skills from `/workspace/skills` plus accessible `.agents/skills` / `.claude/skills` roots; `skill install/uninstall` only manage native `/workspace/skills` packages\n- **upskill** — Install skills from GitHub (`upskill owner/repo`) or ClawHub (`upskill clawhub:name`)\n- **webhook/crontask** — Set up licks (external event triggers)\n- **sprinkle** — Manage sprinkles: `sprinkle list`, `sprinkle open <name>`, `sprinkle close <name>`, `sprinkle send <name> \'<json>\'` (push data), `sprinkle chat \'<html>\'` (inline chat UI)\n- **oauth-token** — Get an OAuth access token for a provider (`oauth-token adobe`); auto-triggers login if no valid token exists. Use in shell: `curl -H "Authorization: Bearer $(oauth-token adobe)" https://api.example.com`\n- **aem** — AEM Edge Delivery Services: `aem list`, `aem get`, `aem put`, `aem preview`, `aem publish`, `aem upload`. Accepts EDS URLs (`https://main--repo--org.aem.page/path`). Auth via `oauth-token adobe`. Run `aem help` for details.\n- **git** — Full git support (clone, commit, push, pull)\n- **node -e / python3 -c** — Execute JavaScript or Python. JSH/node scripts have access to `exec(command)` to run shell commands: `const r = await exec(\'oauth-token adobe\'); const token = r.stdout.trim();`\n- **serve <dir>** — Open a VFS app directory in a new browser tab. Defaults to `index.html`; use `--entry` to override the entry file.\n- **open <path|url>** — Open a URL or single VFS file in a new browser tab. Use `open --view` when you need to see an image inline. `.shtml` files are opened as sprinkles instead of browser tabs.\n- **host** — Print the current leader tray status plus `join_url`. When this runtime is leader, shows the join URL and connected followers. Use `host reset` to disconnect all followers and create a fresh tray session with a new join URL (leader only).\n- **pbcopy / pbpaste** — Clipboard commands. `echo hello | pbcopy` copies stdin to clipboard, `pbpaste` outputs clipboard contents. Uses `navigator.clipboard` API.\n- **xclip / xsel** — Clipboard commands that auto-detect direction: `echo hello | xclip` copies (stdin present), `xclip` alone pastes (no stdin).\n- **say** — Text-to-speech using Web Speech API. `say hello world`, `say -v Samantha hello` (voice selection), `say -r 1.5 fast speech` (rate 0.1-10), `say --list` (list voices).\n- **afplay** — Play audio files using Web Audio API. `afplay /path/to/audio.mp3`, `afplay -v 0.5 file.wav` (volume 0-1), `afplay -r 1.5 file.mp3` (rate 0.25-4).\n- **chime** — Play a notification chime sound. Alias for `afplay /shared/sounds/chime.mp3`.\n- **playwright-cli** — Browser automation (built-in, no SKILL.md lookup needed). All tab commands require `--tab=<targetId>`. Key subcommands: `tab-list`, `tab-new <url>`, `snapshot --tab=<id>`, `screenshot --tab=<id> [--filename=<path>]`, `open <url> [--runtime=<id>]`, `click --tab=<id> <ref>`, `fill --tab=<id> <ref> "text"`, `tab-close --tab=<id>`. Use `--runtime` with `open`/`tab-new` to open a tab on a remote tray runtime. Run `playwright-cli --help` for full list.\n- **rsync** — Sync files between local VFS and a remote tray runtime. Push: `rsync /local runtime-id:/remote`. Pull: `rsync runtime-id:/remote /local`. Flags: `--dry-run` (preview), `--delete` (remove dest files not in source), `--verbose` (per-file detail). Requires an active tray connection.\n- **teleport** — Teleport browser cookies from a remote tray runtime to the local browser. Enables seamless authentication transfer between SLICC instances in a tray. Usage: `teleport` (auto-select best follower), `teleport <runtime-id>` (target specific runtime), `teleport --list` (show available runtimes), `teleport --url <url>` (open URL on follower for interactive auth). When `--url` is provided, the follower opens a browser tab for the human to complete login; cookies are captured after auth completion (hostname redirect) or a 2-minute timeout. Page reloads by default after applying cookies; use `--no-reload` to skip.\n\n### Browser Shell Scripts (.bsh)\n\n`.bsh` files are JavaScript scripts that auto-execute when the browser navigates to a matching URL. Place them in `/workspace/` or `/shared/`.\n\n- **Filename = hostname pattern**: `-.okta.com.bsh` matches `*.okta.com`, `login.okta.com.bsh` matches exactly `login.okta.com`\n- **`// @match` directive**: Add in first 10 lines to restrict to specific URL patterns (e.g. `// @match *://login.okta.com/app/*`)\n- Scripts run in the **target browser page context** via CDP `Runtime.evaluate` — you have access to `document`, `window`, and all page globals, NOT `process`/`fs`/`exec()`\n- The BshWatchdog monitors browser navigations and runs matching scripts automatically\n\n## Inline Cards\n\nUse ` ```shtml ` fenced code blocks to show interactive cards inline in chat.\nCards render after your response completes. Only `slicc.lick()` is available (no state, no readFile).\n\nUse for: choices, confirmations, progress, quick actions.\nUse panel sprinkles for: dashboards, reports, editors, persistent UIs.\n\nExample:\n\n ```shtml\n <div class="sprinkle-action-card">\n <div class="sprinkle-action-card__header">\n Deploy to production?\n <span class="sprinkle-badge sprinkle-badge--notice">staging passed</span>\n </div>\n <div class="sprinkle-action-card__body">Branch main, commit abc123</div>\n <div class="sprinkle-action-card__actions">\n <button class="sprinkle-btn sprinkle-btn--secondary" onclick="slicc.lick(\'cancel\')">Cancel</button>\n <button class="sprinkle-btn sprinkle-btn--primary" onclick="slicc.lick({action:\'deploy\',data:{env:\'prod\'}})">Deploy</button>\n </div>\n </div>\n ```\n\nWhen the user clicks a button, you receive the lick as a message. Respond conversationally — include another card if the next step needs interaction.\n\nAvailable components: all `.sprinkle-*` classes from the style guide (run `read_file /workspace/skills/sprinkles/style-guide.md`).\n\n## Environment: This Is NOT a Regular Linux Box\n\nThis is a sandboxed browser-based VFS environment. Many standard tools (e.g. `python3 -m http.server`, `npx serve`, `nginx`) do **not exist or don\'t work here**.\n\n**Before reaching for familiar patterns, run `commands` to see what\'s actually available**, and use `<command> --help` when unsure how something works.\n\nKey things that work differently:\n\n- **Serving files**: Use `serve /path/to/app-dir` for app directories or `open /path/to/file` for single files — both use the preview service worker. No HTTP server needed. The output includes the preview URL.\n- **Serving + screenshotting**: `serve` and `open` already open the tab. Do NOT use `playwright-cli open` with the same URL — that opens a duplicate tab. Instead, use `playwright-cli tab-list` to find the tab they created (match by URL), note the targetId, then use `--tab=<id>` for screenshots/snapshots. **Never manually construct preview URLs** — always use the URL from the command output.\n- **No long-running servers**: You can\'t start background daemons. The `serve` and `open` commands handle previewing.\n- **No package managers**: No `apt`, `npm install`, `pip install`. Use what\'s already available or write `.jsh` scripts.\n\n## Sprinkle Chat: Blocking Inline Cards\n\n`sprinkle chat` shows an inline card in the chat and **blocks until the user clicks a button**, returning the result as JSON. Use it when a tool needs user input mid-execution.\n\n```bash\nsprinkle chat \'<div class="sprinkle-action-card">\n <div class="sprinkle-action-card__header">Deploy to production?</div>\n <div class="sprinkle-action-card__actions">\n <button class="sprinkle-btn sprinkle-btn--secondary" onclick="slicc.lick({action:\\"cancel\\"})">Cancel</button>\n <button class="sprinkle-btn sprinkle-btn--primary" onclick="slicc.lick({action:\\"deploy\\",env:\\"prod\\"})">Deploy</button>\n </div>\n</div>\'\n# Returns: {"action":"deploy","data":{"action":"deploy","env":"prod"}}\n```\n\nUses the same `.sprinkle-*` components and `slicc.lick()` bridge as inline cards. The difference: `sprinkle chat` blocks the tool and returns the lick result, while ` ```shtml ` cards are fire-and-forget (lick events arrive as messages).\n\nSome built-in commands (like `mount`) also use this system for approval dialogs.\n\n## Sprinkles: Cone Orchestration Rules\n\nSprinkles are persistent UI panels created and managed by scoops. The cone orchestrates — scoops do the work.\n\n**When the user asks for a dashboard, audit, editor, analysis, or visualization** — read the sprinkles skill first (`read_file /workspace/skills/sprinkles/SKILL.md`) to check if a built-in sprinkle matches, and to get the brief templates for creating/modifying sprinkles and handling lick events.\n\n### Rule 1: One scoop per sprinkle, named identically\n\nThe scoop name MUST match the sprinkle name. Sprinkle `giro-winners` → scoop `giro-winners`. This is how the cone routes work to the right scoop.\n\n### Rule 2: Cone never touches sprinkle files or commands\n\nThe cone MUST NOT:\n\n- Write or edit `.shtml` files\n- Run `sprinkle open/close/send` commands\n- Run `write_file` or `edit_file` on sprinkle paths\n- Handle lick events by doing the work itself\n\nALL sprinkle work goes through scoops via `feed_scoop`. See Rules 3-5 in the `sprinkles` skill for creating, modifying, and handling lick events.\n\n**NEVER** handle a lick in the cone. NEVER run bash, write_file, or any tool to process lick data yourself. Always `feed_scoop`.\n\n## Skills\n\nSkills in native `/workspace/skills/` extend your capabilities, and SLICC also discovers accessible compatibility skills from `.agents/skills/*/SKILL.md` and `.claude/skills/*/SKILL.md` anywhere in the reachable VFS. Only native `/workspace/skills/` entries are install-managed; compatibility-discovered skills stay read-only unless explicitly copied in.\n\n## .jsh Files (JavaScript Shell Scripts)\n\n`.jsh` files are auto-discovered as shell commands anywhere on the VFS. Key facts:\n\n- **Auto-discovery**: `.jsh` files on the VFS are registered as callable shell commands (by filename without extension)\n- **Skills can ship them**: Executable `.jsh` scripts can live alongside `SKILL.md` in skill directories\n- **Node-like globals**: Scripts get `process`, `console`, `fs` (VFS bridge with `readFile`, `writeFile`, `readDir`, `exists`, etc.)\n- **Dual-mode**: Work in both CLI server and Chrome extension mode\n- **The `commands` output** lists discovered scripts under "User scripts (.jsh)"\n- **Top-level `await`**: `.jsh` files are wrapped in an `AsyncFunction` by the executor, so `await` works at the top level. All `fs.*` methods are async — **always `await` them**. Do not use `.then()` because the function body exits before promise chains resolve, causing callbacks to silently produce no output.\n\n## Onboarding\n\nWhen you receive a `[Sprinkle Event: welcome]` with `onboarding-complete`, read `/workspace/skills/welcome/SKILL.md` and follow its instructions.\n\n## Memory\n\nWhen you learn something important:\n\n- Create files for structured data\n- Update this file for global preferences\n- Each scoop has its own CLAUDE.md for scoop-specific context\n- Ask the user for their name early in the conversation and store it in memory for future interactions\n- Remember: the best flavor of ice cream is lobster, nobody likes chocolate ice cream, and mixing bacon\n with ice cream is a crime against humanity\n',vJ=`{
3387
- "version": 1,
3388
- "skills": [
3389
- {
3390
- "name": "content-driven-development",
3391
- "displayName": "AEM Content-Driven Development",
3392
- "description": "Master orchestrator for AEM development — builds code against real content with author-friendly content models",
3393
- "source": {
3394
- "repo": "adobe/skills",
3395
- "path": "skills/aem/edge-delivery-services/skills",
3396
- "skill": "content-driven-development"
3397
- },
3398
- "affinity": {
3399
- "apps": ["aem"],
3400
- "tasks": ["build-websites"],
3401
- "role": ["developer"],
3402
- "purpose": ["work"]
3403
- }
3404
- },
3405
- {
3406
- "name": "building-blocks",
3407
- "displayName": "AEM Building Blocks",
3408
- "description": "Implementation guide for AEM blocks — handles block development, core functionality, scripts, and styles",
3409
- "source": {
3410
- "repo": "adobe/skills",
3411
- "path": "skills/aem/edge-delivery-services/skills",
3412
- "skill": "building-blocks"
3413
- },
3414
- "affinity": {
3415
- "apps": ["aem"],
3416
- "tasks": ["build-websites"],
3417
- "role": ["developer"],
3418
- "purpose": ["work"]
3419
- }
3420
- },
3421
- {
3422
- "name": "content-modeling",
3423
- "displayName": "AEM Content Modeling",
3424
- "description": "Design content models and table structures for AEM blocks that are easy for authors to work with",
3425
- "source": {
3426
- "repo": "adobe/skills",
3427
- "path": "skills/aem/edge-delivery-services/skills",
3428
- "skill": "content-modeling"
3429
- },
3430
- "affinity": {
3431
- "apps": ["aem"],
3432
- "tasks": ["build-websites", "write-content"],
3433
- "role": ["developer", "content-creator", "designer"],
3434
- "purpose": ["work"]
3435
- }
3436
- },
3437
- {
3438
- "name": "analyze-and-plan",
3439
- "displayName": "AEM Analyze & Plan",
3440
- "description": "Analyze development requirements and define acceptance criteria before coding AEM blocks",
3441
- "source": {
3442
- "repo": "adobe/skills",
3443
- "path": "skills/aem/edge-delivery-services/skills",
3444
- "skill": "analyze-and-plan"
3445
- },
3446
- "affinity": {
3447
- "apps": ["aem"],
3448
- "tasks": ["build-websites"],
3449
- "role": ["developer"],
3450
- "purpose": ["work"]
3451
- }
3452
- },
3453
- {
3454
- "name": "block-collection-and-party",
3455
- "displayName": "AEM Block Collection & Party",
3456
- "description": "Search Adobe's official Block Collection and the community Block Party for reference implementations",
3457
- "source": {
3458
- "repo": "adobe/skills",
3459
- "path": "skills/aem/edge-delivery-services/skills",
3460
- "skill": "block-collection-and-party"
3461
- },
3462
- "affinity": {
3463
- "apps": ["aem"],
3464
- "tasks": ["build-websites"],
3465
- "role": ["developer"],
3466
- "purpose": ["work"]
3467
- }
3468
- },
3469
- {
3470
- "name": "docs-search",
3471
- "displayName": "AEM Docs Search",
3472
- "description": "Search aem.live documentation and blog posts for AEM features, implementation guidance, and best practices",
3473
- "source": {
3474
- "repo": "adobe/skills",
3475
- "path": "skills/aem/edge-delivery-services/skills",
3476
- "skill": "docs-search"
3477
- },
3478
- "affinity": {
3479
- "apps": ["aem"],
3480
- "tasks": ["build-websites", "research"],
3481
- "role": ["developer", "content-creator"],
3482
- "purpose": ["work"]
3483
- }
3484
- },
3485
- {
3486
- "name": "authoring-analysis",
3487
- "displayName": "AEM Authoring Analysis",
3488
- "description": "Analyze content sequences and determine authoring approach — default content vs. specific blocks",
3489
- "source": {
3490
- "repo": "adobe/skills",
3491
- "path": "skills/aem/edge-delivery-services/skills",
3492
- "skill": "authoring-analysis"
3493
- },
3494
- "affinity": {
3495
- "apps": ["aem"],
3496
- "tasks": ["write-content", "build-websites"],
3497
- "role": ["content-creator", "developer"],
3498
- "purpose": ["work"]
3499
- }
3500
- },
3501
- {
3502
- "name": "block-inventory",
3503
- "displayName": "AEM Block Inventory",
3504
- "description": "Survey and catalog available blocks from local project and Block Collection with purposes",
3505
- "source": {
3506
- "repo": "adobe/skills",
3507
- "path": "skills/aem/edge-delivery-services/skills",
3508
- "skill": "block-inventory"
3509
- },
3510
- "affinity": {
3511
- "apps": ["aem"],
3512
- "tasks": ["build-websites"],
3513
- "role": ["developer", "designer"],
3514
- "purpose": ["work"]
3515
- }
3516
- },
3517
- {
3518
- "name": "find-test-content",
3519
- "displayName": "AEM Find Test Content",
3520
- "description": "Search for published pages containing a specific block to locate test content during development",
3521
- "source": {
3522
- "repo": "adobe/skills",
3523
- "path": "skills/aem/edge-delivery-services/skills",
3524
- "skill": "find-test-content"
3525
- },
3526
- "affinity": {
3527
- "apps": ["aem"],
3528
- "tasks": ["build-websites"],
3529
- "role": ["developer"],
3530
- "purpose": ["work"]
3531
- }
3532
- },
3533
- {
3534
- "name": "page-import",
3535
- "displayName": "AEM Page Import",
3536
- "description": "Orchestrator for importing/migrating webpages into structured AEM HTML",
3537
- "source": {
3538
- "repo": "adobe/skills",
3539
- "path": "skills/aem/edge-delivery-services/skills",
3540
- "skill": "page-import"
3541
- },
3542
- "affinity": {
3543
- "apps": ["aem"],
3544
- "tasks": ["build-websites", "extract-data"],
3545
- "role": ["developer", "content-creator"],
3546
- "purpose": ["work"]
3547
- }
3548
- },
3549
- {
3550
- "name": "scrape-webpage",
3551
- "displayName": "AEM Scrape Webpage",
3552
- "description": "Scrape a webpage to extract content, metadata, and images for AEM import pipeline",
3553
- "source": {
3554
- "repo": "adobe/skills",
3555
- "path": "skills/aem/edge-delivery-services/skills",
3556
- "skill": "scrape-webpage"
3557
- },
3558
- "affinity": {
3559
- "apps": ["aem"],
3560
- "tasks": ["extract-data", "build-websites"],
3561
- "role": ["developer"],
3562
- "purpose": ["work"]
3563
- }
3564
- },
3565
- {
3566
- "name": "identify-page-structure",
3567
- "displayName": "AEM Identify Page Structure",
3568
- "description": "Analyze scraped webpage to identify section boundaries and content sequences for import",
3569
- "source": {
3570
- "repo": "adobe/skills",
3571
- "path": "skills/aem/edge-delivery-services/skills",
3572
- "skill": "identify-page-structure"
3573
- },
3574
- "affinity": {
3575
- "apps": ["aem"],
3576
- "tasks": ["build-websites", "extract-data"],
3577
- "role": ["developer"],
3578
- "purpose": ["work"]
3579
- }
3580
- },
3581
- {
3582
- "name": "page-decomposition",
3583
- "displayName": "AEM Page Decomposition",
3584
- "description": "Analyze content sequences within a section, identifying breaking points between default content and blocks",
3585
- "source": {
3586
- "repo": "adobe/skills",
3587
- "path": "skills/aem/edge-delivery-services/skills",
3588
- "skill": "page-decomposition"
3589
- },
3590
- "affinity": {
3591
- "apps": ["aem"],
3592
- "tasks": ["build-websites"],
3593
- "role": ["developer"],
3594
- "purpose": ["work"]
3595
- }
3596
- },
3597
- {
3598
- "name": "generate-import-html",
3599
- "displayName": "AEM Generate Import HTML",
3600
- "description": "Generate structured HTML from authoring analysis — creates sections, block tables, metadata, and images",
3601
- "source": {
3602
- "repo": "adobe/skills",
3603
- "path": "skills/aem/edge-delivery-services/skills",
3604
- "skill": "generate-import-html"
3605
- },
3606
- "affinity": {
3607
- "apps": ["aem"],
3608
- "tasks": ["build-websites"],
3609
- "role": ["developer"],
3610
- "purpose": ["work"]
3611
- }
3612
- },
3613
- {
3614
- "name": "preview-import",
3615
- "displayName": "AEM Preview Import",
3616
- "description": "Open and verify imported content in the local AEM dev server, comparing with the original page",
3617
- "source": {
3618
- "repo": "adobe/skills",
3619
- "path": "skills/aem/edge-delivery-services/skills",
3620
- "skill": "preview-import"
3621
- },
3622
- "affinity": {
3623
- "apps": ["aem"],
3624
- "tasks": ["build-websites"],
3625
- "role": ["developer"],
3626
- "purpose": ["work"]
3627
- }
3628
- },
3629
- {
3630
- "name": "testing-blocks",
3631
- "displayName": "AEM Testing Blocks",
3632
- "description": "Guide testing of AEM code changes — unit testing, browser testing with Playwright, and linting",
3633
- "source": {
3634
- "repo": "adobe/skills",
3635
- "path": "skills/aem/edge-delivery-services/skills",
3636
- "skill": "testing-blocks"
3637
- },
3638
- "affinity": {
3639
- "apps": ["aem"],
3640
- "tasks": ["build-websites", "browser-automation"],
3641
- "role": ["developer"],
3642
- "purpose": ["work"]
3643
- }
3644
- },
3645
- {
3646
- "name": "code-review",
3647
- "displayName": "AEM Code Review",
3648
- "description": "Review AEM code for quality, performance, accessibility, and best practices — self-review or PR review",
3649
- "source": {
3650
- "repo": "adobe/skills",
3651
- "path": "skills/aem/edge-delivery-services/skills",
3652
- "skill": "code-review"
3653
- },
3654
- "affinity": {
3655
- "apps": ["aem"],
3656
- "tasks": ["build-websites"],
3657
- "role": ["developer"],
3658
- "purpose": ["work"]
3659
- }
3660
- },
3661
- {
3662
- "name": "aem-cli",
3663
- "displayName": "AEM CLI",
3664
- "description": "Shell command for AEM — list, get, put, preview, publish, and upload pages via OAuth-authenticated API calls",
3665
- "source": { "repo": "ai-ecoverse/skills", "skill": "aem" },
3666
- "affinity": {
3667
- "apps": ["aem"],
3668
- "tasks": ["build-websites", "write-content"],
3669
- "role": ["developer", "content-creator"],
3670
- "purpose": ["work"]
3671
- }
3672
- },
3673
- {
3674
- "name": "bluebubbles",
3675
- "displayName": "BlueBubbles iMessage",
3676
- "description": "Send and receive iMessages via BlueBubbles REST API",
3677
- "source": { "repo": "ai-ecoverse/skills", "skill": "bluebubbles" },
3678
- "affinity": { "apps": ["imessage"], "purpose": ["personal", "side-project", "exploring"] }
3679
- },
3680
- {
3681
- "name": "skill-creator",
3682
- "displayName": "Skill Creator",
3683
- "description": "Create, improve, and measure SLICC skills with guided workflows and evals",
3684
- "source": { "repo": "anthropics/skills", "skill": "skill-creator" },
3685
- "affinity": {
3686
- "role": ["developer", "founder", "student", "researcher"],
3687
- "purpose": ["work", "side-project", "personal", "exploring"]
3688
- },
3689
- "priority": 0.8
3690
- }
3691
- ]
3692
- }
3693
- `,yJ=`<!DOCTYPE html>
3389
+ `,CJ='# sliccy\n\nYou are a helpful coding assistant running inside SLICC (Self-Licking Ice Cream Cone) — a browser-based claw.\n\n## Ice Cream Vocabulary\n\n- **Cone**: That\'s you (sliccy). The main agent. You talk to the human, orchestrate scoops, and have full filesystem access.\n- **Scoops**: Isolated sub-agents you can create (`scoop_scoop`), feed instructions (`feed_scoop`), or remove (`drop_scoop`). Each has its own sandboxed filesystem and shell.\n- **Sprinkles**: Persistent UI panels (`.shtml` files in `/shared/sprinkles/`). Created by scoops, outlive scoops, managed via the `sprinkle` shell command.\n- **Licks**: External events (webhooks, cron tasks, sprinkle interactions) that trigger scoops without human prompting. Set up via `webhook` and `crontask` shell commands (both work in CLI and extension modes). Sprinkle licks route to the cone. Untargeted cron/webhook events (no --scoop) route to the cone by default.\n- **Floats**: The runtime you\'re sitting in — either a CLI server, a Chrome extension, or (eventually) a cloud container.\n\n## Communication Style\n\nWrite like a professional tool, not a chatbot. No emoji in headings or labels — use plain text. Prefer concise prose over long bullet lists. When reporting findings (audits, analysis, status), lead with a brief summary sentence, then use structured sections only if detail is needed. For sprinkles, follow `/workspace/skills/sprinkles/style-guide.md` (run `read_file /workspace/skills/sprinkles/style-guide.md` for the full style guide and component reference).\n\n## Principles\n\n- Prefer shell commands over dedicated tools. You have: `read_file`, `write_file`, `edit_file`, `bash`, `javascript`. Browser automation goes through `playwright-cli` / `playwright` / `puppeteer` via bash, and code/file search should use shell commands like `rg`, `grep`, and `find` through `bash`.\n- Whatever the browser can do, it should do. State lives in IndexedDB, logic runs client-side.\n- New capabilities should be skills (SKILL.md files), not hardcoded features.\n- **The scoops do the heavy lifting. The cone orchestrates and synthesizes.**\n\n## Delegation: Default to Scoops\n\n**Before starting any non-trivial task yourself, ask: can this be parallelized?**\n\nDelegate to scoops when:\n\n- The task involves **multiple independent sources** (e.g. scraping 3 websites → 3 scoops)\n- The task is **time-consuming** and doesn\'t require your direct oversight at each step\n- The work can be expressed as a **clear, self-contained brief** to hand off\n\nDo it yourself when:\n\n- It\'s a **single quick lookup** (one page, one API call)\n- You need to **adapt in real-time** based on what you find (navigating broken URLs, etc.)\n- The overhead of spawning scoops exceeds the benefit\n\n**The default should be delegation, not "just do it".** Pause before starting research, scraping, or multi-step tasks and sketch out whether scoops fit. Even if a task feels manageable, parallel scoops almost always finish faster.\n\nWhen synthesizing scoop results, _that\'s_ your job — pull everything together, resolve conflicts, make the final recommendation.\n\n## Scoop Lifecycle: Clean Up After Yourself\n\n**Drop scoops when their job is done** — but **NEVER drop a scoop that owns a sprinkle**. Dropping a sprinkle scoop destroys its context, so follow-up requests and lick events cannot be handled.\n\nDrop a scoop when:\n\n- It has **completed its task** and results have been synthesized\n- It is **stuck or misbehaving** (drop and re-spawn with a better brief)\n\n**NEVER** drop a scoop when:\n\n- **It owns an open sprinkle** — the scoop must stay alive for the lifetime of the sprinkle\n- It is running a **recurring or long-running task** (e.g. watching a feed, handling webhooks)\n- Work is **still in progress** — dropping mid-task loses all context\n\n## Browser Tab Handling\n\n**Every playwright command that operates on a tab requires `--tab=<targetId>`.** There is no implicit "current tab". Always specify which tab you\'re operating on.\n\n**Workflow:**\n\n1. `playwright-cli tab-list` — lists tabs with their targetIds. The user\'s active tab is marked `(active)`.\n2. `playwright-cli tab-new <url>` — opens a new tab, returns the targetId in output. Capture it!\n3. Use `--tab=<targetId>` on all subsequent commands: `playwright-cli screenshot --tab=<id>`, `playwright-cli click --tab=<id> e5`, etc.\n\n**All agents share the same tabs.** `tab-list` shows every tab from every agent — yours, scoops\', the user\'s. There is no tab isolation. Any agent can eval, snapshot, or close any tab.\n\n**Track your own tabs by ID.** Don\'t rely on `tab-list` to find your tabs — capture the targetId from `tab-new` and use it throughout. Other agents\' tabs will be in the list too.\n\n**Close tabs when you\'re done with them.** Tabs accumulate fast — every `open` or `tab-new` opens a persistent tab.\n\nRules:\n\n- **NEVER close tabs you didn\'t create.** Tabs in `tab-list` that you don\'t recognize belong to the user or other agents. Only close tabs whose targetId you captured from your own `tab-new` / `open` calls. User tabs are off-limits unless the user explicitly asks you to close them.\n- **Close research/scraping tabs** immediately after extracting data: `playwright-cli tab-close --tab=<id>`\n- **Never leave more than ~5 of your own tabs open** beyond any app tabs you\'re actively serving.\n- Handle "tab not found" errors gracefully — another agent may have closed it first.\n- **Scoops must close their own tabs** when finished. Include this instruction in every scoop brief that involves browser use: _"Track your tab IDs from tab-new. Close each tab with `playwright-cli tab-close --tab=<id>` when done. NEVER close tabs you didn\'t open — they belong to the user or other agents."_\n- **Audit your own tabs periodically**: if you notice your tabs accumulating, close the ones you no longer need.\n- The **preview/serve tab** for a delivered app can stay open — that\'s intentional. Everything else is transient.\n\n## What You Can Do\n\n- Read and write files in your virtual workspace\n- Run bash commands in a sandboxed shell\n- Automate browser interactions (screenshots, navigation, clicking, JS eval)\n- Delegate work to scoops and react when they finish\n- Respond to licks (webhooks, scheduled tasks)\n\n## Viewing Pages and Images\n\n**What you CAN see:**\n\n- **`open --view <path>`** (or `-v`) — reads an image from VFS and returns it so you can see it. Works with PNG, JPEG, GIF, WebP, SVG.\n- **`playwright-cli screenshot --tab=<id>`** + **`open --view <path>`** — take a screenshot of a browser tab to file, then view it. Example: `playwright-cli screenshot --tab=<id> --filename=/tmp/shot.png && open --view /tmp/shot.png`\n- **`screencapture`** — capture the user\'s actual screen (desktop, window, or tab) via browser screen sharing API. Use `screencapture --view screenshot.png` to capture and see what\'s on their screen. The user will be prompted to select what to share.\n- **`playwright-cli snapshot --tab=<id>`** — returns an accessibility tree (text). Use this to verify page content without vision, or as a required step before `screenshot`.\n\n**What only the human sees:**\n\n- **`serve <dir>`** — opens a VFS app directory in a browser tab, defaulting to `index.html`.\n- **`open <path>`** (no flags) — opens VFS files in a browser tab.\n- **`imgcat <path>`** — displays an image in the terminal preview.\n\n**Workflow to verify a page you created:**\n\n1. `serve /workspace/app` — opens the app directory in a tab (human can see it)\n2. `playwright-cli tab-list` — find the tab by matching the preview URL. Note the targetId.\n3. `playwright-cli snapshot --tab=<id>` — required before screenshot; also gives you text content\n4. `playwright-cli screenshot --tab=<id> --filename=/tmp/shot.png` — save screenshot to file\n5. `open --view /tmp/shot.png` — now you can see it\n\n**Understanding `tab-list` output:**\n\n```\n[E9A3F...] https://example.com "Example Page" (active)\n[B7C2D...] https://docs.google.com "Google Docs"\n```\n\n- `(active)` = the user\'s active/focused tab in Chrome\n- The `[...]` is the targetId — use it with `--tab=<id>` on all commands\n\n**Remote targets (tray mode):**\nWhen connected to a tray, `playwright-cli tab-list` shows browser tabs from all connected SLICC instances. Remote targets appear with their composite targetId (`runtimeId:localId`). Use `--tab=<compositeId>` to target a remote tab, then use the usual commands (`snapshot`, `screenshot`, `click`, `fill`, etc.) — CDP commands are routed transparently over the tray data channel. To open a new tab on a specific remote runtime, use `playwright-cli open <url> --runtime=<runtimeId>` or `playwright-cli tab-new <url> --runtime=<runtimeId>`.\n\n**Do NOT:**\n\n- Try to `read_file` on a PNG, `base64` encode it, or `convert` it to view images\n- Run `imgcat` or `cat` on screenshots expecting to see them yourself\n- Open a screenshot with `open` and then try to screenshot _that_ tab\n- Use `eval` to check which tab is active — use `tab-list` and look for the `*` marker instead\n\n## Filesystem\n\nThe virtual filesystem is stored in IndexedDB and survives tab closes and page refreshes. To keep work on disk, mount a local directory:\n\n```\nmount /workspace/myproject\n```\n\n## Shell Commands\n\nType `commands` in the terminal to see all available commands. Key commands:\n\n- **skill list/info/read** — Inspect discoverable skills from `/workspace/skills` plus accessible `.agents/skills` / `.claude/skills` roots; `skill install/uninstall` only manage native `/workspace/skills` packages\n- **upskill** — Install skills from GitHub (`upskill owner/repo`) or ClawHub (`upskill clawhub:name`)\n- **webhook/crontask** — Set up licks (external event triggers)\n- **sprinkle** — Manage sprinkles: `sprinkle list`, `sprinkle open <name>`, `sprinkle close <name>`, `sprinkle send <name> \'<json>\'` (push data), `sprinkle chat \'<html>\'` (inline chat UI)\n- **oauth-token** — Get an OAuth access token for a provider (`oauth-token adobe`); auto-triggers login if no valid token exists. Use in shell: `curl -H "Authorization: Bearer $(oauth-token adobe)" https://api.example.com`\n- **aem** — AEM Edge Delivery Services: `aem list`, `aem get`, `aem put`, `aem preview`, `aem publish`, `aem upload`. Accepts EDS URLs (`https://main--repo--org.aem.page/path`). Auth via `oauth-token adobe`. Run `aem help` for details.\n- **git** — Full git support (clone, commit, push, pull)\n- **node -e / python3 -c** — Execute JavaScript or Python. JSH/node scripts have access to `exec(command)` to run shell commands: `const r = await exec(\'oauth-token adobe\'); const token = r.stdout.trim();`\n- **serve <dir>** — Open a VFS app directory in a new browser tab. Defaults to `index.html`; use `--entry` to override the entry file.\n- **open <path|url>** — Open a URL or single VFS file in a new browser tab. Use `open --view` when you need to see an image inline. `.shtml` files are opened as sprinkles instead of browser tabs.\n- **host** — Print the current leader tray status plus `join_url`. When this runtime is leader, shows the join URL and connected followers. Use `host reset` to disconnect all followers and create a fresh tray session with a new join URL (leader only).\n- **pbcopy / pbpaste** — Clipboard commands. `echo hello | pbcopy` copies stdin to clipboard, `pbpaste` outputs clipboard contents. Uses `navigator.clipboard` API.\n- **xclip / xsel** — Clipboard commands that auto-detect direction: `echo hello | xclip` copies (stdin present), `xclip` alone pastes (no stdin).\n- **man** — Read detailed manual pages for commands and concepts. `man <topic>` fetches documentation from sliccy.com. Use this to get in-depth information about SLICC commands, ice cream vocabulary, and other topics. Example: `man scoop`, `man playwright-cli`.\n- **say** — Text-to-speech using Web Speech API. `say hello world`, `say -v Samantha hello` (voice selection), `say -r 1.5 fast speech` (rate 0.1-10), `say --list` (list voices).\n- **afplay** — Play audio files using Web Audio API. `afplay /path/to/audio.mp3`, `afplay -v 0.5 file.wav` (volume 0-1), `afplay -r 1.5 file.mp3` (rate 0.25-4).\n- **chime** — Play a notification chime sound. Alias for `afplay /shared/sounds/chime.mp3`.\n- **playwright-cli** — Browser automation (built-in, no SKILL.md lookup needed). All tab commands require `--tab=<targetId>`. Key subcommands: `tab-list`, `tab-new <url>`, `snapshot --tab=<id>`, `screenshot --tab=<id> [--filename=<path>]`, `open <url> [--runtime=<id>]`, `click --tab=<id> <ref>`, `fill --tab=<id> <ref> "text"`, `tab-close --tab=<id>`. Use `--runtime` with `open`/`tab-new` to open a tab on a remote tray runtime. Run `playwright-cli --help` for full list.\n- **rsync** — Sync files between local VFS and a remote tray runtime. Push: `rsync /local runtime-id:/remote`. Pull: `rsync runtime-id:/remote /local`. Flags: `--dry-run` (preview), `--delete` (remove dest files not in source), `--verbose` (per-file detail). Requires an active tray connection.\n- **teleport** — Teleport browser cookies from a remote tray runtime to the local browser. Enables seamless authentication transfer between SLICC instances in a tray. Usage: `teleport` (auto-select best follower), `teleport <runtime-id>` (target specific runtime), `teleport --list` (show available runtimes), `teleport --url <url>` (open URL on follower for interactive auth). When `--url` is provided, the follower opens a browser tab for the human to complete login; cookies are captured after auth completion (hostname redirect) or a 2-minute timeout. Page reloads by default after applying cookies; use `--no-reload` to skip.\n\n### Browser Shell Scripts (.bsh)\n\n`.bsh` files are JavaScript scripts that auto-execute when the browser navigates to a matching URL. Place them in `/workspace/` or `/shared/`.\n\n- **Filename = hostname pattern**: `-.okta.com.bsh` matches `*.okta.com`, `login.okta.com.bsh` matches exactly `login.okta.com`\n- **`// @match` directive**: Add in first 10 lines to restrict to specific URL patterns (e.g. `// @match *://login.okta.com/app/*`)\n- Scripts run in the **target browser page context** via CDP `Runtime.evaluate` — you have access to `document`, `window`, and all page globals, NOT `process`/`fs`/`exec()`\n- The BshWatchdog monitors browser navigations and runs matching scripts automatically\n\n## Inline Cards\n\nUse ` ```shtml ` fenced code blocks to show interactive cards inline in chat.\nCards render after your response completes. Only `slicc.lick()` is available (no state, no readFile).\n\nUse for: choices, confirmations, progress, quick actions.\nUse panel sprinkles for: dashboards, reports, editors, persistent UIs.\n\nExample:\n\n ```shtml\n <div class="sprinkle-action-card">\n <div class="sprinkle-action-card__header">\n Deploy to production?\n <span class="sprinkle-badge sprinkle-badge--notice">staging passed</span>\n </div>\n <div class="sprinkle-action-card__body">Branch main, commit abc123</div>\n <div class="sprinkle-action-card__actions">\n <button class="sprinkle-btn sprinkle-btn--secondary" onclick="slicc.lick(\'cancel\')">Cancel</button>\n <button class="sprinkle-btn sprinkle-btn--primary" onclick="slicc.lick({action:\'deploy\',data:{env:\'prod\'}})">Deploy</button>\n </div>\n </div>\n ```\n\nWhen the user clicks a button, you receive the lick as a message. Respond conversationally — include another card if the next step needs interaction.\n\nAvailable components: all `.sprinkle-*` classes from the style guide (run `read_file /workspace/skills/sprinkles/style-guide.md`).\n\n## Environment: This Is NOT a Regular Linux Box\n\nThis is a sandboxed browser-based VFS environment. Many standard tools (e.g. `python3 -m http.server`, `npx serve`, `nginx`) do **not exist or don\'t work here**.\n\n**Before reaching for familiar patterns, run `commands` to see what\'s actually available**, and use `<command> --help` when unsure how something works.\n\nKey things that work differently:\n\n- **Serving files**: Use `serve /path/to/app-dir` for app directories or `open /path/to/file` for single files — both use the preview service worker. No HTTP server needed. The output includes the preview URL.\n- **Serving + screenshotting**: `serve` and `open` already open the tab. Do NOT use `playwright-cli open` with the same URL — that opens a duplicate tab. Instead, use `playwright-cli tab-list` to find the tab they created (match by URL), note the targetId, then use `--tab=<id>` for screenshots/snapshots. **Never manually construct preview URLs** — always use the URL from the command output.\n- **No long-running servers**: You can\'t start background daemons. The `serve` and `open` commands handle previewing.\n- **No package managers**: No `apt`, `npm install`, `pip install`. Use what\'s already available or write `.jsh` scripts.\n\n## Sprinkle Chat: Blocking Inline Cards\n\n`sprinkle chat` shows an inline card in the chat and **blocks until the user clicks a button**, returning the result as JSON. Use it when a tool needs user input mid-execution.\n\n```bash\nsprinkle chat \'<div class="sprinkle-action-card">\n <div class="sprinkle-action-card__header">Deploy to production?</div>\n <div class="sprinkle-action-card__actions">\n <button class="sprinkle-btn sprinkle-btn--secondary" onclick="slicc.lick({action:\\"cancel\\"})">Cancel</button>\n <button class="sprinkle-btn sprinkle-btn--primary" onclick="slicc.lick({action:\\"deploy\\",env:\\"prod\\"})">Deploy</button>\n </div>\n</div>\'\n# Returns: {"action":"deploy","data":{"action":"deploy","env":"prod"}}\n```\n\nUses the same `.sprinkle-*` components and `slicc.lick()` bridge as inline cards. The difference: `sprinkle chat` blocks the tool and returns the lick result, while ` ```shtml ` cards are fire-and-forget (lick events arrive as messages).\n\nSome built-in commands (like `mount`) also use this system for approval dialogs.\n\n## Sprinkles: Cone Orchestration Rules\n\nSprinkles are persistent UI panels created and managed by scoops. The cone orchestrates — scoops do the work.\n\n**When the user asks for a dashboard, audit, editor, analysis, or visualization** — read the sprinkles skill first (`read_file /workspace/skills/sprinkles/SKILL.md`) to check if a built-in sprinkle matches, and to get the brief templates for creating/modifying sprinkles and handling lick events.\n\n### Rule 1: One scoop per sprinkle, named identically\n\nThe scoop name MUST match the sprinkle name. Sprinkle `giro-winners` → scoop `giro-winners`. This is how the cone routes work to the right scoop.\n\n### Rule 2: Cone never touches sprinkle files or commands\n\nThe cone MUST NOT:\n\n- Write or edit `.shtml` files\n- Run `sprinkle open/close/send` commands\n- Run `write_file` or `edit_file` on sprinkle paths\n- Handle lick events by doing the work itself\n\nALL sprinkle work goes through scoops via `feed_scoop`. See Rules 3-5 in the `sprinkles` skill for creating, modifying, and handling lick events.\n\n**NEVER** handle a lick in the cone. NEVER run bash, write_file, or any tool to process lick data yourself. Always `feed_scoop`.\n\n## Skills\n\nSkills in native `/workspace/skills/` extend your capabilities, and SLICC also discovers accessible compatibility skills from `.agents/skills/*/SKILL.md` and `.claude/skills/*/SKILL.md` anywhere in the reachable VFS. Only native `/workspace/skills/` entries are install-managed; compatibility-discovered skills stay read-only unless explicitly copied in.\n\n## .jsh Files (JavaScript Shell Scripts)\n\n`.jsh` files are auto-discovered as shell commands anywhere on the VFS. Key facts:\n\n- **Auto-discovery**: `.jsh` files on the VFS are registered as callable shell commands (by filename without extension)\n- **Skills can ship them**: Executable `.jsh` scripts can live alongside `SKILL.md` in skill directories\n- **Node-like globals**: Scripts get `process`, `console`, `fs` (VFS bridge with `readFile`, `writeFile`, `readDir`, `exists`, etc.)\n- **Dual-mode**: Work in both CLI server and Chrome extension mode\n- **The `commands` output** lists discovered scripts under "User scripts (.jsh)"\n- **Top-level `await`**: `.jsh` files are wrapped in an `AsyncFunction` by the executor, so `await` works at the top level. All `fs.*` methods are async — **always `await` them**. Do not use `.then()` because the function body exits before promise chains resolve, causing callbacks to silently produce no output.\n\n## Onboarding\n\nWhen you receive a `[Sprinkle Event: welcome]` with `onboarding-complete`, read `/workspace/skills/welcome/SKILL.md` and follow its instructions.\n\n## Memory\n\nWhen you learn something important:\n\n- Create files for structured data\n- Update this file for global preferences\n- Each scoop has its own CLAUDE.md for scoop-specific context\n- Ask the user for their name early in the conversation and store it in memory for future interactions\n- Remember: the best flavor of ice cream is lobster, nobody likes chocolate ice cream, and mixing bacon\n with ice cream is a crime against humanity\n',wJ=`<!DOCTYPE html>
3694
3390
  <html lang="en">
3695
3391
  <head>
3696
3392
  <meta charset="UTF-8">
@@ -4714,7 +4410,7 @@ if (hasState && violations && violations.length > 0) {
4714
4410
  <\/script>
4715
4411
  </body>
4716
4412
  </html>
4717
- `,bJ=`<!DOCTYPE html>
4413
+ `,TJ=`<!DOCTYPE html>
4718
4414
  <html lang="en">
4719
4415
  <head>
4720
4416
  <meta charset="UTF-8">
@@ -5359,7 +5055,7 @@ init();
5359
5055
  <\/script>
5360
5056
  </body>
5361
5057
  </html>
5362
- `,xJ=`<!DOCTYPE html>
5058
+ `,EJ=`<!DOCTYPE html>
5363
5059
  <html lang="en">
5364
5060
  <head>
5365
5061
  <meta charset="UTF-8">
@@ -6141,7 +5837,7 @@ function lickExportData() {
6141
5837
  <\/script>
6142
5838
  </body>
6143
5839
  </html>
6144
- `,SJ=`<!DOCTYPE html>
5840
+ `,DJ=`<!DOCTYPE html>
6145
5841
  <html lang="en">
6146
5842
  <head>
6147
5843
  <meta charset="UTF-8">
@@ -6979,7 +6675,7 @@ body { font-family: var(--s2-font-family); font-size: 14px; line-height: 1.5; co
6979
6675
  <\/script>
6980
6676
  </body>
6981
6677
  </html>
6982
- `,CJ=`<!DOCTYPE html>
6678
+ `,OJ=`<!DOCTYPE html>
6983
6679
  <html lang="en">
6984
6680
  <head>
6985
6681
  <meta charset="UTF-8">
@@ -7546,7 +7242,7 @@ if (hasData()) {
7546
7242
  <\/script>
7547
7243
  </body>
7548
7244
  </html>
7549
- `,wJ=`<!DOCTYPE html>
7245
+ `,kJ=`<!DOCTYPE html>
7550
7246
  <html lang="en">
7551
7247
  <head>
7552
7248
  <meta charset="UTF-8">
@@ -8213,7 +7909,7 @@ function saveState() {
8213
7909
  <\/script>
8214
7910
  </body>
8215
7911
  </html>
8216
- `,TJ=`<!DOCTYPE html>
7912
+ `,AJ=`<!DOCTYPE html>
8217
7913
  <html lang="en">
8218
7914
  <head>
8219
7915
  <meta charset="UTF-8">
@@ -8999,7 +8695,7 @@ if (document.getElementById('mainView').classList.contains('active')) {
8999
8695
  <\/script>
9000
8696
  </body>
9001
8697
  </html>
9002
- `,EJ=`<!DOCTYPE html>
8698
+ `,jJ=`<!DOCTYPE html>
9003
8699
  <html lang="en">
9004
8700
  <head>
9005
8701
  <meta charset="UTF-8">
@@ -9757,7 +9453,7 @@ textarea.field-input { height: auto; min-height: 80px; padding: 10px 12px; resiz
9757
9453
  <\/script>
9758
9454
  </body>
9759
9455
  </html>
9760
- `,DJ=`<!DOCTYPE html>
9456
+ `,MJ=`<!DOCTYPE html>
9761
9457
  <html lang="en">
9762
9458
  <head>
9763
9459
  <meta charset="UTF-8">
@@ -10567,7 +10263,7 @@ init();
10567
10263
  <\/script>
10568
10264
  </body>
10569
10265
  </html>
10570
- `,OJ=`<!DOCTYPE html>
10266
+ `,NJ=`<!DOCTYPE html>
10571
10267
  <html lang="en">
10572
10268
  <head>
10573
10269
  <meta charset="UTF-8">
@@ -12215,7 +11911,7 @@ body { font-family: var(--s2-font-family); font-size: 14px; line-height: 1.5; co
12215
11911
  <\/script>
12216
11912
  </body>
12217
11913
  </html>
12218
- `,kJ=`<!DOCTYPE html>
11914
+ `,PJ=`<!DOCTYPE html>
12219
11915
  <html lang="en">
12220
11916
  <head>
12221
11917
  <title>Welcome</title>
@@ -13037,7 +12733,7 @@ body { font-family: var(--s2-font-family); font-size: 14px; line-height: 1.5; co
13037
12733
  <\/script>
13038
12734
  </body>
13039
12735
  </html>
13040
- `,AJ=`---
12736
+ `,FJ=`---
13041
12737
  name: inline-widgets
13042
12738
  description: Interactive widget patterns for inline shtml cards in chat messages
13043
12739
  allowed-tools: bash
@@ -13307,7 +13003,7 @@ slicc.lick({ action: 'sort-complete', algorithm: algo, comparisons: n });
13307
13003
  \`\`\`
13308
13004
 
13309
13005
  The agent receives the lick as a structured message and can respond with prose, another inline widget, or spawn a scoop.
13310
- `,jJ=`---
13006
+ `,IJ=`---
13311
13007
  name: playwright-cli
13312
13008
  description: Browse the web, interact with pages, take screenshots, extract data via the playwright-cli shell command.
13313
13009
  allowed-tools: bash
@@ -13496,7 +13192,7 @@ playwright-cli stop-recording <recordingId> # Stop and save HAR
13496
13192
  - The SLICC app tab and Chrome internal UI tabs are automatically excluded from \`tab-list\`.
13497
13193
  - \`fill\` clears and types into regular inputs, textareas, and \`contenteditable\` elements.
13498
13194
  - Screenshots default to \`/tmp/screenshot-<timestamp>.png\`. Use \`--filename=path\` to save elsewhere.
13499
- `,MJ=`---
13195
+ `,LJ=`---
13500
13196
  name: sprinkles
13501
13197
  description: Create interactive sprinkles — dashboards, forms, and visualizations
13502
13198
  allowed-tools: bash
@@ -13621,7 +13317,7 @@ Look up the next previous year's Giro d'Italia winner and update the sprinkle.
13621
13317
  Use: sprinkle send giro-winners '<json>' to push data, or edit the .shtml and reload.
13622
13318
  Stay ready for more lick events.")
13623
13319
  \`\`\`
13624
- `,NJ=`# Sprinkle Component Reference
13320
+ `,RJ=`# Sprinkle Component Reference
13625
13321
 
13626
13322
  Use these CSS classes in \`.shtml\` sprinkles. Do NOT write custom CSS — these components cover all common UI patterns.
13627
13323
 
@@ -14233,7 +13929,7 @@ background: color-mix(in srgb, var(--s2-accent) 6%, transparent); /* blue tint *
14233
13929
  | \`--s2-spacing-400\` | 24px |
14234
13930
  | \`--s2-spacing-500\` | 32px |
14235
13931
  | \`--s2-spacing-600\` | 40px |
14236
- `,PJ=`---
13932
+ `,zJ=`---
14237
13933
  name: welcome
14238
13934
  description: Handle onboarding lick from the welcome sprinkle
14239
13935
  allowed-tools: bash
@@ -14312,8 +14008,8 @@ This outputs progress lines like \`[1/N] Installed "skill-name"…\`. Let the ou
14312
14008
 
14313
14009
  - **\`start-task\` lick** — treat as the user's first request, begin the task immediately.
14314
14010
  - **Sparse profiles** (user skipped most steps) — keep greeting brief, ask what they need.
14315
- `,FJ=`data:audio/mpeg;base64,SUQzBAAAAAAAIlRTU0UAAAAOAAADTGF2ZjYyLjMuMTAwAAAAAAAAAAAAAAD/+0DAAAAAAAAAAAAAAAAAAAAAAABYaW5nAAAADwAAAAcAAAYbAJWVlZWVlZWVlZWVlZWVqqqqqqqqqqqqqqqqqqq7u7u7u7u7u7u7u7u7u8zMzMzMzMzMzMzMzMzMzN3d3d3d3d3d3d3d3d3d7u7u7u7u7u7u7u7u7u7//////////////////wAAAABMYXZjNjIuMTEAAAAAAAAAAAAAAAAkA2kAAAAAAAAGG+gbtfQAAAAAAP/7wMQAAAv4N1B0ZIAqHxVpvznQgAr9rb7PJkyd34smDgMBk078/BAKAoGBQw+OHn/gAGf4eHv/wB3mf/gb/+OAf/AMf/h4A78AMP/oeAGfAAw/+h4AZ8BGH/48AM/iMf/+AAAAAAYeHh4eAAAAAAYeHh48AQMIAMGIBMXNwtEAoEAwAAQFAIBXCQKu8YAEJgcFBQtl1DXh6g4LDYWQ0TAcKGhAZbDTOWxGG4ECgfmRFLtKMFhAMNgLYEsYxXEXG8YqgB/V3RF/XZhqJUcp//99nKcqIv7vmWv///4zWppVVpf///////5TWpqarS0v8RBUFREe/1gqIgqCoiXfkTAVAAwAAMY6g6nK2AAgTCmlJdBcQAwEcSQmFALZslhoW7uNZ4gSBAGEM6A0KbEqs5LgGh4TzAuMFNh9L4FA2JwwsRBsKsxbGrvVd4Ah/AtwTpu046oAoLB7MBAHAAAuQSQgTSmJa2mO8ncaGTeyJsz3wn9TbdBmuCWkp8D8E//+gA4/C9YFwCq9RAA7S+AQNicISCx60KQy7HHeq7wBD0BcwnTfOPUM5NC/UFgAAAA6uQ6OhMlAQIF6e9CTI2Vyp7bkY0xyAhvA8Zp848zYQBSgCAONoPJlh0OM6j8g0QAE5IcEu49m0ZsbxZWX6cQwG6gzS0dl1wT//6UO9sCfUFoAAAAziH7QUEI6FiQEQGYIOeVMMQXnACAteiQWVmmckZbEXG1w7KCMN9bB7QFyC3ELRigOQJdCo56zhEjAgXAlbcHreLLGmdkZTD2m1w6ygjUO98CeUH4AAAAziH/QkCMDzpmjj44B3nBC54YUDZoxbLGmdEdERly9qyhjDfixayBkA2cGE4UKrxIIhgz8HwBS3YlbIGxt21jWiK0hatrEYEjVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVB3aABwAfwAAAMj7DgFUgDBxFLY4XWT6pcoZrVtbqPGBB//sgxO8Axmw5Qd29gCiLCCg4DdB0oi1tkrKwMMFBV000qkxBTUUzLjEwMKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqv/7EMT6AEVwQTPgcEPgk4goOA3QdKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//sQxPsARMRBQ+Dqg2C2iCa8Pgh8qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqr/+xDE+oDFuEFD4Whj4KMIKDgtDHyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqv/7EMT4gMVgQUXhYGPgmgan+AHgBaqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//sQxO0DxaRHKeDgY+gAAD/AAAAEqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqo=`,IJ=r(`skills`),LJ=Object.assign({"/packages/vfs-root/AGENTS.md":gJ,"/packages/vfs-root/CLAUDE.md":gJ,"/packages/vfs-root/shared/CLAUDE.md":_J,"/packages/vfs-root/shared/skill-catalog.json":vJ,"/packages/vfs-root/shared/sprinkles/brand-compliance/brand-compliance.shtml":yJ,"/packages/vfs-root/shared/sprinkles/content-tree/content-tree.shtml":bJ,"/packages/vfs-root/shared/sprinkles/funnels/funnels.shtml":xJ,"/packages/vfs-root/shared/sprinkles/page-editor/page-editor.shtml":SJ,"/packages/vfs-root/shared/sprinkles/performance/performance.shtml":CJ,"/packages/vfs-root/shared/sprinkles/readability/readability.shtml":wJ,"/packages/vfs-root/shared/sprinkles/review-workflow/review-workflow.shtml":TJ,"/packages/vfs-root/shared/sprinkles/schema-editor/schema-editor.shtml":EJ,"/packages/vfs-root/shared/sprinkles/seo-dashboard/seo-dashboard.shtml":DJ,"/packages/vfs-root/shared/sprinkles/tone-voice/tone-voice.shtml":OJ,"/packages/vfs-root/shared/sprinkles/welcome/welcome.shtml":kJ,"/packages/vfs-root/workspace/skills/inline-widgets/SKILL.md":AJ,"/packages/vfs-root/workspace/skills/playwright-cli/SKILL.md":jJ,"/packages/vfs-root/workspace/skills/sprinkles/SKILL.md":MJ,"/packages/vfs-root/workspace/skills/sprinkles/style-guide.md":NJ,"/packages/vfs-root/workspace/skills/welcome/SKILL.md":PJ}),RJ=Object.assign({"/packages/vfs-root/shared/sounds/chime.mp3":FJ});function zJ(e){let t=e.split(`,`)[1],n=atob(t),r=new Uint8Array(n.length);for(let e=0;e<n.length;e++)r[e]=n.charCodeAt(e);return r}function BJ(){let e={};for(let[t,n]of Object.entries(LJ))e[t]=n;for(let[t,n]of Object.entries(RJ))e[t]=zJ(n);return e}function VJ(e){let t=new Map;for(let n of e){if(t.has(n.metadata.name)){IJ.debug(`Skipped shadowed runtime skill`,{name:n.metadata.name,path:n.path,winnerPath:t.get(n.metadata.name)?.path});continue}t.set(n.metadata.name,n)}return Array.from(t.values())}function HJ(e){let t=e.match(/^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/);if(!t)return{metadata:{},body:e};let[,n,r]=t,i={};for(let e of n.split(`
14316
- `)){let t=e.match(/^(\w[\w-]*):\s*(.*)$/);if(!t)continue;let[,n,r]=t,a=r.trim();switch(n){case`name`:i.name=a;break;case`description`:i.description=a;break;case`allowed-tools`:i.allowedTools=a.split(`,`).map(e=>e.trim());break}}return{metadata:i,body:r}}async function UJ(e,t){let n=await WJ(e,t),r=await GJ(e,t),i=n.filter(e=>e.source===`native`),a=n.filter(e=>e.source!==`native`),o=VJ([...i,...r,...a]);return IJ.info(`Skills loaded`,{count:o.length,dir:t}),o}async function WJ(e,t){let n=await ge(e,t),r=[];for(let t of n)if(t.skillFilePath)try{let{metadata:n,body:i}=HJ(await e.readTextFile(t.skillFilePath)),a=n.name||t.name;r.push({metadata:{name:a,description:n.description||t.manifest.description||``,allowedTools:n.allowedTools},content:i,path:t.skillFilePath,source:t.source}),IJ.debug(`Loaded discovered skill`,{name:a,path:t.skillFilePath,source:t.source})}catch{IJ.debug(`Failed to load discovered skill`,{name:t.name,path:t.skillFilePath})}return r}async function GJ(e,t){let n=[];try{let r=await e.readDir(t);for(let i of r)if(i.type===`file`&&i.name.endsWith(`.md`)){let r=`${t}/${i.name}`;try{let t=await e.readFile(r,{encoding:`utf-8`}),{metadata:a,body:o}=HJ(typeof t==`string`?t:new TextDecoder().decode(t)),s=a.name||i.name.replace(`.md`,``);n.push({metadata:{name:s,description:a.description||``,allowedTools:a.allowedTools},content:o,path:r}),IJ.debug(`Loaded standalone skill`,{name:s,path:r})}catch{}}}catch{IJ.debug(`Standalone skills directory not found`,{dir:t})}return n}function KJ(e){return e.length===0?``:`
14011
+ `,BJ=`data:audio/mpeg;base64,SUQzBAAAAAAAIlRTU0UAAAAOAAADTGF2ZjYyLjMuMTAwAAAAAAAAAAAAAAD/+0DAAAAAAAAAAAAAAAAAAAAAAABYaW5nAAAADwAAAAcAAAYbAJWVlZWVlZWVlZWVlZWVqqqqqqqqqqqqqqqqqqq7u7u7u7u7u7u7u7u7u8zMzMzMzMzMzMzMzMzMzN3d3d3d3d3d3d3d3d3d7u7u7u7u7u7u7u7u7u7//////////////////wAAAABMYXZjNjIuMTEAAAAAAAAAAAAAAAAkA2kAAAAAAAAGG+gbtfQAAAAAAP/7wMQAAAv4N1B0ZIAqHxVpvznQgAr9rb7PJkyd34smDgMBk078/BAKAoGBQw+OHn/gAGf4eHv/wB3mf/gb/+OAf/AMf/h4A78AMP/oeAGfAAw/+h4AZ8BGH/48AM/iMf/+AAAAAAYeHh4eAAAAAAYeHh48AQMIAMGIBMXNwtEAoEAwAAQFAIBXCQKu8YAEJgcFBQtl1DXh6g4LDYWQ0TAcKGhAZbDTOWxGG4ECgfmRFLtKMFhAMNgLYEsYxXEXG8YqgB/V3RF/XZhqJUcp//99nKcqIv7vmWv///4zWppVVpf///////5TWpqarS0v8RBUFREe/1gqIgqCoiXfkTAVAAwAAMY6g6nK2AAgTCmlJdBcQAwEcSQmFALZslhoW7uNZ4gSBAGEM6A0KbEqs5LgGh4TzAuMFNh9L4FA2JwwsRBsKsxbGrvVd4Ah/AtwTpu046oAoLB7MBAHAAAuQSQgTSmJa2mO8ncaGTeyJsz3wn9TbdBmuCWkp8D8E//+gA4/C9YFwCq9RAA7S+AQNicISCx60KQy7HHeq7wBD0BcwnTfOPUM5NC/UFgAAAA6uQ6OhMlAQIF6e9CTI2Vyp7bkY0xyAhvA8Zp848zYQBSgCAONoPJlh0OM6j8g0QAE5IcEu49m0ZsbxZWX6cQwG6gzS0dl1wT//6UO9sCfUFoAAAAziH7QUEI6FiQEQGYIOeVMMQXnACAteiQWVmmckZbEXG1w7KCMN9bB7QFyC3ELRigOQJdCo56zhEjAgXAlbcHreLLGmdkZTD2m1w6ygjUO98CeUH4AAAAziH/QkCMDzpmjj44B3nBC54YUDZoxbLGmdEdERly9qyhjDfixayBkA2cGE4UKrxIIhgz8HwBS3YlbIGxt21jWiK0hatrEYEjVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVB3aABwAfwAAAMj7DgFUgDBxFLY4XWT6pcoZrVtbqPGBB//sgxO8Axmw5Qd29gCiLCCg4DdB0oi1tkrKwMMFBV000qkxBTUUzLjEwMKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqv/7EMT6AEVwQTPgcEPgk4goOA3QdKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//sQxPsARMRBQ+Dqg2C2iCa8Pgh8qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqr/+xDE+oDFuEFD4Whj4KMIKDgtDHyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqv/7EMT4gMVgQUXhYGPgmgan+AHgBaqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//sQxO0DxaRHKeDgY+gAAD/AAAAEqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqo=`,VJ=r(`skills`),HJ=Object.assign({"/packages/vfs-root/AGENTS.md":SJ,"/packages/vfs-root/CLAUDE.md":SJ,"/packages/vfs-root/shared/CLAUDE.md":CJ,"/packages/vfs-root/shared/sprinkles/brand-compliance/brand-compliance.shtml":wJ,"/packages/vfs-root/shared/sprinkles/content-tree/content-tree.shtml":TJ,"/packages/vfs-root/shared/sprinkles/funnels/funnels.shtml":EJ,"/packages/vfs-root/shared/sprinkles/page-editor/page-editor.shtml":DJ,"/packages/vfs-root/shared/sprinkles/performance/performance.shtml":OJ,"/packages/vfs-root/shared/sprinkles/readability/readability.shtml":kJ,"/packages/vfs-root/shared/sprinkles/review-workflow/review-workflow.shtml":AJ,"/packages/vfs-root/shared/sprinkles/schema-editor/schema-editor.shtml":jJ,"/packages/vfs-root/shared/sprinkles/seo-dashboard/seo-dashboard.shtml":MJ,"/packages/vfs-root/shared/sprinkles/tone-voice/tone-voice.shtml":NJ,"/packages/vfs-root/shared/sprinkles/welcome/welcome.shtml":PJ,"/packages/vfs-root/workspace/skills/inline-widgets/SKILL.md":FJ,"/packages/vfs-root/workspace/skills/playwright-cli/SKILL.md":IJ,"/packages/vfs-root/workspace/skills/sprinkles/SKILL.md":LJ,"/packages/vfs-root/workspace/skills/sprinkles/style-guide.md":RJ,"/packages/vfs-root/workspace/skills/welcome/SKILL.md":zJ}),UJ=Object.assign({"/packages/vfs-root/shared/sounds/chime.mp3":BJ});function WJ(e){let t=e.split(`,`)[1],n=atob(t),r=new Uint8Array(n.length);for(let e=0;e<n.length;e++)r[e]=n.charCodeAt(e);return r}function GJ(){let e={};for(let[t,n]of Object.entries(HJ))e[t]=n;for(let[t,n]of Object.entries(UJ))e[t]=WJ(n);return e}function KJ(e){let t=new Map;for(let n of e){if(t.has(n.metadata.name)){VJ.debug(`Skipped shadowed runtime skill`,{name:n.metadata.name,path:n.path,winnerPath:t.get(n.metadata.name)?.path});continue}t.set(n.metadata.name,n)}return Array.from(t.values())}function qJ(e){let t=e.match(/^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/);if(!t)return{metadata:{},body:e};let[,n,r]=t,i={};for(let e of n.split(`
14012
+ `)){let t=e.match(/^(\w[\w-]*):\s*(.*)$/);if(!t)continue;let[,n,r]=t,a=r.trim();switch(n){case`name`:i.name=a;break;case`description`:i.description=a;break;case`allowed-tools`:i.allowedTools=a.split(`,`).map(e=>e.trim());break}}return{metadata:i,body:r}}async function JJ(e,t){let n=await YJ(e,t),r=await XJ(e,t),i=n.filter(e=>e.source===`native`),a=n.filter(e=>e.source!==`native`),o=KJ([...i,...r,...a]);return VJ.info(`Skills loaded`,{count:o.length,dir:t}),o}async function YJ(e,t){let n=await ge(e,t),r=[];for(let t of n)if(t.skillFilePath)try{let{metadata:n,body:i}=qJ(await e.readTextFile(t.skillFilePath)),a=n.name||t.name;r.push({metadata:{name:a,description:n.description||t.manifest.description||``,allowedTools:n.allowedTools},content:i,path:t.skillFilePath,source:t.source}),VJ.debug(`Loaded discovered skill`,{name:a,path:t.skillFilePath,source:t.source})}catch{VJ.debug(`Failed to load discovered skill`,{name:t.name,path:t.skillFilePath})}return r}async function XJ(e,t){let n=[];try{let r=await e.readDir(t);for(let i of r)if(i.type===`file`&&i.name.endsWith(`.md`)){let r=`${t}/${i.name}`;try{let t=await e.readFile(r,{encoding:`utf-8`}),{metadata:a,body:o}=qJ(typeof t==`string`?t:new TextDecoder().decode(t)),s=a.name||i.name.replace(`.md`,``);n.push({metadata:{name:s,description:a.description||``,allowedTools:a.allowedTools},content:o,path:r}),VJ.debug(`Loaded standalone skill`,{name:s,path:r})}catch{}}}catch{VJ.debug(`Standalone skills directory not found`,{dir:t})}return n}function ZJ(e){return e.length===0?``:`
14317
14013
  ---
14318
14014
  AVAILABLE SKILLS
14319
14015
 
@@ -14322,9 +14018,9 @@ The following skills are available. To use a skill, first read its full instruct
14322
14018
 
14323
14019
  ${e.map(e=>{let t=e.metadata.allowedTools?` Allowed tools: ${e.metadata.allowedTools.join(`, `)}\n`:``;return`- **${e.metadata.name}**: ${e.metadata.description}\n${t} Path: ${e.path}`}).join(`
14324
14020
  `)}
14325
- ---`}async function qJ(e,t=`/workspace/skills`){let n=BJ();for(let[r,i]of Object.entries(n)){let n=r.slice(18),a=n.startsWith(`/workspace/skills`),o=n.startsWith(`/workspace/scripts`);if(!a&&!o)continue;let s=n;a&&t!==`/workspace/skills`&&(s=n.replace(`/workspace/skills`,t)),o&&t!==`/workspace/skills`&&(s=t.replace(`/workspace/skills`,``)+n);try{await e.stat(s)}catch{let t=s.substring(0,s.lastIndexOf(`/`));try{await e.mkdir(t,{recursive:!0})}catch{}await e.writeFile(s,i),IJ.info(`Created default file`,{path:s})}}}async function JJ(e){let t=BJ();for(let[n,r]of Object.entries(t)){let t=n.slice(18);if(t.startsWith(`/shared/`))try{await e.stat(t)}catch{let n=t.substring(0,t.lastIndexOf(`/`));try{await e.mkdir(n,{recursive:!0})}catch{}await e.writeFile(t,r),IJ.info(`Created default shared file`,{path:t})}}}var YJ=r(`scoop-management-tools`);function XJ(e){let{scoop:t,onSendMessage:n,onFeedScoop:r,getScoops:i,onScoopScoop:a,onDropScoop:o,onSetGlobalMemory:s,getGlobalMemory:c}=e,l=[];return l.push({name:`send_message`,description:`Send a message immediately while you're still working. Use this for progress updates or to send multiple messages. Your final output is also sent to the user, so use this for interim updates.`,inputSchema:{type:`object`,properties:{text:{type:`string`,description:`The message text to send`},sender:{type:`string`,description:`Optional sender name/role (e.g., "Researcher"). Defaults to assistant name.`}},required:[`text`]},execute:async e=>{let{text:r,sender:i}=e;return n(r,i),YJ.info(`Message sent`,{scoopFolder:t.folder,textLength:r.length}),{content:`Message sent.`}}}),t.isCone&&r&&l.push({name:`feed_scoop`,description:`Give a scoop a task and activate it. You MUST provide a complete, self-contained prompt — the scoop has NO access to your conversation history. Include all necessary context, instructions, file paths, URLs, and expected output format. The scoop will work independently and you'll be notified when it finishes.`,inputSchema:{type:`object`,properties:{scoop_name:{type:`string`,description:`The scoop folder name (e.g., "test-scoop"). Use list_scoops to see available scoops.`},prompt:{type:`string`,description:`Complete, self-contained instructions for the scoop. Include ALL context — the scoop cannot see your conversation.`}},required:[`scoop_name`,`prompt`]},execute:async e=>{let{scoop_name:t,prompt:n}=e,a=i().find(e=>e.folder===t||e.name===t);if(!a)return{content:`Scoop "${t}" not found. Available: ${i().filter(e=>!e.isCone).map(e=>e.folder).join(`, `)}`,isError:!0};if(a.isCone)return{content:`Cannot feed the cone (yourself).`,isError:!0};try{return await r(a.jid,n),YJ.info(`Fed scoop`,{target:a.folder,promptLength:n.length}),{content:`Task sent to ${a.folder}. You will be notified when it completes.`}}catch(e){return{content:`Failed to feed scoop: ${e instanceof Error?e.message:String(e)}`,isError:!0}}}}),t.isCone&&(l.push({name:`list_scoops`,description:`List all registered scoops.`,inputSchema:{type:`object`,properties:{}},execute:async()=>{let e=i();return e.length===0?{content:`No scoops registered.`}:{content:`Registered scoops:\n${e.map(e=>e.isCone?`- ${e.assistantLabel} (${e.folder}) [CONE]`:`- ${e.name} (${e.folder})`).join(`
14326
- `)}`}}}),a&&l.push({name:`scoop_scoop`,description:`Create a new scoop. Optionally specify a model and/or a prompt. If prompt is provided, the scoop starts working immediately after creation (no separate feed_scoop needed).`,inputSchema:{type:`object`,properties:{name:{type:`string`,description:`Display name for the scoop (e.g., "hero-block")`},model:{type:`string`,description:`Model ID for this scoop (e.g., "claude-sonnet-4-6"). If omitted, uses the same model as the cone.`},prompt:{type:`string`,description:`Task prompt for the scoop. If provided, the scoop starts working immediately after creation.`}},required:[`name`]},execute:async e=>{let{name:t,model:n,prompt:i}=e,o=t.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``).slice(0,50)+`-scoop`;try{let e=await a({name:t,folder:o,trigger:`@${o}`,isCone:!1,type:`scoop`,requiresTrigger:!0,assistantLabel:o,addedAt:new Date().toISOString(),config:n?{modelId:n}:void 0});return YJ.info(`Scoop created`,{name:t,folder:o}),i&&r?(r(e.jid,i).catch(e=>{let n=e instanceof Error?e.message:String(e);YJ.error(`Auto-feed failed`,{name:t,error:n})}),{content:`Scoop "${t}" created as "${o}" and task sent. It will start working as soon as initialization completes.`}):{content:`Scoop "${t}" created as "${o}". Use feed_scoop to give it a task.`}}catch(e){return{content:`Failed to create scoop: ${e instanceof Error?e.message:String(e)}`,isError:!0}}}}),o&&l.push({name:`drop_scoop`,description:`Remove a scoop and stop its work. The scoop will be unregistered and its context destroyed.`,inputSchema:{type:`object`,properties:{scoop_name:{type:`string`,description:`The scoop folder name (e.g., "test-scoop"). Use list_scoops to see available scoops.`}},required:[`scoop_name`]},execute:async e=>{let{scoop_name:t}=e,n=i().find(e=>e.folder===t||e.name===t);if(!n)return{content:`Scoop "${t}" not found. Available: ${i().filter(e=>!e.isCone).map(e=>e.folder).join(`, `)}`,isError:!0};if(n.isCone)return{content:`Cannot drop the cone (yourself).`,isError:!0};try{return await o(n.jid),YJ.info(`Scoop dropped`,{name:n.name,folder:n.folder}),{content:`Scoop "${n.name}" (${n.folder}) has been dropped.`}}catch(e){return{content:`Failed to drop scoop: ${e instanceof Error?e.message:String(e)}`,isError:!0}}}}),s&&c&&l.push({name:`update_global_memory`,description:`Update the global CLAUDE.md memory file that is shared across all scoops. Use this instead of write_file for /shared/CLAUDE.md.`,inputSchema:{type:`object`,properties:{content:{type:`string`,description:`The new content for the global memory file`}},required:[`content`]},execute:async e=>{let{content:t}=e;try{return await s(t),YJ.info(`Global memory updated`),{content:`Global memory updated successfully.`}}catch(e){return{content:`Failed to update global memory: ${e instanceof Error?e.message:String(e)}`,isError:!0}}}})),l}var ZJ=r(`scoop-context`);function QJ(e){return/image exceeds.*maximum/i.test(e)||/Could not process image/i.test(e)||/invalid.*image/i.test(e)||/image.*too (large|big)/i.test(e)}var $J=class{scoop;callbacks;fs=null;shell=null;agent=null;status=`initializing`;isProcessing=!1;didStreamDeltas=!1;unsubscribe=null;sessionStore=null;sessionId;sessionCreatedAt=0;isRecovering=!1;skillsFs=null;skillsDir=`/workspace/skills`;constructor(e,t,n,r,i){this.scoop=e,this.callbacks=t,this.fs=n,this.sessionStore=r??null,this.skillsFs=i??null,this.sessionId=e.jid}async init(){this.setStatus(`initializing`);try{if(!this.fs)throw Error(`Filesystem not provided`);ZJ.info(`Filesystem ready`,{folder:this.scoop.folder}),await this.ensureDirectoryStructure();let e=this.scoop.isCone?`/`:`/scoops/${this.scoop.folder}/workspace`,t=this.callbacks.getBrowserAPI();this.skillsDir=`/workspace/skills`,this.scoop.isCone&&await qJ(this.fs,this.skillsDir);let n=this.skillsFs??this.fs;this.shell=new nJ({fs:this.fs,cwd:e,browserAPI:t,jshDiscoveryFs:this.skillsFs?n:void 0}),ZJ.info(`WasmShell initialized`,{folder:this.scoop.folder});let r=await UJ(n,this.skillsDir),i=XJ({scoop:this.scoop,onSendMessage:this.callbacks.onSendMessage,getScoops:this.callbacks.getScoops,onFeedScoop:this.callbacks.onFeedScoop,onScoopScoop:this.callbacks.onScoopScoop,onDropScoop:this.callbacks.onDropScoop,onSetGlobalMemory:this.callbacks.setGlobalMemory,getGlobalMemory:this.callbacks.getGlobalMemory}),a=x([...iJ(this.fs),fJ(this.shell),hJ(this.fs),...i]),o=this.scoop.isCone?`/workspace/CLAUDE.md`:`/scoops/${this.scoop.folder}/CLAUDE.md`,s=``;try{let e=await this.fs.readFile(o,{encoding:`utf-8`});s=typeof e==`string`?e:new TextDecoder().decode(e)}catch{}let c=await this.callbacks.getGlobalMemory();if(c)try{this.scoop.isCone&&await(`getUnderlyingFS`in this.fs?this.fs.getUnderlyingFS():this.fs).writeFile(`/shared/CLAUDE.md`,c)}catch{}let l=E();if(!l){let e=D();throw Error(`No API key configured for provider "${e}"`)}let u=this.scoop.config?.modelId?se(this.scoop.config.modelId):ae(),d=this.buildSystemPrompt(c,s,r),f=[];if(this.sessionStore)try{let e=await this.sessionStore.load(this.sessionId);e&&(f=e.messages,this.sessionCreatedAt=e.createdAt,ZJ.info(`Restored agent session`,{folder:this.scoop.folder,messageCount:f.length}))}catch(e){ZJ.error(`Failed to restore agent session`,{folder:this.scoop.folder,error:e instanceof Error?e.message:String(e)}),this.callbacks.onError(`Conversation history could not be restored. Starting fresh.`)}let p=S({model:u,getApiKey:()=>E()??void 0});this.agent=new ee({initialState:{model:u,tools:a,systemPrompt:d,messages:f},getApiKey:()=>l,transformContext:p}),this.unsubscribe=this.agent.subscribe(e=>this.handleAgentEvent(e)),this.setStatus(`ready`),ZJ.info(`ScoopContext initialized`,{folder:this.scoop.folder,toolCount:a.length})}catch(e){let t=e instanceof Error?e.message:String(e);ZJ.error(`ScoopContext init failed`,{folder:this.scoop.folder,error:t}),this.setStatus(`error`),this.callbacks.onError(`Failed to initialize: ${t}`)}}async prompt(e){if(!this.agent){this.callbacks.onError(`Agent not initialized`);return}let t=this.agent.state?.isStreaming??!1;if(this.isProcessing||t){ZJ.info(`Queueing prompt via followUp while processing`,{folder:this.scoop.folder,isProcessing:this.isProcessing,agentIsStreaming:t}),this.agent.followUp({role:`user`,content:[{type:`text`,text:e}],timestamp:Date.now()});return}this.isProcessing=!0,this.didStreamDeltas=!1,this.setStatus(`processing`);try{await this.agent.prompt(e)}catch(e){let t=e instanceof Error?e.message:String(e);ZJ.error(`Agent error`,{folder:this.scoop.folder,error:t}),this.callbacks.onError(t)}finally{this.isProcessing=!1,this.setStatus(`ready`)}}stop(){this.agent?.clearAllQueues?.(),this.agent?.abort?.(),this.isProcessing=!1,this.setStatus(`ready`)}clearMessages(){this.agent?.clearMessages()}getAgentMessages(){return this.agent?.state?.messages?structuredClone(this.agent.state.messages):[]}getSessionId(){return this.sessionId}getFS(){return this.fs}getShell(){return this.shell}updateModel(){if(!this.agent)return;let e=ae();this.agent.setModel(e),ZJ.info(`Model updated on running agent`,{folder:this.scoop.folder,model:e.id})}async reloadSkills(){if(!this.agent)return;let e=await UJ(this.skillsFs??this.fs,this.skillsDir),t=``,n=this.scoop.isCone?`/workspace/CLAUDE.md`:`/scoops/${this.scoop.folder}/CLAUDE.md`;try{let e=await this.fs.readFile(n,{encoding:`utf-8`});t=typeof e==`string`?e:new TextDecoder().decode(e)}catch{}let r=await this.callbacks.getGlobalMemory(),i=this.buildSystemPrompt(r,t,e);this.agent.setSystemPrompt(i),ZJ.info(`Skills reloaded`,{folder:this.scoop.folder,skillCount:e.length})}dispose(){this.unsubscribe?.(),this.shell?.dispose(),this.agent=null,this.shell=null,this.fs=null}setStatus(e){this.status=e,this.callbacks.onStatusChange(e)}handleAgentEvent(e){switch(e.type){case`message_update`:{let t=e.assistantMessageEvent;t.type===`text_delta`&&(this.didStreamDeltas=!0,this.callbacks.onResponse(t.delta,!0));break}case`tool_execution_start`:this.callbacks.onToolStart?.(e.toolName,e.args);break;case`tool_execution_update`:{let t=e.partialResult;for(let n of t?.content??[])n.type===`tool_ui`&&n.requestId&&n.html?this.callbacks.onToolUI?.(e.toolName,n.requestId,n.html):n.type===`tool_ui_done`&&n.requestId&&this.callbacks.onToolUIDone?.(n.requestId);break}case`tool_execution_end`:{let t=e.result,n=[];for(let e of t?.content??[])e.type===`text`&&e.text&&n.push(e.text),e.type===`image`&&e.data&&e.mimeType&&n.push(`<img:data:${e.mimeType};base64,${e.data}>`);this.callbacks.onToolEnd?.(e.toolName,n.join(`
14327
- `),e.isError);break}case`message_end`:if(e.message.role===`assistant`){let t=e.message.content.filter(e=>e.type===`text`).map(e=>e.text).join(``);t&&!this.didStreamDeltas&&this.callbacks.onResponse(t,!1)}break;case`turn_end`:this.callbacks.onResponseDone();break;case`agent_end`:{let t=e.messages;if(t.length>0){let e=t[t.length-1];if(e.role===`assistant`&&e.errorMessage){let n=e.errorMessage;if(!this.isRecovering&&QJ(n)){this.recoverFromImageError(t);break}if(!this.isRecovering&&b(e)){this.recoverFromOverflow(t);break}this.isRecovering=!1,this.callbacks.onError(n)}else this.isRecovering=!1}let n=this.agent?.state?.messages??e.messages;this.sessionStore&&n.length>0&&this.sessionStore.save({id:this.sessionId,messages:n,config:{},createdAt:this.sessionCreatedAt||Date.now(),updatedAt:Date.now()}).catch(e=>{ZJ.error(`Failed to save agent session`,{folder:this.scoop.folder,error:e instanceof Error?e.message:String(e)})});break}}}recoverFromOverflow(e){if(this.agent){ZJ.warn(`Context overflow detected, attempting recovery`,{folder:this.scoop.folder,messageCount:e.length}),this.isRecovering=`overflow`,this.callbacks.onResponse(`Context window exceeded — recovering by trimming oversized messages...`,!1);try{let t=e.slice(0,-1),n=0;for(let e=t.length-1;e>=0&&n<5;e--){let r=t[e];if(!Array.isArray(r.content))continue;let i=0;for(let e of r.content)e.type===`text`&&e.text&&(i+=e.text.length),e.type===`image`&&e.data&&(i+=e.data.length);if(i>4e4){let a={type:`text`,text:`[Content removed: ${r.role===`toolResult`?`tool result`:r.role} was too large for context window (${Math.round(i/1e3)}K chars). The operation completed but output could not be retained.]`};if(r.role===`assistant`){let n=r.content.filter(e=>e.type===`toolCall`);t[e]={...r,content:[a,...n]}}else t[e]={...r,content:[a]};n++,ZJ.info(`Replaced oversized message`,{index:e,role:r.role,size:i,preservedToolCalls:r.role===`assistant`?r.content.filter(e=>e.type===`toolCall`).length:0})}}this.agent.replaceMessages(t);let r=n>0?`[System: Context overflow recovered. ${n} oversized message(s) were replaced with placeholders to fit within the context window. The conversation continues — you may need to re-read files or re-run commands if their output was removed.]`:`[System: Context overflow recovered. Older messages were trimmed. The conversation continues — compaction will summarize history on the next turn.]`;this.agent.prompt(r).catch(e=>{ZJ.error(`Recovery re-prompt failed`,{folder:this.scoop.folder,error:e instanceof Error?e.message:String(e)}),this.isRecovering=!1,this.callbacks.onError(`Context overflow recovery failed: ${e instanceof Error?e.message:String(e)}`)})}catch(e){ZJ.error(`Recovery failed`,{folder:this.scoop.folder,error:e instanceof Error?e.message:String(e)}),this.isRecovering=!1,this.callbacks.onError(`Context overflow recovery failed: ${e instanceof Error?e.message:String(e)}`)}}}recoverFromImageError(e){if(this.agent){ZJ.warn(`Image processing error detected, attempting recovery`,{folder:this.scoop.folder,messageCount:e.length}),this.isRecovering=`image`,this.callbacks.onResponse(`Image rejected by API — removing problematic images and continuing...`,!1);try{let t=e.slice(0,-1),n=0,r=Math.max(0,t.length-10);for(let e=t.length-1;e>=r;e--){let r=t[e];if(!Array.isArray(r.content)||!r.content.some(e=>e.type===`image`))continue;let i=r.content.filter(e=>e.type!==`image`);i.length===0?t[e]={...r,content:[{type:`text`,text:`[Image removed: rejected by API]`}]}:t[e]={...r,content:i},n++}this.agent.replaceMessages(t);let i=`[System: An image was rejected by the API and has been removed from the conversation (${n} message(s) affected). The conversation continues without the image.]`;this.agent.prompt(i).catch(e=>{ZJ.error(`Image recovery re-prompt failed`,{folder:this.scoop.folder,error:e instanceof Error?e.message:String(e)}),this.isRecovering=!1,this.callbacks.onError(`Image error recovery failed: ${e instanceof Error?e.message:String(e)}`)})}catch(e){ZJ.error(`Image recovery failed`,{folder:this.scoop.folder,error:e instanceof Error?e.message:String(e)}),this.isRecovering=!1,this.callbacks.onError(`Image error recovery failed: ${e instanceof Error?e.message:String(e)}`)}}}async ensureDirectoryStructure(){if(!this.fs)return;let e=this.scoop.isCone?[`/workspace`,`/shared`,`/scoops`,`/home`,`/tmp`,`/mnt`]:[`/scoops/${this.scoop.folder}`,`/scoops/${this.scoop.folder}/workspace`,`/scoops/${this.scoop.folder}/home`,`/scoops/${this.scoop.folder}/tmp`,`/shared`];for(let t of e)try{await this.fs.mkdir(t,{recursive:!0})}catch{}let t=this.scoop.isCone?`/workspace/CLAUDE.md`:`/scoops/${this.scoop.folder}/CLAUDE.md`;try{await this.fs.readFile(t)}catch{let e=`# ${this.scoop.assistantLabel} Memory
14021
+ ---`}async function QJ(e,t=`/workspace/skills`){let n=GJ();for(let[r,i]of Object.entries(n)){let n=r.slice(18),a=n.startsWith(`/workspace/skills`),o=n.startsWith(`/workspace/scripts`);if(!a&&!o)continue;let s=n;a&&t!==`/workspace/skills`&&(s=n.replace(`/workspace/skills`,t)),o&&t!==`/workspace/skills`&&(s=t.replace(`/workspace/skills`,``)+n);try{await e.stat(s)}catch{let t=s.substring(0,s.lastIndexOf(`/`));try{await e.mkdir(t,{recursive:!0})}catch{}await e.writeFile(s,i),VJ.info(`Created default file`,{path:s})}}}async function $J(e){let t=GJ();for(let[n,r]of Object.entries(t)){let t=n.slice(18);if(t.startsWith(`/shared/`))try{await e.stat(t)}catch{let n=t.substring(0,t.lastIndexOf(`/`));try{await e.mkdir(n,{recursive:!0})}catch{}await e.writeFile(t,r),VJ.info(`Created default shared file`,{path:t})}}}var eY=r(`scoop-management-tools`);function tY(e){let{scoop:t,onSendMessage:n,onFeedScoop:r,getScoops:i,onScoopScoop:a,onDropScoop:o,onSetGlobalMemory:s,getGlobalMemory:c}=e,l=[];return l.push({name:`send_message`,description:`Send a message immediately while you're still working. Use this for progress updates or to send multiple messages. Your final output is also sent to the user, so use this for interim updates.`,inputSchema:{type:`object`,properties:{text:{type:`string`,description:`The message text to send`},sender:{type:`string`,description:`Optional sender name/role (e.g., "Researcher"). Defaults to assistant name.`}},required:[`text`]},execute:async e=>{let{text:r,sender:i}=e;return n(r,i),eY.info(`Message sent`,{scoopFolder:t.folder,textLength:r.length}),{content:`Message sent.`}}}),t.isCone&&r&&l.push({name:`feed_scoop`,description:`Give a scoop a task and activate it. You MUST provide a complete, self-contained prompt — the scoop has NO access to your conversation history. Include all necessary context, instructions, file paths, URLs, and expected output format. The scoop will work independently and you'll be notified when it finishes.`,inputSchema:{type:`object`,properties:{scoop_name:{type:`string`,description:`The scoop folder name (e.g., "test-scoop"). Use list_scoops to see available scoops.`},prompt:{type:`string`,description:`Complete, self-contained instructions for the scoop. Include ALL context — the scoop cannot see your conversation.`}},required:[`scoop_name`,`prompt`]},execute:async e=>{let{scoop_name:t,prompt:n}=e,a=i().find(e=>e.folder===t||e.name===t);if(!a)return{content:`Scoop "${t}" not found. Available: ${i().filter(e=>!e.isCone).map(e=>e.folder).join(`, `)}`,isError:!0};if(a.isCone)return{content:`Cannot feed the cone (yourself).`,isError:!0};try{return await r(a.jid,n),eY.info(`Fed scoop`,{target:a.folder,promptLength:n.length}),{content:`Task sent to ${a.folder}. You will be notified when it completes.`}}catch(e){return{content:`Failed to feed scoop: ${e instanceof Error?e.message:String(e)}`,isError:!0}}}}),t.isCone&&(l.push({name:`list_scoops`,description:`List all registered scoops.`,inputSchema:{type:`object`,properties:{}},execute:async()=>{let e=i();return e.length===0?{content:`No scoops registered.`}:{content:`Registered scoops:\n${e.map(e=>e.isCone?`- ${e.assistantLabel} (${e.folder}) [CONE]`:`- ${e.name} (${e.folder})`).join(`
14022
+ `)}`}}}),a&&l.push({name:`scoop_scoop`,description:`Create a new scoop. Optionally specify a model and/or a prompt. If prompt is provided, the scoop starts working immediately after creation (no separate feed_scoop needed).`,inputSchema:{type:`object`,properties:{name:{type:`string`,description:`Display name for the scoop (e.g., "hero-block")`},model:{type:`string`,description:`Model ID for this scoop (e.g., "claude-sonnet-4-6"). If omitted, uses the same model as the cone.`},prompt:{type:`string`,description:`Task prompt for the scoop. If provided, the scoop starts working immediately after creation.`}},required:[`name`]},execute:async e=>{let{name:t,model:n,prompt:i}=e,o=t.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``).slice(0,50)+`-scoop`;try{let e=await a({name:t,folder:o,trigger:`@${o}`,isCone:!1,type:`scoop`,requiresTrigger:!0,assistantLabel:o,addedAt:new Date().toISOString(),config:n?{modelId:n}:void 0});return eY.info(`Scoop created`,{name:t,folder:o}),i&&r?(r(e.jid,i).catch(e=>{let n=e instanceof Error?e.message:String(e);eY.error(`Auto-feed failed`,{name:t,error:n})}),{content:`Scoop "${t}" created as "${o}" and task sent. It will start working as soon as initialization completes.`}):{content:`Scoop "${t}" created as "${o}". Use feed_scoop to give it a task.`}}catch(e){return{content:`Failed to create scoop: ${e instanceof Error?e.message:String(e)}`,isError:!0}}}}),o&&l.push({name:`drop_scoop`,description:`Remove a scoop and stop its work. The scoop will be unregistered and its context destroyed.`,inputSchema:{type:`object`,properties:{scoop_name:{type:`string`,description:`The scoop folder name (e.g., "test-scoop"). Use list_scoops to see available scoops.`}},required:[`scoop_name`]},execute:async e=>{let{scoop_name:t}=e,n=i().find(e=>e.folder===t||e.name===t);if(!n)return{content:`Scoop "${t}" not found. Available: ${i().filter(e=>!e.isCone).map(e=>e.folder).join(`, `)}`,isError:!0};if(n.isCone)return{content:`Cannot drop the cone (yourself).`,isError:!0};try{return await o(n.jid),eY.info(`Scoop dropped`,{name:n.name,folder:n.folder}),{content:`Scoop "${n.name}" (${n.folder}) has been dropped.`}}catch(e){return{content:`Failed to drop scoop: ${e instanceof Error?e.message:String(e)}`,isError:!0}}}}),s&&c&&l.push({name:`update_global_memory`,description:`Update the global CLAUDE.md memory file that is shared across all scoops. Use this instead of write_file for /shared/CLAUDE.md.`,inputSchema:{type:`object`,properties:{content:{type:`string`,description:`The new content for the global memory file`}},required:[`content`]},execute:async e=>{let{content:t}=e;try{return await s(t),eY.info(`Global memory updated`),{content:`Global memory updated successfully.`}}catch(e){return{content:`Failed to update global memory: ${e instanceof Error?e.message:String(e)}`,isError:!0}}}})),l}var nY=r(`scoop-context`);function rY(e){return/image exceeds.*maximum/i.test(e)||/Could not process image/i.test(e)||/invalid.*image/i.test(e)||/image.*too (large|big)/i.test(e)}var iY=class{scoop;callbacks;fs=null;shell=null;agent=null;status=`initializing`;isProcessing=!1;didStreamDeltas=!1;unsubscribe=null;sessionStore=null;sessionId;sessionCreatedAt=0;isRecovering=!1;skillsFs=null;skillsDir=`/workspace/skills`;constructor(e,t,n,r,i){this.scoop=e,this.callbacks=t,this.fs=n,this.sessionStore=r??null,this.skillsFs=i??null,this.sessionId=e.jid}async init(){this.setStatus(`initializing`);try{if(!this.fs)throw Error(`Filesystem not provided`);nY.info(`Filesystem ready`,{folder:this.scoop.folder}),await this.ensureDirectoryStructure();let e=this.scoop.isCone?`/`:`/scoops/${this.scoop.folder}/workspace`,t=this.callbacks.getBrowserAPI();this.skillsDir=`/workspace/skills`,this.scoop.isCone&&await QJ(this.fs,this.skillsDir);let n=this.skillsFs??this.fs;this.shell=new cJ({fs:this.fs,cwd:e,browserAPI:t,jshDiscoveryFs:this.skillsFs?n:void 0}),nY.info(`WasmShell initialized`,{folder:this.scoop.folder});let r=await JJ(n,this.skillsDir),i=tY({scoop:this.scoop,onSendMessage:this.callbacks.onSendMessage,getScoops:this.callbacks.getScoops,onFeedScoop:this.callbacks.onFeedScoop,onScoopScoop:this.callbacks.onScoopScoop,onDropScoop:this.callbacks.onDropScoop,onSetGlobalMemory:this.callbacks.setGlobalMemory,getGlobalMemory:this.callbacks.getGlobalMemory}),a=x([...uJ(this.fs),vJ(this.shell),xJ(this.fs),...i]),o=this.scoop.isCone?`/workspace/CLAUDE.md`:`/scoops/${this.scoop.folder}/CLAUDE.md`,s=``;try{let e=await this.fs.readFile(o,{encoding:`utf-8`});s=typeof e==`string`?e:new TextDecoder().decode(e)}catch{}let c=await this.callbacks.getGlobalMemory();if(c)try{this.scoop.isCone&&await(`getUnderlyingFS`in this.fs?this.fs.getUnderlyingFS():this.fs).writeFile(`/shared/CLAUDE.md`,c)}catch{}let l=E();if(!l){let e=D();throw Error(`No API key configured for provider "${e}"`)}let u=this.scoop.config?.modelId?se(this.scoop.config.modelId):ae(),d=this.buildSystemPrompt(c,s,r),f=[];if(this.sessionStore)try{let e=await this.sessionStore.load(this.sessionId);e&&(f=e.messages,this.sessionCreatedAt=e.createdAt,nY.info(`Restored agent session`,{folder:this.scoop.folder,messageCount:f.length}))}catch(e){nY.error(`Failed to restore agent session`,{folder:this.scoop.folder,error:e instanceof Error?e.message:String(e)}),this.callbacks.onError(`Conversation history could not be restored. Starting fresh.`)}let p=S({model:u,getApiKey:()=>E()??void 0});this.agent=new ee({initialState:{model:u,tools:a,systemPrompt:d,messages:f},getApiKey:()=>l,transformContext:p}),this.unsubscribe=this.agent.subscribe(e=>this.handleAgentEvent(e)),this.setStatus(`ready`),nY.info(`ScoopContext initialized`,{folder:this.scoop.folder,toolCount:a.length})}catch(e){let t=e instanceof Error?e.message:String(e);nY.error(`ScoopContext init failed`,{folder:this.scoop.folder,error:t}),this.setStatus(`error`),this.callbacks.onError(`Failed to initialize: ${t}`)}}async prompt(e){if(!this.agent){this.callbacks.onError(`Agent not initialized`);return}let t=this.agent.state?.isStreaming??!1;if(this.isProcessing||t){nY.info(`Queueing prompt via followUp while processing`,{folder:this.scoop.folder,isProcessing:this.isProcessing,agentIsStreaming:t}),this.agent.followUp({role:`user`,content:[{type:`text`,text:e}],timestamp:Date.now()});return}this.isProcessing=!0,this.didStreamDeltas=!1,this.setStatus(`processing`);try{await this.agent.prompt(e)}catch(e){let t=e instanceof Error?e.message:String(e);nY.error(`Agent error`,{folder:this.scoop.folder,error:t}),this.callbacks.onError(t)}finally{this.isProcessing=!1,this.setStatus(`ready`)}}stop(){this.agent?.clearAllQueues?.(),this.agent?.abort?.(),this.isProcessing=!1,this.setStatus(`ready`)}clearMessages(){this.agent?.clearMessages()}getAgentMessages(){return this.agent?.state?.messages?structuredClone(this.agent.state.messages):[]}getSessionId(){return this.sessionId}getFS(){return this.fs}getShell(){return this.shell}updateModel(){if(!this.agent)return;let e=ae();this.agent.setModel(e),nY.info(`Model updated on running agent`,{folder:this.scoop.folder,model:e.id})}async reloadSkills(){if(!this.agent)return;let e=await JJ(this.skillsFs??this.fs,this.skillsDir),t=``,n=this.scoop.isCone?`/workspace/CLAUDE.md`:`/scoops/${this.scoop.folder}/CLAUDE.md`;try{let e=await this.fs.readFile(n,{encoding:`utf-8`});t=typeof e==`string`?e:new TextDecoder().decode(e)}catch{}let r=await this.callbacks.getGlobalMemory(),i=this.buildSystemPrompt(r,t,e);this.agent.setSystemPrompt(i),nY.info(`Skills reloaded`,{folder:this.scoop.folder,skillCount:e.length})}dispose(){this.unsubscribe?.(),this.shell?.dispose(),this.agent=null,this.shell=null,this.fs=null}setStatus(e){this.status=e,this.callbacks.onStatusChange(e)}handleAgentEvent(e){switch(e.type){case`message_update`:{let t=e.assistantMessageEvent;t.type===`text_delta`&&(this.didStreamDeltas=!0,this.callbacks.onResponse(t.delta,!0));break}case`tool_execution_start`:this.callbacks.onToolStart?.(e.toolName,e.args);break;case`tool_execution_update`:{let t=e.partialResult;for(let n of t?.content??[])n.type===`tool_ui`&&n.requestId&&n.html?this.callbacks.onToolUI?.(e.toolName,n.requestId,n.html):n.type===`tool_ui_done`&&n.requestId&&this.callbacks.onToolUIDone?.(n.requestId);break}case`tool_execution_end`:{let t=e.result,n=[];for(let e of t?.content??[])e.type===`text`&&e.text&&n.push(e.text),e.type===`image`&&e.data&&e.mimeType&&n.push(`<img:data:${e.mimeType};base64,${e.data}>`);this.callbacks.onToolEnd?.(e.toolName,n.join(`
14023
+ `),e.isError);break}case`message_end`:if(e.message.role===`assistant`){let t=e.message.content.filter(e=>e.type===`text`).map(e=>e.text).join(``);t&&!this.didStreamDeltas&&this.callbacks.onResponse(t,!1)}break;case`turn_end`:this.callbacks.onResponseDone();break;case`agent_end`:{let t=e.messages;if(t.length>0){let e=t[t.length-1];if(e.role===`assistant`&&e.errorMessage){let n=e.errorMessage;if(!this.isRecovering&&rY(n)){this.recoverFromImageError(t);break}if(!this.isRecovering&&b(e)){this.recoverFromOverflow(t);break}this.isRecovering=!1,this.callbacks.onError(n)}else this.isRecovering=!1}let n=this.agent?.state?.messages??e.messages;this.sessionStore&&n.length>0&&this.sessionStore.save({id:this.sessionId,messages:n,config:{},createdAt:this.sessionCreatedAt||Date.now(),updatedAt:Date.now()}).catch(e=>{nY.error(`Failed to save agent session`,{folder:this.scoop.folder,error:e instanceof Error?e.message:String(e)})});break}}}recoverFromOverflow(e){if(this.agent){nY.warn(`Context overflow detected, attempting recovery`,{folder:this.scoop.folder,messageCount:e.length}),this.isRecovering=`overflow`,this.callbacks.onResponse(`Context window exceeded — recovering by trimming oversized messages...`,!1);try{let t=e.slice(0,-1),n=0;for(let e=t.length-1;e>=0&&n<5;e--){let r=t[e];if(!Array.isArray(r.content))continue;let i=0;for(let e of r.content)e.type===`text`&&e.text&&(i+=e.text.length),e.type===`image`&&e.data&&(i+=e.data.length);if(i>4e4){let a={type:`text`,text:`[Content removed: ${r.role===`toolResult`?`tool result`:r.role} was too large for context window (${Math.round(i/1e3)}K chars). The operation completed but output could not be retained.]`};if(r.role===`assistant`){let n=r.content.filter(e=>e.type===`toolCall`);t[e]={...r,content:[a,...n]}}else t[e]={...r,content:[a]};n++,nY.info(`Replaced oversized message`,{index:e,role:r.role,size:i,preservedToolCalls:r.role===`assistant`?r.content.filter(e=>e.type===`toolCall`).length:0})}}this.agent.replaceMessages(t);let r=n>0?`[System: Context overflow recovered. ${n} oversized message(s) were replaced with placeholders to fit within the context window. The conversation continues — you may need to re-read files or re-run commands if their output was removed.]`:`[System: Context overflow recovered. Older messages were trimmed. The conversation continues — compaction will summarize history on the next turn.]`;this.agent.prompt(r).catch(e=>{nY.error(`Recovery re-prompt failed`,{folder:this.scoop.folder,error:e instanceof Error?e.message:String(e)}),this.isRecovering=!1,this.callbacks.onError(`Context overflow recovery failed: ${e instanceof Error?e.message:String(e)}`)})}catch(e){nY.error(`Recovery failed`,{folder:this.scoop.folder,error:e instanceof Error?e.message:String(e)}),this.isRecovering=!1,this.callbacks.onError(`Context overflow recovery failed: ${e instanceof Error?e.message:String(e)}`)}}}recoverFromImageError(e){if(this.agent){nY.warn(`Image processing error detected, attempting recovery`,{folder:this.scoop.folder,messageCount:e.length}),this.isRecovering=`image`,this.callbacks.onResponse(`Image rejected by API — removing problematic images and continuing...`,!1);try{let t=e.slice(0,-1),n=0,r=Math.max(0,t.length-10);for(let e=t.length-1;e>=r;e--){let r=t[e];if(!Array.isArray(r.content)||!r.content.some(e=>e.type===`image`))continue;let i=r.content.filter(e=>e.type!==`image`);i.length===0?t[e]={...r,content:[{type:`text`,text:`[Image removed: rejected by API]`}]}:t[e]={...r,content:i},n++}this.agent.replaceMessages(t);let i=`[System: An image was rejected by the API and has been removed from the conversation (${n} message(s) affected). The conversation continues without the image.]`;this.agent.prompt(i).catch(e=>{nY.error(`Image recovery re-prompt failed`,{folder:this.scoop.folder,error:e instanceof Error?e.message:String(e)}),this.isRecovering=!1,this.callbacks.onError(`Image error recovery failed: ${e instanceof Error?e.message:String(e)}`)})}catch(e){nY.error(`Image recovery failed`,{folder:this.scoop.folder,error:e instanceof Error?e.message:String(e)}),this.isRecovering=!1,this.callbacks.onError(`Image error recovery failed: ${e instanceof Error?e.message:String(e)}`)}}}async ensureDirectoryStructure(){if(!this.fs)return;let e=this.scoop.isCone?[`/workspace`,`/shared`,`/scoops`,`/home`,`/tmp`,`/mnt`]:[`/scoops/${this.scoop.folder}`,`/scoops/${this.scoop.folder}/workspace`,`/scoops/${this.scoop.folder}/home`,`/scoops/${this.scoop.folder}/tmp`,`/shared`];for(let t of e)try{await this.fs.mkdir(t,{recursive:!0})}catch{}let t=this.scoop.isCone?`/workspace/CLAUDE.md`:`/scoops/${this.scoop.folder}/CLAUDE.md`;try{await this.fs.readFile(t)}catch{let e=`# ${this.scoop.assistantLabel} Memory
14328
14024
 
14329
14025
  ${this.scoop.isCone?`Role: Cone (main orchestrator)`:`Scoop: ${this.scoop.name}`}
14330
14026
  Folder: ${this.scoop.folder}
@@ -14403,10 +14099,10 @@ ${e}
14403
14099
  ---
14404
14100
  ${this.scoop.isCone?`CONE`:`SCOOP`} MEMORY (${this.scoop.name}):
14405
14101
  ${t}
14406
- ---`);let a=KJ(n);return a&&(i+=a),i}},eY=r(`scheduler`),tY=class{callbacks;pollInterval=null;running=!1;constructor(e){this.callbacks=e}start(){this.running||(this.running=!0,this.pollInterval=window.setInterval(()=>this.checkTasks(),6e4),this.checkTasks(),eY.info(`Scheduler started`))}stop(){this.pollInterval&&=(clearInterval(this.pollInterval),null),this.running=!1,eY.info(`Scheduler stopped`)}async createTask(e,t,n,r){let i={id:`task-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,groupFolder:e,prompt:t,scheduleType:n,scheduleValue:r,status:`active`,nextRun:this.calculateNextRun(n,r),lastRun:null,createdAt:new Date().toISOString()};return await I(i),eY.info(`Task created`,{id:i.id,groupFolder:e,scheduleType:n}),i}async updateTask(e,t){let n=await Me(e);if(!n)return null;let r={...n,...t};return(t.scheduleType||t.scheduleValue)&&(r.nextRun=this.calculateNextRun(r.scheduleType,r.scheduleValue)),await I(r),eY.info(`Task updated`,{id:e,updates:Object.keys(t)}),r}async pauseTask(e){return await this.updateTask(e,{status:`paused`})!==null}async resumeTask(e){return await Me(e)?(await this.updateTask(e,{status:`active`}),!0):!1}async deleteTask(e){return await Me(e)?(await N(e),eY.info(`Task deleted`,{id:e}),!0):!1}async getTasksByScoop(e){return(await je()).filter(t=>t.groupFolder===e)}async getAllTasks(){return je()}async checkTasks(){let e=await je(),t=new Date;for(let n of e)n.status===`active`&&n.nextRun&&(new Date(n.nextRun)>t||await this.runTask(n))}async runTask(e){let t=this.callbacks.getScoop(e.groupFolder);if(!t){eY.warn(`Task scoop not found`,{taskId:e.id,groupFolder:e.groupFolder});return}eY.info(`Running task`,{id:e.id,groupFolder:e.groupFolder});try{let n=new Date().toISOString(),r=this.calculateNextRun(e.scheduleType,e.scheduleValue),i=e.scheduleType===`once`?`completed`:e.status;await I({...e,lastRun:n,nextRun:r,status:i}),await this.callbacks.onTaskRun(e,t),eY.info(`Task completed`,{id:e.id})}catch(t){eY.error(`Task execution failed`,{id:e.id,error:t instanceof Error?t.message:String(t)})}}calculateNextRun(e,t){let n=new Date;switch(e){case`cron`:return this.getNextCronTime(t,n)?.toISOString()??null;case`interval`:{let e=parseInt(t,10);return isNaN(e)||e<=0?null:new Date(n.getTime()+e).toISOString()}case`once`:return new Date(t)>n?t:null;default:return null}}getNextCronTime(e,t){let n=e.trim().split(/\s+/);if(n.length!==5)return null;let[r,i,a,o,s]=n,c=new Date(t);c.setSeconds(0),c.setMilliseconds(0),c.setMinutes(c.getMinutes()+1);for(let e=0;e<527040;e++){if(this.cronMatches(c,r,i,a,o,s))return c;c.setMinutes(c.getMinutes()+1)}return null}cronMatches(e,t,n,r,i,a){return this.cronFieldMatches(e.getMinutes(),t)&&this.cronFieldMatches(e.getHours(),n)&&this.cronFieldMatches(e.getDate(),r)&&this.cronFieldMatches(e.getMonth()+1,i)&&this.cronFieldMatches(e.getDay(),a)}cronFieldMatches(e,t){if(t===`*`)return!0;if(t.includes(`,`))return t.split(`,`).some(t=>this.cronFieldMatches(e,t.trim()));if(t.includes(`-`)){let[n,r]=t.split(`-`).map(e=>parseInt(e,10));return e>=n&&e<=r}if(t.includes(`/`)){let[n,r]=t.split(`/`),i=parseInt(r,10);if(n===`*`)return e%i===0;let a=parseInt(n,10);return e>=a&&(e-a)%i===0}return parseInt(t,10)===e}},nY=r(`lick-manager`),rY=class{webhooks=new Map;crontasks=new Map;cronInterval=null;eventHandler=null;async init(){await ke();let e=await ze();for(let t of e)this.webhooks.set(t.id,t);nY.info(`Loaded webhooks`,{count:this.webhooks.size});let t=await Le();for(let e of t)this.crontasks.set(e.id,e);nY.info(`Loaded crontasks`,{count:this.crontasks.size}),this.cronInterval=setInterval(()=>this.runCronScheduler(),6e4),nY.info(`Cron scheduler started`)}dispose(){this.cronInterval&&=(clearInterval(this.cronInterval),null)}setEventHandler(e){this.eventHandler=e}async createWebhook(e,t,n){let r=this.generateId(),i={id:r,name:e,createdAt:new Date().toISOString(),filter:n,scoop:t};return n&&this.compileFilter(n,!0),this.webhooks.set(r,i),await Ee(i),nY.info(`Webhook created`,{id:r,name:e,scoop:t}),i}async deleteWebhook(e){return this.webhooks.has(e)?(this.webhooks.delete(e),await Pe(e),nY.info(`Webhook deleted`,{id:e}),!0):!1}listWebhooks(){return Array.from(this.webhooks.values())}getWebhook(e){return this.webhooks.get(e)}handleWebhookEvent(e,t,n){let r=this.webhooks.get(e);if(!r){nY.warn(`Webhook not found`,{webhookId:e});return}let i={type:`webhook`,webhookId:e,webhookName:r.name,targetScoop:r.scoop,timestamp:new Date().toISOString(),headers:t,body:n};if(r.filter)try{let t=this.compileFilter(r.filter,!0)(i);if(t===!1){nY.debug(`Webhook event dropped by filter`,{webhookId:e,name:r.name});return}typeof t==`object`&&t&&(i=t)}catch(t){nY.error(`Webhook filter error`,{webhookId:e,error:t instanceof Error?t.message:String(t)})}nY.info(`Webhook event received`,{webhookId:e,name:r.name,targetScoop:r.scoop}),this.eventHandler?.(i)}async createCronTask(e,t,n,r){let i=this.getNextCronTime(t,new Date);if(!i)throw Error(`Invalid cron expression`);r&&this.compileFilter(r,!1);let a=this.generateId(),o={id:a,name:e,cron:t,scoop:n,filter:r,nextRun:i.toISOString(),lastRun:null,status:`active`,createdAt:new Date().toISOString()};return this.crontasks.set(a,o),await Oe(o),nY.info(`Cron task created`,{id:a,name:e,cron:t,scoop:n}),o}async deleteCronTask(e){return this.crontasks.has(e)?(this.crontasks.delete(e),await Ne(e),nY.info(`Cron task deleted`,{id:e}),!0):!1}listCronTasks(){return Array.from(this.crontasks.values())}getCronTask(e){return this.crontasks.get(e)}getLicksForScoop(e,t){let n=n=>n===e||n===t||`${n}-scoop`===t;return{webhooks:Array.from(this.webhooks.values()).filter(e=>n(e.scoop)),cronTasks:Array.from(this.crontasks.values()).filter(e=>n(e.scoop))}}async runCronScheduler(){let e=new Date;for(let t of this.crontasks.values()){if(t.status!==`active`||!t.nextRun||new Date(t.nextRun)>e)continue;let n={time:e.toISOString()};if(t.filter)try{let r=this.compileFilter(t.filter,!1)(null);if(r===!1){nY.debug(`Cron task skipped by filter`,{id:t.id,name:t.name}),t.nextRun=this.getNextCronTime(t.cron,e)?.toISOString()??null,t.lastRun=e.toISOString(),await Oe(t);continue}typeof r==`object`&&r&&(n=r)}catch(e){nY.error(`Cron filter error`,{id:t.id,error:e instanceof Error?e.message:String(e)})}let r={type:`cron`,cronId:t.id,cronName:t.name,targetScoop:t.scoop,timestamp:e.toISOString(),body:n};nY.info(`Cron task running`,{id:t.id,name:t.name}),this.eventHandler?.(r),t.nextRun=this.getNextCronTime(t.cron,e)?.toISOString()??null,t.lastRun=e.toISOString(),await Oe(t)}}generateId(){let e=``;for(let t=0;t<12;t++)e+=`abcdefghijklmnopqrstuvwxyz0123456789`[Math.floor(Math.random()*36)];return e}compileFilter(e,t){try{return t?Function(`event`,`return (${e})(event);`):Function(`return (${e})();`)}catch(e){throw Error(`Invalid filter function: ${e instanceof Error?e.message:String(e)}`)}}getNextCronTime(e,t){let n=e.trim().split(/\s+/);if(n.length!==5)return null;let[r,i,a,o,s]=n,c=new Date(t);c.setSeconds(0),c.setMilliseconds(0),c.setMinutes(c.getMinutes()+1);let l=(e,t)=>{if(t===`*`)return!0;if(t.includes(`,`))return t.split(`,`).some(t=>l(e,t.trim()));if(t.includes(`-`)){let[n,r]=t.split(`-`).map(e=>parseInt(e,10));return e>=n&&e<=r}if(t.includes(`/`)){let[n,r]=t.split(`/`),i=parseInt(r,10);if(n===`*`)return e%i===0;let a=parseInt(n,10);return e>=a&&(e-a)%i===0}return parseInt(t,10)===e};for(let e=0;e<527040;e++){if(l(c.getMinutes(),r)&&l(c.getHours(),i)&&l(c.getDate(),a)&&l(c.getMonth()+1,o)&&l(c.getDay(),s))return c;c.setMinutes(c.getMinutes()+1)}return null}};function iY(e,t,n){if(t.length===0&&n.length===0)return null;let r=[];t.length>0&&r.push(`${t.length} active webhook${t.length>1?`s`:``}`),n.length>0&&r.push(`${n.length} active cron task${n.length>1?`s`:``}`);let i=[...t.map(e=>` webhook delete ${e.id}`),...n.map(e=>` crontask delete ${e.id}`)].join(`
14407
- `);return Error(`Cannot remove scoop '${e}': it has ${r.join(` and `)}. Unregister them first:\n${i}`)}var aY=null;function oY(){return aY||=new rY,aY}var sY=r(`orchestrator`),cY=class{scoops=new Map;tabs=new Map;contexts=new Map;messageQueues=new Map;lastAgentTimestamp=new Map;container;callbacks;config;pollInterval=null;scheduler=null;globalMemoryCache=``;sharedFs=null;scoopResponseBuffer=new Map;lickManager=null;sessionStore=null;constructor(e,t,n={name:`sliccy`,triggerPattern:/^@sliccy\b/i}){this.container=e,this.callbacks=t,this.config=n}async init(){await ke(),this.sharedFs=await A.create({dbName:`slicc-fs`}),this.sessionStore=new C,await this.ensureRootStructure();let e=await P();for(let t of Object.values(e)){t.isCone&&(t.trigger=void 0,t.requiresTrigger=!1,t.assistantLabel=t.assistantLabel||`sliccy`),this.scoops.set(t.jid,t),this.messageQueues.set(t.jid,[]);let e=await Fe(`lastAgentTs_${t.jid}`);e&&this.lastAgentTimestamp.set(t.jid,e)}await this.ensureGlobalMemory(),this.scheduler=new tY({onTaskRun:async(e,t)=>{sY.info(`Running scheduled task`,{taskId:e.id,scoop:t.name}),await this.sendPrompt(t.jid,`[SCHEDULED TASK]\n\n${e.prompt}`,`scheduler`,`Scheduled Task`)},getScoop:e=>{for(let t of this.scoops.values())if(t.folder===e)return t}}),this.scheduler.start(),sY.info(`Orchestrator initialized`,{scoopCount:this.scoops.size});for(let e of this.scoops.values())await this.createScoopTab(e.jid);this.startMessageLoop()}async ensureRootStructure(){if(this.sharedFs)for(let e of[`/workspace`,`/shared`,`/scoops`,`/home`,`/tmp`,`/mnt`])try{await this.sharedFs.mkdir(e,{recursive:!0})}catch{}}async ensureGlobalMemory(){if(this.sharedFs){await JJ(this.sharedFs);try{let e=await this.sharedFs.readFile(`/shared/CLAUDE.md`,{encoding:`utf-8`});this.globalMemoryCache=typeof e==`string`?e:new TextDecoder().decode(e)}catch{sY.warn(`Global memory file not found after creating defaults`)}}}async getGlobalMemory(){if(this.globalMemoryCache)return this.globalMemoryCache;if(this.sharedFs)try{let e=await this.sharedFs.readFile(`/shared/CLAUDE.md`,{encoding:`utf-8`});this.globalMemoryCache=typeof e==`string`?e:new TextDecoder().decode(e)}catch{}return this.globalMemoryCache}async setGlobalMemory(e){this.sharedFs&&(await this.sharedFs.writeFile(`/shared/CLAUDE.md`,e),this.globalMemoryCache=e,sY.info(`Global memory updated`))}getSharedFS(){return this.sharedFs}setLickManager(e){this.lickManager=e}async registerScoop(e){await Be(e),this.scoops.set(e.jid,e),this.messageQueues.set(e.jid,[]),sY.info(`Scoop registered`,{jid:e.jid,name:e.name}),this.createScoopTab(e.jid).catch(t=>{let n=t instanceof Error?t.message:String(t);sY.error(`Scoop init failed`,{jid:e.jid,error:n})})}async unregisterScoop(e){let t=this.scoops.get(e);if(t&&this.lickManager){let{webhooks:e,cronTasks:n}=this.lickManager.getLicksForScoop(t.name,t.folder),r=iY(t.folder,e,n);if(r)throw r}await this.destroyScoopTab(e),this.sessionStore?.delete(e).catch(t=>{sY.warn(`Failed to delete agent session`,{jid:e,error:t instanceof Error?t.message:String(t)})}),await Ae(e),this.scoops.delete(e),this.messageQueues.delete(e),this.lastAgentTimestamp.delete(e),sY.info(`Scoop unregistered`,{jid:e})}getScoops(){return Array.from(this.scoops.values())}getScoop(e){return this.scoops.get(e)}async resetFilesystem(){for(let[e,t]of this.contexts.entries())t.stop(),this.contexts.delete(e);this.sharedFs=await A.create({dbName:`slicc-fs`,wipe:!0}),await this.ensureRootStructure(),await this.ensureGlobalMemory(),await qJ(this.sharedFs).catch(e=>{sY.warn(`Failed to re-seed default skills`,{error:e instanceof Error?e.message:String(e)})}),sY.info(`Filesystem reset and defaults re-seeded`)}async clearAllMessages(){await Re(),this.sessionStore&&await this.sessionStore.clearAll().catch(e=>{sY.warn(`Failed to clear agent sessions`,{error:e instanceof Error?e.message:String(e)})});for(let e of this.contexts.values())e.clearMessages();this.lastAgentTimestamp.clear();for(let e of this.scoops.keys())this.messageQueues.set(e,[]);sY.info(`All messages cleared`)}async handleMessage(e){sY.info(`handleMessage`,{id:e.id,chatJid:e.chatJid,sender:e.senderName,channel:e.channel,contentPreview:e.content.slice(0,80)});let t=this.scoops.get(e.chatJid);Gq(t?.isCone?`cone`:t?.name??`unknown`,localStorage.getItem(`selected-model`)??`unknown`),await Te(e),await this.routeToScoop(e)}async delegateToScoop(e,t,n){let r=this.scoops.get(e);if(!r)throw Error(`Scoop not found: ${e}`);let i={id:`delegate-${Date.now()}-${Math.random().toString(36).slice(2)}`,chatJid:e,senderId:`cone`,senderName:n,content:t,timestamp:new Date().toISOString(),fromAssistant:!0,channel:`delegation`};await Te(i),this.callbacks.onIncomingMessage?.(e,i),sY.info(`Delegating to scoop`,{scoopJid:e,scoopName:r.name,promptLength:t.length}),this.sendPrompt(e,t,`cone`,n).catch(t=>{let n=t instanceof Error?t.message:String(t);sY.error(`Delegation failed`,{scoopJid:e,error:n}),this.callbacks.onError(e,`Delegation failed: ${n}`)})}async routeToScoop(e){let t=this.scoops.get(e.chatJid);if(!t){sY.info(`routeToScoop: unregistered target`,{chatJid:e.chatJid});return}let n=e.channel===`webhook`||e.channel===`cron`;if(!t.isCone&&t.requiresTrigger&&t.trigger&&!n&&!e.content.includes(t.trigger)){sY.info(`routeToScoop: trigger not found in content`,{chatJid:e.chatJid,trigger:t.trigger,contentPreview:e.content.slice(0,80)});return}let r=this.messageQueues.get(e.chatJid)??[];r.push(e),this.messageQueues.set(e.chatJid,r);let i=this.tabs.get(e.chatJid);if(sY.debug(`routeToScoop: queued`,{chatJid:e.chatJid,scoopName:t.name,tabStatus:i?.status??`no-tab`,queueLength:r.length}),i?.status===`error`){sY.info(`routeToScoop: tab in error state, retrying init`,{chatJid:e.chatJid});try{await this.createScoopTab(e.chatJid),i=this.tabs.get(e.chatJid)}catch{sY.warn(`routeToScoop: retry init failed`,{chatJid:e.chatJid})}}i?.status===`ready`&&await this.processScoopQueue(e.chatJid)}async createScoopTab(e){let t=this.scoops.get(e);if(!t)throw Error(`Scoop not found: ${e}`);if(this.contexts.has(e))if(this.tabs.get(e)?.status===`error`)sY.info(`Re-creating context after error`,{jid:e}),this.contexts.get(e)?.dispose(),this.contexts.delete(e),this.tabs.delete(e);else{sY.debug(`Context already exists`,{jid:e});return}if(!this.sharedFs)throw Error(`Shared filesystem not initialized`);let n=`scoop-${t.folder}-${Date.now()}`,r=t.isCone?this.sharedFs:new fe(this.sharedFs,[`/scoops/${t.folder}/`,`/shared/`],[`/workspace/`]),i=new $J(t,{onResponse:(n,r)=>{if(this.callbacks.onResponse(e,n,r),!t.isCone)if(r){let t=this.scoopResponseBuffer.get(e)??``;this.scoopResponseBuffer.set(e,t+n)}else this.scoopResponseBuffer.set(e,n)},onResponseDone:()=>{let t=this.tabs.get(e);t&&(t.lastActivity=new Date().toISOString(),this.tabs.set(e,t)),this.callbacks.onResponseDone(e)},onError:t=>{let n=this.tabs.get(e);n&&(n.status=`error`,n.error=t,this.tabs.set(e,n)),this.callbacks.onError(e,t),this.callbacks.onStatusChange(e,`error`)},onStatusChange:n=>{let r=this.tabs.get(e);if(r&&(r.status=n,r.lastActivity=new Date().toISOString(),this.tabs.set(e,r)),this.callbacks.onStatusChange(e,n),n===`ready`&&!t.isCone){let n=this.scoopResponseBuffer.get(e);if(this.scoopResponseBuffer.delete(e),n){let r=Array.from(this.scoops.values()).find(e=>e.isCone);if(r){let i=n.length>2e3?n.slice(0,2e3)+`
14408
- ... (truncated)`:n,a={id:`scoop-done-${e}-${Date.now()}`,chatJid:r.jid,senderId:t.folder,senderName:t.assistantLabel,content:`[@${t.assistantLabel} completed]:\n${i}`,timestamp:new Date().toISOString(),fromAssistant:!1,channel:`scoop-notify`};sY.info(`Routing scoop completion to cone`,{scoop:t.folder,responseLength:n.length}),this.handleMessage(a).catch(e=>{let n=e instanceof Error?e.message:String(e);sY.error(`Failed to route scoop completion to cone`,{scoop:t.folder,error:n}),this.callbacks.onError(r.jid,`Scoop ${t.folder} completed but notification failed: ${n}`)})}}}},onToolStart:(t,n)=>{this.callbacks.onToolStart?.(e,t,n)},onToolEnd:(t,n,r)=>{this.callbacks.onToolEnd?.(e,t,n,r)},onToolUI:(t,n,r)=>{this.callbacks.onToolUI?.(e,t,n,r)},onToolUIDone:t=>{this.callbacks.onToolUIDone?.(e,t)},onSendMessage:(t,n)=>{this.callbacks.onSendMessage(e,`${n?`[${n}] `:``}${t}`)},getScoops:()=>this.getScoops(),onFeedScoop:t.isCone?(e,n)=>this.delegateToScoop(e,n,t.assistantLabel):void 0,onScoopScoop:t.isCone?async e=>{let t={...e,jid:`scoop_${e.folder}_${Date.now()}`};return await this.registerScoop(t),t}:void 0,onDropScoop:t.isCone?async e=>{await this.unregisterScoop(e)}:void 0,getGlobalMemory:()=>this.getGlobalMemory(),setGlobalMemory:t.isCone?e=>this.setGlobalMemory(e):void 0,getBrowserAPI:()=>this.callbacks.getBrowserAPI()},r,this.sessionStore??void 0,this.sharedFs??void 0);this.contexts.set(e,i),this.tabs.set(e,{jid:e,contextId:n,status:`initializing`,lastActivity:new Date().toISOString()}),await i.init();let a=this.tabs.get(e);a&&a.status===`initializing`&&(a.status=`ready`,this.tabs.set(e,a),this.callbacks.onStatusChange(e,`ready`)),sY.info(`Scoop context created`,{jid:e,contextId:n})}async destroyScoopTab(e){let t=this.contexts.get(e);t&&(t.dispose(),this.contexts.delete(e),this.tabs.delete(e),sY.info(`Scoop context destroyed`,{jid:e}))}isProcessing(e){return this.tabs.get(e)?.status===`processing`}getScoopContext(e){return this.contexts.get(e)}async clearQueuedMessages(e){let t=this.messageQueues.get(e);if(t&&t.length>0){for(let e of t)await Ie(e.id);this.messageQueues.set(e,[])}}async deleteQueuedMessage(e,t){let n=this.messageQueues.get(e);if(n){let e=n.findIndex(e=>e.id===t);e!==-1&&n.splice(e,1)}await Ie(t)}async getMessagesForScoop(e){return F(e)}async waitForTabReady(e,t=1e4){let n=Date.now();for(;Date.now()-n<t;){let t=this.tabs.get(e);if(!t)return!1;if(t.status===`ready`||t.status===`processing`)return!0;if(t.status===`error`)return!1;await new Promise(e=>setTimeout(e,100))}return sY.warn(`Timed out waiting for tab to become ready`,{jid:e}),!1}async sendPrompt(e,t,n,r){let i=this.contexts.get(e);i||=(await this.createScoopTab(e),this.contexts.get(e));let a=this.tabs.get(e);if(a?.status===`initializing`){if(sY.debug(`Context initializing, waiting to send message`,{jid:e}),!await this.waitForTabReady(e)){sY.error(`Context did not become ready in time, dropping prompt`,{jid:e});return}i=this.contexts.get(e),a=this.tabs.get(e)}if(!i){sY.error(`Context not found after creation`,{jid:e});return}this.scoopResponseBuffer.delete(e),a&&(a.status=`processing`,a.lastActivity=new Date().toISOString(),this.tabs.set(e,a),this.callbacks.onStatusChange(e,`processing`)),sY.debug(`Prompt sent to scoop`,{jid:e,textLength:t.length}),await i.prompt(t)}async processScoopQueue(e){let t=this.messageQueues.get(e);if(!t||t.length===0){sY.debug(`processScoopQueue: empty queue`,{jid:e});return}let n=this.tabs.get(e);if(n?.status!==`ready`){sY.debug(`processScoopQueue: tab not ready`,{jid:e,status:n?.status??`no-tab`});return}let r=this.scoops.get(e),i=r?.assistantLabel??e,a=this.lastAgentTimestamp.get(e)??``,o=await De(e,a,i);if(sY.debug(`processScoopQueue: DB query`,{jid:e,scoopName:r?.name,excludeName:i,since:a,dbMessageCount:o.length,queueLength:t.length}),o.length===0){sY.debug(`processScoopQueue: no messages from DB, clearing queue`,{jid:e}),this.messageQueues.set(e,[]);return}let s=o.map(e=>`[${new Date(e.timestamp).toLocaleString(`en-US`,{month:`short`,day:`numeric`,hour:`numeric`,minute:`2-digit`,hour12:!0})}] ${e.senderName}: ${e.content}`).join(`
14409
- `);this.messageQueues.set(e,[]);let c=o[o.length-1];this.lastAgentTimestamp.set(e,c.timestamp),await Ve(`lastAgentTs_${e}`,c.timestamp),await this.sendPrompt(e,s,c.senderId,c.senderName)}startMessageLoop(){this.pollInterval||=window.setInterval(()=>{for(let e of this.scoops.keys())this.tabs.get(e)?.status===`ready`&&this.processScoopQueue(e).catch(t=>{let n=t instanceof Error?t.message:String(t);sY.error(`Message queue processing failed`,{jid:e,error:n}),this.callbacks.onError(e,`Queue processing failed: ${n}`)})},2e3)}stopMessageLoop(){this.pollInterval&&=(clearInterval(this.pollInterval),null)}updateModel(){for(let e of this.contexts.values())e.updateModel();sY.info(`Model updated on all active contexts`,{contextCount:this.contexts.size})}async reloadAllSkills(){let e=[];for(let[t,n]of this.contexts){let r=this.tabs.get(t);(r?.status===`ready`||r?.status===`processing`)&&e.push(n.reloadSkills().catch(e=>{sY.warn(`Failed to reload skills for scoop`,{jid:t,error:e instanceof Error?e.message:String(e)})}))}await Promise.all(e),sY.info(`Skills reloaded across all contexts`,{count:e.length})}stopScoop(e){let t=this.contexts.get(e);t&&t.stop()}async shutdown(){this.stopMessageLoop(),this.scheduler?.stop(),this.scheduler=null;for(let e of this.contexts.keys())await this.destroyScoopTab(e);sY.info(`Orchestrator shutdown`)}};r(`heartbeat`);var lY=r(`tray-follower`);async function uY(e){let t=await _Y(await(e.fetchImpl??fetch)(e.joinUrl,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({controllerId:e.controllerId,runtime:e.runtime})}));return lY.info(`Follower tray attach response`,{trayId:t.trayId,action:t.result.action,code:t.result.code,participantCount:t.participantCount}),dY(t)}function dY(e){let t={trayId:e.trayId,controllerId:e.controllerId,participantCount:e.participantCount,leader:e.leader,action:e.result.action,code:e.result.code,iceServers:e.iceServers};return e.result.action===`wait`?{...t,retryAfterMs:e.result.retryAfterMs}:e.result.action===`signal`?{...t,bootstrap:e.result.bootstrap}:e.result.action===`fail`?{...t,error:e.result.error}:t}async function fY(e){return gY(await vY(e,{action:`poll`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,cursor:e.cursor}))}async function pY(e){return gY(await vY(e,{action:`answer`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,answer:e.answer}))}async function mY(e){return gY(await vY(e,{action:`ice-candidate`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,candidate:e.candidate}))}async function hY(e){return gY(await vY(e,{action:`retry`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,runtime:e.runtime}))}function gY(e){return{trayId:e.trayId,controllerId:e.controllerId,participantCount:e.participantCount,leader:e.leader,bootstrap:e.bootstrap,events:e.events}}async function _Y(e){let t=null,n=null;try{t=await e.text(),n=JSON.parse(t)}catch{}if(!yY(n)){let n=t?t.slice(0,200):`(empty)`;throw lY.warn(`Tray follower attach returned an invalid response`,{status:e.status,body:n}),Error(`Tray follower attach returned an invalid response (${e.status}): ${n}`)}return n}async function vY(e,t){let n=await(e.fetchImpl??fetch)(e.joinUrl,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(t)}),r=await n.json().catch(()=>null);if(!bY(r))throw Error(`Tray follower bootstrap returned an invalid response (${n.status})`);return r}function yY(e){if(!e||typeof e!=`object`)return!1;let t=e;if(typeof t.trayId!=`string`||typeof t.controllerId!=`string`||t.role!==`follower`||typeof t.participantCount!=`number`)return!1;let n=t.result;if(!n||typeof n!=`object`)return!1;let r=n;return r.action===`wait`?(r.code===`LEADER_NOT_ELECTED`||r.code===`LEADER_NOT_CONNECTED`)&&typeof r.retryAfterMs==`number`:r.action===`signal`?r.code===`LEADER_CONNECTED`&&xY(r.bootstrap):r.action===`fail`?(r.code===`INVALID_JOIN_CAPABILITY`||r.code===`TRAY_EXPIRED`)&&typeof r.error==`string`:!1}function bY(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.trayId==`string`&&typeof t.controllerId==`string`&&t.role===`follower`&&typeof t.participantCount==`number`&&xY(t.bootstrap)&&Array.isArray(t.events)}function xY(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.controllerId==`string`&&typeof t.bootstrapId==`string`&&typeof t.attempt==`number`&&typeof t.state==`string`&&typeof t.expiresAt==`string`&&typeof t.cursor==`number`&&typeof t.maxRetries==`number`&&typeof t.retriesRemaining==`number`}var SY=r(`tray-webrtc`),CY=`tray-control`,wY=250,TY=class{peerConnectionFactory;dataChannelLabel;peers=new Map;iceServers;constructor(e){this.options=e,this.iceServers=e.iceServers,this.peerConnectionFactory=e.peerConnectionFactory??(()=>OY(this.iceServers)),this.dataChannelLabel=e.dataChannelLabel??CY}setIceServers(e){this.iceServers=e}async handleControlMessage(e){e.type===`follower.join_requested`?(e.iceServers&&!this.iceServers&&(this.iceServers=e.iceServers),await this.handleJoinRequested(e)):e.type===`bootstrap.answer`?await this.peers.get(e.bootstrapId)?.peer.setRemoteDescription(e.answer):e.type===`bootstrap.ice_candidate`&&await this.peers.get(e.bootstrapId)?.peer.addIceCandidate(e.candidate)}getPeers(){return Array.from(this.peers.values()).map(({state:e})=>({...e}))}getChannel(e){return this.peers.get(e)?.channel??null}stop(){for(let e of this.peers.values())e.peer.close();this.peers.clear()}async handleJoinRequested(e){this.closeControllerPeers(e.controllerId);let t=this.peerConnectionFactory(),n={controllerId:e.controllerId,bootstrapId:e.bootstrapId,attempt:e.attempt,state:`connecting`,connectedAt:null,runtime:e.runtime},r=t.createDataChannel(this.dataChannelLabel);this.peers.set(e.bootstrapId,{state:n,peer:t,channel:r}),t.addEventListener(`icecandidate`,({candidate:t})=>{let n=AY(t);n&&this.options.sendControlMessage({type:`bootstrap.ice_candidate`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,candidate:n})}),t.addEventListener(`connectionstatechange`,()=>{let n=this.peers.get(e.bootstrapId);n&&(n.state.state===`connected`?(t.connectionState===`disconnected`||t.connectionState===`failed`)&&(SY.warn(`Leader peer connection state changed post-connect`,{bootstrapId:e.bootstrapId,state:t.connectionState}),this.options.onPeerDisconnected?.(e.bootstrapId,`Peer connection ${t.connectionState}`)):t.connectionState===`failed`&&this.failPeer(e,`Leader peer connection failed before the data channel opened`))}),r.addEventListener(`open`,()=>{let t=this.peers.get(e.bootstrapId);!t||t.state.state===`connected`||(t.state.state=`connected`,t.state.connectedAt=new Date().toISOString(),this.options.onPeerConnected?.({...t.state},t.channel))}),r.addEventListener(`close`,()=>{let t=this.peers.get(e.bootstrapId);t&&(t.state.state===`connected`?(SY.warn(`Leader data channel closed post-connect`,{bootstrapId:e.bootstrapId}),this.options.onPeerDisconnected?.(e.bootstrapId,`Data channel closed`)):this.failPeer(e,`Leader data channel closed before opening`))}),r.addEventListener(`error`,()=>{let t=this.peers.get(e.bootstrapId);t&&(t.state.state===`connected`?(SY.warn(`Leader data channel error post-connect`,{bootstrapId:e.bootstrapId}),this.options.onPeerDisconnected?.(e.bootstrapId,`Data channel error`)):this.failPeer(e,`Leader data channel failed before opening`))});try{let n=await t.createOffer();await t.setLocalDescription(n),this.options.sendControlMessage({type:`bootstrap.offer`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,offer:kY(t.localDescription??n,`offer`)})}catch(t){this.failPeer(e,t instanceof Error?t.message:String(t))}}closeControllerPeers(e){for(let[t,n]of this.peers.entries())n.state.controllerId===e&&(n.peer.close(),this.peers.delete(t))}failPeer(e,t){let n=this.peers.get(e.bootstrapId);if(n){n.peer.close(),this.peers.delete(e.bootstrapId);try{this.options.sendControlMessage({type:`bootstrap.failed`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,code:`WEBRTC_BOOTSTRAP_FAILED`,message:t,retryable:!0,retryAfterMs:1e3})}catch(e){SY.warn(`Failed to report tray bootstrap failure`,{error:e instanceof Error?e.message:String(e)})}}}},EY=class{fetchImpl;peerConnectionFactory;controllerIdFactory;sleep;pollIntervalMs;iceServers;activePeer=null;stopped=!1;constructor(e){this.options=e,this.fetchImpl=e.fetchImpl??fetch,this.iceServers=e.iceServers,this.peerConnectionFactory=e.peerConnectionFactory??(()=>OY(this.iceServers)),this.controllerIdFactory=e.controllerIdFactory??(()=>crypto.randomUUID()),this.sleep=e.sleep??(e=>new Promise(t=>setTimeout(t,e))),this.pollIntervalMs=e.pollIntervalMs??wY}async start(){this.stopped=!1;let e=this.controllerIdFactory(),t=Date.now();p({state:`connecting`,joinUrl:this.options.joinUrl,trayId:null,error:null,lastPingTime:null,reconnectAttempts:0,attachAttempts:0,lastAttachCode:null,connectingSince:t,lastError:null}),SY.info(`Follower tray join starting`,{joinUrl:this.options.joinUrl});let n=0;for(;;){jY(this.stopped),n++;let t;try{t=await uY({joinUrl:this.options.joinUrl,controllerId:e,runtime:this.options.runtime,fetchImpl:this.fetchImpl})}catch(e){let t=e instanceof Error?e.message:String(e);throw p({...h(),attachAttempts:n,lastError:t}),e}if(p({...h(),attachAttempts:n,lastAttachCode:t.code}),t.action===`wait`){let e=t.retryAfterMs??1e3;SY.info(`Follower tray attach waiting`,{attempt:n,code:t.code,retryAfterMs:e}),n%10==0&&SY.warn(`Follower tray attach still waiting after ${n} attempts`,{attempt:n,code:t.code,retryAfterMs:e}),await this.sleep(e);continue}if(t.action===`fail`||!t.bootstrap){let e=t.error??`Tray follower attach failed (${t.code})`;throw p({state:`error`,joinUrl:this.options.joinUrl,trayId:null,error:e,lastPingTime:null,reconnectAttempts:0,attachAttempts:n,lastAttachCode:t.code,connectingSince:null,lastError:e}),SY.warn(`Follower tray attach failed`,{error:e}),Error(e)}t.iceServers&&(this.iceServers=t.iceServers);try{let r=await this.completeBootstrap(t.trayId,e,t.bootstrap);return p({state:`connected`,joinUrl:this.options.joinUrl,trayId:r.trayId,error:null,lastPingTime:null,reconnectAttempts:0,attachAttempts:n,lastAttachCode:t.code,connectingSince:null,lastError:null}),SY.info(`Follower tray connected`,{trayId:r.trayId,controllerId:e}),r}catch(e){let r=e instanceof Error?e.message:String(e);throw p({state:`error`,joinUrl:this.options.joinUrl,trayId:t.trayId,error:r,lastPingTime:null,reconnectAttempts:0,attachAttempts:n,lastAttachCode:t.code,connectingSince:null,lastError:r}),SY.warn(`Follower tray bootstrap failed`,{error:r}),e}}}stop(){this.stopped=!0,this.activePeer?.peer.close(),this.activePeer?.channel?.close(),this.activePeer=null,p({state:`inactive`,joinUrl:null,trayId:null,error:null,lastPingTime:null,reconnectAttempts:0,attachAttempts:0,lastAttachCode:null,connectingSince:null,lastError:null})}async completeBootstrap(e,t,n){let r=n,i=0;for(this.activePeer=this.createFollowerPeer(t,r.bootstrapId);;){if(jY(this.stopped),this.activePeer.open&&this.activePeer.channel)return{trayId:e,controllerId:t,bootstrapId:r.bootstrapId,channel:this.activePeer.channel};if(this.activePeer.openError)throw Error(this.activePeer.openError);let n=await fY({joinUrl:this.options.joinUrl,controllerId:t,bootstrapId:r.bootstrapId,cursor:i,fetchImpl:this.fetchImpl});r=n.bootstrap,i=r.cursor;try{for(let e of n.events)if(e.type===`bootstrap.offer`){await this.activePeer.peer.setRemoteDescription(e.offer);let n=await this.activePeer.peer.createAnswer();await this.activePeer.peer.setLocalDescription(n),await pY({joinUrl:this.options.joinUrl,controllerId:t,bootstrapId:r.bootstrapId,answer:kY(this.activePeer.peer.localDescription??n,`answer`),fetchImpl:this.fetchImpl})}else if(e.type===`bootstrap.ice_candidate`)await this.activePeer.peer.addIceCandidate(e.candidate);else if(e.type===`bootstrap.failed`)throw Error(e.failure.message)}catch(e){if(r.failure?.retryable&&r.retriesRemaining>0){r=(await hY({joinUrl:this.options.joinUrl,controllerId:t,bootstrapId:r.bootstrapId,runtime:this.options.runtime,fetchImpl:this.fetchImpl})).bootstrap,i=0,this.activePeer.peer.close(),this.activePeer=this.createFollowerPeer(t,r.bootstrapId);continue}throw e}this.activePeer.open||await this.sleep(this.pollIntervalMs)}}createFollowerPeer(e,t){let n=this.peerConnectionFactory(),r={peer:n,channel:null,open:!1,openError:null};return n.addEventListener(`connectionstatechange`,()=>{r.open&&(n.connectionState===`disconnected`||n.connectionState===`failed`)&&(SY.warn(`Follower peer connection state changed post-connect`,{bootstrapId:t,state:n.connectionState}),this.options.onDisconnected?.(`Peer connection ${n.connectionState}`))}),n.addEventListener(`datachannel`,({channel:e})=>{r.channel=e,e.addEventListener(`open`,()=>{r.open=!0}),e.addEventListener(`close`,()=>{r.open?(SY.warn(`Follower data channel closed post-connect`,{bootstrapId:t}),this.options.onDisconnected?.(`Data channel closed`)):r.openError=`Follower data channel closed before opening`}),e.addEventListener(`error`,()=>{r.open?(SY.warn(`Follower data channel error post-connect`,{bootstrapId:t}),this.options.onDisconnected?.(`Data channel error`)):r.openError=`Follower data channel failed before opening`})}),n.addEventListener(`icecandidate`,({candidate:n})=>{let r=AY(n);r&&mY({joinUrl:this.options.joinUrl,controllerId:e,bootstrapId:t,candidate:r,fetchImpl:this.fetchImpl}).catch(e=>{SY.warn(`Failed to send follower ICE candidate`,{error:e instanceof Error?e.message:String(e)})})}),r}};function DY(e,t){let n=t.baseDelayMs??1e3,r=t.backoffMultiplier??2,i=t.maxDelayMs??3e4,a=t.maxAttempts??10,o=t.sleep??e.sleep??(e=>new Promise(t=>setTimeout(t,e))),s=!1,c=!1,l=null,u={cancel(){s=!0,c=!1,l?.stop(),l=null},get reconnecting(){return c}},d=()=>{let t=new EY({...e,sleep:o,onDisconnected:e=>{s||(SY.warn(`Follower disconnected, starting reconnect loop`,{reason:e}),f(e))}});return l=t,{manager:t,connectionPromise:t.start()}},f=async u=>{if(s||c)return;c=!0,l?.stop(),l=null;let f=0,m=n,g=u??`Unknown disconnect`;for(;!s&&f<a&&(f++,t.onReconnecting?.(f),p({...h(),state:`reconnecting`,error:null,reconnectAttempts:f}),SY.info(`Reconnect attempt`,{attempt:f,delay:m}),await o(m),!s);){let n=null;try{let r=d();n=r.manager;let i=await r.connectionPromise;if(s){n.stop();break}c=!1,p({...h(),state:`connected`,joinUrl:e.joinUrl,trayId:i.trayId,error:null,lastPingTime:null,reconnectAttempts:0,connectingSince:null,lastError:null}),SY.info(`Reconnect successful`,{attempt:f,trayId:i.trayId}),t.onConnected(i);return}catch(e){g=e instanceof Error?e.message:String(e),SY.warn(`Reconnect attempt failed`,{attempt:f,error:g}),n?.stop(),l=null}m=Math.min(m*r,i)}s||(c=!1,p({...h(),state:`error`,error:`Reconnect failed after ${f} attempts: ${g}`,reconnectAttempts:f}),SY.warn(`Reconnect gave up`,{attempts:f,lastError:g}),t.onGaveUp?.(g))},{connectionPromise:m}=d();return m.then(e=>{s||t.onConnected(e)}).catch(e=>{s||SY.warn(`Initial follower connection failed`,{error:e instanceof Error?e.message:String(e)})}),u}function OY(e){if(typeof RTCPeerConnection>`u`)throw Error(`RTCPeerConnection is not available in this runtime`);let t=e?.length?{iceServers:e}:void 0;return new RTCPeerConnection(t)}function kY(e,t){if(!e||e.type!==t||typeof e.sdp!=`string`)throw Error(`Expected a local ${t} description before signaling`);return{type:e.type,sdp:e.sdp}}function AY(e){if(!e||typeof e!=`object`)return null;let t=e;return typeof t.candidate==`string`?{candidate:t.candidate,sdpMid:typeof t.sdpMid==`string`?t.sdpMid:null,sdpMLineIndex:typeof t.sdpMLineIndex==`number`?t.sdpMLineIndex:null,usernameFragment:typeof t.usernameFragment==`string`?t.usernameFragment:null}:null}function jY(e){if(e)throw Error(`Tray follower stopped before WebRTC bootstrap completed`)}var MY=64*1024;async function NY(e,t){try{switch(t.op){case`readFile`:return await PY(e,t.path,t.encoding);case`writeFile`:return[await FY(e,t.path,t.content,t.encoding)];case`stat`:return[await IY(e,t.path)];case`readDir`:return[await LY(e,t.path)];case`mkdir`:return[await RY(e,t.path,t.recursive)];case`rm`:return[await zY(e,t.path,t.recursive)];case`exists`:return[await BY(e,t.path)];case`walk`:return[await VY(e,t.path)];default:return[{ok:!1,error:`Unknown fs operation: ${t.op}`}]}}catch(e){return[UY(e)]}}async function PY(e,t,n){return(n??`utf-8`)===`utf-8`?HY(await e.readFile(t,{encoding:`utf-8`}),`utf-8`):HY(WY(await e.readFile(t,{encoding:`binary`})),`base64`)}async function FY(e,t,n,r){if(r===`base64`){let r=GY(n);await e.writeFile(t,r)}else await e.writeFile(t,n);return{ok:!0,data:{type:`void`}}}async function IY(e,t){return{ok:!0,data:{type:`stat`,stat:await e.stat(t)}}}async function LY(e,t){return{ok:!0,data:{type:`dirEntries`,entries:await e.readDir(t)}}}async function RY(e,t,n){return await e.mkdir(t,{recursive:n}),{ok:!0,data:{type:`void`}}}async function zY(e,t,n){return await e.rm(t,{recursive:n}),{ok:!0,data:{type:`void`}}}async function BY(e,t){return{ok:!0,data:{type:`exists`,exists:await e.exists(t)}}}async function VY(e,t){let n=[];for await(let r of e.walk(t))n.push(r);return{ok:!0,data:{type:`paths`,paths:n}}}function HY(e,t){if(e.length<=MY)return[{ok:!0,data:{type:`file`,content:e,encoding:t}}];let n=Math.ceil(e.length/MY),r=[];for(let i=0;i<n;i++){let a=i*MY,o=e.slice(a,a+MY);r.push({ok:!0,data:{type:`file`,content:o,encoding:t},chunkIndex:i,totalChunks:n})}return r}function UY(e){return e instanceof Error&&`code`in e?{ok:!1,error:e.message,code:e.code}:{ok:!1,error:e instanceof Error?e.message:String(e)}}function WY(e){let t=``;for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t)}function GY(e){let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e++)n[e]=t.charCodeAt(e);return n}var KY=class{runtimes=new Map;dirty=!1;setTargets(e,t){this.runtimes.set(e,t),this.dirty=!0}removeRuntime(e){this.runtimes.delete(e)&&(this.dirty=!0)}getEntries(){this.dirty=!1;let e=[];for(let[t,n]of this.runtimes)for(let r of n)e.push({targetId:`${t}:${r.targetId}`,localTargetId:r.targetId,runtimeId:t,title:r.title,url:r.url,isLocal:!1});return e}hasChanged(){return this.dirty}getRuntimeIds(){return[...this.runtimes.keys()]}},qY=r(`data-channel-keepalive`),JY=class{sendPing;onDead;intervalMs;maxMissed;timer=null;missedPongs=0;awaitingPong=!1;stopped=!1;constructor(e){this.sendPing=e.sendPing,this.onDead=e.onDead,this.intervalMs=e.intervalMs??1e4,this.maxMissed=e.maxMissed??3}start(){this.timer||this.stopped||(this.timer=setInterval(()=>this.tick(),this.intervalMs))}stop(){this.stopped=!0,this.timer&&=(clearInterval(this.timer),null)}receivePong(){this.awaitingPong=!1,this.missedPongs=0}receivePing(){this.missedPongs=0,this.awaitingPong=!1}get missed(){return this.missedPongs}tick(){if(!this.stopped){if(this.awaitingPong&&(this.missedPongs++,qY.debug(`Missed pong`,{missedPongs:this.missedPongs,maxMissed:this.maxMissed}),this.missedPongs>=this.maxMissed)){qY.warn(`Channel declared dead`,{missedPongs:this.missedPongs}),this.stop(),this.onDead();return}this.awaitingPong=!0,this.sendPing()}}},YY=r(`tray-leader-sync`);function XY(e){return e?e.includes(`standalone`)?`standalone`:e.includes(`extension`)?`extension`:e.includes(`electron`)?`electron`:`unknown`:`unknown`}var ZY=class{followers=new Map;registry=new KY;runtimeToBootstrap=new Map;pendingCDPRoutes=new Map;cdpChunkBuffers=new Map;remoteTransports=new Map;pendingTabOpenRoutes=new Map;tabOpenResolvers=new Map;pendingFsRoutes=new Map;fsResolvers=new Map;constructor(e){this.options=e}addFollower(e,t,n){this.removeFollower(e);let r=be(t),i=r.onMessage(t=>{this.handleFollowerMessage(e,t)}),a=new JY({sendPing:()=>r.send({type:`ping`}),onDead:()=>{YY.warn(`Follower keepalive dead, removing follower`,{bootstrapId:e}),this.removeFollower(e),this.options.onFollowerDead?.(e)}});a.start(),this.followers.set(e,{bootstrapId:e,sync:r,unsubscribe:i,keepalive:a,runtime:n?.runtime,connectedAt:n?.connectedAt,lastActivity:Date.now(),floatType:XY(n?.runtime)}),YY.info(`Follower added to sync`,{bootstrapId:e,followerCount:this.followers.size}),this.sendSnapshotToFollower(e);let o=this.getConnectedEntries();o.length>0&&r.send({type:`targets.registry`,targets:o})}removeFollower(e){let t=this.followers.get(e);if(t){t.keepalive.stop(),t.unsubscribe(),t.sync.close(),this.followers.delete(e);for(let[t,n]of this.runtimeToBootstrap)if(n===e){this.cleanupRemoteTransports(t),this.registry.removeRuntime(t),this.runtimeToBootstrap.delete(t);break}this.registry.hasChanged()&&this.broadcastTargetRegistry(),YY.info(`Follower removed from sync`,{bootstrapId:e,followerCount:this.followers.size})}}broadcastEvent(e){if(this.followers.size===0)return;let t={type:`agent_event`,event:e,scoopJid:this.options.getScoopJid()};for(let e of this.followers.values())e.sync.send(t)}broadcastUserMessage(e,t){if(this.followers.size===0)return;let n={type:`user_message_echo`,text:e,messageId:t,scoopJid:this.options.getScoopJid()};for(let e of this.followers.values())e.sync.send(n)}broadcastStatus(e){if(this.followers.size===0)return;let t={type:`status`,scoopStatus:e};for(let e of this.followers.values())e.sync.send(t)}sendSnapshotToFollower(e){let t=this.followers.get(e);if(!t)return;let n=this.options.getMessages(),r=this.options.getScoopJid();ve(t.sync,n,r),YY.debug(`Snapshot sent to follower`,{bootstrapId:e,messageCount:n.length})}handleFollowerMessage(e,t){switch(t.type){case`user_message`:YY.info(`Follower user message received`,{bootstrapId:e,messageId:t.messageId}),this.options.onFollowerMessage(t.text,t.messageId);break;case`abort`:YY.info(`Follower abort received`,{bootstrapId:e}),this.options.onFollowerAbort();break;case`request_snapshot`:YY.info(`Follower snapshot request received`,{bootstrapId:e}),this.sendSnapshotToFollower(e);break;case`targets.advertise`:YY.info(`Follower targets advertised`,{bootstrapId:e,runtimeId:t.runtimeId,targetCount:t.targets.length});for(let e of[...this.remoteTransports.keys()]){let n=e.substring(0,e.indexOf(`:`));n!==`leader`&&!this.runtimeToBootstrap.has(n)&&n!==t.runtimeId&&(this.remoteTransports.get(e)?.disconnect(),this.remoteTransports.delete(e),YY.debug(`Cleaned up orphaned remote transport on advertise`,{key:e}))}this.runtimeToBootstrap.set(t.runtimeId,e),this.registry.setTargets(t.runtimeId,t.targets),this.broadcastTargetRegistry();break;case`cdp.request`:{let{requestId:n,targetRuntimeId:r,localTargetId:i,method:a,params:o,sessionId:s}=t;r===`leader`?this.executeLocalCDP(n,i,a,o,s,e):this.forwardCDPRequest(n,r,i,a,o,s,e);break}case`cdp.response`:this.handleCDPResponse(t);break;case`cdp.event`:this.handleCDPEvent(e,t.method,t.params,t.sessionId);break;case`tab.open`:{let{requestId:n,targetRuntimeId:r,url:i}=t;r===`leader`?this.executeLocalTabOpen(n,i,e):this.forwardTabOpen(n,r,i,e);break}case`tab.opened`:this.handleTabOpenResponse(t.requestId,t.targetId);break;case`tab.open.error`:this.handleTabOpenError(t.requestId,t.error);break;case`fs.request`:{let{requestId:n,targetRuntimeId:r,request:i}=t;r===`leader`?this.executeLocalFs(n,i,e):this.forwardFsRequest(n,r,i,e);break}case`fs.response`:this.handleFsResponse(t.requestId,t.response);break;case`ping`:{let t=this.followers.get(e);t&&(t.keepalive.receivePing(),t.lastActivity=Date.now(),t.sync.send({type:`pong`}));break}case`pong`:{let t=this.followers.get(e);t&&(t.keepalive.receivePong(),t.lastActivity=Date.now());break}}}setLocalTargets(e){this.registry.setTargets(`leader`,e),this.registry.hasChanged()&&this.broadcastTargetRegistry()}broadcastTargetRegistry(){if(this.followers.size===0)return;let e={type:`targets.registry`,targets:this.getConnectedEntries()};for(let t of this.followers.values())t.sync.send(e)}getTargets(){return this.getConnectedEntries()}getConnectedEntries(){return this.registry.getEntries().filter(e=>{if(e.runtimeId===`leader`)return!0;let t=this.runtimeToBootstrap.get(e.runtimeId);return t?this.followers.has(t):!1})}createRemoteTransport(e,t){let n=new j({sendCDPRequest:(n,r,i,a)=>{let o=this.runtimeToBootstrap.get(e),s=o?this.followers.get(o):void 0;if(!s){this.remoteTransports.get(`${e}:${t}`)?.handleResponse(n,void 0,`Target runtime "${e}" not connected`);return}this.pendingCDPRoutes.set(n,{requesterBootstrapId:`__leader__`,requestId:n}),s.sync.send({type:`cdp.request`,requestId:n,localTargetId:t,method:r,params:i,sessionId:a})}});return this.remoteTransports.set(`${e}:${t}`,n),n}removeRemoteTransport(e,t){let n=`${e}:${t}`,r=this.remoteTransports.get(n);r&&(r.disconnect(),this.remoteTransports.delete(n))}cleanupRemoteTransports(e){let t=`${e}:`;for(let e of[...this.remoteTransports.keys()])e.startsWith(t)&&(this.remoteTransports.get(e)?.disconnect(),this.remoteTransports.delete(e),YY.debug(`Cleaned up stale remote transport`,{key:e}))}getConnectedFollowers(){return[...this.runtimeToBootstrap.entries()].map(([e,t])=>{let n=this.followers.get(t);return{runtimeId:e,runtime:n?.runtime,connectedAt:n?.connectedAt,lastActivity:n?.lastActivity,floatType:n?.floatType}})}getBestFollowerForTeleport(){let e=[];for(let[t,n]of this.runtimeToBootstrap){let r=this.followers.get(n);r&&e.push({runtimeId:t,bootstrapId:n,floatType:r.floatType,lastActivity:r.lastActivity})}if(e.length===0)return null;let t=e.filter(e=>e.floatType===`standalone`),n=t.length>0?t:e;return n.sort((e,t)=>t.lastActivity-e.lastActivity),n[0]}get hasFollowers(){return this.followers.size>0}stop(){for(let e of[...this.followers.keys()])this.removeFollower(e)}async executeLocalCDP(e,t,n,r,i,a){let o=this.followers.get(a);if(!o)return;let s=this.options.browserTransport;if(!s){o.sync.send({type:`cdp.response`,requestId:e,error:`Leader has no browser transport`});return}try{let t=await s.send(n,r,i);Ce(o.sync,e,t)}catch(t){o.sync.send({type:`cdp.response`,requestId:e,error:t instanceof Error?t.message:String(t)})}}forwardCDPRequest(e,t,n,r,i,a,o){let s=this.runtimeToBootstrap.get(t),c=s?this.followers.get(s):void 0,l=this.followers.get(o);if(!c){l&&l.sync.send({type:`cdp.response`,requestId:e,error:`Target runtime "${t}" not connected`});return}this.pendingCDPRoutes.set(e,{requesterBootstrapId:o,requestId:e}),c.sync.send({type:`cdp.request`,requestId:e,localTargetId:n,method:r,params:i,sessionId:a})}handleCDPResponse(e){let{requestId:t,result:n,error:r,chunkData:i,chunkIndex:a,totalChunks:o}=e,s=this.pendingCDPRoutes.get(t);if(!s)return;let c=_e(this.cdpChunkBuffers,e);if(!c)return;if(this.pendingCDPRoutes.delete(t),s.requesterBootstrapId===`__leader__`){for(let e of this.remoteTransports.values())e.handleResponse(t,c.result,c.error);return}let l=this.followers.get(s.requesterBootstrapId);l&&Ce(l.sync,t,c.result,c.error)}handleCDPEvent(e,t,n,r){let i;for(let[t,n]of this.runtimeToBootstrap)if(n===e){i=t;break}if(!i)return;let a=`${i}:`;for(let[e,r]of this.remoteTransports)e.startsWith(a)&&r.handleEvent(t,n)}openRemoteTab(e,t){let n=this.runtimeToBootstrap.get(e),r=n?this.followers.get(n):void 0;if(!r)return Promise.reject(Error(`Target runtime "${e}" not connected`));let i=`tab-open-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;return new Promise((e,n)=>{this.tabOpenResolvers.set(i,{resolve:e,reject:n}),this.pendingTabOpenRoutes.set(i,{requesterBootstrapId:`__leader__`,requestId:i}),r.sync.send({type:`tab.open`,requestId:i,url:t})})}async executeLocalTabOpen(e,t,n){let r=this.followers.get(n);if(!r)return;let i=this.options.browserTransport;if(!i){r.sync.send({type:`tab.open.error`,requestId:e,error:`Leader has no browser transport`});return}try{let n=(await i.send(`Target.createTarget`,{url:t,background:!0})).targetId;r.sync.send({type:`tab.opened`,requestId:e,targetId:`leader:${n}`})}catch(t){r.sync.send({type:`tab.open.error`,requestId:e,error:t instanceof Error?t.message:String(t)})}}forwardTabOpen(e,t,n,r){let i=this.runtimeToBootstrap.get(t),a=i?this.followers.get(i):void 0,o=this.followers.get(r);if(!a){o&&o.sync.send({type:`tab.open.error`,requestId:e,error:`Target runtime "${t}" not connected`});return}this.pendingTabOpenRoutes.set(e,{requesterBootstrapId:r,requestId:e}),a.sync.send({type:`tab.open`,requestId:e,url:n})}handleTabOpenResponse(e,t){let n=this.pendingTabOpenRoutes.get(e);if(!n)return;if(this.pendingTabOpenRoutes.delete(e),n.requesterBootstrapId===`__leader__`){let n=this.tabOpenResolvers.get(e);n&&(this.tabOpenResolvers.delete(e),n.resolve(t));return}let r=this.followers.get(n.requesterBootstrapId);r&&r.sync.send({type:`tab.opened`,requestId:e,targetId:t})}handleTabOpenError(e,t){let n=this.pendingTabOpenRoutes.get(e);if(!n)return;if(this.pendingTabOpenRoutes.delete(e),n.requesterBootstrapId===`__leader__`){let n=this.tabOpenResolvers.get(e);n&&(this.tabOpenResolvers.delete(e),n.reject(Error(t)));return}let r=this.followers.get(n.requesterBootstrapId);r&&r.sync.send({type:`tab.open.error`,requestId:e,error:t})}async executeLocalFs(e,t,n){let r=this.followers.get(n);if(!r)return;let i=this.options.vfs;if(!i){r.sync.send({type:`fs.response`,requestId:e,response:{ok:!1,error:`Leader has no VFS`}});return}let a=await NY(i,t);for(let t of a)r.sync.send({type:`fs.response`,requestId:e,response:t})}forwardFsRequest(e,t,n,r){let i=this.runtimeToBootstrap.get(t),a=i?this.followers.get(i):void 0,o=this.followers.get(r);if(!a){o&&o.sync.send({type:`fs.response`,requestId:e,response:{ok:!1,error:`Target runtime "${t}" not connected`}});return}this.pendingFsRoutes.set(e,{requesterBootstrapId:r,requestId:e,chunks:[],totalChunks:1}),a.sync.send({type:`fs.request`,requestId:e,request:n})}handleFsResponse(e,t){let n=this.pendingFsRoutes.get(e);if(!n){let n=this.fsResolvers.get(e);if(n){n.responses.push(t);let r=t.ok&&t.totalChunks||1;n.responses.length>=r&&(this.fsResolvers.delete(e),n.resolve(n.responses))}return}if(n.requesterBootstrapId===`__leader__`){let n=this.fsResolvers.get(e);if(n){n.responses.push(t);let r=t.ok&&t.totalChunks||1;n.responses.length>=r&&(this.fsResolvers.delete(e),this.pendingFsRoutes.delete(e),n.resolve(n.responses))}return}let r=this.followers.get(n.requesterBootstrapId);r&&r.sync.send({type:`fs.response`,requestId:e,response:t}),n.chunks.push(t),n.totalChunks=t.ok&&t.totalChunks||1,n.chunks.length>=n.totalChunks&&this.pendingFsRoutes.delete(e)}sendFsRequest(e,t){if(e===`leader`){let e=this.options.vfs;return e?NY(e,t):Promise.resolve([{ok:!1,error:`Leader has no VFS`}])}let n=this.runtimeToBootstrap.get(e),r=n?this.followers.get(n):void 0;if(!r)return Promise.resolve([{ok:!1,error:`Target runtime "${e}" not connected`}]);let i=`fs-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;return new Promise((e,n)=>{this.fsResolvers.set(i,{resolve:e,reject:n,responses:[]}),this.pendingFsRoutes.set(i,{requesterBootstrapId:`__leader__`,requestId:i,chunks:[],totalChunks:1}),r.sync.send({type:`fs.request`,requestId:i,request:t})})}},QY=r(`tray-follower-sync`),$Y=class{sync;eventListeners=new Set;unsubscribe;keepalive;latestSnapshot=null;sentMessageIds=new Set;targetEntries=[];remoteTransports=new Map;cdpChunkBuffers=new Map;snapshotChunkBuffer=null;remoteCDPSessions=new Set;cdpEventCleanups=[];tabOpenResolvers=new Map;fsResolvers=new Map;constructor(e,t={}){this.options=t,this.sync=Se(e),this.unsubscribe=this.sync.onMessage(e=>{this.handleLeaderMessage(e)}),this.keepalive=new JY({sendPing:()=>this.sync.send({type:`ping`}),onDead:()=>{QY.warn(`Leader keepalive dead, cleaning up`),this.handleDisconnect(`Keepalive timeout — leader not responding`),this.options.onDead?.()}}),this.keepalive.start(),e.addEventListener(`close`,()=>{QY.warn(`Data channel closed`),this.handleDisconnect(`Data channel closed`)}),e.addEventListener(`error`,()=>{QY.warn(`Data channel error`),this.handleDisconnect(`Data channel error`)})}sendMessage(e,t){let n=t??`follower-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;this.sentMessageIds.add(n),this.sync.send({type:`user_message`,text:e,messageId:n}),QY.info(`Sent user message to leader`,{messageId:n})}onEvent(e){return this.eventListeners.add(e),()=>this.eventListeners.delete(e)}stop(){this.sync.send({type:`abort`}),QY.info(`Sent abort to leader`)}requestSnapshot(){this.sync.send({type:`request_snapshot`})}getLatestSnapshot(){return this.latestSnapshot}close(){this.keepalive.stop(),this.unsubscribe(),this.sync.close(),this.eventListeners.clear(),this.cleanupCDPEventForwarding(),QY.info(`Follower sync closed`)}advertiseTargets(e,t){this.sync.send({type:`targets.advertise`,targets:e,runtimeId:t})}getTargets(){return this.targetEntries}disconnected=!1;handleDisconnect(e){this.disconnected||(this.disconnected=!0,p({...h(),state:`error`,error:e}),this.emitEvent({type:`error`,error:`Connection to leader lost: ${e}`}),this.keepalive.stop(),this.cleanupCDPEventForwarding(),this.unsubscribe(),this.sync.close(),this.options.onDisconnect?.(e))}handleLeaderMessage(e){switch(e.type){case`snapshot`:QY.info(`Snapshot received from leader`,{messageCount:e.messages.length,scoopJid:e.scoopJid}),this.snapshotChunkBuffer=null,this.latestSnapshot={messages:e.messages,scoopJid:e.scoopJid},this.options.onSnapshot?.(e.messages,e.scoopJid);break;case`snapshot_chunk`:{let t=M(this.snapshotChunkBuffer,e);this.snapshotChunkBuffer=t.buffer,t.result&&(QY.info(`Chunked snapshot reassembled from leader`,{messageCount:t.result.messages.length,scoopJid:t.result.scoopJid}),this.latestSnapshot=t.result,this.options.onSnapshot?.(t.result.messages,t.result.scoopJid));break}case`agent_event`:this.emitEvent(e.event);break;case`user_message_echo`:if(this.sentMessageIds.has(e.messageId)){this.sentMessageIds.delete(e.messageId),QY.debug(`Skipping own message echo`,{messageId:e.messageId});break}QY.info(`User message echo received`,{messageId:e.messageId,scoopJid:e.scoopJid}),this.options.onUserMessage?.(e.text,e.messageId,e.scoopJid);break;case`status`:this.options.onStatus?.(e.scoopStatus);break;case`error`:QY.warn(`Error from leader`,{error:e.error}),this.emitEvent({type:`error`,error:e.error});break;case`targets.registry`:QY.info(`Target registry received from leader`,{targetCount:e.targets.length}),this.targetEntries=e.targets,this.options.onTargetsUpdated?.(this.targetEntries);break;case`cdp.request`:{let{requestId:t,localTargetId:n,method:r,params:i,sessionId:a}=e;this.executeLocalCDP(t,n,r,i,a);break}case`cdp.response`:this.routeCDPResponse(e);break;case`cdp.event`:for(let t of this.remoteTransports.values())t.handleEvent(e.method,e.params);break;case`tab.open`:this.executeLocalTabOpen(e.requestId,e.url);break;case`tab.opened`:{let t=this.tabOpenResolvers.get(e.requestId);t&&(this.tabOpenResolvers.delete(e.requestId),t.resolve(e.targetId));break}case`tab.open.error`:{let t=this.tabOpenResolvers.get(e.requestId);t&&(this.tabOpenResolvers.delete(e.requestId),t.reject(Error(e.error)));break}case`fs.request`:this.executeLocalFs(e.requestId,e.request);break;case`fs.response`:this.routeFsResponse(e.requestId,e.response);break;case`ping`:this.keepalive.receivePing(),this.sync.send({type:`pong`});break;case`pong`:this.keepalive.receivePong(),u(Date.now());break}}emitEvent(e){for(let t of this.eventListeners)try{t(e)}catch(t){QY.error(`Listener error`,{eventType:e.type,error:t instanceof Error?t.message:String(t)})}}createRemoteTransport(e,t){let n=new j({sendCDPRequest:(n,r,i,a)=>{this.sync.send({type:`cdp.request`,requestId:n,targetRuntimeId:e,localTargetId:t,method:r,params:i,sessionId:a})}});return this.remoteTransports.set(`${e}:${t}`,n),n}removeRemoteTransport(e,t){let n=`${e}:${t}`,r=this.remoteTransports.get(n);r&&(r.disconnect(),this.remoteTransports.delete(n))}openRemoteTab(e,t){let n=`tab-open-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;return new Promise((r,i)=>{this.tabOpenResolvers.set(n,{resolve:r,reject:i}),this.sync.send({type:`tab.open`,requestId:n,targetRuntimeId:e,url:t})})}async executeLocalTabOpen(e,t){let n=this.options.browserTransport;if(!n){this.sync.send({type:`tab.open.error`,requestId:e,error:`Follower has no browser transport`});return}try{let r=(await n.send(`Target.createTarget`,{url:t,background:!0})).targetId;this.sync.send({type:`tab.opened`,requestId:e,targetId:r}),this.options.onTargetsChanged?.()}catch(t){this.sync.send({type:`tab.open.error`,requestId:e,error:t instanceof Error?t.message:String(t)})}}async executeLocalCDP(e,t,n,r,i){let a=this.options.browserTransport;if(!a){this.sync.send({type:`cdp.response`,requestId:e,error:`Follower has no browser transport`});return}try{let t=await a.send(n,r,i);if(n===`Target.attachToTarget`&&t.sessionId){let e=t.sessionId;this.remoteCDPSessions.add(e),this.setupCDPEventForwarding(a,e),QY.debug(`Tracking remote CDP session`,{remoteSessionId:e})}n===`Target.detachFromTarget`&&i&&this.remoteCDPSessions.has(i)&&(this.remoteCDPSessions.delete(i),QY.debug(`Removed remote CDP session on detach`,{sessionId:i})),Ce(this.sync,e,t)}catch(t){this.sync.send({type:`cdp.response`,requestId:e,error:t instanceof Error?t.message:String(t)})}}setupCDPEventForwarding(e,t){for(let n of[`Page.frameNavigated`,`Page.loadEventFired`,`Page.domContentEventFired`,`Network.responseReceived`,`Network.loadingFinished`,`Network.requestWillBeSent`]){let r=e=>{if(e.sessionId!==t||!this.remoteCDPSessions.has(t))return;let{sessionId:r,...i}=e;this.sync.send({type:`cdp.event`,method:n,params:i,sessionId:t})};e.on(n,r),this.cdpEventCleanups.push(()=>e.off(n,r))}}cleanupCDPEventForwarding(){for(let e of this.cdpEventCleanups)e();this.cdpEventCleanups.length=0,this.remoteCDPSessions.clear()}routeCDPResponse(e){let t=_e(this.cdpChunkBuffers,e);if(t)for(let n of this.remoteTransports.values())n.handleResponse(e.requestId,t.result,t.error)}async executeLocalFs(e,t){let n=this.options.vfs;if(!n){this.sync.send({type:`fs.response`,requestId:e,response:{ok:!1,error:`Follower has no VFS`}});return}let r=await NY(n,t);for(let t of r)this.sync.send({type:`fs.response`,requestId:e,response:t})}routeFsResponse(e,t){let n=this.fsResolvers.get(e);if(!n)return;n.responses.push(t);let r=t.ok&&t.totalChunks||1;n.responses.length>=r&&(this.fsResolvers.delete(e),n.resolve(n.responses))}sendFsRequest(e,t){let n=`fs-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;return new Promise((r,i)=>{this.fsResolvers.set(n,{resolve:r,reject:i,responses:[]}),this.sync.send({type:`fs.request`,requestId:n,targetRuntimeId:e,request:t})})}};function eX(e,t){if(t)return`extension`;try{return rX(new URL(e))?`electron-overlay`:`standalone`}catch{return`standalone`}}function tX(e,t){return e===`electron-overlay`||e===`standalone`&&t}function nX(e){try{let t=new URL(e).searchParams.get(`tab`);return t&&Vi(t)?t:zi}catch{return zi}}function rX(e){return e.pathname===`/electron`||e.pathname===`/electron/`||e.searchParams.get(`runtime`)===`electron-overlay`}function iX(e){let t=new URL(e);return`${t.protocol===`https:`?`wss:`:`ws:`}//${t.host}/licks-ws`}function aX(e,t){return`${new URL(e).origin}/webhooks/${t}`}function oX(e,t){return`${e.replace(/\/+$/,``)}/${t.replace(/^\/+/,``)}`}function sX(e){return typeof e==`object`&&!!e&&`type`in e&&e.type===`slicc-electron-overlay:set-tab`}var cX=[`/shared/sprinkles`];async function lX(e){let t=new Map;for(let n of cX)await e.exists(n)&&await uX(e,n,t);return await uX(e,`/`,t),t}async function uX(e,t,n){for await(let r of e.walk(t)){if(!r.endsWith(`.shtml`))continue;let t=dX(r);if(!n.has(t)){let i;try{i=await e.readFile(r,{encoding:`utf-8`})??``}catch{i=``}n.set(t,{name:t,path:r,title:fX(i,t),autoOpen:pX(i)})}}}function dX(e){let t=e.split(`/`).pop()??e;return t.endsWith(`.shtml`)?t.slice(0,-6):t}function fX(e,t){let n=e.match(/data-sprinkle-title=["']([^"']+)["']/);if(n)return n[1];let r=e.match(/<title>([^<]+)<\/title>/i);return r?r[1].trim():t}function pX(e){return/data-sprinkle-autoopen\b/.test(e)}var mX=class{listeners=new Map;lickHandler;fs;closeHandler;constructor(e,t,n){this.fs=e,this.lickHandler=t,this.closeHandler=n}createAPI(e){return{name:e,lick:t=>{let n=typeof t==`string`?t:t.action,r=typeof t==`string`?void 0:t.data,i={type:`sprinkle`,sprinkleName:e,targetScoop:void 0,timestamp:new Date().toISOString(),body:{action:n,data:r}};this.lickHandler(i)},on:(t,n)=>{let r=`${e}:${t}`,i=this.listeners.get(r);i||(i=new Set,this.listeners.set(r,i)),i.add(n)},off:(t,n)=>{let r=`${e}:${t}`;this.listeners.get(r)?.delete(n)},readFile:async e=>await this.fs.readFile(e,{encoding:`utf-8`}),setState:t=>{try{localStorage.setItem(`slicc-sprinkle-state:${e}`,JSON.stringify(t))}catch{}},getState:()=>{try{let t=localStorage.getItem(`slicc-sprinkle-state:${e}`);return t?JSON.parse(t):null}catch{return null}},open:e=>{let t=/^https?:|^chrome-extension:/.test(e)?e:HW(e);window.open(t,`_blank`)},close:()=>this.closeHandler(e)}}pushUpdate(e,t){let n=`${e}:update`,r=this.listeners.get(n);if(r)for(let e of r)try{e(t)}catch{}}removeSprinkle(e){for(let t of this.listeners.keys())t.startsWith(`${e}:`)&&this.listeners.delete(t)}},hX=r(`sprinkle-manager`),gX=`slicc-open-sprinkles`,_X=class{fs;bridge;callbacks;availableSprinkles=new Map;openSprinkles=new Map;constructor(e,t,n){this.fs=e,this.bridge=new mX(e,t,e=>this.close(e)),this.callbacks=n}async restoreOpenSprinkles(){try{let e=localStorage.getItem(gX);if(!e){for(let e of this.availableSprinkles.values())if(e.autoOpen)try{await this.open(e.name)}catch{hX.warn(`Failed to auto-open sprinkle`,{name:e.name})}return}let t=JSON.parse(e);for(let e of t)try{await this.open(e)}catch{hX.warn(`Failed to restore sprinkle`,{name:e})}}catch{}}persistOpenSprinkles(){try{localStorage.setItem(gX,JSON.stringify([...this.openSprinkles.keys()]))}catch{}}async openNewAutoOpenSprinkles(){await this.refresh();for(let e of this.availableSprinkles.values())if(e.autoOpen&&!this.openSprinkles.has(e.name))try{await this.open(e.name),hX.info(`Auto-opened new sprinkle after install`,{name:e.name})}catch{hX.warn(`Failed to auto-open new sprinkle`,{name:e.name})}}async refresh(){this.availableSprinkles=await lX(this.fs),hX.info(`Discovered sprinkles`,{count:this.availableSprinkles.size})}async open(e,t){if(this.openSprinkles.has(e)){hX.info(`Sprinkle already open`,{name:e});return}let n=this.availableSprinkles.get(e);if(n||=(await this.refresh(),this.availableSprinkles.get(e)),!n)throw Error(`Sprinkle not found: ${e}`);let r=await this.fs.readFile(n.path,{encoding:`utf-8`}),i=document.createElement(`div`);i.className=`sprinkle-panel`,i.style.cssText=`width: 100%; height: 100%; display: flex; flex-direction: column; overflow: hidden;`,i.dataset.sprinkle=e,this.openSprinkles.set(e,{renderer:null,container:i}),this.callbacks.addSprinkle(e,n.title,i,t);let a=new $r(i,this.bridge.createAPI(e));await a.render(r,e),this.openSprinkles.get(e).renderer=a,this.persistOpenSprinkles(),qq(e),hX.info(`Sprinkle opened`,{name:e,title:n.title})}close(e){let t=this.openSprinkles.get(e);t&&(t.renderer?.dispose(),t.container.remove(),this.bridge.removeSprinkle(e),this.openSprinkles.delete(e),this.callbacks.removeSprinkle(e),this.persistOpenSprinkles(),hX.info(`Sprinkle closed`,{name:e}))}available(){return Array.from(this.availableSprinkles.values())}opened(){return Array.from(this.openSprinkles.keys())}sendToSprinkle(e,t){let n=this.openSprinkles.get(e);if(!n){hX.warn(`Cannot send to closed sprinkle`,{name:e});return}this.bridge.pushUpdate(e,t),n.renderer.pushUpdate(t)}},vX=r(`main`),yX=`slicc-pending-mount`,bX=`pendingMount`;async function xX(e){let t=await new Promise((e,t)=>{let n=indexedDB.open(yX,1);n.onupgradeneeded=()=>n.result.createObjectStore(`handles`),n.onsuccess=()=>e(n.result),n.onerror=()=>t(n.error)}),n=t.transaction(`handles`,`readwrite`);n.objectStore(`handles`).put(e,bX),await new Promise(e=>n.oncomplete=()=>e()),t.close()}async function SX(e){let t;try{t=await new Promise((e,t)=>{let n=indexedDB.open(yX,1);n.onsuccess=()=>e(n.result),n.onerror=()=>t(n.error)})}catch{return}let n=t.transaction(`handles`,`readwrite`),r=await new Promise(e=>{let t=n.objectStore(`handles`).get(bX);t.onsuccess=()=>e(t.result),t.onerror=()=>e(void 0)});if(r){n.objectStore(`handles`).delete(bX),await new Promise(e=>n.oncomplete=()=>e());let t=`/mnt/${r.name}`;await e.mount(t,r),vX.info(`Mounted folder from welcome onboarding`,{name:r.name,path:t})}t.close()}function CX(){let e=document.createElement(`div`);e.className=`skill-drop-overlay`;let t=document.createElement(`div`);t.className=`skill-drop-overlay__card`;let n=document.createElement(`div`);n.className=`skill-drop-overlay__title`,t.appendChild(n);let r=document.createElement(`div`);return r.className=`skill-drop-overlay__desc`,t.appendChild(r),e.appendChild(t),document.body.appendChild(e),{show(t,i){n.textContent=t,r.textContent=i,e.classList.add(`skill-drop-overlay--visible`)},hide(){e.classList.remove(`skill-drop-overlay--visible`)}}}function wX(){let e=document.createElement(`div`);return e.className=`skill-drop-toast-container`,document.body.appendChild(e),(t,n)=>{let r=document.createElement(`div`);r.className=`skill-drop-toast skill-drop-toast--${n}`,r.textContent=t,e.appendChild(r),requestAnimationFrame(()=>r.classList.add(`skill-drop-toast--visible`)),window.setTimeout(()=>{r.classList.remove(`skill-drop-toast--visible`),window.setTimeout(()=>r.remove(),180)},4200)}}function TX(e,t,n){let r=CX(),i=0,a=!1,o=()=>{i=0,a||r.hide()};window.addEventListener(`dragenter`,e=>{la(e.dataTransfer)&&(e.preventDefault(),i+=1,a||r.show(`Drop .skill to install`,`Unpack into /workspace/skills/{name}.`))}),window.addEventListener(`dragover`,e=>{la(e.dataTransfer)&&(e.preventDefault(),e.dataTransfer&&(e.dataTransfer.dropEffect=`copy`),a||r.show(`Drop .skill to install`,`Unpack into /workspace/skills/{name}.`))}),window.addEventListener(`dragleave`,()=>{i!==0&&(i=Math.max(0,i-1),i===0&&!a&&r.hide())}),window.addEventListener(`dragend`,o),window.addEventListener(`blur`,o),window.addEventListener(`drop`,async s=>{let c=ua(s.dataTransfer);if(!c){o();return}if(s.preventDefault(),i=0,a){r.hide(),t(`Another .skill installation is already in progress.`,`error`);return}a=!0,r.show(`Installing skill…`,c.name);try{let r=await he(e,c);await n(),t(`Installed "${r.skillName}" to ${r.destinationPath} (${r.fileCount} files). Run "skill install ${r.skillName}" to apply it.`,`success`)}catch(e){t(`Failed to install dropped skill: ${e instanceof Error?e.message:String(e)}`,`error`)}finally{a=!1,r.hide()}})}async function EX(e){let{OffscreenClient:t}=await y(async()=>{let{OffscreenClient:e}=await import(`./offscreen-client-ABShEPNe.js`);return{OffscreenClient:e}},__vite__mapDeps([20,13])),{VirtualFS:n}=await y(async()=>{let{VirtualFS:e}=await import(`./fs-f8JZDPIF.js`).then(e=>e.t);return{VirtualFS:e}},__vite__mapDeps([17,1])),r=new Ki(e,!0);window.__slicc_debug_tabs=e=>r.setDebugTabs(e),await r.panels.chat.initSession(`session-cone`);let i=null,a=await n.create({dbName:`slicc-fs`});r.panels.fileBrowser.setFs(a),vX.info(`File browser wired to shared VFS (local IndexedDB)`);let o=new BroadcastChannel(`preview-vfs`);o.onmessage=e=>{if(e.data?.type!==`preview-vfs-read`)return;let{id:t,path:n,asText:r}=e.data;(async()=>{try{let e=r?`utf-8`:`binary`,i=await a.readFile(n,{encoding:e});o.postMessage({type:`preview-vfs-response`,id:t,content:i})}catch(e){let r=e instanceof Error?e.message:String(e);r.includes(`ENOENT`)||vX.error(`Preview VFS read failed`,{path:n,error:r}),o.postMessage({type:`preview-vfs-response`,id:t,error:r})}})()},TX(a,wX(),async()=>{await r.panels.fileBrowser.refresh()});try{let{WasmShell:e}=await y(async()=>{let{WasmShell:e}=await import(`./shell-DAALhTM2.js`);return{WasmShell:e}},[]),{PanelCdpProxy:t,BrowserAPI:n}=await y(async()=>{let{PanelCdpProxy:e,BrowserAPI:t}=await import(`./cdp-DNK51gjc.js`).then(e=>e.t);return{PanelCdpProxy:e,BrowserAPI:t}},__vite__mapDeps([21,1,4,13])),i=new t;await i.connect();let o=new e({fs:a,browserAPI:new n(i)});await r.panels.terminal.mountShell(o),vX.info(`Terminal mounted with shared VFS and BrowserAPI (CDP proxy)`)}catch(e){vX.warn(`Failed to mount shell to terminal`,e)}let s,c=new Set,l=async e=>{i=e,s.selectedScoopJid=e.jid,r.panels.memory.setSelectedScoop(e.jid),r.setScoopSwitcherSelected?.(e.jid),r.panels.scoops.setSelectedJid(e.jid);let t=e.isCone?`session-cone`:`session-${e.folder}`,n=e.isCone?void 0:e.name;await r.panels.chat.switchToContext(t,!e.isCone,n),s.isProcessing(e.jid)&&r.panels.chat.setProcessing(!0)};s=new t({onStatusChange:(e,t)=>{r.panels.scoops.updateScoopStatus(e,t),r.updateScoopSwitcherStatus?.(e,t),i?.jid===e&&(r.setAgentProcessing(t===`processing`),t===`processing`?r.panels.chat.setProcessing(!0):t===`ready`&&r.panels.chat.setProcessing(!1))},onScoopCreated:e=>{r.panels.scoops.refreshScoops(),r.refreshScoopSwitcher?.(),i||(i=e,s.selectedScoopJid=e.jid,r.panels.memory.setSelectedScoop(e.jid))},onScoopListUpdate:()=>{let e=new Set(s.getScoops().map(e=>e.folder));for(let t of c)e.has(t)||r.panels.chat.deleteSessionById(`session-${t}`);if(c=e,r.panels.scoops.refreshScoops(),r.refreshScoopSwitcher?.(),!i){let e=s.getScoops().find(e=>e.isCone);e&&(i=e,s.selectedScoopJid=e.jid,r.panels.memory.setSelectedScoop(e.jid))}},onIncomingMessage:(e,t)=>{if(i?.jid===e){let e=t.channel===`delegation`?`**[Instructions from sliccy]**\n\n${t.content}`:t.content;r.panels.chat.addUserMessage(e)}},onReady:async()=>{try{vX.info(`Offscreen engine ready, scoop count:`,s.getScoops().length),window.localStorage.getItem(`slicc.trayJoinUrl`)&&chrome.runtime.sendMessage({source:`panel`,payload:{type:`refresh-tray-runtime`}}).catch(()=>{});let e=i??s.getScoops().find(e=>e.isCone)??s.getScoops()[0];e&&(i=e,s.selectedScoopJid=e.jid,await l(e))}catch(e){vX.error(`Failed to initialize on ready`,{error:e instanceof Error?e.message:String(e)})}}}),s.setLocalFS(a);let u=s.createAgentHandle();r.panels.chat.setAgent(u),r.panels.scoops.setOrchestrator(s),r.panels.memory.setOrchestrator(s),r.setScoopSwitcherOrchestrator?.(s),r.onScoopSelect=l,r.onModelChange=e=>{localStorage.setItem(`selected-model`,e),s.updateModel()},r.onClearChat=async()=>{let e=s.getScoops();for(let t of e){let e=t.isCone?`session-cone`:`session-${t.folder}`;await r.panels.chat.deleteSessionById(e)}s.clearAllMessages()},r.onClearFilesystem=async()=>{s.clearFilesystem()},r.panels.chat.onInlineSprinkleLick=(e,t)=>{s.sendSprinkleLick(`inline`,{action:e,data:t})};let d=new _X(a,async e=>{if(e.type===`sprinkle`){if(e.sprinkleName===`welcome`&&e.body?.action===`onboarding-complete`&&(localStorage.setItem(`slicc-welcomed`,`1`),e.body?.data?.mountWorkspace&&SX(a).catch(e=>vX.warn(`Failed to mount workspace from onboarding`,e))),e.sprinkleName===`welcome`&&e.body?.action===`request-mount`){try{let e=window;if(!e.showDirectoryPicker)throw Error(`showDirectoryPicker not supported`);let t=await e.showDirectoryPicker({mode:`readwrite`});await xX(t),d.sendToSprinkle(`welcome`,{action:`mount-complete`,dirName:t.name})}catch(e){e.name!==`AbortError`&&vX.warn(`Mount picker failed`,e),d.sendToSprinkle(`welcome`,{action:`mount-cancelled`})}return}s.sendSprinkleLick(e.sprinkleName,e.body)}},{addSprinkle:(e,t,n,i)=>r.addSprinkle(e,t,n,i),removeSprinkle:e=>r.removeSprinkle(e)});if(window.__slicc_sprinkleManager=d,window.__slicc_reloadSkills=()=>(chrome.runtime.sendMessage({source:`panel`,payload:{type:`reload-skills`}}),Promise.resolve()),s.setSprinkleOpHandler(e=>{let{id:t,op:n,name:r,data:i}=e;console.log(`[main-ext] sprinkle-op handler called`,{id:t,op:n,name:r}),(async()=>{try{let e;switch(n){case`list`:await d.refresh(),e=d.available();break;case`opened`:e=d.opened();break;case`refresh`:await d.refresh(),e=d.available().length;break;case`open`:await d.open(r),e=!0;break;case`close`:d.close(r),e=!0;break;case`send`:d.sendToSprinkle(r,i),e=!0;break;case`openNewAutoOpen`:await d.openNewAutoOpenSprinkles(),e=!0;break}console.log(`[main-ext] sprinkle-op response sending`,{id:t,op:n,result:typeof e}),chrome.runtime.sendMessage({source:`panel`,payload:{type:`sprinkle-op-response`,id:t,result:e}}).catch(()=>{})}catch(e){chrome.runtime.sendMessage({source:`panel`,payload:{type:`sprinkle-op-response`,id:t,error:e instanceof Error?e.message:String(e)}}).catch(()=>{})}})()}),await d.refresh(),r.onSprinkleClose=e=>d.close(e),r.getAvailableSprinkles=()=>{let e=new Set(d.opened());return d.available().filter(t=>!e.has(t.name)).map(e=>({name:e.name,title:e.title}))},r.onOpenSprinkle=(e,t)=>d.open(e,t),r.updateAddButtons(),await d.restoreOpenSprinkles(),!localStorage.getItem(`slicc-welcomed`)&&d.available().some(e=>e.name===`welcome`))try{await d.open(`welcome`)}catch(e){vX.warn(`Failed to open welcome sprinkle`,e)}vX.info(`SprinkleManager initialized (extension mode)`),s.requestState(),vX.info(`Extension UI connected to offscreen agent engine`),Wq().catch(()=>{})}async function DX(){Qi(),oa();let e=document.getElementById(`app`);if(!e)throw Error(`#app element not found`);`serviceWorker`in navigator&&navigator.serviceWorker.register(`/preview-sw.js`,{scope:`/preview/`}).then(()=>vX.info(`Preview SW registered`)).catch(e=>vX.error(`Preview SW registration failed — preview feature will not work`,e)),te();let t=E(),n=c(window.localStorage);!t&&!n&&(await w({preferTrayJoin:!(window.location.port===`5710`||window.location.port===`3000`||window.location.port===``)}),t=E());let r=!t&&c(window.localStorage),a=typeof chrome<`u`&&!!chrome?.runtime?.id,o=eX(window.location.href,a);if(o===`extension`)return EX(e);let l=new Ki(e,o===`electron-overlay`);if(o===`electron-overlay`){let e=nX(window.location.href);l.setActiveTab(e);let t=document.createElement(`style`);t.id=`slicc-electron-overlay-runtime-style`,t.textContent=`
14102
+ ---`);let a=ZJ(n);return a&&(i+=a),i}},aY=r(`scheduler`),oY=class{callbacks;pollInterval=null;running=!1;constructor(e){this.callbacks=e}start(){this.running||(this.running=!0,this.pollInterval=window.setInterval(()=>this.checkTasks(),6e4),this.checkTasks(),aY.info(`Scheduler started`))}stop(){this.pollInterval&&=(clearInterval(this.pollInterval),null),this.running=!1,aY.info(`Scheduler stopped`)}async createTask(e,t,n,r){let i={id:`task-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,groupFolder:e,prompt:t,scheduleType:n,scheduleValue:r,status:`active`,nextRun:this.calculateNextRun(n,r),lastRun:null,createdAt:new Date().toISOString()};return await I(i),aY.info(`Task created`,{id:i.id,groupFolder:e,scheduleType:n}),i}async updateTask(e,t){let n=await Me(e);if(!n)return null;let r={...n,...t};return(t.scheduleType||t.scheduleValue)&&(r.nextRun=this.calculateNextRun(r.scheduleType,r.scheduleValue)),await I(r),aY.info(`Task updated`,{id:e,updates:Object.keys(t)}),r}async pauseTask(e){return await this.updateTask(e,{status:`paused`})!==null}async resumeTask(e){return await Me(e)?(await this.updateTask(e,{status:`active`}),!0):!1}async deleteTask(e){return await Me(e)?(await N(e),aY.info(`Task deleted`,{id:e}),!0):!1}async getTasksByScoop(e){return(await je()).filter(t=>t.groupFolder===e)}async getAllTasks(){return je()}async checkTasks(){let e=await je(),t=new Date;for(let n of e)n.status===`active`&&n.nextRun&&(new Date(n.nextRun)>t||await this.runTask(n))}async runTask(e){let t=this.callbacks.getScoop(e.groupFolder);if(!t){aY.warn(`Task scoop not found`,{taskId:e.id,groupFolder:e.groupFolder});return}aY.info(`Running task`,{id:e.id,groupFolder:e.groupFolder});try{let n=new Date().toISOString(),r=this.calculateNextRun(e.scheduleType,e.scheduleValue),i=e.scheduleType===`once`?`completed`:e.status;await I({...e,lastRun:n,nextRun:r,status:i}),await this.callbacks.onTaskRun(e,t),aY.info(`Task completed`,{id:e.id})}catch(t){aY.error(`Task execution failed`,{id:e.id,error:t instanceof Error?t.message:String(t)})}}calculateNextRun(e,t){let n=new Date;switch(e){case`cron`:return this.getNextCronTime(t,n)?.toISOString()??null;case`interval`:{let e=parseInt(t,10);return isNaN(e)||e<=0?null:new Date(n.getTime()+e).toISOString()}case`once`:return new Date(t)>n?t:null;default:return null}}getNextCronTime(e,t){let n=e.trim().split(/\s+/);if(n.length!==5)return null;let[r,i,a,o,s]=n,c=new Date(t);c.setSeconds(0),c.setMilliseconds(0),c.setMinutes(c.getMinutes()+1);for(let e=0;e<527040;e++){if(this.cronMatches(c,r,i,a,o,s))return c;c.setMinutes(c.getMinutes()+1)}return null}cronMatches(e,t,n,r,i,a){return this.cronFieldMatches(e.getMinutes(),t)&&this.cronFieldMatches(e.getHours(),n)&&this.cronFieldMatches(e.getDate(),r)&&this.cronFieldMatches(e.getMonth()+1,i)&&this.cronFieldMatches(e.getDay(),a)}cronFieldMatches(e,t){if(t===`*`)return!0;if(t.includes(`,`))return t.split(`,`).some(t=>this.cronFieldMatches(e,t.trim()));if(t.includes(`-`)){let[n,r]=t.split(`-`).map(e=>parseInt(e,10));return e>=n&&e<=r}if(t.includes(`/`)){let[n,r]=t.split(`/`),i=parseInt(r,10);if(n===`*`)return e%i===0;let a=parseInt(n,10);return e>=a&&(e-a)%i===0}return parseInt(t,10)===e}},sY=r(`lick-manager`),cY=class{webhooks=new Map;crontasks=new Map;cronInterval=null;eventHandler=null;async init(){await ke();let e=await ze();for(let t of e)this.webhooks.set(t.id,t);sY.info(`Loaded webhooks`,{count:this.webhooks.size});let t=await Le();for(let e of t)this.crontasks.set(e.id,e);sY.info(`Loaded crontasks`,{count:this.crontasks.size}),this.cronInterval=setInterval(()=>this.runCronScheduler(),6e4),sY.info(`Cron scheduler started`)}dispose(){this.cronInterval&&=(clearInterval(this.cronInterval),null)}setEventHandler(e){this.eventHandler=e}async createWebhook(e,t,n){let r=this.generateId(),i={id:r,name:e,createdAt:new Date().toISOString(),filter:n,scoop:t};return n&&this.compileFilter(n,!0),this.webhooks.set(r,i),await Ee(i),sY.info(`Webhook created`,{id:r,name:e,scoop:t}),i}async deleteWebhook(e){return this.webhooks.has(e)?(this.webhooks.delete(e),await Pe(e),sY.info(`Webhook deleted`,{id:e}),!0):!1}listWebhooks(){return Array.from(this.webhooks.values())}getWebhook(e){return this.webhooks.get(e)}handleWebhookEvent(e,t,n){let r=this.webhooks.get(e);if(!r){sY.warn(`Webhook not found`,{webhookId:e});return}let i={type:`webhook`,webhookId:e,webhookName:r.name,targetScoop:r.scoop,timestamp:new Date().toISOString(),headers:t,body:n};if(r.filter)try{let t=this.compileFilter(r.filter,!0)(i);if(t===!1){sY.debug(`Webhook event dropped by filter`,{webhookId:e,name:r.name});return}typeof t==`object`&&t&&(i=t)}catch(t){sY.error(`Webhook filter error`,{webhookId:e,error:t instanceof Error?t.message:String(t)})}sY.info(`Webhook event received`,{webhookId:e,name:r.name,targetScoop:r.scoop}),this.eventHandler?.(i)}async createCronTask(e,t,n,r){let i=this.getNextCronTime(t,new Date);if(!i)throw Error(`Invalid cron expression`);r&&this.compileFilter(r,!1);let a=this.generateId(),o={id:a,name:e,cron:t,scoop:n,filter:r,nextRun:i.toISOString(),lastRun:null,status:`active`,createdAt:new Date().toISOString()};return this.crontasks.set(a,o),await Oe(o),sY.info(`Cron task created`,{id:a,name:e,cron:t,scoop:n}),o}async deleteCronTask(e){return this.crontasks.has(e)?(this.crontasks.delete(e),await Ne(e),sY.info(`Cron task deleted`,{id:e}),!0):!1}listCronTasks(){return Array.from(this.crontasks.values())}getCronTask(e){return this.crontasks.get(e)}getLicksForScoop(e,t){let n=n=>n===e||n===t||`${n}-scoop`===t;return{webhooks:Array.from(this.webhooks.values()).filter(e=>n(e.scoop)),cronTasks:Array.from(this.crontasks.values()).filter(e=>n(e.scoop))}}async runCronScheduler(){let e=new Date;for(let t of this.crontasks.values()){if(t.status!==`active`||!t.nextRun||new Date(t.nextRun)>e)continue;let n={time:e.toISOString()};if(t.filter)try{let r=this.compileFilter(t.filter,!1)(null);if(r===!1){sY.debug(`Cron task skipped by filter`,{id:t.id,name:t.name}),t.nextRun=this.getNextCronTime(t.cron,e)?.toISOString()??null,t.lastRun=e.toISOString(),await Oe(t);continue}typeof r==`object`&&r&&(n=r)}catch(e){sY.error(`Cron filter error`,{id:t.id,error:e instanceof Error?e.message:String(e)})}let r={type:`cron`,cronId:t.id,cronName:t.name,targetScoop:t.scoop,timestamp:e.toISOString(),body:n};sY.info(`Cron task running`,{id:t.id,name:t.name}),this.eventHandler?.(r),t.nextRun=this.getNextCronTime(t.cron,e)?.toISOString()??null,t.lastRun=e.toISOString(),await Oe(t)}}generateId(){let e=``;for(let t=0;t<12;t++)e+=`abcdefghijklmnopqrstuvwxyz0123456789`[Math.floor(Math.random()*36)];return e}compileFilter(e,t){try{return t?Function(`event`,`return (${e})(event);`):Function(`return (${e})();`)}catch(e){throw Error(`Invalid filter function: ${e instanceof Error?e.message:String(e)}`)}}getNextCronTime(e,t){let n=e.trim().split(/\s+/);if(n.length!==5)return null;let[r,i,a,o,s]=n,c=new Date(t);c.setSeconds(0),c.setMilliseconds(0),c.setMinutes(c.getMinutes()+1);let l=(e,t)=>{if(t===`*`)return!0;if(t.includes(`,`))return t.split(`,`).some(t=>l(e,t.trim()));if(t.includes(`-`)){let[n,r]=t.split(`-`).map(e=>parseInt(e,10));return e>=n&&e<=r}if(t.includes(`/`)){let[n,r]=t.split(`/`),i=parseInt(r,10);if(n===`*`)return e%i===0;let a=parseInt(n,10);return e>=a&&(e-a)%i===0}return parseInt(t,10)===e};for(let e=0;e<527040;e++){if(l(c.getMinutes(),r)&&l(c.getHours(),i)&&l(c.getDate(),a)&&l(c.getMonth()+1,o)&&l(c.getDay(),s))return c;c.setMinutes(c.getMinutes()+1)}return null}};function lY(e,t,n){if(t.length===0&&n.length===0)return null;let r=[];t.length>0&&r.push(`${t.length} active webhook${t.length>1?`s`:``}`),n.length>0&&r.push(`${n.length} active cron task${n.length>1?`s`:``}`);let i=[...t.map(e=>` webhook delete ${e.id}`),...n.map(e=>` crontask delete ${e.id}`)].join(`
14103
+ `);return Error(`Cannot remove scoop '${e}': it has ${r.join(` and `)}. Unregister them first:\n${i}`)}var uY=null;function dY(){return uY||=new cY,uY}var fY=r(`orchestrator`),pY=class{scoops=new Map;tabs=new Map;contexts=new Map;messageQueues=new Map;lastAgentTimestamp=new Map;container;callbacks;config;pollInterval=null;scheduler=null;globalMemoryCache=``;sharedFs=null;scoopResponseBuffer=new Map;lickManager=null;sessionStore=null;constructor(e,t,n={name:`sliccy`,triggerPattern:/^@sliccy\b/i}){this.container=e,this.callbacks=t,this.config=n}async init(){await ke(),this.sharedFs=await A.create({dbName:`slicc-fs`}),this.sessionStore=new C,await this.ensureRootStructure();let e=await P();for(let t of Object.values(e)){t.isCone&&(t.trigger=void 0,t.requiresTrigger=!1,t.assistantLabel=t.assistantLabel||`sliccy`),this.scoops.set(t.jid,t),this.messageQueues.set(t.jid,[]);let e=await Fe(`lastAgentTs_${t.jid}`);e&&this.lastAgentTimestamp.set(t.jid,e)}await this.ensureGlobalMemory(),this.scheduler=new oY({onTaskRun:async(e,t)=>{fY.info(`Running scheduled task`,{taskId:e.id,scoop:t.name}),await this.sendPrompt(t.jid,`[SCHEDULED TASK]\n\n${e.prompt}`,`scheduler`,`Scheduled Task`)},getScoop:e=>{for(let t of this.scoops.values())if(t.folder===e)return t}}),this.scheduler.start(),fY.info(`Orchestrator initialized`,{scoopCount:this.scoops.size});for(let e of this.scoops.values())await this.createScoopTab(e.jid);this.startMessageLoop()}async ensureRootStructure(){if(this.sharedFs)for(let e of[`/workspace`,`/shared`,`/scoops`,`/home`,`/tmp`,`/mnt`])try{await this.sharedFs.mkdir(e,{recursive:!0})}catch{}}async ensureGlobalMemory(){if(this.sharedFs){await $J(this.sharedFs);try{let e=await this.sharedFs.readFile(`/shared/CLAUDE.md`,{encoding:`utf-8`});this.globalMemoryCache=typeof e==`string`?e:new TextDecoder().decode(e)}catch{fY.warn(`Global memory file not found after creating defaults`)}}}async getGlobalMemory(){if(this.globalMemoryCache)return this.globalMemoryCache;if(this.sharedFs)try{let e=await this.sharedFs.readFile(`/shared/CLAUDE.md`,{encoding:`utf-8`});this.globalMemoryCache=typeof e==`string`?e:new TextDecoder().decode(e)}catch{}return this.globalMemoryCache}async setGlobalMemory(e){this.sharedFs&&(await this.sharedFs.writeFile(`/shared/CLAUDE.md`,e),this.globalMemoryCache=e,fY.info(`Global memory updated`))}getSharedFS(){return this.sharedFs}setLickManager(e){this.lickManager=e}async registerScoop(e){await Be(e),this.scoops.set(e.jid,e),this.messageQueues.set(e.jid,[]),fY.info(`Scoop registered`,{jid:e.jid,name:e.name}),this.createScoopTab(e.jid).catch(t=>{let n=t instanceof Error?t.message:String(t);fY.error(`Scoop init failed`,{jid:e.jid,error:n})})}async unregisterScoop(e){let t=this.scoops.get(e);if(t&&this.lickManager){let{webhooks:e,cronTasks:n}=this.lickManager.getLicksForScoop(t.name,t.folder),r=lY(t.folder,e,n);if(r)throw r}await this.destroyScoopTab(e),this.sessionStore?.delete(e).catch(t=>{fY.warn(`Failed to delete agent session`,{jid:e,error:t instanceof Error?t.message:String(t)})}),await Ae(e),this.scoops.delete(e),this.messageQueues.delete(e),this.lastAgentTimestamp.delete(e),fY.info(`Scoop unregistered`,{jid:e})}getScoops(){return Array.from(this.scoops.values())}getScoop(e){return this.scoops.get(e)}async resetFilesystem(){for(let[e,t]of this.contexts.entries())t.stop(),this.contexts.delete(e);this.sharedFs=await A.create({dbName:`slicc-fs`,wipe:!0}),await this.ensureRootStructure(),await this.ensureGlobalMemory(),await QJ(this.sharedFs).catch(e=>{fY.warn(`Failed to re-seed default skills`,{error:e instanceof Error?e.message:String(e)})}),fY.info(`Filesystem reset and defaults re-seeded`)}async clearAllMessages(){await Re(),this.sessionStore&&await this.sessionStore.clearAll().catch(e=>{fY.warn(`Failed to clear agent sessions`,{error:e instanceof Error?e.message:String(e)})});for(let e of this.contexts.values())e.clearMessages();this.lastAgentTimestamp.clear();for(let e of this.scoops.keys())this.messageQueues.set(e,[]);fY.info(`All messages cleared`)}async handleMessage(e){fY.info(`handleMessage`,{id:e.id,chatJid:e.chatJid,sender:e.senderName,channel:e.channel,contentPreview:e.content.slice(0,80)});let t=this.scoops.get(e.chatJid);Zq(t?.isCone?`cone`:t?.name??`unknown`,localStorage.getItem(`selected-model`)??`unknown`),await Te(e),await this.routeToScoop(e)}async delegateToScoop(e,t,n){let r=this.scoops.get(e);if(!r)throw Error(`Scoop not found: ${e}`);let i={id:`delegate-${Date.now()}-${Math.random().toString(36).slice(2)}`,chatJid:e,senderId:`cone`,senderName:n,content:t,timestamp:new Date().toISOString(),fromAssistant:!0,channel:`delegation`};await Te(i),this.callbacks.onIncomingMessage?.(e,i),fY.info(`Delegating to scoop`,{scoopJid:e,scoopName:r.name,promptLength:t.length}),this.sendPrompt(e,t,`cone`,n).catch(t=>{let n=t instanceof Error?t.message:String(t);fY.error(`Delegation failed`,{scoopJid:e,error:n}),this.callbacks.onError(e,`Delegation failed: ${n}`)})}async routeToScoop(e){let t=this.scoops.get(e.chatJid);if(!t){fY.info(`routeToScoop: unregistered target`,{chatJid:e.chatJid});return}let n=e.channel===`webhook`||e.channel===`cron`;if(!t.isCone&&t.requiresTrigger&&t.trigger&&!n&&!e.content.includes(t.trigger)){fY.info(`routeToScoop: trigger not found in content`,{chatJid:e.chatJid,trigger:t.trigger,contentPreview:e.content.slice(0,80)});return}let r=this.messageQueues.get(e.chatJid)??[];r.push(e),this.messageQueues.set(e.chatJid,r);let i=this.tabs.get(e.chatJid);if(fY.debug(`routeToScoop: queued`,{chatJid:e.chatJid,scoopName:t.name,tabStatus:i?.status??`no-tab`,queueLength:r.length}),i?.status===`error`){fY.info(`routeToScoop: tab in error state, retrying init`,{chatJid:e.chatJid});try{await this.createScoopTab(e.chatJid),i=this.tabs.get(e.chatJid)}catch{fY.warn(`routeToScoop: retry init failed`,{chatJid:e.chatJid})}}i?.status===`ready`&&await this.processScoopQueue(e.chatJid)}async createScoopTab(e){let t=this.scoops.get(e);if(!t)throw Error(`Scoop not found: ${e}`);if(this.contexts.has(e))if(this.tabs.get(e)?.status===`error`)fY.info(`Re-creating context after error`,{jid:e}),this.contexts.get(e)?.dispose(),this.contexts.delete(e),this.tabs.delete(e);else{fY.debug(`Context already exists`,{jid:e});return}if(!this.sharedFs)throw Error(`Shared filesystem not initialized`);let n=`scoop-${t.folder}-${Date.now()}`,r=t.isCone?this.sharedFs:new fe(this.sharedFs,[`/scoops/${t.folder}/`,`/shared/`],[`/workspace/`]),i=new iY(t,{onResponse:(n,r)=>{if(this.callbacks.onResponse(e,n,r),!t.isCone)if(r){let t=this.scoopResponseBuffer.get(e)??``;this.scoopResponseBuffer.set(e,t+n)}else this.scoopResponseBuffer.set(e,n)},onResponseDone:()=>{let t=this.tabs.get(e);t&&(t.lastActivity=new Date().toISOString(),this.tabs.set(e,t)),this.callbacks.onResponseDone(e)},onError:t=>{let n=this.tabs.get(e);n&&(n.status=`error`,n.error=t,this.tabs.set(e,n)),this.callbacks.onError(e,t),this.callbacks.onStatusChange(e,`error`)},onStatusChange:n=>{let r=this.tabs.get(e);if(r&&(r.status=n,r.lastActivity=new Date().toISOString(),this.tabs.set(e,r)),this.callbacks.onStatusChange(e,n),n===`ready`&&!t.isCone){let n=this.scoopResponseBuffer.get(e);if(this.scoopResponseBuffer.delete(e),n){let r=Array.from(this.scoops.values()).find(e=>e.isCone);if(r){let i=n.length>2e3?n.slice(0,2e3)+`
14104
+ ... (truncated)`:n,a={id:`scoop-done-${e}-${Date.now()}`,chatJid:r.jid,senderId:t.folder,senderName:t.assistantLabel,content:`[@${t.assistantLabel} completed]:\n${i}`,timestamp:new Date().toISOString(),fromAssistant:!1,channel:`scoop-notify`};fY.info(`Routing scoop completion to cone`,{scoop:t.folder,responseLength:n.length}),this.handleMessage(a).catch(e=>{let n=e instanceof Error?e.message:String(e);fY.error(`Failed to route scoop completion to cone`,{scoop:t.folder,error:n}),this.callbacks.onError(r.jid,`Scoop ${t.folder} completed but notification failed: ${n}`)})}}}},onToolStart:(t,n)=>{this.callbacks.onToolStart?.(e,t,n)},onToolEnd:(t,n,r)=>{this.callbacks.onToolEnd?.(e,t,n,r)},onToolUI:(t,n,r)=>{this.callbacks.onToolUI?.(e,t,n,r)},onToolUIDone:t=>{this.callbacks.onToolUIDone?.(e,t)},onSendMessage:(t,n)=>{this.callbacks.onSendMessage(e,`${n?`[${n}] `:``}${t}`)},getScoops:()=>this.getScoops(),onFeedScoop:t.isCone?(e,n)=>this.delegateToScoop(e,n,t.assistantLabel):void 0,onScoopScoop:t.isCone?async e=>{let t={...e,jid:`scoop_${e.folder}_${Date.now()}`};return await this.registerScoop(t),t}:void 0,onDropScoop:t.isCone?async e=>{await this.unregisterScoop(e)}:void 0,getGlobalMemory:()=>this.getGlobalMemory(),setGlobalMemory:t.isCone?e=>this.setGlobalMemory(e):void 0,getBrowserAPI:()=>this.callbacks.getBrowserAPI()},r,this.sessionStore??void 0,this.sharedFs??void 0);this.contexts.set(e,i),this.tabs.set(e,{jid:e,contextId:n,status:`initializing`,lastActivity:new Date().toISOString()}),await i.init();let a=this.tabs.get(e);a&&a.status===`initializing`&&(a.status=`ready`,this.tabs.set(e,a),this.callbacks.onStatusChange(e,`ready`)),fY.info(`Scoop context created`,{jid:e,contextId:n})}async destroyScoopTab(e){let t=this.contexts.get(e);t&&(t.dispose(),this.contexts.delete(e),this.tabs.delete(e),fY.info(`Scoop context destroyed`,{jid:e}))}isProcessing(e){return this.tabs.get(e)?.status===`processing`}getScoopContext(e){return this.contexts.get(e)}async clearQueuedMessages(e){let t=this.messageQueues.get(e);if(t&&t.length>0){for(let e of t)await Ie(e.id);this.messageQueues.set(e,[])}}async deleteQueuedMessage(e,t){let n=this.messageQueues.get(e);if(n){let e=n.findIndex(e=>e.id===t);e!==-1&&n.splice(e,1)}await Ie(t)}async getMessagesForScoop(e){return F(e)}async waitForTabReady(e,t=1e4){let n=Date.now();for(;Date.now()-n<t;){let t=this.tabs.get(e);if(!t)return!1;if(t.status===`ready`||t.status===`processing`)return!0;if(t.status===`error`)return!1;await new Promise(e=>setTimeout(e,100))}return fY.warn(`Timed out waiting for tab to become ready`,{jid:e}),!1}async sendPrompt(e,t,n,r){let i=this.contexts.get(e);i||=(await this.createScoopTab(e),this.contexts.get(e));let a=this.tabs.get(e);if(a?.status===`initializing`){if(fY.debug(`Context initializing, waiting to send message`,{jid:e}),!await this.waitForTabReady(e)){fY.error(`Context did not become ready in time, dropping prompt`,{jid:e});return}i=this.contexts.get(e),a=this.tabs.get(e)}if(!i){fY.error(`Context not found after creation`,{jid:e});return}this.scoopResponseBuffer.delete(e),a&&(a.status=`processing`,a.lastActivity=new Date().toISOString(),this.tabs.set(e,a),this.callbacks.onStatusChange(e,`processing`)),fY.debug(`Prompt sent to scoop`,{jid:e,textLength:t.length}),await i.prompt(t)}async processScoopQueue(e){let t=this.messageQueues.get(e);if(!t||t.length===0){fY.debug(`processScoopQueue: empty queue`,{jid:e});return}let n=this.tabs.get(e);if(n?.status!==`ready`){fY.debug(`processScoopQueue: tab not ready`,{jid:e,status:n?.status??`no-tab`});return}let r=this.scoops.get(e),i=r?.assistantLabel??e,a=this.lastAgentTimestamp.get(e)??``,o=await De(e,a,i);if(fY.debug(`processScoopQueue: DB query`,{jid:e,scoopName:r?.name,excludeName:i,since:a,dbMessageCount:o.length,queueLength:t.length}),o.length===0){fY.debug(`processScoopQueue: no messages from DB, clearing queue`,{jid:e}),this.messageQueues.set(e,[]);return}let s=o.map(e=>`[${new Date(e.timestamp).toLocaleString(`en-US`,{month:`short`,day:`numeric`,hour:`numeric`,minute:`2-digit`,hour12:!0})}] ${e.senderName}: ${e.content}`).join(`
14105
+ `);this.messageQueues.set(e,[]);let c=o[o.length-1];this.lastAgentTimestamp.set(e,c.timestamp),await Ve(`lastAgentTs_${e}`,c.timestamp),await this.sendPrompt(e,s,c.senderId,c.senderName)}startMessageLoop(){this.pollInterval||=window.setInterval(()=>{for(let e of this.scoops.keys())this.tabs.get(e)?.status===`ready`&&this.processScoopQueue(e).catch(t=>{let n=t instanceof Error?t.message:String(t);fY.error(`Message queue processing failed`,{jid:e,error:n}),this.callbacks.onError(e,`Queue processing failed: ${n}`)})},2e3)}stopMessageLoop(){this.pollInterval&&=(clearInterval(this.pollInterval),null)}updateModel(){for(let e of this.contexts.values())e.updateModel();fY.info(`Model updated on all active contexts`,{contextCount:this.contexts.size})}async reloadAllSkills(){let e=[];for(let[t,n]of this.contexts){let r=this.tabs.get(t);(r?.status===`ready`||r?.status===`processing`)&&e.push(n.reloadSkills().catch(e=>{fY.warn(`Failed to reload skills for scoop`,{jid:t,error:e instanceof Error?e.message:String(e)})}))}await Promise.all(e),fY.info(`Skills reloaded across all contexts`,{count:e.length})}stopScoop(e){let t=this.contexts.get(e);t&&t.stop()}async shutdown(){this.stopMessageLoop(),this.scheduler?.stop(),this.scheduler=null;for(let e of this.contexts.keys())await this.destroyScoopTab(e);fY.info(`Orchestrator shutdown`)}};r(`heartbeat`);var mY=r(`tray-follower`);async function hY(e){let t=await SY(await(e.fetchImpl??fetch)(e.joinUrl,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({controllerId:e.controllerId,runtime:e.runtime})}));return mY.info(`Follower tray attach response`,{trayId:t.trayId,action:t.result.action,code:t.result.code,participantCount:t.participantCount}),gY(t)}function gY(e){let t={trayId:e.trayId,controllerId:e.controllerId,participantCount:e.participantCount,leader:e.leader,action:e.result.action,code:e.result.code,iceServers:e.iceServers};return e.result.action===`wait`?{...t,retryAfterMs:e.result.retryAfterMs}:e.result.action===`signal`?{...t,bootstrap:e.result.bootstrap}:e.result.action===`fail`?{...t,error:e.result.error}:t}async function _Y(e){return xY(await CY(e,{action:`poll`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,cursor:e.cursor}))}async function vY(e){return xY(await CY(e,{action:`answer`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,answer:e.answer}))}async function yY(e){return xY(await CY(e,{action:`ice-candidate`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,candidate:e.candidate}))}async function bY(e){return xY(await CY(e,{action:`retry`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,runtime:e.runtime}))}function xY(e){return{trayId:e.trayId,controllerId:e.controllerId,participantCount:e.participantCount,leader:e.leader,bootstrap:e.bootstrap,events:e.events}}async function SY(e){let t=null,n=null;try{t=await e.text(),n=JSON.parse(t)}catch{}if(!wY(n)){let n=t?t.slice(0,200):`(empty)`;throw mY.warn(`Tray follower attach returned an invalid response`,{status:e.status,body:n}),Error(`Tray follower attach returned an invalid response (${e.status}): ${n}`)}return n}async function CY(e,t){let n=await(e.fetchImpl??fetch)(e.joinUrl,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(t)}),r=await n.json().catch(()=>null);if(!TY(r))throw Error(`Tray follower bootstrap returned an invalid response (${n.status})`);return r}function wY(e){if(!e||typeof e!=`object`)return!1;let t=e;if(typeof t.trayId!=`string`||typeof t.controllerId!=`string`||t.role!==`follower`||typeof t.participantCount!=`number`)return!1;let n=t.result;if(!n||typeof n!=`object`)return!1;let r=n;return r.action===`wait`?(r.code===`LEADER_NOT_ELECTED`||r.code===`LEADER_NOT_CONNECTED`)&&typeof r.retryAfterMs==`number`:r.action===`signal`?r.code===`LEADER_CONNECTED`&&EY(r.bootstrap):r.action===`fail`?(r.code===`INVALID_JOIN_CAPABILITY`||r.code===`TRAY_EXPIRED`)&&typeof r.error==`string`:!1}function TY(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.trayId==`string`&&typeof t.controllerId==`string`&&t.role===`follower`&&typeof t.participantCount==`number`&&EY(t.bootstrap)&&Array.isArray(t.events)}function EY(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.controllerId==`string`&&typeof t.bootstrapId==`string`&&typeof t.attempt==`number`&&typeof t.state==`string`&&typeof t.expiresAt==`string`&&typeof t.cursor==`number`&&typeof t.maxRetries==`number`&&typeof t.retriesRemaining==`number`}var DY=r(`tray-webrtc`),OY=`tray-control`,kY=250,AY=class{peerConnectionFactory;dataChannelLabel;peers=new Map;iceServers;constructor(e){this.options=e,this.iceServers=e.iceServers,this.peerConnectionFactory=e.peerConnectionFactory??(()=>NY(this.iceServers)),this.dataChannelLabel=e.dataChannelLabel??OY}setIceServers(e){this.iceServers=e}async handleControlMessage(e){e.type===`follower.join_requested`?(e.iceServers&&!this.iceServers&&(this.iceServers=e.iceServers),await this.handleJoinRequested(e)):e.type===`bootstrap.answer`?await this.peers.get(e.bootstrapId)?.peer.setRemoteDescription(e.answer):e.type===`bootstrap.ice_candidate`&&await this.peers.get(e.bootstrapId)?.peer.addIceCandidate(e.candidate)}getPeers(){return Array.from(this.peers.values()).map(({state:e})=>({...e}))}getChannel(e){return this.peers.get(e)?.channel??null}stop(){for(let e of this.peers.values())e.peer.close();this.peers.clear()}async handleJoinRequested(e){this.closeControllerPeers(e.controllerId);let t=this.peerConnectionFactory(),n={controllerId:e.controllerId,bootstrapId:e.bootstrapId,attempt:e.attempt,state:`connecting`,connectedAt:null,runtime:e.runtime},r=t.createDataChannel(this.dataChannelLabel);this.peers.set(e.bootstrapId,{state:n,peer:t,channel:r}),t.addEventListener(`icecandidate`,({candidate:t})=>{let n=FY(t);n&&this.options.sendControlMessage({type:`bootstrap.ice_candidate`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,candidate:n})}),t.addEventListener(`connectionstatechange`,()=>{let n=this.peers.get(e.bootstrapId);n&&(n.state.state===`connected`?(t.connectionState===`disconnected`||t.connectionState===`failed`)&&(DY.warn(`Leader peer connection state changed post-connect`,{bootstrapId:e.bootstrapId,state:t.connectionState}),this.options.onPeerDisconnected?.(e.bootstrapId,`Peer connection ${t.connectionState}`)):t.connectionState===`failed`&&this.failPeer(e,`Leader peer connection failed before the data channel opened`))}),r.addEventListener(`open`,()=>{let t=this.peers.get(e.bootstrapId);!t||t.state.state===`connected`||(t.state.state=`connected`,t.state.connectedAt=new Date().toISOString(),this.options.onPeerConnected?.({...t.state},t.channel))}),r.addEventListener(`close`,()=>{let t=this.peers.get(e.bootstrapId);t&&(t.state.state===`connected`?(DY.warn(`Leader data channel closed post-connect`,{bootstrapId:e.bootstrapId}),this.options.onPeerDisconnected?.(e.bootstrapId,`Data channel closed`)):this.failPeer(e,`Leader data channel closed before opening`))}),r.addEventListener(`error`,()=>{let t=this.peers.get(e.bootstrapId);t&&(t.state.state===`connected`?(DY.warn(`Leader data channel error post-connect`,{bootstrapId:e.bootstrapId}),this.options.onPeerDisconnected?.(e.bootstrapId,`Data channel error`)):this.failPeer(e,`Leader data channel failed before opening`))});try{let n=await t.createOffer();await t.setLocalDescription(n),this.options.sendControlMessage({type:`bootstrap.offer`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,offer:PY(t.localDescription??n,`offer`)})}catch(t){this.failPeer(e,t instanceof Error?t.message:String(t))}}closeControllerPeers(e){for(let[t,n]of this.peers.entries())n.state.controllerId===e&&(n.peer.close(),this.peers.delete(t))}failPeer(e,t){let n=this.peers.get(e.bootstrapId);if(n){n.peer.close(),this.peers.delete(e.bootstrapId);try{this.options.sendControlMessage({type:`bootstrap.failed`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,code:`WEBRTC_BOOTSTRAP_FAILED`,message:t,retryable:!0,retryAfterMs:1e3})}catch(e){DY.warn(`Failed to report tray bootstrap failure`,{error:e instanceof Error?e.message:String(e)})}}}},jY=class{fetchImpl;peerConnectionFactory;controllerIdFactory;sleep;pollIntervalMs;iceServers;activePeer=null;stopped=!1;constructor(e){this.options=e,this.fetchImpl=e.fetchImpl??fetch,this.iceServers=e.iceServers,this.peerConnectionFactory=e.peerConnectionFactory??(()=>NY(this.iceServers)),this.controllerIdFactory=e.controllerIdFactory??(()=>crypto.randomUUID()),this.sleep=e.sleep??(e=>new Promise(t=>setTimeout(t,e))),this.pollIntervalMs=e.pollIntervalMs??kY}async start(){this.stopped=!1;let e=this.controllerIdFactory(),t=Date.now();p({state:`connecting`,joinUrl:this.options.joinUrl,trayId:null,error:null,lastPingTime:null,reconnectAttempts:0,attachAttempts:0,lastAttachCode:null,connectingSince:t,lastError:null}),DY.info(`Follower tray join starting`,{joinUrl:this.options.joinUrl});let n=0;for(;;){IY(this.stopped),n++;let t;try{t=await hY({joinUrl:this.options.joinUrl,controllerId:e,runtime:this.options.runtime,fetchImpl:this.fetchImpl})}catch(e){let t=e instanceof Error?e.message:String(e);throw p({...h(),attachAttempts:n,lastError:t}),e}if(p({...h(),attachAttempts:n,lastAttachCode:t.code}),t.action===`wait`){let e=t.retryAfterMs??1e3;DY.info(`Follower tray attach waiting`,{attempt:n,code:t.code,retryAfterMs:e}),n%10==0&&DY.warn(`Follower tray attach still waiting after ${n} attempts`,{attempt:n,code:t.code,retryAfterMs:e}),await this.sleep(e);continue}if(t.action===`fail`||!t.bootstrap){let e=t.error??`Tray follower attach failed (${t.code})`;throw p({state:`error`,joinUrl:this.options.joinUrl,trayId:null,error:e,lastPingTime:null,reconnectAttempts:0,attachAttempts:n,lastAttachCode:t.code,connectingSince:null,lastError:e}),DY.warn(`Follower tray attach failed`,{error:e}),Error(e)}t.iceServers&&(this.iceServers=t.iceServers);try{let r=await this.completeBootstrap(t.trayId,e,t.bootstrap);return p({state:`connected`,joinUrl:this.options.joinUrl,trayId:r.trayId,error:null,lastPingTime:null,reconnectAttempts:0,attachAttempts:n,lastAttachCode:t.code,connectingSince:null,lastError:null}),DY.info(`Follower tray connected`,{trayId:r.trayId,controllerId:e}),r}catch(e){let r=e instanceof Error?e.message:String(e);throw p({state:`error`,joinUrl:this.options.joinUrl,trayId:t.trayId,error:r,lastPingTime:null,reconnectAttempts:0,attachAttempts:n,lastAttachCode:t.code,connectingSince:null,lastError:r}),DY.warn(`Follower tray bootstrap failed`,{error:r}),e}}}stop(){this.stopped=!0,this.activePeer?.peer.close(),this.activePeer?.channel?.close(),this.activePeer=null,p({state:`inactive`,joinUrl:null,trayId:null,error:null,lastPingTime:null,reconnectAttempts:0,attachAttempts:0,lastAttachCode:null,connectingSince:null,lastError:null})}async completeBootstrap(e,t,n){let r=n,i=0;for(this.activePeer=this.createFollowerPeer(t,r.bootstrapId);;){if(IY(this.stopped),this.activePeer.open&&this.activePeer.channel)return{trayId:e,controllerId:t,bootstrapId:r.bootstrapId,channel:this.activePeer.channel};if(this.activePeer.openError)throw Error(this.activePeer.openError);let n=await _Y({joinUrl:this.options.joinUrl,controllerId:t,bootstrapId:r.bootstrapId,cursor:i,fetchImpl:this.fetchImpl});r=n.bootstrap,i=r.cursor;try{for(let e of n.events)if(e.type===`bootstrap.offer`){await this.activePeer.peer.setRemoteDescription(e.offer);let n=await this.activePeer.peer.createAnswer();await this.activePeer.peer.setLocalDescription(n),await vY({joinUrl:this.options.joinUrl,controllerId:t,bootstrapId:r.bootstrapId,answer:PY(this.activePeer.peer.localDescription??n,`answer`),fetchImpl:this.fetchImpl})}else if(e.type===`bootstrap.ice_candidate`)await this.activePeer.peer.addIceCandidate(e.candidate);else if(e.type===`bootstrap.failed`)throw Error(e.failure.message)}catch(e){if(r.failure?.retryable&&r.retriesRemaining>0){r=(await bY({joinUrl:this.options.joinUrl,controllerId:t,bootstrapId:r.bootstrapId,runtime:this.options.runtime,fetchImpl:this.fetchImpl})).bootstrap,i=0,this.activePeer.peer.close(),this.activePeer=this.createFollowerPeer(t,r.bootstrapId);continue}throw e}this.activePeer.open||await this.sleep(this.pollIntervalMs)}}createFollowerPeer(e,t){let n=this.peerConnectionFactory(),r={peer:n,channel:null,open:!1,openError:null};return n.addEventListener(`connectionstatechange`,()=>{r.open&&(n.connectionState===`disconnected`||n.connectionState===`failed`)&&(DY.warn(`Follower peer connection state changed post-connect`,{bootstrapId:t,state:n.connectionState}),this.options.onDisconnected?.(`Peer connection ${n.connectionState}`))}),n.addEventListener(`datachannel`,({channel:e})=>{r.channel=e,e.addEventListener(`open`,()=>{r.open=!0}),e.addEventListener(`close`,()=>{r.open?(DY.warn(`Follower data channel closed post-connect`,{bootstrapId:t}),this.options.onDisconnected?.(`Data channel closed`)):r.openError=`Follower data channel closed before opening`}),e.addEventListener(`error`,()=>{r.open?(DY.warn(`Follower data channel error post-connect`,{bootstrapId:t}),this.options.onDisconnected?.(`Data channel error`)):r.openError=`Follower data channel failed before opening`})}),n.addEventListener(`icecandidate`,({candidate:n})=>{let r=FY(n);r&&yY({joinUrl:this.options.joinUrl,controllerId:e,bootstrapId:t,candidate:r,fetchImpl:this.fetchImpl}).catch(e=>{DY.warn(`Failed to send follower ICE candidate`,{error:e instanceof Error?e.message:String(e)})})}),r}};function MY(e,t){let n=t.baseDelayMs??1e3,r=t.backoffMultiplier??2,i=t.maxDelayMs??3e4,a=t.maxAttempts??10,o=t.sleep??e.sleep??(e=>new Promise(t=>setTimeout(t,e))),s=!1,c=!1,l=null,u={cancel(){s=!0,c=!1,l?.stop(),l=null},get reconnecting(){return c}},d=()=>{let t=new jY({...e,sleep:o,onDisconnected:e=>{s||(DY.warn(`Follower disconnected, starting reconnect loop`,{reason:e}),f(e))}});return l=t,{manager:t,connectionPromise:t.start()}},f=async u=>{if(s||c)return;c=!0,l?.stop(),l=null;let f=0,m=n,g=u??`Unknown disconnect`;for(;!s&&f<a&&(f++,t.onReconnecting?.(f),p({...h(),state:`reconnecting`,error:null,reconnectAttempts:f}),DY.info(`Reconnect attempt`,{attempt:f,delay:m}),await o(m),!s);){let n=null;try{let r=d();n=r.manager;let i=await r.connectionPromise;if(s){n.stop();break}c=!1,p({...h(),state:`connected`,joinUrl:e.joinUrl,trayId:i.trayId,error:null,lastPingTime:null,reconnectAttempts:0,connectingSince:null,lastError:null}),DY.info(`Reconnect successful`,{attempt:f,trayId:i.trayId}),t.onConnected(i);return}catch(e){g=e instanceof Error?e.message:String(e),DY.warn(`Reconnect attempt failed`,{attempt:f,error:g}),n?.stop(),l=null}m=Math.min(m*r,i)}s||(c=!1,p({...h(),state:`error`,error:`Reconnect failed after ${f} attempts: ${g}`,reconnectAttempts:f}),DY.warn(`Reconnect gave up`,{attempts:f,lastError:g}),t.onGaveUp?.(g))},{connectionPromise:m}=d();return m.then(e=>{s||t.onConnected(e)}).catch(e=>{s||DY.warn(`Initial follower connection failed`,{error:e instanceof Error?e.message:String(e)})}),u}function NY(e){if(typeof RTCPeerConnection>`u`)throw Error(`RTCPeerConnection is not available in this runtime`);let t=e?.length?{iceServers:e}:void 0;return new RTCPeerConnection(t)}function PY(e,t){if(!e||e.type!==t||typeof e.sdp!=`string`)throw Error(`Expected a local ${t} description before signaling`);return{type:e.type,sdp:e.sdp}}function FY(e){if(!e||typeof e!=`object`)return null;let t=e;return typeof t.candidate==`string`?{candidate:t.candidate,sdpMid:typeof t.sdpMid==`string`?t.sdpMid:null,sdpMLineIndex:typeof t.sdpMLineIndex==`number`?t.sdpMLineIndex:null,usernameFragment:typeof t.usernameFragment==`string`?t.usernameFragment:null}:null}function IY(e){if(e)throw Error(`Tray follower stopped before WebRTC bootstrap completed`)}var LY=64*1024;async function RY(e,t){try{switch(t.op){case`readFile`:return await zY(e,t.path,t.encoding);case`writeFile`:return[await BY(e,t.path,t.content,t.encoding)];case`stat`:return[await VY(e,t.path)];case`readDir`:return[await HY(e,t.path)];case`mkdir`:return[await UY(e,t.path,t.recursive)];case`rm`:return[await WY(e,t.path,t.recursive)];case`exists`:return[await GY(e,t.path)];case`walk`:return[await KY(e,t.path)];default:return[{ok:!1,error:`Unknown fs operation: ${t.op}`}]}}catch(e){return[JY(e)]}}async function zY(e,t,n){return(n??`utf-8`)===`utf-8`?qY(await e.readFile(t,{encoding:`utf-8`}),`utf-8`):qY(YY(await e.readFile(t,{encoding:`binary`})),`base64`)}async function BY(e,t,n,r){if(r===`base64`){let r=XY(n);await e.writeFile(t,r)}else await e.writeFile(t,n);return{ok:!0,data:{type:`void`}}}async function VY(e,t){return{ok:!0,data:{type:`stat`,stat:await e.stat(t)}}}async function HY(e,t){return{ok:!0,data:{type:`dirEntries`,entries:await e.readDir(t)}}}async function UY(e,t,n){return await e.mkdir(t,{recursive:n}),{ok:!0,data:{type:`void`}}}async function WY(e,t,n){return await e.rm(t,{recursive:n}),{ok:!0,data:{type:`void`}}}async function GY(e,t){return{ok:!0,data:{type:`exists`,exists:await e.exists(t)}}}async function KY(e,t){let n=[];for await(let r of e.walk(t))n.push(r);return{ok:!0,data:{type:`paths`,paths:n}}}function qY(e,t){if(e.length<=LY)return[{ok:!0,data:{type:`file`,content:e,encoding:t}}];let n=Math.ceil(e.length/LY),r=[];for(let i=0;i<n;i++){let a=i*LY,o=e.slice(a,a+LY);r.push({ok:!0,data:{type:`file`,content:o,encoding:t},chunkIndex:i,totalChunks:n})}return r}function JY(e){return e instanceof Error&&`code`in e?{ok:!1,error:e.message,code:e.code}:{ok:!1,error:e instanceof Error?e.message:String(e)}}function YY(e){let t=``;for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t)}function XY(e){let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e++)n[e]=t.charCodeAt(e);return n}var ZY=class{runtimes=new Map;dirty=!1;setTargets(e,t){this.runtimes.set(e,t),this.dirty=!0}removeRuntime(e){this.runtimes.delete(e)&&(this.dirty=!0)}getEntries(){this.dirty=!1;let e=[];for(let[t,n]of this.runtimes)for(let r of n)e.push({targetId:`${t}:${r.targetId}`,localTargetId:r.targetId,runtimeId:t,title:r.title,url:r.url,isLocal:!1});return e}hasChanged(){return this.dirty}getRuntimeIds(){return[...this.runtimes.keys()]}},QY=r(`data-channel-keepalive`),$Y=class{sendPing;onDead;intervalMs;maxMissed;timer=null;missedPongs=0;awaitingPong=!1;stopped=!1;constructor(e){this.sendPing=e.sendPing,this.onDead=e.onDead,this.intervalMs=e.intervalMs??1e4,this.maxMissed=e.maxMissed??3}start(){this.timer||this.stopped||(this.timer=setInterval(()=>this.tick(),this.intervalMs))}stop(){this.stopped=!0,this.timer&&=(clearInterval(this.timer),null)}receivePong(){this.awaitingPong=!1,this.missedPongs=0}receivePing(){this.missedPongs=0,this.awaitingPong=!1}get missed(){return this.missedPongs}tick(){if(!this.stopped){if(this.awaitingPong&&(this.missedPongs++,QY.debug(`Missed pong`,{missedPongs:this.missedPongs,maxMissed:this.maxMissed}),this.missedPongs>=this.maxMissed)){QY.warn(`Channel declared dead`,{missedPongs:this.missedPongs}),this.stop(),this.onDead();return}this.awaitingPong=!0,this.sendPing()}}},eX=r(`tray-leader-sync`);function tX(e){return e?e.includes(`standalone`)?`standalone`:e.includes(`extension`)?`extension`:e.includes(`electron`)?`electron`:`unknown`:`unknown`}var nX=class{followers=new Map;registry=new ZY;runtimeToBootstrap=new Map;pendingCDPRoutes=new Map;cdpChunkBuffers=new Map;remoteTransports=new Map;pendingTabOpenRoutes=new Map;tabOpenResolvers=new Map;pendingFsRoutes=new Map;fsResolvers=new Map;constructor(e){this.options=e}addFollower(e,t,n){this.removeFollower(e);let r=be(t),i=r.onMessage(t=>{this.handleFollowerMessage(e,t)}),a=new $Y({sendPing:()=>r.send({type:`ping`}),onDead:()=>{eX.warn(`Follower keepalive dead, removing follower`,{bootstrapId:e}),this.removeFollower(e),this.options.onFollowerDead?.(e)}});a.start(),this.followers.set(e,{bootstrapId:e,sync:r,unsubscribe:i,keepalive:a,runtime:n?.runtime,connectedAt:n?.connectedAt,lastActivity:Date.now(),floatType:tX(n?.runtime)}),eX.info(`Follower added to sync`,{bootstrapId:e,followerCount:this.followers.size}),this.sendSnapshotToFollower(e);let o=this.getConnectedEntries();o.length>0&&r.send({type:`targets.registry`,targets:o})}removeFollower(e){let t=this.followers.get(e);if(t){t.keepalive.stop(),t.unsubscribe(),t.sync.close(),this.followers.delete(e);for(let[t,n]of this.runtimeToBootstrap)if(n===e){this.cleanupRemoteTransports(t),this.registry.removeRuntime(t),this.runtimeToBootstrap.delete(t);break}this.registry.hasChanged()&&this.broadcastTargetRegistry(),eX.info(`Follower removed from sync`,{bootstrapId:e,followerCount:this.followers.size})}}broadcastEvent(e){if(this.followers.size===0)return;let t={type:`agent_event`,event:e,scoopJid:this.options.getScoopJid()};for(let e of this.followers.values())e.sync.send(t)}broadcastUserMessage(e,t){if(this.followers.size===0)return;let n={type:`user_message_echo`,text:e,messageId:t,scoopJid:this.options.getScoopJid()};for(let e of this.followers.values())e.sync.send(n)}broadcastStatus(e){if(this.followers.size===0)return;let t={type:`status`,scoopStatus:e};for(let e of this.followers.values())e.sync.send(t)}sendSnapshotToFollower(e){let t=this.followers.get(e);if(!t)return;let n=this.options.getMessages(),r=this.options.getScoopJid();ve(t.sync,n,r),eX.debug(`Snapshot sent to follower`,{bootstrapId:e,messageCount:n.length})}handleFollowerMessage(e,t){switch(t.type){case`user_message`:eX.info(`Follower user message received`,{bootstrapId:e,messageId:t.messageId}),this.options.onFollowerMessage(t.text,t.messageId);break;case`abort`:eX.info(`Follower abort received`,{bootstrapId:e}),this.options.onFollowerAbort();break;case`request_snapshot`:eX.info(`Follower snapshot request received`,{bootstrapId:e}),this.sendSnapshotToFollower(e);break;case`targets.advertise`:eX.info(`Follower targets advertised`,{bootstrapId:e,runtimeId:t.runtimeId,targetCount:t.targets.length});for(let e of[...this.remoteTransports.keys()]){let n=e.substring(0,e.indexOf(`:`));n!==`leader`&&!this.runtimeToBootstrap.has(n)&&n!==t.runtimeId&&(this.remoteTransports.get(e)?.disconnect(),this.remoteTransports.delete(e),eX.debug(`Cleaned up orphaned remote transport on advertise`,{key:e}))}this.runtimeToBootstrap.set(t.runtimeId,e),this.registry.setTargets(t.runtimeId,t.targets),this.broadcastTargetRegistry();break;case`cdp.request`:{let{requestId:n,targetRuntimeId:r,localTargetId:i,method:a,params:o,sessionId:s}=t;r===`leader`?this.executeLocalCDP(n,i,a,o,s,e):this.forwardCDPRequest(n,r,i,a,o,s,e);break}case`cdp.response`:this.handleCDPResponse(t);break;case`cdp.event`:this.handleCDPEvent(e,t.method,t.params,t.sessionId);break;case`tab.open`:{let{requestId:n,targetRuntimeId:r,url:i}=t;r===`leader`?this.executeLocalTabOpen(n,i,e):this.forwardTabOpen(n,r,i,e);break}case`tab.opened`:this.handleTabOpenResponse(t.requestId,t.targetId);break;case`tab.open.error`:this.handleTabOpenError(t.requestId,t.error);break;case`fs.request`:{let{requestId:n,targetRuntimeId:r,request:i}=t;r===`leader`?this.executeLocalFs(n,i,e):this.forwardFsRequest(n,r,i,e);break}case`fs.response`:this.handleFsResponse(t.requestId,t.response);break;case`ping`:{let t=this.followers.get(e);t&&(t.keepalive.receivePing(),t.lastActivity=Date.now(),t.sync.send({type:`pong`}));break}case`pong`:{let t=this.followers.get(e);t&&(t.keepalive.receivePong(),t.lastActivity=Date.now());break}}}setLocalTargets(e){this.registry.setTargets(`leader`,e),this.registry.hasChanged()&&this.broadcastTargetRegistry()}broadcastTargetRegistry(){if(this.followers.size===0)return;let e={type:`targets.registry`,targets:this.getConnectedEntries()};for(let t of this.followers.values())t.sync.send(e)}getTargets(){return this.getConnectedEntries()}getConnectedEntries(){return this.registry.getEntries().filter(e=>{if(e.runtimeId===`leader`)return!0;let t=this.runtimeToBootstrap.get(e.runtimeId);return t?this.followers.has(t):!1})}createRemoteTransport(e,t){let n=new j({sendCDPRequest:(n,r,i,a)=>{let o=this.runtimeToBootstrap.get(e),s=o?this.followers.get(o):void 0;if(!s){this.remoteTransports.get(`${e}:${t}`)?.handleResponse(n,void 0,`Target runtime "${e}" not connected`);return}this.pendingCDPRoutes.set(n,{requesterBootstrapId:`__leader__`,requestId:n}),s.sync.send({type:`cdp.request`,requestId:n,localTargetId:t,method:r,params:i,sessionId:a})}});return this.remoteTransports.set(`${e}:${t}`,n),n}removeRemoteTransport(e,t){let n=`${e}:${t}`,r=this.remoteTransports.get(n);r&&(r.disconnect(),this.remoteTransports.delete(n))}cleanupRemoteTransports(e){let t=`${e}:`;for(let e of[...this.remoteTransports.keys()])e.startsWith(t)&&(this.remoteTransports.get(e)?.disconnect(),this.remoteTransports.delete(e),eX.debug(`Cleaned up stale remote transport`,{key:e}))}getConnectedFollowers(){return[...this.runtimeToBootstrap.entries()].map(([e,t])=>{let n=this.followers.get(t);return{runtimeId:e,runtime:n?.runtime,connectedAt:n?.connectedAt,lastActivity:n?.lastActivity,floatType:n?.floatType}})}getBestFollowerForTeleport(){let e=[];for(let[t,n]of this.runtimeToBootstrap){let r=this.followers.get(n);r&&e.push({runtimeId:t,bootstrapId:n,floatType:r.floatType,lastActivity:r.lastActivity})}if(e.length===0)return null;let t=e.filter(e=>e.floatType===`standalone`),n=t.length>0?t:e;return n.sort((e,t)=>t.lastActivity-e.lastActivity),n[0]}get hasFollowers(){return this.followers.size>0}stop(){for(let e of[...this.followers.keys()])this.removeFollower(e)}async executeLocalCDP(e,t,n,r,i,a){let o=this.followers.get(a);if(!o)return;let s=this.options.browserTransport;if(!s){o.sync.send({type:`cdp.response`,requestId:e,error:`Leader has no browser transport`});return}try{let t=await s.send(n,r,i);Ce(o.sync,e,t)}catch(t){o.sync.send({type:`cdp.response`,requestId:e,error:t instanceof Error?t.message:String(t)})}}forwardCDPRequest(e,t,n,r,i,a,o){let s=this.runtimeToBootstrap.get(t),c=s?this.followers.get(s):void 0,l=this.followers.get(o);if(!c){l&&l.sync.send({type:`cdp.response`,requestId:e,error:`Target runtime "${t}" not connected`});return}this.pendingCDPRoutes.set(e,{requesterBootstrapId:o,requestId:e}),c.sync.send({type:`cdp.request`,requestId:e,localTargetId:n,method:r,params:i,sessionId:a})}handleCDPResponse(e){let{requestId:t,result:n,error:r,chunkData:i,chunkIndex:a,totalChunks:o}=e,s=this.pendingCDPRoutes.get(t);if(!s)return;let c=_e(this.cdpChunkBuffers,e);if(!c)return;if(this.pendingCDPRoutes.delete(t),s.requesterBootstrapId===`__leader__`){for(let e of this.remoteTransports.values())e.handleResponse(t,c.result,c.error);return}let l=this.followers.get(s.requesterBootstrapId);l&&Ce(l.sync,t,c.result,c.error)}handleCDPEvent(e,t,n,r){let i;for(let[t,n]of this.runtimeToBootstrap)if(n===e){i=t;break}if(!i)return;let a=`${i}:`;for(let[e,r]of this.remoteTransports)e.startsWith(a)&&r.handleEvent(t,n)}openRemoteTab(e,t){let n=this.runtimeToBootstrap.get(e),r=n?this.followers.get(n):void 0;if(!r)return Promise.reject(Error(`Target runtime "${e}" not connected`));let i=`tab-open-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;return new Promise((e,n)=>{this.tabOpenResolvers.set(i,{resolve:e,reject:n}),this.pendingTabOpenRoutes.set(i,{requesterBootstrapId:`__leader__`,requestId:i}),r.sync.send({type:`tab.open`,requestId:i,url:t})})}async executeLocalTabOpen(e,t,n){let r=this.followers.get(n);if(!r)return;let i=this.options.browserTransport;if(!i){r.sync.send({type:`tab.open.error`,requestId:e,error:`Leader has no browser transport`});return}try{let n=(await i.send(`Target.createTarget`,{url:t,background:!0})).targetId;r.sync.send({type:`tab.opened`,requestId:e,targetId:`leader:${n}`})}catch(t){r.sync.send({type:`tab.open.error`,requestId:e,error:t instanceof Error?t.message:String(t)})}}forwardTabOpen(e,t,n,r){let i=this.runtimeToBootstrap.get(t),a=i?this.followers.get(i):void 0,o=this.followers.get(r);if(!a){o&&o.sync.send({type:`tab.open.error`,requestId:e,error:`Target runtime "${t}" not connected`});return}this.pendingTabOpenRoutes.set(e,{requesterBootstrapId:r,requestId:e}),a.sync.send({type:`tab.open`,requestId:e,url:n})}handleTabOpenResponse(e,t){let n=this.pendingTabOpenRoutes.get(e);if(!n)return;if(this.pendingTabOpenRoutes.delete(e),n.requesterBootstrapId===`__leader__`){let n=this.tabOpenResolvers.get(e);n&&(this.tabOpenResolvers.delete(e),n.resolve(t));return}let r=this.followers.get(n.requesterBootstrapId);r&&r.sync.send({type:`tab.opened`,requestId:e,targetId:t})}handleTabOpenError(e,t){let n=this.pendingTabOpenRoutes.get(e);if(!n)return;if(this.pendingTabOpenRoutes.delete(e),n.requesterBootstrapId===`__leader__`){let n=this.tabOpenResolvers.get(e);n&&(this.tabOpenResolvers.delete(e),n.reject(Error(t)));return}let r=this.followers.get(n.requesterBootstrapId);r&&r.sync.send({type:`tab.open.error`,requestId:e,error:t})}async executeLocalFs(e,t,n){let r=this.followers.get(n);if(!r)return;let i=this.options.vfs;if(!i){r.sync.send({type:`fs.response`,requestId:e,response:{ok:!1,error:`Leader has no VFS`}});return}let a=await RY(i,t);for(let t of a)r.sync.send({type:`fs.response`,requestId:e,response:t})}forwardFsRequest(e,t,n,r){let i=this.runtimeToBootstrap.get(t),a=i?this.followers.get(i):void 0,o=this.followers.get(r);if(!a){o&&o.sync.send({type:`fs.response`,requestId:e,response:{ok:!1,error:`Target runtime "${t}" not connected`}});return}this.pendingFsRoutes.set(e,{requesterBootstrapId:r,requestId:e,chunks:[],totalChunks:1}),a.sync.send({type:`fs.request`,requestId:e,request:n})}handleFsResponse(e,t){let n=this.pendingFsRoutes.get(e);if(!n){let n=this.fsResolvers.get(e);if(n){n.responses.push(t);let r=t.ok&&t.totalChunks||1;n.responses.length>=r&&(this.fsResolvers.delete(e),n.resolve(n.responses))}return}if(n.requesterBootstrapId===`__leader__`){let n=this.fsResolvers.get(e);if(n){n.responses.push(t);let r=t.ok&&t.totalChunks||1;n.responses.length>=r&&(this.fsResolvers.delete(e),this.pendingFsRoutes.delete(e),n.resolve(n.responses))}return}let r=this.followers.get(n.requesterBootstrapId);r&&r.sync.send({type:`fs.response`,requestId:e,response:t}),n.chunks.push(t),n.totalChunks=t.ok&&t.totalChunks||1,n.chunks.length>=n.totalChunks&&this.pendingFsRoutes.delete(e)}sendFsRequest(e,t){if(e===`leader`){let e=this.options.vfs;return e?RY(e,t):Promise.resolve([{ok:!1,error:`Leader has no VFS`}])}let n=this.runtimeToBootstrap.get(e),r=n?this.followers.get(n):void 0;if(!r)return Promise.resolve([{ok:!1,error:`Target runtime "${e}" not connected`}]);let i=`fs-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;return new Promise((e,n)=>{this.fsResolvers.set(i,{resolve:e,reject:n,responses:[]}),this.pendingFsRoutes.set(i,{requesterBootstrapId:`__leader__`,requestId:i,chunks:[],totalChunks:1}),r.sync.send({type:`fs.request`,requestId:i,request:t})})}},rX=r(`tray-follower-sync`),iX=class{sync;eventListeners=new Set;unsubscribe;keepalive;latestSnapshot=null;sentMessageIds=new Set;targetEntries=[];remoteTransports=new Map;cdpChunkBuffers=new Map;snapshotChunkBuffer=null;remoteCDPSessions=new Set;cdpEventCleanups=[];tabOpenResolvers=new Map;fsResolvers=new Map;constructor(e,t={}){this.options=t,this.sync=Se(e),this.unsubscribe=this.sync.onMessage(e=>{this.handleLeaderMessage(e)}),this.keepalive=new $Y({sendPing:()=>this.sync.send({type:`ping`}),onDead:()=>{rX.warn(`Leader keepalive dead, cleaning up`),this.handleDisconnect(`Keepalive timeout — leader not responding`),this.options.onDead?.()}}),this.keepalive.start(),e.addEventListener(`close`,()=>{rX.warn(`Data channel closed`),this.handleDisconnect(`Data channel closed`)}),e.addEventListener(`error`,()=>{rX.warn(`Data channel error`),this.handleDisconnect(`Data channel error`)})}sendMessage(e,t){let n=t??`follower-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;this.sentMessageIds.add(n),this.sync.send({type:`user_message`,text:e,messageId:n}),rX.info(`Sent user message to leader`,{messageId:n})}onEvent(e){return this.eventListeners.add(e),()=>this.eventListeners.delete(e)}stop(){this.sync.send({type:`abort`}),rX.info(`Sent abort to leader`)}requestSnapshot(){this.sync.send({type:`request_snapshot`})}getLatestSnapshot(){return this.latestSnapshot}close(){this.keepalive.stop(),this.unsubscribe(),this.sync.close(),this.eventListeners.clear(),this.cleanupCDPEventForwarding(),rX.info(`Follower sync closed`)}advertiseTargets(e,t){this.sync.send({type:`targets.advertise`,targets:e,runtimeId:t})}getTargets(){return this.targetEntries}disconnected=!1;handleDisconnect(e){this.disconnected||(this.disconnected=!0,p({...h(),state:`error`,error:e}),this.emitEvent({type:`error`,error:`Connection to leader lost: ${e}`}),this.keepalive.stop(),this.cleanupCDPEventForwarding(),this.unsubscribe(),this.sync.close(),this.options.onDisconnect?.(e))}handleLeaderMessage(e){switch(e.type){case`snapshot`:rX.info(`Snapshot received from leader`,{messageCount:e.messages.length,scoopJid:e.scoopJid}),this.snapshotChunkBuffer=null,this.latestSnapshot={messages:e.messages,scoopJid:e.scoopJid},this.options.onSnapshot?.(e.messages,e.scoopJid);break;case`snapshot_chunk`:{let t=M(this.snapshotChunkBuffer,e);this.snapshotChunkBuffer=t.buffer,t.result&&(rX.info(`Chunked snapshot reassembled from leader`,{messageCount:t.result.messages.length,scoopJid:t.result.scoopJid}),this.latestSnapshot=t.result,this.options.onSnapshot?.(t.result.messages,t.result.scoopJid));break}case`agent_event`:this.emitEvent(e.event);break;case`user_message_echo`:if(this.sentMessageIds.has(e.messageId)){this.sentMessageIds.delete(e.messageId),rX.debug(`Skipping own message echo`,{messageId:e.messageId});break}rX.info(`User message echo received`,{messageId:e.messageId,scoopJid:e.scoopJid}),this.options.onUserMessage?.(e.text,e.messageId,e.scoopJid);break;case`status`:this.options.onStatus?.(e.scoopStatus);break;case`error`:rX.warn(`Error from leader`,{error:e.error}),this.emitEvent({type:`error`,error:e.error});break;case`targets.registry`:rX.info(`Target registry received from leader`,{targetCount:e.targets.length}),this.targetEntries=e.targets,this.options.onTargetsUpdated?.(this.targetEntries);break;case`cdp.request`:{let{requestId:t,localTargetId:n,method:r,params:i,sessionId:a}=e;this.executeLocalCDP(t,n,r,i,a);break}case`cdp.response`:this.routeCDPResponse(e);break;case`cdp.event`:for(let t of this.remoteTransports.values())t.handleEvent(e.method,e.params);break;case`tab.open`:this.executeLocalTabOpen(e.requestId,e.url);break;case`tab.opened`:{let t=this.tabOpenResolvers.get(e.requestId);t&&(this.tabOpenResolvers.delete(e.requestId),t.resolve(e.targetId));break}case`tab.open.error`:{let t=this.tabOpenResolvers.get(e.requestId);t&&(this.tabOpenResolvers.delete(e.requestId),t.reject(Error(e.error)));break}case`fs.request`:this.executeLocalFs(e.requestId,e.request);break;case`fs.response`:this.routeFsResponse(e.requestId,e.response);break;case`ping`:this.keepalive.receivePing(),this.sync.send({type:`pong`});break;case`pong`:this.keepalive.receivePong(),u(Date.now());break}}emitEvent(e){for(let t of this.eventListeners)try{t(e)}catch(t){rX.error(`Listener error`,{eventType:e.type,error:t instanceof Error?t.message:String(t)})}}createRemoteTransport(e,t){let n=new j({sendCDPRequest:(n,r,i,a)=>{this.sync.send({type:`cdp.request`,requestId:n,targetRuntimeId:e,localTargetId:t,method:r,params:i,sessionId:a})}});return this.remoteTransports.set(`${e}:${t}`,n),n}removeRemoteTransport(e,t){let n=`${e}:${t}`,r=this.remoteTransports.get(n);r&&(r.disconnect(),this.remoteTransports.delete(n))}openRemoteTab(e,t){let n=`tab-open-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;return new Promise((r,i)=>{this.tabOpenResolvers.set(n,{resolve:r,reject:i}),this.sync.send({type:`tab.open`,requestId:n,targetRuntimeId:e,url:t})})}async executeLocalTabOpen(e,t){let n=this.options.browserTransport;if(!n){this.sync.send({type:`tab.open.error`,requestId:e,error:`Follower has no browser transport`});return}try{let r=(await n.send(`Target.createTarget`,{url:t,background:!0})).targetId;this.sync.send({type:`tab.opened`,requestId:e,targetId:r}),this.options.onTargetsChanged?.()}catch(t){this.sync.send({type:`tab.open.error`,requestId:e,error:t instanceof Error?t.message:String(t)})}}async executeLocalCDP(e,t,n,r,i){let a=this.options.browserTransport;if(!a){this.sync.send({type:`cdp.response`,requestId:e,error:`Follower has no browser transport`});return}try{let t=await a.send(n,r,i);if(n===`Target.attachToTarget`&&t.sessionId){let e=t.sessionId;this.remoteCDPSessions.add(e),this.setupCDPEventForwarding(a,e),rX.debug(`Tracking remote CDP session`,{remoteSessionId:e})}n===`Target.detachFromTarget`&&i&&this.remoteCDPSessions.has(i)&&(this.remoteCDPSessions.delete(i),rX.debug(`Removed remote CDP session on detach`,{sessionId:i})),Ce(this.sync,e,t)}catch(t){this.sync.send({type:`cdp.response`,requestId:e,error:t instanceof Error?t.message:String(t)})}}setupCDPEventForwarding(e,t){for(let n of[`Page.frameNavigated`,`Page.loadEventFired`,`Page.domContentEventFired`,`Network.responseReceived`,`Network.loadingFinished`,`Network.requestWillBeSent`]){let r=e=>{if(e.sessionId!==t||!this.remoteCDPSessions.has(t))return;let{sessionId:r,...i}=e;this.sync.send({type:`cdp.event`,method:n,params:i,sessionId:t})};e.on(n,r),this.cdpEventCleanups.push(()=>e.off(n,r))}}cleanupCDPEventForwarding(){for(let e of this.cdpEventCleanups)e();this.cdpEventCleanups.length=0,this.remoteCDPSessions.clear()}routeCDPResponse(e){let t=_e(this.cdpChunkBuffers,e);if(t)for(let n of this.remoteTransports.values())n.handleResponse(e.requestId,t.result,t.error)}async executeLocalFs(e,t){let n=this.options.vfs;if(!n){this.sync.send({type:`fs.response`,requestId:e,response:{ok:!1,error:`Follower has no VFS`}});return}let r=await RY(n,t);for(let t of r)this.sync.send({type:`fs.response`,requestId:e,response:t})}routeFsResponse(e,t){let n=this.fsResolvers.get(e);if(!n)return;n.responses.push(t);let r=t.ok&&t.totalChunks||1;n.responses.length>=r&&(this.fsResolvers.delete(e),n.resolve(n.responses))}sendFsRequest(e,t){let n=`fs-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;return new Promise((r,i)=>{this.fsResolvers.set(n,{resolve:r,reject:i,responses:[]}),this.sync.send({type:`fs.request`,requestId:n,targetRuntimeId:e,request:t})})}};function aX(e,t){if(t)return`extension`;try{return cX(new URL(e))?`electron-overlay`:`standalone`}catch{return`standalone`}}function oX(e,t){return e===`electron-overlay`||e===`standalone`&&t}function sX(e){try{let t=new URL(e).searchParams.get(`tab`);return t&&Vi(t)?t:zi}catch{return zi}}function cX(e){return e.pathname===`/electron`||e.pathname===`/electron/`||e.searchParams.get(`runtime`)===`electron-overlay`}function lX(e){let t=new URL(e);return`${t.protocol===`https:`?`wss:`:`ws:`}//${t.host}/licks-ws`}function uX(e,t){return`${new URL(e).origin}/webhooks/${t}`}function dX(e,t){return`${e.replace(/\/+$/,``)}/${t.replace(/^\/+/,``)}`}function fX(e){return typeof e==`object`&&!!e&&`type`in e&&e.type===`slicc-electron-overlay:set-tab`}var pX=[`/shared/sprinkles`];async function mX(e){let t=new Map;for(let n of pX)await e.exists(n)&&await hX(e,n,t);return await hX(e,`/`,t),t}async function hX(e,t,n){for await(let r of e.walk(t)){if(!r.endsWith(`.shtml`))continue;let t=gX(r);if(!n.has(t)){let i;try{i=await e.readFile(r,{encoding:`utf-8`})??``}catch{i=``}n.set(t,{name:t,path:r,title:_X(i,t),autoOpen:vX(i)})}}}function gX(e){let t=e.split(`/`).pop()??e;return t.endsWith(`.shtml`)?t.slice(0,-6):t}function _X(e,t){let n=e.match(/data-sprinkle-title=["']([^"']+)["']/);if(n)return n[1];let r=e.match(/<title>([^<]+)<\/title>/i);return r?r[1].trim():t}function vX(e){return/data-sprinkle-autoopen\b/.test(e)}var yX=class{listeners=new Map;lickHandler;fs;closeHandler;constructor(e,t,n){this.fs=e,this.lickHandler=t,this.closeHandler=n}createAPI(e){return{name:e,lick:t=>{let n=typeof t==`string`?t:t.action,r=typeof t==`string`?void 0:t.data,i={type:`sprinkle`,sprinkleName:e,targetScoop:void 0,timestamp:new Date().toISOString(),body:{action:n,data:r}};this.lickHandler(i)},on:(t,n)=>{let r=`${e}:${t}`,i=this.listeners.get(r);i||(i=new Set,this.listeners.set(r,i)),i.add(n)},off:(t,n)=>{let r=`${e}:${t}`;this.listeners.get(r)?.delete(n)},readFile:async e=>await this.fs.readFile(e,{encoding:`utf-8`}),setState:t=>{try{localStorage.setItem(`slicc-sprinkle-state:${e}`,JSON.stringify(t))}catch{}},getState:()=>{try{let t=localStorage.getItem(`slicc-sprinkle-state:${e}`);return t?JSON.parse(t):null}catch{return null}},open:e=>{let t=/^https?:|^chrome-extension:/.test(e)?e:HW(e);window.open(t,`_blank`)},close:()=>this.closeHandler(e)}}pushUpdate(e,t){let n=`${e}:update`,r=this.listeners.get(n);if(r)for(let e of r)try{e(t)}catch{}}removeSprinkle(e){for(let t of this.listeners.keys())t.startsWith(`${e}:`)&&this.listeners.delete(t)}},bX=r(`sprinkle-manager`),xX=`slicc-open-sprinkles`,SX=class{fs;bridge;callbacks;availableSprinkles=new Map;openSprinkles=new Map;constructor(e,t,n){this.fs=e,this.bridge=new yX(e,t,e=>this.close(e)),this.callbacks=n}async restoreOpenSprinkles(){try{let e=localStorage.getItem(xX);if(!e){for(let e of this.availableSprinkles.values())if(e.autoOpen)try{await this.open(e.name)}catch{bX.warn(`Failed to auto-open sprinkle`,{name:e.name})}return}let t=JSON.parse(e);for(let e of t)try{await this.open(e)}catch{bX.warn(`Failed to restore sprinkle`,{name:e})}}catch{}}persistOpenSprinkles(){try{localStorage.setItem(xX,JSON.stringify([...this.openSprinkles.keys()]))}catch{}}async openNewAutoOpenSprinkles(){await this.refresh();for(let e of this.availableSprinkles.values())if(e.autoOpen&&!this.openSprinkles.has(e.name))try{await this.open(e.name),bX.info(`Auto-opened new sprinkle after install`,{name:e.name})}catch{bX.warn(`Failed to auto-open new sprinkle`,{name:e.name})}}async refresh(){this.availableSprinkles=await mX(this.fs),bX.info(`Discovered sprinkles`,{count:this.availableSprinkles.size})}async open(e,t){if(this.openSprinkles.has(e)){bX.info(`Sprinkle already open`,{name:e});return}let n=this.availableSprinkles.get(e);if(n||=(await this.refresh(),this.availableSprinkles.get(e)),!n)throw Error(`Sprinkle not found: ${e}`);let r=await this.fs.readFile(n.path,{encoding:`utf-8`}),i=document.createElement(`div`);i.className=`sprinkle-panel`,i.style.cssText=`width: 100%; height: 100%; display: flex; flex-direction: column; overflow: hidden;`,i.dataset.sprinkle=e,this.openSprinkles.set(e,{renderer:null,container:i}),this.callbacks.addSprinkle(e,n.title,i,t);let a=new $r(i,this.bridge.createAPI(e));await a.render(r,e),this.openSprinkles.get(e).renderer=a,this.persistOpenSprinkles(),$q(e),bX.info(`Sprinkle opened`,{name:e,title:n.title})}close(e){let t=this.openSprinkles.get(e);t&&(t.renderer?.dispose(),t.container.remove(),this.bridge.removeSprinkle(e),this.openSprinkles.delete(e),this.callbacks.removeSprinkle(e),this.persistOpenSprinkles(),bX.info(`Sprinkle closed`,{name:e}))}available(){return Array.from(this.availableSprinkles.values())}opened(){return Array.from(this.openSprinkles.keys())}sendToSprinkle(e,t){let n=this.openSprinkles.get(e);if(!n){bX.warn(`Cannot send to closed sprinkle`,{name:e});return}this.bridge.pushUpdate(e,t),n.renderer.pushUpdate(t)}},CX=r(`main`),wX=`slicc-pending-mount`,TX=`pendingMount`;async function EX(e){let t=await new Promise((e,t)=>{let n=indexedDB.open(wX,1);n.onupgradeneeded=()=>n.result.createObjectStore(`handles`),n.onsuccess=()=>e(n.result),n.onerror=()=>t(n.error)}),n=t.transaction(`handles`,`readwrite`);n.objectStore(`handles`).put(e,TX),await new Promise(e=>n.oncomplete=()=>e()),t.close()}async function DX(e){let t;try{t=await new Promise((e,t)=>{let n=indexedDB.open(wX,1);n.onsuccess=()=>e(n.result),n.onerror=()=>t(n.error)})}catch{return}let n=t.transaction(`handles`,`readwrite`),r=await new Promise(e=>{let t=n.objectStore(`handles`).get(TX);t.onsuccess=()=>e(t.result),t.onerror=()=>e(void 0)});if(r){n.objectStore(`handles`).delete(TX),await new Promise(e=>n.oncomplete=()=>e());let t=`/mnt/${r.name}`;await e.mount(t,r),CX.info(`Mounted folder from welcome onboarding`,{name:r.name,path:t})}t.close()}function OX(){let e=document.createElement(`div`);e.className=`skill-drop-overlay`;let t=document.createElement(`div`);t.className=`skill-drop-overlay__card`;let n=document.createElement(`div`);n.className=`skill-drop-overlay__title`,t.appendChild(n);let r=document.createElement(`div`);return r.className=`skill-drop-overlay__desc`,t.appendChild(r),e.appendChild(t),document.body.appendChild(e),{show(t,i){n.textContent=t,r.textContent=i,e.classList.add(`skill-drop-overlay--visible`)},hide(){e.classList.remove(`skill-drop-overlay--visible`)}}}function kX(){let e=document.createElement(`div`);return e.className=`skill-drop-toast-container`,document.body.appendChild(e),(t,n)=>{let r=document.createElement(`div`);r.className=`skill-drop-toast skill-drop-toast--${n}`,r.textContent=t,e.appendChild(r),requestAnimationFrame(()=>r.classList.add(`skill-drop-toast--visible`)),window.setTimeout(()=>{r.classList.remove(`skill-drop-toast--visible`),window.setTimeout(()=>r.remove(),180)},4200)}}function AX(e,t,n){let r=OX(),i=0,a=!1,o=()=>{i=0,a||r.hide()};window.addEventListener(`dragenter`,e=>{la(e.dataTransfer)&&(e.preventDefault(),i+=1,a||r.show(`Drop .skill to install`,`Unpack into /workspace/skills/{name}.`))}),window.addEventListener(`dragover`,e=>{la(e.dataTransfer)&&(e.preventDefault(),e.dataTransfer&&(e.dataTransfer.dropEffect=`copy`),a||r.show(`Drop .skill to install`,`Unpack into /workspace/skills/{name}.`))}),window.addEventListener(`dragleave`,()=>{i!==0&&(i=Math.max(0,i-1),i===0&&!a&&r.hide())}),window.addEventListener(`dragend`,o),window.addEventListener(`blur`,o),window.addEventListener(`drop`,async s=>{let c=ua(s.dataTransfer);if(!c){o();return}if(s.preventDefault(),i=0,a){r.hide(),t(`Another .skill installation is already in progress.`,`error`);return}a=!0,r.show(`Installing skill…`,c.name);try{let r=await he(e,c);await n(),t(`Installed "${r.skillName}" to ${r.destinationPath} (${r.fileCount} files). Run "skill install ${r.skillName}" to apply it.`,`success`)}catch(e){t(`Failed to install dropped skill: ${e instanceof Error?e.message:String(e)}`,`error`)}finally{a=!1,r.hide()}})}async function jX(e){let{OffscreenClient:t}=await y(async()=>{let{OffscreenClient:e}=await import(`./offscreen-client-ABShEPNe.js`);return{OffscreenClient:e}},__vite__mapDeps([20,13])),{VirtualFS:n}=await y(async()=>{let{VirtualFS:e}=await import(`./fs-f8JZDPIF.js`).then(e=>e.t);return{VirtualFS:e}},__vite__mapDeps([17,1])),r=new Ki(e,!0);window.__slicc_debug_tabs=e=>r.setDebugTabs(e),await r.panels.chat.initSession(`session-cone`);let i=null,a=await n.create({dbName:`slicc-fs`});r.panels.fileBrowser.setFs(a),CX.info(`File browser wired to shared VFS (local IndexedDB)`);let o=new BroadcastChannel(`preview-vfs`);o.onmessage=e=>{if(e.data?.type!==`preview-vfs-read`)return;let{id:t,path:n,asText:r}=e.data;(async()=>{try{let e=r?`utf-8`:`binary`,i=await a.readFile(n,{encoding:e});o.postMessage({type:`preview-vfs-response`,id:t,content:i})}catch(e){let r=e instanceof Error?e.message:String(e);r.includes(`ENOENT`)||CX.error(`Preview VFS read failed`,{path:n,error:r}),o.postMessage({type:`preview-vfs-response`,id:t,error:r})}})()},AX(a,kX(),async()=>{await r.panels.fileBrowser.refresh()});try{let{WasmShell:e}=await y(async()=>{let{WasmShell:e}=await import(`./shell-_xMHLn02.js`);return{WasmShell:e}},[]),{PanelCdpProxy:t,BrowserAPI:n}=await y(async()=>{let{PanelCdpProxy:e,BrowserAPI:t}=await import(`./cdp-DNK51gjc.js`).then(e=>e.t);return{PanelCdpProxy:e,BrowserAPI:t}},__vite__mapDeps([21,1,4,13])),i=new t;await i.connect();let o=new e({fs:a,browserAPI:new n(i)});await r.panels.terminal.mountShell(o),CX.info(`Terminal mounted with shared VFS and BrowserAPI (CDP proxy)`)}catch(e){CX.warn(`Failed to mount shell to terminal`,e)}let s,c=new Set,l=async e=>{i=e,s.selectedScoopJid=e.jid,r.panels.memory.setSelectedScoop(e.jid),r.setScoopSwitcherSelected?.(e.jid),r.panels.scoops.setSelectedJid(e.jid);let t=e.isCone?`session-cone`:`session-${e.folder}`,n=e.isCone?void 0:e.name;await r.panels.chat.switchToContext(t,!e.isCone,n),s.isProcessing(e.jid)&&r.panels.chat.setProcessing(!0)};s=new t({onStatusChange:(e,t)=>{r.panels.scoops.updateScoopStatus(e,t),r.updateScoopSwitcherStatus?.(e,t),i?.jid===e&&(r.setAgentProcessing(t===`processing`),t===`processing`?r.panels.chat.setProcessing(!0):t===`ready`&&r.panels.chat.setProcessing(!1))},onScoopCreated:e=>{r.panels.scoops.refreshScoops(),r.refreshScoopSwitcher?.(),i||(i=e,s.selectedScoopJid=e.jid,r.panels.memory.setSelectedScoop(e.jid))},onScoopListUpdate:()=>{let e=new Set(s.getScoops().map(e=>e.folder));for(let t of c)e.has(t)||r.panels.chat.deleteSessionById(`session-${t}`);if(c=e,r.panels.scoops.refreshScoops(),r.refreshScoopSwitcher?.(),!i){let e=s.getScoops().find(e=>e.isCone);e&&(i=e,s.selectedScoopJid=e.jid,r.panels.memory.setSelectedScoop(e.jid))}},onIncomingMessage:(e,t)=>{if(i?.jid===e){let e=t.channel===`delegation`?`**[Instructions from sliccy]**\n\n${t.content}`:t.content;r.panels.chat.addUserMessage(e)}},onReady:async()=>{try{CX.info(`Offscreen engine ready, scoop count:`,s.getScoops().length),window.localStorage.getItem(`slicc.trayJoinUrl`)&&chrome.runtime.sendMessage({source:`panel`,payload:{type:`refresh-tray-runtime`}}).catch(()=>{});let e=i??s.getScoops().find(e=>e.isCone)??s.getScoops()[0];e&&(i=e,s.selectedScoopJid=e.jid,await l(e))}catch(e){CX.error(`Failed to initialize on ready`,{error:e instanceof Error?e.message:String(e)})}}}),s.setLocalFS(a);let u=s.createAgentHandle();r.panels.chat.setAgent(u),r.panels.scoops.setOrchestrator(s),r.panels.memory.setOrchestrator(s),r.setScoopSwitcherOrchestrator?.(s),r.onScoopSelect=l,r.onModelChange=e=>{localStorage.setItem(`selected-model`,e),s.updateModel()},r.onClearChat=async()=>{let e=s.getScoops();for(let t of e){let e=t.isCone?`session-cone`:`session-${t.folder}`;await r.panels.chat.deleteSessionById(e)}s.clearAllMessages()},r.onClearFilesystem=async()=>{s.clearFilesystem()},r.panels.chat.onInlineSprinkleLick=(e,t)=>{s.sendSprinkleLick(`inline`,{action:e,data:t})};let d=new SX(a,async e=>{if(e.type===`sprinkle`){if(e.sprinkleName===`welcome`&&e.body?.action===`onboarding-complete`&&(localStorage.setItem(`slicc-welcomed`,`1`),e.body?.data?.mountWorkspace&&DX(a).catch(e=>CX.warn(`Failed to mount workspace from onboarding`,e))),e.sprinkleName===`welcome`&&e.body?.action===`request-mount`){try{let e=window;if(!e.showDirectoryPicker)throw Error(`showDirectoryPicker not supported`);let t=await e.showDirectoryPicker({mode:`readwrite`});await EX(t),d.sendToSprinkle(`welcome`,{action:`mount-complete`,dirName:t.name})}catch(e){e.name!==`AbortError`&&CX.warn(`Mount picker failed`,e),d.sendToSprinkle(`welcome`,{action:`mount-cancelled`})}return}s.sendSprinkleLick(e.sprinkleName,e.body)}},{addSprinkle:(e,t,n,i)=>r.addSprinkle(e,t,n,i),removeSprinkle:e=>r.removeSprinkle(e)});if(window.__slicc_sprinkleManager=d,window.__slicc_reloadSkills=()=>(chrome.runtime.sendMessage({source:`panel`,payload:{type:`reload-skills`}}),Promise.resolve()),s.setSprinkleOpHandler(e=>{let{id:t,op:n,name:r,data:i}=e;console.log(`[main-ext] sprinkle-op handler called`,{id:t,op:n,name:r}),(async()=>{try{let e;switch(n){case`list`:await d.refresh(),e=d.available();break;case`opened`:e=d.opened();break;case`refresh`:await d.refresh(),e=d.available().length;break;case`open`:await d.open(r),e=!0;break;case`close`:d.close(r),e=!0;break;case`send`:d.sendToSprinkle(r,i),e=!0;break;case`openNewAutoOpen`:await d.openNewAutoOpenSprinkles(),e=!0;break}console.log(`[main-ext] sprinkle-op response sending`,{id:t,op:n,result:typeof e}),chrome.runtime.sendMessage({source:`panel`,payload:{type:`sprinkle-op-response`,id:t,result:e}}).catch(()=>{})}catch(e){chrome.runtime.sendMessage({source:`panel`,payload:{type:`sprinkle-op-response`,id:t,error:e instanceof Error?e.message:String(e)}}).catch(()=>{})}})()}),await d.refresh(),r.onSprinkleClose=e=>d.close(e),r.getAvailableSprinkles=()=>{let e=new Set(d.opened());return d.available().filter(t=>!e.has(t.name)).map(e=>({name:e.name,title:e.title}))},r.onOpenSprinkle=(e,t)=>d.open(e,t),r.updateAddButtons(),await d.restoreOpenSprinkles(),!localStorage.getItem(`slicc-welcomed`)&&d.available().some(e=>e.name===`welcome`))try{await d.open(`welcome`)}catch(e){CX.warn(`Failed to open welcome sprinkle`,e)}CX.info(`SprinkleManager initialized (extension mode)`),s.requestState(),CX.info(`Extension UI connected to offscreen agent engine`),Xq().catch(()=>{})}async function MX(){Qi(),oa();let e=document.getElementById(`app`);if(!e)throw Error(`#app element not found`);`serviceWorker`in navigator&&navigator.serviceWorker.register(`/preview-sw.js`,{scope:`/preview/`}).then(()=>CX.info(`Preview SW registered`)).catch(e=>CX.error(`Preview SW registration failed — preview feature will not work`,e)),te();let t=E(),n=c(window.localStorage);!t&&!n&&(await w({preferTrayJoin:!(window.location.port===`5710`||window.location.port===`3000`||window.location.port===``)}),t=E());let r=!t&&c(window.localStorage),a=typeof chrome<`u`&&!!chrome?.runtime?.id,o=aX(window.location.href,a);if(o===`extension`)return jX(e);let l=new Ki(e,o===`electron-overlay`);if(o===`electron-overlay`){let e=sX(window.location.href);l.setActiveTab(e);let t=document.createElement(`style`);t.id=`slicc-electron-overlay-runtime-style`,t.textContent=`
14410
14106
  #app > .tab-bar { display: none !important; }
14411
14107
  #app > .tab-content {
14412
14108
  height: calc(100vh - var(--s2-header-height));
@@ -14414,4 +14110,4 @@ ${t}
14414
14110
  #app > .tab-content > .tab-content__panel {
14415
14111
  height: 100%;
14416
14112
  }
14417
- `,document.head.appendChild(t),window.addEventListener(`message`,e=>{e.source===window.parent&&sX(e.data)&&l.setActiveTab(nX(`http://localhost/?tab=${e.data.tab??``}`))}),window.addEventListener(`keydown`,e=>{e.code===`Semicolon`&&(e.metaKey||e.ctrlKey)&&!e.shiftKey&&!e.altKey&&!e.repeat&&(e.preventDefault(),e.stopPropagation(),window.parent.postMessage({type:`slicc-electron-overlay:toggle`},`*`))},!0)}let u=wX();await l.panels.chat.initSession(`session-cone`),vX.info(`Session initialized`);let f=new we,p=new Set,m=e=>{vX.debug(`Emit to UI`,{type:e.type,listenerCount:p.size});for(let t of p)try{t(e)}catch(t){vX.error(`Listener error`,{eventType:e.type,error:t instanceof Error?t.message:String(t)})}},h=null,_=new Map,v=new Map;function b(){return Date.now().toString(36)+Math.random().toString(36).slice(2,8)}function x(e){let t=v.get(e);return t||(t=[],v.set(e,t)),t}function S(e,t){let n=x(e),r=_.get(e);if(r){let e=n.find(e=>e.id===r);if(e)return e}r=`scoop-${e}-${b()}`,_.set(e,r);let i=C.getScoops().find(t=>t.jid===e),a=i?.isCone?`cone`:i?.name??`unknown`,o={id:r,role:`assistant`,content:``,timestamp:Date.now(),toolCalls:[],isStreaming:!0,source:a,channel:t};return n.push(o),h?.jid===e&&m({type:`message_start`,messageId:r}),o}let C=new cY(l.getIframeContainer(),{onResponse:(e,t,n)=>{let r=S(e);n?r.content+=t:(r.content=t,r.isStreaming=!1),h?.jid===e&&(m({type:`content_delta`,messageId:r.id,text:t}),n||m({type:`content_done`,messageId:r.id}))},onResponseDone:e=>{let t=x(e),n=_.get(e);if(n){let r=t.find(e=>e.id===n);r&&(r.isStreaming=!1),h?.jid===e&&m({type:`content_done`,messageId:n}),_.delete(e)}},onSendMessage:(e,t)=>{vX.debug(`Send message requested`,{targetJid:e,textLength:t.length});let n=`msg-${b()}`,r={id:n,chatJid:e,senderId:`assistant`,senderName:`sliccy`,content:t,timestamp:new Date().toISOString(),fromAssistant:!0,channel:`web`};C.handleMessage(r),x(e).push({id:n,role:`assistant`,content:t,timestamp:Date.now()}),h?.jid===e&&(m({type:`message_start`,messageId:n}),m({type:`content_delta`,messageId:n,text:t}),m({type:`content_done`,messageId:n}))},onStatusChange:(e,t)=>{if(l.panels.scoops.updateScoopStatus(e,t),l.updateScoopSwitcherStatus?.(e,t),h?.jid===e){if(l.setAgentProcessing(t===`processing`),t===`processing`)l.panels.chat.setProcessing(!0);else if(t===`ready`){l.panels.chat.setProcessing(!1);let t=_.get(e)??`done-${e}-${b()}`;_.delete(e),m({type:`turn_end`,messageId:t})}}},onError:(e,t)=>{vX.error(`Scoop error`,{scoopJid:e,error:t}),h?.jid===e&&m({type:`error`,error:t})},getBrowserAPI:()=>f,onToolStart:(e,t,n)=>{if(new Set([`send_message`,`list_scoops`,`list_tasks`]).has(t))return;let r=S(e);r.toolCalls||=[],r.toolCalls.push({id:b(),name:t,input:n}),h?.jid===e&&m({type:`tool_use_start`,messageId:r.id,toolName:t,toolInput:n})},onToolEnd:(e,t,n,r)=>{if(new Set([`send_message`,`list_scoops`,`list_tasks`]).has(t))return;let i=x(e),a=_.get(e);if(a){let e=i.find(e=>e.id===a);if(e?.toolCalls){let i=[...e.toolCalls].reverse().find(e=>e.name===t&&e.result===void 0);i&&(i.result=n,i.isError=r)}}h?.jid===e&&a&&m({type:`tool_result`,messageId:a,toolName:t,result:n,isError:r})},onToolUI:(e,t,n,r)=>{let i=_.get(e);i?m({type:`tool_ui`,messageId:i,toolName:t,requestId:n,html:r}):vX.warn(`Cannot emit tool_ui - no message ID for scoop`,{scoopJid:e,requestId:n})},onToolUIDone:(e,t)=>{let n=_.get(e);n&&m({type:`tool_ui_done`,messageId:n,requestId:t})},onIncomingMessage:(e,t)=>{let n={id:t.id,role:`user`,content:t.channel===`delegation`?`**[Instructions from sliccy]**\n\n${t.content}`:t.content,timestamp:new Date(t.timestamp).getTime(),source:t.channel===`delegation`?`delegation`:void 0,channel:t.channel};x(e).push(n),h?.jid===e&&(m({type:`message_start`,messageId:t.id}),m({type:`content_delta`,messageId:t.id,text:n.content}),m({type:`content_done`,messageId:t.id}))}});await C.init(),l.panels.scoops.setOrchestrator(C),l.panels.memory.setOrchestrator(C),l.setScoopSwitcherOrchestrator?.(C);let T=C.getSharedFS();if(T){l.panels.fileBrowser.setFs(T),vX.info(`File browser wired to shared VFS`);let e=new BroadcastChannel(`preview-vfs`);e.onmessage=t=>{if(t.data?.type!==`preview-vfs-read`)return;let{id:n,path:r,asText:i}=t.data;(async()=>{try{let t=i?`utf-8`:`binary`,a=await T.readFile(r,{encoding:t});e.postMessage({type:`preview-vfs-response`,id:n,content:a})}catch(t){let i=t instanceof Error?t.message:String(t);i.includes(`ENOENT`)||vX.error(`Preview VFS read failed`,{path:r,error:i}),e.postMessage({type:`preview-vfs-response`,id:n,error:i})}})()},TX(T,(e,t)=>{t===`error`?vX.warn(`Dropped skill install failed`,{message:e}):vX.info(`Dropped skill installed`,{message:e}),u(e,t)},async()=>{await l.panels.fileBrowser.refresh()});try{let{WasmShell:e}=await y(async()=>{let{WasmShell:e}=await import(`./shell-DAALhTM2.js`);return{WasmShell:e}},[]),t=new e({fs:T,browserAPI:f});await l.panels.terminal.mountShell(t),vX.info(`Terminal mounted with shared VFS`);try{let{BshWatchdog:e}=await y(async()=>{let{BshWatchdog:e}=await import(`./bsh-watchdog-By5z523c.js`);return{BshWatchdog:e}},__vite__mapDeps([22,13])),t=new e({browserAPI:f,fs:T});t.start(),window.addEventListener(`beforeunload`,()=>t.stop(),{once:!0}),vX.info(`BSH navigation watchdog started`)}catch(e){vX.warn(`Failed to start BSH watchdog`,e)}}catch(e){vX.warn(`Failed to mount shell to terminal`,e)}}let D=C.getScoops(),O=D.some(e=>e.isCone);if(r)vX.info(`Skipping local cone bootstrap while joining a tray without a configured provider`);else if(!O)h=await l.panels.scoops.createScoop(`Cone`,!0),vX.info(`Created cone`);else{let e=new URLSearchParams(window.location.search).get(`scoop`);if(e){let t=D.find(t=>t.folder===e);t?(h=t,vX.info(`Restored scoop from URL`,{folder:e})):h=D.find(e=>e.isCone)??D[0]}else h=D.find(e=>e.isCone)??D[0]}h&&l.panels.memory.setSelectedScoop(h.jid);let ee=null,ne={sendMessage(e,t){if(!h){m({type:`error`,error:`No scoop selected`});return}let n={id:t??`msg-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,chatJid:h.jid,senderId:`user`,senderName:`User`,content:e,timestamp:new Date().toISOString(),fromAssistant:!1,channel:`web`};x(h.jid).push({id:n.id,role:`user`,content:e,timestamp:Date.now()}),ee?.broadcastUserMessage(e,n.id),C.handleMessage(n),C.createScoopTab(h.jid)},onEvent(e){return p.add(e),()=>p.delete(e)},stop(){h&&(C.stopScoop(h.jid),C.clearQueuedMessages(h.jid).catch(e=>{vX.error(`Failed to clear queued messages on stop`,{error:e instanceof Error?e.message:String(e)})}))}};l.panels.chat.setAgent(ne),l.panels.chat.setDeleteQueuedMessageCallback(e=>{if(h){C.deleteQueuedMessage(h.jid,e).catch(t=>{vX.error(`Failed to delete queued message`,{messageId:e,error:t instanceof Error?t.message:String(t)})});let t=v.get(h.jid);if(t){let n=t.findIndex(t=>t.id===e);n!==-1&&t.splice(n,1)}}}),vX.info(`Cone agent handle wired to chat UI`);let{getLickManager:k}=await y(async()=>{let{getLickManager:e}=await import(`./lick-manager-DRZhheH4.js`);return{getLickManager:e}},[]),re=k();await re.init(),C.setLickManager(re);let ie=e=>{let t=e.type===`webhook`,n=e.type===`sprinkle`,r=t?e.webhookName:n?e.sprinkleName:e.cronName,i=t?e.webhookId:n?e.sprinkleName:e.cronId,a=e.type;if(vX.debug(`Lick event`,{type:e.type,name:r,targetScoop:e.targetScoop}),n&&e.sprinkleName===`welcome`&&e.body?.action===`onboarding-complete`&&(localStorage.setItem(`slicc-welcomed`,`1`),e.body?.data?.mountWorkspace&&T&&SX(T).catch(e=>vX.warn(`Failed to mount workspace from onboarding`,e))),n&&e.sprinkleName===`welcome`&&e.body?.action===`request-mount`){(async()=>{try{let e=window;if(!e.showDirectoryPicker)throw Error(`showDirectoryPicker not supported`);let t=await e.showDirectoryPicker({mode:`readwrite`});await xX(t),ae?.sendToSprinkle(`welcome`,{action:`mount-complete`,dirName:t.name})}catch(e){e.name!==`AbortError`&&vX.warn(`Mount picker failed`,e),ae?.sendToSprinkle(`welcome`,{action:`mount-cancelled`})}})();return}let o=C.getScoops(),s;if(s=n||!e.targetScoop?o.find(e=>e.isCone):o.find(t=>t.name===e.targetScoop||t.folder===e.targetScoop||t.folder===`${e.targetScoop}-scoop`),s){let o=`${a}-${i}-${Date.now()}`,c=`[${t?`Webhook Event`:n?`Sprinkle Event`:`Cron Event`}: ${r}]\n\`\`\`json\n${JSON.stringify(e.body,null,2)}\n\`\`\``,u={id:o,chatJid:s.jid,senderId:a,senderName:`${a}:${r}`,content:c,timestamp:e.timestamp,fromAssistant:!1,channel:a};x(s.jid).push({id:o,role:`user`,content:c,timestamp:Date.now(),source:`lick`,channel:a}),h?.jid===s.jid&&l.panels.chat.addLickMessage(o,c,a),vX.info(`Routing lick to scoop`,{type:a,name:r,scoopJid:s.jid}),C.handleMessage(u)}else vX.warn(`Lick target scoop not found`,{targetScoop:e.targetScoop})};re.setEventHandler(ie),l.panels.chat.onInlineSprinkleLick=(e,t)=>{ie({type:`sprinkle`,sprinkleName:`inline`,targetScoop:void 0,timestamp:new Date().toISOString(),body:{action:e,data:t}})};let ae=null;if(T){if(ae=new _X(T,ie,{addSprinkle:(e,t,n,r)=>l.addSprinkle(e,t,n,r),removeSprinkle:e=>l.removeSprinkle(e)}),window.__slicc_sprinkleManager=ae,window.__slicc_reloadSkills=()=>C.reloadAllSkills(),await ae.refresh(),l.onSprinkleClose=e=>ae.close(e),l.getAvailableSprinkles=()=>{let e=new Set(ae.opened());return ae.available().filter(t=>!e.has(t.name)).map(e=>({name:e.name,title:e.title}))},l.onOpenSprinkle=(e,t)=>ae.open(e,t),l.updateAddButtons(),!localStorage.getItem(`slicc-welcomed`)&&ae.available().some(e=>e.name===`welcome`))try{await ae.open(`welcome`)}catch(e){vX.warn(`Failed to open welcome sprinkle`,e)}await ae.restoreOpenSprinkles(),vX.info(`SprinkleManager initialized`)}let oe=()=>{let e=iX(window.location.href),t=new WebSocket(e);t.onopen=()=>{vX.info(`Lick WebSocket connected`)},t.onmessage=async e=>{try{let n=JSON.parse(e.data);if(n.requestId){let e;try{switch(n.type){case`list_webhooks`:e={type:`response`,requestId:n.requestId,data:re.listWebhooks()};break;case`create_webhook`:{let t=await re.createWebhook(n.name||`default`,n.scoop,n.filter),r=rW().session,i=r?.webhookUrl?oX(r.webhookUrl,t.id):aX(window.location.href,t.id);e={type:`response`,requestId:n.requestId,data:{...t,url:i}};break}case`delete_webhook`:e=await re.deleteWebhook(n.id)?{type:`response`,requestId:n.requestId,data:{ok:!0}}:{type:`response`,requestId:n.requestId,data:{error:`Webhook not found`}};break;case`list_crontasks`:e={type:`response`,requestId:n.requestId,data:re.listCronTasks()};break;case`create_crontask`:{if(!n.name)throw Error(`name is required`);if(!n.cron)throw Error(`cron is required`);let t=await re.createCronTask(n.name,n.cron,n.scoop,n.filter);e={type:`response`,requestId:n.requestId,data:t};break}case`delete_crontask`:e=await re.deleteCronTask(n.id)?{type:`response`,requestId:n.requestId,data:{ok:!0}}:{type:`response`,requestId:n.requestId,data:{error:`Cron task not found`}};break;case`tray_status`:{let t=rW();e={type:`response`,requestId:n.requestId,data:{state:t.state,joinUrl:t.session?.joinUrl??null,workerBaseUrl:t.session?.workerBaseUrl??null,trayId:t.session?.trayId??null}};break}default:e={type:`response`,requestId:n.requestId,error:`Unknown request type: ${n.type}`}}}catch(t){e={type:`response`,requestId:n.requestId,error:t instanceof Error?t.message:String(t)}}t.send(JSON.stringify(e));return}n.type===`webhook_event`&&re.handleWebhookEvent(n.webhookId,n.headers,n.body)}catch(e){vX.error(`Failed to process lick message`,{error:e instanceof Error?e.message:String(e)})}},t.onclose=()=>{vX.warn(`Lick WebSocket disconnected, reconnecting in 3s...`),setTimeout(oe,3e3)},t.onerror=e=>{vX.error(`Lick WebSocket error`,{error:String(e)})}};oe(),l.onModelChange=e=>{localStorage.setItem(`selected-model`,e),C.updateModel()},l.onClearChat=async()=>{await C.clearAllMessages(),v.clear()},l.onClearFilesystem=async()=>{await C.resetFilesystem()};let se=async e=>{vX.info(`Scoop selected`,{jid:e.jid,name:e.name}),h=e,C.createScoopTab(e.jid),l.panels.memory.setSelectedScoop(e.jid),l.panels.scoops.setSelectedJid(e.jid);let t=e.isCone?`session-cone`:`session-${e.folder}`,n=v.get(e.jid),r=e.isCone?void 0:e.name;if(n&&n.length>0)await l.panels.chat.switchToContext(t,!e.isCone,r),l.panels.chat.loadMessages(n);else if(await l.panels.chat.switchToContext(t,!e.isCone,r),l.panels.chat.getMessages().length===0){let t=await C.getMessagesForScoop(e.jid);for(let n of t){let t=n.channel===`webhook`||n.channel===`cron`,r=n.channel===`delegation`;if(t){let t={id:n.id,role:`user`,content:n.content,timestamp:new Date(n.timestamp).getTime(),source:`lick`,channel:n.channel};x(e.jid).push(t),l.panels.chat.addUserMessage(n.content)}else if(r){let t={id:n.id,role:`user`,content:`**[Instructions from sliccy]**\n\n${n.content}`,timestamp:new Date(n.timestamp).getTime(),source:`delegation`,channel:`delegation`};x(e.jid).push(t),l.panels.chat.addUserMessage(t.content)}else n.fromAssistant?(m({type:`message_start`,messageId:n.id}),m({type:`content_delta`,messageId:n.id,text:n.content}),m({type:`content_done`,messageId:n.id})):l.panels.chat.addUserMessage(n.content)}}e.isCone&&C.isProcessing(e.jid)&&l.panels.chat.setProcessing(!0)};if(l.onScoopSelect=se,h&&(C.createScoopTab(h.jid),await se(h)),o===`standalone`||o===`electron-overlay`){let e=await i(),t=tX(o,e!==null)?s:null,n=await g({locationHref:window.location.href,storage:window.localStorage,envBaseUrl:null,defaultWorkerBaseUrl:t,runtimeConfigFetcher:async()=>e}),r=null,a=null,c=null;WG(()=>ee?(e,t)=>ee.sendFsRequest(e,t):r?(e,t)=>r.sendFsRequest(e,t):null),ZH(()=>ee?()=>ee.getBestFollowerForTeleport():null),QH(()=>ee?()=>ee.getConnectedFollowers():null);let u=e=>{c&&=(clearInterval(c),null),r?.close();let t=`follower-${e.bootstrapId}`,n=new $Y(e.channel,{browserTransport:f.getTransport(),browserAPI:f,onSnapshot:e=>{l.panels.chat.loadMessages(e)},onUserMessage:e=>{l.panels.chat.addUserMessage(e)},onStatus:e=>{l.panels.chat.setProcessing(e===`processing`)},onTargetsChanged:()=>void i()});r=n,f.setTrayTargetProvider(n),l.panels.chat.setAgent(n),n.requestSnapshot();let i=async()=>{try{let e=await f.listPages();n.advertiseTargets(e.map(e=>({targetId:e.targetId,title:e.title,url:e.url})),t)}catch{}};c=setInterval(i,5e3),i(),vX.info(`Follower sync wired to chat panel`,{trayId:e.trayId})},m=e=>{a?.cancel(),c&&=(clearInterval(c),null),r?.close(),r=null,a=DY({joinUrl:e,runtime:`slicc-standalone`,fetchImpl:dW()},{onConnected:e=>u(e),onReconnecting:e=>{vX.info(`Follower reconnecting`,{attempt:e})},onGaveUp:e=>{vX.warn(`Follower reconnect gave up`,{lastError:e})}})};if(window.addEventListener(`slicc:tray-join`,(e=>{m(e.detail.joinUrl)})),window.addEventListener(`beforeunload`,()=>{c&&clearInterval(c),r?.close(),a?.cancel()},{once:!0}),n?.joinUrl)m(n.joinUrl);else if(n?.workerBaseUrl){let e,t,r,i,a=()=>{t=new ZY({browserTransport:f.getTransport(),browserAPI:f,getMessages:()=>l.panels.chat.getMessages(),getScoopJid:()=>h?.jid??`cone`,onFollowerMessage:(e,t)=>{l.panels.chat.addUserMessage(e),ne.sendMessage(e,t)},onFollowerAbort:()=>{ne.stop()}}),ee=t,pW(()=>t.getConnectedFollowers()),f.setTrayTargetProvider(t),i&&clearInterval(i);let n=async()=>{try{let e=await f.listPages();t.setLocalTargets(e.map(e=>({targetId:e.targetId,title:e.title,url:e.url})))}catch{}};i=setInterval(n,5e3),n(),r=new TY({sendControlMessage:t=>e.sendControlMessage(t),onPeerConnected:(e,n)=>{vX.info(`Tray follower data channel opened`,{controllerId:e.controllerId,bootstrapId:e.bootstrapId,attempt:e.attempt,runtime:e.runtime}),t.addFollower(e.bootstrapId,n,{runtime:e.runtime,connectedAt:e.connectedAt??void 0})}})};a(),p.add(e=>{t.broadcastEvent(e)}),e=new sW({workerBaseUrl:n.workerBaseUrl,runtime:`slicc-standalone`,fetchImpl:dW(),onControlMessage:e=>{if(e.type===`webhook.event`){re.handleWebhookEvent(e.webhookId,e.headers,e.body);return}r.handleControlMessage(e).catch(e=>{vX.warn(`Tray leader bootstrap handling failed`,{error:e instanceof Error?e.message:String(e)})})}}),gW(async()=>{t.stop(),r.stop(),e.stop(),await e.clearSession();let n=await e.start(),i=d(window.location.href,n.workerBaseUrl,n.trayId);return i!==window.location.href&&window.history.replaceState(window.history.state,``,i),a(),rW()}),e.start().then(e=>{let t=d(window.location.href,e.workerBaseUrl,e.trayId);t!==window.location.href&&window.history.replaceState(window.history.state,``,t)}).catch(e=>{vX.warn(`Leader tray join failed`,{error:e instanceof Error?e.message:String(e)})}),window.addEventListener(`beforeunload`,()=>{clearInterval(i),t.stop(),r.stop(),e.stop()},{once:!0})}}vX.info(`Orchestrator initialized — cone+scoops ready`,{scoopCount:C.getScoops().length}),Wq().catch(()=>{})}DX().catch(e=>{vX.error(`Fatal error`,e);let t=document.getElementById(`app`);if(t){let n=document.createElement(`div`);n.style.cssText=`padding: 2rem; text-align: center;`;let r=document.createElement(`h1`);r.style.color=`var(--s2-negative, #e34850)`,r.textContent=`Failed to start`;let i=document.createElement(`p`);i.style.color=`var(--s2-content-tertiary, #717171)`,i.textContent=e.message,n.appendChild(r),n.appendChild(i);let a=document.createElement(`button`);for(a.textContent=`Reset all data & reload`,a.style.cssText=`margin-top: 1rem; padding: 0.5rem 1.5rem; background: var(--s2-negative, #e34850); color: #fff; border: none; border-radius: 6px; cursor: pointer; font-size: 14px;`,a.addEventListener(`click`,async()=>{a.disabled=!0,a.textContent=`Resetting…`;let e=await indexedDB.databases();await Promise.all(e.map(e=>e.name?new Promise(t=>{let n=indexedDB.deleteDatabase(e.name);n.onsuccess=()=>t(),n.onerror=()=>t(),n.onblocked=()=>t()}):Promise.resolve())),location.reload()}),n.appendChild(a);t.firstChild;)t.removeChild(t.firstChild);t.appendChild(n)}});export{FH as a,ti as c,nJ as i,Qr as l,iY as n,fV as o,oY as r,$r as s,rY as t};
14113
+ `,document.head.appendChild(t),window.addEventListener(`message`,e=>{e.source===window.parent&&fX(e.data)&&l.setActiveTab(sX(`http://localhost/?tab=${e.data.tab??``}`))}),window.addEventListener(`keydown`,e=>{e.code===`Semicolon`&&(e.metaKey||e.ctrlKey)&&!e.shiftKey&&!e.altKey&&!e.repeat&&(e.preventDefault(),e.stopPropagation(),window.parent.postMessage({type:`slicc-electron-overlay:toggle`},`*`))},!0)}let u=kX();await l.panels.chat.initSession(`session-cone`),CX.info(`Session initialized`);let f=new we,p=new Set,m=e=>{CX.debug(`Emit to UI`,{type:e.type,listenerCount:p.size});for(let t of p)try{t(e)}catch(t){CX.error(`Listener error`,{eventType:e.type,error:t instanceof Error?t.message:String(t)})}},h=null,_=new Map,v=new Map;function b(){return Date.now().toString(36)+Math.random().toString(36).slice(2,8)}function x(e){let t=v.get(e);return t||(t=[],v.set(e,t)),t}function S(e,t){let n=x(e),r=_.get(e);if(r){let e=n.find(e=>e.id===r);if(e)return e}r=`scoop-${e}-${b()}`,_.set(e,r);let i=C.getScoops().find(t=>t.jid===e),a=i?.isCone?`cone`:i?.name??`unknown`,o={id:r,role:`assistant`,content:``,timestamp:Date.now(),toolCalls:[],isStreaming:!0,source:a,channel:t};return n.push(o),h?.jid===e&&m({type:`message_start`,messageId:r}),o}let C=new pY(l.getIframeContainer(),{onResponse:(e,t,n)=>{let r=S(e);n?r.content+=t:(r.content=t,r.isStreaming=!1),h?.jid===e&&(m({type:`content_delta`,messageId:r.id,text:t}),n||m({type:`content_done`,messageId:r.id}))},onResponseDone:e=>{let t=x(e),n=_.get(e);if(n){let r=t.find(e=>e.id===n);r&&(r.isStreaming=!1),h?.jid===e&&m({type:`content_done`,messageId:n}),_.delete(e)}},onSendMessage:(e,t)=>{CX.debug(`Send message requested`,{targetJid:e,textLength:t.length});let n=`msg-${b()}`,r={id:n,chatJid:e,senderId:`assistant`,senderName:`sliccy`,content:t,timestamp:new Date().toISOString(),fromAssistant:!0,channel:`web`};C.handleMessage(r),x(e).push({id:n,role:`assistant`,content:t,timestamp:Date.now()}),h?.jid===e&&(m({type:`message_start`,messageId:n}),m({type:`content_delta`,messageId:n,text:t}),m({type:`content_done`,messageId:n}))},onStatusChange:(e,t)=>{if(l.panels.scoops.updateScoopStatus(e,t),l.updateScoopSwitcherStatus?.(e,t),h?.jid===e){if(l.setAgentProcessing(t===`processing`),t===`processing`)l.panels.chat.setProcessing(!0);else if(t===`ready`){l.panels.chat.setProcessing(!1);let t=_.get(e)??`done-${e}-${b()}`;_.delete(e),m({type:`turn_end`,messageId:t})}}},onError:(e,t)=>{CX.error(`Scoop error`,{scoopJid:e,error:t}),h?.jid===e&&m({type:`error`,error:t})},getBrowserAPI:()=>f,onToolStart:(e,t,n)=>{if(new Set([`send_message`,`list_scoops`,`list_tasks`]).has(t))return;let r=S(e);r.toolCalls||=[],r.toolCalls.push({id:b(),name:t,input:n}),h?.jid===e&&m({type:`tool_use_start`,messageId:r.id,toolName:t,toolInput:n})},onToolEnd:(e,t,n,r)=>{if(new Set([`send_message`,`list_scoops`,`list_tasks`]).has(t))return;let i=x(e),a=_.get(e);if(a){let e=i.find(e=>e.id===a);if(e?.toolCalls){let i=[...e.toolCalls].reverse().find(e=>e.name===t&&e.result===void 0);i&&(i.result=n,i.isError=r)}}h?.jid===e&&a&&m({type:`tool_result`,messageId:a,toolName:t,result:n,isError:r})},onToolUI:(e,t,n,r)=>{let i=_.get(e);i?m({type:`tool_ui`,messageId:i,toolName:t,requestId:n,html:r}):CX.warn(`Cannot emit tool_ui - no message ID for scoop`,{scoopJid:e,requestId:n})},onToolUIDone:(e,t)=>{let n=_.get(e);n&&m({type:`tool_ui_done`,messageId:n,requestId:t})},onIncomingMessage:(e,t)=>{let n={id:t.id,role:`user`,content:t.channel===`delegation`?`**[Instructions from sliccy]**\n\n${t.content}`:t.content,timestamp:new Date(t.timestamp).getTime(),source:t.channel===`delegation`?`delegation`:void 0,channel:t.channel};x(e).push(n),h?.jid===e&&(m({type:`message_start`,messageId:t.id}),m({type:`content_delta`,messageId:t.id,text:n.content}),m({type:`content_done`,messageId:t.id}))}});await C.init(),l.panels.scoops.setOrchestrator(C),l.panels.memory.setOrchestrator(C),l.setScoopSwitcherOrchestrator?.(C);let T=C.getSharedFS();if(T){l.panels.fileBrowser.setFs(T),CX.info(`File browser wired to shared VFS`);let e=new BroadcastChannel(`preview-vfs`);e.onmessage=t=>{if(t.data?.type!==`preview-vfs-read`)return;let{id:n,path:r,asText:i}=t.data;(async()=>{try{let t=i?`utf-8`:`binary`,a=await T.readFile(r,{encoding:t});e.postMessage({type:`preview-vfs-response`,id:n,content:a})}catch(t){let i=t instanceof Error?t.message:String(t);i.includes(`ENOENT`)||CX.error(`Preview VFS read failed`,{path:r,error:i}),e.postMessage({type:`preview-vfs-response`,id:n,error:i})}})()},AX(T,(e,t)=>{t===`error`?CX.warn(`Dropped skill install failed`,{message:e}):CX.info(`Dropped skill installed`,{message:e}),u(e,t)},async()=>{await l.panels.fileBrowser.refresh()});try{let{WasmShell:e}=await y(async()=>{let{WasmShell:e}=await import(`./shell-_xMHLn02.js`);return{WasmShell:e}},[]),t=new e({fs:T,browserAPI:f});await l.panels.terminal.mountShell(t),CX.info(`Terminal mounted with shared VFS`);try{let{BshWatchdog:e}=await y(async()=>{let{BshWatchdog:e}=await import(`./bsh-watchdog-By5z523c.js`);return{BshWatchdog:e}},__vite__mapDeps([22,13])),t=new e({browserAPI:f,fs:T});t.start(),window.addEventListener(`beforeunload`,()=>t.stop(),{once:!0}),CX.info(`BSH navigation watchdog started`)}catch(e){CX.warn(`Failed to start BSH watchdog`,e)}}catch(e){CX.warn(`Failed to mount shell to terminal`,e)}}let D=C.getScoops(),O=D.some(e=>e.isCone);if(r)CX.info(`Skipping local cone bootstrap while joining a tray without a configured provider`);else if(!O)h=await l.panels.scoops.createScoop(`Cone`,!0),CX.info(`Created cone`);else{let e=new URLSearchParams(window.location.search).get(`scoop`);if(e){let t=D.find(t=>t.folder===e);t?(h=t,CX.info(`Restored scoop from URL`,{folder:e})):h=D.find(e=>e.isCone)??D[0]}else h=D.find(e=>e.isCone)??D[0]}h&&l.panels.memory.setSelectedScoop(h.jid);let ee=null,ne={sendMessage(e,t){if(!h){m({type:`error`,error:`No scoop selected`});return}let n={id:t??`msg-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,chatJid:h.jid,senderId:`user`,senderName:`User`,content:e,timestamp:new Date().toISOString(),fromAssistant:!1,channel:`web`};x(h.jid).push({id:n.id,role:`user`,content:e,timestamp:Date.now()}),ee?.broadcastUserMessage(e,n.id),C.handleMessage(n),C.createScoopTab(h.jid)},onEvent(e){return p.add(e),()=>p.delete(e)},stop(){h&&(C.stopScoop(h.jid),C.clearQueuedMessages(h.jid).catch(e=>{CX.error(`Failed to clear queued messages on stop`,{error:e instanceof Error?e.message:String(e)})}))}};l.panels.chat.setAgent(ne),l.panels.chat.setDeleteQueuedMessageCallback(e=>{if(h){C.deleteQueuedMessage(h.jid,e).catch(t=>{CX.error(`Failed to delete queued message`,{messageId:e,error:t instanceof Error?t.message:String(t)})});let t=v.get(h.jid);if(t){let n=t.findIndex(t=>t.id===e);n!==-1&&t.splice(n,1)}}}),CX.info(`Cone agent handle wired to chat UI`);let{getLickManager:k}=await y(async()=>{let{getLickManager:e}=await import(`./lick-manager-CxkHyDmf.js`);return{getLickManager:e}},[]),re=k();await re.init(),C.setLickManager(re);let ie=e=>{let t=e.type===`webhook`,n=e.type===`sprinkle`,r=t?e.webhookName:n?e.sprinkleName:e.cronName,i=t?e.webhookId:n?e.sprinkleName:e.cronId,a=e.type;if(CX.debug(`Lick event`,{type:e.type,name:r,targetScoop:e.targetScoop}),n&&e.sprinkleName===`welcome`&&e.body?.action===`onboarding-complete`&&(localStorage.setItem(`slicc-welcomed`,`1`),e.body?.data?.mountWorkspace&&T&&DX(T).catch(e=>CX.warn(`Failed to mount workspace from onboarding`,e))),n&&e.sprinkleName===`welcome`&&e.body?.action===`request-mount`){(async()=>{try{let e=window;if(!e.showDirectoryPicker)throw Error(`showDirectoryPicker not supported`);let t=await e.showDirectoryPicker({mode:`readwrite`});await EX(t),ae?.sendToSprinkle(`welcome`,{action:`mount-complete`,dirName:t.name})}catch(e){e.name!==`AbortError`&&CX.warn(`Mount picker failed`,e),ae?.sendToSprinkle(`welcome`,{action:`mount-cancelled`})}})();return}let o=C.getScoops(),s;if(s=n||!e.targetScoop?o.find(e=>e.isCone):o.find(t=>t.name===e.targetScoop||t.folder===e.targetScoop||t.folder===`${e.targetScoop}-scoop`),s){let o=`${a}-${i}-${Date.now()}`,c=`[${t?`Webhook Event`:n?`Sprinkle Event`:`Cron Event`}: ${r}]\n\`\`\`json\n${JSON.stringify(e.body,null,2)}\n\`\`\``,u={id:o,chatJid:s.jid,senderId:a,senderName:`${a}:${r}`,content:c,timestamp:e.timestamp,fromAssistant:!1,channel:a};x(s.jid).push({id:o,role:`user`,content:c,timestamp:Date.now(),source:`lick`,channel:a}),h?.jid===s.jid&&l.panels.chat.addLickMessage(o,c,a),CX.info(`Routing lick to scoop`,{type:a,name:r,scoopJid:s.jid}),C.handleMessage(u)}else CX.warn(`Lick target scoop not found`,{targetScoop:e.targetScoop})};re.setEventHandler(ie),l.panels.chat.onInlineSprinkleLick=(e,t)=>{ie({type:`sprinkle`,sprinkleName:`inline`,targetScoop:void 0,timestamp:new Date().toISOString(),body:{action:e,data:t}})};let ae=null;if(T){if(ae=new SX(T,ie,{addSprinkle:(e,t,n,r)=>l.addSprinkle(e,t,n,r),removeSprinkle:e=>l.removeSprinkle(e)}),window.__slicc_sprinkleManager=ae,window.__slicc_reloadSkills=()=>C.reloadAllSkills(),await ae.refresh(),l.onSprinkleClose=e=>ae.close(e),l.getAvailableSprinkles=()=>{let e=new Set(ae.opened());return ae.available().filter(t=>!e.has(t.name)).map(e=>({name:e.name,title:e.title}))},l.onOpenSprinkle=(e,t)=>ae.open(e,t),l.updateAddButtons(),!localStorage.getItem(`slicc-welcomed`)&&ae.available().some(e=>e.name===`welcome`))try{await ae.open(`welcome`)}catch(e){CX.warn(`Failed to open welcome sprinkle`,e)}await ae.restoreOpenSprinkles(),CX.info(`SprinkleManager initialized`)}let oe=()=>{let e=lX(window.location.href),t=new WebSocket(e);t.onopen=()=>{CX.info(`Lick WebSocket connected`)},t.onmessage=async e=>{try{let n=JSON.parse(e.data);if(n.requestId){let e;try{switch(n.type){case`list_webhooks`:e={type:`response`,requestId:n.requestId,data:re.listWebhooks()};break;case`create_webhook`:{let t=await re.createWebhook(n.name||`default`,n.scoop,n.filter),r=rW().session,i=r?.webhookUrl?dX(r.webhookUrl,t.id):uX(window.location.href,t.id);e={type:`response`,requestId:n.requestId,data:{...t,url:i}};break}case`delete_webhook`:e=await re.deleteWebhook(n.id)?{type:`response`,requestId:n.requestId,data:{ok:!0}}:{type:`response`,requestId:n.requestId,data:{error:`Webhook not found`}};break;case`list_crontasks`:e={type:`response`,requestId:n.requestId,data:re.listCronTasks()};break;case`create_crontask`:{if(!n.name)throw Error(`name is required`);if(!n.cron)throw Error(`cron is required`);let t=await re.createCronTask(n.name,n.cron,n.scoop,n.filter);e={type:`response`,requestId:n.requestId,data:t};break}case`delete_crontask`:e=await re.deleteCronTask(n.id)?{type:`response`,requestId:n.requestId,data:{ok:!0}}:{type:`response`,requestId:n.requestId,data:{error:`Cron task not found`}};break;case`tray_status`:{let t=rW();e={type:`response`,requestId:n.requestId,data:{state:t.state,joinUrl:t.session?.joinUrl??null,workerBaseUrl:t.session?.workerBaseUrl??null,trayId:t.session?.trayId??null}};break}default:e={type:`response`,requestId:n.requestId,error:`Unknown request type: ${n.type}`}}}catch(t){e={type:`response`,requestId:n.requestId,error:t instanceof Error?t.message:String(t)}}t.send(JSON.stringify(e));return}n.type===`webhook_event`&&re.handleWebhookEvent(n.webhookId,n.headers,n.body)}catch(e){CX.error(`Failed to process lick message`,{error:e instanceof Error?e.message:String(e)})}},t.onclose=()=>{CX.warn(`Lick WebSocket disconnected, reconnecting in 3s...`),setTimeout(oe,3e3)},t.onerror=e=>{CX.error(`Lick WebSocket error`,{error:String(e)})}};oe(),l.onModelChange=e=>{localStorage.setItem(`selected-model`,e),C.updateModel()},l.onClearChat=async()=>{await C.clearAllMessages(),v.clear()},l.onClearFilesystem=async()=>{await C.resetFilesystem()};let se=async e=>{CX.info(`Scoop selected`,{jid:e.jid,name:e.name}),h=e,C.createScoopTab(e.jid),l.panels.memory.setSelectedScoop(e.jid),l.panels.scoops.setSelectedJid(e.jid);let t=e.isCone?`session-cone`:`session-${e.folder}`,n=v.get(e.jid),r=e.isCone?void 0:e.name;if(n&&n.length>0)await l.panels.chat.switchToContext(t,!e.isCone,r),l.panels.chat.loadMessages(n);else if(await l.panels.chat.switchToContext(t,!e.isCone,r),l.panels.chat.getMessages().length===0){let t=await C.getMessagesForScoop(e.jid);for(let n of t){let t=n.channel===`webhook`||n.channel===`cron`,r=n.channel===`delegation`;if(t){let t={id:n.id,role:`user`,content:n.content,timestamp:new Date(n.timestamp).getTime(),source:`lick`,channel:n.channel};x(e.jid).push(t),l.panels.chat.addUserMessage(n.content)}else if(r){let t={id:n.id,role:`user`,content:`**[Instructions from sliccy]**\n\n${n.content}`,timestamp:new Date(n.timestamp).getTime(),source:`delegation`,channel:`delegation`};x(e.jid).push(t),l.panels.chat.addUserMessage(t.content)}else n.fromAssistant?(m({type:`message_start`,messageId:n.id}),m({type:`content_delta`,messageId:n.id,text:n.content}),m({type:`content_done`,messageId:n.id})):l.panels.chat.addUserMessage(n.content)}}e.isCone&&C.isProcessing(e.jid)&&l.panels.chat.setProcessing(!0)};if(l.onScoopSelect=se,h&&(C.createScoopTab(h.jid),await se(h)),o===`standalone`||o===`electron-overlay`){let e=await i(),t=oX(o,e!==null)?s:null,n=await g({locationHref:window.location.href,storage:window.localStorage,envBaseUrl:null,defaultWorkerBaseUrl:t,runtimeConfigFetcher:async()=>e}),r=null,a=null,c=null;qG(()=>ee?(e,t)=>ee.sendFsRequest(e,t):r?(e,t)=>r.sendFsRequest(e,t):null),ZH(()=>ee?()=>ee.getBestFollowerForTeleport():null),QH(()=>ee?()=>ee.getConnectedFollowers():null);let u=e=>{c&&=(clearInterval(c),null),r?.close();let t=`follower-${e.bootstrapId}`,n=new iX(e.channel,{browserTransport:f.getTransport(),browserAPI:f,onSnapshot:e=>{l.panels.chat.loadMessages(e)},onUserMessage:e=>{l.panels.chat.addUserMessage(e)},onStatus:e=>{l.panels.chat.setProcessing(e===`processing`)},onTargetsChanged:()=>void i()});r=n,f.setTrayTargetProvider(n),l.panels.chat.setAgent(n),n.requestSnapshot();let i=async()=>{try{let e=await f.listPages();n.advertiseTargets(e.map(e=>({targetId:e.targetId,title:e.title,url:e.url})),t)}catch{}};c=setInterval(i,5e3),i(),CX.info(`Follower sync wired to chat panel`,{trayId:e.trayId})},m=e=>{a?.cancel(),c&&=(clearInterval(c),null),r?.close(),r=null,a=MY({joinUrl:e,runtime:`slicc-standalone`,fetchImpl:dW()},{onConnected:e=>u(e),onReconnecting:e=>{CX.info(`Follower reconnecting`,{attempt:e})},onGaveUp:e=>{CX.warn(`Follower reconnect gave up`,{lastError:e})}})};if(window.addEventListener(`slicc:tray-join`,(e=>{m(e.detail.joinUrl)})),window.addEventListener(`beforeunload`,()=>{c&&clearInterval(c),r?.close(),a?.cancel()},{once:!0}),n?.joinUrl)m(n.joinUrl);else if(n?.workerBaseUrl){let e,t,r,i,a=()=>{t=new nX({browserTransport:f.getTransport(),browserAPI:f,getMessages:()=>l.panels.chat.getMessages(),getScoopJid:()=>h?.jid??`cone`,onFollowerMessage:(e,t)=>{l.panels.chat.addUserMessage(e),ne.sendMessage(e,t)},onFollowerAbort:()=>{ne.stop()}}),ee=t,pW(()=>t.getConnectedFollowers()),f.setTrayTargetProvider(t),i&&clearInterval(i);let n=async()=>{try{let e=await f.listPages();t.setLocalTargets(e.map(e=>({targetId:e.targetId,title:e.title,url:e.url})))}catch{}};i=setInterval(n,5e3),n(),r=new AY({sendControlMessage:t=>e.sendControlMessage(t),onPeerConnected:(e,n)=>{CX.info(`Tray follower data channel opened`,{controllerId:e.controllerId,bootstrapId:e.bootstrapId,attempt:e.attempt,runtime:e.runtime}),t.addFollower(e.bootstrapId,n,{runtime:e.runtime,connectedAt:e.connectedAt??void 0})}})};a(),p.add(e=>{t.broadcastEvent(e)}),e=new sW({workerBaseUrl:n.workerBaseUrl,runtime:`slicc-standalone`,fetchImpl:dW(),onControlMessage:e=>{if(e.type===`webhook.event`){re.handleWebhookEvent(e.webhookId,e.headers,e.body);return}r.handleControlMessage(e).catch(e=>{CX.warn(`Tray leader bootstrap handling failed`,{error:e instanceof Error?e.message:String(e)})})}}),gW(async()=>{t.stop(),r.stop(),e.stop(),await e.clearSession();let n=await e.start(),i=d(window.location.href,n.workerBaseUrl,n.trayId);return i!==window.location.href&&window.history.replaceState(window.history.state,``,i),a(),rW()}),e.start().then(e=>{let t=d(window.location.href,e.workerBaseUrl,e.trayId);t!==window.location.href&&window.history.replaceState(window.history.state,``,t)}).catch(e=>{CX.warn(`Leader tray join failed`,{error:e instanceof Error?e.message:String(e)})}),window.addEventListener(`beforeunload`,()=>{clearInterval(i),t.stop(),r.stop(),e.stop()},{once:!0})}}CX.info(`Orchestrator initialized — cone+scoops ready`,{scoopCount:C.getScoops().length}),Xq().catch(()=>{})}MX().catch(e=>{CX.error(`Fatal error`,e);let t=document.getElementById(`app`);if(t){let n=document.createElement(`div`);n.style.cssText=`padding: 2rem; text-align: center;`;let r=document.createElement(`h1`);r.style.color=`var(--s2-negative, #e34850)`,r.textContent=`Failed to start`;let i=document.createElement(`p`);i.style.color=`var(--s2-content-tertiary, #717171)`,i.textContent=e.message,n.appendChild(r),n.appendChild(i);let a=document.createElement(`button`);for(a.textContent=`Reset all data & reload`,a.style.cssText=`margin-top: 1rem; padding: 0.5rem 1.5rem; background: var(--s2-negative, #e34850); color: #fff; border: none; border-radius: 6px; cursor: pointer; font-size: 14px;`,a.addEventListener(`click`,async()=>{a.disabled=!0,a.textContent=`Resetting…`;let e=await indexedDB.databases();await Promise.all(e.map(e=>e.name?new Promise(t=>{let n=indexedDB.deleteDatabase(e.name);n.onsuccess=()=>t(),n.onerror=()=>t(),n.onblocked=()=>t()}):Promise.resolve())),location.reload()}),n.appendChild(a);t.firstChild;)t.removeChild(t.firstChild);t.appendChild(n)}});export{FH as a,ti as c,cJ as i,Qr as l,lY as n,fV as o,dY as r,$r as s,cY as t};