pipane 0.1.9 → 0.1.10
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/README.md +1 -1
- package/dist/build-info.json +2 -2
- package/dist/client/assets/__vite-browser-external-DGfF_P2w.js +1 -0
- package/dist/client/assets/backend-landing-page-CF2aHs0U.js +1 -0
- package/dist/client/assets/{__vite-browser-external-DtLbhLGx.js → backend-protocol-BvNAsFvb.js} +1 -1
- package/dist/client/assets/device-identity-C_w2NbSk.js +4 -0
- package/dist/client/assets/index-DtrSEX3O.css +1 -0
- package/dist/client/assets/index-bOr1Y6MY.js +2 -0
- package/dist/client/assets/{main-DEfSB8wO.js → main-CQj3ADar.js} +531 -427
- package/dist/client/assets/pairing-page-CiEb8c3R.js +1 -0
- package/dist/client/assets/remote-backend-manager-Bbt7CXRP.js +1 -0
- package/dist/client/assets/rendezvous-trust-api-xLnrhe-v.js +1 -0
- package/dist/client/assets/webrtc-frame-transport-Drpqhhdy.js +1 -0
- package/dist/client/assets/workspace-backend-client-kUrfC0HS.js +1 -0
- package/dist/client/assets/ws-agent-adapter-Cauprivt.js +6 -0
- package/dist/client/index.html +5 -17
- package/dist/server/server/frame-connection.js +157 -40
- package/dist/server/server/frame-router.js +2 -1
- package/dist/server/server/server.js +13 -10
- package/dist/server/server/ws-handler.js +44 -23
- package/dist/server/shared/data-channel-framing.js +31 -1
- package/docs/protocol.md +4 -2
- package/package.json +1 -1
- package/dist/client/assets/backend-landing-page-B7SbyIXQ.js +0 -1
- package/dist/client/assets/index-C7_1ODks.js +0 -2
- package/dist/client/assets/index-DgI_gkjg.css +0 -1
- package/dist/client/assets/pairing-page-C0YByC2D.js +0 -1
- package/dist/client/assets/remote-backend-manager-DCSdS38m.js +0 -1
- package/dist/client/assets/rendezvous-trust-api-C2Zob5i4.js +0 -4
- package/dist/client/assets/webrtc-frame-transport-DGX5EO_A.js +0 -1
- package/dist/client/assets/ws-agent-adapter-DpkkZGPl.js +0 -6
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import{_ as ie}from"./index-C7_1ODks.js";import{i as oe}from"./__vite-browser-external-DtLbhLGx.js";function ae(i){const e=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],s=(S,f)=>S>>>f|S<<32-f,t=new TextEncoder().encode(i),n=t.length*8,o=new Uint8Array(Math.ceil((t.length+9)/64)*64);o.set(t),o[t.length]=128;const a=new DataView(o.buffer);a.setUint32(o.length-4,n,!1),n>4294967295&&a.setUint32(o.length-8,Math.floor(n/4294967296),!1);let[r,h,u,_,y,v,w,c]=[1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225];const g=new Int32Array(64);for(let S=0;S<o.length;S+=64){for(let d=0;d<16;d++)g[d]=a.getInt32(S+d*4,!1);for(let d=16;d<64;d++){const U=s(g[d-15],7)^s(g[d-15],18)^g[d-15]>>>3,q=s(g[d-2],17)^s(g[d-2],19)^g[d-2]>>>10;g[d]=g[d-16]+U+g[d-7]+q|0}let[f,$,L,N,P,A,F,R]=[r,h,u,_,y,v,w,c];for(let d=0;d<64;d++){const U=s(P,6)^s(P,11)^s(P,25),q=P&A^~P&F,V=R+U+q+e[d]+g[d]|0,se=s(f,2)^s(f,13)^s(f,22),te=f&$^f&L^$&L,ne=se+te|0;R=F,F=A,A=P,P=N+V|0,N=L,L=$,$=f,f=V+ne|0}r=r+f|0,h=h+$|0,u=u+L|0,_=_+N|0,y=y+P|0,v=v+A|0,w=w+F|0,c=c+R|0}return[r,h,u,_,y,v,w,c].map(S=>(S>>>0).toString(16).padStart(8,"0")).join("")}async function re(i){if(typeof globalThis.crypto?.subtle?.digest=="function"){const e=new TextEncoder().encode(i),s=await globalThis.crypto.subtle.digest("SHA-256",e),t=new Uint8Array(s);return Array.from(t).map(n=>n.toString(16).padStart(2,"0")).join("")}if(typeof globalThis.process<"u"){const{createHash:e}=await ie(async()=>{const{createHash:s}=await import("./__vite-browser-external-DtLbhLGx.js").then(t=>t._);return{createHash:s}},[]);return e("sha256").update(i,"utf8").digest("hex")}return ae(i)}function ce(i,e){let s=i;for(const t of e)s=s.slice(0,t.offset)+t.insert+s.slice(t.offset+t.deleteCount);return s}async function le(i,e,s){if(s.length===0)return{data:i,hash:e};let t=i,n=e,o;for(const r of s){if(o=r,r.op==="full"){t=r.data,n=r.hash;continue}if(r.baseHash!==n)return console.warn("[jsonl-sync] Base hash mismatch, need full sync",{expected:r.baseHash,actual:n}),null;t=ce(t,r.patches),n=r.hash}const a=await re(t);if(a!==n){const r=o?.op==="full"?"[jsonl-sync] Full sync hash mismatch":"[jsonl-sync] Post-patch hash mismatch";return console.error(r,{expected:n,actual:a}),null}return{data:t,hash:n}}const he=10*6e4,de=he+9e4,D=1;class Q extends Error{constructor(e,s,t){super(`${s}: ${t}`),this.code=e}}function p(i,e,s="invalid_message"){throw new Q(s,i,e)}function K(i){return typeof i=="object"&&i!==null&&!Array.isArray(i)}function m(i,e){return K(i)||p(e,"expected an object"),i}function l(i,e,s=!0){return(typeof i!="string"||!s&&i.length===0)&&p(e,s?"expected a string":"expected a non-empty string"),i}function k(i,e){return i===void 0?void 0:l(i,e)}function b(i,e){return typeof i!="boolean"&&p(e,"expected a boolean"),i}function C(i,e){return(!Number.isSafeInteger(i)||i<0)&&p(e,"expected a non-negative safe integer"),i}function M(i,e){return(typeof i!="number"||!Number.isFinite(i))&&p(e,"expected a finite number"),i}function T(i,e){return Array.isArray(i)||p(e,"expected an array"),i}function H(i,e){return T(i,e).map((s,t)=>l(s,`${e}[${t}]`))}function O(i,e){const s=m(i,e);for(const[t,n]of Object.entries(s))l(n,`${e}.${t}`);return s}function Y(i,e){const s=m(i,e);for(const[t,n]of Object.entries(s))n!=="running"&&n!=="done"&&p(`${e}.${t}`,"expected 'running' or 'done'");return s}function ue(i,e){const s=m(i,e);for(const[t,n]of Object.entries(s))H(n,`${e}.${t}`);return s}function B(i,e){return["off","minimal","low","medium","high","xhigh","max"].includes(String(i))||p(e,"expected a supported thinking level"),i}function ge(i,e){const s=m(i,e);return l(s.provider,`${e}.provider`,!1),l(s.modelId,`${e}.modelId`,!1),s}function W(i,e){const s=m(i,e);l(s.provider,`${e}.provider`,!1);const t=k(s.id,`${e}.id`),n=k(s.modelId,`${e}.modelId`);return!t&&!n&&p(e,"expected id or modelId"),s}function pe(i,e){if(i.protocolVersion!==D){const s=i.protocolVersion===void 0?"missing":JSON.stringify(i.protocolVersion);p(`${e}.protocolVersion`,`unsupported protocol version ${s}; expected ${D}`,"unsupported_version")}}function X(i){try{return{ok:!0,value:JSON.parse(i)}}catch(e){return{ok:!1,error:{code:"invalid_json",message:`Invalid JSON: ${e instanceof Error?e.message:String(e)}`,requestId:null,command:"parse"}}}}function Z(i,e,s){const t=K(i)?i:void 0,n=typeof t?.id=="string"?t.id:null,o=typeof t?.type=="string"?t.type:s,a=e instanceof Q?e:new Q("invalid_message","$",e instanceof Error?e.message:String(e));return{ok:!1,error:{code:a.code,message:a.message,requestId:n,command:o}}}function me(i,e){T(i,e).forEach((s,t)=>{const n=m(s,`${e}[${t}]`);l(n.name,`${e}[${t}].name`,!1),k(n.description,`${e}[${t}].description`),["extension","prompt","skill"].includes(String(n.source))||p(`${e}[${t}].source`,"expected extension, prompt, or skill"),n.sourceInfo!==void 0&&m(n.sourceInfo,`${e}[${t}].sourceInfo`),k(n.location,`${e}[${t}].location`),k(n.path,`${e}[${t}].path`)})}function fe(i,e){const s=m(i,e);l(s.sessionFile,`${e}.sessionFile`,!1),l(s.sessionId,`${e}.sessionId`,!1);for(const n of["userMessages","assistantMessages","toolCalls","toolResults","totalMessages"])C(s[n],`${e}.${n}`);const t=m(s.tokens,`${e}.tokens`);for(const n of["input","output","cacheRead","cacheWrite","total"])C(t[n],`${e}.tokens.${n}`);if(M(s.cost,`${e}.cost`)<0&&p(`${e}.cost`,"expected a non-negative number"),s.contextUsage!==void 0){const n=m(s.contextUsage,`${e}.contextUsage`);n.tokens!==null&&C(n.tokens,`${e}.contextUsage.tokens`),C(n.contextWindow,`${e}.contextUsage.contextWindow`),n.percent!==null&&M(n.percent,`${e}.contextUsage.percent`)<0&&p(`${e}.contextUsage.percent`,"expected a non-negative number or null")}}function _e(i,e,s){const t=m(e,s);switch(i){case"install_pi":case"subscribe_session":case"steer":case"remove_steering":case"abort":case"set_session_name":break;case"prompt":case"fork_prompt":l(t.newSessionPath,`${s}.newSessionPath`,!1);break;case"hard_kill":b(t.killed,`${s}.killed`),t.reason!==void 0&&t.reason!=="signal_failed"&&t.reason!=="not_attached"&&p(`${s}.reason`,"expected signal_failed or not_attached");break;case"compact":break;case"get_available_models":T(t.models,`${s}.models`).forEach((n,o)=>W(n,`${s}.models[${o}]`));break;case"get_default_model":t.model!==null&&W(t.model,`${s}.model`),B(t.thinkingLevel,`${s}.thinkingLevel`);break;case"get_session_statuses":Y(t.statuses,`${s}.statuses`);break;case"get_session_stats":fe(t,s);break;case"fork":l(t.text,`${s}.text`),b(t.cancelled,`${s}.cancelled`),t.newSessionPath!==null&&l(t.newSessionPath,`${s}.newSessionPath`,!1);break;case"get_commands":me(t.commands,`${s}.commands`);break;case"reload_processes":C(t.killed,`${s}.killed`),C(t.draining,`${s}.draining`);break}}const Se=new Set(["install_pi","subscribe_session","prompt","steer","remove_steering","abort","hard_kill","compact","get_available_models","get_default_model","get_session_statuses","get_session_stats","fork","fork_prompt","set_session_name","get_commands","reload_processes"]);function ye(i,e){const s=l(i,e,!1);return Se.has(s)||p(e,`unknown response command '${s}'`,"unknown_message"),s}function ve(i,e){T(i,e).forEach((s,t)=>{const n=m(s,`${e}[${t}]`);C(n.offset,`${e}[${t}].offset`),C(n.deleteCount,`${e}[${t}].deleteCount`),l(n.insert,`${e}[${t}].insert`)})}function we(i){const e=X(i);if(!e.ok)return e;const s=e.value;try{const t=m(s,"$message");pe(t,"$message");const n=l(t.type,"$message.type",!1);switch(n){case"response":{if(b(t.success,"$message.success")){l(t.id,"$message.id",!1);const a=ye(t.command,"$message.command");_e(a,t.data,"$message.data")}else t.id!==null&&l(t.id,"$message.id",!1),l(t.command,"$message.command",!1),l(t.error,"$message.error",!1),["invalid_json","invalid_message","unsupported_version","unknown_command","unknown_message","command_failed"].includes(String(t.code))||p("$message.code","expected a protocol error code");break}case"init":Y(t.sessionStatuses,"$message.sessionStatuses"),ue(t.steeringQueues,"$message.steeringQueues"),O(t.providerUsageStatuses,"$message.providerUsageStatuses");break;case"pi_install_required":l(t.command,"$message.command",!1),b(t.installable,"$message.installable"),b(t.installing,"$message.installing"),l(t.message,"$message.message",!1);break;case"session_status_change":l(t.sessionPath,"$message.sessionPath",!1),t.status!=="running"&&t.status!=="done"&&p("$message.status","expected running or done");break;case"provider_usage":O(t.statuses,"$message.statuses");break;case"extension_status":l(t.sessionPath,"$message.sessionPath",!1),O(t.statuses,"$message.statuses");break;case"session_sync":l(t.sessionPath,"$message.sessionPath",!1),C(t.revision,"$message.revision"),l(t.hash,"$message.hash",!1),t.op==="full"?l(t.data,"$message.data"):t.op==="delta"?(l(t.baseHash,"$message.baseHash",!1),ve(t.patches,"$message.patches")):p("$message.op","expected full or delta");break;case"control_state":l(t.sessionPath,"$message.sessionPath",!1),t.controlRevision!==void 0&&C(t.controlRevision,"$message.controlRevision"),W(t.model,"$message.model"),B(t.thinkingLevel,"$message.thinkingLevel");break;case"session_attached":l(t.sessionPath,"$message.sessionPath",!1),k(t.cwd,"$message.cwd"),k(t.firstMessage,"$message.firstMessage");break;case"sessions_changed":l(t.file,"$message.file");break;default:p("$message.type",`unknown server message '${n}'`,"unknown_message")}return{ok:!0,value:t}}catch(t){return Z(s,t,"unknown")}}function Ce(i){const e=X(i);if(!e.ok)return e;const s=e.value;try{const t=m(s,"$session");T(t.messages,"$session.messages").forEach((o,a)=>{const r=m(o,`$session.messages[${a}]`);l(r.role,`$session.messages[${a}].role`,!1)}),b(t.isStreaming,"$session.isStreaming"),H(t.pendingToolCalls,"$session.pendingToolCalls");const n=m(t.toolCallTimings,"$session.toolCallTimings");for(const[o,a]of Object.entries(n)){const r=m(a,`$session.toolCallTimings.${o}`);M(r.startedAt,`$session.toolCallTimings.${o}.startedAt`),r.completedAt!==void 0&&M(r.completedAt,`$session.toolCallTimings.${o}.completedAt`)}return t.model!==null&&ge(t.model,"$session.model"),B(t.thinkingLevel,"$session.thinkingLevel"),H(t.steeringQueue,"$session.steeringQueue"),k(t.error,"$session.error"),{ok:!0,value:t}}catch(t){return Z(s,t,"session_sync")}}function $e(i,e){return JSON.stringify({protocolVersion:D,id:e,...i})}function Pe(i){throw new Error(`Unhandled protocol variant: ${JSON.stringify(i)}`)}const x=["off","minimal","low","medium","high","xhigh","max"];function E(i){return i?.id??i?.modelId}function j(i,e){const s=E(i),t=E(e);return!!i&&!!e&&!!s&&!!t&&i.provider===e.provider&&s===t}function J(i){const e=E(i);if(!(!i.provider||!e))return{provider:i.provider,modelId:e}}function ke(i){if(!i)return!1;if(typeof i.reasoning=="boolean")return i.reasoning;if(i.thinkingLevelMap)return!0;const e=String(i.provider??"").toLowerCase(),s=String(E(i)??"").toLowerCase();return!!(e==="openai-codex"||e==="openai"&&s.startsWith("gpt-5"))}function be(i){if(!ke(i))return["off"];const e=i?.thinkingLevelMap;return x.filter(s=>{const t=e?.[s];return t===null?!1:s==="xhigh"||s==="max"?t!==void 0:!0})}function G(i,e){const s=be(i);if(s.includes(e))return e;const t=x.indexOf(e);if(t===-1)return s[0]??"off";for(let n=t;n<x.length;n++){const o=x[n];if(s.includes(o))return o}for(let n=t-1;n>=0;n--){const o=x[n];if(s.includes(o))return o}return s[0]??"off"}class Le extends Error{constructor(e,s,t){super(e),this.status=s,this.details=t,this.name="BackendApiError"}}class xe{constructor(e={}){this.fetch=e.fetch??globalThis.fetch.bind(globalThis)}listSessions(){return this.requestJson("/api/sessions")}async deleteSession(e){await this.requestJson("/api/sessions",{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e})})}async listForkMessages(e){return(await this.requestJson(`/api/sessions/fork-messages?path=${encodeURIComponent(e)}`)).messages??[]}browseDirectory(e){return this.requestJson(`/api/browse?path=${encodeURIComponent(e)}`)}createDirectory(e,s){return this.requestJson("/api/directories",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({parentPath:e,name:s})})}async getRawSession(e){const s=await this.fetch(`/api/sessions/raw?path=${encodeURIComponent(e)}`);if(!s.ok)throw await this.toError(s,"Failed to load raw session");return s.text()}getFileContent(e,s){const t=new URLSearchParams({sessionPath:e,path:s});return this.requestJson(`/api/files/content?${t}`,{cache:"no-store"})}createFileUpload(e){return this.requestJson("/api/files/uploads",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})}appendFileUpload(e){return this.requestJson(`/api/files/uploads/${encodeURIComponent(e.uploadId)}/chunks`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({offset:e.offset,data:e.data})})}completeFileUpload(e){return this.requestJson(`/api/files/uploads/${encodeURIComponent(e)}/complete`,{method:"POST"})}getLocalSettings(){return this.requestJson("/api/settings/local")}validateLocalSettings(e){return this.requestValidation("/api/settings/local/validate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({content:e})})}patchLocalSettings(e){return this.requestValidation("/api/settings/local",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})}saveLocalSettings(e){return this.requestValidation("/api/settings/local",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({content:e})})}getUpdates(){return this.requestJson("/api/updates",{cache:"no-store"})}runUpdate(e){return this.requestJson(`/api/updates/${e}`,{method:"POST",headers:{"X-Pipane-Action":"update"}})}async requestValidation(e,s){const t=await this.fetch(e,s),n=await this.readJson(t);if(!t.ok&&typeof n?.valid!="boolean")throw this.errorFromPayload(t,n,"Settings request failed");return n}async requestJson(e,s){const t=s?await this.fetch(e,s):await this.fetch(e),n=await this.readJson(t);if(!t.ok)throw this.errorFromPayload(t,n,`Backend request failed (${t.status})`);return n}async readJson(e){return e.json().catch(()=>({}))}async toError(e,s){const t=await this.readJson(e);return this.errorFromPayload(e,t,s)}errorFromPayload(e,s,t){const n=Array.isArray(s?.errors)?s.errors.filter(a=>typeof a=="string"):[],o=typeof s?.error=="string"?s.error:n.length>0?n.join(`
|
|
2
|
-
`):t;return new Le(o,e.status,s)}}const ee=[{name:"help",description:"Show this help",source:"builtin"},{name:"new",description:"Start a new session",source:"builtin"},{name:"session",description:"Show session file, messages, tokens, and cost",source:"builtin"},{name:"fork",description:"Fork session from a previous message",source:"builtin"},{name:"compact",description:"Compact conversation history",source:"builtin",argumentHint:"[instructions]",acceptsArguments:!0},{name:"name",description:"Set session display name",source:"builtin",argumentHint:"<name>",acceptsArguments:!0},{name:"reload",description:"Restart all pooled pi RPC processes",source:"builtin"}];function Re(i){const e=ee.map(t=>({...t})),s=new Set(e.map(t=>t.name.toLocaleLowerCase()));for(const t of i){const n=t.name.toLocaleLowerCase();s.has(n)||(s.add(n),e.push({name:t.name,description:t.description??"",source:t.source,acceptsArguments:!0}))}return e}function Te(i,e){const s=i.toLocaleLowerCase(),t=e.toLocaleLowerCase();if(!t)return 0;if(s===t)return 1e5;let n=s.startsWith(t)?5e4:0,o=0,a=-2,r=-1;for(const h of t){const u=s.indexOf(h,o);if(u===-1)return;r===-1&&(r=u);const _=u>0?s[u-1]:"";u===0||_==="-"||_===":"||_==="_"?n+=18:n+=4,u===a+1&&(n+=12),a=u,o=u+1}return n-=r*3,n-=s.length-t.length,n}function Ue(i,e){return i.map((s,t)=>({command:s,index:t,score:Te(s.name,e)})).filter(s=>s.score!==void 0).sort((s,t)=>t.score-s.score||s.index-t.index).map(s=>s.command)}function qe(i){switch(i){case"builtin":return"Built-in";case"extension":return"Extension";case"prompt":return"Prompt";case"skill":return"Skill"}}const z=1,Ae=1e4;class Fe{constructor(e={}){this.socket=null,this.reconnecting=!1,this.reconnectAttempt=0,this.manuallyClosed=!1,this.frameListeners=new Set,this.connectionListeners=new Set,this.createWebSocket=e.createWebSocket??(s=>new WebSocket(s)),this.schedule=e.schedule??globalThis.setTimeout.bind(globalThis),this.cancelSchedule=e.cancelSchedule??globalThis.clearTimeout.bind(globalThis),e.socket&&(this.socket=e.socket,this.attachFrameHandler(e.socket))}get isConnected(){return this.socket?.readyState===z}get isReconnecting(){return this.reconnecting}onFrame(e){return this.frameListeners.add(e),()=>this.frameListeners.delete(e)}onConnectionChange(e){return this.connectionListeners.add(e),()=>this.connectionListeners.delete(e)}async connect(e){this.isConnected||(this.endpoint=e,this.manuallyClosed=!1,await this.openSocket(!1))}send(e){if(!this.socket||this.socket.readyState!==z)throw new Error("Backend transport is not connected");this.socket.send(e)}close(e=1e3,s="Client closed"){this.manuallyClosed=!0,this.reconnecting=!1,this.reconnectTimer&&(this.cancelSchedule(this.reconnectTimer),this.reconnectTimer=void 0),this.socket?.close(e,s)}attachFrameHandler(e){e.onmessage=s=>{const t=String(s.data);for(const n of this.frameListeners)n(t)}}emitConnectionChange(e){for(const s of this.connectionListeners)s(e)}openSocket(e){const s=this.endpoint;return s?new Promise((t,n)=>{const o=this.createWebSocket(s);let a=!1,r=!1;this.socket=o,this.attachFrameHandler(o),o.onopen=()=>{this.socket===o&&(a=!0,r=!0,this.reconnecting=!1,this.reconnectAttempt=0,this.emitConnectionChange({connected:!0,reconnected:e}),t())},o.onerror=()=>{!e&&!r&&(r=!0,n(new Error("WebSocket connection failed")))},o.onclose=()=>{if(this.socket===o&&(this.socket=null),r||(r=!0,n(new Error("WebSocket closed before connecting"))),this.manuallyClosed){a&&this.emitConnectionChange({connected:!1,reconnected:!1});return}(a||e)&&(this.scheduleReconnect(),a&&this.emitConnectionChange({connected:!1,reconnected:!1}))}}):Promise.reject(new Error("Backend transport endpoint is missing"))}scheduleReconnect(){if(this.reconnectTimer||this.manuallyClosed)return;this.reconnecting=!0,this.reconnectAttempt++;const e=Math.min(500*2**(this.reconnectAttempt-1),Ae);this.reconnectTimer=this.schedule(()=>{this.reconnectTimer=void 0,this.openSocket(!0).catch(()=>{})},e)}}const Ie="provider-usage";function Me(i){const e=typeof i?.provider=="string"?i.provider.toLowerCase():"";if(e.includes("codex"))return"codex";if(e.includes("anthropic"))return"anthropic"}class Oe{constructor(e={}){this.sessionsChangedListeners=new Set,this.piInstallRequiredListeners=new Set,this.pendingRequests=new Map,this.requestId=0,this._connectionListeners=new Set,this._state={model:void 0,thinkingLevel:"off",messages:[],isStreaming:!1,error:void 0},this._pendingToolCallIds=new Set,this._toolCallTimings={},this._steeringQueues=new Map,this._steeringQueueListeners=new Set,this._extensionStatuses=new Map,this._providerUsageStatuses=new Map,this._extensionStatusListeners=new Set,this._controlRevision=0,this._availableModels=null,this._sessionId="",this._sessionStatus="virtual",this._localAssistantMessages=[],this._optimisticSessions=new Map,this._globalSessionStatus=new Map,this._globalStatusListeners=new Set,this._sessionNonce=0,this._pendingNewPrompt=!1,this._startingPrompts=new Map,this._syncJson="",this._syncHash="",this._pendingSessionSyncs=[],this._sessionSyncFlushScheduled=!1,this._sessionSyncFlushInProgress=!1,this._sessionListeners=new Set,this._contentListeners=new Set,this._statusListeners=new Set,this.transport=e.transport??new Fe({socket:e.socket,createWebSocket:e.createWebSocket}),this.api=e.api??new xe({fetch:e.fetch}),this.requestFrame=e.requestFrame??(s=>requestAnimationFrame(s)),this.transport.onFrame(s=>this.handleMessage(s)),this.transport.onConnectionChange(s=>this.handleTransportConnectionChange(s.connected,s.reconnected))}get state(){return this._state}get sessionId(){return this._sessionId}get sessionFile(){return this._sessionPath}get sessionName(){return this._sessionName}get sessionStatus(){return this._sessionStatus}get isConnected(){return this.transport.isConnected}get isReconnecting(){return this.transport.isReconnecting}onConnectionChange(e){return this._connectionListeners.add(e),()=>this._connectionListeners.delete(e)}emitConnectionChange(e){for(const s of this._connectionListeners)s(e)}get pendingToolCallIds(){return this._pendingToolCallIds}get toolCallTimings(){return this._toolCallTimings}get steeringQueue(){return this._sessionPath?this._steeringQueues.get(this._sessionPath)??[]:[]}get extensionStatuses(){const e=new Map(this._extensionStatuses),s=Me(this._state.model),t=s?this._providerUsageStatuses.get(s):this._providerUsageStatuses.size===1?this._providerUsageStatuses.values().next().value:void 0;return t&&e.set(Ie,t),e}onExtensionStatusChange(e){return this._extensionStatusListeners.add(e),()=>this._extensionStatusListeners.delete(e)}replaceExtensionStatuses(e){const s=new Map;if(e&&typeof e=="object"&&!Array.isArray(e))for(const[t,n]of Object.entries(e))typeof n=="string"&&s.set(t,n);if(!(s.size===this._extensionStatuses.size&&[...s].every(([t,n])=>this._extensionStatuses.get(t)===n))){this._extensionStatuses=s;for(const t of this._extensionStatusListeners)t()}}replaceProviderUsageStatuses(e){const s=new Map;if(e&&typeof e=="object"&&!Array.isArray(e))for(const[t,n]of Object.entries(e))typeof n=="string"&&s.set(t,n);if(!(s.size===this._providerUsageStatuses.size&&[...s].every(([t,n])=>this._providerUsageStatuses.get(t)===n))){this._providerUsageStatuses=s;for(const t of this._extensionStatusListeners)t()}}clearExtensionStatuses(){this.replaceExtensionStatuses({})}getSessionStatus(e){return this._globalSessionStatus.get(e)}onGlobalStatusChange(e){return this._globalStatusListeners.add(e),()=>this._globalStatusListeners.delete(e)}emitGlobalStatusChange(){for(const e of this._globalStatusListeners)e()}setGlobalSessionStatus(e,s){this._globalSessionStatus.set(e,s),s==="running"&&this._startingPrompts.get(e)?.resolveReady(e),this.emitGlobalStatusChange()}setAllSessionStatuses(e){this._globalSessionStatus.clear();for(const[s,t]of Object.entries(e))this._globalSessionStatus.set(s,t);this.emitGlobalStatusChange()}onSteeringQueueChange(e){return this._steeringQueueListeners.add(e),()=>this._steeringQueueListeners.delete(e)}emitSteeringQueueChange(){for(const e of this._steeringQueueListeners)e()}enqueueSteering(e,s){const t=this._steeringQueues.get(e)??[];this._steeringQueues.set(e,[...t,s]),this.emitSteeringQueueChange()}onSessionChange(e){return this._sessionListeners.add(e),()=>this._sessionListeners.delete(e)}emitSessionChange(){for(const e of this._sessionListeners)e()}onContentChange(e){return this._contentListeners.add(e),()=>this._contentListeners.delete(e)}emitContentChange(){for(const e of this._contentListeners)e()}onStatusChange(e){return this._statusListeners.add(e),()=>this._statusListeners.delete(e)}emitStatusChange(){for(const e of this._statusListeners)e()}onSessionsChanged(e){return this.sessionsChangedListeners.add(e),()=>this.sessionsChangedListeners.delete(e)}onPiInstallRequired(e){return this.piInstallRequiredListeners.add(e),()=>this.piInstallRequiredListeners.delete(e)}emitPiInstallRequired(e){for(const s of this.piInstallRequiredListeners)s(e)}toErrorMessage(e){if(e instanceof Error)return e.message;if(typeof e=="string")return e;try{return JSON.stringify(e)}catch{return String(e)}}reportError(e,s="Request failed"){const t=this.toErrorMessage(e);this._state.error=t,this._state.messages=[...this._state.messages,{role:"assistant",content:[{type:"text",text:`⚠️ ${s}: ${t}`}],timestamp:Date.now()}],this.emitStatusChange(),this.emitContentChange()}async connect(e){await this.transport.connect(e),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&this.syncStateOnFocus()})}disconnect(){this.transport.close()}getConnectionDiagnostics(){return this.transport.getConnectionDiagnostics?.()??Promise.resolve(void 0)}handleTransportConnectionChange(e,s){e?s?this.onReconnected():this._sessionStatus="virtual":this.handleTransportDisconnected(),this.emitConnectionChange(e)}handleTransportDisconnected(){for(const e of this.pendingRequests.values())e.reject(new Error("Backend transport disconnected"));this.pendingRequests.clear(),this._pendingControl?.phase==="sent"?this.rollbackSentControl(this._pendingControl.revision):this._pendingControl?.phase==="acknowledged"&&(this._pendingControl=void 0)}async onReconnected(){this._sessionPath&&this._sessionStatus!=="virtual"&&(this._awaitingFullSync=void 0,this.requestFullSessionSync(this._sessionPath)),this.refreshSessionStatuses()}async syncStateOnFocus(){this.refreshSessionStatuses(),this._sessionPath&&this._sessionStatus!=="virtual"&&this.subscribeToSession(this._sessionPath),this._sessionStatus==="detached"&&this._state.isStreaming&&(console.log("[ws-adapter] Tab regained focus: clearing stale streaming state"),this._state.isStreaming=!1,this._pendingToolCallIds.clear(),this.emitStatusChange())}async refreshSessionStatuses(){try{const e=await this.send({type:"get_session_statuses"});e?.statuses&&this.setAllSessionStatuses(e.statuses)}catch(e){console.error("Failed to refresh session statuses:",e)}}async subscribeToSession(e){try{await this.send({type:"subscribe_session",sessionPath:e??""})}catch(s){console.error("Failed to subscribe to session:",s)}}async requestFullSessionSync(e){const s={sessionPath:e,sessionNonce:this._sessionNonce};this._awaitingFullSync?.sessionPath===s.sessionPath&&this._awaitingFullSync.sessionNonce===s.sessionNonce||(this._awaitingFullSync=s,this._syncJson="",this._syncHash="",this._syncRevision=void 0,this.clearSessionSyncQueue(),await this.subscribeToSession(e))}handleProtocolError(e){const s=`Protocol error: ${e.message}`;console.error(`[ws-adapter] ${s}`),this._state.error=s,this.emitStatusChange(),e.code==="unsupported_version"&&this.transport.close(1002,"Unsupported protocol version")}handleMessage(e){if(oe(e))return;const s=we(e);if(!s.ok){this.handleProtocolError(s.error);return}const t=s.value;switch(t.type){case"response":{if(!t.success&&t.id===null){this._state.error=t.error,this.emitStatusChange();return}if(t.id===null)return;const n=this.pendingRequests.get(t.id);if(!n)return;if(this.pendingRequests.delete(t.id),t.command!==n.command){n.reject(new Error(`Mismatched response for ${n.command}: received ${t.command}`));return}t.success?n.resolve(t.data):(this._state.error=t.error,this.emitStatusChange(),n.reject(new Error(t.error)));return}case"pi_install_required":this.emitPiInstallRequired({command:t.command,installable:t.installable,installing:t.installing,message:t.message});return;case"init":this.setAllSessionStatuses(t.sessionStatuses),this.replaceProviderUsageStatuses(t.providerUsageStatuses),this._steeringQueues.clear();for(const[n,o]of Object.entries(t.steeringQueues))o.length>0&&this._steeringQueues.set(n,[...o]);this.emitSteeringQueueChange();return;case"session_status_change":this.setGlobalSessionStatus(t.sessionPath,t.status);return;case"provider_usage":this.replaceProviderUsageStatuses(t.statuses);return;case"extension_status":t.sessionPath===this._sessionPath&&this.replaceExtensionStatuses(t.statuses);return;case"session_sync":if(t.sessionPath!==this._sessionPath)return;this.enqueueSessionSync({...t,__sessionPath:t.sessionPath,__sessionNonce:this._sessionNonce});return;case"control_state":{if(t.sessionPath!==this._sessionPath)return;this.applyAuthoritativeControlState(t.model,t.thinkingLevel,t.controlRevision)&&this.emitContentChange();return}case"session_attached":{this.setGlobalSessionStatus(t.sessionPath,"running"),t.cwd&&(this._pendingCwd=t.cwd);const n=t.sessionPath===this._sessionPath||this._sessionStatus==="virtual"&&this._pendingNewPrompt;if(n){if(this._sessionStatus==="virtual"){this._sessionPath=t.sessionPath;const a=I.basename(t.sessionPath,".jsonl"),r=a.split("_");this._sessionId=r.length>1?r.slice(1).join("_"):a,this._startingPrompts.get(`virtual:${this._sessionNonce}`)?.resolveReady(t.sessionPath)}this._sessionStatus="attached",this._state.isStreaming=!0,this.requestFullSessionSync(t.sessionPath),this.emitStatusChange()}if(!this._optimisticSessions.has(t.sessionPath)){const o=new Date().toISOString(),a=I.basename(t.sessionPath,".jsonl"),r=a.split("_"),h=r.length>1?r.slice(1).join("_"):a;this._optimisticSessions.set(t.sessionPath,{id:h,path:t.sessionPath,cwd:t.cwd??"",created:o,modified:o,lastUserPromptTime:o,messageCount:1,firstMessage:t.firstMessage??"(new session)"})}n&&this.emitSessionChange();return}case"sessions_changed":for(const n of this.sessionsChangedListeners)n(t.file);return;default:Pe(t)}}enqueueSessionSync(e){const s=this._awaitingFullSync!==void 0&&this._awaitingFullSync.sessionPath===e.__sessionPath&&this._awaitingFullSync.sessionNonce===e.__sessionNonce;if(e.op==="full")s&&(this._awaitingFullSync=void 0),this._pendingSessionSyncs=[e];else{if(s)return;this._pendingSessionSyncs.push(e)}this._sessionSyncFlushScheduled||this._sessionSyncFlushInProgress||(this._sessionSyncFlushScheduled=!0,this.requestFrame(()=>{this._sessionSyncFlushScheduled=!1,this.flushSessionSyncQueue()}))}clearSessionSyncQueue(){this._pendingSessionSyncs=[],this._sessionSyncFlushScheduled=!1}async flushSessionSyncQueue(){if(this._sessionSyncFlushInProgress)return;this._sessionSyncFlushInProgress=!0;const e=this._pendingSessionSyncs.splice(0);try{const s=await this.applySessionSyncBatch(e);s&&this.emitSessionSyncChanges(s)}finally{this._sessionSyncFlushInProgress=!1,this._pendingSessionSyncs.length>0&&!this._sessionSyncFlushScheduled&&(this._sessionSyncFlushScheduled=!0,this.requestFrame(()=>{this._sessionSyncFlushScheduled=!1,this.flushSessionSyncQueue()}))}}emitSessionSyncChanges(e){e.steering&&this.emitSteeringQueueChange(),e.content&&this.emitContentChange(),e.status&&this.emitStatusChange()}async applySessionSyncBatch(e){const s=this._sessionPath,t=this._sessionNonce;if(!s||e.length===0||e.some(c=>c.__sessionPath!==s||c.__sessionNonce!==t))return;let n=this._syncRevision;for(const c of e){if(c.op==="full"){n=c.revision;continue}if(n===void 0||c.revision!==n+1){console.error("[ws-adapter] Session revision gap, re-subscribing",{expected:n===void 0?"full snapshot":n+1,actual:c.revision}),this.requestFullSessionSync(s);return}n=c.revision}const o=e.map(c=>c.op==="full"?{op:"full",data:c.data,hash:c.hash}:{op:"delta",patches:c.patches,hash:c.hash,baseHash:c.baseHash});if(o[0]?.op==="delta"&&!this._syncHash){console.warn("[ws-adapter] Ignoring delta while awaiting full sync");return}const a=await le(this._syncJson,this._syncHash,o);if(s!==this._sessionPath||t!==this._sessionNonce)return;if(!a){console.error("[ws-adapter] Sync verification failed, re-subscribing"),this.requestFullSessionSync(s);return}const r=Ce(a.data);if(!r.ok){this.handleProtocolError(r.error);return}const h=r.value;this._syncJson=a.data,this._syncHash=a.hash,this._syncRevision=n;const u=this._state.isStreaming,_=this._sessionStatus,y=this._state.error,v=[...this._steeringQueues.get(s)??[]];this._state.messages=[...h.messages??[],...this._localAssistantMessages],this._state.isStreaming=h.isStreaming??!1,this._sessionStatus!=="virtual"&&(this._sessionStatus=this._state.isStreaming?"attached":"detached"),this._pendingToolCallIds=new Set(h.pendingToolCalls??[]),this._toolCallTimings=h.toolCallTimings??{},this.applyAuthoritativeControlState(h.model,h.thinkingLevel),Array.isArray(h.steeringQueue)&&(h.steeringQueue.length>0?this._steeringQueues.set(s,[...h.steeringQueue]):this._steeringQueues.delete(s)),this._state.error=h.error||void 0;const w=this._steeringQueues.get(s)??[];return{content:!0,status:u!==this._state.isStreaming||_!==this._sessionStatus||y!==this._state.error,steering:v.length!==w.length||v.some((c,g)=>c!==w[g])}}send(e){if(!this.transport.isConnected)return Promise.reject(new Error("Backend transport is not connected"));const s=`req_${++this.requestId}`;return new Promise((t,n)=>{const o=e.type==="compact"?de:e.type==="prompt"||e.type==="fork_prompt"?9e4:3e4,a=setTimeout(()=>{this.pendingRequests.delete(s),n(new Error(`Timeout waiting for response to ${e.type}`))},o);this.pendingRequests.set(s,{command:e.type,resolve:r=>{clearTimeout(a),t(r)},reject:r=>{clearTimeout(a),n(r)}}),this.transport.send($e(e,s))})}async fetchAvailableModels(){const s=(await this.send({type:"get_available_models"}))?.models??[];this._availableModels=s;const t=this.resolveModel(this._state.model);return t&&(this._state.model=t),s}resolveModel(e){if(!e)return;const s=this._availableModels?.find(n=>j(n,e));if(s)return s;const t=J(e);if(t)return{...e,provider:t.provider,id:t.modelId}}markControlPending(){const e=++this._controlRevision;return this._pendingControl={revision:e,sessionNonce:this._sessionNonce,phase:"local"},e}markControlSent(e){this._pendingControl?.revision===e&&this._pendingControl.sessionNonce===this._sessionNonce&&(this._pendingControl.phase="sent")}rollbackSentControl(e){const s=this._pendingControl;if(!s||s.revision!==e||s.phase!=="sent")return;this._pendingControl=void 0;const t=this._lastAuthoritativeControl;t?.sessionNonce===this._sessionNonce&&(this._state.model=t.model,this._state.thinkingLevel=t.thinkingLevel,this.emitContentChange())}rememberAuthoritativeControl(e,s){this._lastAuthoritativeControl={sessionNonce:this._sessionNonce,model:e,thinkingLevel:s}}applyAuthoritativeControlState(e,s,t){const n=this.resolveModel(e),o=s,a=this._pendingControl;if(t!==void 0){if(a){if(a.sessionNonce!==this._sessionNonce||a.revision!==t)return!1;a.phase="acknowledged",a.model=n,a.thinkingLevel=o}return n&&(this._state.model=n),o&&(this._state.thinkingLevel=o),n&&o&&this.rememberAuthoritativeControl(n,o),!!n||!!o}if(a){if(!(a.phase==="acknowledged"&&!!a.model&&j(e,a.model)&&o===a.thinkingLevel))return!1;this._pendingControl=void 0}return n&&(this._state.model=n),o&&(this._state.thinkingLevel=o),n&&o&&this.rememberAuthoritativeControl(n,o),!!n||!!o}async installPi(){await this.send({type:"install_pi"})}async loadDefaultModel(){if(this._state.model)return;const e=await this.send({type:"get_default_model"});this.applyAuthoritativeControlState(e?.model,e?.thinkingLevel)}setCwd(e){this._pendingCwd=e}get cwd(){return this._pendingCwd}createStartingPrompt(e){let s,t;const n={ready:new Promise(o=>{s=o}),resolveReady:o=>s(o),finished:new Promise(o=>{t=o}),resolveFinished:()=>t()};return this._startingPrompts.set(e,n),n}finishStartingPrompt(e,s,t){s.resolveReady(t),s.resolveFinished(),this._startingPrompts.get(e)===s&&this._startingPrompts.delete(e)}async prompt(e,s){let t;if(typeof e=="string"?t=e:Array.isArray(e)?t=e.map(c=>this.extractText(c)).join(`
|
|
3
|
-
`):t=this.extractText(e),this.clearLocalAssistantMessages(),await this.handleSlashCommand(t))return;const o=this._sessionStatus==="virtual"?`virtual:${this._sessionNonce}`:this._sessionPath,a=o?this._startingPrompts.get(o):void 0;if(a){const c=await a.ready;if(c&&this._globalSessionStatus.get(c)==="running"){this.enqueueSteering(c,t),await this.send({type:"steer",sessionPath:c,message:t});return}if(await a.finished,!c)throw new Error("The session failed to start before the queued prompt could be sent");return this.prompt(e,s)}if((this._sessionPath?this._globalSessionStatus.get(this._sessionPath)==="running":!1)&&this._sessionPath){this.enqueueSteering(this._sessionPath,t),await this.send({type:"steer",sessionPath:this._sessionPath,message:t});return}const h=this._state.model;if(!h)throw new Error(`BUG: effective model is undefined when sending prompt. sessionStatus=${this._sessionStatus}, sessionPath=${this._sessionPath}`);const u=J(h);if(!u)throw new Error("BUG: active model has no provider/model ID");const _=this._state.thinkingLevel,y=this._pendingControl?.revision??this._controlRevision;this.markControlSent(y);const v=o??`virtual:${this._sessionNonce}`,w=this.createStartingPrompt(v);if(this._sessionStatus==="virtual"){const c=this._sessionNonce;this._pendingNewPrompt=!0;try{const g=await this.send({type:"prompt",sessionPath:"__new__",cwd:this._pendingCwd,message:t,model:u,thinkingLevel:_,controlRevision:y,images:s});if(this._sessionNonce!==c){console.log("[ws-adapter] Discarding stale prompt response (session changed during await)");return}const S=g?.newSessionPath;if(S&&!this._sessionPath){this._sessionPath=S;const f=I.basename(S,".jsonl"),$=f.split("_");this._sessionId=$.length>1?$.slice(1).join("_"):f,this._sessionStatus="attached",this.requestFullSessionSync(S),this.emitSessionChange(),this.emitStatusChange()}}catch(g){throw this.rollbackSentControl(y),g}finally{this._pendingNewPrompt=!1;const g=this._sessionNonce===c?this._sessionPath:void 0;this.finishStartingPrompt(v,w,g)}return}if(!this._sessionPath)throw new Error("No session loaded");try{await this.send({type:"prompt",sessionPath:this._sessionPath,message:t,model:u,thinkingLevel:_,controlRevision:y,images:s})}catch(c){throw this.rollbackSentControl(y),c}finally{this.finishStartingPrompt(v,w,this._sessionPath)}}extractText(e){if("content"in e){if(typeof e.content=="string")return e.content;if(Array.isArray(e.content))return e.content.filter(s=>s.type==="text").map(s=>s.text).join(`
|
|
4
|
-
`)}return""}async fetchCommands(){try{const e=this._sessionPath?{sessionPath:this._sessionPath}:{cwd:this._pendingCwd};return(await this.send({type:"get_commands",...e}))?.commands??[]}catch{return[]}}clearLocalAssistantMessages(){if(this._localAssistantMessages.length===0)return;const e=new Set(this._localAssistantMessages);this._localAssistantMessages=[],this._state.messages=this._state.messages.filter(s=>!e.has(s)),this.emitContentChange()}appendLocalAssistantMessage(e){const s={role:"assistant",content:[{type:"text",text:e}]};this._localAssistantMessages.push(s),this._state.messages=[...this._state.messages,s],this.emitContentChange()}formatSessionStats(e){const s=o=>o.toLocaleString("en-US"),t=`$${e.cost.toFixed(e.cost<.01?4:e.cost<1?3:2)}`,n=["**Session information**","",`- **File:** \`${e.sessionFile}\``,`- **ID:** \`${e.sessionId}\``,`- **Messages:** ${s(e.totalMessages)} total (${s(e.userMessages)} user, ${s(e.assistantMessages)} assistant)`,`- **Tools:** ${s(e.toolCalls)} calls, ${s(e.toolResults)} results`,`- **Tokens:** ${s(e.tokens.total)} total (${s(e.tokens.input)} input, ${s(e.tokens.output)} output, ${s(e.tokens.cacheRead)} cache read, ${s(e.tokens.cacheWrite)} cache write)`,`- **Cost:** ${t}`];if(e.contextUsage){const o=e.contextUsage.tokens===null?`unknown / ${s(e.contextUsage.contextWindow)}`:`${s(e.contextUsage.tokens)} / ${s(e.contextUsage.contextWindow)}${e.contextUsage.percent===null?"":` (${e.contextUsage.percent}%)`}`;n.push(`- **Context:** ${o}`)}return n.join(`
|
|
5
|
-
`)}async showSessionMessage(){if(!this._sessionPath){this.appendLocalAssistantMessage("No active session yet. Send a message first to create one.");return}const e=await this.send({type:"get_session_stats",sessionPath:this._sessionPath});this.appendLocalAssistantMessage(this.formatSessionStats(e))}async showHelpMessage(){const e=["**Built-in commands:**","","| Command | Description |","|---------|-------------|",...ee.map(a=>{const r=a.argumentHint?` ${a.argumentHint}`:"";return`| \`/${a.name}${r}\` | ${a.description} |`})],s=await this.fetchCommands(),t=s.filter(a=>a.source==="extension"),n=s.filter(a=>a.source==="prompt"),o=s.filter(a=>a.source==="skill");if(t.length>0){e.push("","**Extension commands:**","","| Command | Description |","|---------|-------------|");for(const a of t)e.push(`| \`/${a.name}\` | ${a.description||""} |`)}if(n.length>0){e.push("","**Prompt templates:**","","| Command | Description |","|---------|-------------|");for(const a of n){const r=a.location?` *(${a.location})*`:"";e.push(`| \`/${a.name}\` | ${a.description||""}${r} |`)}}if(o.length>0){e.push("","**Skills:**","","| Command | Description |","|---------|-------------|");for(const a of o){const r=a.location?` *(${a.location})*`:"";e.push(`| \`/${a.name}\` | ${a.description||""}${r} |`)}}e.push("","**Keyboard shortcuts:**","","| Shortcut | Action |","|----------|--------|","| `Enter` | Send message (also works during streaming to steer) |","| `Cmd+Enter` | Fork session and send message in the fork |","| `Shift+Enter` | New line |","| `Escape` | Abort current turn |"),this.appendLocalAssistantMessage(e.join(`
|
|
6
|
-
`))}async handleSlashCommand(e){const s=e.trim();if(!s.startsWith("/"))return!1;if(s==="/help")return await this.showHelpMessage(),!0;if(s==="/new")return await this.newSession(),!0;if(s==="/session")return await this.showSessionMessage(),!0;if(s==="/fork")return window.dispatchEvent(new CustomEvent("pi-fork-request")),!0;if(s==="/compact"||s.startsWith("/compact ")){if(!this._sessionPath)return!0;const t=s.startsWith("/compact ")?s.slice(9).trim():void 0,n={role:"compactionSummary",summary:"",tokensBefore:0,timestamp:Date.now(),_compacting:!0};this._state.isStreaming=!0,this._state.messages=[...this._state.messages,n],this.emitStatusChange(),this.emitContentChange();try{await this.send({type:"compact",sessionPath:this._sessionPath,customInstructions:t})}catch(o){throw this._state.messages=this._state.messages.filter(a=>a!==n),this.emitContentChange(),o}finally{this._state.isStreaming=!1,this.emitStatusChange()}return await this.subscribeToSession(this._sessionPath),!0}if(s.startsWith("/name ")){const t=s.slice(6).trim();if(!t)return!0;if(!this._sessionPath)return this.appendLocalAssistantMessage("Cannot set name: no active session. Send a message first."),!0;try{await this.send({type:"set_session_name",sessionPath:this._sessionPath,name:t}),this._sessionName=t,this.appendLocalAssistantMessage(`Session renamed to **${t}**`),this.emitSessionChange()}catch(n){this.appendLocalAssistantMessage(`Failed to rename session: ${n?.message||"unknown error"}`)}return!0}if(s==="/reload"){try{const t=await this.send({type:"reload_processes"}),n=t?.killed??0,o=t?.draining??0;this.appendLocalAssistantMessage(`Reload requested: killed ${n} idle process(es), draining ${o} running process(es).`)}catch(t){this.appendLocalAssistantMessage(`Failed to reload pi processes: ${t?.message||"unknown error"}`)}return!0}return!1}abort(){this._sessionPath&&this.send({type:"abort",sessionPath:this._sessionPath}).catch(()=>{})}hardKill(){this._sessionPath&&this.send({type:"hard_kill",sessionPath:this._sessionPath}).catch(()=>{})}steer(e){const s=this.extractText(e);!s||!this._sessionPath||!(this._globalSessionStatus.get(this._sessionPath)==="running")||(this.enqueueSteering(this._sessionPath,s),this.send({type:"steer",sessionPath:this._sessionPath,message:s}).catch(console.error))}removeSteering(e){this._sessionPath&&this.send({type:"remove_steering",sessionPath:this._sessionPath,index:e}).catch(console.error)}setModel(e){const s=this.resolveModel(e)??e,t=j(this._state.model,s),n=G(s,this._state.thinkingLevel);t&&n===this._state.thinkingLevel||(this._state.model=s,this._state.thinkingLevel=n,this.markControlPending(),this.emitContentChange())}setThinkingLevel(e){const s=G(this._state.model,e);s!==this._state.thinkingLevel&&(this._state.thinkingLevel=s,this.markControlPending(),this.emitContentChange())}async getForkMessages(){return this._sessionPath?this.listForkMessages(this._sessionPath):[]}listForkMessages(e){return this.api.listForkMessages(e)}browseDirectory(e){return this.api.browseDirectory(e)}createDirectory(e,s){return this.api.createDirectory(e,s)}getRawSession(e){return this.api.getRawSession(e)}getFileContent(e,s){return this.api.getFileContent(e,s)}createFileUpload(e){return this.api.createFileUpload(e)}appendFileUpload(e){return this.api.appendFileUpload(e)}completeFileUpload(e){return this.api.completeFileUpload(e)}getLocalSettings(){return this.api.getLocalSettings()}validateLocalSettings(e){return this.api.validateLocalSettings(e)}patchLocalSettings(e){return this.api.patchLocalSettings(e)}saveLocalSettings(e){return this.api.saveLocalSettings(e)}getUpdates(){return this.api.getUpdates()}runUpdate(e){return this.api.runUpdate(e)}async fork(e){if(!this._sessionPath)throw new Error("No session loaded");const s=await this.send({type:"fork",sessionPath:this._sessionPath,entryId:e});return{text:s?.text??"",cancelled:s?.cancelled??!1,newSessionPath:s?.newSessionPath??null}}async forkAndPrompt(e,s){if(!this._sessionPath||this._sessionStatus==="virtual"){await this.prompt(e,s);return}if(!this._state.model)throw new Error(`BUG: _state.model is undefined when sending fork_prompt. sessionPath=${this._sessionPath}`);const t=J(this._state.model);if(!t)throw new Error("BUG: active model has no provider/model ID");const n=this._pendingControl?.revision??this._controlRevision;this.markControlSent(n);const o=this._sessionNonce;let a;try{a=await this.send({type:"fork_prompt",sessionPath:this._sessionPath,message:e,model:t,thinkingLevel:this._state.thinkingLevel,controlRevision:n,images:s})}catch(r){throw this.rollbackSentControl(n),r}if(this._sessionNonce!==o){console.log("[ws-adapter] Discarding stale fork_prompt response (session changed during await)");return}a?.newSessionPath&&await this.switchSession(a.newSessionPath)}async listSessions(){const e=await this.api.listSessions(),s=new Set(e.map(n=>n.path));for(const[n,o]of this._optimisticSessions)if(s.has(n)){const a=e.find(r=>r.path===n);a&&!a.cwd&&o.cwd?a.cwd=o.cwd:this._optimisticSessions.delete(n)}else e.push(o);const t=this.virtualSessionInfo;return t&&!s.has(t.path)&&e.push(t),e}get optimisticSessions(){return Array.from(this._optimisticSessions.values())}async deleteSession(e){await this.api.deleteSession(e)}async switchSession(e,s){const t=++this._sessionNonce;s!==void 0&&(this._pendingCwd=s),this._pendingNewPrompt=!1,this._pendingControl=void 0,this._lastAuthoritativeControl=void 0,this._sessionPath=e,this._localAssistantMessages=[],this.clearExtensionStatuses();const n=I.basename(e,".jsonl"),o=n.split("_");this._sessionId=o.length>1?o.slice(1).join("_"):n,this._sessionStatus="detached",this._state.messages=[],this._state.isStreaming=!1,this._pendingToolCallIds.clear(),this._toolCallTimings={},this._awaitingFullSync=void 0,this._state.error=void 0,await this.requestFullSessionSync(e),!(t!==this._sessionNonce||e!==this._sessionPath)&&(this._globalSessionStatus.get(e)==="running"&&(this._sessionStatus="attached",this._state.isStreaming=!0),this.emitSessionChange(),this.emitStatusChange())}async newSession(e){this._sessionNonce++,this._pendingNewPrompt=!1,this._pendingControl=void 0,this._sessionId=typeof crypto.randomUUID=="function"?crypto.randomUUID():Array.from(crypto.getRandomValues(new Uint8Array(16))).map(s=>s.toString(16).padStart(2,"0")).join("").replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/,"$1-$2-$3-$4-$5"),this._sessionPath=void 0,this._sessionName=void 0,this._localAssistantMessages=[],this.clearExtensionStatuses(),this._sessionStatus="virtual",this._pendingCwd=e,this._state.model?this.rememberAuthoritativeControl(this._state.model,this._state.thinkingLevel):this._lastAuthoritativeControl=void 0,this._state.messages=[],this._state.isStreaming=!1,this._pendingToolCallIds.clear(),this._toolCallTimings={},this._syncJson="",this._syncHash="",this._syncRevision=void 0,this._awaitingFullSync=void 0,this.clearSessionSyncQueue(),this._state.error=void 0,this.subscribeToSession(void 0),this.emitSessionChange(),this.emitStatusChange()}get virtualSessionInfo(){if(this._sessionStatus!=="virtual"||!this._pendingCwd)return;const e=new Date().toISOString();return{id:this._sessionId,path:`__virtual__${this._sessionId}`,cwd:this._pendingCwd,created:e,modified:e,lastUserPromptTime:e,messageCount:0,firstMessage:"(new session)"}}}const I={basename(i,e){const s=i.split("/").pop()||i;return e&&s.endsWith(e)?s.slice(0,-e.length):s}};export{Oe as W,G as c,Ue as f,be as g,Re as m,qe as s};
|