sliccy 1.34.2 → 1.34.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ui/assets/{es-DoVXtjfC.js → es-BToPWWPM.js} +1 -1
- package/dist/ui/assets/{index-27r5vb8i.js → index-CHCOW6vR.js} +65 -375
- package/dist/ui/assets/lick-manager-BIap53QC.js +1 -0
- package/dist/ui/assets/shell-D1BtrGhx.js +1 -0
- package/dist/ui/assets/sprinkle-renderer-1h7GfOJt.js +1 -0
- package/dist/ui/index.html +1 -1
- package/dist/ui/packages/webapp/index.html +1 -1
- package/package.json +1 -1
- package/dist/ui/assets/lick-manager-DRZhheH4.js +0 -1
- package/dist/ui/assets/shell-DAALhTM2.js +0 -1
- package/dist/ui/assets/sprinkle-renderer-Deu5t635.js +0 -1
|
@@ -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-
|
|
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-BToPWWPM.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={"&":`&`,"<":`<`,">":`>`,'"':`"`,"'":`'`},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-1h7GfOJt.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;
|
|
@@ -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-
|
|
2769
|
+
`,stderr:``,exitCode:0}})}var rG=null,iG=null;async function aG(){return rG||=y(()=>import(`./es-BToPWWPM.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.)
|
|
@@ -3043,12 +3043,12 @@ Requires the secret launch code to proceed.
|
|
|
3043
3043
|
`,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
3044
|
`,stderr:``,exitCode:0}):{stdout:``,stderr:`⚠️ WARNING: this will reset the entire environment, file system, chats, and scoops.
|
|
3045
3045
|
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
|
|
3047
|
-
`}function
|
|
3048
|
-
`}function
|
|
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=`https://www.sliccy.com/skills/catalog.json`;function JK(e){if(!(!e||!e.trim()))return e.split(`,`).map(e=>e.trim()).filter(Boolean)}function YK(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:JK(e.apps),tasks:JK(e.tasks),role:JK(e.role),purpose:JK(e.purpose)},priority:n}})}var XK={apps:3,tasks:2,role:1,purpose:1};function ZK(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*XK.apps,r.push(`apps(${i.join(`, `)})`));let a=(e.affinity.tasks??[]).filter(e=>t.tasks.includes(e));return a.length&&(n+=a.length*XK.tasks,r.push(`tasks(${a.join(`, `)})`)),(e.affinity.role??[]).includes(t.role)&&(n+=XK.role,r.push(`role(${t.role})`)),(e.affinity.purpose??[]).includes(t.purpose)&&(n+=XK.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 QK(e){let t=`upskill ${e.repo}`;return e.path&&(t+=` --path ${e.path}`),e.skill&&(t+=` --skill ${e.skill}`),t}var $K;function eq(){return $K||=A.create({dbName:WK}),$K}async function tq(){try{return(await(await eq()).readTextFile(GK)).trim()||void 0}catch{return}}function nq(e,t=KK){let n={Accept:t,"User-Agent":`slicc-upskill`};return e&&(n.Authorization=`Bearer ${e}`),n}async function rq(e){let t=await tq();return{hasToken:!!t,request:(n,r=KK)=>e(n,{headers:nq(t,r)})}}function iq(e,t){if(!e)return;let n=t.toLowerCase();for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return r}function aq(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 oq(e,t,n){let r=aq(e.body),i=r?` GitHub said: ${r}`:``,a=iq(e.headers,`retry-after`),o=iq(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 sq(){return`Discovery roots: /workspace/skills plus accessible **/.agents/skills/* and **/.claude/skills/* anywhere in the VFS.
|
|
3047
|
+
`}function cq(){return`Only native /workspace/skills entries are install-managed; compatibility-discovered .agents/.claude skills remain read-only.
|
|
3048
|
+
`}function lq(e){switch(e){case`native`:return`native`;case`agents`:return`.agents`;case`claude`:return`.claude`}}function uq(e){return e.source===`native`}function dq(e){return uq(e)?e.installed&&e.installedVersion?`installed (v${e.installedVersion})`:`available`:e.installed&&e.installedVersion?`compatibility (state v${e.installedVersion})`:`compatibility (read-only)`}function fq(e){return uq(e)?`install-managed (/workspace/skills)`:`compatibility-only (read-only)`}function pq(e,t){let n=`${t}:\n\n`;n+=` NAME VERSION SOURCE STATUS
|
|
3049
3049
|
`,n+=` ─────────────────────────────────────────────────────────────
|
|
3050
|
-
`;for(let t of e)n+=` ${t.name.padEnd(20)} ${t.manifest.version.padEnd(10)} ${
|
|
3051
|
-
`;for(let n of e.shadowedPaths)t+=` - ${n}\n`}return t}function
|
|
3050
|
+
`;for(let t of e)n+=` ${t.name.padEnd(20)} ${t.manifest.version.padEnd(10)} ${lq(t.source).padEnd(9)} ${dq(t)}\n`;return n+=`\n${sq()}`,n+=cq(),n}function mq(e){let t=`Skill: ${e.manifest.skill}\n`;if(t+=`Version: ${e.manifest.version}\n`,t+=`Description: ${e.manifest.description||`(none)`}\n`,t+=`Source: ${lq(e.source)}\n`,t+=`Source root: ${e.sourceRoot}\n`,t+=`Management: ${fq(e)}\n`,t+=`Status: ${dq(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 hq(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 gq(){return{stdout:`usage: upskill <command> [options]
|
|
3052
3052
|
|
|
3053
3053
|
Install skills from GitHub repositories, ClawHub, or Tessl registry.
|
|
3054
3054
|
|
|
@@ -3061,7 +3061,7 @@ Commands:
|
|
|
3061
3061
|
<clawhub-url> Install skill from ClawHub URL
|
|
3062
3062
|
tessl:<name> Install skill from Tessl registry
|
|
3063
3063
|
|
|
3064
|
-
${
|
|
3064
|
+
${sq()}${cq()}
|
|
3065
3065
|
|
|
3066
3066
|
GitHub Installation:
|
|
3067
3067
|
upskill owner/repo List available skills in repo
|
|
@@ -3102,21 +3102,20 @@ Examples:
|
|
|
3102
3102
|
upskill aemcoder/skills@fix/stateless-tab-targeting --all
|
|
3103
3103
|
upskill https://clawhub.ai/arun-8687/tavily-search
|
|
3104
3104
|
upskill tessl:postgres-pro
|
|
3105
|
-
`,stderr:``,exitCode:0}}async function
|
|
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/
|
|
3105
|
+
`,stderr:``,exitCode:0}}async function _q(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 vq(e){let t=e.match(/github\.com\/([^\/?#]+)\/([^\/?#]+)/);return t?{owner:t[1],repo:t[2].replace(/\.git$/,``)}:null}async function yq(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=vq(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 bq=10;async function xq(e,t,n=1){let[r,i]=await Promise.allSettled([_q(e,t),yq(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/bq),f=Math.max(1,Math.min(n,d)),p=(f-1)*bq,m=s.slice(p,p+bq),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
3107
|
`}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
3108
|
`,a.length>0&&(h+=` From ClawHub: upskill clawhub:<slug>
|
|
3109
3109
|
`),o.length>0&&(h+=` From Tessl: upskill <owner/repo> --skill <name>
|
|
3110
|
-
`),{stdout:h,stderr:``,exitCode:0}}async function
|
|
3111
|
-
`,exitCode:1};let i;try{let
|
|
3112
|
-
`,exitCode:
|
|
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:
|
|
3110
|
+
`),{stdout:h,stderr:``,exitCode:0}}async function Sq(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=Cq(f,i);return await jq(),{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 Cq(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=wq(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 wq(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 Tq(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=vq(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 Eq(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`?Eq(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 Dq(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 Oq(e,t,n,r,i,a){if(i){let n=await Eq(e,t,i,a);if(n.status===`ok`){let e=Dq(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(oq(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 kq(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 Eq(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=Dq(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 Fq(),await Nq(),{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: ${oq(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(oq(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(oq(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 jq(),{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 Aq(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 jq(){await Fq(),await Nq()}async function Mq(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 Nq(){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 Pq(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 Fq(){try{if(typeof window>`u`)return;let e=window.__slicc_sprinkleManager;e&&typeof e.openNewAutoOpenSprinkles==`function`&&await e.openNewAutoOpenSprinkles()}catch{}}async function Iq(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 e=await t(qK,{headers:{Accept:`application/json`}});if(e.status!==200)throw Error(`HTTP ${e.status}`);i=YK(JSON.parse(e.body).data)}catch(e){return{stdout:``,stderr:`upskill: failed to fetch skill catalog from ${qK}: ${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=ZK(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.
|
|
3112
|
+
`,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 Eq(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=Dq(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 Mq(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 jq()),{stdout:s,stderr:c,exitCode:c?1:0}}let s=`Recommended skills for you:
|
|
3114
3113
|
|
|
3115
|
-
`,c=0;for(let e of o){c++;let t=
|
|
3116
|
-
`,{stdout:s,stderr:``,exitCode:0}}function
|
|
3114
|
+
`,c=0;for(let e of o){c++;let t=QK(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
|
|
3115
|
+
`,{stdout:s,stderr:``,exitCode:0}}function Lq(e,t){return qP(`upskill`,async(n,r)=>{if(n.length===0||n.includes(`--help`)||n.includes(`-h`))return gq();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 Iq(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${sq()}${cq()}`,stderr:``,exitCode:0}:{stdout:pq(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:mq(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
3116
|
`,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
|
|
3119
|
-
`,exitCode:1};let r=await
|
|
3117
|
+
`,exitCode:1};u=n[++p]}else r.startsWith(`-`)||(l=r);p++}if(d)return xq(d,t,f);if(!l)return gq();let m=Aq(l);if(m){let n=r.getRegisteredCommands?.()??[];return Sq(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
|
|
3118
|
+
`,exitCode:1};let r=await Tq(n,t);if(`error`in r)return{stdout:``,stderr:`upskill: ${r.error}\n`,exitCode:1};let i=await rq(t);return kq(r.owner,r.repo,r.skillPath,r.skillName,e,i,c,t)}let h=Pq(l);if(h){let{owner:n,repo:r}=h,d=u??h.branch,f=await rq(t),p=await Oq(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 Eq(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=Dq(i.files);for(let t=0;t<m.length;t++){let i=m[t],o=await Mq(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 kq(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 jq()),{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 Rq(e){return qP(`skill`,async(t,n)=>{if(t.length===0||t.includes(`--help`)||t.includes(`-h`))return{stdout:`usage: skill <command> [options]
|
|
3120
3119
|
|
|
3121
3120
|
Commands:
|
|
3122
3121
|
list List discoverable skills and management status
|
|
@@ -3125,7 +3124,7 @@ Commands:
|
|
|
3125
3124
|
install <name> Install a native /workspace/skills skill (apply manifest)
|
|
3126
3125
|
uninstall <name> Uninstall a native /workspace/skills skill
|
|
3127
3126
|
|
|
3128
|
-
${
|
|
3127
|
+
${sq()}${cq()}
|
|
3129
3128
|
|
|
3130
3129
|
For installing skills from registries or GitHub, use 'upskill':
|
|
3131
3130
|
upskill search "query" Search ClawHub + Tessl
|
|
@@ -3137,12 +3136,12 @@ Examples:
|
|
|
3137
3136
|
skill list
|
|
3138
3137
|
skill info bluebubbles
|
|
3139
3138
|
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${
|
|
3141
|
-
`,exitCode:1};let r=await i.getSkillInfo(e,n);return r?{stdout:
|
|
3139
|
+
`,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${sq()}${cq()}\nInstall install-managed skills with: upskill owner/repo --all\n`,stderr:``,exitCode:0}:{stdout:pq(t,`Discoverable skills`),stderr:``,exitCode:0}}case`info`:{let n=t[1];if(!n)return{stdout:``,stderr:`skill: info requires a skill name
|
|
3140
|
+
`,exitCode:1};let r=await i.getSkillInfo(e,n);return r?{stdout:mq(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
3141
|
`,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
3142
|
`,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&&!
|
|
3145
|
-
`,exitCode:1};let r=await i.getSkillInfo(e,n);if(r&&!
|
|
3143
|
+
`,exitCode:1};let r=await i.getSkillInfo(e,n);if(r&&!uq(r))return{stdout:``,stderr:hq(`skill`,r),exitCode:1};let a=await i.applySkill(e,n);return a.success?(await Fq(),await Nq(),{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
|
|
3144
|
+
`,exitCode:1};let r=await i.getSkillInfo(e,n);if(r&&!uq(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 zq(e){return e.replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`).replace(/'/g,`'`)}var Bq=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
3145
|
`,stderr:``,exitCode:0}:{stdout:e.map(e=>e).join(`
|
|
3147
3146
|
`)+`
|
|
3148
3147
|
`,stderr:``,exitCode:0}}if(!n)return{stdout:``,stderr:`mount: mount point required
|
|
@@ -3150,7 +3149,7 @@ Usage: mount <target-path>
|
|
|
3150
3149
|
`,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
3150
|
<div class="sprinkle-action-card">
|
|
3152
3151
|
<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>${
|
|
3152
|
+
<div class="sprinkle-action-card__body">The agent wants to mount a local directory at <code>${zq(r)}</code>. This will give the agent read/write access to files in the directory you select.</div>
|
|
3154
3153
|
<div class="sprinkle-action-card__actions">
|
|
3155
3154
|
<button class="sprinkle-btn sprinkle-btn--secondary" data-action="deny">Deny</button>
|
|
3156
3155
|
<button class="sprinkle-btn sprinkle-btn--primary" data-action="approve">Select directory</button>
|
|
@@ -3158,7 +3157,7 @@ Usage: mount <target-path>
|
|
|
3158
3157
|
</div>
|
|
3159
3158
|
`,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
3159
|
`)+`
|
|
3161
|
-
`,stderr:``,exitCode:0}}};async function
|
|
3160
|
+
`,stderr:``,exitCode:0}}};async function Vq(e,t,n){return await n.fs.exists(e)?Hq(await n.fs.readFile(e),[`node`,e,...t],n):{stdout:``,stderr:`jsh: cannot find script '${e}'\n`,exitCode:127}}async function Hq(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
3161
|
const __stdout = [];
|
|
3163
3162
|
const __stderr = [];
|
|
3164
3163
|
const __origConsole = { log: console.log, error: console.error, warn: console.warn, info: console.info };
|
|
@@ -3201,8 +3200,8 @@ Usage: mount <target-path>
|
|
|
3201
3200
|
console.info = __origConsole.info;
|
|
3202
3201
|
return { stdout: __stdout.join(''), stderr: __stderr.join('') };
|
|
3203
3202
|
`,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
|
|
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
|
|
3203
|
+
`});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 Uq(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 Wq=null,Gq=!1;function Kq(){return typeof chrome<`u`&&chrome?.runtime?.id?`extension`:typeof document<`u`&&document.documentElement?.dataset?.electronOverlay?`electron`:`cli`}async function qq(){if(!Gq&&!(typeof localStorage<`u`&&localStorage.getItem(`telemetry-disabled`)===`true`))try{typeof window<`u`&&(window.SAMPLE_PAGEVIEWS_AT_RATE=`high`),Wq=(await y(()=>import(`./src-CpO2JX79.js`),[])).sampleRUM,Gq=!0,Wq&&Wq(`navigate`,{source:typeof document<`u`?document.referrer:``,target:Kq()})}catch{}}function Jq(e,t){Wq?.(`formsubmit`,{source:e,target:t})}function Yq(e){Wq?.(`fill`,{source:e})}function Xq(e){Wq?.(`viewblock`,{source:e})}function Zq(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 Qq(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 $q(e,t){if(Qq(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 eJ(e){if(e){if(e instanceof Headers){let t={};return e.forEach((e,n)=>{t[n]=e}),t}return e}}function tJ(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 nJ(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 rJ(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 iJ(){return typeof chrome<`u`&&chrome?.runtime?.id?async(e,t)=>{let n=eJ(t?.headers),r=await fetch(e,{method:t?.method??`GET`,headers:n,body:tJ(t?.body,n)}),i=await $q(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={...nJ(eJ(t?.headers)),"X-Target-URL":e},i={method:n,headers:r,cache:`no-store`};t?.body&&![`GET`,`HEAD`].includes(n)&&(i.body=tJ(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 $q(a,e),s={};a.headers.forEach((e,t)=>{s[t]=e});let c=rJ(s);return{status:a.status,statusText:a.statusText,headers:c,body:o,url:e}}}var aJ=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 Bq({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=iJ(),s=[r,a,Rq(e.fs),Lq(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?Uq(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 Hq(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){Yq(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
|
|
3204
|
+
`),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 Vq(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
3205
|
`,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
3206
|
`).entries()){if(e+n.length>=this.cursorPos)return t;e+=n.length+1}return 0}positionTerminalCursor(){let e=this.currentLine.split(`
|
|
3208
3207
|
`),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 +3215,9 @@ Usage: mount <target-path>
|
|
|
3216
3215
|
`,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
3216
|
`).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
3217
|
`);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=`${
|
|
3218
|
+
`+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=`${Zq(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=Zq(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())}},oJ=r(`tool:fs`);function sJ(e){return[cJ(e),lJ(e),uJ(e)]}function cJ(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;oJ.debug(`Read`,{path:n,offset:r,limit:i});try{let t=(await e.readTextFile(n)).split(`
|
|
3220
3219
|
`),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
|
|
3220
|
+
`)}}catch(e){let t=e instanceof Error?e.message:String(e);return oJ.error(`Read failed`,{path:n,error:t}),{content:t,isError:!0}}}}}function lJ(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;oJ.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 oJ.error(`Write failed`,{path:n,error:t}),{content:t,isError:!0}}}}}function uJ(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;oJ.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 oJ.error(`Edit failed`,{path:n,error:t}),{content:t,isError:!0}}}}}var dJ=r(`tool:bash`),fJ=/^(?:[A-Za-z_][A-Za-z0-9_]*=[^\s]+\s+)*(?:command\s+)?(?:grep|egrep|fgrep|rg)\b/;function pJ(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 mJ(e,t,n){return t!==1||n.trim()?!1:fJ.test(pJ(e))}function hJ(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;dJ.debug(`Execute`,{command:n});try{let t=await e.executeCommand(n);dJ.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&&!mJ(n,t.exitCode,t.stderr)}}catch(e){let t=e instanceof Error?e.message:String(e);return dJ.error(`Error`,{command:n,error:t}),{content:`Shell error: ${t}`,isError:!0}}}}}r(`tool:search`);var gJ=r(`tool:javascript`),_J=`<!DOCTYPE html><html><head><script>
|
|
3222
3221
|
const pendingVfs = new Map();
|
|
3223
3222
|
let vfsIdCounter = 0;
|
|
3224
3223
|
|
|
@@ -3337,10 +3336,10 @@ addEventListener('message', async (e) => {
|
|
|
3337
3336
|
}
|
|
3338
3337
|
}
|
|
3339
3338
|
});
|
|
3340
|
-
<\/script></head><body></body></html>`;function
|
|
3339
|
+
<\/script></head><body></body></html>`;function vJ(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);gJ.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`,()=>{gJ.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(_J),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);gJ.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}`;gJ.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
3340
|
`)),r.error?(a&&(a+=`
|
|
3342
3341
|
`),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
|
|
3342
|
+
`),a+=r.result),{content:a||`(no output)`})}catch(e){let t=e instanceof Error?e.message:String(e);return gJ.error(`JS execution error`,{error:t}),{content:`JavaScript error: ${t}`,isError:!0}}}}}var yJ=`# CLAUDE.md
|
|
3344
3343
|
|
|
3345
3344
|
This file covers the default virtual filesystem payload in \`packages/vfs-root/\`.
|
|
3346
3345
|
|
|
@@ -3350,15 +3349,14 @@ This file covers the default virtual filesystem payload in \`packages/vfs-root/\
|
|
|
3350
3349
|
|
|
3351
3350
|
## Directory Structure
|
|
3352
3351
|
|
|
3353
|
-
| Path
|
|
3354
|
-
|
|
|
3355
|
-
| \`packages/vfs-root/shared/\`
|
|
3356
|
-
| \`packages/vfs-root/workspace/\`
|
|
3357
|
-
| \`packages/vfs-root/shared/CLAUDE.md\`
|
|
3358
|
-
| \`packages/vfs-root/shared/sprinkles/\`
|
|
3359
|
-
| \`packages/vfs-root/shared/sounds/\`
|
|
3360
|
-
| \`packages/vfs-root/
|
|
3361
|
-
| \`packages/vfs-root/workspace/skills/\` | Default installable workspace skills |
|
|
3352
|
+
| Path | Purpose |
|
|
3353
|
+
| ------------------------------------- | ------------------------------------------------------------------ |
|
|
3354
|
+
| \`packages/vfs-root/shared/\` | Shared content that becomes \`/shared/\` in the VFS |
|
|
3355
|
+
| \`packages/vfs-root/workspace/\` | Default workspace content that becomes \`/workspace/\` in the VFS |
|
|
3356
|
+
| \`packages/vfs-root/shared/CLAUDE.md\` | Agent-facing runtime instructions bundled into \`/shared/CLAUDE.md\` |
|
|
3357
|
+
| \`packages/vfs-root/shared/sprinkles/\` | Built-in sprinkle UIs |
|
|
3358
|
+
| \`packages/vfs-root/shared/sounds/\` | Shared notification sounds |
|
|
3359
|
+
| \`packages/vfs-root/workspace/skills/\` | Default installable workspace skills |
|
|
3362
3360
|
|
|
3363
3361
|
## Adding Default Content
|
|
3364
3362
|
|
|
@@ -3366,7 +3364,6 @@ This file covers the default virtual filesystem payload in \`packages/vfs-root/\
|
|
|
3366
3364
|
|
|
3367
3365
|
- Add new built-in workspace skills under \`packages/vfs-root/workspace/skills/<skill-name>/\`.
|
|
3368
3366
|
- 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
3367
|
|
|
3371
3368
|
### Sprinkles
|
|
3372
3369
|
|
|
@@ -3383,314 +3380,7 @@ This file covers the default virtual filesystem payload in \`packages/vfs-root/\
|
|
|
3383
3380
|
\`packages/vfs-root/shared/CLAUDE.md\` is **agent-facing runtime content** bundled into the virtual filesystem.
|
|
3384
3381
|
|
|
3385
3382
|
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>
|
|
3383
|
+
`,bJ='# 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',xJ=`<!DOCTYPE html>
|
|
3694
3384
|
<html lang="en">
|
|
3695
3385
|
<head>
|
|
3696
3386
|
<meta charset="UTF-8">
|
|
@@ -4714,7 +4404,7 @@ if (hasState && violations && violations.length > 0) {
|
|
|
4714
4404
|
<\/script>
|
|
4715
4405
|
</body>
|
|
4716
4406
|
</html>
|
|
4717
|
-
`,
|
|
4407
|
+
`,SJ=`<!DOCTYPE html>
|
|
4718
4408
|
<html lang="en">
|
|
4719
4409
|
<head>
|
|
4720
4410
|
<meta charset="UTF-8">
|
|
@@ -5359,7 +5049,7 @@ init();
|
|
|
5359
5049
|
<\/script>
|
|
5360
5050
|
</body>
|
|
5361
5051
|
</html>
|
|
5362
|
-
`,
|
|
5052
|
+
`,CJ=`<!DOCTYPE html>
|
|
5363
5053
|
<html lang="en">
|
|
5364
5054
|
<head>
|
|
5365
5055
|
<meta charset="UTF-8">
|
|
@@ -6141,7 +5831,7 @@ function lickExportData() {
|
|
|
6141
5831
|
<\/script>
|
|
6142
5832
|
</body>
|
|
6143
5833
|
</html>
|
|
6144
|
-
`,
|
|
5834
|
+
`,wJ=`<!DOCTYPE html>
|
|
6145
5835
|
<html lang="en">
|
|
6146
5836
|
<head>
|
|
6147
5837
|
<meta charset="UTF-8">
|
|
@@ -6979,7 +6669,7 @@ body { font-family: var(--s2-font-family); font-size: 14px; line-height: 1.5; co
|
|
|
6979
6669
|
<\/script>
|
|
6980
6670
|
</body>
|
|
6981
6671
|
</html>
|
|
6982
|
-
`,
|
|
6672
|
+
`,TJ=`<!DOCTYPE html>
|
|
6983
6673
|
<html lang="en">
|
|
6984
6674
|
<head>
|
|
6985
6675
|
<meta charset="UTF-8">
|
|
@@ -7546,7 +7236,7 @@ if (hasData()) {
|
|
|
7546
7236
|
<\/script>
|
|
7547
7237
|
</body>
|
|
7548
7238
|
</html>
|
|
7549
|
-
`,
|
|
7239
|
+
`,EJ=`<!DOCTYPE html>
|
|
7550
7240
|
<html lang="en">
|
|
7551
7241
|
<head>
|
|
7552
7242
|
<meta charset="UTF-8">
|
|
@@ -8213,7 +7903,7 @@ function saveState() {
|
|
|
8213
7903
|
<\/script>
|
|
8214
7904
|
</body>
|
|
8215
7905
|
</html>
|
|
8216
|
-
`,
|
|
7906
|
+
`,DJ=`<!DOCTYPE html>
|
|
8217
7907
|
<html lang="en">
|
|
8218
7908
|
<head>
|
|
8219
7909
|
<meta charset="UTF-8">
|
|
@@ -8999,7 +8689,7 @@ if (document.getElementById('mainView').classList.contains('active')) {
|
|
|
8999
8689
|
<\/script>
|
|
9000
8690
|
</body>
|
|
9001
8691
|
</html>
|
|
9002
|
-
`,
|
|
8692
|
+
`,OJ=`<!DOCTYPE html>
|
|
9003
8693
|
<html lang="en">
|
|
9004
8694
|
<head>
|
|
9005
8695
|
<meta charset="UTF-8">
|
|
@@ -9757,7 +9447,7 @@ textarea.field-input { height: auto; min-height: 80px; padding: 10px 12px; resiz
|
|
|
9757
9447
|
<\/script>
|
|
9758
9448
|
</body>
|
|
9759
9449
|
</html>
|
|
9760
|
-
`,
|
|
9450
|
+
`,kJ=`<!DOCTYPE html>
|
|
9761
9451
|
<html lang="en">
|
|
9762
9452
|
<head>
|
|
9763
9453
|
<meta charset="UTF-8">
|
|
@@ -10567,7 +10257,7 @@ init();
|
|
|
10567
10257
|
<\/script>
|
|
10568
10258
|
</body>
|
|
10569
10259
|
</html>
|
|
10570
|
-
`,
|
|
10260
|
+
`,AJ=`<!DOCTYPE html>
|
|
10571
10261
|
<html lang="en">
|
|
10572
10262
|
<head>
|
|
10573
10263
|
<meta charset="UTF-8">
|
|
@@ -12215,7 +11905,7 @@ body { font-family: var(--s2-font-family); font-size: 14px; line-height: 1.5; co
|
|
|
12215
11905
|
<\/script>
|
|
12216
11906
|
</body>
|
|
12217
11907
|
</html>
|
|
12218
|
-
`,
|
|
11908
|
+
`,jJ=`<!DOCTYPE html>
|
|
12219
11909
|
<html lang="en">
|
|
12220
11910
|
<head>
|
|
12221
11911
|
<title>Welcome</title>
|
|
@@ -13037,7 +12727,7 @@ body { font-family: var(--s2-font-family); font-size: 14px; line-height: 1.5; co
|
|
|
13037
12727
|
<\/script>
|
|
13038
12728
|
</body>
|
|
13039
12729
|
</html>
|
|
13040
|
-
`,
|
|
12730
|
+
`,MJ=`---
|
|
13041
12731
|
name: inline-widgets
|
|
13042
12732
|
description: Interactive widget patterns for inline shtml cards in chat messages
|
|
13043
12733
|
allowed-tools: bash
|
|
@@ -13307,7 +12997,7 @@ slicc.lick({ action: 'sort-complete', algorithm: algo, comparisons: n });
|
|
|
13307
12997
|
\`\`\`
|
|
13308
12998
|
|
|
13309
12999
|
The agent receives the lick as a structured message and can respond with prose, another inline widget, or spawn a scoop.
|
|
13310
|
-
`,
|
|
13000
|
+
`,NJ=`---
|
|
13311
13001
|
name: playwright-cli
|
|
13312
13002
|
description: Browse the web, interact with pages, take screenshots, extract data via the playwright-cli shell command.
|
|
13313
13003
|
allowed-tools: bash
|
|
@@ -13496,7 +13186,7 @@ playwright-cli stop-recording <recordingId> # Stop and save HAR
|
|
|
13496
13186
|
- The SLICC app tab and Chrome internal UI tabs are automatically excluded from \`tab-list\`.
|
|
13497
13187
|
- \`fill\` clears and types into regular inputs, textareas, and \`contenteditable\` elements.
|
|
13498
13188
|
- Screenshots default to \`/tmp/screenshot-<timestamp>.png\`. Use \`--filename=path\` to save elsewhere.
|
|
13499
|
-
`,
|
|
13189
|
+
`,PJ=`---
|
|
13500
13190
|
name: sprinkles
|
|
13501
13191
|
description: Create interactive sprinkles — dashboards, forms, and visualizations
|
|
13502
13192
|
allowed-tools: bash
|
|
@@ -13621,7 +13311,7 @@ Look up the next previous year's Giro d'Italia winner and update the sprinkle.
|
|
|
13621
13311
|
Use: sprinkle send giro-winners '<json>' to push data, or edit the .shtml and reload.
|
|
13622
13312
|
Stay ready for more lick events.")
|
|
13623
13313
|
\`\`\`
|
|
13624
|
-
`,
|
|
13314
|
+
`,FJ=`# Sprinkle Component Reference
|
|
13625
13315
|
|
|
13626
13316
|
Use these CSS classes in \`.shtml\` sprinkles. Do NOT write custom CSS — these components cover all common UI patterns.
|
|
13627
13317
|
|
|
@@ -14233,7 +13923,7 @@ background: color-mix(in srgb, var(--s2-accent) 6%, transparent); /* blue tint *
|
|
|
14233
13923
|
| \`--s2-spacing-400\` | 24px |
|
|
14234
13924
|
| \`--s2-spacing-500\` | 32px |
|
|
14235
13925
|
| \`--s2-spacing-600\` | 40px |
|
|
14236
|
-
`,
|
|
13926
|
+
`,IJ=`---
|
|
14237
13927
|
name: welcome
|
|
14238
13928
|
description: Handle onboarding lick from the welcome sprinkle
|
|
14239
13929
|
allowed-tools: bash
|
|
@@ -14312,8 +14002,8 @@ This outputs progress lines like \`[1/N] Installed "skill-name"…\`. Let the ou
|
|
|
14312
14002
|
|
|
14313
14003
|
- **\`start-task\` lick** — treat as the user's first request, begin the task immediately.
|
|
14314
14004
|
- **Sparse profiles** (user skipped most steps) — keep greeting brief, ask what they need.
|
|
14315
|
-
`,
|
|
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
|
|
14005
|
+
`,LJ=`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=`,RJ=r(`skills`),zJ=Object.assign({"/packages/vfs-root/AGENTS.md":yJ,"/packages/vfs-root/CLAUDE.md":yJ,"/packages/vfs-root/shared/CLAUDE.md":bJ,"/packages/vfs-root/shared/sprinkles/brand-compliance/brand-compliance.shtml":xJ,"/packages/vfs-root/shared/sprinkles/content-tree/content-tree.shtml":SJ,"/packages/vfs-root/shared/sprinkles/funnels/funnels.shtml":CJ,"/packages/vfs-root/shared/sprinkles/page-editor/page-editor.shtml":wJ,"/packages/vfs-root/shared/sprinkles/performance/performance.shtml":TJ,"/packages/vfs-root/shared/sprinkles/readability/readability.shtml":EJ,"/packages/vfs-root/shared/sprinkles/review-workflow/review-workflow.shtml":DJ,"/packages/vfs-root/shared/sprinkles/schema-editor/schema-editor.shtml":OJ,"/packages/vfs-root/shared/sprinkles/seo-dashboard/seo-dashboard.shtml":kJ,"/packages/vfs-root/shared/sprinkles/tone-voice/tone-voice.shtml":AJ,"/packages/vfs-root/shared/sprinkles/welcome/welcome.shtml":jJ,"/packages/vfs-root/workspace/skills/inline-widgets/SKILL.md":MJ,"/packages/vfs-root/workspace/skills/playwright-cli/SKILL.md":NJ,"/packages/vfs-root/workspace/skills/sprinkles/SKILL.md":PJ,"/packages/vfs-root/workspace/skills/sprinkles/style-guide.md":FJ,"/packages/vfs-root/workspace/skills/welcome/SKILL.md":IJ}),BJ=Object.assign({"/packages/vfs-root/shared/sounds/chime.mp3":LJ});function VJ(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 HJ(){let e={};for(let[t,n]of Object.entries(zJ))e[t]=n;for(let[t,n]of Object.entries(BJ))e[t]=VJ(n);return e}function UJ(e){let t=new Map;for(let n of e){if(t.has(n.metadata.name)){RJ.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 WJ(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(`
|
|
14006
|
+
`)){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 GJ(e,t){let n=await KJ(e,t),r=await qJ(e,t),i=n.filter(e=>e.source===`native`),a=n.filter(e=>e.source!==`native`),o=UJ([...i,...r,...a]);return RJ.info(`Skills loaded`,{count:o.length,dir:t}),o}async function KJ(e,t){let n=await ge(e,t),r=[];for(let t of n)if(t.skillFilePath)try{let{metadata:n,body:i}=WJ(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}),RJ.debug(`Loaded discovered skill`,{name:a,path:t.skillFilePath,source:t.source})}catch{RJ.debug(`Failed to load discovered skill`,{name:t.name,path:t.skillFilePath})}return r}async function qJ(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}=WJ(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}),RJ.debug(`Loaded standalone skill`,{name:s,path:r})}catch{}}}catch{RJ.debug(`Standalone skills directory not found`,{dir:t})}return n}function JJ(e){return e.length===0?``:`
|
|
14317
14007
|
---
|
|
14318
14008
|
AVAILABLE SKILLS
|
|
14319
14009
|
|
|
@@ -14322,9 +14012,9 @@ The following skills are available. To use a skill, first read its full instruct
|
|
|
14322
14012
|
|
|
14323
14013
|
${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
14014
|
`)}
|
|
14325
|
-
---`}async function
|
|
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
|
|
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&&
|
|
14015
|
+
---`}async function YJ(e,t=`/workspace/skills`){let n=HJ();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),RJ.info(`Created default file`,{path:s})}}}async function XJ(e){let t=HJ();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),RJ.info(`Created default shared file`,{path:t})}}}var ZJ=r(`scoop-management-tools`);function QJ(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),ZJ.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),ZJ.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(`
|
|
14016
|
+
`)}`}}}),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 ZJ.info(`Scoop created`,{name:t,folder:o}),i&&r?(r(e.jid,i).catch(e=>{let n=e instanceof Error?e.message:String(e);ZJ.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),ZJ.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),ZJ.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 $J=r(`scoop-context`);function eY(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 tY=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`);$J.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 YJ(this.fs,this.skillsDir);let n=this.skillsFs??this.fs;this.shell=new aJ({fs:this.fs,cwd:e,browserAPI:t,jshDiscoveryFs:this.skillsFs?n:void 0}),$J.info(`WasmShell initialized`,{folder:this.scoop.folder});let r=await GJ(n,this.skillsDir),i=QJ({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([...sJ(this.fs),hJ(this.shell),vJ(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,$J.info(`Restored agent session`,{folder:this.scoop.folder,messageCount:f.length}))}catch(e){$J.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`),$J.info(`ScoopContext initialized`,{folder:this.scoop.folder,toolCount:a.length})}catch(e){let t=e instanceof Error?e.message:String(e);$J.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){$J.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);$J.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),$J.info(`Model updated on running agent`,{folder:this.scoop.folder,model:e.id})}async reloadSkills(){if(!this.agent)return;let e=await GJ(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),$J.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(`
|
|
14017
|
+
`),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&&eY(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=>{$J.error(`Failed to save agent session`,{folder:this.scoop.folder,error:e instanceof Error?e.message:String(e)})});break}}}recoverFromOverflow(e){if(this.agent){$J.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++,$J.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=>{$J.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){$J.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){$J.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=>{$J.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){$J.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
14018
|
|
|
14329
14019
|
${this.scoop.isCone?`Role: Cone (main orchestrator)`:`Scoop: ${this.scoop.name}`}
|
|
14330
14020
|
Folder: ${this.scoop.folder}
|
|
@@ -14403,10 +14093,10 @@ ${e}
|
|
|
14403
14093
|
---
|
|
14404
14094
|
${this.scoop.isCone?`CONE`:`SCOOP`} MEMORY (${this.scoop.name}):
|
|
14405
14095
|
${t}
|
|
14406
|
-
---`);let a=
|
|
14407
|
-
`);return Error(`Cannot remove scoop '${e}': it has ${r.join(` and `)}. Unregister them first:\n${i}`)}var
|
|
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`};
|
|
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=`
|
|
14096
|
+
---`);let a=JJ(n);return a&&(i+=a),i}},nY=r(`scheduler`),rY=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(),nY.info(`Scheduler started`))}stop(){this.pollInterval&&=(clearInterval(this.pollInterval),null),this.running=!1,nY.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),nY.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),nY.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),nY.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){nY.warn(`Task scoop not found`,{taskId:e.id,groupFolder:e.groupFolder});return}nY.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),nY.info(`Task completed`,{id:e.id})}catch(t){nY.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}},iY=r(`lick-manager`),aY=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);iY.info(`Loaded webhooks`,{count:this.webhooks.size});let t=await Le();for(let e of t)this.crontasks.set(e.id,e);iY.info(`Loaded crontasks`,{count:this.crontasks.size}),this.cronInterval=setInterval(()=>this.runCronScheduler(),6e4),iY.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),iY.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),iY.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){iY.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){iY.debug(`Webhook event dropped by filter`,{webhookId:e,name:r.name});return}typeof t==`object`&&t&&(i=t)}catch(t){iY.error(`Webhook filter error`,{webhookId:e,error:t instanceof Error?t.message:String(t)})}iY.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),iY.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),iY.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){iY.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){iY.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};iY.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 oY(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(`
|
|
14097
|
+
`);return Error(`Cannot remove scoop '${e}': it has ${r.join(` and `)}. Unregister them first:\n${i}`)}var sY=null;function cY(){return sY||=new aY,sY}var lY=r(`orchestrator`),uY=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 rY({onTaskRun:async(e,t)=>{lY.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(),lY.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 XJ(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{lY.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,lY.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,[]),lY.info(`Scoop registered`,{jid:e.jid,name:e.name}),this.createScoopTab(e.jid).catch(t=>{let n=t instanceof Error?t.message:String(t);lY.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=oY(t.folder,e,n);if(r)throw r}await this.destroyScoopTab(e),this.sessionStore?.delete(e).catch(t=>{lY.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),lY.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 YJ(this.sharedFs).catch(e=>{lY.warn(`Failed to re-seed default skills`,{error:e instanceof Error?e.message:String(e)})}),lY.info(`Filesystem reset and defaults re-seeded`)}async clearAllMessages(){await Re(),this.sessionStore&&await this.sessionStore.clearAll().catch(e=>{lY.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,[]);lY.info(`All messages cleared`)}async handleMessage(e){lY.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);Jq(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),lY.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);lY.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){lY.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)){lY.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(lY.debug(`routeToScoop: queued`,{chatJid:e.chatJid,scoopName:t.name,tabStatus:i?.status??`no-tab`,queueLength:r.length}),i?.status===`error`){lY.info(`routeToScoop: tab in error state, retrying init`,{chatJid:e.chatJid});try{await this.createScoopTab(e.chatJid),i=this.tabs.get(e.chatJid)}catch{lY.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`)lY.info(`Re-creating context after error`,{jid:e}),this.contexts.get(e)?.dispose(),this.contexts.delete(e),this.tabs.delete(e);else{lY.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 tY(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)+`
|
|
14098
|
+
... (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`};lY.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);lY.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`)),lY.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),lY.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 lY.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(lY.debug(`Context initializing, waiting to send message`,{jid:e}),!await this.waitForTabReady(e)){lY.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){lY.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`)),lY.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){lY.debug(`processScoopQueue: empty queue`,{jid:e});return}let n=this.tabs.get(e);if(n?.status!==`ready`){lY.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(lY.debug(`processScoopQueue: DB query`,{jid:e,scoopName:r?.name,excludeName:i,since:a,dbMessageCount:o.length,queueLength:t.length}),o.length===0){lY.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(`
|
|
14099
|
+
`);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);lY.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();lY.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=>{lY.warn(`Failed to reload skills for scoop`,{jid:t,error:e instanceof Error?e.message:String(e)})}))}await Promise.all(e),lY.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);lY.info(`Orchestrator shutdown`)}};r(`heartbeat`);var dY=r(`tray-follower`);async function fY(e){let t=await yY(await(e.fetchImpl??fetch)(e.joinUrl,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({controllerId:e.controllerId,runtime:e.runtime})}));return dY.info(`Follower tray attach response`,{trayId:t.trayId,action:t.result.action,code:t.result.code,participantCount:t.participantCount}),pY(t)}function pY(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 mY(e){return vY(await bY(e,{action:`poll`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,cursor:e.cursor}))}async function hY(e){return vY(await bY(e,{action:`answer`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,answer:e.answer}))}async function gY(e){return vY(await bY(e,{action:`ice-candidate`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,candidate:e.candidate}))}async function _Y(e){return vY(await bY(e,{action:`retry`,controllerId:e.controllerId,bootstrapId:e.bootstrapId,runtime:e.runtime}))}function vY(e){return{trayId:e.trayId,controllerId:e.controllerId,participantCount:e.participantCount,leader:e.leader,bootstrap:e.bootstrap,events:e.events}}async function yY(e){let t=null,n=null;try{t=await e.text(),n=JSON.parse(t)}catch{}if(!xY(n)){let n=t?t.slice(0,200):`(empty)`;throw dY.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 bY(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(!SY(r))throw Error(`Tray follower bootstrap returned an invalid response (${n.status})`);return r}function xY(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`&&CY(r.bootstrap):r.action===`fail`?(r.code===`INVALID_JOIN_CAPABILITY`||r.code===`TRAY_EXPIRED`)&&typeof r.error==`string`:!1}function SY(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`&&CY(t.bootstrap)&&Array.isArray(t.events)}function CY(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 wY=r(`tray-webrtc`),TY=`tray-control`,EY=250,DY=class{peerConnectionFactory;dataChannelLabel;peers=new Map;iceServers;constructor(e){this.options=e,this.iceServers=e.iceServers,this.peerConnectionFactory=e.peerConnectionFactory??(()=>AY(this.iceServers)),this.dataChannelLabel=e.dataChannelLabel??TY}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=MY(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`)&&(wY.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`?(wY.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`?(wY.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:jY(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){wY.warn(`Failed to report tray bootstrap failure`,{error:e instanceof Error?e.message:String(e)})}}}},OY=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??(()=>AY(this.iceServers)),this.controllerIdFactory=e.controllerIdFactory??(()=>crypto.randomUUID()),this.sleep=e.sleep??(e=>new Promise(t=>setTimeout(t,e))),this.pollIntervalMs=e.pollIntervalMs??EY}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}),wY.info(`Follower tray join starting`,{joinUrl:this.options.joinUrl});let n=0;for(;;){NY(this.stopped),n++;let t;try{t=await fY({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;wY.info(`Follower tray attach waiting`,{attempt:n,code:t.code,retryAfterMs:e}),n%10==0&&wY.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}),wY.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}),wY.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}),wY.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(NY(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 mY({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 hY({joinUrl:this.options.joinUrl,controllerId:t,bootstrapId:r.bootstrapId,answer:jY(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 _Y({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`)&&(wY.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?(wY.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?(wY.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=MY(n);r&&gY({joinUrl:this.options.joinUrl,controllerId:e,bootstrapId:t,candidate:r,fetchImpl:this.fetchImpl}).catch(e=>{wY.warn(`Failed to send follower ICE candidate`,{error:e instanceof Error?e.message:String(e)})})}),r}};function kY(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 OY({...e,sleep:o,onDisconnected:e=>{s||(wY.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}),wY.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}),wY.info(`Reconnect successful`,{attempt:f,trayId:i.trayId}),t.onConnected(i);return}catch(e){g=e instanceof Error?e.message:String(e),wY.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}),wY.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||wY.warn(`Initial follower connection failed`,{error:e instanceof Error?e.message:String(e)})}),u}function AY(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 jY(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 MY(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 NY(e){if(e)throw Error(`Tray follower stopped before WebRTC bootstrap completed`)}var PY=64*1024;async function FY(e,t){try{switch(t.op){case`readFile`:return await IY(e,t.path,t.encoding);case`writeFile`:return[await LY(e,t.path,t.content,t.encoding)];case`stat`:return[await RY(e,t.path)];case`readDir`:return[await zY(e,t.path)];case`mkdir`:return[await BY(e,t.path,t.recursive)];case`rm`:return[await VY(e,t.path,t.recursive)];case`exists`:return[await HY(e,t.path)];case`walk`:return[await UY(e,t.path)];default:return[{ok:!1,error:`Unknown fs operation: ${t.op}`}]}}catch(e){return[GY(e)]}}async function IY(e,t,n){return(n??`utf-8`)===`utf-8`?WY(await e.readFile(t,{encoding:`utf-8`}),`utf-8`):WY(KY(await e.readFile(t,{encoding:`binary`})),`base64`)}async function LY(e,t,n,r){if(r===`base64`){let r=qY(n);await e.writeFile(t,r)}else await e.writeFile(t,n);return{ok:!0,data:{type:`void`}}}async function RY(e,t){return{ok:!0,data:{type:`stat`,stat:await e.stat(t)}}}async function zY(e,t){return{ok:!0,data:{type:`dirEntries`,entries:await e.readDir(t)}}}async function BY(e,t,n){return await e.mkdir(t,{recursive:n}),{ok:!0,data:{type:`void`}}}async function VY(e,t,n){return await e.rm(t,{recursive:n}),{ok:!0,data:{type:`void`}}}async function HY(e,t){return{ok:!0,data:{type:`exists`,exists:await e.exists(t)}}}async function UY(e,t){let n=[];for await(let r of e.walk(t))n.push(r);return{ok:!0,data:{type:`paths`,paths:n}}}function WY(e,t){if(e.length<=PY)return[{ok:!0,data:{type:`file`,content:e,encoding:t}}];let n=Math.ceil(e.length/PY),r=[];for(let i=0;i<n;i++){let a=i*PY,o=e.slice(a,a+PY);r.push({ok:!0,data:{type:`file`,content:o,encoding:t},chunkIndex:i,totalChunks:n})}return r}function GY(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 KY(e){let t=``;for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t)}function qY(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 JY=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()]}},YY=r(`data-channel-keepalive`),XY=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++,YY.debug(`Missed pong`,{missedPongs:this.missedPongs,maxMissed:this.maxMissed}),this.missedPongs>=this.maxMissed)){YY.warn(`Channel declared dead`,{missedPongs:this.missedPongs}),this.stop(),this.onDead();return}this.awaitingPong=!0,this.sendPing()}}},ZY=r(`tray-leader-sync`);function QY(e){return e?e.includes(`standalone`)?`standalone`:e.includes(`extension`)?`extension`:e.includes(`electron`)?`electron`:`unknown`:`unknown`}var $Y=class{followers=new Map;registry=new JY;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 XY({sendPing:()=>r.send({type:`ping`}),onDead:()=>{ZY.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:QY(n?.runtime)}),ZY.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(),ZY.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),ZY.debug(`Snapshot sent to follower`,{bootstrapId:e,messageCount:n.length})}handleFollowerMessage(e,t){switch(t.type){case`user_message`:ZY.info(`Follower user message received`,{bootstrapId:e,messageId:t.messageId}),this.options.onFollowerMessage(t.text,t.messageId);break;case`abort`:ZY.info(`Follower abort received`,{bootstrapId:e}),this.options.onFollowerAbort();break;case`request_snapshot`:ZY.info(`Follower snapshot request received`,{bootstrapId:e}),this.sendSnapshotToFollower(e);break;case`targets.advertise`:ZY.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),ZY.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),ZY.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 FY(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?FY(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})})}},eX=r(`tray-follower-sync`),tX=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 XY({sendPing:()=>this.sync.send({type:`ping`}),onDead:()=>{eX.warn(`Leader keepalive dead, cleaning up`),this.handleDisconnect(`Keepalive timeout — leader not responding`),this.options.onDead?.()}}),this.keepalive.start(),e.addEventListener(`close`,()=>{eX.warn(`Data channel closed`),this.handleDisconnect(`Data channel closed`)}),e.addEventListener(`error`,()=>{eX.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}),eX.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`}),eX.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(),eX.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`:eX.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&&(eX.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),eX.debug(`Skipping own message echo`,{messageId:e.messageId});break}eX.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`:eX.warn(`Error from leader`,{error:e.error}),this.emitEvent({type:`error`,error:e.error});break;case`targets.registry`:eX.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){eX.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),eX.debug(`Tracking remote CDP session`,{remoteSessionId:e})}n===`Target.detachFromTarget`&&i&&this.remoteCDPSessions.has(i)&&(this.remoteCDPSessions.delete(i),eX.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 FY(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 nX(e,t){if(t)return`extension`;try{return aX(new URL(e))?`electron-overlay`:`standalone`}catch{return`standalone`}}function rX(e,t){return e===`electron-overlay`||e===`standalone`&&t}function iX(e){try{let t=new URL(e).searchParams.get(`tab`);return t&&Vi(t)?t:zi}catch{return zi}}function aX(e){return e.pathname===`/electron`||e.pathname===`/electron/`||e.searchParams.get(`runtime`)===`electron-overlay`}function oX(e){let t=new URL(e);return`${t.protocol===`https:`?`wss:`:`ws:`}//${t.host}/licks-ws`}function sX(e,t){return`${new URL(e).origin}/webhooks/${t}`}function cX(e,t){return`${e.replace(/\/+$/,``)}/${t.replace(/^\/+/,``)}`}function lX(e){return typeof e==`object`&&!!e&&`type`in e&&e.type===`slicc-electron-overlay:set-tab`}var uX=[`/shared/sprinkles`];async function dX(e){let t=new Map;for(let n of uX)await e.exists(n)&&await fX(e,n,t);return await fX(e,`/`,t),t}async function fX(e,t,n){for await(let r of e.walk(t)){if(!r.endsWith(`.shtml`))continue;let t=pX(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:mX(i,t),autoOpen:hX(i)})}}}function pX(e){let t=e.split(`/`).pop()??e;return t.endsWith(`.shtml`)?t.slice(0,-6):t}function mX(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 hX(e){return/data-sprinkle-autoopen\b/.test(e)}var gX=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)}},_X=r(`sprinkle-manager`),vX=`slicc-open-sprinkles`,yX=class{fs;bridge;callbacks;availableSprinkles=new Map;openSprinkles=new Map;constructor(e,t,n){this.fs=e,this.bridge=new gX(e,t,e=>this.close(e)),this.callbacks=n}async restoreOpenSprinkles(){try{let e=localStorage.getItem(vX);if(!e){for(let e of this.availableSprinkles.values())if(e.autoOpen)try{await this.open(e.name)}catch{_X.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{_X.warn(`Failed to restore sprinkle`,{name:e})}}catch{}}persistOpenSprinkles(){try{localStorage.setItem(vX,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),_X.info(`Auto-opened new sprinkle after install`,{name:e.name})}catch{_X.warn(`Failed to auto-open new sprinkle`,{name:e.name})}}async refresh(){this.availableSprinkles=await dX(this.fs),_X.info(`Discovered sprinkles`,{count:this.availableSprinkles.size})}async open(e,t){if(this.openSprinkles.has(e)){_X.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(),Xq(e),_X.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(),_X.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){_X.warn(`Cannot send to closed sprinkle`,{name:e});return}this.bridge.pushUpdate(e,t),n.renderer.pushUpdate(t)}},bX=r(`main`),xX=`slicc-pending-mount`,SX=`pendingMount`;async function CX(e){let t=await new Promise((e,t)=>{let n=indexedDB.open(xX,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,SX),await new Promise(e=>n.oncomplete=()=>e()),t.close()}async function wX(e){let t;try{t=await new Promise((e,t)=>{let n=indexedDB.open(xX,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(SX);t.onsuccess=()=>e(t.result),t.onerror=()=>e(void 0)});if(r){n.objectStore(`handles`).delete(SX),await new Promise(e=>n.oncomplete=()=>e());let t=`/mnt/${r.name}`;await e.mount(t,r),bX.info(`Mounted folder from welcome onboarding`,{name:r.name,path:t})}t.close()}function TX(){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 EX(){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 DX(e,t,n){let r=TX(),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 OX(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),bX.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`)||bX.error(`Preview VFS read failed`,{path:n,error:r}),o.postMessage({type:`preview-vfs-response`,id:t,error:r})}})()},DX(a,EX(),async()=>{await r.panels.fileBrowser.refresh()});try{let{WasmShell:e}=await y(async()=>{let{WasmShell:e}=await import(`./shell-D1BtrGhx.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),bX.info(`Terminal mounted with shared VFS and BrowserAPI (CDP proxy)`)}catch(e){bX.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{bX.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){bX.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 yX(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&&wX(a).catch(e=>bX.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 CX(t),d.sendToSprinkle(`welcome`,{action:`mount-complete`,dirName:t.name})}catch(e){e.name!==`AbortError`&&bX.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){bX.warn(`Failed to open welcome sprinkle`,e)}bX.info(`SprinkleManager initialized (extension mode)`),s.requestState(),bX.info(`Extension UI connected to offscreen agent engine`),qq().catch(()=>{})}async function kX(){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(()=>bX.info(`Preview SW registered`)).catch(e=>bX.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=nX(window.location.href,a);if(o===`extension`)return OX(e);let l=new Ki(e,o===`electron-overlay`);if(o===`electron-overlay`){let e=iX(window.location.href);l.setActiveTab(e);let t=document.createElement(`style`);t.id=`slicc-electron-overlay-runtime-style`,t.textContent=`
|
|
14410
14100
|
#app > .tab-bar { display: none !important; }
|
|
14411
14101
|
#app > .tab-content {
|
|
14412
14102
|
height: calc(100vh - var(--s2-header-height));
|
|
@@ -14414,4 +14104,4 @@ ${t}
|
|
|
14414
14104
|
#app > .tab-content > .tab-content__panel {
|
|
14415
14105
|
height: 100%;
|
|
14416
14106
|
}
|
|
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};
|
|
14107
|
+
`,document.head.appendChild(t),window.addEventListener(`message`,e=>{e.source===window.parent&&lX(e.data)&&l.setActiveTab(iX(`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=EX();await l.panels.chat.initSession(`session-cone`),bX.info(`Session initialized`);let f=new we,p=new Set,m=e=>{bX.debug(`Emit to UI`,{type:e.type,listenerCount:p.size});for(let t of p)try{t(e)}catch(t){bX.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 uY(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)=>{bX.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)=>{bX.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}):bX.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),bX.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`)||bX.error(`Preview VFS read failed`,{path:r,error:i}),e.postMessage({type:`preview-vfs-response`,id:n,error:i})}})()},DX(T,(e,t)=>{t===`error`?bX.warn(`Dropped skill install failed`,{message:e}):bX.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-D1BtrGhx.js`);return{WasmShell:e}},[]),t=new e({fs:T,browserAPI:f});await l.panels.terminal.mountShell(t),bX.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}),bX.info(`BSH navigation watchdog started`)}catch(e){bX.warn(`Failed to start BSH watchdog`,e)}}catch(e){bX.warn(`Failed to mount shell to terminal`,e)}}let D=C.getScoops(),O=D.some(e=>e.isCone);if(r)bX.info(`Skipping local cone bootstrap while joining a tray without a configured provider`);else if(!O)h=await l.panels.scoops.createScoop(`Cone`,!0),bX.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,bX.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=>{bX.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=>{bX.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)}}}),bX.info(`Cone agent handle wired to chat UI`);let{getLickManager:k}=await y(async()=>{let{getLickManager:e}=await import(`./lick-manager-BIap53QC.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(bX.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&&wX(T).catch(e=>bX.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 CX(t),ae?.sendToSprinkle(`welcome`,{action:`mount-complete`,dirName:t.name})}catch(e){e.name!==`AbortError`&&bX.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),bX.info(`Routing lick to scoop`,{type:a,name:r,scoopJid:s.jid}),C.handleMessage(u)}else bX.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 yX(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){bX.warn(`Failed to open welcome sprinkle`,e)}await ae.restoreOpenSprinkles(),bX.info(`SprinkleManager initialized`)}let oe=()=>{let e=oX(window.location.href),t=new WebSocket(e);t.onopen=()=>{bX.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?cX(r.webhookUrl,t.id):sX(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){bX.error(`Failed to process lick message`,{error:e instanceof Error?e.message:String(e)})}},t.onclose=()=>{bX.warn(`Lick WebSocket disconnected, reconnecting in 3s...`),setTimeout(oe,3e3)},t.onerror=e=>{bX.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=>{bX.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=rX(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 tX(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(),bX.info(`Follower sync wired to chat panel`,{trayId:e.trayId})},m=e=>{a?.cancel(),c&&=(clearInterval(c),null),r?.close(),r=null,a=kY({joinUrl:e,runtime:`slicc-standalone`,fetchImpl:dW()},{onConnected:e=>u(e),onReconnecting:e=>{bX.info(`Follower reconnecting`,{attempt:e})},onGaveUp:e=>{bX.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 $Y({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 DY({sendControlMessage:t=>e.sendControlMessage(t),onPeerConnected:(e,n)=>{bX.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=>{bX.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=>{bX.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})}}bX.info(`Orchestrator initialized — cone+scoops ready`,{scoopCount:C.getScoops().length}),qq().catch(()=>{})}kX().catch(e=>{bX.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,aJ as i,Qr as l,oY as n,fV as o,cY as r,$r as s,aY as t};
|