typebulb 0.20.3 → 0.20.4

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.
@@ -1376,7 +1376,7 @@ ${ZEt(m)}`};let v=VEt(d.code,{jsxImportSource:g.ts?.jsxImportSource});if(v.error
1376
1376
 
1377
1377
  `)}stickToBottomNextRender(){this.#n=!0}#u(o,a){o.segments=[...o.segments??[o.text],a],o.text=o.segments.join(`
1378
1378
 
1379
- `)}applyUser(o){let a=this.messages[this.messages.length-1];if(a&&a.role==="user"){this.#u(a,o.text),a.copy?a.copy.setText(a.text):a.text&&(a.copy=this.#i(a.text));return}this.#s({id:++this.#e,role:"user",text:o.text,thinking:"",tools:[]})}applyAssistant(o){let a=this.#s({id:++this.#e,role:"assistant",text:o.text,thinking:o.thinking,tools:o.tools.map(g=>({...g,isError:!1}))}),d=this.messages[this.messages.length-2];if(a.turnCopy=d?.role==="assistant"&&d.turnCopy||this.#i(""),a.turnCopy.setText(this.#c()),this.#f(a,o.text),this.#h(),o.live)for(let g of o.tools)ovn.has(g.name)&&this.openTools.add(g.id)}#f(o,a){let d=uSt(a);d.some(g=>g.kind==="bulb")&&(o.body=d.map(g=>{if(g.kind==="md")return g.text;let m=new Qre(g.source,`embed-${this.#t++}`);return this.bulbEmbeds.push(m),m}))}#h(){let o=this.bulbEmbeds.map(g=>g.name),a=aSt(o),d=lSt(o);this.#r=new Set(this.bulbEmbeds.filter((g,m)=>a[m])),this.bulbEmbeds.forEach((g,m)=>{g.setChainPosition(d[m]),g.setMounted(!a[m]||this.expandedEmbeds.has(g.key))})}#a(o){Rxe(this.expandedEmbeds,o),this.#h(),this.update()}applyToolResult(o){let a=this.#o(o.id);a&&(a.result=o.content,a.isError=o.isError,a.digest=o.digest)}applyFork(o){let a=this.#l(o.events);this.#s({id:++this.#e,role:"fork",text:"",thinking:"",tools:[],fork:{count:o.count,sub:a}})}#l(o){let a=[];for(let d of o)if(d.type==="user"){let g=a[a.length-1];g&&g.role==="user"?this.#u(g,d.text):a.push({id:++this.#e,role:"user",text:d.text,thinking:"",tools:[]})}else if(d.type==="assistant")a.push({id:++this.#e,role:"assistant",text:d.text,thinking:d.thinking,tools:d.tools.map(g=>({...g,isError:!1}))});else if(d.type==="tool_result"){let g=a.flatMap(m=>m.tools).find(m=>m.id===d.id);g&&(g.result=d.content,g.isError=d.isError,g.digest=d.digest)}return a}#o(o){return this.messages.flatMap(a=>a.tools).find(a=>a.id===o)}scrollSoon(){requestAnimationFrame(()=>{this.scrollEl&&this.#n&&(this.scrollEl.scrollTop=this.scrollEl.scrollHeight)})}onScroll(){let o=this.scrollEl;o&&(this.#n=o.scrollHeight-(o.scrollTop+o.clientHeight)<50)}view(){return hn({class:"messages",onScroll:()=>this.onScroll(),onMounted:o=>{this.scrollEl=o}},this.parent.ready?this.renderMessages():hn({class:"note"},"Connecting\u2026"))}renderMessages(){let o=[],a=-1;for(let d of this.messages)d.role==="user"||o.length===0?(d.role==="user"&&a++,o.push({idx:Math.max(0,a),msgs:[d]})):o[o.length-1].msgs.push(d);return o.flatMap((d,g)=>this.renderTurn(d.msgs,d.idx,g===o.length-1))}renderTurn(o,a,d){if(this.parent.prose){let T=o.filter(D=>D.role==="user"||D.role==="fork"||D.text||D.body),L=[...T].reverse().find(D=>D.role==="assistant"&&!!D.text);return T.map(D=>{if(D.role==="fork")return this.forkStub(D,a);let P=D.role==="user"?D.copy:D===L?D.turnCopy:void 0;return this.bubble(D,a,P??null)})}let g=o.filter(T=>T.role==="assistant");if(d||g.length<2)return o.map(T=>T.role==="fork"?this.forkStub(T,a):this.bubble(T,a));let m=this.expandedTurns.has(a),v=g.slice(0,-1),w=g[g.length-1],I=o.filter(T=>T.role==="user").map(T=>this.bubble(T,a));for(let T of o)T.role==="fork"&&I.push(this.forkStub(T,a));if(I.push(this.turnSummary(v,a)),m)for(let T of v)I.push(this.bubble(T,a));return I.push(this.bubble(w,a)),I}#p(o,a,d,g,m,v){let w=d.has(g);return hn({class:["bubble","assistant",Dye(a)],key:o},hn({class:"turn-summary",onClick:()=>{Rxe(d,g),this.update()}},Oxe(w),ys({class:"turn-summary-text"},m)),v??null)}forkStub(o,a){let d=o.fork,g=this.expandedForks.has(o.id)?hn({class:"fork-body"},d.sub.map(v=>this.bubble(v,a,void 0,!1))):void 0,m=[ivn(),` ${d.count} message${d.count===1?"":"s"} on an abandoned branch`];return this.#p(`fork-${o.id}`,a,this.expandedForks,o.id,m,g)}turnSummary(o,a){return this.#p(`summary-${a}`,a,this.expandedTurns,a,lvn(o))}bubble(o,a,d=o.copy,g=!0){let m=this.parent.prose,v=o.role==="assistant"&&!o.text&&!o.thinking&&o.tools.length>0;return hn({class:["bubble",o.role,v?"tools-only":"",g?Dye(a):""],key:o.id},!m&&o.thinking?K5t({class:"thinking"},W5t("thinking"),I7(o.thinking)):null,this.#g(o),m?null:o.tools.map(w=>this.tool(w)),d?d.view():null)}#g(o){return o.body?o.body.flatMap((a,d)=>typeof a=="string"?a.trim()?[this.#d(`md-${o.id}-${d}`,$re(a))]:[]:this.#b(a)):o.text?this.#d(`md-${o.id}`,o.role==="user"?cSt(o):$re(o.text)):null}#b(o){if(!this.#r.has(o))return[o.view()];let a=this.expandedEmbeds.has(o.key),d=hn({class:"md",key:`fold-${o.key}`},hn({class:"bulb-fold",onClick:()=>this.#a(o.key)},Oxe(a),ys({class:"bulb-fold-text"},`${o.name??"bulb"} \u2014 Version ${o.chainPosition}`),ys({class:"bulb-fold-app"},"\u{1F4A1}")));return a?[d,o.view()]:[d]}#d(o,a){return hn({class:"md",key:o,onMounted:a})}tool(o){let a=this.openTools.has(o.id),d=cvn(o.name,o.input),g=dSt(o),m=d?o6t(d,this.parent.cwd):rvn(nvn(o.input));return hn({class:["tool",o.isError?"err":""]},hn({class:"tool-head"},hn({class:"tool-label"},ys({class:"tool-name",...o.name.startsWith("mcp__")?{title:o.name}:{}},Pxe(o.name)),m?d?uM({class:"tool-sum link",title:d,onClick:v=>{v.preventDefault(),tb.server.openFile(d)}},m):ys({class:"tool-sum"},m):null),o.result===void 0?ys({class:"tool-run"},"\u2026"):null),o.result!==void 0?hn({class:"tool-digest",onClick:()=>{Rxe(this.openTools,o.id),this.update()}},Oxe(a),(g?avn(g):o.digest)||"(no output)"):null,a?hn({class:"tool-card"},this.toolBody(o),o.result!==void 0&&(!(g||hSt(o).length)||o.isError)?I7({class:"tool-out"},o.result.slice(0,4e3)):null):null)}toolBody(o){let a=dSt(o);if(a)return hn({class:"todo-list"},a.map(m=>hn({class:["todo",m.status??""]},ys({class:"todo-icon"},m.status==="completed"?"\u2714":m.status==="in_progress"?"\u25FC":"\u25FB"),ys({class:"todo-text"},m.content??""))));let d=hSt(o);if(d.length)return hn({class:"tool-in"},d.map(fSt));let g=uvn(o);if(!g){let m=Object.entries(o.input??{});return m.length?hn({class:"tool-in"},m.map(([v,w])=>hn({class:"tool-field"},ys({class:"tool-key"},`${v}:`),typeof w=="string"&&pSt(w)?fSt(w):I7({class:"tool-val"},typeof w=="string"?w:JSON.stringify(w,null,2))))):null}return hn({class:"diff"},...g.flatMap((m,v)=>[g.length>1?hn({class:"diff-step"},`edit ${v+1}/${g.length}`):null,m.old?I7({class:"diff-old"},String(m.old)):null,m.new?I7({class:"diff-new"},String(m.new)):null]))}};var qre=class extends Ia{ready=!1;cwd="";sessionId="";sessionPicker=new Gee;tokenPill=new qee;bulbsPill=new Jee;prosePill=new Uee;messageList=new Gre;tokens={in:0,out:0,cached:0,cacheCreate:0};working=!1;latestModel=null;prose=!1;ownPid=0;pills;#e=0;#t=!1;#r=!1;#n;#i;#s;constructor(o){super(),this.pills=o.pills,this.#n=o.title,this.#i=o.overlays??[],this.#s=o.onPollTick}onAttached(){this.#r||(this.#r=!0,this.init())}closePopups(o){this.sessionPicker!==o&&this.sessionPicker.close(),this.bulbsPill!==o&&this.bulbsPill.close();for(let a of this.pills)a!==o&&a.close?.()}async init(){let o=await tb.server.info();this.cwd=o.cwd,this.ownPid=o.pid??0,this.ready=!0,this.updateTitle(),this.update(),this.pump()}updateTitle(){let o=Bye(this.cwd),a=this.sessionPicker.currentPreview(),d=Hee(a,40);document.title=d&&o?`${d} \u2014 ${o}`:d||(o?`${this.#n} \u2014 ${o}`:this.#n)}pump(){if(this.#t)return;this.#t=!0;let o=async()=>{try{let{events:a,cursor:d,working:g,latestModel:m}=await tb.server.poll(this.#e);this.#e=d;for(let I of a)this.apply(I);let v=g!==this.working;this.working=g;let w=m!==this.latestModel;this.latestModel=m??null,(a.length||v||w)&&this.update(),a.length&&this.messageList.scrollSoon(),this.#s?.()}catch(a){console.error("[mirror] poll failed",a)}setTimeout(o,600)};o()}apply(o){switch(o.type){case"cleared":this.messageList.clear(),this.tokens={in:0,out:0,cached:0,cacheCreate:0};break;case"session":this.sessionId=o.sessionId,this.updateTitle();break;case"user":this.messageList.applyUser(o);break;case"assistant":this.messageList.applyAssistant(o);break;case"tool_result":this.messageList.applyToolResult(o);break;case"fork":this.messageList.applyFork(o);break;case"usage":this.tokens={in:o.in,out:o.out,cached:o.cached,cacheCreate:o.cacheCreate};break}}view(){return hn({class:"app"},this.messageList.view(),...this.#i.map(o=>o()),this.statusbar())}statusbar(){return hn({class:"statusbar"},hn({class:"statusbar-actions"},this.prosePill.view(),...this.pills.map(o=>o.view()),this.tokenPill.view(),this.sessionPicker.view(),this.bulbsPill.view()))}};var fvn=[[0,"Low"],[1,"Med"],[2,"High"]],hvn=1,Jre=s=>s?.message??String(s),dvn=()=>pC({viewBox:"0 0 24 24",width:"15",height:"15",class:"anthropic-glyph",fill:"currentColor"},dC({d:"M13.827 3.52h3.603L24 20h-3.603l-6.57-16.48zm-7.258 0h3.767L16.906 20h-3.674l-1.343-3.461H5.017l-1.344 3.46H0L6.57 3.522zm4.132 9.959L8.453 7.687 6.205 13.48H10.7z"})),gSt=s=>s===!0?"ok":s===!1?"bad":"warn",Ure=class extends S7{models=[];hasKey=!0;loaded=!1;current={active:!1,managed:!1,model:null,port:null,provider:null,routedModel:null,caching:"unknown",reasoning:null,externalBaseUrl:null};busy=!1;err=null;enteringKey=!1;keyDraft="";probes={};probing=null;openDiag=null;infoOpen=!1;ticking=!1;keepOpenSelector=".model-wrap";filterId="model-filter";listSelector="#model-list";filterNoun="model";search(){return Promise.resolve([])}modeToggle(){return null}onActivate(o){let a=this.rows()[o];a&&(a.kind==="default"?this.clear():a.kind==="unlock"?this.beginKeyEntry():this.set(a.id))}onAttached(){this.refresh()}async refresh(){try{let[o,a]=await Promise.all([tb.server.listSwitchModels(),tb.server.switchState()]);this.models=o.models,this.hasKey=o.hasKey,this.current=a,this.err=null}catch(o){this.err=Jre(o),console.error("[mirror] switcher refresh failed",o)}finally{this.loaded=!0,this.update()}}async tickState(){if(!(this.ticking||this.enteringKey)){this.ticking=!0;try{let o=await tb.server.switchState(),a=o.active!==this.current.active||o.model!==this.current.model||o.caching!==this.current.caching||o.routedModel!==this.current.routedModel||o.externalBaseUrl!==this.current.externalBaseUrl||o.provider!==this.current.provider||o.reasoning!==this.current.reasoning;this.current=o,a&&this.update()}catch{}finally{this.ticking=!1}}}rows(){let o=[];if(!this.hasKey)o.push({kind:"unlock"});else{let a=this.filter.trim().toLowerCase(),d=null;for(let g of this.models){if(a&&!g.label.toLowerCase().includes(a)&&!g.id.toLowerCase().includes(a))continue;let m={kind:"model",id:g.id,label:g.label,active:this.current.active&&this.current.model===g.id};m.active?d=m:o.push(m)}d&&o.push(d)}return o.push({kind:"default",active:!this.current.active&&!this.current.externalBaseUrl}),o}activeIndex(){let o=this.rows(),a=o.findIndex(d=>d.active);return a<0?Math.max(0,o.length-1):a}async show(){this.beginOpen(),this.refreshList(this.activeIndex()),this.focusFilter(),await this.refresh(),this.refreshList(this.activeIndex()),this.armClose()}onClosed(){super.onClosed(),this.enteringKey=!1,this.keyDraft="",this.openDiag=null,this.infoOpen=!1,this.err=null}async probe(o){if(!this.probing){this.probing=o,this.update();try{this.probes[o]=await tb.server.probeModel({model:o})}catch(a){this.probes[o]={ok:!1,error:Jre(a)}}this.probing=null,this.update()}}showDiag(o){this.openDiag=o,this.update()}closeDiag(){this.openDiag=null,this.update(),this.focusFilter()}label(o){return o?this.models.find(a=>a.id===o)?.label||o.split("/").pop()||o:"Anthropic"}async runBusy(o,a){this.busy=!0,this.err=null,this.update();try{let d=await o();if(d?.ok===!1)return this.err=d.error||a,this.busy=!1,this.update(),!1}catch(d){return this.err=Jre(d),this.busy=!1,this.update(),!1}return this.busy=!1,!0}async set(o){await this.runBusy(()=>tb.server.setSwitchModel({model:o}),"failed to set model")&&(await this.refresh(),this.close())}async clear(){await this.runBusy(()=>tb.server.clearSwitchModel(),"failed to revert")&&(await this.refresh(),this.close())}get reasoningSel(){return this.current.reasoning??hvn}set reasoningSel(o){this.setReasoning(o)}async setReasoning(o){if(this.current.reasoning!==o){this.current={...this.current,reasoning:o},this.update();try{let a=await tb.server.setReasoning({level:o});a?.ok===!1&&(this.err=a.error||"failed to set reasoning",this.update())}catch(a){this.err=Jre(a),this.update()}}}beginKeyEntry(){this.enteringKey=!0,this.keyDraft="",this.update(),setTimeout(()=>document.getElementById("or-key-input")?.focus())}cancelKeyEntry(){this.enteringKey=!1,this.keyDraft="",this.update(),this.focusFilter()}async saveKey(){let o=this.keyDraft.trim();o&&await this.runBusy(()=>tb.server.saveOpenRouterKey({key:o}),"failed to save key")&&(this.enteringKey=!1,this.keyDraft="",await this.refresh(),this.refreshList(this.activeIndex()))}get overridden(){return this.current.active}get uncached(){return this.current.active&&this.current.caching==="uncached"}watchdogView(){return this.uncached?hn({class:["model-banner","warn"]},ys({class:"model-banner-text"},`${this.label(this.current.model)} was served uncached via OpenRouter \u2014 the full context is re-billed each turn. Probe the model to pin a provider that caches, or pick a different one.`)):null}head(){return this.current.active?hn({class:"model-head"},qc({class:"model-info-toggle",onClick:o=>{o.stopPropagation(),this.infoOpen=!0,this.update()}},"Routing info"),hn({class:"reasoning-ctl",title:"Reasoning sets the route\u2019s base thinking effort."},ys({class:"reasoning-label"},"reasoning"),this.reasoningSelect())):this.current.externalBaseUrl?hn({class:"model-head"},ys({class:["model-route","warn"]},"Custom base URL set elsewhere \u2014 \u201CAnthropic (native)\u201D clears it")):null}reasoningSelect(){return t6t({target:this,prop:()=>this.reasoningSel,attrs:{class:"reasoning-select",onClick:o=>o.stopPropagation()},options:fvn.map(([o,a])=>({value:o,label:a}))})}infoView(){let o=this.label(this.current.model),a=()=>{this.infoOpen=!1,this.update()};return hn({class:"picker model-picker diag-mode",tabIndex:0,onMounted:d=>d.focus(),onKeyDown:d=>{d.key==="Escape"&&(d.stopPropagation(),a())}},hn({class:"diag-head"},ys({class:"diag-name"},"Routing"),hn({class:"diag-head-acts"},qc({class:"diag-back",title:"Back to the model list",onClick:d=>{d.stopPropagation(),a()}},"\u2190 models"))),hn({class:"diag-body"},hn({class:"diag-line"},`You are currently routing to ${o} via OpenRouter, not your Anthropic subscription.`),hn({class:"diag-line"},"The route is shared by every Claude Code conversation scoped to this project."),hn({class:"diag-line"},"Switching to or from Anthropic toggles the proxy, so for existing conversations you\u2019ll need to:"),hn({class:["diag-line","diag-bullet"]},"\u2022 Relaunch the Claude CLI"),hn({class:["diag-line","diag-bullet"]},"\u2022 or, in the VS Code extension, run \u201CDeveloper: Restart Extension Host\u201D (Cmd/Ctrl+Shift+P).")))}view(){let o=this.current.active,a=this.uncached,d=!o&&!!this.current.externalBaseUrl,g=this.label(this.current.model),m=a?`${g} via OpenRouter, uncached \u2014 full context re-billed each turn. Click to switch or revert.`:o?`claude \u2192 ${this.current.model}: its Anthropic API is proxied to OpenRouter. Click to switch or revert.`:d?`Custom ANTHROPIC_BASE_URL set outside this tool (${this.current.externalBaseUrl}). Click to manage.`:"Anthropic (native) \u2014 click to proxy claude\u2019s Anthropic API to an OpenRouter model.",v=o?g:d?"custom route":dvn();return hn({class:"model-wrap"},qc({class:["pill",o||d?"on":"glyph",a?"warn":""],title:m,ariaLabel:o||d?void 0:"Anthropic (native)",onClick:w=>{w.stopPropagation(),this.open?this.close():this.show()}},v),this.open?this.popup():null)}popup(){if(this.enteringKey)return this.keyView();if(this.infoOpen)return this.infoView();if(this.openDiag)return this.diagView(this.openDiag);let o=this.rows(),a=this.loaded&&this.hasKey&&!this.models.length;return hn({class:"picker model-picker"},this.head(),hn({id:"model-list",class:"picker-list",onScroll:()=>this.onListScroll()},o.map((d,g)=>this.row(d,g)),a?hn({class:"picker-empty"},this.err?`Couldn't load models: ${this.err}`:"No OpenRouter models in the catalog right now."):null),this.err&&!a?hn({class:"model-err"},`\u2717 ${this.err}`):null,this.hasKey&&this.models.length?this.filterBox(this.models.length,"model"):null)}row(o,a){let d=()=>{this.highlighted!==a&&(this.highlighted=a,this.update())},g=["picker-row",a===this.highlighted?"active":""];if(o.kind==="unlock")return hn({class:g,onMouseEnter:d,onClick:()=>this.onActivate(a)},hn({class:"picker-row-main"},ys({class:"picker-dot"}),ys({class:"picker-preview"},"+ Add OpenRouter key to unlock models\u2026")));if(o.kind==="default")return hn({class:[...g,o.active?"current":"","model-row","model-default-row"],title:"Your normal claude (subscription / API) \u2014 clears the override",onMouseEnter:d,onClick:()=>this.onActivate(a)},hn({class:"picker-row-main"},ys({class:"picker-dot"}),ys({class:"picker-preview"},"Anthropic (native)"),hn({class:"model-trailing"},o.active?this.activeBadge():null)));let m=o.id;return hn({class:[...g,o.active?"current":"","model-row"],title:m,onMouseEnter:d,onClick:()=>this.onActivate(a)},hn({class:"picker-row-main"},ys({class:"picker-dot"}),ys({class:"picker-preview"},o.label),hn({class:"model-trailing"},o.active?this.activeBadge():null,this.statusButton(m))))}activeBadge(){return ys({class:["model-btn","model-active"],title:"Active \u2014 bare claude routes here now"},"active")}statusButton(o){if(this.probing===o)return ys({class:["model-btn","model-status","probing"]},"probing\u2026");let a=this.probes[o];if(!a)return qc({class:["model-btn","model-status","probe"],title:"Check if it\u2019s callable and which provider caches \u2014 pins the caching one.",onClick:g=>{g.stopPropagation(),this.probe(o)}},"probe");let d=this.badge(a);return qc({class:["model-btn","model-status",d.cls],title:`${d.title} \xB7 click for details`,onClick:g=>{g.stopPropagation(),this.showDiag(o)}},d.text)}badge(o){if(!o.ok||o.callable===!1)return{text:"error",cls:"bad",title:o.error||"unavailable"};let a=o.provider?` on ${o.provider}`:"",d=o.cache?.works,g=gSt(d);return d===!0?{text:"cached",cls:g,title:`caching confirmed${a} \u2014 ${o.cache?.note||""}`}:d===!1?{text:"uncached",cls:g,title:`no caching${a} \u2014 ${o.cache?.note||""}`}:{text:"cache?",cls:g,title:`${o.cache?.note||"caching unconfirmed"}${a}`}}diagView(o){return hn({class:"picker model-picker diag-mode",tabIndex:0,onMounted:a=>a.focus(),onKeyDown:a=>{a.key==="Escape"&&(a.stopPropagation(),this.closeDiag())}},hn({class:"diag-head"},ys({class:"diag-name"},this.label(o)),hn({class:"diag-head-acts"},qc({class:"diag-back",title:"Re-run the probe",disabled:this.probing===o,onClick:a=>{a.stopPropagation(),this.probe(o)}},this.probing===o?"probing\u2026":"probe again"),qc({class:"diag-back",title:"Back to the model list",onClick:a=>{a.stopPropagation(),this.closeDiag()}},"\u2190 models"))),hn({class:"diag-body"},...this.diagLines(o)))}diagLines(o){let a=this.probes[o];if(!a)return[hn({class:["diag-line","muted"]},"Not probed yet \u2014 close this and hit probe.")];let d=[];if(!a.ok||a.callable===!1)d.push(hn({class:["diag-line","bad"]},`\u2717 Not callable${a.status?` (HTTP ${a.status})`:""}: ${a.error||"unknown error"}`)),a.restriction&&d.push(hn({class:["diag-line","warn"]},`\u26A0 ${a.restriction}`));else{d.push(hn({class:["diag-line","ok"]},`\u2713 Callable${a.ms?` \xB7 ${a.ms}ms`:""}${a.sample?` \xB7 replied \u201C${a.sample}\u201D`:""}`)),a.provider&&d.push(hn({class:["diag-line","muted"]},`Served by ${a.provider} this probe \u2014 the proxy will pin CC's turns to it when caching is confirmed.`));let g=a.cache;if(g){let m=gSt(g.works),v=g.works===!0?"\u2713 Caching works":g.works===!1?"\u2717 No caching":"~ Caching unconfirmed",w=a.provider?` on ${a.provider}`:"";d.push(hn({class:["diag-line",m]},`${v}${w} \u2014 ${g.note}`)),g.works!==!0&&d.push(hn({class:["diag-line","muted"]},"Without prompt caching every turn re-bills the whole context \u2014 costly over a long session."))}}return d.push(hn({class:["diag-line","muted","small"]},"Caching on OpenRouter is per-provider; the proxy pins the provider a probe confirms so CC keeps caching. A probe makes two small test calls.")),d}keyView(){return hn({class:"picker model-picker key-entry",tabIndex:0,onKeyDown:o=>{o.key==="Escape"&&(o.stopPropagation(),this.cancelKeyEntry())}},hn({class:"key-entry-head"},"Paste your OpenRouter API key"),Pee({target:this,prop:()=>this.keyDraft,id:"or-key-input",attrs:{class:"bulb-filter",placeholder:"sk-or-\u2026",ariaLabel:"OpenRouter API key",onKeyDown:o=>{o.key==="Enter"?(o.preventDefault(),this.saveKey()):o.key==="Escape"&&(o.stopPropagation(),this.cancelKeyEntry())}}}),this.err?hn({class:"model-err"},`\u2717 ${this.err}`):null,hn({class:"key-entry-acts"},qc({class:"pill",onClick:o=>{o.stopPropagation(),this.cancelKeyEntry()}},"Cancel"),qc({class:["pill","on"],onClick:o=>{o.stopPropagation(),this.saveKey()}},this.busy?"Saving\u2026":"Save")),hn({class:"key-entry-note"},"Written to .env in this project (gitignored). Used only via OpenRouter."))}};document.title="Claude Mirror";var jxe=new Ure;new X5t({root:new qre({title:"Claude Mirror",pills:[jxe],overlays:[()=>jxe.watchdogView()],onPollTick:()=>{jxe.tickState()}}),id:"app"});
1379
+ `)}applyUser(o){let a=this.messages[this.messages.length-1];if(a&&a.role==="user"){this.#u(a,o.text),a.copy?a.copy.setText(a.text):a.text&&(a.copy=this.#i(a.text));return}this.#s({id:++this.#e,role:"user",text:o.text,thinking:"",tools:[]})}applyAssistant(o){let a=this.#s({id:++this.#e,role:"assistant",text:o.text,thinking:o.thinking,tools:o.tools.map(g=>({...g,isError:!1}))}),d=this.messages[this.messages.length-2];if(a.turnCopy=d?.role==="assistant"&&d.turnCopy||this.#i(""),a.turnCopy.setText(this.#c()),this.#f(a,o.text),this.#h(),o.live)for(let g of o.tools)ovn.has(g.name)&&this.openTools.add(g.id)}#f(o,a){let d=uSt(a);d.some(g=>g.kind==="bulb")&&(o.body=d.map(g=>{if(g.kind==="md")return g.text;let m=new Qre(g.source,`embed-${this.#t++}`);return this.bulbEmbeds.push(m),m}))}#h(){let o=this.bulbEmbeds.map(g=>g.name),a=aSt(o),d=lSt(o);this.#r=new Set(this.bulbEmbeds.filter((g,m)=>a[m])),this.bulbEmbeds.forEach((g,m)=>{g.setChainPosition(d[m]),g.setMounted(!a[m]||this.expandedEmbeds.has(g.key))})}#a(o){Rxe(this.expandedEmbeds,o),this.#h(),this.update()}applyToolResult(o){let a=this.#o(o.id);a&&(a.result=o.content,a.isError=o.isError,a.digest=o.digest)}applyFork(o){let a=this.#l(o.events);this.#s({id:++this.#e,role:"fork",text:"",thinking:"",tools:[],fork:{count:o.count,sub:a}})}#l(o){let a=[];for(let d of o)if(d.type==="user"){let g=a[a.length-1];g&&g.role==="user"?this.#u(g,d.text):a.push({id:++this.#e,role:"user",text:d.text,thinking:"",tools:[]})}else if(d.type==="assistant")a.push({id:++this.#e,role:"assistant",text:d.text,thinking:d.thinking,tools:d.tools.map(g=>({...g,isError:!1}))});else if(d.type==="tool_result"){let g=a.flatMap(m=>m.tools).find(m=>m.id===d.id);g&&(g.result=d.content,g.isError=d.isError,g.digest=d.digest)}return a}#o(o){return this.messages.flatMap(a=>a.tools).find(a=>a.id===o)}scrollSoon(){requestAnimationFrame(()=>{this.scrollEl&&this.#n&&(this.scrollEl.scrollTop=this.scrollEl.scrollHeight)})}onScroll(){let o=this.scrollEl;o&&(this.#n=o.scrollHeight-(o.scrollTop+o.clientHeight)<50)}view(){return hn({class:"messages",onScroll:()=>this.onScroll(),onMounted:o=>{this.scrollEl=o}},this.parent.ready?this.renderMessages():hn({class:"note"},"Connecting\u2026"))}renderMessages(){let o=[],a=-1;for(let d of this.messages)d.role==="user"||o.length===0?(d.role==="user"&&a++,o.push({idx:Math.max(0,a),msgs:[d]})):o[o.length-1].msgs.push(d);return o.flatMap((d,g)=>this.renderTurn(d.msgs,d.idx,g===o.length-1))}renderTurn(o,a,d){if(this.parent.prose){let T=o.filter(D=>D.role==="user"||D.role==="fork"||D.text||D.body),L=[...T].reverse().find(D=>D.role==="assistant"&&!!D.text);return T.map(D=>{if(D.role==="fork")return this.forkStub(D,a);let P=D.role==="user"?D.copy:D===L?D.turnCopy:void 0;return this.bubble(D,a,P??null)})}let g=o.filter(T=>T.role==="assistant");if(d||g.length<2)return o.map(T=>T.role==="fork"?this.forkStub(T,a):this.bubble(T,a));let m=this.expandedTurns.has(a),v=g.slice(0,-1),w=g[g.length-1],I=o.filter(T=>T.role==="user").map(T=>this.bubble(T,a));for(let T of o)T.role==="fork"&&I.push(this.forkStub(T,a));if(I.push(this.turnSummary(v,a)),m)for(let T of v)I.push(this.bubble(T,a));return I.push(this.bubble(w,a)),I}#p(o,a,d,g,m,v){let w=d.has(g);return hn({class:["bubble","assistant",Dye(a)],key:o},hn({class:"turn-summary",onClick:()=>{Rxe(d,g),this.update()}},Oxe(w),ys({class:"turn-summary-text"},m)),v??null)}forkStub(o,a){let d=o.fork,g=this.expandedForks.has(o.id)?hn({class:"fork-body"},d.sub.map(v=>this.bubble(v,a,void 0,!1))):void 0,m=[ivn(),` ${d.count} message${d.count===1?"":"s"} on an abandoned branch`];return this.#p(`fork-${o.id}`,a,this.expandedForks,o.id,m,g)}turnSummary(o,a){return this.#p(`summary-${a}`,a,this.expandedTurns,a,lvn(o))}bubble(o,a,d=o.copy,g=!0){let m=this.parent.prose,v=o.role==="assistant"&&!o.text&&!o.thinking&&o.tools.length>0;return hn({class:["bubble",o.role,v?"tools-only":"",g?Dye(a):""],key:o.id},!m&&o.thinking?K5t({class:"thinking"},W5t("thinking"),I7(o.thinking)):null,this.#g(o),m?null:o.tools.map(w=>this.tool(w)),d?d.view():null)}#g(o){return o.body?o.body.flatMap((a,d)=>typeof a=="string"?a.trim()?[this.#d(`md-${o.id}-${d}`,$re(a))]:[]:this.#b(a)):o.text?this.#d(`md-${o.id}`,o.role==="user"?cSt(o):$re(o.text)):null}#b(o){if(!this.#r.has(o))return[o.view()];let a=this.expandedEmbeds.has(o.key),d=hn({class:"md",key:`fold-${o.key}`},hn({class:"bulb-fold",onClick:()=>this.#a(o.key)},Oxe(a),ys({class:"bulb-fold-text"},`${o.name??"bulb"} \u2014 Version ${o.chainPosition}`),ys({class:"bulb-fold-app"},"\u{1F4A1}")));return a?[d,o.view()]:[d]}#d(o,a){return hn({class:"md",key:o,onMounted:a})}tool(o){let a=this.openTools.has(o.id),d=cvn(o.name,o.input),g=dSt(o),m=d?o6t(d,this.parent.cwd):rvn(nvn(o.input));return hn({class:["tool",o.isError?"err":""]},hn({class:"tool-head"},hn({class:"tool-label"},ys({class:"tool-name",...o.name.startsWith("mcp__")?{title:o.name}:{}},Pxe(o.name)),m?d?uM({class:"tool-sum link",title:d,onClick:v=>{v.preventDefault(),tb.server.openFile(d)}},m):ys({class:"tool-sum"},m):null),o.result===void 0?ys({class:"tool-run"},"\u2026"):null),o.result!==void 0?hn({class:["tool-digest",a?"open":""],onClick:()=>{Rxe(this.openTools,o.id),this.update()}},Oxe(a),(g?avn(g):o.digest)||"(no output)"):null,a?hn({class:"tool-card"},this.toolBody(o),o.result!==void 0&&(o.isError||!(g||hSt(o).length&&o.result.trim()===o.digest))?I7({class:"tool-out"},o.result.slice(0,4e3)):null):null)}toolBody(o){let a=dSt(o);if(a)return hn({class:"todo-list"},a.map(m=>hn({class:["todo",m.status??""]},ys({class:"todo-icon"},m.status==="completed"?"\u2714":m.status==="in_progress"?"\u25FC":"\u25FB"),ys({class:"todo-text"},m.content??""))));let d=hSt(o);if(d.length)return hn({class:"tool-in"},d.map(fSt));let g=uvn(o);if(!g){let m=Object.entries(o.input??{});return m.length?hn({class:"tool-in"},m.map(([v,w])=>hn({class:"tool-field"},ys({class:"tool-key"},`${v}:`),typeof w=="string"&&pSt(w)?fSt(w):I7({class:"tool-val"},typeof w=="string"?w:JSON.stringify(w,null,2))))):null}return hn({class:"diff"},...g.flatMap((m,v)=>[g.length>1?hn({class:"diff-step"},`edit ${v+1}/${g.length}`):null,m.old?I7({class:"diff-old"},String(m.old)):null,m.new?I7({class:"diff-new"},String(m.new)):null]))}};var qre=class extends Ia{ready=!1;cwd="";sessionId="";sessionPicker=new Gee;tokenPill=new qee;bulbsPill=new Jee;prosePill=new Uee;messageList=new Gre;tokens={in:0,out:0,cached:0,cacheCreate:0};working=!1;latestModel=null;prose=!1;ownPid=0;pills;#e=0;#t=!1;#r=!1;#n;#i;#s;constructor(o){super(),this.pills=o.pills,this.#n=o.title,this.#i=o.overlays??[],this.#s=o.onPollTick}onAttached(){this.#r||(this.#r=!0,this.init())}closePopups(o){this.sessionPicker!==o&&this.sessionPicker.close(),this.bulbsPill!==o&&this.bulbsPill.close();for(let a of this.pills)a!==o&&a.close?.()}async init(){let o=await tb.server.info();this.cwd=o.cwd,this.ownPid=o.pid??0,this.ready=!0,this.updateTitle(),this.update(),this.pump()}updateTitle(){let o=Bye(this.cwd),a=this.sessionPicker.currentPreview(),d=Hee(a,40);document.title=d&&o?`${d} \u2014 ${o}`:d||(o?`${this.#n} \u2014 ${o}`:this.#n)}pump(){if(this.#t)return;this.#t=!0;let o=async()=>{try{let{events:a,cursor:d,working:g,latestModel:m}=await tb.server.poll(this.#e);this.#e=d;for(let I of a)this.apply(I);let v=g!==this.working;this.working=g;let w=m!==this.latestModel;this.latestModel=m??null,(a.length||v||w)&&this.update(),a.length&&this.messageList.scrollSoon(),this.#s?.()}catch(a){console.error("[mirror] poll failed",a)}setTimeout(o,600)};o()}apply(o){switch(o.type){case"cleared":this.messageList.clear(),this.tokens={in:0,out:0,cached:0,cacheCreate:0};break;case"session":this.sessionId=o.sessionId,this.updateTitle();break;case"user":this.messageList.applyUser(o);break;case"assistant":this.messageList.applyAssistant(o);break;case"tool_result":this.messageList.applyToolResult(o);break;case"fork":this.messageList.applyFork(o);break;case"usage":this.tokens={in:o.in,out:o.out,cached:o.cached,cacheCreate:o.cacheCreate};break}}view(){return hn({class:"app"},this.messageList.view(),...this.#i.map(o=>o()),this.statusbar())}statusbar(){return hn({class:"statusbar"},hn({class:"statusbar-actions"},this.prosePill.view(),...this.pills.map(o=>o.view()),this.tokenPill.view(),this.sessionPicker.view(),this.bulbsPill.view()))}};var fvn=[[0,"Low"],[1,"Med"],[2,"High"]],hvn=1,Jre=s=>s?.message??String(s),dvn=()=>pC({viewBox:"0 0 24 24",width:"15",height:"15",class:"anthropic-glyph",fill:"currentColor"},dC({d:"M13.827 3.52h3.603L24 20h-3.603l-6.57-16.48zm-7.258 0h3.767L16.906 20h-3.674l-1.343-3.461H5.017l-1.344 3.46H0L6.57 3.522zm4.132 9.959L8.453 7.687 6.205 13.48H10.7z"})),gSt=s=>s===!0?"ok":s===!1?"bad":"warn",Ure=class extends S7{models=[];hasKey=!0;loaded=!1;current={active:!1,managed:!1,model:null,port:null,provider:null,routedModel:null,caching:"unknown",reasoning:null,externalBaseUrl:null};busy=!1;err=null;enteringKey=!1;keyDraft="";probes={};probing=null;openDiag=null;infoOpen=!1;ticking=!1;keepOpenSelector=".model-wrap";filterId="model-filter";listSelector="#model-list";filterNoun="model";search(){return Promise.resolve([])}modeToggle(){return null}onActivate(o){let a=this.rows()[o];a&&(a.kind==="default"?this.clear():a.kind==="unlock"?this.beginKeyEntry():this.set(a.id))}onAttached(){this.refresh()}async refresh(){try{let[o,a]=await Promise.all([tb.server.listSwitchModels(),tb.server.switchState()]);this.models=o.models,this.hasKey=o.hasKey,this.current=a,this.err=null}catch(o){this.err=Jre(o),console.error("[mirror] switcher refresh failed",o)}finally{this.loaded=!0,this.update()}}async tickState(){if(!(this.ticking||this.enteringKey)){this.ticking=!0;try{let o=await tb.server.switchState(),a=o.active!==this.current.active||o.model!==this.current.model||o.caching!==this.current.caching||o.routedModel!==this.current.routedModel||o.externalBaseUrl!==this.current.externalBaseUrl||o.provider!==this.current.provider||o.reasoning!==this.current.reasoning;this.current=o,a&&this.update()}catch{}finally{this.ticking=!1}}}rows(){let o=[];if(!this.hasKey)o.push({kind:"unlock"});else{let a=this.filter.trim().toLowerCase(),d=null;for(let g of this.models){if(a&&!g.label.toLowerCase().includes(a)&&!g.id.toLowerCase().includes(a))continue;let m={kind:"model",id:g.id,label:g.label,active:this.current.active&&this.current.model===g.id};m.active?d=m:o.push(m)}d&&o.push(d)}return o.push({kind:"default",active:!this.current.active&&!this.current.externalBaseUrl}),o}activeIndex(){let o=this.rows(),a=o.findIndex(d=>d.active);return a<0?Math.max(0,o.length-1):a}async show(){this.beginOpen(),this.refreshList(this.activeIndex()),this.focusFilter(),await this.refresh(),this.refreshList(this.activeIndex()),this.armClose()}onClosed(){super.onClosed(),this.enteringKey=!1,this.keyDraft="",this.openDiag=null,this.infoOpen=!1,this.err=null}async probe(o){if(!this.probing){this.probing=o,this.update();try{this.probes[o]=await tb.server.probeModel({model:o})}catch(a){this.probes[o]={ok:!1,error:Jre(a)}}this.probing=null,this.update()}}showDiag(o){this.openDiag=o,this.update()}closeDiag(){this.openDiag=null,this.update(),this.focusFilter()}label(o){return o?this.models.find(a=>a.id===o)?.label||o.split("/").pop()||o:"Anthropic"}async runBusy(o,a){this.busy=!0,this.err=null,this.update();try{let d=await o();if(d?.ok===!1)return this.err=d.error||a,this.busy=!1,this.update(),!1}catch(d){return this.err=Jre(d),this.busy=!1,this.update(),!1}return this.busy=!1,!0}async set(o){await this.runBusy(()=>tb.server.setSwitchModel({model:o}),"failed to set model")&&(await this.refresh(),this.close())}async clear(){await this.runBusy(()=>tb.server.clearSwitchModel(),"failed to revert")&&(await this.refresh(),this.close())}get reasoningSel(){return this.current.reasoning??hvn}set reasoningSel(o){this.setReasoning(o)}async setReasoning(o){if(this.current.reasoning!==o){this.current={...this.current,reasoning:o},this.update();try{let a=await tb.server.setReasoning({level:o});a?.ok===!1&&(this.err=a.error||"failed to set reasoning",this.update())}catch(a){this.err=Jre(a),this.update()}}}beginKeyEntry(){this.enteringKey=!0,this.keyDraft="",this.update(),setTimeout(()=>document.getElementById("or-key-input")?.focus())}cancelKeyEntry(){this.enteringKey=!1,this.keyDraft="",this.update(),this.focusFilter()}async saveKey(){let o=this.keyDraft.trim();o&&await this.runBusy(()=>tb.server.saveOpenRouterKey({key:o}),"failed to save key")&&(this.enteringKey=!1,this.keyDraft="",await this.refresh(),this.refreshList(this.activeIndex()))}get overridden(){return this.current.active}get uncached(){return this.current.active&&this.current.caching==="uncached"}watchdogView(){return this.uncached?hn({class:["model-banner","warn"]},ys({class:"model-banner-text"},`${this.label(this.current.model)} was served uncached via OpenRouter \u2014 the full context is re-billed each turn. Probe the model to pin a provider that caches, or pick a different one.`)):null}head(){return this.current.active?hn({class:"model-head"},qc({class:"model-info-toggle",onClick:o=>{o.stopPropagation(),this.infoOpen=!0,this.update()}},"Routing info"),hn({class:"reasoning-ctl",title:"Reasoning sets the route\u2019s base thinking effort."},ys({class:"reasoning-label"},"reasoning"),this.reasoningSelect())):this.current.externalBaseUrl?hn({class:"model-head"},ys({class:["model-route","warn"]},"Custom base URL set elsewhere \u2014 \u201CAnthropic (native)\u201D clears it")):null}reasoningSelect(){return t6t({target:this,prop:()=>this.reasoningSel,attrs:{class:"reasoning-select",onClick:o=>o.stopPropagation()},options:fvn.map(([o,a])=>({value:o,label:a}))})}infoView(){let o=this.label(this.current.model),a=()=>{this.infoOpen=!1,this.update()};return hn({class:"picker model-picker diag-mode",tabIndex:0,onMounted:d=>d.focus(),onKeyDown:d=>{d.key==="Escape"&&(d.stopPropagation(),a())}},hn({class:"diag-head"},ys({class:"diag-name"},"Routing"),hn({class:"diag-head-acts"},qc({class:"diag-back",title:"Back to the model list",onClick:d=>{d.stopPropagation(),a()}},"\u2190 models"))),hn({class:"diag-body"},hn({class:"diag-line"},`You are currently routing to ${o} via OpenRouter, not your Anthropic subscription.`),hn({class:"diag-line"},"The route is shared by every Claude Code conversation scoped to this project."),hn({class:"diag-line"},"Switching to or from Anthropic toggles the proxy, so for existing conversations you\u2019ll need to:"),hn({class:["diag-line","diag-bullet"]},"\u2022 Relaunch the Claude CLI"),hn({class:["diag-line","diag-bullet"]},"\u2022 or, in the VS Code extension, run \u201CDeveloper: Restart Extension Host\u201D (Cmd/Ctrl+Shift+P).")))}view(){let o=this.current.active,a=this.uncached,d=!o&&!!this.current.externalBaseUrl,g=this.label(this.current.model),m=a?`${g} via OpenRouter, uncached \u2014 full context re-billed each turn. Click to switch or revert.`:o?`claude \u2192 ${this.current.model}: its Anthropic API is proxied to OpenRouter. Click to switch or revert.`:d?`Custom ANTHROPIC_BASE_URL set outside this tool (${this.current.externalBaseUrl}). Click to manage.`:"Anthropic (native) \u2014 click to proxy claude\u2019s Anthropic API to an OpenRouter model.",v=o?g:d?"custom route":dvn();return hn({class:"model-wrap"},qc({class:["pill",o||d?"on":"glyph",a?"warn":""],title:m,ariaLabel:o||d?void 0:"Anthropic (native)",onClick:w=>{w.stopPropagation(),this.open?this.close():this.show()}},v),this.open?this.popup():null)}popup(){if(this.enteringKey)return this.keyView();if(this.infoOpen)return this.infoView();if(this.openDiag)return this.diagView(this.openDiag);let o=this.rows(),a=this.loaded&&this.hasKey&&!this.models.length;return hn({class:"picker model-picker"},this.head(),hn({id:"model-list",class:"picker-list",onScroll:()=>this.onListScroll()},o.map((d,g)=>this.row(d,g)),a?hn({class:"picker-empty"},this.err?`Couldn't load models: ${this.err}`:"No OpenRouter models in the catalog right now."):null),this.err&&!a?hn({class:"model-err"},`\u2717 ${this.err}`):null,this.hasKey&&this.models.length?this.filterBox(this.models.length,"model"):null)}row(o,a){let d=()=>{this.highlighted!==a&&(this.highlighted=a,this.update())},g=["picker-row",a===this.highlighted?"active":""];if(o.kind==="unlock")return hn({class:g,onMouseEnter:d,onClick:()=>this.onActivate(a)},hn({class:"picker-row-main"},ys({class:"picker-dot"}),ys({class:"picker-preview"},"+ Add OpenRouter key to unlock models\u2026")));if(o.kind==="default")return hn({class:[...g,o.active?"current":"","model-row","model-default-row"],title:"Your normal claude (subscription / API) \u2014 clears the override",onMouseEnter:d,onClick:()=>this.onActivate(a)},hn({class:"picker-row-main"},ys({class:"picker-dot"}),ys({class:"picker-preview"},"Anthropic (native)"),hn({class:"model-trailing"},o.active?this.activeBadge():null)));let m=o.id;return hn({class:[...g,o.active?"current":"","model-row"],title:m,onMouseEnter:d,onClick:()=>this.onActivate(a)},hn({class:"picker-row-main"},ys({class:"picker-dot"}),ys({class:"picker-preview"},o.label),hn({class:"model-trailing"},o.active?this.activeBadge():null,this.statusButton(m))))}activeBadge(){return ys({class:["model-btn","model-active"],title:"Active \u2014 bare claude routes here now"},"active")}statusButton(o){if(this.probing===o)return ys({class:["model-btn","model-status","probing"]},"probing\u2026");let a=this.probes[o];if(!a)return qc({class:["model-btn","model-status","probe"],title:"Check if it\u2019s callable and which provider caches \u2014 pins the caching one.",onClick:g=>{g.stopPropagation(),this.probe(o)}},"probe");let d=this.badge(a);return qc({class:["model-btn","model-status",d.cls],title:`${d.title} \xB7 click for details`,onClick:g=>{g.stopPropagation(),this.showDiag(o)}},d.text)}badge(o){if(!o.ok||o.callable===!1)return{text:"error",cls:"bad",title:o.error||"unavailable"};let a=o.provider?` on ${o.provider}`:"",d=o.cache?.works,g=gSt(d);return d===!0?{text:"cached",cls:g,title:`caching confirmed${a} \u2014 ${o.cache?.note||""}`}:d===!1?{text:"uncached",cls:g,title:`no caching${a} \u2014 ${o.cache?.note||""}`}:{text:"cache?",cls:g,title:`${o.cache?.note||"caching unconfirmed"}${a}`}}diagView(o){return hn({class:"picker model-picker diag-mode",tabIndex:0,onMounted:a=>a.focus(),onKeyDown:a=>{a.key==="Escape"&&(a.stopPropagation(),this.closeDiag())}},hn({class:"diag-head"},ys({class:"diag-name"},this.label(o)),hn({class:"diag-head-acts"},qc({class:"diag-back",title:"Re-run the probe",disabled:this.probing===o,onClick:a=>{a.stopPropagation(),this.probe(o)}},this.probing===o?"probing\u2026":"probe again"),qc({class:"diag-back",title:"Back to the model list",onClick:a=>{a.stopPropagation(),this.closeDiag()}},"\u2190 models"))),hn({class:"diag-body"},...this.diagLines(o)))}diagLines(o){let a=this.probes[o];if(!a)return[hn({class:["diag-line","muted"]},"Not probed yet \u2014 close this and hit probe.")];let d=[];if(!a.ok||a.callable===!1)d.push(hn({class:["diag-line","bad"]},`\u2717 Not callable${a.status?` (HTTP ${a.status})`:""}: ${a.error||"unknown error"}`)),a.restriction&&d.push(hn({class:["diag-line","warn"]},`\u26A0 ${a.restriction}`));else{d.push(hn({class:["diag-line","ok"]},`\u2713 Callable${a.ms?` \xB7 ${a.ms}ms`:""}${a.sample?` \xB7 replied \u201C${a.sample}\u201D`:""}`)),a.provider&&d.push(hn({class:["diag-line","muted"]},`Served by ${a.provider} this probe \u2014 the proxy will pin CC's turns to it when caching is confirmed.`));let g=a.cache;if(g){let m=gSt(g.works),v=g.works===!0?"\u2713 Caching works":g.works===!1?"\u2717 No caching":"~ Caching unconfirmed",w=a.provider?` on ${a.provider}`:"";d.push(hn({class:["diag-line",m]},`${v}${w} \u2014 ${g.note}`)),g.works!==!0&&d.push(hn({class:["diag-line","muted"]},"Without prompt caching every turn re-bills the whole context \u2014 costly over a long session."))}}return d.push(hn({class:["diag-line","muted","small"]},"Caching on OpenRouter is per-provider; the proxy pins the provider a probe confirms so CC keeps caching. A probe makes two small test calls.")),d}keyView(){return hn({class:"picker model-picker key-entry",tabIndex:0,onKeyDown:o=>{o.key==="Escape"&&(o.stopPropagation(),this.cancelKeyEntry())}},hn({class:"key-entry-head"},"Paste your OpenRouter API key"),Pee({target:this,prop:()=>this.keyDraft,id:"or-key-input",attrs:{class:"bulb-filter",placeholder:"sk-or-\u2026",ariaLabel:"OpenRouter API key",onKeyDown:o=>{o.key==="Enter"?(o.preventDefault(),this.saveKey()):o.key==="Escape"&&(o.stopPropagation(),this.cancelKeyEntry())}}}),this.err?hn({class:"model-err"},`\u2717 ${this.err}`):null,hn({class:"key-entry-acts"},qc({class:"pill",onClick:o=>{o.stopPropagation(),this.cancelKeyEntry()}},"Cancel"),qc({class:["pill","on"],onClick:o=>{o.stopPropagation(),this.saveKey()}},this.busy?"Saving\u2026":"Save")),hn({class:"key-entry-note"},"Written to .env in this project (gitignored). Used only via OpenRouter."))}};document.title="Claude Mirror";var jxe=new Ure;new X5t({root:new qre({title:"Claude Mirror",pills:[jxe],overlays:[()=>jxe.watchdogView()],onPollTick:()=>{jxe.tickState()}}),id:"app"});
1380
1380
  /*! Bundled license information:
1381
1381
 
1382
1382
  dompurify/dist/purify.es.mjs:
@@ -1258,6 +1258,9 @@ a.server-port:hover { text-decoration: underline; }
1258
1258
  user-select: text;
1259
1259
  }
1260
1260
  .tool-digest:hover { color: var(--fg); }
1261
+ /* Expanded = nothing readable hidden: the digest wraps to its full text (it may be the whole
1262
+ result — suppressed patch one-liners rely on this). */
1263
+ .tool-digest.open { white-space: normal; }
1261
1264
 
1262
1265
  /* Expanded input/output card beneath the digest row — additive only, the rows above keep their
1263
1266
  collapsed look. First child sheds its top divider (nothing above it inside the card). */
@@ -1376,7 +1376,7 @@ ${JEt(m)}`};let v=qEt(d.code,{jsxImportSource:g.ts?.jsxImportSource});if(v.error
1376
1376
 
1377
1377
  `)}stickToBottomNextRender(){this.#n=!0}#u(o,a){o.segments=[...o.segments??[o.text],a],o.text=o.segments.join(`
1378
1378
 
1379
- `)}applyUser(o){let a=this.messages[this.messages.length-1];if(a&&a.role==="user"){this.#u(a,o.text),a.copy?a.copy.setText(a.text):a.text&&(a.copy=this.#i(a.text));return}this.#s({id:++this.#e,role:"user",text:o.text,thinking:"",tools:[]})}applyAssistant(o){let a=this.#s({id:++this.#e,role:"assistant",text:o.text,thinking:o.thinking,tools:o.tools.map(g=>({...g,isError:!1}))}),d=this.messages[this.messages.length-2];if(a.turnCopy=d?.role==="assistant"&&d.turnCopy||this.#i(""),a.turnCopy.setText(this.#c()),this.#f(a,o.text),this.#h(),o.live)for(let g of o.tools)W4n.has(g.name)&&this.openTools.add(g.id)}#f(o,a){let d=eSt(a);d.some(g=>g.kind==="bulb")&&(o.body=d.map(g=>{if(g.kind==="md")return g.text;let m=new $re(g.source,`embed-${this.#t++}`);return this.bulbEmbeds.push(m),m}))}#h(){let o=this.bulbEmbeds.map(g=>g.name),a=tSt(o),d=nSt(o);this.#r=new Set(this.bulbEmbeds.filter((g,m)=>a[m])),this.bulbEmbeds.forEach((g,m)=>{g.setChainPosition(d[m]),g.setMounted(!a[m]||this.expandedEmbeds.has(g.key))})}#a(o){Dxe(this.expandedEmbeds,o),this.#h(),this.update()}applyToolResult(o){let a=this.#o(o.id);a&&(a.result=o.content,a.isError=o.isError,a.digest=o.digest)}applyFork(o){let a=this.#l(o.events);this.#s({id:++this.#e,role:"fork",text:"",thinking:"",tools:[],fork:{count:o.count,sub:a}})}#l(o){let a=[];for(let d of o)if(d.type==="user"){let g=a[a.length-1];g&&g.role==="user"?this.#u(g,d.text):a.push({id:++this.#e,role:"user",text:d.text,thinking:"",tools:[]})}else if(d.type==="assistant")a.push({id:++this.#e,role:"assistant",text:d.text,thinking:d.thinking,tools:d.tools.map(g=>({...g,isError:!1}))});else if(d.type==="tool_result"){let g=a.flatMap(m=>m.tools).find(m=>m.id===d.id);g&&(g.result=d.content,g.isError=d.isError,g.digest=d.digest)}return a}#o(o){return this.messages.flatMap(a=>a.tools).find(a=>a.id===o)}scrollSoon(){requestAnimationFrame(()=>{this.scrollEl&&this.#n&&(this.scrollEl.scrollTop=this.scrollEl.scrollHeight)})}onScroll(){let o=this.scrollEl;o&&(this.#n=o.scrollHeight-(o.scrollTop+o.clientHeight)<50)}view(){return Kr({class:"messages",onScroll:()=>this.onScroll(),onMounted:o=>{this.scrollEl=o}},this.parent.ready?this.renderMessages():Kr({class:"note"},"Connecting\u2026"))}renderMessages(){let o=[],a=-1;for(let d of this.messages)d.role==="user"||o.length===0?(d.role==="user"&&a++,o.push({idx:Math.max(0,a),msgs:[d]})):o[o.length-1].msgs.push(d);return o.flatMap((d,g)=>this.renderTurn(d.msgs,d.idx,g===o.length-1))}renderTurn(o,a,d){if(this.parent.prose){let T=o.filter(D=>D.role==="user"||D.role==="fork"||D.text||D.body),L=[...T].reverse().find(D=>D.role==="assistant"&&!!D.text);return T.map(D=>{if(D.role==="fork")return this.forkStub(D,a);let j=D.role==="user"?D.copy:D===L?D.turnCopy:void 0;return this.bubble(D,a,j??null)})}let g=o.filter(T=>T.role==="assistant");if(d||g.length<2)return o.map(T=>T.role==="fork"?this.forkStub(T,a):this.bubble(T,a));let m=this.expandedTurns.has(a),v=g.slice(0,-1),A=g[g.length-1],I=o.filter(T=>T.role==="user").map(T=>this.bubble(T,a));for(let T of o)T.role==="fork"&&I.push(this.forkStub(T,a));if(I.push(this.turnSummary(v,a)),m)for(let T of v)I.push(this.bubble(T,a));return I.push(this.bubble(A,a)),I}#p(o,a,d,g,m,v){let A=d.has(g);return Kr({class:["bubble","assistant",Iye(a)],key:o},Kr({class:"turn-summary",onClick:()=>{Dxe(d,g),this.update()}},Mxe(A),Ro({class:"turn-summary-text"},m)),v??null)}forkStub(o,a){let d=o.fork,g=this.expandedForks.has(o.id)?Kr({class:"fork-body"},d.sub.map(v=>this.bubble(v,a,void 0,!1))):void 0,m=[z4n(),` ${d.count} message${d.count===1?"":"s"} on an abandoned branch`];return this.#p(`fork-${o.id}`,a,this.expandedForks,o.id,m,g)}turnSummary(o,a){return this.#p(`summary-${a}`,a,this.expandedTurns,a,Z4n(o))}bubble(o,a,d=o.copy,g=!0){let m=this.parent.prose,v=o.role==="assistant"&&!o.text&&!o.thinking&&o.tools.length>0;return Kr({class:["bubble",o.role,v?"tools-only":"",g?Iye(a):""],key:o.id},!m&&o.thinking?$5t({class:"thinking"},H5t("thinking"),I7(o.thinking)):null,this.#g(o),m?null:o.tools.map(A=>this.tool(A)),d?d.view():null)}#g(o){return o.body?o.body.flatMap((a,d)=>typeof a=="string"?a.trim()?[this.#d(`md-${o.id}-${d}`,Pre(a))]:[]:this.#b(a)):o.text?this.#d(`md-${o.id}`,o.role==="user"?ZIt(o):Pre(o.text)):null}#b(o){if(!this.#r.has(o))return[o.view()];let a=this.expandedEmbeds.has(o.key),d=Kr({class:"md",key:`fold-${o.key}`},Kr({class:"bulb-fold",onClick:()=>this.#a(o.key)},Mxe(a),Ro({class:"bulb-fold-text"},`${o.name??"bulb"} \u2014 Version ${o.chainPosition}`),Ro({class:"bulb-fold-app"},"\u{1F4A1}")));return a?[d,o.view()]:[d]}#d(o,a){return Kr({class:"md",key:o,onMounted:a})}tool(o){let a=this.openTools.has(o.id),d=Y4n(o.name,o.input),g=sSt(o),m=d?V5t(d,this.parent.cwd):U4n(J4n(o.input));return Kr({class:["tool",o.isError?"err":""]},Kr({class:"tool-head"},Kr({class:"tool-label"},Ro({class:"tool-name",...o.name.startsWith("mcp__")?{title:o.name}:{}},Bxe(o.name)),m?d?sM({class:"tool-sum link",title:d,onClick:v=>{v.preventDefault(),tb.server.openFile(d)}},m):Ro({class:"tool-sum"},m):null),o.result===void 0?Ro({class:"tool-run"},"\u2026"):null),o.result!==void 0?Kr({class:"tool-digest",onClick:()=>{Dxe(this.openTools,o.id),this.update()}},Mxe(a),(g?V4n(g):o.digest)||"(no output)"):null,a?Kr({class:"tool-card"},this.toolBody(o),o.result!==void 0&&(!(g||iSt(o).length)||o.isError)?I7({class:"tool-out"},o.result.slice(0,4e3)):null):null)}toolBody(o){let a=sSt(o);if(a)return Kr({class:"todo-list"},a.map(m=>Kr({class:["todo",m.status??""]},Ro({class:"todo-icon"},m.status==="completed"?"\u2714":m.status==="in_progress"?"\u25FC":"\u25FB"),Ro({class:"todo-text"},m.content??""))));let d=iSt(o);if(d.length)return Kr({class:"tool-in"},d.map(rSt));let g=X4n(o);if(!g){let m=Object.entries(o.input??{});return m.length?Kr({class:"tool-in"},m.map(([v,A])=>Kr({class:"tool-field"},Ro({class:"tool-key"},`${v}:`),typeof A=="string"&&oSt(A)?rSt(A):I7({class:"tool-val"},typeof A=="string"?A:JSON.stringify(A,null,2))))):null}return Kr({class:"diff"},...g.flatMap((m,v)=>[g.length>1?Kr({class:"diff-step"},`edit ${v+1}/${g.length}`):null,m.old?I7({class:"diff-old"},String(m.old)):null,m.new?I7({class:"diff-new"},String(m.new)):null]))}};var Qre=class extends Ku{ready=!1;cwd="";sessionId="";sessionPicker=new Hee;tokenPill=new Qee;bulbsPill=new Gee;prosePill=new qee;messageList=new Hre;tokens={in:0,out:0,cached:0,cacheCreate:0};working=!1;latestModel=null;prose=!1;ownPid=0;pills;#e=0;#t=!1;#r=!1;#n;#i;#s;constructor(o){super(),this.pills=o.pills,this.#n=o.title,this.#i=o.overlays??[],this.#s=o.onPollTick}onAttached(){this.#r||(this.#r=!0,this.init())}closePopups(o){this.sessionPicker!==o&&this.sessionPicker.close(),this.bulbsPill!==o&&this.bulbsPill.close();for(let a of this.pills)a!==o&&a.close?.()}async init(){let o=await tb.server.info();this.cwd=o.cwd,this.ownPid=o.pid??0,this.ready=!0,this.updateTitle(),this.update(),this.pump()}updateTitle(){let o=Sye(this.cwd),a=this.sessionPicker.currentPreview(),d=Fee(a,40);document.title=d&&o?`${d} \u2014 ${o}`:d||(o?`${this.#n} \u2014 ${o}`:this.#n)}pump(){if(this.#t)return;this.#t=!0;let o=async()=>{try{let{events:a,cursor:d,working:g,latestModel:m}=await tb.server.poll(this.#e);this.#e=d;for(let I of a)this.apply(I);let v=g!==this.working;this.working=g;let A=m!==this.latestModel;this.latestModel=m??null,(a.length||v||A)&&this.update(),a.length&&this.messageList.scrollSoon(),this.#s?.()}catch(a){console.error("[mirror] poll failed",a)}setTimeout(o,600)};o()}apply(o){switch(o.type){case"cleared":this.messageList.clear(),this.tokens={in:0,out:0,cached:0,cacheCreate:0};break;case"session":this.sessionId=o.sessionId,this.updateTitle();break;case"user":this.messageList.applyUser(o);break;case"assistant":this.messageList.applyAssistant(o);break;case"tool_result":this.messageList.applyToolResult(o);break;case"fork":this.messageList.applyFork(o);break;case"usage":this.tokens={in:o.in,out:o.out,cached:o.cached,cacheCreate:o.cacheCreate};break}}view(){return Kr({class:"app"},this.messageList.view(),...this.#i.map(o=>o()),this.statusbar())}statusbar(){return Kr({class:"statusbar"},Kr({class:"statusbar-actions"},this.prosePill.view(),...this.pills.map(o=>o.view()),this.tokenPill.view(),this.sessionPicker.view(),this.bulbsPill.view()))}};var Gre=class extends Ku{get parent(){return this.ctx.parent}view(){let o=this.parent.latestModel;if(!o)return Ro({class:"model-wrap"});let a=o.includes("/")?o.slice(o.lastIndexOf("/")+1):o;return Ro({class:"model-wrap"},Ro({class:"token",title:`Model: ${o}`},a))}};document.title="Pi Mirror";new G5t({root:new Qre({title:"Pi Mirror",pills:[new Gre]}),id:"app"});
1379
+ `)}applyUser(o){let a=this.messages[this.messages.length-1];if(a&&a.role==="user"){this.#u(a,o.text),a.copy?a.copy.setText(a.text):a.text&&(a.copy=this.#i(a.text));return}this.#s({id:++this.#e,role:"user",text:o.text,thinking:"",tools:[]})}applyAssistant(o){let a=this.#s({id:++this.#e,role:"assistant",text:o.text,thinking:o.thinking,tools:o.tools.map(g=>({...g,isError:!1}))}),d=this.messages[this.messages.length-2];if(a.turnCopy=d?.role==="assistant"&&d.turnCopy||this.#i(""),a.turnCopy.setText(this.#c()),this.#f(a,o.text),this.#h(),o.live)for(let g of o.tools)W4n.has(g.name)&&this.openTools.add(g.id)}#f(o,a){let d=eSt(a);d.some(g=>g.kind==="bulb")&&(o.body=d.map(g=>{if(g.kind==="md")return g.text;let m=new $re(g.source,`embed-${this.#t++}`);return this.bulbEmbeds.push(m),m}))}#h(){let o=this.bulbEmbeds.map(g=>g.name),a=tSt(o),d=nSt(o);this.#r=new Set(this.bulbEmbeds.filter((g,m)=>a[m])),this.bulbEmbeds.forEach((g,m)=>{g.setChainPosition(d[m]),g.setMounted(!a[m]||this.expandedEmbeds.has(g.key))})}#a(o){Dxe(this.expandedEmbeds,o),this.#h(),this.update()}applyToolResult(o){let a=this.#o(o.id);a&&(a.result=o.content,a.isError=o.isError,a.digest=o.digest)}applyFork(o){let a=this.#l(o.events);this.#s({id:++this.#e,role:"fork",text:"",thinking:"",tools:[],fork:{count:o.count,sub:a}})}#l(o){let a=[];for(let d of o)if(d.type==="user"){let g=a[a.length-1];g&&g.role==="user"?this.#u(g,d.text):a.push({id:++this.#e,role:"user",text:d.text,thinking:"",tools:[]})}else if(d.type==="assistant")a.push({id:++this.#e,role:"assistant",text:d.text,thinking:d.thinking,tools:d.tools.map(g=>({...g,isError:!1}))});else if(d.type==="tool_result"){let g=a.flatMap(m=>m.tools).find(m=>m.id===d.id);g&&(g.result=d.content,g.isError=d.isError,g.digest=d.digest)}return a}#o(o){return this.messages.flatMap(a=>a.tools).find(a=>a.id===o)}scrollSoon(){requestAnimationFrame(()=>{this.scrollEl&&this.#n&&(this.scrollEl.scrollTop=this.scrollEl.scrollHeight)})}onScroll(){let o=this.scrollEl;o&&(this.#n=o.scrollHeight-(o.scrollTop+o.clientHeight)<50)}view(){return Kr({class:"messages",onScroll:()=>this.onScroll(),onMounted:o=>{this.scrollEl=o}},this.parent.ready?this.renderMessages():Kr({class:"note"},"Connecting\u2026"))}renderMessages(){let o=[],a=-1;for(let d of this.messages)d.role==="user"||o.length===0?(d.role==="user"&&a++,o.push({idx:Math.max(0,a),msgs:[d]})):o[o.length-1].msgs.push(d);return o.flatMap((d,g)=>this.renderTurn(d.msgs,d.idx,g===o.length-1))}renderTurn(o,a,d){if(this.parent.prose){let T=o.filter(D=>D.role==="user"||D.role==="fork"||D.text||D.body),L=[...T].reverse().find(D=>D.role==="assistant"&&!!D.text);return T.map(D=>{if(D.role==="fork")return this.forkStub(D,a);let j=D.role==="user"?D.copy:D===L?D.turnCopy:void 0;return this.bubble(D,a,j??null)})}let g=o.filter(T=>T.role==="assistant");if(d||g.length<2)return o.map(T=>T.role==="fork"?this.forkStub(T,a):this.bubble(T,a));let m=this.expandedTurns.has(a),v=g.slice(0,-1),A=g[g.length-1],I=o.filter(T=>T.role==="user").map(T=>this.bubble(T,a));for(let T of o)T.role==="fork"&&I.push(this.forkStub(T,a));if(I.push(this.turnSummary(v,a)),m)for(let T of v)I.push(this.bubble(T,a));return I.push(this.bubble(A,a)),I}#p(o,a,d,g,m,v){let A=d.has(g);return Kr({class:["bubble","assistant",Iye(a)],key:o},Kr({class:"turn-summary",onClick:()=>{Dxe(d,g),this.update()}},Mxe(A),Ro({class:"turn-summary-text"},m)),v??null)}forkStub(o,a){let d=o.fork,g=this.expandedForks.has(o.id)?Kr({class:"fork-body"},d.sub.map(v=>this.bubble(v,a,void 0,!1))):void 0,m=[z4n(),` ${d.count} message${d.count===1?"":"s"} on an abandoned branch`];return this.#p(`fork-${o.id}`,a,this.expandedForks,o.id,m,g)}turnSummary(o,a){return this.#p(`summary-${a}`,a,this.expandedTurns,a,Z4n(o))}bubble(o,a,d=o.copy,g=!0){let m=this.parent.prose,v=o.role==="assistant"&&!o.text&&!o.thinking&&o.tools.length>0;return Kr({class:["bubble",o.role,v?"tools-only":"",g?Iye(a):""],key:o.id},!m&&o.thinking?$5t({class:"thinking"},H5t("thinking"),I7(o.thinking)):null,this.#g(o),m?null:o.tools.map(A=>this.tool(A)),d?d.view():null)}#g(o){return o.body?o.body.flatMap((a,d)=>typeof a=="string"?a.trim()?[this.#d(`md-${o.id}-${d}`,Pre(a))]:[]:this.#b(a)):o.text?this.#d(`md-${o.id}`,o.role==="user"?ZIt(o):Pre(o.text)):null}#b(o){if(!this.#r.has(o))return[o.view()];let a=this.expandedEmbeds.has(o.key),d=Kr({class:"md",key:`fold-${o.key}`},Kr({class:"bulb-fold",onClick:()=>this.#a(o.key)},Mxe(a),Ro({class:"bulb-fold-text"},`${o.name??"bulb"} \u2014 Version ${o.chainPosition}`),Ro({class:"bulb-fold-app"},"\u{1F4A1}")));return a?[d,o.view()]:[d]}#d(o,a){return Kr({class:"md",key:o,onMounted:a})}tool(o){let a=this.openTools.has(o.id),d=Y4n(o.name,o.input),g=sSt(o),m=d?V5t(d,this.parent.cwd):U4n(J4n(o.input));return Kr({class:["tool",o.isError?"err":""]},Kr({class:"tool-head"},Kr({class:"tool-label"},Ro({class:"tool-name",...o.name.startsWith("mcp__")?{title:o.name}:{}},Bxe(o.name)),m?d?sM({class:"tool-sum link",title:d,onClick:v=>{v.preventDefault(),tb.server.openFile(d)}},m):Ro({class:"tool-sum"},m):null),o.result===void 0?Ro({class:"tool-run"},"\u2026"):null),o.result!==void 0?Kr({class:["tool-digest",a?"open":""],onClick:()=>{Dxe(this.openTools,o.id),this.update()}},Mxe(a),(g?V4n(g):o.digest)||"(no output)"):null,a?Kr({class:"tool-card"},this.toolBody(o),o.result!==void 0&&(o.isError||!(g||iSt(o).length&&o.result.trim()===o.digest))?I7({class:"tool-out"},o.result.slice(0,4e3)):null):null)}toolBody(o){let a=sSt(o);if(a)return Kr({class:"todo-list"},a.map(m=>Kr({class:["todo",m.status??""]},Ro({class:"todo-icon"},m.status==="completed"?"\u2714":m.status==="in_progress"?"\u25FC":"\u25FB"),Ro({class:"todo-text"},m.content??""))));let d=iSt(o);if(d.length)return Kr({class:"tool-in"},d.map(rSt));let g=X4n(o);if(!g){let m=Object.entries(o.input??{});return m.length?Kr({class:"tool-in"},m.map(([v,A])=>Kr({class:"tool-field"},Ro({class:"tool-key"},`${v}:`),typeof A=="string"&&oSt(A)?rSt(A):I7({class:"tool-val"},typeof A=="string"?A:JSON.stringify(A,null,2))))):null}return Kr({class:"diff"},...g.flatMap((m,v)=>[g.length>1?Kr({class:"diff-step"},`edit ${v+1}/${g.length}`):null,m.old?I7({class:"diff-old"},String(m.old)):null,m.new?I7({class:"diff-new"},String(m.new)):null]))}};var Qre=class extends Ku{ready=!1;cwd="";sessionId="";sessionPicker=new Hee;tokenPill=new Qee;bulbsPill=new Gee;prosePill=new qee;messageList=new Hre;tokens={in:0,out:0,cached:0,cacheCreate:0};working=!1;latestModel=null;prose=!1;ownPid=0;pills;#e=0;#t=!1;#r=!1;#n;#i;#s;constructor(o){super(),this.pills=o.pills,this.#n=o.title,this.#i=o.overlays??[],this.#s=o.onPollTick}onAttached(){this.#r||(this.#r=!0,this.init())}closePopups(o){this.sessionPicker!==o&&this.sessionPicker.close(),this.bulbsPill!==o&&this.bulbsPill.close();for(let a of this.pills)a!==o&&a.close?.()}async init(){let o=await tb.server.info();this.cwd=o.cwd,this.ownPid=o.pid??0,this.ready=!0,this.updateTitle(),this.update(),this.pump()}updateTitle(){let o=Sye(this.cwd),a=this.sessionPicker.currentPreview(),d=Fee(a,40);document.title=d&&o?`${d} \u2014 ${o}`:d||(o?`${this.#n} \u2014 ${o}`:this.#n)}pump(){if(this.#t)return;this.#t=!0;let o=async()=>{try{let{events:a,cursor:d,working:g,latestModel:m}=await tb.server.poll(this.#e);this.#e=d;for(let I of a)this.apply(I);let v=g!==this.working;this.working=g;let A=m!==this.latestModel;this.latestModel=m??null,(a.length||v||A)&&this.update(),a.length&&this.messageList.scrollSoon(),this.#s?.()}catch(a){console.error("[mirror] poll failed",a)}setTimeout(o,600)};o()}apply(o){switch(o.type){case"cleared":this.messageList.clear(),this.tokens={in:0,out:0,cached:0,cacheCreate:0};break;case"session":this.sessionId=o.sessionId,this.updateTitle();break;case"user":this.messageList.applyUser(o);break;case"assistant":this.messageList.applyAssistant(o);break;case"tool_result":this.messageList.applyToolResult(o);break;case"fork":this.messageList.applyFork(o);break;case"usage":this.tokens={in:o.in,out:o.out,cached:o.cached,cacheCreate:o.cacheCreate};break}}view(){return Kr({class:"app"},this.messageList.view(),...this.#i.map(o=>o()),this.statusbar())}statusbar(){return Kr({class:"statusbar"},Kr({class:"statusbar-actions"},this.prosePill.view(),...this.pills.map(o=>o.view()),this.tokenPill.view(),this.sessionPicker.view(),this.bulbsPill.view()))}};var Gre=class extends Ku{get parent(){return this.ctx.parent}view(){let o=this.parent.latestModel;if(!o)return Ro({class:"model-wrap"});let a=o.includes("/")?o.slice(o.lastIndexOf("/")+1):o;return Ro({class:"model-wrap"},Ro({class:"token",title:`Model: ${o}`},a))}};document.title="Pi Mirror";new G5t({root:new Qre({title:"Pi Mirror",pills:[new Gre]}),id:"app"});
1380
1380
  /*! Bundled license information:
1381
1381
 
1382
1382
  dompurify/dist/purify.es.mjs:
@@ -1258,6 +1258,9 @@ a.server-port:hover { text-decoration: underline; }
1258
1258
  user-select: text;
1259
1259
  }
1260
1260
  .tool-digest:hover { color: var(--fg); }
1261
+ /* Expanded = nothing readable hidden: the digest wraps to its full text (it may be the whole
1262
+ result — suppressed patch one-liners rely on this). */
1263
+ .tool-digest.open { white-space: normal; }
1261
1264
 
1262
1265
  /* Expanded input/output card beneath the digest row — additive only, the rows above keep their
1263
1266
  collapsed look. First child sheds its top divider (nothing above it inside the card). */
package/dist/index.js CHANGED
@@ -326,7 +326,7 @@ const something = require('module-name') // NOT SUPPORTED!
326
326
  `),n=[];if(t.forEach((o,a)=>{let c=AS(o);c!==void 0&&n.push({id:c,idx:a})}),!n.length)return e==="latest"?r:"";let s=e==="latest"?n[n.length-1]:n.find(o=>o.id===e);if(!s)return"";let i=n.find(o=>o.idx>s.idx);return t.slice(s.idx,i?i.idx:t.length).join(`
327
327
  `)}function Qa(r){try{return process.kill(r,0),!0}catch(e){return e.code==="EPERM"}}async function oi(r){await SS(_e(),{recursive:!0}),await ap(Va(r.pid),JSON.stringify(r))}async function dp(r,e){let t=Va(r);try{let n=JSON.parse(await op(t,"utf8"));if(n.denied===e)return;n.denied=e,await ap(t,JSON.stringify(n))}catch{}}async function yt(r){await Wa(Va(r)).catch(()=>{}),await Wa(rn(r)).catch(()=>{}),await Wa(Ya(r)).catch(()=>{})}async function J(r){let e;try{e=await vS(_e())}catch{return[]}let t=[];return await Promise.all(e.map(async s=>{if(!/^\d+\.json$/.test(s))return;let i=parseInt(s,10),o;try{o=JSON.parse(await op(ae.join(_e(),s),"utf8"))}catch{await yt(i);return}o&&typeof o.pid=="number"&&Qa(o.pid)?t.push(o):await yt(i)})),(r?t.filter(s=>s.agent==null&&Wd(s.file,r)):t).sort((s,i)=>s.startedAt-i.startedAt)}async function Xa(r,e){let t=z(r);return(await J()).find(n=>n.cwd!=null&&z(n.cwd)===t&&(e?n.agent===e:n.agent!=null))}async function bt(r){try{process.kill(r,"SIGTERM")}catch{}await yt(r)}function Xt(r,e){let t=z(e);return r.filter(n=>n.agent==null&&n.pid!==process.pid&&z(n.file)===t)}async function Za(r){let e=Xt(await J(),r);for(let t of e)await bt(t.pid);return e}function OS(r,e,t){(process.platform==="win32"?sp("cmd",["/c","start","","/b",r,...e],{cwd:t,stdio:"ignore",windowsHide:!0}):sp(r,e,{cwd:t,detached:!0,stdio:"ignore"})).unref()}function pp(){return ae.join(ae.dirname(xS(import.meta.url)),"index.js")}function PS(r,e={}){return{command:process.execPath,args:[pp(),...e.trust?["--trust"]:[],r,...e.open===!1?["--no-open"]:[]]}}function RS(r){return{command:process.execPath,args:[pp(),`agent:${r}`,"--no-open"]}}async function mp(r,e,t,n){let s=await r();if(s)return s;OS(e.command,e.args,t);let i=Date.now()+2e4;for(;Date.now()<i;){await TS(150);let o=await r();if(o)return o}throw new Error(`Launched ${n} but it did not register within 20s.`)}async function ai(r,e={}){let t=e.cwd??process.cwd(),n=ae.resolve(t,r);return await Za(n),mp(async()=>Xt(await J(),n)[0],PS(r,e),t,ae.basename(r))}async function hp(r,e=process.cwd()){return mp(()=>Xa(e,r),RS(r),e,`the ${r} mirror`)}var ip,ES,TS,Le=R(()=>{Xs();ip=1e6;ES=/^── run (\d+) ── /;TS=r=>new Promise(e=>setTimeout(e,r))});function Se(r){return r.length>5e4?r.slice(0,5e4)+`
328
328
  \u2026[${r.length-5e4} more characters truncated]`:r}function $e(r){let e=r.replace(CS,"").split(`
329
- `).map(i=>i.trim()).filter(Boolean),t=e[0];if(!t)return"";let n=t.length>96?t.slice(0,96).trimEnd()+"\u2026":t,s=e.length-1;return s>0?`${n} (+${s} line${s===1?"":"s"})`:n}var CS,ci,li=R(()=>{CS=/\u001b\[[0-9;]*m/g;ci=(r,e)=>`![pasted image](data:${e||"image/png"};base64,${r})`});import{existsSync as NS,readdirSync as _S,statSync as IS}from"fs";import{join as LS}from"path";function ui(r){if(!NS(r))return[];let e;try{e=_S(r)}catch{return[]}let t=[];for(let n of e){if(!n.endsWith(".jsonl"))continue;let s=LS(r,n);try{let i=IS(s);i.isFile()&&t.push({sessionId:n.slice(0,-6),file:s,mtime:i.mtimeMs})}catch{}}return t}var ec=R(()=>{});var Zt,tc=R(()=>{Zt=class{ensureWaitSupport(){}}});import{openSync as $S,readSync as MS,closeSync as DS,statSync as BS,readdirSync as jS,readFileSync as FS}from"fs";import{join as fi}from"path";import{homedir as wp}from"os";function qS(r){return r.replace(/[^a-zA-Z0-9]/g,"-")}function di(r){let e=r?.type==="image"?r.source:void 0;return e?.type==="base64"&&e.data?ci(e.data,e.media_type):""}function rc(r){return typeof r=="string"?Se(r):Array.isArray(r)?r.map(e=>{if(typeof e=="string")return Se(e);let t=e;return typeof t?.text=="string"?Se(t.text):t?.content!=null?rc(t.content):di(t)}).join(`
329
+ `).map(i=>i.trim()).filter(Boolean),t=e[0];if(!t)return"";let n=t.length>300?t.slice(0,300).trimEnd()+"\u2026":t,s=e.length-1;return s>0?`${n} (+${s} line${s===1?"":"s"})`:n}var CS,ci,li=R(()=>{CS=/\u001b\[[0-9;]*m/g;ci=(r,e)=>`![pasted image](data:${e||"image/png"};base64,${r})`});import{existsSync as NS,readdirSync as _S,statSync as IS}from"fs";import{join as LS}from"path";function ui(r){if(!NS(r))return[];let e;try{e=_S(r)}catch{return[]}let t=[];for(let n of e){if(!n.endsWith(".jsonl"))continue;let s=LS(r,n);try{let i=IS(s);i.isFile()&&t.push({sessionId:n.slice(0,-6),file:s,mtime:i.mtimeMs})}catch{}}return t}var ec=R(()=>{});var Zt,tc=R(()=>{Zt=class{ensureWaitSupport(){}}});import{openSync as $S,readSync as MS,closeSync as DS,statSync as BS,readdirSync as jS,readFileSync as FS}from"fs";import{join as fi}from"path";import{homedir as wp}from"os";function qS(r){return r.replace(/[^a-zA-Z0-9]/g,"-")}function di(r){let e=r?.type==="image"?r.source:void 0;return e?.type==="base64"&&e.data?ci(e.data,e.media_type):""}function rc(r){return typeof r=="string"?Se(r):Array.isArray(r)?r.map(e=>{if(typeof e=="string")return Se(e);let t=e;return typeof t?.text=="string"?Se(t.text):t?.content!=null?rc(t.content):di(t)}).join(`
330
330
  `):r==null?"":Se(JSON.stringify(r))}function JS(r){let e=r.trim();return!!e&&vp.some(t=>t.test(e))}function KS(r){let e=r.trim();return e?vp.some(t=>{let n=t.exec(e);return!!n&&n.index===0}):!0}function HS(r){return r.replace(WS,"")}function VS(r){let e=/^<command-name>([\s\S]*?)<\/command-name>/.exec(r)?.[1]?.trim();if(!e)return;let t=/<command-args>([\s\S]*?)<\/command-args>/.exec(r)?.[1]?.trim();return t?`${e} ${t}`:e}function tt(r){let e=HS(r).trim();return e?VS(e)??(JS(e)?"":e):""}function nc(r){return r?.type==="text"&&typeof r.text=="string"?tt(r.text):""}function sc(r,e){if(typeof r=="string")return $e(r);if(!r||typeof r!="object")return $e(e);let t=r;if(t.type==="text"&&typeof t.file?.numLines=="number")return he(t.file.numLines,"line");if(t.type==="image"){let n=yp(t.file?.originalSize);return n?`image (${n})`:"image"}if(t.type==="pdf"){let n=yp(t.file?.originalSize);return n?`PDF (${n})`:"PDF"}if(t.type==="parts"&&typeof t.file?.count=="number")return he(t.file.count,"page");if(t.type==="file_unchanged")return"unchanged since last read";if(t.type==="create"&&typeof t.content=="string")return`created, ${he(t.content.split(`
331
331
  `).length,"line")}`;if(t.mode==="content")return he(t.numLines??0,"line");if(t.mode==="count")return`${he(t.numMatches??0,"match","matches")} (${he(t.numFiles??0,"file")})`;if(t.mode==="files_with_matches")return he(t.numFiles??0,"file");if(Array.isArray(t.structuredPatch)){let n=0,s=0;for(let i of t.structuredPatch)for(let o of i?.lines??[])typeof o=="string"&&(o.startsWith("+")?n++:o.startsWith("-")&&s++);return`+${n} \u2212${s}`}return typeof t.stdout=="string"||typeof t.stderr=="string"?t.backgroundTaskId?"running in background":t.interrupted?"interrupted":$e(t.stdout||t.stderr||"")||"no output":typeof t.code=="number"&&typeof t.codeText=="string"?`${t.code} ${t.codeText}`:typeof t.searchCount=="number"?he(t.searchCount,"search","searches"):Array.isArray(t.matches)&&typeof t.total_deferred_tools=="number"?he(t.matches.length,"tool"):Array.isArray(t.newTodos)?he(t.newTodos.length,"todo"):typeof t.numFiles=="number"?he(t.numFiles,"file"):$e(e)}function nn(r){return!!r.isSidechain||!!r.isMeta}function YS(r){let e;try{e=$S(r,"r")}catch{return""}try{let n=65536;try{n=BS(r).size}catch{}let s=(l,f)=>{if(f<=0)return"";let u=Buffer.alloc(f),d=MS(e,u,0,f,l);return u.subarray(0,d).toString("utf8")},i=(l,f,u)=>{let d="";for(let p of l.split(`
332
332
  `)){if(!p.includes(`"${f}"`))continue;let y;try{y=JSON.parse(p)}catch{continue}let m=y?.[u];y?.type===f&&typeof m=="string"&&m&&(d=m)}return d},o=s(0,Math.min(65536,n)),a=n>65536?s(n-65536,65536):"",c=i(a,"custom-title","customTitle")||i(o,"custom-title","customTitle")||i(a,"ai-title","aiTitle")||i(o,"ai-title","aiTitle");if(c)return c.replace(/\s+/g," ").trim().slice(0,200);for(let l of o.split(`
@@ -1375,5 +1375,5 @@ Shutting down...`);try{a.shutdownSwitcher?.()}catch{}g.close(),v?.(),s(),await y
1375
1375
  `),St({target:r,onChange:async()=>{try{console.log("Re-running..."),await a()}catch(c){console.error("Error:",c)}}}))}import{Console as o0}from"node:console";Le();async function Wm(r,e,t,n,s){f0();try{let p=Xt(await J(),r)[0];p&&(si(p.pid,ve(p.pid).offset),console.error(`note: 'call' boots a fresh server.ts instance; the running server (${p.url}) is not contacted \u2014 state shared with it must live on disk.`))}catch{}let i=ke(t),{bulb:o,config:a}=await me(r);o.server||hn("This bulb has no **server.ts** block; nothing to call."),rt(i,r,o.server);let c;try{c=await Zr(o.server,s,n,a.dependencies)}catch(p){hn(p instanceof Error?p.message:String(p))}let l=gi(c,e.fn);if(!l){let p=[...Object.keys(c).filter(y=>typeof c[y]=="function"),...Object.keys(pc)];hn(`Function '${e.fn}' not found. Available: ${p.length?p.join(", "):"(none)"}.`)}let f=await a0(e);if(yi(l)){try{for await(let p of l(...f))await Km(JSON.stringify(p,Hm)+`
1376
1376
  `)}catch(p){hn(p instanceof Error?p.stack??p.message:String(p))}return Jm(0)}let u;try{u=await l(...f)}catch(p){hn(p instanceof Error?p.stack??p.message:String(p))}let d=u0(u);d!==void 0&&await Km(d+`
1377
1377
  `),Jm(0)}function Jm(r){process.exitCode=r,setTimeout(()=>process.exit(r),2e3).unref?.()}async function a0(r){if(r.hasArgsFlag){let e=r.argsJson??"";return e==="-"&&(e=await d0()),l0(e)}return c0(r.positional)}function c0(r){return r.map(e=>{try{return JSON.parse(e)}catch{return e}})}function l0(r){let e;try{e=JSON.parse(r)}catch(t){throw new Error(`--args must be a JSON array: ${t instanceof Error?t.message:String(t)}`)}if(!Array.isArray(e))throw new Error(`--args must be a JSON array, got ${e===null?"null":typeof e}`);return e}function u0(r){if(r!==void 0)return JSON.stringify(r,Hm,2)}function Hm(r,e){return typeof e=="bigint"?e.toString():e}function hn(r){process.stderr.write(r+`
1378
- `),process.exit(1)}function f0(){let r=new o0(process.stderr,process.stderr);console.log=r.log.bind(r),console.info=r.info.bind(r),console.debug=r.debug.bind(r),console.dir=r.dir.bind(r)}function Km(r){return new Promise((e,t)=>{process.stdout.write(r,n=>n?t(n):e())})}async function d0(){let r=[];for await(let e of process.stdin)r.push(e);return Buffer.concat(r).toString("utf-8")}var $c="0.20.3";function Vm(r,e){r||(console.error(`This bulb runs server-side Node code (server.ts), which --trust must authorize:
1378
+ `),process.exit(1)}function f0(){let r=new o0(process.stderr,process.stderr);console.log=r.log.bind(r),console.info=r.info.bind(r),console.debug=r.debug.bind(r),console.dir=r.dir.bind(r)}function Km(r){return new Promise((e,t)=>{process.stdout.write(r,n=>n?t(n):e())})}async function d0(){let r=[];for await(let e of process.stdin)r.push(e);return Buffer.concat(r).toString("utf-8")}var $c="0.20.4";function Vm(r,e){r||(console.error(`This bulb runs server-side Node code (server.ts), which --trust must authorize:
1379
1379
  ${e}`),process.exit(1))}async function p0(){let r=Hc(process.argv.slice(2));if(r.version&&(console.log(`typebulb ${$c}`),process.exit(0)),r.help&&(Vc(),process.exit(0)),Tp(),r.subcommand==="logs"){await Bp(r.file||void 0,{follow:r.follow,clear:r.clear,run:r.run,lines:r.lines});return}if(r.subcommand==="wait"){await jp(r.file||void 0,{match:r.match,timeoutSec:r.timeoutSec});return}if(r.subcommand==="stop"){r.stopScope?await qp(r.stopScope):await Fp(r.file||void 0);return}if(r.subcommand==="send"){await Jp(r.file,r.sendMessage,r.sendWaitMs??0);return}if(r.subcommand==="skill"){await $p($c);return}if(r.subcommand==="models"){await Ip(r.mode);return}if(r.subcommand==="agent"){await(r.agentTarget?Fm(r):_p($c));return}if(r.subcommand==="trust"||r.subcommand==="untrust"){await np(r.file||void 0,r.subcommand==="trust");return}let e;if(!r.file||r.file==="."){let l=await Kd(process.cwd());l||(console.error("No .bulb.md file found in current directory"),process.exit(1)),e=l}else e=De.resolve(r.file);await Ym.access(e).then(()=>!0,()=>!1)||(Gt().includes(r.file)&&(console.error(`To open the ${r.file} agent mirror, run: npx typebulb agent:${r.file}`),process.exit(1)),console.error(`File not found: ${e}`),process.exit(1)),e.endsWith(".bulb.md")||(console.error("File must have .bulb.md extension"),process.exit(1));let n=r.file&&r.file!=="."?r.file:De.relative(process.cwd(),e)||De.basename(e),s=`npx typebulb --trust ${n.includes(" ")?`"${n}"`:n}`;if(r.subcommand==="predict"){await rp(e,s);return}let i=!r.noTrust&&gt(e);i&&!r.trust&&console.log("trust: granted from memory (run `typebulb untrust` to revoke)"),r.trust=r.noTrust?!1:r.trust||i;let o;try{o=await me(e)}catch{}let a;if(r.local){o&&!(r.local.name in(o.config.dependencies??{}))&&(console.error(`--replace: '${r.local.name}' is not a dependency in this bulb's config.json; nothing to replace.`),process.exit(1)),o&&r.subcommand!=="call"&&(!o.bulb.code||r.server)&&console.warn("warning: --replace has no effect in server mode (the override is client-only).");try{a=await Kc(r.local)}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exit(1)}console.log(`replace: ${a.name} \u2192 ${De.relative(process.cwd(),a.dir)||"."}`)}if(r.subcommand==="check"){await tp(e,a);return}let c=De.dirname(e);if(r.subcommand==="call"){Vm(r.trust,s),await Wm(e,{fn:r.fn,positional:r.callArgs,argsJson:r.argsJson,hasArgsFlag:r.hasArgsFlag},r.mode,a,c);return}if(o&&o.bulb.server&&(gs(o.bulb)||r.server)){Vm(r.trust,s),await Um(e,r.watch,r.mode,a,c);return}await Gp(e,r,s,a,c)}p0().catch(r=>{console.error("Error:",r.message),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typebulb",
3
- "version": "0.20.3",
3
+ "version": "0.20.4",
4
4
  "description": "Typebulb CLI to run single-file markdown apps called bulbs, either as standalone web apps or embedded in agent responses.",
5
5
  "license": "MIT",
6
6
  "repository": {