typebulb 0.24.0 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/claude/client.js +2 -2
- package/dist/agents/claude/styles.css +4 -0
- package/dist/agents/pi/client.js +116 -116
- package/dist/agents/pi/matchu-patchu.ts +1 -1
- package/dist/agents/pi/styles.css +4 -0
- package/dist/index.js +100 -99
- package/package.json +1 -1
|
@@ -1376,8 +1376,8 @@ ${iCt(m)}`};let v=rCt(d.code,{jsxImportSource:g.ts?.jsxImportSource});if(v.error
|
|
|
1376
1376
|
|
|
1377
1377
|
`)}stickToBottomNextRender(){this.#n=!0}#l(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.#l(a,o.text),a.copy?a.copy.setText(a.text):a.text&&(a.copy=this.#a(a.text));return}this.#f({id:++this.#e,role:"user",text:o.text,thinking:"",tools:[]})}applyAssistant(o){let a=this.#f({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.#a(""),a.turnCopy.setText(this.#h()),this.#u(a,o.text),this.#d(),o.live)for(let g of o.tools)bvn.has(g.name)&&this.openTools.add(g.id)}#u(o,a){let d=$xe(a);d.some(g=>g.kind==="bulb")&&(o.body=d.map(g=>{if(g.kind==="md")return g.text;let m=new zre(g.source,`embed-${this.#t++}`);return this.bulbEmbeds.push(m),m}))}#d(){let o=this.bulbEmbeds.map(g=>g.name),a=fSt(o),d=hSt(o);this.#i=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))})}#p(o){Qxe(this.expandedEmbeds,o),this.#d(),this.update()}applyToolResult(o){let a=this.#g(o.id);a&&(a.result=o.content,a.isError=o.isError,a.digest=o.digest)}applyFork(o){let a=this.#m(o.events);this.#f({id:++this.#e,role:"fork",text:"",thinking:"",tools:[],fork:{count:o.count,sub:a}})}#m(o){let a=[];for(let d of o)if(d.type==="user"){let g=a[a.length-1];g&&g.role==="user"?this.#l(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}#g(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=yF(o,50))}view(){return Zt({class:"messages",onScroll:()=>this.onScroll(),onMounted:o=>{this.scrollEl=o}},this.parent.ready?this.renderMessages():Zt({class:"note"},"Connecting\u2026"))}renderMessages(){let o=[],a=-1;for(let w of this.messages)w.role==="user"||o.length===0?(w.role==="user"&&a++,o.push({idx:Math.max(0,a),msgs:[w]})):o[o.length-1].msgs.push(w);let d=o.flatMap((w,I)=>this.renderTurn(w.msgs,w.idx,I===o.length-1));d.unshift(this.#w());let g=this.parent.echo,m=this.parent.draft,v=g?a+1:Math.max(0,a);return g&&d.push(this.#A(g,v)),m?d.push(this.#v(m,v)):(this.#r.clear(),this.#o=!1),d}#w(){return Zt({class:"masthead",key:"masthead"},$ee({class:"masthead-logo light",src:lvn,alt:"typebulb"}),$ee({class:"masthead-logo dark",src:fvn,alt:"typebulb"}),Zt({class:"masthead-tagline"},"a live mirror of your agent\u2019s session, with embedded bulbs, latex, svg, mermaid and more"))}#A(o,a){return Zt({class:["bubble","user",kF(a)],key:`echo-${o.length}`},this.#b(`md-echo-${o.length}`,Fxe({id:-1,role:"user",text:o,thinking:"",tools:[]})))}#v(o,a){let d=`draft-${o.text.length}-${o.thinking.length}`;return o.text.length<this.#s&&this.#r.clear(),this.#s=o.text.length,Zt({class:["bubble","assistant","draft",kF(a)],key:d},!this.parent.prose&&o.thinking?Oye({class:"thinking",open:this.#o,onToggle:g=>{this.#o=g.currentTarget.open}},Rye("thinking"),
|
|
1380
|
-
`).length;return Zt({class:"md",key:`draft-bulb-${a}`},Zt({class:"embed bulb-streaming"},Zt({class:"bulb-streaming-head"},Ji("\u{1F4A1} "),Ji({class:"shimmer-text shimmer-slow"},`${d?`${d} \u2014 `:""}writing\u2026`),Ji({class:"bulb-streaming-count"},`${g} lines`)),Zt({class:["bulb-code","md"],
|
|
1379
|
+
`)}applyUser(o){let a=this.messages[this.messages.length-1];if(a&&a.role==="user"){this.#l(a,o.text),a.copy?a.copy.setText(a.text):a.text&&(a.copy=this.#a(a.text));return}this.#f({id:++this.#e,role:"user",text:o.text,thinking:"",tools:[]})}applyAssistant(o){let a=this.#f({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.#a(""),a.turnCopy.setText(this.#h()),this.#u(a,o.text),this.#d(),o.live)for(let g of o.tools)bvn.has(g.name)&&this.openTools.add(g.id)}#u(o,a){let d=$xe(a);d.some(g=>g.kind==="bulb")&&(o.body=d.map(g=>{if(g.kind==="md")return g.text;let m=new zre(g.source,`embed-${this.#t++}`);return this.bulbEmbeds.push(m),m}))}#d(){let o=this.bulbEmbeds.map(g=>g.name),a=fSt(o),d=hSt(o);this.#i=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))})}#p(o){Qxe(this.expandedEmbeds,o),this.#d(),this.update()}applyToolResult(o){let a=this.#g(o.id);a&&(a.result=o.content,a.isError=o.isError,a.digest=o.digest)}applyFork(o){let a=this.#m(o.events);this.#f({id:++this.#e,role:"fork",text:"",thinking:"",tools:[],fork:{count:o.count,sub:a}})}#m(o){let a=[];for(let d of o)if(d.type==="user"){let g=a[a.length-1];g&&g.role==="user"?this.#l(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}#g(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=yF(o,50))}view(){return Zt({class:"messages",onScroll:()=>this.onScroll(),onMounted:o=>{this.scrollEl=o}},this.parent.ready?this.renderMessages():Zt({class:"note"},"Connecting\u2026"))}renderMessages(){let o=[],a=-1;for(let w of this.messages)w.role==="user"||o.length===0?(w.role==="user"&&a++,o.push({idx:Math.max(0,a),msgs:[w]})):o[o.length-1].msgs.push(w);let d=o.flatMap((w,I)=>this.renderTurn(w.msgs,w.idx,I===o.length-1));d.unshift(this.#w());let g=this.parent.echo,m=this.parent.draft,v=g?a+1:Math.max(0,a);return g&&d.push(this.#A(g,v)),m?d.push(this.#v(m,v)):(this.#r.clear(),this.#o=!1),d}#w(){return Zt({class:"masthead",key:"masthead"},$ee({class:"masthead-logo light",src:lvn,alt:"typebulb"}),$ee({class:"masthead-logo dark",src:fvn,alt:"typebulb"}),Zt({class:"masthead-tagline"},"a live mirror of your agent\u2019s session, with embedded bulbs, latex, svg, mermaid and more"))}#A(o,a){return Zt({class:["bubble","user",kF(a)],key:`echo-${o.length}`},this.#b(`md-echo-${o.length}`,Fxe({id:-1,role:"user",text:o,thinking:"",tools:[]})))}#v(o,a){let d=`draft-${o.text.length}-${o.thinking.length}`;return o.text.length<this.#s&&this.#r.clear(),this.#s=o.text.length,Zt({class:["bubble","assistant","draft",kF(a)],key:d},!this.parent.prose&&o.thinking?Oye({class:"thinking",open:this.#o,onToggle:g=>{this.#o=g.currentTarget.open}},Rye("thinking"),this.#E(o.thinking)):null,o.text.trim()?this.#x(d,o.text):Zt({class:"draft-wait shimmer-text"},"\u2026"))}#x(o,a){let d=$xe(a);return d.some(g=>g.kind==="bulb")?d.map((g,m)=>g.kind==="md"?g.text.trim()?this.#b(`${o}-md-${m}`,ZM(g.text)):null:this.#C(g.source,m)):this.#b(o,ZM(a))}#y(o,a){return{onScroll:d=>{let g=d.currentTarget;this.#r.set(o,{top:g.scrollTop,stuck:yF(g,50)})},onMounted:d=>{a?.(d);let g=this.#r.get(o);d.scrollTop=g&&!g.stuck?g.top:d.scrollHeight}}}#E(o){return e6({key:`think-${o.length}`,...this.#y(-1)},o)}#C(o,a){let d=mH(o),g=o.split(`
|
|
1380
|
+
`).length;return Zt({class:"md",key:`draft-bulb-${a}`},Zt({class:"embed bulb-streaming"},Zt({class:"bulb-streaming-head"},Ji("\u{1F4A1} "),Ji({class:"shimmer-text shimmer-slow"},`${d?`${d} \u2014 `:""}writing\u2026`),Ji({class:"bulb-streaming-count"},`${g} lines`)),Zt({class:["bulb-code","md"],key:`bulb-code-${o.length}`,...this.#y(a,m=>{m.innerHTML=Jre.render(wH(o))})})))}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}#k(o,a,d,g,m,v){let w=d.has(g);return Zt({class:["bubble","assistant",kF(a)],key:o},Zt({class:"turn-summary",onClick:()=>{Qxe(d,g),this.update()}},Hxe(w),Ji({class:"turn-summary-text"},m)),v??null)}forkStub(o,a){let d=o.fork,g=this.expandedForks.has(o.id)?Zt({class:"fork-body"},d.sub.map(v=>this.bubble(v,a,void 0,!1))):void 0,m=[pvn(),` ${d.count} message${d.count===1?"":"s"} on an abandoned branch`];return this.#k(`fork-${o.id}`,a,this.expandedForks,o.id,m,g)}turnSummary(o,a){return this.#k(`summary-${a}`,a,this.expandedTurns,a,vvn(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 Zt({class:["bubble",o.role,v?"tools-only":"",g?kF(a):""],key:o.id},!m&&o.thinking?Oye({class:"thinking"},Rye("thinking"),e6(o.thinking)):null,this.#T(o),o.role==="user"?this.#I(o):null,m?null:o.tools.map(w=>this.tool(w)),d?d.view():null)}#I(o){let d=[...o.text.matchAll(avn)].map(g=>g[1]).map(g=>this.#S(g)).filter(g=>!!g);return d.length?Zt({class:"paste-thumbs"},d.map(g=>$ee({class:"paste-thumb",src:g,alt:"pasted image"}))):null}#S(o){let a=this.#c.get(o);if(!(a==="pending"||a==="failed")){if(a)return a;this.#c.set(o,"pending"),(async()=>{try{let d=await tb.server.composerPasteRead(o);this.#c.set(o,d?.ok?`data:${d.mime};base64,${d.base64}`:"failed"),d?.ok&&(this.update(),this.scrollSoon())}catch{this.#c.set(o,"failed")}})()}}#T(o){return o.body?o.body.flatMap((a,d)=>typeof a=="string"?a.trim()?[this.#b(`md-${o.id}-${d}`,ZM(a))]:[]:this.#_(a)):o.text?this.#b(`md-${o.id}`,o.role==="user"?Fxe(o):ZM(o.text)):null}#_(o){if(!this.#i.has(o))return[o.view()];let a=this.expandedEmbeds.has(o.key),d=Zt({class:"md",key:`fold-${o.key}`},Zt({class:"bulb-fold",onClick:()=>this.#p(o.key)},Hxe(a),Ji({class:"bulb-fold-text"},`${o.name??"bulb"} \u2014 Version ${o.chainPosition}`),Ji({class:"bulb-fold-app"},"\u{1F4A1}")));return a?[d,o.view()]:[d]}#b(o,a){return Zt({class:"md",key:o,onMounted:a})}tool(o){let a=this.openTools.has(o.id),d=mvn(o.name,o.input),g=mSt(o),m=d?f6t(d,this.parent.cwd):dvn(hvn(o.input));return Zt({class:["tool",o.isError?"err":""]},Zt({class:"tool-head"},Zt({class:"tool-label"},Ji({class:"tool-name",...o.name.startsWith("mcp__")?{title:o.name}:{}},Gxe(o.name)),m?d?oM({class:"tool-sum link",title:d,onClick:v=>{v.preventDefault(),tb.server.openFile(d)}},m):Ji({class:"tool-sum"},m):null),o.result===void 0?Ji({class:"tool-run"},"\u2026"):null),o.result!==void 0?Zt({class:["tool-digest",a?"open":""],onClick:()=>{Qxe(this.openTools,o.id),this.update()}},Hxe(a),(g?Avn(g):o.digest)||"(no output)"):null,a?Zt({class:"tool-card"},this.toolBody(o),o.result!==void 0&&(o.isError||!(g||bSt(o).length&&o.result.trim()===o.digest))?e6({class:"tool-out"},o.result.slice(0,4e3)):null):null)}toolBody(o){let a=mSt(o);if(a)return Zt({class:"todo-list"},a.map(m=>Zt({class:["todo",m.status??""]},Ji({class:"todo-icon"},m.status==="completed"?"\u2714":m.status==="in_progress"?"\u25FC":"\u25FB"),Ji({class:"todo-text"},m.content??""))));let d=bSt(o);if(d.length)return Zt({class:"tool-in"},d.map(gSt));let g=wvn(o);if(!g){let m=Object.entries(o.input??{});return m.length?Zt({class:"tool-in"},m.map(([v,w])=>Zt({class:"tool-field"},Ji({class:"tool-key"},`${v}:`),typeof w=="string"&&wSt(w)?gSt(w):e6({class:"tool-val"},typeof w=="string"?w:JSON.stringify(w,null,2))))):null}return Zt({class:"diff"},...g.flatMap((m,v)=>[g.length>1?Zt({class:"diff-step"},`edit ${v+1}/${g.length}`):null,m.old?e6({class:"diff-old"},String(m.old)):null,m.new?e6({class:"diff-new"},String(m.new)):null]))}};var Wre=class extends Ia{ready=!1;cwd="";sessionId=null;sessionPicker=new Kee;tokenPill=new Wee;bulbsPill=new Yee;prosePill=new Xee;messageList=new Kre;tokens={in:0,out:0,cached:0,cacheCreate:0};cost=0;stats=null;working=!1;latestModel=null;driverModel=null;busy=[];prose=!1;ownPid=0;pills;composer;draft=null;echo=null;#e=0;#t=!1;#i=!1;#n;#r;#s;constructor(o){super(),this.pills=o.pills,this.composer=o.composer,this.#n=o.title,this.#r=o.overlays??[],this.#s=o.onPollTick}onAttached(){this.#i||(this.#i=!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.composer&&(this.composer.enabled=!!o.composer),this.ready=!0,this.updateTitle(),this.update(),this.pump()}updateTitle(){let o=jye(this.cwd),a=this.sessionPicker.currentPreview(),d=Uee(a,40);document.title=d&&o?`${d} \u2014 ${o}`:d||(o?`${this.#n} \u2014 ${o}`:this.#n)}refreshSessions(){this.sessionPicker.loadSessions().then(()=>this.update()).catch(()=>{})}pump(){if(this.#t)return;this.#t=!0;let o=async()=>{try{let{events:a,cursor:d,working:g,latestModel:m,composer:v,busy:w}=await tb.server.poll(this.#e);this.#e=d;for(let F of a)this.apply(F);let I=g!==this.working;this.working=g;let T=Array.isArray(w)?w:[],L=T.join(`
|
|
1381
1381
|
`)!==this.busy.join(`
|
|
1382
1382
|
`);this.busy=T;let D=m!==this.latestModel;this.latestModel=m??null;let P=this.composer&&v?this.composer.syncFromPoll(v):!1;(a.length||I||D||P||L)&&this.update(),(a.length||P)&&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},this.cost=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},this.cost+=o.cost??0;break}}view(){return Zt({class:"app"},Zt({class:"chat"},this.messageList.view(),...this.#r.map(o=>o()),this.statusbar()),this.composer?.enabled?this.composer.view():null)}statusbar(){return Zt({class:"statusbar"},Zt({class:"statusbar-actions"},this.prosePill.view(),...this.pills.map(o=>o.view()),this.tokenPill.view(),this.sessionPicker.view(),this.bulbsPill.view()))}};var yvn=[[0,"Low"],[1,"Med"],[2,"High"]],kvn=1,Yre=s=>s?.message??String(s),xvn=()=>c6t({viewBox:"0 0 24 24",width:"15",height:"15",class:"anthropic-glyph",fill:"currentColor"},o6t({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"})),ASt=s=>s===!0?"ok":s===!1?"bad":"warn",Xre=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=o.error??null}catch(o){this.err=Yre(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:Yre(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=Yre(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??kvn}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=Yre(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?Zt({class:["model-banner","warn"]},Ji({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?Zt({class:"model-head"},qc({class:"model-info-toggle",onClick:o=>{o.stopPropagation(),this.infoOpen=!0,this.update()}},"Routing info"),Zt({class:"reasoning-ctl",title:"Reasoning sets the route\u2019s base thinking effort."},Ji({class:"reasoning-label"},"reasoning"),this.reasoningSelect())):this.current.externalBaseUrl?Zt({class:"model-head"},Ji({class:["model-route","warn"]},"Custom base URL set elsewhere \u2014 \u201CAnthropic (native)\u201D clears it")):null}reasoningSelect(){return s6t({target:this,prop:()=>this.reasoningSel,attrs:{class:"reasoning-select",onClick:o=>o.stopPropagation()},options:yvn.map(([o,a])=>({value:o,label:a}))})}infoView(){let o=this.label(this.current.model),a=()=>{this.infoOpen=!1,this.update()};return Zt({class:"picker model-picker diag-mode",tabIndex:0,onMounted:d=>d.focus(),onKeyDown:d=>{d.key==="Escape"&&(d.stopPropagation(),a())}},Zt({class:"diag-head"},Ji({class:"diag-name"},"Routing"),Zt({class:"diag-head-acts"},qc({class:"diag-back",title:"Back to the model list",onClick:d=>{d.stopPropagation(),a()}},"\u2190 models"))),Zt({class:"diag-body"},Zt({class:"diag-line"},`You are currently routing to ${o} via OpenRouter, not your Anthropic subscription.`),Zt({class:"diag-line"},"The route is shared by every Claude Code conversation scoped to this project."),Zt({class:"diag-line"},"Switching to or from Anthropic toggles the proxy, so for existing conversations you\u2019ll need to:"),Zt({class:["diag-line","diag-bullet"]},"\u2022 Relaunch the Claude CLI"),Zt({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":xvn();return Zt({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 Zt({class:"picker model-picker"},this.head(),Zt({id:"model-list",class:"picker-list",onScroll:()=>this.onListScroll()},o.map((d,g)=>this.row(d,g)),a?Zt({class:"picker-empty"},this.err?`Couldn't load models: ${this.err}`:"No OpenRouter models in the catalog right now."):null),this.err&&!a?Zt({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 Zt({class:g,onMouseEnter:d,onClick:()=>this.onActivate(a)},Zt({class:"picker-row-main"},Ji({class:"picker-dot"}),Ji({class:"picker-preview"},"+ Add OpenRouter key to unlock models\u2026")));if(o.kind==="default")return Zt({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)},Zt({class:"picker-row-main"},Ji({class:"picker-dot"}),Ji({class:"picker-preview"},"Anthropic (native)"),Zt({class:"model-trailing"},o.active?this.activeBadge():null)));let m=o.id;return Zt({class:[...g,o.active?"current":"","model-row"],title:m,onMouseEnter:d,onClick:()=>this.onActivate(a)},Zt({class:"picker-row-main"},Ji({class:"picker-dot"}),Ji({class:"picker-preview"},o.label),Zt({class:"model-trailing"},o.active?this.activeBadge():null,this.statusButton(m))))}activeBadge(){return Ji({class:["model-btn","model-active"],title:"Active \u2014 bare claude routes here now"},"active")}statusButton(o){if(this.probing===o)return Ji({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=ASt(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 Zt({class:"picker model-picker diag-mode",tabIndex:0,onMounted:a=>a.focus(),onKeyDown:a=>{a.key==="Escape"&&(a.stopPropagation(),this.closeDiag())}},Zt({class:"diag-head"},Ji({class:"diag-name"},this.label(o)),Zt({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"))),Zt({class:"diag-body"},...this.diagLines(o)))}diagLines(o){let a=this.probes[o];if(!a)return[Zt({class:["diag-line","muted"]},"Not probed yet \u2014 close this and hit probe.")];let d=[];if(!a.ok||a.callable===!1)d.push(Zt({class:["diag-line","bad"]},`\u2717 Not callable${a.status?` (HTTP ${a.status})`:""}: ${a.error||"unknown error"}`)),a.restriction&&d.push(Zt({class:["diag-line","warn"]},`\u26A0 ${a.restriction}`));else{d.push(Zt({class:["diag-line","ok"]},`\u2713 Callable${a.ms?` \xB7 ${a.ms}ms`:""}${a.sample?` \xB7 replied \u201C${a.sample}\u201D`:""}`)),a.provider&&d.push(Zt({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=ASt(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(Zt({class:["diag-line",m]},`${v}${w} \u2014 ${g.note}`)),g.works!==!0&&d.push(Zt({class:["diag-line","muted"]},"Without prompt caching every turn re-bills the whole context \u2014 costly over a long session."))}}return d.push(Zt({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 Zt({class:"picker model-picker key-entry",tabIndex:0,onKeyDown:o=>{o.key==="Escape"&&(o.stopPropagation(),this.cancelKeyEntry())}},Zt({class:"key-entry-head"},"Paste your OpenRouter API key"),Qee({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?Zt({class:"model-err"},`\u2717 ${this.err}`):null,Zt({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")),Zt({class:"key-entry-note"},"Written to .env in this project (gitignored). Used only via OpenRouter."))}};document.title="Claude Mirror";var qxe=new Xre;new t6t({root:new Wre({title:"Claude Mirror",pills:[qxe],overlays:[()=>qxe.watchdogView()],onPollTick:()=>{qxe.tickState()}}),id:"app"});
|
|
1383
1383
|
/*! Bundled license information:
|
|
@@ -1604,6 +1604,10 @@ html[data-theme="dark"] .masthead-logo.dark { display: block; }
|
|
|
1604
1604
|
/* The <summary> toggle defaults to a text cursor — give it the pointer every other expandable uses. */
|
|
1605
1605
|
.thinking summary { cursor: pointer; }
|
|
1606
1606
|
.thinking pre { white-space: pre-wrap; }
|
|
1607
|
+
/* Streaming (draft) thinking: capped + scrollable at the bulb-streaming card's height — ambient
|
|
1608
|
+
progress, not reading material — stuck to the live edge unless the user scrolls up
|
|
1609
|
+
(#draftThinkingPre). Durable rows stay uncapped: finished thinking IS reading material. */
|
|
1610
|
+
.draft .thinking pre { max-height: 220px; overflow-y: auto; }
|
|
1607
1611
|
|
|
1608
1612
|
/* Copy button: an .overlay-pill revealed on bubble-hover. */
|
|
1609
1613
|
.bubble:hover .copy { opacity: 1; }
|