@tstax/coding-tab 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/browser.js CHANGED
@@ -1,103 +1,110 @@
1
- "use strict";var CodingTab=(()=>{var O=Object.defineProperty;var ct=Object.getOwnPropertyDescriptor;var ut=Object.getOwnPropertyNames;var gt=Object.prototype.hasOwnProperty;var ht=(d,r)=>{for(var l in r)O(d,l,{get:r[l],enumerable:!0})},mt=(d,r,l,s)=>{if(r&&typeof r=="object"||typeof r=="function")for(let u of ut(r))!gt.call(d,u)&&u!==l&&O(d,u,{get:()=>r[u],enumerable:!(s=ct(r,u))||s.enumerable});return d};var pt=d=>mt(O({},"__esModule",{value:!0}),d);var wt={};ht(wt,{mountCodingTab:()=>F});function g(d){return d.replace(/[&<>"']/g,r=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[r])}function P(d){let r=[],l=/`([^`\n]+)`/g,s=0,u;for(;(u=l.exec(d))!==null;)r.push(J(d.slice(s,u.index))),r.push(`<code>${u[1]}</code>`),s=u.index+u[0].length;return r.push(J(d.slice(s))),r.join("")}function J(d){return d.replace(/\*\*([^*\n]+)\*\*/g,"<strong>$1</strong>").replace(/(^|[^*])\*([^*\n]+)\*(?!\*)/g,"$1<em>$2</em>").replace(/\[([^\]\n]+)\]\(([^)\s]+)\)/g,(r,l,s)=>`<a href="${/^(https?:|mailto:|\/|#)/i.test(s)?s:"#"}" target="_blank" rel="noreferrer noopener">${l}</a>`)}function G(d,r){if(d.length===0)return;let l=d.join(" ").trim();d.length=0,l&&r.push(`<p>${P(l)}</p>`)}function W(d,r){for(;d.length>0;){let l=d.pop();r.push(`<${l.type}>${l.items.join("")}</${l.type}>`)}}function z(d){let l=g(d).replace(/\r\n/g,`
1
+ "use strict";var CodingTab=(()=>{var N=Object.defineProperty;var vt=Object.getOwnPropertyDescriptor;var _t=Object.getOwnPropertyNames;var yt=Object.prototype.hasOwnProperty;var $t=(l,i)=>{for(var u in i)N(l,u,{get:i[u],enumerable:!0})},wt=(l,i,u,r)=>{if(i&&typeof i=="object"||typeof i=="function")for(let h of _t(i))!yt.call(l,h)&&h!==u&&N(l,h,{get:()=>i[h],enumerable:!(r=vt(i,h))||r.enumerable});return l};var kt=l=>wt(N({},"__esModule",{value:!0}),l);var Lt={};$t(Lt,{mountCodingTab:()=>Z});function g(l){return l.replace(/[&<>"']/g,i=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[i])}function q(l){let i=[],u=/`([^`\n]+)`/g,r=0,h;for(;(h=u.exec(l))!==null;)i.push(V(l.slice(r,h.index))),i.push(`<code>${h[1]}</code>`),r=h.index+h[0].length;return i.push(V(l.slice(r))),i.join("")}function V(l){return l.replace(/\*\*([^*\n]+)\*\*/g,"<strong>$1</strong>").replace(/(^|[^*])\*([^*\n]+)\*(?!\*)/g,"$1<em>$2</em>").replace(/\[([^\]\n]+)\]\(([^)\s]+)\)/g,(i,u,r)=>`<a href="${/^(https?:|mailto:|\/|#)/i.test(r)?r:"#"}" target="_blank" rel="noreferrer noopener">${u}</a>`)}function z(l,i){if(l.length===0)return;let u=l.join(" ").trim();l.length=0,u&&i.push(`<p>${q(u)}</p>`)}function K(l,i){for(;l.length>0;){let u=l.pop();i.push(`<${u.type}>${u.items.join("")}</${u.type}>`)}}function Y(l){let u=g(l).replace(/\r\n/g,`
2
2
  `).split(`
3
- `),s=[],u=[],m=[],a=!1,f="",p=[],w=()=>{G(u,s),W(m,s)};for(let S=0;S<l.length;S++){let b=l[S],M=b.match(/^\s*```(\w*)\s*$/);if(M){if(a){let v=f?` class="lang-${f}"`:"";s.push(`<pre><code${v}>${p.join(`
4
- `)}</code></pre>`),p.length=0,f="",a=!1}else w(),a=!0,f=M[1]??"";continue}if(a){p.push(b);continue}if(!b.trim()){w();continue}if(/^\s*(-{3,}|\*{3,}|_{3,})\s*$/.test(b)){w(),s.push("<hr />");continue}let C=b.match(/^(#{1,6})\s+(.*)$/);if(C){w();let v=Math.min(6,C[1].length);s.push(`<h${v}>${P(C[2].trim())}</h${v}>`);continue}let y=b.match(/^(\s*)[-*]\s+(.*)$/),c=b.match(/^(\s*)(\d+)\.\s+(.*)$/);if(y||c){G(u,s);let v=(y?y[1]:c[1]).length,L=y?"ul":"ol",I=y?y[2]:c[3];for(;m.length>0&&m[m.length-1].indent>v;){let E=m.pop(),$=m[m.length-1]?.items,A=`<${E.type}>${E.items.join("")}</${E.type}>`;$&&$.length>0?$[$.length-1]=$[$.length-1].replace(/<\/li>$/,`${A}</li>`):s.push(A)}let k=m[m.length-1];!k||k.indent<v||k.type!==L?m.push({type:L,indent:v,items:[`<li>${P(I)}</li>`]}):k.items.push(`<li>${P(I)}</li>`);continue}m.length>0&&W(m,s),u.push(b.trim())}return a?s.push(`<pre><code>${p.join(`
5
- `)}</code></pre>`):w(),s.join(`
6
- `)}var K='<svg width="18" height="18" viewBox="0 0 16 16" fill="currentColor"><path d="M8 0C3.58 0 0 3.58 0 8a8 8 0 005.47 7.59c.4.07.55-.17.55-.38v-1.34c-2.23.48-2.7-1.07-2.7-1.07-.36-.92-.89-1.16-.89-1.16-.73-.5.05-.49.05-.49.81.06 1.23.83 1.23.83.72 1.23 1.88.87 2.34.66.07-.52.28-.87.5-1.07-1.78-.2-3.65-.89-3.65-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.13 0 0 .67-.21 2.2.82a7.65 7.65 0 014 0c1.53-1.04 2.2-.82 2.2-.82.44 1.11.16 1.93.08 2.13.51.56.82 1.28.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.74.54 1.49v2.21c0 .21.15.46.55.38A8 8 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>',V='<svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><path d="M8 3v10M3 8h10"/></svg>',ft='<svg width="13" height="13" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"><path d="M3 4h10M6 4V2.5a.5.5 0 01.5-.5h3a.5.5 0 01.5.5V4M5 4l.7 9.1a.9.9 0 00.9.9h2.8a.9.9 0 00.9-.9L11 4"/></svg>',bt='<svg width="13" height="13" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="M11 2.5l2.5 2.5L6 12.5 3 13l.5-3z"/></svg>',vt='<svg width="18" height="18" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><path d="M2.5 4h11M2.5 8h11M2.5 12h11"/></svg>',_t='<svg class="ct-chevron" width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3 2l4 3-4 3"/></svg>';function T(d){return g(d)}function yt(d){let r=d.match(/github\.com[/:]([^/]+)\/([^/]+?)(?:\.git)?\/?$/);return r?`${r[1]}/${r[2]}`:d}function _(){return typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2)}function $t(d){let r=Date.now()-d;return r<6e4?"just now":r<36e5?`${Math.round(r/6e4)}m`:r<864e5?`${Math.round(r/36e5)}h`:r<6048e5?`${Math.round(r/864e5)}d`:new Date(d).toLocaleDateString()}function F(d,r){let l=r.apiBase.replace(/\/$/,""),s=document.createElement("div");s.className="coding-tab",d.innerHTML="",d.appendChild(s);let u=!1;function m(){if(u||(u=!0,document.querySelector('link[data-coding-tab="style"]')))return;let t=document.createElement("link");t.rel="stylesheet",t.href=`${l}/style.css`,t.dataset.codingTab="style",document.head.appendChild(t)}m();let a={me:null,models:[],mode:r.defaultMode??"plan",model:r.defaultModel??"sonnet",repoUrl:r.defaultRepo??"",repoLocked:!1,chats:[],activeChatId:null,sidebarOpen:window.innerWidth>=720,expandedTools:new Set,mergeStates:new Map};function f(){return a.chats.find(t=>t.meta.id===a.activeChatId)??null}async function p(t,n){let e=await fetch(`${l}${t}`,{credentials:"include",headers:{"Content-Type":"application/json",...n?.headers??{}},...n});if(!e.ok)throw Object.assign(new Error(`${e.status} ${e.statusText}`),{status:e.status});return await e.json()}async function w(){try{let{chats:t}=await p("/chats"),n=new Map(a.chats.map(e=>[e.meta.id,e]));a.chats=t.map(e=>{let o=n.get(e.id);return o?{...o,meta:e}:{meta:e,loaded:!1,isStreaming:!1,activeRunId:null,abort:null}})}catch(t){console.error("[coding-tab] /chats list failed",t),a.chats=[]}}async function S(t){let n=a.chats.find(e=>e.meta.id===t);if(!n)return null;if(n.loaded)return n;try{let{chat:e}=await p(`/chats/${t}`);return n.turns=e.turns,n.loaded=!0,n.meta={id:e.id,title:e.title,mode:e.mode,model:e.model,createdAt:e.createdAt,updatedAt:e.updatedAt},a.mode=e.mode,a.model=e.model,n}catch(e){return console.error(`[coding-tab] /chats/${t} load failed`,e),null}}async function b(){try{let{chat:t}=await p("/chats",{method:"POST",body:JSON.stringify({mode:a.mode,model:a.model,repoUrl:a.repoLocked?void 0:a.repoUrl||void 0})}),n={meta:{id:t.id,title:t.title,mode:t.mode,model:t.model,createdAt:t.createdAt,updatedAt:t.updatedAt},turns:[],loaded:!0,isStreaming:!1,activeRunId:null,abort:null};return a.chats.unshift(n),a.activeChatId=n.meta.id,n}catch(t){return console.error("[coding-tab] create chat failed",t),null}}async function M(t){a.activeChatId=t,window.innerWidth<720&&(a.sidebarOpen=!1),c(),await S(t),c()}async function C(t){let n=a.chats.find(e=>e.meta.id===t);if(n&&confirm(`Delete chat "${n.meta.title}"? This cannot be undone.`)){n.abort?.abort();try{await p(`/chats/${t}`,{method:"DELETE"})}catch(e){console.error(`[coding-tab] delete chat ${t} failed`,e);return}a.chats=a.chats.filter(e=>e.meta.id!==t),a.activeChatId===t&&(a.activeChatId=a.chats[0]?.meta.id??null),c()}}async function y(t){let n=a.chats.find(i=>i.meta.id===t);if(!n)return;let e=prompt("Rename chat",n.meta.title);if(e===null)return;let o=e.trim();if(!(!o||o===n.meta.title))try{let{chat:i}=await p(`/chats/${t}`,{method:"PATCH",body:JSON.stringify({title:o})});n.meta={...n.meta,title:i.title,updatedAt:i.updatedAt},c()}catch(i){console.error(`[coding-tab] rename chat ${t} failed`,i)}}function c(){if(!a.me){s.innerHTML=`
3
+ `),r=[],h=[],p=[],a=!1,f="",m=[],k=()=>{z(h,r),K(p,r)};for(let C=0;C<u.length;C++){let b=u[C],P=b.match(/^\s*```(\w*)\s*$/);if(P){if(a){let v=f?` class="lang-${f}"`:"";r.push(`<pre><code${v}>${m.join(`
4
+ `)}</code></pre>`),m.length=0,f="",a=!1}else k(),a=!0,f=P[1]??"";continue}if(a){m.push(b);continue}if(!b.trim()){k();continue}if(/^\s*(-{3,}|\*{3,}|_{3,})\s*$/.test(b)){k(),r.push("<hr />");continue}let M=b.match(/^(#{1,6})\s+(.*)$/);if(M){k();let v=Math.min(6,M[1].length);r.push(`<h${v}>${q(M[2].trim())}</h${v}>`);continue}let $=b.match(/^(\s*)[-*]\s+(.*)$/),c=b.match(/^(\s*)(\d+)\.\s+(.*)$/);if($||c){z(h,r);let v=($?$[1]:c[1]).length,R=$?"ul":"ol",A=$?$[2]:c[3];for(;p.length>0&&p[p.length-1].indent>v;){let I=p.pop(),w=p[p.length-1]?.items,H=`<${I.type}>${I.items.join("")}</${I.type}>`;w&&w.length>0?w[w.length-1]=w[w.length-1].replace(/<\/li>$/,`${H}</li>`):r.push(H)}let E=p[p.length-1];!E||E.indent<v||E.type!==R?p.push({type:R,indent:v,items:[`<li>${q(A)}</li>`]}):E.items.push(`<li>${q(A)}</li>`);continue}p.length>0&&K(p,r),h.push(b.trim())}return a?r.push(`<pre><code>${m.join(`
5
+ `)}</code></pre>`):k(),r.join(`
6
+ `)}var Q='<svg width="18" height="18" viewBox="0 0 16 16" fill="currentColor"><path d="M8 0C3.58 0 0 3.58 0 8a8 8 0 005.47 7.59c.4.07.55-.17.55-.38v-1.34c-2.23.48-2.7-1.07-2.7-1.07-.36-.92-.89-1.16-.89-1.16-.73-.5.05-.49.05-.49.81.06 1.23.83 1.23.83.72 1.23 1.88.87 2.34.66.07-.52.28-.87.5-1.07-1.78-.2-3.65-.89-3.65-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.13 0 0 .67-.21 2.2.82a7.65 7.65 0 014 0c1.53-1.04 2.2-.82 2.2-.82.44 1.11.16 1.93.08 2.13.51.56.82 1.28.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.74.54 1.49v2.21c0 .21.15.46.55.38A8 8 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>',X='<svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><path d="M8 3v10M3 8h10"/></svg>',St='<svg width="13" height="13" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"><path d="M3 4h10M6 4V2.5a.5.5 0 01.5-.5h3a.5.5 0 01.5.5V4M5 4l.7 9.1a.9.9 0 00.9.9h2.8a.9.9 0 00.9-.9L11 4"/></svg>',Tt='<svg width="13" height="13" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="M11 2.5l2.5 2.5L6 12.5 3 13l.5-3z"/></svg>',Ct='<svg width="18" height="18" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><path d="M2.5 4h11M2.5 8h11M2.5 12h11"/></svg>',Et='<svg class="ct-chevron" width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3 2l4 3-4 3"/></svg>';function y(l){return g(l)}function U(l){let i=l.match(/github\.com[/:]([^/]+)\/([^/]+?)(?:\.git)?\/?$/);return i?`${i[1]}/${i[2]}`:l}function xt(l){let i=l.match(/github\.com[/:]([^/]+)\/([^/]+?)(?:\.git)?\/?$/);return i?`https://github.com/${i[1]}/${i[2]}`:l.replace(/\.git\/?$/,"")}function Mt(l){return`${xt(l)}/pulls`}function _(){return typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2)}function It(l){let i=Date.now()-l;return i<6e4?"just now":i<36e5?`${Math.round(i/6e4)}m`:i<864e5?`${Math.round(i/36e5)}h`:i<6048e5?`${Math.round(i/864e5)}d`:new Date(l).toLocaleDateString()}function Z(l,i){let u=i.apiBase.replace(/\/$/,""),r=document.createElement("div");r.className="coding-tab",l.innerHTML="",l.appendChild(r);let h=!1;function p(){if(h||(h=!0,document.querySelector('link[data-coding-tab="style"]')))return;let t=document.createElement("link");t.rel="stylesheet",t.href=`${u}/style.css`,t.dataset.codingTab="style",document.head.appendChild(t)}p();let a={me:null,models:[],mode:i.defaultMode??"plan",model:i.defaultModel??"sonnet",repoUrl:i.defaultRepo??"",repoLocked:!1,chats:[],activeChatId:null,sidebarOpen:window.innerWidth>=720,expandedTools:new Set,mergeStates:new Map};function f(){return a.chats.find(t=>t.meta.id===a.activeChatId)??null}async function m(t,e){let n=await fetch(`${u}${t}`,{credentials:"include",headers:{"Content-Type":"application/json",...e?.headers??{}},...e});if(!n.ok)throw Object.assign(new Error(`${n.status} ${n.statusText}`),{status:n.status});return await n.json()}async function k(){try{let{chats:t}=await m("/chats"),e=new Map(a.chats.map(n=>[n.meta.id,n]));a.chats=t.map(n=>{let s=e.get(n.id);return s?{...s,meta:n}:{meta:n,loaded:!1,isStreaming:!1,activeRunId:null,abort:null,isReconnecting:!1,pollTurnId:null,pollPromise:null}})}catch(t){console.error("[coding-tab] /chats list failed",t),a.chats=[]}}async function C(t){let e=a.chats.find(n=>n.meta.id===t);if(!e)return null;if(e.loaded)return e;try{let{chat:n}=await m(`/chats/${t}`);return e.turns=n.turns,e.loaded=!0,e.meta={id:n.id,title:n.title,mode:n.mode,model:n.model,createdAt:n.createdAt,updatedAt:n.updatedAt},a.mode=n.mode,a.model=n.model,e}catch(n){return console.error(`[coding-tab] /chats/${t} load failed`,n),null}}async function b(){try{let{chat:t}=await m("/chats",{method:"POST",body:JSON.stringify({mode:a.mode,model:a.model,repoUrl:a.repoLocked?void 0:a.repoUrl||void 0})}),e={meta:{id:t.id,title:t.title,mode:t.mode,model:t.model,createdAt:t.createdAt,updatedAt:t.updatedAt},turns:[],loaded:!0,isStreaming:!1,activeRunId:null,abort:null,isReconnecting:!1,pollTurnId:null,pollPromise:null};return a.chats.unshift(e),a.activeChatId=e.meta.id,e}catch(t){return console.error("[coding-tab] create chat failed",t),null}}async function P(t){a.activeChatId=t,window.innerWidth<720&&(a.sidebarOpen=!1),c(),await C(t),c()}async function M(t){let e=a.chats.find(n=>n.meta.id===t);if(e&&confirm(`Delete chat "${e.meta.title}"? This cannot be undone.`)){e.abort?.abort();try{await m(`/chats/${t}`,{method:"DELETE"})}catch(n){console.error(`[coding-tab] delete chat ${t} failed`,n);return}a.chats=a.chats.filter(n=>n.meta.id!==t),a.activeChatId===t&&(a.activeChatId=a.chats[0]?.meta.id??null),c()}}async function $(t){let e=a.chats.find(o=>o.meta.id===t);if(!e)return;let n=prompt("Rename chat",e.meta.title);if(n===null)return;let s=n.trim();if(!(!s||s===e.meta.title))try{let{chat:o}=await m(`/chats/${t}`,{method:"PATCH",body:JSON.stringify({title:s})});e.meta={...e.meta,title:o.title,updatedAt:o.updatedAt},c()}catch(o){console.error(`[coding-tab] rename chat ${t} failed`,o)}}function c(){if(!a.me){r.innerHTML=`
7
7
  <div class="coding-tab__signin">
8
8
  <h2>Coding Tab</h2>
9
9
  <p>Sign in with GitHub to start a coding session against your repo. Your token is used to clone, push, and open pull requests on your behalf.</p>
10
- <a href="${l}/auth/login">${K}<span>Sign in with GitHub</span></a>
10
+ <a href="${u}/auth/login">${Q}<span>Sign in with GitHub</span></a>
11
11
  </div>
12
12
  `;return}let t=`
13
13
  <div class="coding-tab__header">
14
- <button class="coding-tab__hamburger" data-role="toggle-sidebar" aria-label="Toggle chat list">${vt}</button>
14
+ <button class="coding-tab__hamburger" data-role="toggle-sidebar" aria-label="Toggle chat list">${Ct}</button>
15
15
  <select data-role="model" title="Model">
16
- ${a.models.map(h=>`<option value="${h.choice}" ${a.model===h.choice?"selected":""}>${g(h.displayName)}</option>`).join("")}
16
+ ${a.models.map(d=>`<option value="${d.choice}" ${a.model===d.choice?"selected":""}>${g(d.displayName)}</option>`).join("")}
17
17
  </select>
18
18
  <div class="coding-tab__mode">
19
19
  <button data-mode="plan" class="${a.mode==="plan"?"is-active":""}">Plan</button>
20
20
  <button data-mode="agent" class="${a.mode==="agent"?"is-active":""}">Agent</button>
21
21
  </div>
22
- ${a.repoLocked&&a.repoUrl?`<a class="coding-tab__repo-locked" href="${T(a.repoUrl)}" target="_blank" rel="noreferrer" title="Locked to this app's repo (set by the server)">${K}<span>${g(yt(a.repoUrl))}</span></a>`:`<input data-role="repo" placeholder="https://github.com/org/repo" value="${T(a.repoUrl)}" style="flex:1;min-width:200px" />`}
22
+ ${a.repoLocked&&a.repoUrl?`<a class="coding-tab__repo-locked" href="${y(Mt(a.repoUrl))}" target="_blank" rel="noreferrer" title="Open ${y(U(a.repoUrl))} pull requests on GitHub">${Q}<span>${g(U(a.repoUrl))}</span></a>`:`<input data-role="repo" placeholder="https://github.com/org/repo" value="${y(a.repoUrl)}" style="flex:1;min-width:200px" />`}
23
23
  <div class="coding-tab__user">
24
24
  ${a.me.avatarUrl?`<img src="${a.me.avatarUrl}" alt="" />`:""}
25
25
  <span class="coding-tab__user-name">@${g(a.me.githubLogin)}</span>
26
26
  <button data-role="logout">Sign out</button>
27
27
  </div>
28
28
  </div>
29
- `,n=`
29
+ `,e=`
30
30
  <aside class="coding-tab__sidebar ${a.sidebarOpen?"is-open":""}">
31
- <button class="coding-tab__btn primary coding-tab__new-chat" data-role="new-chat">${V}<span>New chat</span></button>
31
+ <button class="coding-tab__btn primary coding-tab__new-chat" data-role="new-chat">${X}<span>New chat</span></button>
32
32
  <div class="coding-tab__chat-list">
33
- ${a.chats.length===0?'<div class="coding-tab__chat-empty">No chats yet \u2014 start one with the button above.</div>':a.chats.map(h=>v(h)).join("")}
33
+ ${a.chats.length===0?'<div class="coding-tab__chat-empty">No chats yet \u2014 start one with the button above.</div>':a.chats.map(d=>v(d)).join("")}
34
34
  </div>
35
35
  </aside>
36
- `,e=f(),o=`
36
+ `,n=f(),s=`
37
37
  <main class="coding-tab__pane">
38
- ${e?I(e):L()}
38
+ ${n?A(n):R()}
39
39
  </main>
40
- `;s.innerHTML=`
40
+ `;r.innerHTML=`
41
41
  ${t}
42
42
  <div class="coding-tab__body">
43
- ${n}
44
- ${o}
43
+ ${e}
44
+ ${s}
45
45
  </div>
46
- `;let i=s.querySelector("[data-role=thread]");i&&(i.scrollTop=i.scrollHeight),tt()}function v(t){let n=t.meta.id===a.activeChatId?" is-active":"",e=t.isStreaming?'<span class="coding-tab__chat-row-dot" title="Streaming"></span>':"";return`
47
- <div class="coding-tab__chat-row${n}" data-chat-id="${t.meta.id}">
46
+ `;let o=r.querySelector("[data-role=thread]");o&&(o.scrollTop=o.scrollHeight),ot()}function v(t){let e=t.meta.id===a.activeChatId?" is-active":"",n=t.isStreaming?`<span class="coding-tab__chat-row-dot" title="${t.isReconnecting?"Reconnecting":"Streaming"}"></span>`:"";return`
47
+ <div class="coding-tab__chat-row${e}" data-chat-id="${t.meta.id}">
48
48
  <button class="coding-tab__chat-row-main" data-role="select-chat" data-chat-id="${t.meta.id}">
49
- ${e}
49
+ ${n}
50
50
  <span class="coding-tab__chat-row-title">${g(t.meta.title)}</span>
51
- <span class="coding-tab__chat-row-meta">${t.meta.mode==="plan"?"Plan":"Agent"} \xB7 ${$t(t.meta.updatedAt)}</span>
51
+ <span class="coding-tab__chat-row-meta">${t.meta.mode==="plan"?"Plan":"Agent"} \xB7 ${It(t.meta.updatedAt)}</span>
52
52
  </button>
53
53
  <div class="coding-tab__chat-row-actions">
54
- <button data-role="rename-chat" data-chat-id="${t.meta.id}" title="Rename">${bt}</button>
55
- <button data-role="delete-chat" data-chat-id="${t.meta.id}" title="Delete">${ft}</button>
54
+ <button data-role="rename-chat" data-chat-id="${t.meta.id}" title="Rename">${Tt}</button>
55
+ <button data-role="delete-chat" data-chat-id="${t.meta.id}" title="Delete">${St}</button>
56
56
  </div>
57
57
  </div>
58
- `}function L(){return`
58
+ `}function R(){return`
59
59
  <div class="coding-tab__pane-empty">
60
60
  <h3>Start a new chat</h3>
61
61
  <p>Pick a mode (Plan or Agent), choose a model, and click <strong>New chat</strong> to begin. Each chat keeps its own context.</p>
62
- <button class="coding-tab__btn primary" data-role="new-chat">${V}<span>New chat</span></button>
62
+ <button class="coding-tab__btn primary" data-role="new-chat">${X}<span>New chat</span></button>
63
63
  </div>
64
- `}function I(t){let n=t.turns??[],e=t.loaded?n.length===0?'<div class="coding-tab__notice info">Type a message below to kick off this chat.</div>':n.map(i=>k(i)).join(""):'<div class="coding-tab__notice info">Loading\u2026</div>',o=n.length===0?'Ask anything (e.g. "add dark mode that follows the OS setting")':a.mode==="plan"?"Refine the plan, or ask another planning question":"Send another instruction";return`
65
- <div class="coding-tab__thread" data-role="thread">${e}</div>
64
+ `}function A(t){let e=t.turns??[],n=t.loaded?e.length===0?'<div class="coding-tab__notice info">Type a message below to kick off this chat.</div>':e.map(d=>E(d)).join(""):'<div class="coding-tab__notice info">Loading\u2026</div>',s=e.length===0?'Ask anything (e.g. "add dark mode that follows the OS setting")':a.mode==="plan"?"Refine the plan, or ask another planning question":"Send another instruction",o=t.isReconnecting?"Reconnecting\u2026":t.isStreaming?"Working\u2026":"Send";return`
65
+ <div class="coding-tab__thread" data-role="thread">${n}</div>
66
66
  <div class="coding-tab__composer">
67
- <textarea data-role="prompt" placeholder="${T(o)}" rows="2"></textarea>
68
- <button class="coding-tab__btn primary" data-role="send" ${t.isStreaming?"disabled":""}>${t.isStreaming?"Working\u2026":"Send"}</button>
67
+ <textarea data-role="prompt" placeholder="${y(s)}" rows="2"></textarea>
68
+ <button class="coding-tab__btn primary" data-role="send" ${t.isStreaming?"disabled":""}>${g(o)}</button>
69
69
  ${t.isStreaming?'<button class="coding-tab__btn danger" data-role="cancel">Stop</button>':""}
70
70
  </div>
71
- `}function k(t){if(t.role==="user"){let h=t.prompt??Z(t);return`<div class="coding-tab__msg user">
71
+ `}function E(t){if(t.role==="user"){let x=t.prompt??st(t);return`<div class="coding-tab__msg user">
72
72
  <div class="coding-tab__msg-role">You \xB7 ${t.isPlan?"Plan":"Agent"}</div>
73
- <div class="coding-tab__msg-body">${g(h)}</div>
74
- </div>`}let n=t.events.length===0&&t.status==="running"?'<div class="coding-tab__msg-pending">Working\u2026</div>':t.events.map(h=>E(h,t.isPlan)).join(""),e=t.status&&t.status!=="finished"?`<div class="coding-tab__status">${g(t.status)}</div>`:"",o=t.showExecute&&!f()?.isStreaming?`<div class="coding-tab__plan-actions">
73
+ <div class="coding-tab__msg-body">${g(x)}</div>
74
+ </div>`}let s=f()?.turns?.at(-1)?.id===t.id&&f()?.isReconnecting===!0?`<div class="coding-tab__msg-pending coding-tab__msg-reconnecting">Reconnecting\u2026 (the page lost the live stream \u2014 the agent is still working on Cursor's side, fetching latest progress)</div>`:"",o=t.events.length===0&&t.status==="running"?'<div class="coding-tab__msg-pending">Working\u2026</div>':t.events.map(x=>I(x,t.isPlan)).join(""),d=t.status&&t.status!=="finished"?`<div class="coding-tab__status">${g(t.status)}</div>`:"",S=t.showExecute&&!f()?.isStreaming?`<div class="coding-tab__plan-actions">
75
75
  <button class="coding-tab__btn primary" data-role="execute" data-turn="${t.id}">Execute plan</button>
76
- </div>`:"",i=t.pr?X(t.pr):"";return`<div class="coding-tab__msg assistant">
77
- <div class="coding-tab__msg-role">Coding Tab \xB7 ${t.isPlan?"Plan":"Agent"} ${e}</div>
78
- <div class="coding-tab__msg-body">${n}${o}${i}</div>
79
- </div>`}function E(t,n){if(t.kind==="text"){let e=t.text.trim();return e?`<div class="coding-tab__md">${n?z(e):$(e)}</div>`:""}return A(t)}function $(t){return g(t).split(/\n\s*\n/).map(n=>n.replace(/`([^`\n]+)`/g,"<code>$1</code>").replace(/\*\*([^*\n]+)\*\*/g,"<strong>$1</strong>").replace(/\n/g,"<br />")).map(n=>`<p>${n}</p>`).join("")}function A(t){let n=Y(t.name,t.args),e=a.expandedTools.has(t.id),o=e?Q(t):"";return`
76
+ </div>`:"",T=t.pr?at(t.pr):t.branch?nt(t.branch):"";return`<div class="coding-tab__msg assistant">
77
+ <div class="coding-tab__msg-role">Coding Tab \xB7 ${t.isPlan?"Plan":"Agent"} ${d}</div>
78
+ <div class="coding-tab__msg-body">${o}${s}${S}${T}</div>
79
+ </div>`}function I(t,e){if(t.kind==="text"){let n=t.text.trim();return n?`<div class="coding-tab__md">${e?Y(n):w(n)}</div>`:""}return H(t)}function w(t){return g(t).split(/\n\s*\n/).map(e=>e.replace(/`([^`\n]+)`/g,"<code>$1</code>").replace(/\*\*([^*\n]+)\*\*/g,"<strong>$1</strong>").replace(/\[([^\]\n]+)\]\(([^)\s]+)\)/g,(n,s,o)=>`<a href="${/^(https?:|mailto:|\/|#)/i.test(o)?o:"#"}" target="_blank" rel="noreferrer noopener">${s}</a>`).replace(/(^|[\s(])(https?:\/\/[^\s<>"')\]]+)/g,(n,s,o)=>`${s}<a href="${o}" target="_blank" rel="noreferrer noopener">${o}</a>`).replace(/\n/g,"<br />")).map(e=>`<p>${e}</p>`).join("")}function H(t){let e=tt(t.name,t.args),n=a.expandedTools.has(t.id),s=n?et(t):"";return`
80
80
  <div class="coding-tab__tool" data-status="${t.status}" data-tool-id="${t.id}">
81
- <button class="coding-tab__tool-header" data-role="toggle-tool" data-tool-id="${t.id}" aria-expanded="${e}">
81
+ <button class="coding-tab__tool-header" data-role="toggle-tool" data-tool-id="${t.id}" aria-expanded="${n}">
82
82
  <span class="coding-tab__tool-dot"></span>
83
- ${_t}
83
+ ${Et}
84
84
  <span class="coding-tab__tool-name">${g(t.name)}</span>
85
- ${n?`<span class="coding-tab__tool-summary">${g(n)}</span>`:""}
85
+ ${e?`<span class="coding-tab__tool-summary">${g(e)}</span>`:""}
86
86
  </button>
87
- ${o}
87
+ ${s}
88
+ </div>
89
+ `}function tt(t,e){if(!e||typeof e!="object")return"";let n=e,s=t.toLowerCase();if(s.includes("grep")){let o=typeof n.pattern=="string"?n.pattern:typeof n.query=="string"?n.query:"";return o?`"${o}"`:""}if(s.includes("read")&&typeof n.path=="string"){let o=typeof n.offset=="number"||typeof n.limit=="number"?`:${n.offset??""}-${Number(n.offset??0)+Number(n.limit??0)||""}`:"";return`${n.path}${o}`}return(s.includes("glob")||s.includes("file_search"))&&typeof n.glob_pattern=="string"?n.glob_pattern:s==="shell"&&typeof n.command=="string"?n.command.slice(0,80):s==="task"&&typeof n.description=="string"?n.description:s.includes("write")&&typeof n.path=="string"||s.includes("edit")&&typeof n.path=="string"||s.includes("delete")&&typeof n.path=="string"?n.path:""}function et(t){let e=t.args!==void 0&&t.args!==null?`<div class="coding-tab__tool-section"><div class="coding-tab__tool-label">Args</div><pre>${g(j(t.args))}</pre></div>`:"",n=t.result!==void 0&&t.result!==null?`<div class="coding-tab__tool-section"><div class="coding-tab__tool-label">Result</div><pre>${g(j(t.result))}</pre></div>`:t.status==="running"?'<div class="coding-tab__tool-section"><div class="coding-tab__tool-label">Result</div><pre class="coding-tab__tool-pending">\u2026running</pre></div>':"";return`<div class="coding-tab__tool-detail">${e}${n}</div>`}function j(t){if(typeof t=="string")return t;try{return JSON.stringify(t,null,2)}catch{return String(t)}}function nt(t){let e=U(t.repoUrl);return`<div class="coding-tab__pr coding-tab__pr--branch">
90
+ <div class="coding-tab__pr-title">Branch pushed: <code>${g(t.branch)}</code></div>
91
+ <div class="coding-tab__pr-status">No PR was opened automatically. Click below to create one yourself on GitHub.</div>
92
+ <div class="coding-tab__pr-actions">
93
+ <a class="coding-tab__btn primary" href="${y(t.compareUrl)}" target="_blank" rel="noreferrer">Create PR on GitHub</a>
94
+ <a class="coding-tab__btn" href="${y(t.repoUrl)}/pulls" target="_blank" rel="noreferrer">View ${g(e)} PRs</a>
88
95
  </div>
89
- `}function Y(t,n){if(!n||typeof n!="object")return"";let e=n,o=t.toLowerCase();if(o.includes("grep")){let i=typeof e.pattern=="string"?e.pattern:typeof e.query=="string"?e.query:"";return i?`"${i}"`:""}if(o.includes("read")&&typeof e.path=="string"){let i=typeof e.offset=="number"||typeof e.limit=="number"?`:${e.offset??""}-${Number(e.offset??0)+Number(e.limit??0)||""}`:"";return`${e.path}${i}`}return(o.includes("glob")||o.includes("file_search"))&&typeof e.glob_pattern=="string"?e.glob_pattern:o==="shell"&&typeof e.command=="string"?e.command.slice(0,80):o==="task"&&typeof e.description=="string"?e.description:o.includes("write")&&typeof e.path=="string"||o.includes("edit")&&typeof e.path=="string"||o.includes("delete")&&typeof e.path=="string"?e.path:""}function Q(t){let n=t.args!==void 0&&t.args!==null?`<div class="coding-tab__tool-section"><div class="coding-tab__tool-label">Args</div><pre>${g(H(t.args))}</pre></div>`:"",e=t.result!==void 0&&t.result!==null?`<div class="coding-tab__tool-section"><div class="coding-tab__tool-label">Result</div><pre>${g(H(t.result))}</pre></div>`:t.status==="running"?'<div class="coding-tab__tool-section"><div class="coding-tab__tool-label">Result</div><pre class="coding-tab__tool-pending">\u2026running</pre></div>':"";return`<div class="coding-tab__tool-detail">${n}${e}</div>`}function H(t){if(typeof t=="string")return t;try{return JSON.stringify(t,null,2)}catch{return String(t)}}function X(t){let n=a.mergeStates.get(t.url)??{state:"idle"},e,o="";switch(n.state){case"loading":e='<button class="coding-tab__btn primary" data-state="loading" disabled>Merging\u2026</button>',o='<div class="coding-tab__pr-status">Merging this PR and triggering Railway redeploy\u2026</div>';break;case"success":e='<button class="coding-tab__btn success" disabled>Merged \u2713</button>',o=`<div class="coding-tab__pr-status is-success">Merged commit ${g(n.sha.slice(0,7))}. Railway should redeploy on the next push hook.</div>`;break;case"error":e=`<button class="coding-tab__btn primary" data-role="merge" data-pr="${T(t.url)}">Try merge again</button>`,o=`<div class="coding-tab__pr-status is-error">Merge failed: ${g(n.message)}</div>`;break;default:e=`<button class="coding-tab__btn primary" data-role="merge" data-pr="${T(t.url)}">Merge & Redeploy</button>`}return`<div class="coding-tab__pr">
96
+ </div>`}function at(t){let e=a.mergeStates.get(t.url)??{state:"idle"},n,s="";switch(e.state){case"loading":n='<button class="coding-tab__btn primary" data-state="loading" disabled>Merging\u2026</button>',s='<div class="coding-tab__pr-status">Merging this PR and triggering Railway redeploy\u2026</div>';break;case"success":n='<button class="coding-tab__btn success" disabled>Merged \u2713</button>',s=`<div class="coding-tab__pr-status is-success">Merged commit ${g(e.sha.slice(0,7))}. Railway should redeploy on the next push hook.</div>`;break;case"error":n=`<button class="coding-tab__btn primary" data-role="merge" data-pr="${y(t.url)}">Try merge again</button>`,s=`<div class="coding-tab__pr-status is-error">Merge failed: ${g(e.message)}</div>`;break;default:n=`<button class="coding-tab__btn primary" data-role="merge" data-pr="${y(t.url)}">Merge & Redeploy</button>`}return`<div class="coding-tab__pr">
90
97
  <div class="coding-tab__pr-title">PR #${t.number} opened in ${g(t.owner)}/${g(t.repo)}</div>
91
98
  ${t.title?`<div>${g(t.title)}</div>`:""}
92
99
  <div class="coding-tab__pr-actions">
93
- <a class="coding-tab__btn" href="${T(t.url)}" target="_blank" rel="noreferrer">Open in GitHub</a>
94
- ${e}
100
+ <a class="coding-tab__btn" href="${y(t.url)}" target="_blank" rel="noreferrer">Open in GitHub</a>
101
+ ${n}
95
102
  </div>
96
- ${o}
97
- </div>`}function Z(t){return t.events.filter(n=>n.kind==="text").map(n=>n.text).join(`
103
+ ${s}
104
+ </div>`}function st(t){return t.events.filter(e=>e.kind==="text").map(e=>e.text).join(`
98
105
 
99
- `)}function tt(){s.querySelector('[data-role="model"]')?.addEventListener("change",t=>{a.model=t.target.value}),s.querySelectorAll("[data-mode]").forEach(t=>{t.addEventListener("click",()=>{a.mode=t.dataset.mode,c()})}),s.querySelector('[data-role="repo"]')?.addEventListener("change",t=>{a.repoUrl=t.target.value.trim()}),s.querySelector('[data-role="logout"]')?.addEventListener("click",async()=>{await fetch(`${l}/auth/logout`,{method:"POST",credentials:"include"}).catch(()=>{});for(let t of a.chats)t.abort?.abort();a.me=null,a.chats=[],a.activeChatId=null,c()}),s.querySelector('[data-role="toggle-sidebar"]')?.addEventListener("click",()=>{a.sidebarOpen=!a.sidebarOpen,c()}),s.querySelectorAll('[data-role="new-chat"]').forEach(t=>t.addEventListener("click",async()=>{await b()&&window.innerWidth<720&&(a.sidebarOpen=!1),c()})),s.querySelectorAll('[data-role="select-chat"]').forEach(t=>t.addEventListener("click",()=>{let n=t.dataset.chatId;M(n)})),s.querySelectorAll('[data-role="rename-chat"]').forEach(t=>t.addEventListener("click",n=>{n.stopPropagation(),y(t.dataset.chatId)})),s.querySelectorAll('[data-role="delete-chat"]').forEach(t=>t.addEventListener("click",n=>{n.stopPropagation(),C(t.dataset.chatId)})),s.querySelector('[data-role="send"]')?.addEventListener("click",()=>q()),s.querySelector('[data-role="prompt"]')?.addEventListener("keydown",t=>{let n=t;n.key==="Enter"&&(n.metaKey||n.ctrlKey)&&(n.preventDefault(),q())}),s.querySelector('[data-role="cancel"]')?.addEventListener("click",()=>nt()),s.querySelectorAll('[data-role="execute"]').forEach(t=>t.addEventListener("click",()=>et())),s.querySelectorAll('[data-role="merge"]').forEach(t=>{t.addEventListener("click",()=>at(t.dataset.pr))}),s.querySelectorAll('[data-role="toggle-tool"]').forEach(t=>t.addEventListener("click",()=>{let n=t.dataset.toolId;a.expandedTools.has(n)?a.expandedTools.delete(n):a.expandedTools.add(n),c()}))}async function q(){let t=f();if(!t&&(t=await b(),!t)||t.isStreaming)return;let n=s.querySelector('[data-role="prompt"]'),e=n?.value.trim()??"";if(!e)return;n&&(n.value=""),t.turns=t.turns??[];let o={id:_(),chatId:t.meta.id,seq:t.turns.length,role:"user",isPlan:a.mode==="plan",status:"finished",events:[{kind:"text",id:_(),text:e}],prompt:e,createdAt:Date.now()};t.turns.push(o);let i={id:_(),chatId:t.meta.id,seq:t.turns.length,role:"assistant",isPlan:a.mode==="plan",status:"running",events:[],createdAt:Date.now()};t.turns.push(i),t.isStreaming=!0,t.meta.title==="New chat"&&(t.meta={...t.meta,title:e.length>60?`${e.slice(0,57)}\u2026`:e}),t.meta={...t.meta,mode:a.mode,model:a.model,updatedAt:Date.now()},c();try{await j("/agent/send",{chatId:t.meta.id,prompt:e,mode:a.mode},t,i)}catch(h){h.name!=="AbortError"&&N(i,h),i.status="error"}finally{t.isStreaming=!1,t.activeRunId=null,t.abort=null,c()}}async function et(){let t=f();if(!t||t.isStreaming)return;t.turns=t.turns??[];let n={id:_(),chatId:t.meta.id,seq:t.turns.length,role:"assistant",isPlan:!1,status:"running",events:[],createdAt:Date.now()};t.turns.push(n),t.isStreaming=!0,c();try{await j("/agent/execute",{chatId:t.meta.id},t,n)}catch(e){e.name!=="AbortError"&&N(n,e),n.status="error"}finally{t.isStreaming=!1,t.activeRunId=null,t.abort=null,c()}}async function nt(){let t=f();if(t){if(t.activeRunId)try{await p("/agent/cancel",{method:"POST",body:JSON.stringify({chatId:t.meta.id,runId:t.activeRunId})})}catch(n){console.error("[coding-tab] cancel failed",n)}t.abort?.abort()}}async function at(t){let n=f();if(n&&a.mergeStates.get(t)?.state!=="loading"){a.mergeStates.set(t,{state:"loading"}),c(),n.turns=n.turns??[];try{let e=await p("/pr/merge",{method:"POST",body:JSON.stringify({prUrl:t,mergeMethod:"squash"})});e.merged?(a.mergeStates.set(t,{state:"success",sha:e.sha}),n.turns.push({id:_(),chatId:n.meta.id,seq:n.turns.length,role:"assistant",isPlan:!1,status:"finished",events:[{kind:"text",id:_(),text:`Merged commit \`${e.sha.slice(0,7)}\` into the default branch. Railway should redeploy on the next push hook.`}],createdAt:Date.now()})):a.mergeStates.set(t,{state:"error",message:"GitHub returned merged=false"})}catch(e){let o=e instanceof Error?e.message:String(e);a.mergeStates.set(t,{state:"error",message:o})}finally{c()}}}function N(t,n){let e=n instanceof Error?n.message:String(n);t.events.push({kind:"text",id:_(),text:`[error] ${e}`})}async function j(t,n,e,o){e.abort=new AbortController;let i=await fetch(`${l}${t}`,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json",Accept:"text/event-stream"},body:JSON.stringify(n),signal:e.abort.signal});if(!i.ok||!i.body)throw new Error(`${i.status} ${i.statusText}`);let h=i.body.getReader(),rt=new TextDecoder,R="",U=!1;for(;;){let{value:it,done:dt}=await h.read();if(dt)break;R+=rt.decode(it,{stream:!0});let B=R.split(`
106
+ `)}function ot(){r.querySelector('[data-role="model"]')?.addEventListener("change",t=>{a.model=t.target.value}),r.querySelectorAll("[data-mode]").forEach(t=>{t.addEventListener("click",()=>{a.mode=t.dataset.mode,c()})}),r.querySelector('[data-role="repo"]')?.addEventListener("change",t=>{a.repoUrl=t.target.value.trim()}),r.querySelector('[data-role="logout"]')?.addEventListener("click",async()=>{await fetch(`${u}/auth/logout`,{method:"POST",credentials:"include"}).catch(()=>{});for(let t of a.chats)t.abort?.abort();a.me=null,a.chats=[],a.activeChatId=null,c()}),r.querySelector('[data-role="toggle-sidebar"]')?.addEventListener("click",()=>{a.sidebarOpen=!a.sidebarOpen,c()}),r.querySelectorAll('[data-role="new-chat"]').forEach(t=>t.addEventListener("click",async()=>{await b()&&window.innerWidth<720&&(a.sidebarOpen=!1),c()})),r.querySelectorAll('[data-role="select-chat"]').forEach(t=>t.addEventListener("click",()=>{let e=t.dataset.chatId;P(e)})),r.querySelectorAll('[data-role="rename-chat"]').forEach(t=>t.addEventListener("click",e=>{e.stopPropagation(),$(t.dataset.chatId)})),r.querySelectorAll('[data-role="delete-chat"]').forEach(t=>t.addEventListener("click",e=>{e.stopPropagation(),M(t.dataset.chatId)})),r.querySelector('[data-role="send"]')?.addEventListener("click",()=>B()),r.querySelector('[data-role="prompt"]')?.addEventListener("keydown",t=>{let e=t;e.key==="Enter"&&(e.metaKey||e.ctrlKey)&&(e.preventDefault(),B())}),r.querySelector('[data-role="cancel"]')?.addEventListener("click",()=>rt()),r.querySelectorAll('[data-role="execute"]').forEach(t=>t.addEventListener("click",()=>it())),r.querySelectorAll('[data-role="merge"]').forEach(t=>{t.addEventListener("click",()=>lt(t.dataset.pr))}),r.querySelectorAll('[data-role="toggle-tool"]').forEach(t=>t.addEventListener("click",()=>{let e=t.dataset.toolId;a.expandedTools.has(e)?a.expandedTools.delete(e):a.expandedTools.add(e),c()}))}async function B(){let t=f();if(!t&&(t=await b(),!t)||t.isStreaming)return;let e=r.querySelector('[data-role="prompt"]'),n=e?.value.trim()??"";if(!n)return;e&&(e.value=""),t.turns=t.turns??[];let s={id:_(),chatId:t.meta.id,seq:t.turns.length,role:"user",isPlan:a.mode==="plan",status:"finished",events:[{kind:"text",id:_(),text:n}],prompt:n,createdAt:Date.now()};t.turns.push(s);let o={id:_(),chatId:t.meta.id,seq:t.turns.length,role:"assistant",isPlan:a.mode==="plan",status:"running",events:[],createdAt:Date.now()};t.turns.push(o),t.isStreaming=!0,t.meta.title==="New chat"&&(t.meta={...t.meta,title:n.length>60?`${n.slice(0,57)}\u2026`:n}),t.meta={...t.meta,mode:a.mode,model:a.model,updatedAt:Date.now()},c();try{await G("/agent/send",{chatId:t.meta.id,prompt:n,mode:a.mode},t,o)}finally{t.isReconnecting||(t.isStreaming=!1,t.activeRunId=null,t.abort=null),c()}}async function it(){let t=f();if(!t||t.isStreaming)return;t.turns=t.turns??[];let e={id:_(),chatId:t.meta.id,seq:t.turns.length,role:"assistant",isPlan:!1,status:"running",events:[],createdAt:Date.now()};t.turns.push(e),t.isStreaming=!0,c();try{await G("/agent/execute",{chatId:t.meta.id},t,e)}finally{t.isReconnecting||(t.isStreaming=!1,t.activeRunId=null,t.abort=null),c()}}async function rt(){let t=f();if(t){if(t.activeRunId)try{await m("/agent/cancel",{method:"POST",body:JSON.stringify({chatId:t.meta.id,runId:t.activeRunId})})}catch(e){console.error("[coding-tab] cancel failed",e)}t.abort?.abort()}}async function lt(t){let e=f();if(e&&a.mergeStates.get(t)?.state!=="loading"){a.mergeStates.set(t,{state:"loading"}),c(),e.turns=e.turns??[];try{let n=await m("/pr/merge",{method:"POST",body:JSON.stringify({prUrl:t,mergeMethod:"squash"})});n.merged?(a.mergeStates.set(t,{state:"success",sha:n.sha}),e.turns.push({id:_(),chatId:e.meta.id,seq:e.turns.length,role:"assistant",isPlan:!1,status:"finished",events:[{kind:"text",id:_(),text:`Merged commit \`${n.sha.slice(0,7)}\` into the default branch. Railway should redeploy on the next push hook.`}],createdAt:Date.now()})):a.mergeStates.set(t,{state:"error",message:"GitHub returned merged=false"})}catch(n){let s=n instanceof Error?n.message:String(n);a.mergeStates.set(t,{state:"error",message:s})}finally{c()}}}function dt(t,e){let n=e instanceof Error?e.message:String(e);t.events.push({kind:"text",id:_(),text:`[error] ${n}`})}function ct(t){if(!(t instanceof Error)||t.name==="AbortError")return!1;let e=t.message.toLowerCase();return e.includes("load failed")||e.includes("network")||e.includes("failed to fetch")||e.includes("the network connection was lost")||e.includes("err_network")||e.includes("connection")||e==="fetch failed"}async function D(t,e){let n=Date.now(),s=15*6e4,o=2e3;t.isReconnecting=!0,t.pollTurnId=e,c();try{for(;Date.now()-n<s;){if(!a.chats.find(d=>d.meta.id===t.meta.id))return;try{let{chat:d}=await m(`/chats/${t.meta.id}`);t.turns=d.turns,t.meta={id:d.id,title:d.title,mode:d.mode,model:d.model,createdAt:d.createdAt,updatedAt:d.updatedAt};let S=d.turns.find(T=>T.id===e);if(!S||S.status&&S.status!=="running")return;c()}catch(d){console.warn("[coding-tab] poll tick failed",d)}await ut(o)}}finally{t.isReconnecting=!1,t.pollTurnId=null,t.pollPromise=null,t.isStreaming=!1,t.activeRunId=null,t.abort=null,c()}}function ut(t){return new Promise(e=>setTimeout(e,t))}async function G(t,e,n,s){try{await gt(t,e,n,s)}catch(o){if(o.name==="AbortError")return;if(ct(o)){let d=D(n,s.id);n.pollPromise=d,await d;return}dt(s,o),s.status="error"}}async function gt(t,e,n,s){n.abort=new AbortController;let o=await fetch(`${u}${t}`,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json",Accept:"text/event-stream"},body:JSON.stringify(e),signal:n.abort.signal});if(!o.ok||!o.body)throw new Error(`${o.status} ${o.statusText}`);let d=o.body.getReader(),S=new TextDecoder,T="",x=!1;for(;;){let{value:pt,done:ft}=await d.read();if(ft)break;T+=S.decode(pt,{stream:!0});let J=T.split(`
100
107
 
101
- `);R=B.pop()??"";for(let lt of B){let D=lt.split(`
102
- `).find(x=>x.startsWith("data: "));if(D)try{let x=JSON.parse(D.slice(6));U=st(x,e,o,U),c()}catch(x){console.warn("[coding-tab] bad sse event",x)}}}}function st(t,n,e,o){switch(t.kind){case"ready":return n.activeRunId=t.runId,!1;case"text":{let i=e.events[e.events.length-1];return o&&i&&i.kind==="text"?i.text+=t.text:e.events.push({kind:"text",id:_(),text:t.text}),!0}case"thinking":return o;case"tool":{let i=e.events.find(h=>h.kind==="tool"&&h.callId===t.callId);return i?(i.status=t.status,t.args!==void 0&&(i.args=t.args),t.result!==void 0&&(i.result=t.result)):e.events.push({kind:"tool",id:_(),callId:t.callId,name:t.name,status:t.status,args:t.args,result:t.result}),!1}case"status":return o;case"result":return e.status=t.status,t.pr&&(e.pr=t.pr),e.isPlan&&t.status==="finished"&&(e.showExecute=!0),n.activeRunId=null,!1;case"error":return e.events.push({kind:"text",id:_(),text:`[error] ${t.message}`}),e.status="error",n.activeRunId=null,!1}}async function ot(){try{let t=await p("/auth/me");a.me=t,t.defaultRepoUrl&&(a.repoUrl=t.defaultRepoUrl,a.repoLocked=!0)}catch(t){let n=t.status;if(n===401||n===403){a.me=null,c();return}console.error("[coding-tab] /auth/me failed",t),a.me=null,c();return}try{let{models:t}=await p("/models");a.models=t,t.length>0&&!t.find(n=>n.choice===a.model)&&(a.model=t[0].choice)}catch(t){console.error("[coding-tab] /models failed",t),a.models=[{choice:"sonnet",cursorModelId:"auto",displayName:"Sonnet (fallback)"},{choice:"opus",cursorModelId:"auto",displayName:"Opus (fallback)"}]}await w(),a.chats.length>0&&!a.activeChatId&&(a.activeChatId=a.chats[0].meta.id,S(a.activeChatId).then(()=>c())),c()}return ot(),{destroy(){for(let t of a.chats)t.abort?.abort();d.removeChild(s)}}}typeof window<"u"&&(window.CodingTab={mountCodingTab:F});return pt(wt);})();
108
+ `);T=J.pop()??"";for(let bt of J){let W=bt.split(`
109
+ `).find(L=>L.startsWith("data: "));if(W)try{let L=JSON.parse(W.slice(6));x=ht(L,n,s,x),c()}catch(L){console.warn("[coding-tab] bad sse event",L)}}}}function ht(t,e,n,s){switch(t.kind){case"ready":return e.activeRunId=t.runId,!1;case"text":{let o=n.events[n.events.length-1];return s&&o&&o.kind==="text"?o.text+=t.text:n.events.push({kind:"text",id:_(),text:t.text}),!0}case"thinking":return s;case"tool":{let o=n.events.find(d=>d.kind==="tool"&&d.callId===t.callId);return o?(o.status=t.status,t.args!==void 0&&(o.args=t.args),t.result!==void 0&&(o.result=t.result)):n.events.push({kind:"tool",id:_(),callId:t.callId,name:t.name,status:t.status,args:t.args,result:t.result}),!1}case"status":return s;case"result":return n.status=t.status,t.pr&&(n.pr=t.pr),t.branch&&!t.pr&&(n.branch=t.branch),n.isPlan&&t.status==="finished"&&(n.showExecute=!0),e.activeRunId=null,!1;case"error":return n.events.push({kind:"text",id:_(),text:`[error] ${t.message}`}),n.status="error",e.activeRunId=null,!1}}async function mt(){try{let t=await m("/auth/me");a.me=t,t.defaultRepoUrl&&(a.repoUrl=t.defaultRepoUrl,a.repoLocked=!0)}catch(t){let e=t.status;if(e===401||e===403){a.me=null,c();return}console.error("[coding-tab] /auth/me failed",t),a.me=null,c();return}try{let{models:t}=await m("/models");a.models=t,t.length>0&&!t.find(e=>e.choice===a.model)&&(a.model=t[0].choice)}catch(t){console.error("[coding-tab] /models failed",t),a.models=[{choice:"sonnet",cursorModelId:"auto",displayName:"Sonnet (fallback)"},{choice:"opus",cursorModelId:"auto",displayName:"Opus (fallback)"}]}await k(),a.chats.length>0&&!a.activeChatId?(a.activeChatId=a.chats[0].meta.id,C(a.activeChatId).then(()=>{O(),c()})):O(),c()}function O(){for(let t of a.chats){if(t.pollPromise)continue;let e=t.turns?.at(-1);if(!e||e.role!=="assistant"||e.status&&e.status!=="running")continue;t.isStreaming=!0;let n=D(t,e.id);t.pollPromise=n,n.catch(s=>console.warn("[coding-tab] resume poll failed",s))}}let F=()=>{if(document.visibilityState==="visible"){if(a.activeChatId){let t=a.chats.find(e=>e.meta.id===a.activeChatId);if(t){m(`/chats/${t.meta.id}`).then(({chat:e})=>{t.turns=e.turns,t.meta={id:e.id,title:e.title,mode:e.mode,model:e.model,createdAt:e.createdAt,updatedAt:e.updatedAt},O(),c()}).catch(e=>console.warn("[coding-tab] visibility refresh failed",e));return}}O()}};return document.addEventListener("visibilitychange",F),mt(),{destroy(){document.removeEventListener("visibilitychange",F);for(let t of a.chats)t.abort?.abort();l.removeChild(r)}}}typeof window<"u"&&(window.CodingTab={mountCodingTab:Z});return kt(Lt);})();
103
110
  //# sourceMappingURL=browser.js.map