@thevinci/web 1.2.1 → 1.3.0
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/assets/{GitView-p2ahAsFg.js → GitView-CRSR4Udh.js} +1 -1
- package/dist/assets/{HtmlEditor-CHu9gPrY.js → HtmlEditor-Cdmqf-2N.js} +1 -1
- package/dist/assets/{JsonTreeView-DNPUiy8M.js → JsonTreeView-BHfF9Efv.js} +1 -1
- package/dist/assets/{MarkdownRendererImpl-BtNl6Se-.js → MarkdownRendererImpl--9MJLbha.js} +1 -1
- package/dist/assets/{MultiRunWindow-520sOCac.js → MultiRunWindow-BgvoIqrW.js} +1 -1
- package/dist/assets/{OnboardingScreen-DoVP7Zm9.js → OnboardingScreen-D0MEhln5.js} +1 -1
- package/dist/assets/{SettingsWindow-B86Yerqr.js → SettingsWindow-Z-EFYu7z.js} +1 -1
- package/dist/assets/{TerminalView-D3pqxDPY.js → TerminalView-Ck9CASld.js} +1 -1
- package/dist/assets/{ToolOutputDialog-B40CkAsQ.js → ToolOutputDialog-nYirsIiU.js} +1 -1
- package/dist/assets/{es-B_p_C6PU.js → es-BFs9z5Pk.js} +1 -1
- package/dist/assets/{index-DbxIdVC4.js → index-BW75F1_U.js} +1 -1
- package/dist/assets/{ko-BslW5iXu.js → ko-DfXnAsXe.js} +1 -1
- package/dist/assets/{main-0lfSGrYL.js → main-C0ZrxisB.js} +35 -35
- package/dist/assets/{main-DvKMcqtE.js → main-DZyYGTEK.js} +2 -2
- package/dist/assets/{miniChat-DsZ_1ciq.js → miniChat-BYeO3Yg4.js} +2 -2
- package/dist/assets/{modelPrefsAutoSave-Cn7yX5JT.js → modelPrefsAutoSave-BUSppnWi.js} +60 -60
- package/dist/assets/{pl-BgO82JHA.js → pl-Cks13LmZ.js} +1 -1
- package/dist/assets/{pt-BR-QJ9vjGtl.js → pt-BR-ChRbcRLR.js} +1 -1
- package/dist/assets/{renderElectronMiniChatApp-BQK3OCIO.js → renderElectronMiniChatApp-BilFShcX.js} +2 -2
- package/dist/assets/{uk-DmQyBDIS.js → uk-DOLQ485O.js} +1 -1
- package/dist/assets/{zh-CN-P6ISeynY.js → zh-CN-DYWE2Jha.js} +1 -1
- package/dist/index.html +2 -2
- package/dist/mini-chat.html +2 -2
- package/package.json +2 -1
- package/server/lib/fs/routes.js +62 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const n of document.querySelectorAll('link[rel="modulepreload"]'))o(n);new MutationObserver(n=>{for(const s of n)if(s.type==="childList")for(const c of s.addedNodes)c.tagName==="LINK"&&c.rel==="modulepreload"&&o(c)}).observe(document,{childList:!0,subtree:!0});function e(n){const s={};return n.integrity&&(s.integrity=n.integrity),n.referrerPolicy&&(s.referrerPolicy=n.referrerPolicy),n.crossOrigin==="use-credentials"?s.credentials="include":n.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function o(n){if(n.ep)return;n.ep=!0;const s=e(n);fetch(n.href,s)}})();const Y=1,p=1,j=0,V="/api/terminal/ws",tt=1200,et=250,rt=2e4,ot=5e3,P="__vinciTerminalTransportState",nt=new TextEncoder,J=new TextDecoder,N=r=>{if(/^wss?:\/\//i.test(r))return r;if(/^https?:\/\//i.test(r)){const o=new URL(r);return o.protocol=o.protocol==="https:"?"wss:":"ws:",o.toString()}if(typeof window>"u")return"";const t=r.startsWith("/")?r:`/${r}`;return`${window.location.protocol==="https:"?"wss:":"ws:"}//${window.location.host}${t}`},I=r=>{const t=nt.encode(JSON.stringify(r)),e=new Uint8Array(t.length+1);return e[0]=Y,e.set(t,1),e},E=r=>r?((r.transports??[]).includes("ws")||r.preferred==="ws")&&typeof r.ws?.path=="string"&&r.ws.path.length>0:!1,A=r=>r.streamCapability?.ws?.path??r.inputCapability?.ws?.path??V,st=r=>{switch(r){case"SESSION_NOT_FOUND":return new Error("Terminal session not found");case"NOT_BOUND":return new Error("Terminal session is not bound");case"WRITE_FAIL":return new Error("Failed to write to terminal");case"RATE_LIMIT":return new Error("Terminal websocket is rate limited");case"BAD_FRAME":return new Error("Terminal websocket protocol violation");default:return new Error("Terminal websocket error")}};class it{socket=null;socketUrl="";boundSessionId=null;requestedSessionId=null;openPromise=null;reconnectTimeout=null;keepaliveInterval=null;closed=!1;subscriptions=new Map;activeSubscriptionToken=null;configure(t){if(t){if(this.socketUrl===t){this.closed=!1,this.isConnectedOrConnecting()||this.ensureConnected();return}this.socketUrl=t,this.closed=!1,this.resetConnection(),this.ensureConnected()}}subscribe(t,e,o,n){const s=Symbol(t),c={token:s,sessionId:t,onEvent:e,onError:o,maxRetries:n?.maxRetries??3,initialRetryDelay:n?.initialRetryDelay??1e3,maxRetryDelay:n?.maxRetryDelay??8e3,connectionTimeout:n?.connectionTimeout??1e4,retryCount:0,connected:!1,connectionTimeoutId:null};return this.subscriptions.set(s,c),this.activeSubscriptionToken=s,this.boundSessionId=null,this.requestedSessionId=t,this.ensureConnected(),this.startConnectionTimeout(c),this.bindActiveSession(),()=>{this.clearConnectionTimeout(c),this.subscriptions.delete(s),this.activeSubscriptionToken===s&&(this.activeSubscriptionToken=null),this.boundSessionId===t&&(this.boundSessionId=null),this.requestedSessionId===t&&(this.requestedSessionId=null),this.subscriptions.size===0&&(this.clearReconnectTimeout(),this.resetConnection())}}async sendInput(t,e){if(!t||!e||this.closed||!this.socketUrl)return!1;const o=await this.getOpenSocket(tt);if(!o||o.readyState!==p)return!1;try{return this.boundSessionId!==t&&(this.requestedSessionId=t,o.send(I({t:"b",s:t,v:2}))),o.send(e),!0}catch{return this.handleSocketFailure(new Error("Terminal websocket send failed")),!1}}unbindSession(t){t&&(this.boundSessionId===t&&(this.boundSessionId=null),this.requestedSessionId===t&&(this.requestedSessionId=null))}close(){this.closed=!0,this.clearReconnectTimeout();for(const t of this.subscriptions.values())this.clearConnectionTimeout(t);this.resetConnection(),this.socketUrl="",this.subscriptions.clear(),this.activeSubscriptionToken=null}prime(){this.closed||!this.socketUrl||this.isConnectedOrConnecting()||this.ensureConnected()}isConnectedOrConnecting(t){return this.closed||t&&this.socketUrl!==t?!1:this.socket&&(this.socket.readyState===p||this.socket.readyState===j)?!0:this.openPromise!==null}getActiveSubscription(){return this.activeSubscriptionToken?this.subscriptions.get(this.activeSubscriptionToken)??null:null}startConnectionTimeout(t){this.clearConnectionTimeout(t),t.connectionTimeoutId=setTimeout(()=>{this.getActiveSubscription()?.token!==t.token||t.connected||this.handleSocketFailure(new Error("Connection timeout"))},t.connectionTimeout)}clearConnectionTimeout(t){t.connectionTimeoutId&&(clearTimeout(t.connectionTimeoutId),t.connectionTimeoutId=null)}async getOpenSocket(t){if(this.socket&&this.socket.readyState===p)return this.socket;if(this.ensureConnected(),this.socket&&this.socket.readyState===p)return this.socket;const e=await Promise.race([this.openPromise??Promise.resolve(null),new Promise(o=>{setTimeout(()=>o(null),t)})]);return e&&e.readyState===p?e:this.socket&&this.socket.readyState===p?this.socket:null}ensureConnected(){this.closed||!this.socketUrl||this.socket&&(this.socket.readyState===p||this.socket.readyState===j)||this.openPromise||(this.clearReconnectTimeout(),this.openPromise=new Promise(t=>{let e=!1,o=null;const n=s=>{e||(e=!0,o&&(clearTimeout(o),o=null),this.openPromise=null,t(s))};try{const s=new WebSocket(this.socketUrl);s.binaryType="arraybuffer",s.onopen=()=>{this.socket=s,this.startKeepalive(),n(s)},s.onmessage=c=>{this.handleSocketMessage(c.data)},s.onerror=()=>{!this.closed&&!this.getActiveSubscription()&&this.scheduleReconnect(new Error("Terminal websocket error"))},s.onclose=()=>{this.socket===s&&(this.socket=null,this.boundSessionId=null,this.stopKeepalive(),this.closed||this.scheduleReconnect(new Error("Terminal stream connection error"))),n(null)},this.socket=s,o=setTimeout(()=>{s.readyState===j&&(s.close(),n(null))},ot)}catch{n(null),this.closed||this.scheduleReconnect(new Error("Terminal websocket open failed"))}}))}bindActiveSession(){const t=this.getActiveSubscription();if(!(!t||!this.socket||this.socket.readyState!==p)){this.requestedSessionId=t.sessionId;try{this.socket.send(I({t:"b",s:t.sessionId,v:2}))}catch{this.handleSocketFailure(new Error("Terminal websocket bind failed"))}}}scheduleReconnect(t){if(this.closed||!this.socketUrl||this.reconnectTimeout)return;const e=this.getActiveSubscription();if(!e)return;const o=e.retryCount+1,n=e.initialRetryDelay,s=e.maxRetryDelay,c=e.maxRetries;if(o>c){this.clearConnectionTimeout(e),e.onError?.(t,!0);return}e.retryCount=o,e.connected=!1,e.onEvent({type:"reconnecting",attempt:o,maxAttempts:c}),this.startConnectionTimeout(e);const f=Math.min(n*Math.pow(2,Math.max(o-1,0)),s),l=Math.floor(Math.random()*et),h=f+l;this.reconnectTimeout=setTimeout(()=>{this.reconnectTimeout=null,this.ensureConnected(),this.bindActiveSession()},h)}clearReconnectTimeout(){this.reconnectTimeout&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=null)}sendControl(t){if(!this.socket||this.socket.readyState!==p)return!1;try{return this.socket.send(I(t)),!0}catch{return this.handleSocketFailure(new Error("Terminal websocket control send failed")),!1}}startKeepalive(){this.stopKeepalive(),this.keepaliveInterval=setInterval(()=>{this.closed||this.sendControl({t:"p",v:2})},rt)}stopKeepalive(){this.keepaliveInterval&&(clearInterval(this.keepaliveInterval),this.keepaliveInterval=null)}async handleSocketMessage(t){const e=await this.asUint8Array(t);if(e&&e.length>0&&e[0]===Y){this.handleControlMessage(e);return}const o=await this.asText(t);if(!o)return;const n=this.getActiveSubscription();n&&n.onEvent({type:"data",data:o})}handleControlMessage(t){if(t.length<2)return;let e;try{e=JSON.parse(J.decode(t.subarray(1)))}catch{this.handleSocketFailure(new Error("Terminal websocket control parse failed"));return}const o=this.getActiveSubscription();switch(e.t){case"ok":this.bindActiveSession();return;case"po":return;case"bok":{if(this.boundSessionId=e.s??this.requestedSessionId,!o)return;o.retryCount=0,o.connected=!0,this.clearConnectionTimeout(o),o.onEvent({type:"connected",runtime:e.runtime,ptyBackend:e.ptyBackend});return}case"x":{if(!o){this.boundSessionId=null;return}if(e.s&&e.s!==o.sessionId)return;o.connected=!1,this.clearConnectionTimeout(o),this.boundSessionId=null,this.requestedSessionId=null,o.onEvent({type:"exit",exitCode:e.exitCode,signal:e.signal??null});return}case"e":{const n=st(e.c),s=e.f===!0||e.c==="SESSION_NOT_FOUND";(e.c==="NOT_BOUND"||e.c==="SESSION_NOT_FOUND")&&(this.boundSessionId=null),o&&(o.connected=!1,s&&this.clearConnectionTimeout(o),o.onError?.(n,s)),e.f===!0&&this.handleSocketFailure(n);return}default:return}}async asUint8Array(t){if(t instanceof ArrayBuffer)return new Uint8Array(t);if(t instanceof Uint8Array)return t;if(typeof Blob<"u"&&t instanceof Blob){const e=await t.arrayBuffer();return new Uint8Array(e)}return null}async asText(t){if(typeof t=="string")return t;const e=await this.asUint8Array(t);return e?J.decode(e):""}handleSocketFailure(t){this.boundSessionId=null,this.requestedSessionId=null,this.resetConnection(),this.scheduleReconnect(t)}resetConnection(){if(this.openPromise=null,this.stopKeepalive(),this.socket){const t=this.socket;this.socket=null,t.onopen=null,t.onmessage=null,t.onerror=null,t.onclose=null,(t.readyState===p||t.readyState===j)&&t.close()}this.boundSessionId=null}}const y=()=>{const r=globalThis;return r[P]||(r[P]={inputCapability:null,streamCapability:null,manager:null}),r[P]},$=()=>{const r=y();return r.manager||(r.manager=new it),r.manager},Q=r=>{const t=y();if(t.inputCapability=r?.input??null,t.streamCapability=r?.stream??null,!E(t.inputCapability)&&!E(t.streamCapability)){t.manager?.close(),t.manager=null;return}const e=N(A(t));if(!e)return;$().configure(e)},at=async(r,t)=>{const e=await fetch(`/api/terminal/${r}/input`,{method:"POST",headers:{"Content-Type":"text/plain"},body:t});if(!e.ok){const o=await e.json().catch(()=>({error:"Failed to send terminal input"}));throw new Error(o.error||"Failed to send terminal input")}};async function ct(r){const t=await fetch("/api/terminal/create",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cwd:r.cwd,cols:r.cols??80,rows:r.rows??24})});if(!t.ok){const o=await t.json().catch(()=>({error:"Failed to create terminal"}));throw new Error(o.error||"Failed to create terminal session")}const e=await t.json();return Q(e.capabilities),e}const U=(r,t,e,o={})=>{const n=o.maxRetries??3,s=o.initialRetryDelay??1e3,c=o.maxRetryDelay??8e3,f=o.connectionTimeout??1e4;let l=null,h=0,w=null,T=null,m=!1,g=!1;const x=()=>{w&&(clearTimeout(w),w=null),T&&(clearTimeout(T),T=null)},F=()=>{m||(m=!0,x(),l&&(l.close(),l=null))},_=(b,k)=>{if(!(m||g)){if(h<n&&!k){h+=1;const S=Math.min(s*Math.pow(2,h-1),c);t({type:"reconnecting",attempt:h,maxAttempts:n}),w=setTimeout(()=>{!m&&!g&&D()},S);return}e?.(b,!0),F()}},D=()=>{if(m||g||l&&l.readyState!==EventSource.CLOSED)return;l=new EventSource(`/api/terminal/${r}/stream`);let b=!1;T=setTimeout(()=>{!b&&l?.readyState!==EventSource.OPEN&&(l?.close(),_(new Error("Connection timeout"),!1))},f),l.onopen=()=>{b||(b=!0,h=0,x(),t({type:"connected"}))},l.onmessage=k=>{try{const S=JSON.parse(k.data);S.type==="exit"&&(y().manager?.unbindSession(r),g=!0,F()),t(S)}catch(S){e?.(S,!1)}},l.onerror=()=>{x();const k=g||l?.readyState===EventSource.CLOSED;l?.close(),l=null,g||_(new Error("Terminal stream connection error"),k)}};return D(),F};function lt(r,t,e,o={}){const n=y();if(!E(n.streamCapability))return U(r,t,e,o);const s=$(),c=N(A(n));return c?(s.configure(c),s.subscribe(r,t,e,o)):U(r,t,e,o)}async function ut(r,t){const e=y();e.manager&&await e.manager.sendInput(r,t)||await at(r,t)}async function ht(r,t,e){const o=await fetch(`/api/terminal/${r}/resize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cols:t,rows:e})});if(!o.ok){const n=await o.json().catch(()=>({error:"Failed to resize terminal"}));throw new Error(n.error||"Failed to resize terminal")}}async function dt(r){y().manager?.unbindSession(r);const t=await fetch(`/api/terminal/${r}`,{method:"DELETE"});if(!t.ok){const e=await t.json().catch(()=>({error:"Failed to close terminal"}));throw new Error(e.error||"Failed to close terminal")}}async function ft(r,t){y().manager?.unbindSession(r);const e=await fetch(`/api/terminal/${r}/restart`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cwd:t.cwd,cols:t.cols??80,rows:t.rows??24})});if(!e.ok){const n=await e.json().catch(()=>({error:"Failed to restart terminal"}));throw new Error(n.error||"Failed to restart terminal")}const o=await e.json();return Q(o.capabilities),o}async function pt(r){const t=await fetch("/api/terminal/force-kill",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});if(!t.ok){const e=await t.json().catch(()=>({error:"Failed to force kill terminal"}));throw new Error(e.error||"Failed to force kill terminal")}r.sessionId&&y().manager?.unbindSession(r.sessionId)}function Ce(){const r=y();if(r.inputCapability&&r.streamCapability&&!E(r.inputCapability)&&!E(r.streamCapability))return;const t=A(r)||V,e=N(t);if(!e)return;const o=$();o.isConnectedOrConnecting(e)||(o.configure(e),o.prime())}const wt=r=>{const t=r?.retry;return{maxRetries:t?.maxRetries??3,initialRetryDelay:t?.initialDelayMs??1e3,maxRetryDelay:t?.maxDelayMs??8e3,connectionTimeout:r?.connectionTimeoutMs??1e4}},yt=()=>({async createSession(r){return ct(r)},connect(r,t,e){const o=lt(r,t.onEvent,t.onError,wt(e));return{close:()=>o()}},async sendInput(r,t){await ut(r,t)},async resize(r){await ht(r.sessionId,r.cols,r.rows)},async close(r){await dt(r)},async restartSession(r,t){return ft(r,{cwd:t.cwd??"",cols:t.cols,rows:t.rows})},async forceKill(r){await pt(r)}}),mt=()=>{if(typeof window>"u")return"";const r=window.__APP_DESKTOP_SERVER__?.origin;return r||window.location.origin},i="/api/git",gt=1200,Tt=5e3,W=new Map,C=new Map,M=new Map,O=new Map,R=r=>r.trim();function a(r,t,e){const o=new URL(r,mt());if(t&&o.searchParams.set("directory",t),e)for(const[n,s]of Object.entries(e))s!==void 0&&o.searchParams.set(n,String(s));return o.toString()}async function St(r){const t=R(r),e=Date.now(),o=M.get(t);if(o&&o.expiresAt>e)return o.value;const n=O.get(t);if(n)return n;const s=(async()=>{const c=await fetch(a(`${i}/check`,r));if(!c.ok)throw new Error(`Failed to check git repository: ${c.statusText}`);const l=!!(await c.json()).isGitRepository;return M.set(t,{value:l,expiresAt:Date.now()+Tt}),l})();O.set(t,s);try{return await s}finally{O.get(t)===s&&O.delete(t)}}async function bt(r,t){const e=t?.mode,o=e==="light"?`${R(r)}::light`:R(r),n=Date.now(),s=W.get(o);if(s&&s.expiresAt>n)return s.value;const c=C.get(o);if(c)return c;const f=(async()=>{const l=await fetch(a(`${i}/status`,r,e?{mode:e}:void 0));if(!l.ok)throw new Error(`Failed to get git status: ${l.statusText}`);const h=await l.json();return W.set(o,{value:h,expiresAt:Date.now()+gt}),h})();C.set(o,f);try{return await f}finally{C.get(o)===f&&C.delete(o)}}async function kt(r,t){const{path:e,staged:o,contextLines:n}=t;if(!e)throw new Error("path is required to fetch git diff");const s=await fetch(a(`${i}/diff`,r,{path:e,staged:o?"true":void 0,context:n}));if(!s.ok)throw new Error(`Failed to get git diff: ${s.statusText}`);return s.json()}async function Et(r,t){const{path:e,staged:o}=t;if(!e)throw new Error("path is required to fetch git file diff");const n=await fetch(a(`${i}/file-diff`,r,{path:e,staged:o?"true":void 0}));if(!n.ok)throw new Error(`Failed to get git file diff: ${n.statusText}`);return n.json()}async function jt(r,t){if(!t)throw new Error("path is required to revert git changes");const e=await fetch(a(`${i}/revert`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t})});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to revert git changes")}}async function Ct(r){if(!r)return!1;const t=await fetch(a(`${i}/worktree-type`,r));if(!t.ok)throw new Error(`Failed to detect worktree type: ${t.statusText}`);return!!(await t.json()).linked}async function Ot(r){const t=await fetch(a(`${i}/branches`,r));if(!t.ok)throw new Error(`Failed to get branches: ${t.statusText}`);return t.json()}async function vt(r,t){if(!t?.branch)throw new Error("branch is required to delete a branch");const e=await fetch(a(`${i}/branches`,r),{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to delete branch")}return e.json()}async function xt(r,t){if(!t?.branch)throw new Error("branch is required to delete remote branch");const e=await fetch(a(`${i}/remote-branches`,r),{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to delete remote branch")}return e.json()}async function Ft(r,t){const e=t?.remote?.trim();if(!e)throw new Error("remote is required to remove a remote");const o=await fetch(a(`${i}/remotes`,r),{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify({remote:e})});if(!o.ok){const n=await o.json().catch(()=>({error:o.statusText}));throw new Error(n.error||"Failed to remove remote")}return o.json()}async function Pt(r,t,e){if(!Array.isArray(t)||t.length===0)throw new Error("No files provided to generate commit message");const o={files:t};e?.zenModel&&(o.zenModel=e.zenModel),e?.providerId&&(o.providerId=e.providerId),e?.modelId&&(o.modelId=e.modelId);const n=await fetch(a(`${i}/commit-message`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)});if(!n.ok){const l=await n.json().catch(()=>({error:n.statusText}));console.error("[git-generation][browser] http error",{status:n.status,statusText:n.statusText,error:l});const h=typeof l?.traceId=="string"&&l.traceId?` (traceId: ${l.traceId})`:"";throw new Error(`${l.error||"Failed to generate commit message"}${h}`)}const s=await n.json();if(!s?.message||typeof s.message!="object")throw new Error("Malformed commit generation response");const c=typeof s.message.subject=="string"&&s.message.subject.trim().length>0?s.message.subject.trim():"",f=Array.isArray(s.message.highlights)?s.message.highlights.filter(l=>typeof l=="string"&&l.trim().length>0).map(l=>l.trim()):[];return{message:{subject:c,highlights:f}}}async function It(r,t){const{base:e,head:o,context:n,zenModel:s,providerId:c,modelId:f}=t;if(!e||!o)throw new Error("base and head are required");const l={base:e,head:o};n?.trim()&&(l.context=n.trim()),s&&(l.zenModel=s),c&&(l.providerId=c),f&&(l.modelId=f);const h=await fetch(a(`${i}/pr-description`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(l)});if(!h.ok){const g=await h.json().catch(()=>({error:h.statusText}));throw new Error(g.error||"Failed to generate PR description")}const w=await h.json().catch(()=>null),T=typeof w?.title=="string"?w.title:"",m=typeof w?.body=="string"?w.body:"";if(!T&&!m)throw new Error("Malformed PR description response");return{title:T,body:m}}async function L(r){const t=await fetch(a(`${i}/worktrees`,r));if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to list worktrees")}return t.json()}async function B(r,t){const e=await fetch(a(`${i}/worktrees/validate`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t??{})});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to validate worktree")}return e.json()}async function Oe(r){const t=await fetch(a(`${i}/worktrees/bootstrap-status`,r));if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to get worktree bootstrap status")}return t.json()}async function ve(r,t){const e=await fetch(a(`${i}/worktrees/preview`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t??{})});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to preview worktree")}return e.json()}async function q(r,t){const e=await fetch(a(`${i}/worktrees`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t??{})});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to create worktree")}return e.json()}async function z(r,t){const e=await fetch(a(`${i}/worktrees`,r),{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify(t??{})});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to delete worktree")}return e.json()}async function Rt(r,t,e={}){const o=await fetch(a(`${i}/commit`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({message:t,addAll:e.addAll??!1,files:e.files})});if(!o.ok){const n=await o.json().catch(()=>({error:o.statusText}));throw new Error(n.error||"Failed to create commit")}return o.json()}async function Nt(r,t={}){const e=await fetch(a(`${i}/push`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to push")}return e.json()}async function At(r,t={}){const e=await fetch(a(`${i}/pull`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to pull")}return e.json()}async function $t(r,t={}){const e=await fetch(a(`${i}/fetch`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to fetch")}return e.json()}async function Gt(r){const t=await fetch(a(`${i}/stashes`,r));if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to list stashes")}return t.json()}async function _t(r,t){const e=await fetch(a(`${i}/stashes/file-counts`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refs:t})});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to count stash files")}return e.json()}async function X(r,t={}){const e=await fetch(a(`${i}/stash`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to stash changes")}return e.json()}const G=async(r,t,e)=>{const o=await fetch(a(`${i}/${t}`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!o.ok){const n=await o.json().catch(()=>({error:o.statusText}));throw new Error(n.error||`Failed to ${t}`)}return o.json()},Dt=(r,t)=>G(r,"stash/apply",t),Z=(r,t)=>G(r,"stash/pop",t),Jt=(r,t)=>G(r,"stash/drop",t);async function Ut(r,t){const e=await fetch(a(`${i}/checkout`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({branch:t})});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to checkout branch")}return e.json()}async function Wt(r,t,e){const o=await fetch(a(`${i}/branches`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:t,startPoint:e})});if(!o.ok){const n=await o.json().catch(()=>({error:o.statusText}));throw new Error(n.error||"Failed to create branch")}return o.json()}async function Mt(r,t,e){const o=await fetch(a(`${i}/branches/rename`,r),{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldName:t,newName:e})});if(!o.ok){const n=await o.json().catch(()=>({error:o.statusText}));throw new Error(n.error||"Failed to rename branch")}return o.json()}async function Lt(r,t={}){const e=await fetch(a(`${i}/log`,r,{maxCount:t.maxCount,from:t.from,to:t.to,file:t.file}));if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(`Failed to get git log: ${o.error||e.statusText}`)}return e.json()}async function Bt(r,t){const e=await fetch(a(`${i}/commit-files`,r,{hash:t}));if(!e.ok)throw new Error(`Failed to get commit files: ${e.statusText}`);return e.json()}async function xe(r,t,e,o){const n=await fetch(a(`${i}/commit-file-diff`,r,{hash:t,path:e,binary:o?"true":void 0}));if(!n.ok)throw new Error(`Failed to get commit file diff: ${n.statusText}`);return n.json()}async function qt(){const r=await fetch(a(`${i}/identities`,void 0));if(!r.ok)throw new Error(`Failed to get git identities: ${r.statusText}`);return r.json()}async function zt(r){const t=await fetch(a(`${i}/identities`,void 0),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to create git identity")}return t.json()}async function Kt(r,t){const e=await fetch(a(`${i}/identities/${r}`,void 0),{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to update git identity")}return e.json()}async function Ht(r){const t=await fetch(a(`${i}/identities/${r}`,void 0),{method:"DELETE"});if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to delete git identity")}}async function Yt(r){if(!r)return null;const t=await fetch(a(`${i}/current-identity`,r));if(!t.ok)throw new Error(`Failed to get current git identity: ${t.statusText}`);const e=await t.json();return e?{userName:e.userName??null,userEmail:e.userEmail??null,sshCommand:e.sshCommand??null}:null}async function Vt(r){if(!r)return!1;const t=await fetch(a(`${i}/has-local-identity`,r));if(!t.ok)throw new Error(`Failed to check local identity: ${t.statusText}`);return(await t.json().catch(()=>null))?.hasLocalIdentity===!0}async function Fe(){const r=await fetch(a(`${i}/global-identity`,void 0));if(!r.ok)throw new Error(`Failed to get global git identity: ${r.statusText}`);const t=await r.json();return!t||!t.userName&&!t.userEmail?null:{userName:t.userName??null,userEmail:t.userEmail??null,sshCommand:t.sshCommand??null}}async function Qt(r,t){const e=await fetch(a(`${i}/set-identity`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:t})});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to set git identity")}return e.json()}async function Pe(){const r=await fetch(a(`${i}/discover-credentials`,void 0));if(!r.ok)throw new Error(`Failed to discover git credentials: ${r.statusText}`);return r.json()}async function Ie(r,t){if(!r)return null;const e=await fetch(a(`${i}/remote-url`,r,{remote:t}));return e.ok?(await e.json()).url??null:null}async function Xt(r){const t=await fetch(a(`${i}/remotes`,r));if(!t.ok)throw new Error(`Failed to get remotes: ${t.statusText}`);return t.json()}async function Zt(r,t){const e=await fetch(a(`${i}/rebase`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to rebase")}return e.json()}async function te(r){const t=await fetch(a(`${i}/rebase/abort`,r),{method:"POST"});if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to abort rebase")}return t.json()}async function ee(r,t){const e=await fetch(a(`${i}/merge`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to merge")}return e.json()}async function re(r){const t=await fetch(a(`${i}/merge/abort`,r),{method:"POST"});if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to abort merge")}return t.json()}async function oe(r){const t=await fetch(a(`${i}/rebase/continue`,r),{method:"POST"});if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to continue rebase")}return t.json()}async function ne(r){const t=await fetch(a(`${i}/merge/continue`,r),{method:"POST"});if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to continue merge")}return t.json()}async function se(r,t){return await X(r,{message:t?.message}),{success:!0}}async function ie(r){return await Z(r,{ref:"stash@{0}"}),{success:!0}}async function ae(r){const t=await fetch(a(`${i}/conflict-details`,r));if(!t.ok)throw new Error(`Failed to get conflict details: ${t.statusText}`);return t.json()}async function ce(r,t){const e=await fetch(`${i}/validate-directory`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({directory:r,worktreeRoot:t})});if(!e.ok)throw new Error(`Failed to validate worktree directory: ${e.statusText}`);return e.json()}async function le(r){const t=await fetch(`${i}/canonicalize-worktree-state`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({directory:r})});if(!t.ok)throw new Error(`Failed to canonicalize worktree state: ${t.statusText}`);return t.json()}const ue=()=>({checkIsGitRepository:St,getGitStatus:bt,getGitDiff:kt,getGitFileDiff:Et,revertGitFile:jt,isLinkedWorktree:Ct,getGitBranches:Ot,deleteGitBranch:vt,deleteRemoteBranch:xt,removeRemote:Ft,generateCommitMessage:Pt,generatePullRequestDescription:It,listGitWorktrees:L,validateGitWorktree:B,createGitWorktree:q,deleteGitWorktree:z,validateWorktreeDirectory:ce,canonicalizeWorktreeState:le,createGitCommit(r,t,e){return Rt(r,t,e)},gitPush:Nt,gitPull:At,gitFetch:$t,listGitStashes:Gt,countGitStashFiles:_t,stashGitChanges:X,applyGitStash:Dt,popGitStash:Z,dropGitStash:Jt,checkoutBranch:Ut,createBranch:Wt,renameBranch:Mt,getGitLog(r,t){return Lt(r,t)},getCommitFiles:Bt,getCurrentGitIdentity:Yt,hasLocalIdentity:Vt,setGitIdentity:Qt,getGitIdentities:qt,createGitIdentity:zt,updateGitIdentity:Kt,deleteGitIdentity:Ht,getRemotes:Xt,rebase:Zt,abortRebase:te,continueRebase:oe,merge:ee,abortMerge:re,continueMerge:ne,stash:se,stashPop:ie,getConflictDetails:ae,worktree:{list:L,validate:B,create:q,remove:z}}),d=r=>r.replace(/\\/g,"/"),he=(r,t)=>{const e=d(t?.directory||t?.path||r),o=Array.isArray(t?.entries)?t.entries:[];return{directory:e,entries:o.filter(n=>!!(n&&typeof n.name=="string"&&typeof n.path=="string")).map(n=>({name:n.name,path:d(n.path),isDirectory:!!n.isDirectory}))}},de=()=>({async listDirectory(r){const t=d(r),e=new URLSearchParams;t&&e.set("path",t);const o=await fetch(`/api/fs/list${e.toString()?`?${e.toString()}`:""}`);if(!o.ok){const s=await o.json().catch(()=>({error:o.statusText}));throw new Error(s.error||"Failed to list directory")}const n=await o.json();return he(t,n)},async search(r){const t=new URLSearchParams,e=d(r.directory);e&&t.set("directory",e),t.set("query",r.query),t.set("dirs","false"),t.set("type","file"),typeof r.maxResults=="number"&&Number.isFinite(r.maxResults)&&t.set("limit",String(r.maxResults));const o=await fetch(`/api/find/file?${t.toString()}`);if(!o.ok){const c=await o.json().catch(()=>({error:o.statusText}));throw new Error(c.error||"Failed to search files")}const n=await o.json();return(Array.isArray(n)?n:[]).map(c=>({path:d(`${e}/${c}`),preview:[d(c)]}))},async createDirectory(r){const t=d(r),e=await fetch("/api/fs/mkdir",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t})});if(!e.ok){const n=await e.json().catch(()=>({error:e.statusText}));throw new Error(n.error||"Failed to create directory")}const o=await e.json();return{success:!!o?.success,path:typeof o?.path=="string"?d(o.path):t}},async statFile(r,t){const e=d(r),o=new URLSearchParams({path:e});t?.allowOutsideWorkspace&&o.set("allowOutsideWorkspace","true");const n=await fetch(`/api/fs/stat?${o.toString()}`);if(!n.ok){const c=await n.json().catch(()=>({error:n.statusText}));throw new Error(c.error||"Failed to stat file")}const s=await n.json().catch(()=>({}));return{path:typeof s.path=="string"?d(s.path):e,isFile:!!s.isFile,size:typeof s.size=="number"?s.size:0,mtimeMs:typeof s.mtimeMs=="number"?s.mtimeMs:void 0}},async readFile(r,t){const e=d(r),o=new URLSearchParams({path:e});t?.allowOutsideWorkspace&&o.set("allowOutsideWorkspace","true"),t?.optional&&o.set("optional","true");const n=await fetch(`/api/fs/read?${o.toString()}`,{cache:t?.optional?"no-store":"default"});if(!n.ok){const c=await n.json().catch(()=>({error:n.statusText}));throw new Error(c.error||"Failed to read file")}return{content:await n.text(),path:e}},async writeFile(r,t){const e=d(r),o=await fetch("/api/fs/write",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e,content:t})});if(!o.ok){const s=await o.json().catch(()=>({error:o.statusText}));throw new Error(s.error||"Failed to write file")}const n=await o.json().catch(()=>({}));return{success:!!n.success,path:typeof n.path=="string"?d(n.path):e}},async delete(r){const t=d(r),e=await fetch("/api/fs/delete",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t})});if(!e.ok){const n=await e.json().catch(()=>({error:e.statusText}));throw new Error(n.error||"Failed to delete file")}return{success:!!(await e.json().catch(()=>({}))).success}},async rename(r,t){const e=await fetch("/api/fs/rename",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldPath:r,newPath:t})});if(!e.ok){const n=await e.json().catch(()=>({error:e.statusText}));throw new Error(n.error||"Failed to rename file")}const o=await e.json().catch(()=>({}));return{success:!!o.success,path:typeof o.path=="string"?d(o.path):t}},async revealPath(r){const t=await fetch("/api/fs/reveal",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:d(r)})});if(!t.ok){const o=await t.json().catch(()=>({error:t.statusText}));throw new Error(o.error||"Failed to reveal path")}return{success:!!(await t.json().catch(()=>({}))).success}},async downloadFile(r){const t=d(r),e=`/api/fs/raw?path=${encodeURIComponent(t)}&download=true`,o=document.createElement("a");o.href=e,o.download=t.split("/").pop()||"file",document.body.appendChild(o),o.click(),document.body.removeChild(o)}}),K="/api/config/settings",fe="/api/config/reload",H=r=>!r||typeof r!="object"?{}:r,pe=()=>({async load(){const r=await fetch(K,{method:"GET",headers:{Accept:"application/json"}});if(!r.ok)throw new Error(`Failed to load settings: ${r.statusText}`);return{settings:H(await r.json().catch(()=>({}))),source:"web"}},async save(r){const t=await fetch(K,{method:"PUT",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(r)});if(!t.ok){const o=await t.json().catch(()=>({error:t.statusText}));throw new Error(o.error||"Failed to save settings")}return H(await t.json().catch(()=>({})))},async restartOpenCode(){const r=await fetch(fe,{method:"POST"});if(!r.ok){const t=await r.json().catch(()=>({error:r.statusText}));throw new Error(t.error||"Failed to restart OpenCode")}return{restarted:!0}}}),we=()=>({async requestDirectoryAccess(r){return{success:!0,path:r.path}},async startAccessingDirectory(r){return{success:!0}},async stopAccessingDirectory(r){return{success:!0}}}),ye=1500,me=async()=>{if(typeof navigator>"u"||!("serviceWorker"in navigator))return null;let r=null;try{r=await navigator.serviceWorker.getRegistration()??null}catch{r=null}if(r?.active)return r;if(!r)return null;try{return await Promise.race([navigator.serviceWorker.ready,new Promise(e=>{setTimeout(()=>e(null),ye)})])??r}catch{return r}},ge=async r=>{const t=await me();if(!t||typeof t.showNotification!="function")return!1;try{return await t.showNotification(r?.title??"Vinci",{body:r?.body,tag:r?.tag}),!0}catch(e){return console.warn("Failed to send notification via service worker",e),!1}},Te=async r=>{if(typeof Notification>"u")return console.info("Notifications not supported in this environment",r),!1;if(Notification.permission==="default"&&await Notification.requestPermission()!=="granted"||Notification.permission!=="granted")return console.warn("Notification permission not granted"),!1;try{return await ge(r)||new Notification(r?.title??"Vinci",{body:r?.body,tag:r?.tag}),!0}catch(t){return console.warn("Failed to send notification",t),!1}},Se=async r=>{if(typeof window>"u")return!1;const t=window.__TAURI__;if(!t?.core?.invoke)return!1;try{return await t.core.invoke("desktop_notify",{payload:{title:r?.title,body:r?.body,tag:r?.tag}}),!0}catch(e){return console.warn("Failed to send native notification (tauri)",e),!1}},be=()=>({async notifyAgentCompletion(r){return await Se(r)||await Te(r)},canNotify:()=>typeof window<"u"&&window.__TAURI__?.core?.invoke?!0:typeof Notification<"u"?Notification.permission==="granted":!1}),ke=()=>({async getAvailableTools(){const r=await fetch("/api/experimental/tool/ids");if(!r.ok)throw new Error(`Tools API returned ${r.status} ${r.statusText}`);const t=await r.json();if(!Array.isArray(t))throw new Error("Tools API returned invalid data format");return t.filter(e=>typeof e=="string"&&e!=="invalid").sort()}}),v=async(r,t)=>{try{const e=await fetch(r,{...t,credentials:"include",headers:{Accept:"application/json",...t?.headers??{}}});return e.ok?await e.json():null}catch{return null}},Ee=()=>({async getVapidPublicKey(){return v("/api/push/vapid-public-key")},async subscribe(r){return v("/api/push/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)})},async unsubscribe(r){return v("/api/push/subscribe",{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)})},async setVisibility(r){return v("/api/push/visibility",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),keepalive:!0})}}),u=async r=>await r.json().catch(()=>null),je=()=>({async authStatus(){const r=await fetch("/api/github/auth/status",{method:"GET",headers:{Accept:"application/json"}}),t=await u(r);if(!r.ok||!t)throw new Error(t?.error||r.statusText||"Failed to load GitHub status");return t},async authStart(){const r=await fetch("/api/github/auth/start",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({})}),t=await u(r);if(!r.ok||!t||!("deviceCode"in t))throw new Error(t?.error||r.statusText||"Failed to start GitHub auth");return t},async authComplete(r){const t=await fetch("/api/github/auth/complete",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({deviceCode:r})}),e=await u(t);if(!t.ok||!e)throw new Error(e?.error||t.statusText||"Failed to complete GitHub auth");return e},async authDisconnect(){const r=await fetch("/api/github/auth",{method:"DELETE",headers:{Accept:"application/json"}}),t=await u(r);if(!r.ok)throw new Error(t?.error||r.statusText||"Failed to disconnect GitHub");return{removed:!!t?.removed}},async authActivate(r){const t=await fetch("/api/github/auth/activate",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({accountId:r})}),e=await u(t);if(!t.ok||!e)throw new Error(e?.error||t.statusText||"Failed to activate GitHub account");return e},async me(){const r=await fetch("/api/github/me",{method:"GET",headers:{Accept:"application/json"}}),t=await u(r);if(!r.ok||!t)throw new Error(t?.error||r.statusText||"Failed to fetch GitHub user");return t},async prStatus(r,t,e,o){const n=new URLSearchParams({directory:r,branch:t,...e?{remote:e}:{},...o?.force?{force:"true"}:{}}),s=await fetch(`/api/github/pr/status?${n.toString()}`,{method:"GET",headers:{Accept:"application/json"}}),c=await u(s);if(!s.ok||!c)throw new Error(c?.error||s.statusText||"Failed to load PR status");return c},async prCreate(r){const t=await fetch("/api/github/pr/create",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(r)}),e=await u(t);if(!t.ok||!e)throw new Error(e?.error||t.statusText||"Failed to create PR");return e},async prUpdate(r){const t=await fetch("/api/github/pr/update",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(r)}),e=await u(t);if(!t.ok||!e)throw new Error(e?.error||t.statusText||"Failed to update PR");return e},async prMerge(r){const t=await fetch("/api/github/pr/merge",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(r)}),e=await u(t);if(!t.ok||!e)throw new Error(e?.error||t.statusText||"Failed to merge PR");return e},async prReady(r){const t=await fetch("/api/github/pr/ready",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(r)}),e=await u(t);if(!t.ok||!e)throw new Error(e?.error||t.statusText||"Failed to mark PR ready");return e},async repoUpstream(r){const t=await fetch(`/api/github/repo/upstream?directory=${encodeURIComponent(r)}`,{method:"GET",headers:{Accept:"application/json"}}),e=await u(t);if(!t.ok||!e)throw new Error(e?.error||t.statusText||"Failed to detect upstream repo");return e},async repoBranches(r,t){const e=await fetch(`/api/github/repo/branches?owner=${encodeURIComponent(r)}&repo=${encodeURIComponent(t)}`,{method:"GET",headers:{Accept:"application/json"}}),o=await u(e);if(!e.ok||!o)throw new Error(o?.error||e.statusText||"Failed to fetch repo branches");return o.branches??[]},async prsList(r,t){const e=t?.page??1,o=await fetch(`/api/github/pulls/list?directory=${encodeURIComponent(r)}&page=${encodeURIComponent(String(e))}`,{method:"GET",headers:{Accept:"application/json"}}),n=await u(o);if(!o.ok||!n)throw new Error(n?.error||o.statusText||"Failed to load pull requests");return n},async prContext(r,t,e){const o=new URL("/api/github/pulls/context",window.location.origin);o.searchParams.set("directory",r),o.searchParams.set("number",String(t)),e?.includeDiff&&o.searchParams.set("diff","1"),e?.includeCheckDetails&&o.searchParams.set("checkDetails","1"),e?.sourceRepo?.owner&&e.sourceRepo.repo&&(o.searchParams.set("owner",e.sourceRepo.owner),o.searchParams.set("repo",e.sourceRepo.repo));const n=await fetch(o.toString(),{method:"GET",headers:{Accept:"application/json"}}),s=await u(n);if(!n.ok||!s)throw new Error(s?.error||n.statusText||"Failed to load pull request context");return s},async issuesList(r,t){const e=t?.page??1,o=await fetch(`/api/github/issues/list?directory=${encodeURIComponent(r)}&page=${encodeURIComponent(String(e))}`,{method:"GET",headers:{Accept:"application/json"}}),n=await u(o);if(!o.ok||!n)throw new Error(n?.error||o.statusText||"Failed to load issues");return n},async issueGet(r,t,e){const o=new URL("/api/github/issues/get",window.location.origin);o.searchParams.set("directory",r),o.searchParams.set("number",String(t)),e?.sourceRepo?.owner&&e.sourceRepo.repo&&(o.searchParams.set("owner",e.sourceRepo.owner),o.searchParams.set("repo",e.sourceRepo.repo));const n=await fetch(o.toString(),{method:"GET",headers:{Accept:"application/json"}}),s=await u(n);if(!n.ok||!s)throw new Error(s?.error||n.statusText||"Failed to load issue");return s},async issueComments(r,t,e){const o=new URL("/api/github/issues/comments",window.location.origin);o.searchParams.set("directory",r),o.searchParams.set("number",String(t)),e?.sourceRepo?.owner&&e.sourceRepo.repo&&(o.searchParams.set("owner",e.sourceRepo.owner),o.searchParams.set("repo",e.sourceRepo.repo));const n=await fetch(o.toString(),{method:"GET",headers:{Accept:"application/json"}}),s=await u(n);if(!n.ok||!s)throw new Error(s?.error||n.statusText||"Failed to load issue comments");return s}}),Re=()=>({runtime:{platform:"web",isDesktop:!1,isVSCode:!1,label:"web"},terminal:yt(),git:ue(),files:de(),settings:pe(),permissions:we(),notifications:be(),github:je(),push:Ee(),tools:ke()});export{Qt as $,oe as A,_t as B,Wt as C,Rt as D,vt as E,Jt as F,xe as G,Bt as H,ae as I,Yt as J,kt as K,Et as L,Lt as M,Ie as N,Xt as O,$t as P,At as Q,Nt as R,Vt as S,Ct as T,Gt as U,ee as V,Z as W,Zt as X,Ft as Y,Mt as Z,jt as _,dt as a,se as a0,X as a1,ie as a2,ce as a3,Ce as a4,lt as b,Re as c,Ht as d,zt as e,pt as f,Oe as g,Pe as h,Fe as i,qt as j,St as k,bt as l,Ot as m,q as n,z as o,L as p,ve as q,xt as r,re as s,te as t,Kt as u,B as v,Dt as w,le as x,Ut as y,ne as z};
|
|
1
|
+
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const n of document.querySelectorAll('link[rel="modulepreload"]'))o(n);new MutationObserver(n=>{for(const s of n)if(s.type==="childList")for(const c of s.addedNodes)c.tagName==="LINK"&&c.rel==="modulepreload"&&o(c)}).observe(document,{childList:!0,subtree:!0});function e(n){const s={};return n.integrity&&(s.integrity=n.integrity),n.referrerPolicy&&(s.referrerPolicy=n.referrerPolicy),n.crossOrigin==="use-credentials"?s.credentials="include":n.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function o(n){if(n.ep)return;n.ep=!0;const s=e(n);fetch(n.href,s)}})();const Y=1,p=1,j=0,V="/api/terminal/ws",tt=1200,et=250,rt=2e4,ot=5e3,P="__vinciTerminalTransportState",nt=new TextEncoder,J=new TextDecoder,N=r=>{if(/^wss?:\/\//i.test(r))return r;if(/^https?:\/\//i.test(r)){const o=new URL(r);return o.protocol=o.protocol==="https:"?"wss:":"ws:",o.toString()}if(typeof window>"u")return"";const t=r.startsWith("/")?r:`/${r}`;return`${window.location.protocol==="https:"?"wss:":"ws:"}//${window.location.host}${t}`},I=r=>{const t=nt.encode(JSON.stringify(r)),e=new Uint8Array(t.length+1);return e[0]=Y,e.set(t,1),e},E=r=>r?((r.transports??[]).includes("ws")||r.preferred==="ws")&&typeof r.ws?.path=="string"&&r.ws.path.length>0:!1,A=r=>r.streamCapability?.ws?.path??r.inputCapability?.ws?.path??V,st=r=>{switch(r){case"SESSION_NOT_FOUND":return new Error("Terminal session not found");case"NOT_BOUND":return new Error("Terminal session is not bound");case"WRITE_FAIL":return new Error("Failed to write to terminal");case"RATE_LIMIT":return new Error("Terminal websocket is rate limited");case"BAD_FRAME":return new Error("Terminal websocket protocol violation");default:return new Error("Terminal websocket error")}};class it{socket=null;socketUrl="";boundSessionId=null;requestedSessionId=null;openPromise=null;reconnectTimeout=null;keepaliveInterval=null;closed=!1;subscriptions=new Map;activeSubscriptionToken=null;configure(t){if(t){if(this.socketUrl===t){this.closed=!1,this.isConnectedOrConnecting()||this.ensureConnected();return}this.socketUrl=t,this.closed=!1,this.resetConnection(),this.ensureConnected()}}subscribe(t,e,o,n){const s=Symbol(t),c={token:s,sessionId:t,onEvent:e,onError:o,maxRetries:n?.maxRetries??3,initialRetryDelay:n?.initialRetryDelay??1e3,maxRetryDelay:n?.maxRetryDelay??8e3,connectionTimeout:n?.connectionTimeout??1e4,retryCount:0,connected:!1,connectionTimeoutId:null};return this.subscriptions.set(s,c),this.activeSubscriptionToken=s,this.boundSessionId=null,this.requestedSessionId=t,this.ensureConnected(),this.startConnectionTimeout(c),this.bindActiveSession(),()=>{this.clearConnectionTimeout(c),this.subscriptions.delete(s),this.activeSubscriptionToken===s&&(this.activeSubscriptionToken=null),this.boundSessionId===t&&(this.boundSessionId=null),this.requestedSessionId===t&&(this.requestedSessionId=null),this.subscriptions.size===0&&(this.clearReconnectTimeout(),this.resetConnection())}}async sendInput(t,e){if(!t||!e||this.closed||!this.socketUrl)return!1;const o=await this.getOpenSocket(tt);if(!o||o.readyState!==p)return!1;try{return this.boundSessionId!==t&&(this.requestedSessionId=t,o.send(I({t:"b",s:t,v:2}))),o.send(e),!0}catch{return this.handleSocketFailure(new Error("Terminal websocket send failed")),!1}}unbindSession(t){t&&(this.boundSessionId===t&&(this.boundSessionId=null),this.requestedSessionId===t&&(this.requestedSessionId=null))}close(){this.closed=!0,this.clearReconnectTimeout();for(const t of this.subscriptions.values())this.clearConnectionTimeout(t);this.resetConnection(),this.socketUrl="",this.subscriptions.clear(),this.activeSubscriptionToken=null}prime(){this.closed||!this.socketUrl||this.isConnectedOrConnecting()||this.ensureConnected()}isConnectedOrConnecting(t){return this.closed||t&&this.socketUrl!==t?!1:this.socket&&(this.socket.readyState===p||this.socket.readyState===j)?!0:this.openPromise!==null}getActiveSubscription(){return this.activeSubscriptionToken?this.subscriptions.get(this.activeSubscriptionToken)??null:null}startConnectionTimeout(t){this.clearConnectionTimeout(t),t.connectionTimeoutId=setTimeout(()=>{this.getActiveSubscription()?.token!==t.token||t.connected||this.handleSocketFailure(new Error("Connection timeout"))},t.connectionTimeout)}clearConnectionTimeout(t){t.connectionTimeoutId&&(clearTimeout(t.connectionTimeoutId),t.connectionTimeoutId=null)}async getOpenSocket(t){if(this.socket&&this.socket.readyState===p)return this.socket;if(this.ensureConnected(),this.socket&&this.socket.readyState===p)return this.socket;const e=await Promise.race([this.openPromise??Promise.resolve(null),new Promise(o=>{setTimeout(()=>o(null),t)})]);return e&&e.readyState===p?e:this.socket&&this.socket.readyState===p?this.socket:null}ensureConnected(){this.closed||!this.socketUrl||this.socket&&(this.socket.readyState===p||this.socket.readyState===j)||this.openPromise||(this.clearReconnectTimeout(),this.openPromise=new Promise(t=>{let e=!1,o=null;const n=s=>{e||(e=!0,o&&(clearTimeout(o),o=null),this.openPromise=null,t(s))};try{const s=new WebSocket(this.socketUrl);s.binaryType="arraybuffer",s.onopen=()=>{this.socket=s,this.startKeepalive(),n(s)},s.onmessage=c=>{this.handleSocketMessage(c.data)},s.onerror=()=>{!this.closed&&!this.getActiveSubscription()&&this.scheduleReconnect(new Error("Terminal websocket error"))},s.onclose=()=>{this.socket===s&&(this.socket=null,this.boundSessionId=null,this.stopKeepalive(),this.closed||this.scheduleReconnect(new Error("Terminal stream connection error"))),n(null)},this.socket=s,o=setTimeout(()=>{s.readyState===j&&(s.close(),n(null))},ot)}catch{n(null),this.closed||this.scheduleReconnect(new Error("Terminal websocket open failed"))}}))}bindActiveSession(){const t=this.getActiveSubscription();if(!(!t||!this.socket||this.socket.readyState!==p)){this.requestedSessionId=t.sessionId;try{this.socket.send(I({t:"b",s:t.sessionId,v:2}))}catch{this.handleSocketFailure(new Error("Terminal websocket bind failed"))}}}scheduleReconnect(t){if(this.closed||!this.socketUrl||this.reconnectTimeout)return;const e=this.getActiveSubscription();if(!e)return;const o=e.retryCount+1,n=e.initialRetryDelay,s=e.maxRetryDelay,c=e.maxRetries;if(o>c){this.clearConnectionTimeout(e),e.onError?.(t,!0);return}e.retryCount=o,e.connected=!1,e.onEvent({type:"reconnecting",attempt:o,maxAttempts:c}),this.startConnectionTimeout(e);const f=Math.min(n*Math.pow(2,Math.max(o-1,0)),s),l=Math.floor(Math.random()*et),d=f+l;this.reconnectTimeout=setTimeout(()=>{this.reconnectTimeout=null,this.ensureConnected(),this.bindActiveSession()},d)}clearReconnectTimeout(){this.reconnectTimeout&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=null)}sendControl(t){if(!this.socket||this.socket.readyState!==p)return!1;try{return this.socket.send(I(t)),!0}catch{return this.handleSocketFailure(new Error("Terminal websocket control send failed")),!1}}startKeepalive(){this.stopKeepalive(),this.keepaliveInterval=setInterval(()=>{this.closed||this.sendControl({t:"p",v:2})},rt)}stopKeepalive(){this.keepaliveInterval&&(clearInterval(this.keepaliveInterval),this.keepaliveInterval=null)}async handleSocketMessage(t){const e=await this.asUint8Array(t);if(e&&e.length>0&&e[0]===Y){this.handleControlMessage(e);return}const o=await this.asText(t);if(!o)return;const n=this.getActiveSubscription();n&&n.onEvent({type:"data",data:o})}handleControlMessage(t){if(t.length<2)return;let e;try{e=JSON.parse(J.decode(t.subarray(1)))}catch{this.handleSocketFailure(new Error("Terminal websocket control parse failed"));return}const o=this.getActiveSubscription();switch(e.t){case"ok":this.bindActiveSession();return;case"po":return;case"bok":{if(this.boundSessionId=e.s??this.requestedSessionId,!o)return;o.retryCount=0,o.connected=!0,this.clearConnectionTimeout(o),o.onEvent({type:"connected",runtime:e.runtime,ptyBackend:e.ptyBackend});return}case"x":{if(!o){this.boundSessionId=null;return}if(e.s&&e.s!==o.sessionId)return;o.connected=!1,this.clearConnectionTimeout(o),this.boundSessionId=null,this.requestedSessionId=null,o.onEvent({type:"exit",exitCode:e.exitCode,signal:e.signal??null});return}case"e":{const n=st(e.c),s=e.f===!0||e.c==="SESSION_NOT_FOUND";(e.c==="NOT_BOUND"||e.c==="SESSION_NOT_FOUND")&&(this.boundSessionId=null),o&&(o.connected=!1,s&&this.clearConnectionTimeout(o),o.onError?.(n,s)),e.f===!0&&this.handleSocketFailure(n);return}default:return}}async asUint8Array(t){if(t instanceof ArrayBuffer)return new Uint8Array(t);if(t instanceof Uint8Array)return t;if(typeof Blob<"u"&&t instanceof Blob){const e=await t.arrayBuffer();return new Uint8Array(e)}return null}async asText(t){if(typeof t=="string")return t;const e=await this.asUint8Array(t);return e?J.decode(e):""}handleSocketFailure(t){this.boundSessionId=null,this.requestedSessionId=null,this.resetConnection(),this.scheduleReconnect(t)}resetConnection(){if(this.openPromise=null,this.stopKeepalive(),this.socket){const t=this.socket;this.socket=null,t.onopen=null,t.onmessage=null,t.onerror=null,t.onclose=null,(t.readyState===p||t.readyState===j)&&t.close()}this.boundSessionId=null}}const y=()=>{const r=globalThis;return r[P]||(r[P]={inputCapability:null,streamCapability:null,manager:null}),r[P]},$=()=>{const r=y();return r.manager||(r.manager=new it),r.manager},Q=r=>{const t=y();if(t.inputCapability=r?.input??null,t.streamCapability=r?.stream??null,!E(t.inputCapability)&&!E(t.streamCapability)){t.manager?.close(),t.manager=null;return}const e=N(A(t));if(!e)return;$().configure(e)},at=async(r,t)=>{const e=await fetch(`/api/terminal/${r}/input`,{method:"POST",headers:{"Content-Type":"text/plain"},body:t});if(!e.ok){const o=await e.json().catch(()=>({error:"Failed to send terminal input"}));throw new Error(o.error||"Failed to send terminal input")}};async function ct(r){const t=await fetch("/api/terminal/create",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cwd:r.cwd,cols:r.cols??80,rows:r.rows??24})});if(!t.ok){const o=await t.json().catch(()=>({error:"Failed to create terminal"}));throw new Error(o.error||"Failed to create terminal session")}const e=await t.json();return Q(e.capabilities),e}const U=(r,t,e,o={})=>{const n=o.maxRetries??3,s=o.initialRetryDelay??1e3,c=o.maxRetryDelay??8e3,f=o.connectionTimeout??1e4;let l=null,d=0,w=null,T=null,m=!1,g=!1;const x=()=>{w&&(clearTimeout(w),w=null),T&&(clearTimeout(T),T=null)},v=()=>{m||(m=!0,x(),l&&(l.close(),l=null))},_=(b,k)=>{if(!(m||g)){if(d<n&&!k){d+=1;const S=Math.min(s*Math.pow(2,d-1),c);t({type:"reconnecting",attempt:d,maxAttempts:n}),w=setTimeout(()=>{!m&&!g&&D()},S);return}e?.(b,!0),v()}},D=()=>{if(m||g||l&&l.readyState!==EventSource.CLOSED)return;l=new EventSource(`/api/terminal/${r}/stream`);let b=!1;T=setTimeout(()=>{!b&&l?.readyState!==EventSource.OPEN&&(l?.close(),_(new Error("Connection timeout"),!1))},f),l.onopen=()=>{b||(b=!0,d=0,x(),t({type:"connected"}))},l.onmessage=k=>{try{const S=JSON.parse(k.data);S.type==="exit"&&(y().manager?.unbindSession(r),g=!0,v()),t(S)}catch(S){e?.(S,!1)}},l.onerror=()=>{x();const k=g||l?.readyState===EventSource.CLOSED;l?.close(),l=null,g||_(new Error("Terminal stream connection error"),k)}};return D(),v};function lt(r,t,e,o={}){const n=y();if(!E(n.streamCapability))return U(r,t,e,o);const s=$(),c=N(A(n));return c?(s.configure(c),s.subscribe(r,t,e,o)):U(r,t,e,o)}async function ut(r,t){const e=y();e.manager&&await e.manager.sendInput(r,t)||await at(r,t)}async function ht(r,t,e){const o=await fetch(`/api/terminal/${r}/resize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cols:t,rows:e})});if(!o.ok){const n=await o.json().catch(()=>({error:"Failed to resize terminal"}));throw new Error(n.error||"Failed to resize terminal")}}async function dt(r){y().manager?.unbindSession(r);const t=await fetch(`/api/terminal/${r}`,{method:"DELETE"});if(!t.ok){const e=await t.json().catch(()=>({error:"Failed to close terminal"}));throw new Error(e.error||"Failed to close terminal")}}async function ft(r,t){y().manager?.unbindSession(r);const e=await fetch(`/api/terminal/${r}/restart`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cwd:t.cwd,cols:t.cols??80,rows:t.rows??24})});if(!e.ok){const n=await e.json().catch(()=>({error:"Failed to restart terminal"}));throw new Error(n.error||"Failed to restart terminal")}const o=await e.json();return Q(o.capabilities),o}async function pt(r){const t=await fetch("/api/terminal/force-kill",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});if(!t.ok){const e=await t.json().catch(()=>({error:"Failed to force kill terminal"}));throw new Error(e.error||"Failed to force kill terminal")}r.sessionId&&y().manager?.unbindSession(r.sessionId)}function Ce(){const r=y();if(r.inputCapability&&r.streamCapability&&!E(r.inputCapability)&&!E(r.streamCapability))return;const t=A(r)||V,e=N(t);if(!e)return;const o=$();o.isConnectedOrConnecting(e)||(o.configure(e),o.prime())}const wt=r=>{const t=r?.retry;return{maxRetries:t?.maxRetries??3,initialRetryDelay:t?.initialDelayMs??1e3,maxRetryDelay:t?.maxDelayMs??8e3,connectionTimeout:r?.connectionTimeoutMs??1e4}},yt=()=>({async createSession(r){return ct(r)},connect(r,t,e){const o=lt(r,t.onEvent,t.onError,wt(e));return{close:()=>o()}},async sendInput(r,t){await ut(r,t)},async resize(r){await ht(r.sessionId,r.cols,r.rows)},async close(r){await dt(r)},async restartSession(r,t){return ft(r,{cwd:t.cwd??"",cols:t.cols,rows:t.rows})},async forceKill(r){await pt(r)}}),mt=()=>{if(typeof window>"u")return"";const r=window.__APP_DESKTOP_SERVER__?.origin;return r||window.location.origin},i="/api/git",gt=1200,Tt=5e3,W=new Map,C=new Map,M=new Map,O=new Map,R=r=>r.trim();function a(r,t,e){const o=new URL(r,mt());if(t&&o.searchParams.set("directory",t),e)for(const[n,s]of Object.entries(e))s!==void 0&&o.searchParams.set(n,String(s));return o.toString()}async function St(r){const t=R(r),e=Date.now(),o=M.get(t);if(o&&o.expiresAt>e)return o.value;const n=O.get(t);if(n)return n;const s=(async()=>{const c=await fetch(a(`${i}/check`,r));if(!c.ok)throw new Error(`Failed to check git repository: ${c.statusText}`);const l=!!(await c.json()).isGitRepository;return M.set(t,{value:l,expiresAt:Date.now()+Tt}),l})();O.set(t,s);try{return await s}finally{O.get(t)===s&&O.delete(t)}}async function bt(r,t){const e=t?.mode,o=e==="light"?`${R(r)}::light`:R(r),n=Date.now(),s=W.get(o);if(s&&s.expiresAt>n)return s.value;const c=C.get(o);if(c)return c;const f=(async()=>{const l=await fetch(a(`${i}/status`,r,e?{mode:e}:void 0));if(!l.ok)throw new Error(`Failed to get git status: ${l.statusText}`);const d=await l.json();return W.set(o,{value:d,expiresAt:Date.now()+gt}),d})();C.set(o,f);try{return await f}finally{C.get(o)===f&&C.delete(o)}}async function kt(r,t){const{path:e,staged:o,contextLines:n}=t;if(!e)throw new Error("path is required to fetch git diff");const s=await fetch(a(`${i}/diff`,r,{path:e,staged:o?"true":void 0,context:n}));if(!s.ok)throw new Error(`Failed to get git diff: ${s.statusText}`);return s.json()}async function Et(r,t){const{path:e,staged:o}=t;if(!e)throw new Error("path is required to fetch git file diff");const n=await fetch(a(`${i}/file-diff`,r,{path:e,staged:o?"true":void 0}));if(!n.ok)throw new Error(`Failed to get git file diff: ${n.statusText}`);return n.json()}async function jt(r,t){if(!t)throw new Error("path is required to revert git changes");const e=await fetch(a(`${i}/revert`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t})});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to revert git changes")}}async function Ct(r){if(!r)return!1;const t=await fetch(a(`${i}/worktree-type`,r));if(!t.ok)throw new Error(`Failed to detect worktree type: ${t.statusText}`);return!!(await t.json()).linked}async function Ot(r){const t=await fetch(a(`${i}/branches`,r));if(!t.ok)throw new Error(`Failed to get branches: ${t.statusText}`);return t.json()}async function Ft(r,t){if(!t?.branch)throw new Error("branch is required to delete a branch");const e=await fetch(a(`${i}/branches`,r),{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to delete branch")}return e.json()}async function xt(r,t){if(!t?.branch)throw new Error("branch is required to delete remote branch");const e=await fetch(a(`${i}/remote-branches`,r),{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to delete remote branch")}return e.json()}async function vt(r,t){const e=t?.remote?.trim();if(!e)throw new Error("remote is required to remove a remote");const o=await fetch(a(`${i}/remotes`,r),{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify({remote:e})});if(!o.ok){const n=await o.json().catch(()=>({error:o.statusText}));throw new Error(n.error||"Failed to remove remote")}return o.json()}async function Pt(r,t,e){if(!Array.isArray(t)||t.length===0)throw new Error("No files provided to generate commit message");const o={files:t};e?.zenModel&&(o.zenModel=e.zenModel),e?.providerId&&(o.providerId=e.providerId),e?.modelId&&(o.modelId=e.modelId);const n=await fetch(a(`${i}/commit-message`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)});if(!n.ok){const l=await n.json().catch(()=>({error:n.statusText}));console.error("[git-generation][browser] http error",{status:n.status,statusText:n.statusText,error:l});const d=typeof l?.traceId=="string"&&l.traceId?` (traceId: ${l.traceId})`:"";throw new Error(`${l.error||"Failed to generate commit message"}${d}`)}const s=await n.json();if(!s?.message||typeof s.message!="object")throw new Error("Malformed commit generation response");const c=typeof s.message.subject=="string"&&s.message.subject.trim().length>0?s.message.subject.trim():"",f=Array.isArray(s.message.highlights)?s.message.highlights.filter(l=>typeof l=="string"&&l.trim().length>0).map(l=>l.trim()):[];return{message:{subject:c,highlights:f}}}async function It(r,t){const{base:e,head:o,context:n,zenModel:s,providerId:c,modelId:f}=t;if(!e||!o)throw new Error("base and head are required");const l={base:e,head:o};n?.trim()&&(l.context=n.trim()),s&&(l.zenModel=s),c&&(l.providerId=c),f&&(l.modelId=f);const d=await fetch(a(`${i}/pr-description`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(l)});if(!d.ok){const g=await d.json().catch(()=>({error:d.statusText}));throw new Error(g.error||"Failed to generate PR description")}const w=await d.json().catch(()=>null),T=typeof w?.title=="string"?w.title:"",m=typeof w?.body=="string"?w.body:"";if(!T&&!m)throw new Error("Malformed PR description response");return{title:T,body:m}}async function L(r){const t=await fetch(a(`${i}/worktrees`,r));if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to list worktrees")}return t.json()}async function B(r,t){const e=await fetch(a(`${i}/worktrees/validate`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t??{})});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to validate worktree")}return e.json()}async function Oe(r){const t=await fetch(a(`${i}/worktrees/bootstrap-status`,r));if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to get worktree bootstrap status")}return t.json()}async function Fe(r,t){const e=await fetch(a(`${i}/worktrees/preview`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t??{})});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to preview worktree")}return e.json()}async function q(r,t){const e=await fetch(a(`${i}/worktrees`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t??{})});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to create worktree")}return e.json()}async function z(r,t){const e=await fetch(a(`${i}/worktrees`,r),{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify(t??{})});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to delete worktree")}return e.json()}async function Rt(r,t,e={}){const o=await fetch(a(`${i}/commit`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({message:t,addAll:e.addAll??!1,files:e.files})});if(!o.ok){const n=await o.json().catch(()=>({error:o.statusText}));throw new Error(n.error||"Failed to create commit")}return o.json()}async function Nt(r,t={}){const e=await fetch(a(`${i}/push`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to push")}return e.json()}async function At(r,t={}){const e=await fetch(a(`${i}/pull`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to pull")}return e.json()}async function $t(r,t={}){const e=await fetch(a(`${i}/fetch`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to fetch")}return e.json()}async function Gt(r){const t=await fetch(a(`${i}/stashes`,r));if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to list stashes")}return t.json()}async function _t(r,t){const e=await fetch(a(`${i}/stashes/file-counts`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refs:t})});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to count stash files")}return e.json()}async function X(r,t={}){const e=await fetch(a(`${i}/stash`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to stash changes")}return e.json()}const G=async(r,t,e)=>{const o=await fetch(a(`${i}/${t}`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!o.ok){const n=await o.json().catch(()=>({error:o.statusText}));throw new Error(n.error||`Failed to ${t}`)}return o.json()},Dt=(r,t)=>G(r,"stash/apply",t),Z=(r,t)=>G(r,"stash/pop",t),Jt=(r,t)=>G(r,"stash/drop",t);async function Ut(r,t){const e=await fetch(a(`${i}/checkout`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({branch:t})});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to checkout branch")}return e.json()}async function Wt(r,t,e){const o=await fetch(a(`${i}/branches`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:t,startPoint:e})});if(!o.ok){const n=await o.json().catch(()=>({error:o.statusText}));throw new Error(n.error||"Failed to create branch")}return o.json()}async function Mt(r,t,e){const o=await fetch(a(`${i}/branches/rename`,r),{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldName:t,newName:e})});if(!o.ok){const n=await o.json().catch(()=>({error:o.statusText}));throw new Error(n.error||"Failed to rename branch")}return o.json()}async function Lt(r,t={}){const e=await fetch(a(`${i}/log`,r,{maxCount:t.maxCount,from:t.from,to:t.to,file:t.file}));if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(`Failed to get git log: ${o.error||e.statusText}`)}return e.json()}async function Bt(r,t){const e=await fetch(a(`${i}/commit-files`,r,{hash:t}));if(!e.ok)throw new Error(`Failed to get commit files: ${e.statusText}`);return e.json()}async function xe(r,t,e,o){const n=await fetch(a(`${i}/commit-file-diff`,r,{hash:t,path:e,binary:o?"true":void 0}));if(!n.ok)throw new Error(`Failed to get commit file diff: ${n.statusText}`);return n.json()}async function qt(){const r=await fetch(a(`${i}/identities`,void 0));if(!r.ok)throw new Error(`Failed to get git identities: ${r.statusText}`);return r.json()}async function zt(r){const t=await fetch(a(`${i}/identities`,void 0),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to create git identity")}return t.json()}async function Kt(r,t){const e=await fetch(a(`${i}/identities/${r}`,void 0),{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to update git identity")}return e.json()}async function Ht(r){const t=await fetch(a(`${i}/identities/${r}`,void 0),{method:"DELETE"});if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to delete git identity")}}async function Yt(r){if(!r)return null;const t=await fetch(a(`${i}/current-identity`,r));if(!t.ok)throw new Error(`Failed to get current git identity: ${t.statusText}`);const e=await t.json();return e?{userName:e.userName??null,userEmail:e.userEmail??null,sshCommand:e.sshCommand??null}:null}async function Vt(r){if(!r)return!1;const t=await fetch(a(`${i}/has-local-identity`,r));if(!t.ok)throw new Error(`Failed to check local identity: ${t.statusText}`);return(await t.json().catch(()=>null))?.hasLocalIdentity===!0}async function ve(){const r=await fetch(a(`${i}/global-identity`,void 0));if(!r.ok)throw new Error(`Failed to get global git identity: ${r.statusText}`);const t=await r.json();return!t||!t.userName&&!t.userEmail?null:{userName:t.userName??null,userEmail:t.userEmail??null,sshCommand:t.sshCommand??null}}async function Qt(r,t){const e=await fetch(a(`${i}/set-identity`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:t})});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to set git identity")}return e.json()}async function Pe(){const r=await fetch(a(`${i}/discover-credentials`,void 0));if(!r.ok)throw new Error(`Failed to discover git credentials: ${r.statusText}`);return r.json()}async function Ie(r,t){if(!r)return null;const e=await fetch(a(`${i}/remote-url`,r,{remote:t}));return e.ok?(await e.json()).url??null:null}async function Xt(r){const t=await fetch(a(`${i}/remotes`,r));if(!t.ok)throw new Error(`Failed to get remotes: ${t.statusText}`);return t.json()}async function Zt(r,t){const e=await fetch(a(`${i}/rebase`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to rebase")}return e.json()}async function te(r){const t=await fetch(a(`${i}/rebase/abort`,r),{method:"POST"});if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to abort rebase")}return t.json()}async function ee(r,t){const e=await fetch(a(`${i}/merge`,r),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const o=await e.json().catch(()=>({error:e.statusText}));throw new Error(o.error||"Failed to merge")}return e.json()}async function re(r){const t=await fetch(a(`${i}/merge/abort`,r),{method:"POST"});if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to abort merge")}return t.json()}async function oe(r){const t=await fetch(a(`${i}/rebase/continue`,r),{method:"POST"});if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to continue rebase")}return t.json()}async function ne(r){const t=await fetch(a(`${i}/merge/continue`,r),{method:"POST"});if(!t.ok){const e=await t.json().catch(()=>({error:t.statusText}));throw new Error(e.error||"Failed to continue merge")}return t.json()}async function se(r,t){return await X(r,{message:t?.message}),{success:!0}}async function ie(r){return await Z(r,{ref:"stash@{0}"}),{success:!0}}async function ae(r){const t=await fetch(a(`${i}/conflict-details`,r));if(!t.ok)throw new Error(`Failed to get conflict details: ${t.statusText}`);return t.json()}async function ce(r,t){const e=await fetch(`${i}/validate-directory`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({directory:r,worktreeRoot:t})});if(!e.ok)throw new Error(`Failed to validate worktree directory: ${e.statusText}`);return e.json()}async function le(r){const t=await fetch(`${i}/canonicalize-worktree-state`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({directory:r})});if(!t.ok)throw new Error(`Failed to canonicalize worktree state: ${t.statusText}`);return t.json()}const ue=()=>({checkIsGitRepository:St,getGitStatus:bt,getGitDiff:kt,getGitFileDiff:Et,revertGitFile:jt,isLinkedWorktree:Ct,getGitBranches:Ot,deleteGitBranch:Ft,deleteRemoteBranch:xt,removeRemote:vt,generateCommitMessage:Pt,generatePullRequestDescription:It,listGitWorktrees:L,validateGitWorktree:B,createGitWorktree:q,deleteGitWorktree:z,validateWorktreeDirectory:ce,canonicalizeWorktreeState:le,createGitCommit(r,t,e){return Rt(r,t,e)},gitPush:Nt,gitPull:At,gitFetch:$t,listGitStashes:Gt,countGitStashFiles:_t,stashGitChanges:X,applyGitStash:Dt,popGitStash:Z,dropGitStash:Jt,checkoutBranch:Ut,createBranch:Wt,renameBranch:Mt,getGitLog(r,t){return Lt(r,t)},getCommitFiles:Bt,getCurrentGitIdentity:Yt,hasLocalIdentity:Vt,setGitIdentity:Qt,getGitIdentities:qt,createGitIdentity:zt,updateGitIdentity:Kt,deleteGitIdentity:Ht,getRemotes:Xt,rebase:Zt,abortRebase:te,continueRebase:oe,merge:ee,abortMerge:re,continueMerge:ne,stash:se,stashPop:ie,getConflictDetails:ae,worktree:{list:L,validate:B,create:q,remove:z}}),h=r=>r.replace(/\\/g,"/"),he=(r,t)=>{const e=h(t?.directory||t?.path||r),o=Array.isArray(t?.entries)?t.entries:[];return{directory:e,entries:o.filter(n=>!!(n&&typeof n.name=="string"&&typeof n.path=="string")).map(n=>({name:n.name,path:h(n.path),isDirectory:!!n.isDirectory}))}},de=()=>({async listDirectory(r){const t=h(r),e=new URLSearchParams;t&&e.set("path",t);const o=await fetch(`/api/fs/list${e.toString()?`?${e.toString()}`:""}`);if(!o.ok){const s=await o.json().catch(()=>({error:o.statusText}));throw new Error(s.error||"Failed to list directory")}const n=await o.json();return he(t,n)},async search(r){const t=new URLSearchParams,e=h(r.directory);e&&t.set("directory",e),t.set("query",r.query),t.set("dirs","false"),t.set("type","file"),typeof r.maxResults=="number"&&Number.isFinite(r.maxResults)&&t.set("limit",String(r.maxResults));const o=await fetch(`/api/find/file?${t.toString()}`);if(!o.ok){const c=await o.json().catch(()=>({error:o.statusText}));throw new Error(c.error||"Failed to search files")}const n=await o.json();return(Array.isArray(n)?n:[]).map(c=>({path:h(`${e}/${c}`),preview:[h(c)]}))},async createDirectory(r){const t=h(r),e=await fetch("/api/fs/mkdir",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t})});if(!e.ok){const n=await e.json().catch(()=>({error:e.statusText}));throw new Error(n.error||"Failed to create directory")}const o=await e.json();return{success:!!o?.success,path:typeof o?.path=="string"?h(o.path):t}},async statFile(r,t){const e=h(r),o=new URLSearchParams({path:e});t?.allowOutsideWorkspace&&o.set("allowOutsideWorkspace","true");const n=await fetch(`/api/fs/stat?${o.toString()}`);if(!n.ok){const c=await n.json().catch(()=>({error:n.statusText}));throw new Error(c.error||"Failed to stat file")}const s=await n.json().catch(()=>({}));return{path:typeof s.path=="string"?h(s.path):e,isFile:!!s.isFile,size:typeof s.size=="number"?s.size:0,mtimeMs:typeof s.mtimeMs=="number"?s.mtimeMs:void 0}},async readFile(r,t){const e=h(r),o=new URLSearchParams({path:e});t?.allowOutsideWorkspace&&o.set("allowOutsideWorkspace","true"),t?.optional&&o.set("optional","true");const n=await fetch(`/api/fs/read?${o.toString()}`,{cache:t?.optional?"no-store":"default"});if(!n.ok){const c=await n.json().catch(()=>({error:n.statusText}));throw new Error(c.error||"Failed to read file")}return{content:await n.text(),path:e}},async writeFile(r,t){const e=h(r),o=await fetch("/api/fs/write",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e,content:t})});if(!o.ok){const s=await o.json().catch(()=>({error:o.statusText}));throw new Error(s.error||"Failed to write file")}const n=await o.json().catch(()=>({}));return{success:!!n.success,path:typeof n.path=="string"?h(n.path):e}},async delete(r){const t=h(r),e=await fetch("/api/fs/delete",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t})});if(!e.ok){const n=await e.json().catch(()=>({error:e.statusText}));throw new Error(n.error||"Failed to delete file")}return{success:!!(await e.json().catch(()=>({}))).success}},async rename(r,t){const e=await fetch("/api/fs/rename",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldPath:r,newPath:t})});if(!e.ok){const n=await e.json().catch(()=>({error:e.statusText}));throw new Error(n.error||"Failed to rename file")}const o=await e.json().catch(()=>({}));return{success:!!o.success,path:typeof o.path=="string"?h(o.path):t}},async revealPath(r){const t=await fetch("/api/fs/reveal",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:h(r)})});if(!t.ok){const o=await t.json().catch(()=>({error:t.statusText}));throw new Error(o.error||"Failed to reveal path")}return{success:!!(await t.json().catch(()=>({}))).success}},async downloadFile(r){const t=h(r),e=`/api/fs/raw?path=${encodeURIComponent(t)}&download=true`,o=document.createElement("a");o.href=e,o.download=t.split("/").pop()||"file",document.body.appendChild(o),o.click(),document.body.removeChild(o)},async uploadFile(r,t){const e=h(r),o=new FormData;o.set("path",e),o.set("file",t,t instanceof File?t.name:"upload");const n=await fetch("/api/fs/upload",{method:"POST",body:o});if(!n.ok){const f=await n.json().catch(()=>({error:n.statusText}));throw new Error(f.error||"Failed to upload file")}const s=await n.json().catch(()=>({})),c=s.files?.[0];return{success:!!s.success,path:c?.path??e}}}),K="/api/config/settings",fe="/api/config/reload",H=r=>!r||typeof r!="object"?{}:r,pe=()=>({async load(){const r=await fetch(K,{method:"GET",headers:{Accept:"application/json"}});if(!r.ok)throw new Error(`Failed to load settings: ${r.statusText}`);return{settings:H(await r.json().catch(()=>({}))),source:"web"}},async save(r){const t=await fetch(K,{method:"PUT",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(r)});if(!t.ok){const o=await t.json().catch(()=>({error:t.statusText}));throw new Error(o.error||"Failed to save settings")}return H(await t.json().catch(()=>({})))},async restartOpenCode(){const r=await fetch(fe,{method:"POST"});if(!r.ok){const t=await r.json().catch(()=>({error:r.statusText}));throw new Error(t.error||"Failed to restart OpenCode")}return{restarted:!0}}}),we=()=>({async requestDirectoryAccess(r){return{success:!0,path:r.path}},async startAccessingDirectory(r){return{success:!0}},async stopAccessingDirectory(r){return{success:!0}}}),ye=1500,me=async()=>{if(typeof navigator>"u"||!("serviceWorker"in navigator))return null;let r=null;try{r=await navigator.serviceWorker.getRegistration()??null}catch{r=null}if(r?.active)return r;if(!r)return null;try{return await Promise.race([navigator.serviceWorker.ready,new Promise(e=>{setTimeout(()=>e(null),ye)})])??r}catch{return r}},ge=async r=>{const t=await me();if(!t||typeof t.showNotification!="function")return!1;try{return await t.showNotification(r?.title??"Vinci",{body:r?.body,tag:r?.tag}),!0}catch(e){return console.warn("Failed to send notification via service worker",e),!1}},Te=async r=>{if(typeof Notification>"u")return console.info("Notifications not supported in this environment",r),!1;if(Notification.permission==="default"&&await Notification.requestPermission()!=="granted"||Notification.permission!=="granted")return console.warn("Notification permission not granted"),!1;try{return await ge(r)||new Notification(r?.title??"Vinci",{body:r?.body,tag:r?.tag}),!0}catch(t){return console.warn("Failed to send notification",t),!1}},Se=async r=>{if(typeof window>"u")return!1;const t=window.__TAURI__;if(!t?.core?.invoke)return!1;try{return await t.core.invoke("desktop_notify",{payload:{title:r?.title,body:r?.body,tag:r?.tag}}),!0}catch(e){return console.warn("Failed to send native notification (tauri)",e),!1}},be=()=>({async notifyAgentCompletion(r){return await Se(r)||await Te(r)},canNotify:()=>typeof window<"u"&&window.__TAURI__?.core?.invoke?!0:typeof Notification<"u"?Notification.permission==="granted":!1}),ke=()=>({async getAvailableTools(){const r=await fetch("/api/experimental/tool/ids");if(!r.ok)throw new Error(`Tools API returned ${r.status} ${r.statusText}`);const t=await r.json();if(!Array.isArray(t))throw new Error("Tools API returned invalid data format");return t.filter(e=>typeof e=="string"&&e!=="invalid").sort()}}),F=async(r,t)=>{try{const e=await fetch(r,{...t,credentials:"include",headers:{Accept:"application/json",...t?.headers??{}}});return e.ok?await e.json():null}catch{return null}},Ee=()=>({async getVapidPublicKey(){return F("/api/push/vapid-public-key")},async subscribe(r){return F("/api/push/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)})},async unsubscribe(r){return F("/api/push/subscribe",{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)})},async setVisibility(r){return F("/api/push/visibility",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),keepalive:!0})}}),u=async r=>await r.json().catch(()=>null),je=()=>({async authStatus(){const r=await fetch("/api/github/auth/status",{method:"GET",headers:{Accept:"application/json"}}),t=await u(r);if(!r.ok||!t)throw new Error(t?.error||r.statusText||"Failed to load GitHub status");return t},async authStart(){const r=await fetch("/api/github/auth/start",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({})}),t=await u(r);if(!r.ok||!t||!("deviceCode"in t))throw new Error(t?.error||r.statusText||"Failed to start GitHub auth");return t},async authComplete(r){const t=await fetch("/api/github/auth/complete",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({deviceCode:r})}),e=await u(t);if(!t.ok||!e)throw new Error(e?.error||t.statusText||"Failed to complete GitHub auth");return e},async authDisconnect(){const r=await fetch("/api/github/auth",{method:"DELETE",headers:{Accept:"application/json"}}),t=await u(r);if(!r.ok)throw new Error(t?.error||r.statusText||"Failed to disconnect GitHub");return{removed:!!t?.removed}},async authActivate(r){const t=await fetch("/api/github/auth/activate",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({accountId:r})}),e=await u(t);if(!t.ok||!e)throw new Error(e?.error||t.statusText||"Failed to activate GitHub account");return e},async me(){const r=await fetch("/api/github/me",{method:"GET",headers:{Accept:"application/json"}}),t=await u(r);if(!r.ok||!t)throw new Error(t?.error||r.statusText||"Failed to fetch GitHub user");return t},async prStatus(r,t,e,o){const n=new URLSearchParams({directory:r,branch:t,...e?{remote:e}:{},...o?.force?{force:"true"}:{}}),s=await fetch(`/api/github/pr/status?${n.toString()}`,{method:"GET",headers:{Accept:"application/json"}}),c=await u(s);if(!s.ok||!c)throw new Error(c?.error||s.statusText||"Failed to load PR status");return c},async prCreate(r){const t=await fetch("/api/github/pr/create",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(r)}),e=await u(t);if(!t.ok||!e)throw new Error(e?.error||t.statusText||"Failed to create PR");return e},async prUpdate(r){const t=await fetch("/api/github/pr/update",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(r)}),e=await u(t);if(!t.ok||!e)throw new Error(e?.error||t.statusText||"Failed to update PR");return e},async prMerge(r){const t=await fetch("/api/github/pr/merge",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(r)}),e=await u(t);if(!t.ok||!e)throw new Error(e?.error||t.statusText||"Failed to merge PR");return e},async prReady(r){const t=await fetch("/api/github/pr/ready",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(r)}),e=await u(t);if(!t.ok||!e)throw new Error(e?.error||t.statusText||"Failed to mark PR ready");return e},async repoUpstream(r){const t=await fetch(`/api/github/repo/upstream?directory=${encodeURIComponent(r)}`,{method:"GET",headers:{Accept:"application/json"}}),e=await u(t);if(!t.ok||!e)throw new Error(e?.error||t.statusText||"Failed to detect upstream repo");return e},async repoBranches(r,t){const e=await fetch(`/api/github/repo/branches?owner=${encodeURIComponent(r)}&repo=${encodeURIComponent(t)}`,{method:"GET",headers:{Accept:"application/json"}}),o=await u(e);if(!e.ok||!o)throw new Error(o?.error||e.statusText||"Failed to fetch repo branches");return o.branches??[]},async prsList(r,t){const e=t?.page??1,o=await fetch(`/api/github/pulls/list?directory=${encodeURIComponent(r)}&page=${encodeURIComponent(String(e))}`,{method:"GET",headers:{Accept:"application/json"}}),n=await u(o);if(!o.ok||!n)throw new Error(n?.error||o.statusText||"Failed to load pull requests");return n},async prContext(r,t,e){const o=new URL("/api/github/pulls/context",window.location.origin);o.searchParams.set("directory",r),o.searchParams.set("number",String(t)),e?.includeDiff&&o.searchParams.set("diff","1"),e?.includeCheckDetails&&o.searchParams.set("checkDetails","1"),e?.sourceRepo?.owner&&e.sourceRepo.repo&&(o.searchParams.set("owner",e.sourceRepo.owner),o.searchParams.set("repo",e.sourceRepo.repo));const n=await fetch(o.toString(),{method:"GET",headers:{Accept:"application/json"}}),s=await u(n);if(!n.ok||!s)throw new Error(s?.error||n.statusText||"Failed to load pull request context");return s},async issuesList(r,t){const e=t?.page??1,o=await fetch(`/api/github/issues/list?directory=${encodeURIComponent(r)}&page=${encodeURIComponent(String(e))}`,{method:"GET",headers:{Accept:"application/json"}}),n=await u(o);if(!o.ok||!n)throw new Error(n?.error||o.statusText||"Failed to load issues");return n},async issueGet(r,t,e){const o=new URL("/api/github/issues/get",window.location.origin);o.searchParams.set("directory",r),o.searchParams.set("number",String(t)),e?.sourceRepo?.owner&&e.sourceRepo.repo&&(o.searchParams.set("owner",e.sourceRepo.owner),o.searchParams.set("repo",e.sourceRepo.repo));const n=await fetch(o.toString(),{method:"GET",headers:{Accept:"application/json"}}),s=await u(n);if(!n.ok||!s)throw new Error(s?.error||n.statusText||"Failed to load issue");return s},async issueComments(r,t,e){const o=new URL("/api/github/issues/comments",window.location.origin);o.searchParams.set("directory",r),o.searchParams.set("number",String(t)),e?.sourceRepo?.owner&&e.sourceRepo.repo&&(o.searchParams.set("owner",e.sourceRepo.owner),o.searchParams.set("repo",e.sourceRepo.repo));const n=await fetch(o.toString(),{method:"GET",headers:{Accept:"application/json"}}),s=await u(n);if(!n.ok||!s)throw new Error(s?.error||n.statusText||"Failed to load issue comments");return s}}),Re=()=>({runtime:{platform:"web",isDesktop:!1,isVSCode:!1,label:"web"},terminal:yt(),git:ue(),files:de(),settings:pe(),permissions:we(),notifications:be(),github:je(),push:Ee(),tools:ke()});export{Qt as $,oe as A,_t as B,Wt as C,Rt as D,Ft as E,Jt as F,xe as G,Bt as H,ae as I,Yt as J,kt as K,Et as L,Lt as M,Ie as N,Xt as O,$t as P,At as Q,Nt as R,Vt as S,Ct as T,Gt as U,ee as V,Z as W,Zt as X,vt as Y,Mt as Z,jt as _,dt as a,se as a0,X as a1,ie as a2,ce as a3,Ce as a4,lt as b,Re as c,Ht as d,zt as e,pt as f,Oe as g,Pe as h,ve as i,qt as j,St as k,bt as l,Ot as m,q as n,z as o,L as p,Fe as q,xt as r,re as s,te as t,Kt as u,B as v,Dt as w,le as x,Ut as y,ne as z};
|
|
@@ -8,7 +8,7 @@ const e={"settings.appearance.language.label":"언어","settings.appearance.lang
|
|
|
8
8
|
|
|
9
9
|
{log}`,"contextPanel.preview.noUrlDetectedWithLog":`개발 서버가 응답할 수 있는 상태가 되지 못했습니다. 마지막 출력:
|
|
10
10
|
|
|
11
|
-
{log}`,"contextPanel.preview.console.open":"미리보기 콘솔 열기","contextPanel.preview.console.waiting":"미리보기 콘솔 대기 중","contextPanel.preview.console.title":"미리보기 콘솔","contextPanel.preview.console.attach":"첨부","contextPanel.preview.console.copy":"복사","contextPanel.preview.console.clear":"지우기","contextPanel.preview.console.empty":"아직 미리보기 콘솔 이벤트가 없습니다.","contextPanel.preview.console.noFilteredEvents":"이 필터와 일치하는 이벤트가 없습니다.","contextPanel.preview.console.runtimeError":"런타임 오류","contextPanel.preview.console.copied":"미리보기 콘솔 복사됨","contextPanel.preview.console.copyFailed":"미리보기 콘솔 복사 실패","contextPanel.preview.console.attached":"미리보기 콘솔이 채팅에 첨부되었습니다","contextPanel.preview.console.attachNoSession":"미리보기 로그를 첨부하기 전에 채팅 세션을 여세요","contextPanel.preview.console.attachAnnotation":"이것은 이 프로젝트에서 실행 중인 개발 서버의 브라우저 콘솔 로그입니다.","contextPanel.preview.inspect.toggle":"미리보기 요소 검사","contextPanel.preview.inspect.attached":"미리보기 주석이 채팅에 첨부되었습니다","contextPanel.preview.inspect.attachNoSession":"미리보기 주석을 첨부하기 전에 채팅 세션을 여세요","contextPanel.preview.inspect.attachAnnotation":"인앱 미리보기에서 선택한 DOM 요소입니다.","contextPanel.preview.inspect.attachAnnotationWithScreenshot":"인앱 미리보기에서 선택한 DOM 요소입니다. 선택한 요소가 강조된 보이는 미리보기 영역 스크린샷이 첨부되었습니다.","contextPanel.preview.console.filter.all":"전체","contextPanel.preview.console.filter.errors":"오류","contextPanel.preview.console.filter.warnings":"경고","contextPanel.preview.console.filter.logs":"로그","terminalView.preview.open":"미리보기","terminalView.preview.openTitle":"미리보기 패널 열기","header.services.shutdownDev":"Vinci 종료","chat.messageBody.actions.openPreviewAria":"미리보기 열기","chat.messageBody.actions.openPreview":"미리보기 열기","contextPanel.tab.closeTabAria":"{label} 탭 닫기","contextPanel.actions.collapsePanel":"접기 패널","contextPanel.actions.expandPanel":"펼치기 패널","contextPanel.actions.closePanel":"패널 닫기","contextPanel.actions.resizePanelAria":"컨텍스트 패널 크기 조정","contextPanel.iframe.sessionChatTitle":"세션 채팅 {sessionID}","sidebarFilesTree.menu.rename":"이름 변경","sidebarFilesTree.menu.copyPath":"경로 복사","sidebarFilesTree.menu.save":"저장","sidebarFilesTree.menu.newFile":"새 파일","sidebarFilesTree.menu.newFolder":"새 폴더","sidebarFilesTree.menu.delete":"삭제","sidebarFilesTree.toast.pathCopied":"경로 복사됨","sidebarFilesTree.toast.copyFailed":"복사 실패","sidebarFilesTree.toast.revealFailed":"경로 표시 실패","sidebarFilesTree.toast.filenameRequired":"파일 이름 필수","sidebarFilesTree.toast.writeNotSupported":"쓰기를 지원하지 않음","sidebarFilesTree.toast.fileCreated":"파일 생성됨","sidebarFilesTree.toast.operationFailed":"작업 실패","sidebarFilesTree.toast.folderNameRequired":"폴더 이름 필수","sidebarFilesTree.toast.folderCreated":"폴더 생성됨","sidebarFilesTree.toast.nameRequired":"이름 필수","sidebarFilesTree.toast.renameNotSupported":"이름 변경을 지원하지 않음","sidebarFilesTree.toast.renamedSuccessfully":"이름 변경됨","sidebarFilesTree.toast.deleteNotSupported":"삭제를 지원하지 않음","sidebarFilesTree.toast.deletedSuccessfully":"삭제됨","sidebarFilesTree.search.placeholder":"파일 검색…","sidebarFilesTree.search.clearAria":"검색 지우기","sidebarFilesTree.actions.newFileTitle":"새 파일","sidebarFilesTree.actions.newFolderTitle":"새 폴더","sidebarFilesTree.actions.refreshTitle":"새로고침","sidebarFilesTree.state.searching":"검색 중…","sidebarFilesTree.state.loading":"로드 중…","sidebarFilesTree.dialog.createFile.title":"파일 생성","sidebarFilesTree.dialog.createFolder.title":"폴더 생성","sidebarFilesTree.dialog.rename.title":"이름 변경","sidebarFilesTree.dialog.delete.title":"삭제","sidebarFilesTree.dialog.createFile.description":"{path}에 새 파일 생성","sidebarFilesTree.dialog.createFolder.description":"{path}에 새 폴더 생성","sidebarFilesTree.dialog.rename.description":"{name} 이름 변경","sidebarFilesTree.dialog.delete.description":"{name}을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.","sidebarFilesTree.dialog.rootFallback":"루트","sidebarFilesTree.dialog.rename.placeholder":"새 이름","sidebarFilesTree.dialog.namePlaceholder":"이름","sidebarFilesTree.dialog.cancel":"취소","sidebarFilesTree.dialog.confirm":"확인","sidebarFilesTree.dialog.delete.confirm":"삭제","filesView.dialog.createFile.title":"파일 생성","filesView.dialog.createFolder.title":"폴더 생성","filesView.dialog.rename.title":"이름 변경","filesView.dialog.delete.title":"삭제","filesView.dialog.createFile.description":"{path}에 새 파일 생성","filesView.dialog.createFolder.description":"{path}에 새 폴더 생성","filesView.dialog.rename.description":"{name} 이름 변경","filesView.dialog.delete.description":"{name}을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.","filesView.dialog.rootFallback":"루트","filesView.dialog.rename.placeholder":"새 이름","filesView.dialog.namePlaceholder":"이름","filesView.dialog.cancel":"취소","filesView.dialog.confirm":"확인","filesView.dialog.delete.confirm":"삭제","filesView.editor.saving":"저장 중…","filesView.editor.saved":"저장됨","filesView.editor.autoSaveOn":"자동 저장 켜짐","filesView.editor.manualSave":"수동 저장","filesView.editor.saveNowTitle":"지금 저장({shortcut}) · 1.5초 후 자동 저장","filesView.editor.saveNowManualTitle":"지금 저장({shortcut})","filesView.editor.saveAria":"저장 ({shortcut})","filesView.editor.openInDesktopApp":"데스크톱 앱에서 열기","filesView.editor.refreshApps":"앱 새로고침","filesView.editor.disableLineWrap":"줄 바꿈 끄기","filesView.editor.enableLineWrap":"줄 바꿈 켜기","filesView.editor.findInFile":"파일에서 찾기","filesView.editor.goToLine":"줄로 이동","filesView.editor.switchToTextView":"텍스트 보기로 전환","filesView.editor.switchToTreeView":"트리 보기로 전환","filesView.toast.copyFailed":"복사 실패","filesView.toast.openInAppFailed":"{app}에서 열기 실패","filesView.toast.savingNotSupported":"저장을 지원하지 않음","filesView.toast.writeFileFailed":"파일 쓰기 실패","filesView.toast.saveFailed":"저장 실패","filesView.editor.copyFileContents":"파일 내용 복사","filesView.editor.copyFilePathTitle":"파일 경로 복사({path})","filesView.editor.saveFile":"파일 저장","filesView.editor.exitFullscreen":"전체 화면 종료","filesView.editor.fullscreen":"전체 화면","filesView.unsaved.title":"저장하지 않은 변경 사항","filesView.unsaved.description":"계속하기 전에 편집 내용을 저장할까요?","filesView.unsaved.saveChanges":"변경 사항 저장","filesView.unsaved.discard":"버리기","filesView.editor.back":"뒤로","filesView.editor.openFilesAria":"파일 열기","filesView.editor.closeFileAria":"{name} 닫기","filesView.editor.selectFile":"파일 선택","filesView.editor.showControlsAria":"편집기 컨트롤 표시","filesView.editor.controlsTitle":"편집기 컨트롤","filesView.editor.pickFileFromTree":"트리에서 파일을 선택하세요.","filesView.state.loading":"로드 중…","filesView.state.openingFileAtChange":"변경 위치에서 파일 여는 중…","filesView.tree.search.placeholder":"파일 검색…","filesView.tree.search.clearAria":"검색 지우기","filesView.tree.search.searching":"검색 중…","filesView.tree.actions.newFileTitle":"새 파일","filesView.tree.actions.newFolderTitle":"새 폴더","filesView.editor.imageAltFallback":"이미지","filesView.error.jsonViewerUnavailable":"JSON 뷰어를 사용할 수 없음","filesView.error.switchToTextMode":"원본 내용을 보려면 텍스트 모드로 전환하세요.","filesView.warning.largeFilePreviewLimited":"이 파일은 큽니다({sizeKb}KB). 미리보기가 제한될 수 있습니다.","filesView.error.previewUnavailable":"미리보기를 사용할 수 없음","filesView.error.switchToEditMode":"문제를 수정하려면 편집 모드로 전환하세요.","filesView.error.readFileFailed":"파일 읽기 실패","filesView.editor.htmlPreviewTitle":"HTML 미리보기","filesView.editor.videoUnsupported":"브라우저가 비디오 요소를 지원하지 않습니다.","filesView.editor.audioUnsupported":"브라우저가 오디오 요소를 지원하지 않습니다.","contextUsage.aria.label":"컨텍스트 사용량","contextUsage.mobile.title":"컨텍스트 사용량","contextUsage.mobile.usedTokens":"사용한 토큰","contextUsage.mobile.contextLimit":"컨텍스트 한도","contextUsage.mobile.outputLimit":"출력 한도","contextUsage.mobile.usage":"사용량","contextUsage.tooltip.usedTokens":"사용됨 토큰: {tokens}","contextUsage.tooltip.contextLimit":"컨텍스트 한도: {tokens}","contextUsage.tooltip.outputLimit":"출력 한도: {tokens}","contextSidebar.session.untitled":"제목 없는 세션","contextSidebar.empty.openSession":"컨텍스트를 볼 세션을 여세요.","contextSidebar.section.context":"컨텍스트","contextSidebar.section.lastAssistantMessage":"마지막 어시스턴트 메시지","contextSidebar.section.rawMessages":"원본 메시지","contextSidebar.context.percentUsed":"{percent}% 사용됨","contextSidebar.breakdown.user":"사용자","contextSidebar.breakdown.assistant":"어시스턴트","contextSidebar.breakdown.toolCalls":"도구 호출","contextSidebar.breakdown.other":"기타","contextSidebar.stats.messages":"메시지","contextSidebar.stats.user":"사용자","contextSidebar.stats.assistant":"어시스턴트","contextSidebar.stats.cost":"비용","contextSidebar.tokens.input":"입력","contextSidebar.tokens.output":"출력","contextSidebar.tokens.reasoning":"추론","contextSidebar.tokens.cacheRead":"캐시 읽기","contextSidebar.tokens.cacheWrite":"캐시 쓰기","contextSidebar.actions.copyJson":"JSON 복사","contextSidebar.actions.copy":"복사","contextSidebar.actions.copied":"복사됨","planView.file.defaultName":"plan","planView.title.default":"플랜","planView.error.saveFailed":"저장 실패","planView.error.previewUnavailable":"미리보기를 사용할 수 없음","planView.error.switchToEditMode":"문제를 수정하려면 편집 모드로 전환하세요.","planView.error.writeFailed":"쓰기 실패","planView.error.writePlanFileFailed":"플랜 파일 쓰기 실패({status})","planView.actions.improvePlanAria":"플랜 개선","planView.actions.improve":"개선","planView.actions.implementPlanAria":"플랜 구현","planView.actions.implement":"구현","planView.actions.sendToNewSession":"새 세션으로 보내기","planView.actions.sendToNewWorktreeSession":"새 워크트리 세션으로 보내기","planView.actions.copyPlanContents":"플랜 내용 복사","planView.state.loading":"로드 중…","diffView.binary.unavailable":"이 파일의 콘텐츠는 볼 수 없습니다.","diffView.change.untracked":"추적되지 않은 파일","diffView.change.new":"새 파일","diffView.change.deleted":"삭제된 파일","diffView.change.renamed":"이름 변경된 파일","diffView.change.copied":"복사된 파일","diffView.change.modified":"수정된 파일","diffView.mode.single.label":"단일 파일","diffView.mode.single.description":"파일을 하나씩 표시","diffView.mode.stacked.label":"모든 파일","diffView.mode.stacked.description":"수정된 파일을 모두 쌓아서 표시","diffView.selector.selectFile":"파일 선택","diffView.selector.viewMode":"보기 모드","diffView.image.original":"원본","diffView.image.modified":"수정됨","diffView.image.new":"새 파일","diffView.image.originalAlt":"원본: {path}","diffView.image.modifiedAlt":"수정본: {path}","diffView.section.files":"파일","diffView.state.selectSessionDirectory":"변경사항을 볼 세션 디렉터리를 선택하세요","diffView.state.loadingRepositoryStatus":"레포지토리 상태 로드 중…","diffView.state.notGitRepository":"Git 레포지토리가 아닙니다. Git 탭에서 초기화하거나 디렉터리를 변경하세요.","diffView.state.cleanWorkingTree":"워킹 트리가 깨끗합니다. 표시할 변경 사항이 없습니다.","diffView.state.failedToLoadDiff":"변경사항을 불러오지 못했습니다","diffView.state.loadingDiff":"변경사항 불러오는 중…","diffView.state.loadingChanges":"변경 사항 로드 중…","diffView.summary.changedFilesSingle":"파일 {count}개 변경됨","diffView.summary.changedFilesPlural":"파일 {count}개 변경됨","diffView.actions.retry":"다시 시도","diffView.actions.disableLineWrap":"줄 바꿈 끄기","diffView.actions.enableLineWrap":"줄 바꿈 켜기","diffView.actions.openFileInEditorAtChange":"변경 위치에서 이 파일을 에디터로 열기","diffView.actions.openFileAtFirstChangedLine":"첫 변경 줄에서 이 파일 열기","rightSidebar.contextNotesTodo.plan.defaultTitle":"플랜","rightSidebar.contextNotesTodo.empty.selectProject":"메모와 Todo를 추가할 프로젝트를 선택하세요.","rightSidebar.contextNotesTodo.notes.title":"빠른 메모 - {project}","rightSidebar.contextNotesTodo.notes.placeholder":"컨텍스트, 리마인더, 링크를 기록하세요","rightSidebar.contextNotesTodo.todo.title":"Todo","rightSidebar.contextNotesTodo.todo.itemsSingle":"{count}개 항목","rightSidebar.contextNotesTodo.todo.itemsPlural":"{count}개 항목","rightSidebar.contextNotesTodo.todo.clearCompleted":"완료 항목 지우기","rightSidebar.contextNotesTodo.todo.inputPlaceholder":"Todo 추가","rightSidebar.contextNotesTodo.todo.addAria":"Todo 추가","rightSidebar.contextNotesTodo.todo.empty":"아직 Todo가 없습니다. 이 프로젝트용 체크리스트를 추가해 보세요.","rightSidebar.contextNotesTodo.todo.actions.markComplete":'"{text}" 완료로 표시',"rightSidebar.contextNotesTodo.todo.actions.collapse":'접기 todo "{text}"',"rightSidebar.contextNotesTodo.todo.actions.expand":'펼치기 todo "{text}"',"rightSidebar.contextNotesTodo.todo.actions.delete":'"{text}" 삭제',"rightSidebar.contextNotesTodo.todo.actions.send":'보내기 "{text}"',"rightSidebar.contextNotesTodo.todo.actions.reorder":'재정렬 "{text}"',"rightSidebar.contextNotesTodo.todo.resizeAria":"할 일 목록 크기 조정","rightSidebar.contextNotesTodo.todo.sendMenu.currentSession":"현재 세션으로 보내기","rightSidebar.contextNotesTodo.todo.sendMenu.newSession":"새 세션으로 보내기","rightSidebar.contextNotesTodo.todo.sendMenu.newWorktreeSession":"새 워크트리 세션으로 보내기","rightSidebar.contextNotesTodo.plans.title":"플랜","rightSidebar.contextNotesTodo.plans.filesSingle":"{count} 파일","rightSidebar.contextNotesTodo.plans.filesPlural":"{count} 파일","rightSidebar.contextNotesTodo.plans.importFromFile":"파일에서 플랜 가져오기","rightSidebar.contextNotesTodo.plans.empty":"아직 저장된 플랜 없음","rightSidebar.contextNotesTodo.plans.deletePlan":"플랜 삭제","rightSidebar.contextNotesTodo.plans.deletePlanWithTitle":'플랜 "{title}" 삭제',"rightSidebar.contextNotesTodo.sendDialog.title.newSession":"새 세션으로 보내기","rightSidebar.contextNotesTodo.sendDialog.title.newWorktree":"새 워크트리로 보내기","rightSidebar.contextNotesTodo.sendDialog.variant.default":"기본값","rightSidebar.contextNotesTodo.sendDialog.actions.cancel":"취소","rightSidebar.contextNotesTodo.sendDialog.actions.send":"보내기","rightSidebar.contextNotesTodo.sendDialog.actions.sending":"보내는 중…","rightSidebar.contextNotesTodo.toast.saveNotesFailed":"프로젝트 메모 저장 실패","rightSidebar.contextNotesTodo.toast.loadNotesFailed":"프로젝트 메모 로드 실패","rightSidebar.contextNotesTodo.toast.noActiveSession":"활성 세션이 선택되지 않음","rightSidebar.contextNotesTodo.toast.sentToCurrentSession":"Todo를 현재 세션으로 보냄","rightSidebar.contextNotesTodo.toast.worktreeRequiresGitRepo":"워크트리 작업은 Git 레포지토리에서만 사용할 수 있습니다","rightSidebar.contextNotesTodo.toast.createSessionFailed":"세션 생성 실패","rightSidebar.contextNotesTodo.toast.sentToNewSession":"할 일을 새 세션으로 보냈습니다","rightSidebar.contextNotesTodo.toast.sentToNewWorktreeSession":"할 일을 새 워크트리 세션으로 보냈습니다","rightSidebar.contextNotesTodo.toast.sendTodoFailed":"Todo 전송 실패","rightSidebar.contextNotesTodo.toast.deletePlanFailed":"플랜 삭제 실패","rightSidebar.contextNotesTodo.toast.planFileEmpty":"플랜 파일이 비어 있음","rightSidebar.contextNotesTodo.toast.importPlanFailed":"플랜 가져오기 실패","rightSidebar.contextNotesTodo.toast.planImported":"플랜 가져옴","rightSidebar.contextNotesTodo.toast.readPlanFileFailed":"플랜 파일 읽기 실패","inlineComment.range.lines":"줄 {start}-{end}","inlineComment.input.placeholder":"댓글 추가… (Cmd+Enter로 저장)","inlineComment.actions.cancel":"취소","inlineComment.actions.save":"저장","inlineComment.actions.comment":"댓글","inlineComment.actions.showLess":"간단히 보기","inlineComment.actions.showMore":"더 보기","inlineComment.actions.editComment":"편집 댓글","inlineComment.actions.deleteComment":"댓글 삭제","inlineComment.toast.selectSessionToSave":"댓글을 저장할 세션을 선택하세요","header.github.connectedWithLogin":"GitHub: {login}","header.github.connected":"GitHub 연결됨","header.github.avatarWithLogin":"{login} 아바타","header.github.avatar":"GitHub 아바타","header.github.accountsTitle":"GitHub 계정","header.services.openWithCurrent":"인스턴스, 사용량, MCP 열기(현재: {current})","header.services.open":"서비스, 사용량, MCP 열기","header.services.tooltip.currentInstanceWithShortcuts":"현재 인스턴스: {current} ({toggle}; 다음 탭 {nextTab})","header.services.tooltip.servicesWithShortcuts":"서비스 ({toggle}; 다음 탭 {nextTab})","header.services.title":"서비스","header.services.viewAria":"서비스 보기","header.services.closeAria":"서비스 닫기","header.services.rateLimits":"레이트 리밋","header.services.refreshRateLimitsAria":"레이트 리밋 새로고침","header.services.noRateLimits":"사용 가능한 레이트 리밋이 없습니다.","header.services.noRateLimitsReported":"보고된 레이트 리밋이 없습니다.","header.services.used":"사용됨","header.services.remaining":"남은 양","header.services.modelFamily.other":"기타","header.actions.openPlanAria":"플랜 열기","header.actions.planWithShortcut":"플랜 ({shortcut})","header.actions.terminalPanelWithShortcut":"터미널 패널 ({shortcut})","header.actions.toggleTerminalPanelAria":"토글 터미널 패널","terminalView.stream.processExitedMessage":`\r
|
|
11
|
+
{log}`,"contextPanel.preview.console.open":"미리보기 콘솔 열기","contextPanel.preview.console.waiting":"미리보기 콘솔 대기 중","contextPanel.preview.console.title":"미리보기 콘솔","contextPanel.preview.console.attach":"첨부","contextPanel.preview.console.copy":"복사","contextPanel.preview.console.clear":"지우기","contextPanel.preview.console.empty":"아직 미리보기 콘솔 이벤트가 없습니다.","contextPanel.preview.console.noFilteredEvents":"이 필터와 일치하는 이벤트가 없습니다.","contextPanel.preview.console.runtimeError":"런타임 오류","contextPanel.preview.console.copied":"미리보기 콘솔 복사됨","contextPanel.preview.console.copyFailed":"미리보기 콘솔 복사 실패","contextPanel.preview.console.attached":"미리보기 콘솔이 채팅에 첨부되었습니다","contextPanel.preview.console.attachNoSession":"미리보기 로그를 첨부하기 전에 채팅 세션을 여세요","contextPanel.preview.console.attachAnnotation":"이것은 이 프로젝트에서 실행 중인 개발 서버의 브라우저 콘솔 로그입니다.","contextPanel.preview.inspect.toggle":"미리보기 요소 검사","contextPanel.preview.inspect.attached":"미리보기 주석이 채팅에 첨부되었습니다","contextPanel.preview.inspect.attachNoSession":"미리보기 주석을 첨부하기 전에 채팅 세션을 여세요","contextPanel.preview.inspect.attachAnnotation":"인앱 미리보기에서 선택한 DOM 요소입니다.","contextPanel.preview.inspect.attachAnnotationWithScreenshot":"인앱 미리보기에서 선택한 DOM 요소입니다. 선택한 요소가 강조된 보이는 미리보기 영역 스크린샷이 첨부되었습니다.","contextPanel.preview.console.filter.all":"전체","contextPanel.preview.console.filter.errors":"오류","contextPanel.preview.console.filter.warnings":"경고","contextPanel.preview.console.filter.logs":"로그","terminalView.preview.open":"미리보기","terminalView.preview.openTitle":"미리보기 패널 열기","header.services.shutdownDev":"Vinci 종료","chat.messageBody.actions.openPreviewAria":"미리보기 열기","chat.messageBody.actions.openPreview":"미리보기 열기","contextPanel.tab.closeTabAria":"{label} 탭 닫기","contextPanel.actions.collapsePanel":"접기 패널","contextPanel.actions.expandPanel":"펼치기 패널","contextPanel.actions.closePanel":"패널 닫기","contextPanel.actions.resizePanelAria":"컨텍스트 패널 크기 조정","contextPanel.iframe.sessionChatTitle":"세션 채팅 {sessionID}","sidebarFilesTree.menu.rename":"이름 변경","sidebarFilesTree.menu.copyPath":"경로 복사","sidebarFilesTree.menu.save":"저장","sidebarFilesTree.menu.newFile":"새 파일","sidebarFilesTree.menu.newFolder":"새 폴더","sidebarFilesTree.menu.delete":"삭제","sidebarFilesTree.toast.pathCopied":"경로 복사됨","sidebarFilesTree.toast.copyFailed":"복사 실패","sidebarFilesTree.toast.revealFailed":"경로 표시 실패","sidebarFilesTree.toast.filenameRequired":"파일 이름 필수","sidebarFilesTree.toast.writeNotSupported":"쓰기를 지원하지 않음","sidebarFilesTree.toast.fileCreated":"파일 생성됨","sidebarFilesTree.toast.operationFailed":"작업 실패","sidebarFilesTree.toast.folderNameRequired":"폴더 이름 필수","sidebarFilesTree.toast.folderCreated":"폴더 생성됨","sidebarFilesTree.toast.nameRequired":"이름 필수","sidebarFilesTree.toast.renameNotSupported":"이름 변경을 지원하지 않음","sidebarFilesTree.toast.renamedSuccessfully":"이름 변경됨","sidebarFilesTree.toast.deleteNotSupported":"삭제를 지원하지 않음","sidebarFilesTree.toast.deletedSuccessfully":"삭제됨","sidebarFilesTree.search.placeholder":"파일 검색…","sidebarFilesTree.search.clearAria":"검색 지우기","sidebarFilesTree.actions.newFileTitle":"새 파일","sidebarFilesTree.actions.newFolderTitle":"새 폴더","sidebarFilesTree.actions.refreshTitle":"새로고침","sidebarFilesTree.actions.uploadTitle":"파일 업로드","sidebarFilesTree.toast.uploadSuccess":"{count}개 파일 업로드됨","sidebarFilesTree.toast.uploadFailed":"{count}개 파일 업로드 실패","sidebarFilesTree.state.searching":"검색 중…","sidebarFilesTree.state.loading":"로드 중…","sidebarFilesTree.dialog.createFile.title":"파일 생성","sidebarFilesTree.dialog.createFolder.title":"폴더 생성","sidebarFilesTree.dialog.rename.title":"이름 변경","sidebarFilesTree.dialog.delete.title":"삭제","sidebarFilesTree.dialog.createFile.description":"{path}에 새 파일 생성","sidebarFilesTree.dialog.createFolder.description":"{path}에 새 폴더 생성","sidebarFilesTree.dialog.rename.description":"{name} 이름 변경","sidebarFilesTree.dialog.delete.description":"{name}을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.","sidebarFilesTree.dialog.rootFallback":"루트","sidebarFilesTree.dialog.rename.placeholder":"새 이름","sidebarFilesTree.dialog.namePlaceholder":"이름","sidebarFilesTree.dialog.cancel":"취소","sidebarFilesTree.dialog.confirm":"확인","sidebarFilesTree.dialog.delete.confirm":"삭제","filesView.dialog.createFile.title":"파일 생성","filesView.dialog.createFolder.title":"폴더 생성","filesView.dialog.rename.title":"이름 변경","filesView.dialog.delete.title":"삭제","filesView.dialog.createFile.description":"{path}에 새 파일 생성","filesView.dialog.createFolder.description":"{path}에 새 폴더 생성","filesView.dialog.rename.description":"{name} 이름 변경","filesView.dialog.delete.description":"{name}을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.","filesView.dialog.rootFallback":"루트","filesView.dialog.rename.placeholder":"새 이름","filesView.dialog.namePlaceholder":"이름","filesView.dialog.cancel":"취소","filesView.dialog.confirm":"확인","filesView.dialog.delete.confirm":"삭제","filesView.editor.saving":"저장 중…","filesView.editor.saved":"저장됨","filesView.editor.autoSaveOn":"자동 저장 켜짐","filesView.editor.manualSave":"수동 저장","filesView.editor.saveNowTitle":"지금 저장({shortcut}) · 1.5초 후 자동 저장","filesView.editor.saveNowManualTitle":"지금 저장({shortcut})","filesView.editor.saveAria":"저장 ({shortcut})","filesView.editor.openInDesktopApp":"데스크톱 앱에서 열기","filesView.editor.refreshApps":"앱 새로고침","filesView.editor.disableLineWrap":"줄 바꿈 끄기","filesView.editor.enableLineWrap":"줄 바꿈 켜기","filesView.editor.findInFile":"파일에서 찾기","filesView.editor.goToLine":"줄로 이동","filesView.editor.switchToTextView":"텍스트 보기로 전환","filesView.editor.switchToTreeView":"트리 보기로 전환","filesView.toast.copyFailed":"복사 실패","filesView.toast.openInAppFailed":"{app}에서 열기 실패","filesView.toast.savingNotSupported":"저장을 지원하지 않음","filesView.toast.writeFileFailed":"파일 쓰기 실패","filesView.toast.saveFailed":"저장 실패","filesView.editor.copyFileContents":"파일 내용 복사","filesView.editor.copyFilePathTitle":"파일 경로 복사({path})","filesView.editor.saveFile":"파일 저장","filesView.editor.exitFullscreen":"전체 화면 종료","filesView.editor.fullscreen":"전체 화면","filesView.unsaved.title":"저장하지 않은 변경 사항","filesView.unsaved.description":"계속하기 전에 편집 내용을 저장할까요?","filesView.unsaved.saveChanges":"변경 사항 저장","filesView.unsaved.discard":"버리기","filesView.editor.back":"뒤로","filesView.editor.openFilesAria":"파일 열기","filesView.editor.closeFileAria":"{name} 닫기","filesView.editor.selectFile":"파일 선택","filesView.editor.showControlsAria":"편집기 컨트롤 표시","filesView.editor.controlsTitle":"편집기 컨트롤","filesView.editor.pickFileFromTree":"트리에서 파일을 선택하세요.","filesView.state.loading":"로드 중…","filesView.state.openingFileAtChange":"변경 위치에서 파일 여는 중…","filesView.tree.search.placeholder":"파일 검색…","filesView.tree.search.clearAria":"검색 지우기","filesView.tree.search.searching":"검색 중…","filesView.tree.actions.newFileTitle":"새 파일","filesView.tree.actions.newFolderTitle":"새 폴더","filesView.editor.imageAltFallback":"이미지","filesView.error.jsonViewerUnavailable":"JSON 뷰어를 사용할 수 없음","filesView.error.switchToTextMode":"원본 내용을 보려면 텍스트 모드로 전환하세요.","filesView.warning.largeFilePreviewLimited":"이 파일은 큽니다({sizeKb}KB). 미리보기가 제한될 수 있습니다.","filesView.error.previewUnavailable":"미리보기를 사용할 수 없음","filesView.error.switchToEditMode":"문제를 수정하려면 편집 모드로 전환하세요.","filesView.error.readFileFailed":"파일 읽기 실패","filesView.editor.htmlPreviewTitle":"HTML 미리보기","filesView.editor.videoUnsupported":"브라우저가 비디오 요소를 지원하지 않습니다.","filesView.editor.audioUnsupported":"브라우저가 오디오 요소를 지원하지 않습니다.","contextUsage.aria.label":"컨텍스트 사용량","contextUsage.mobile.title":"컨텍스트 사용량","contextUsage.mobile.usedTokens":"사용한 토큰","contextUsage.mobile.contextLimit":"컨텍스트 한도","contextUsage.mobile.outputLimit":"출력 한도","contextUsage.mobile.usage":"사용량","contextUsage.tooltip.usedTokens":"사용됨 토큰: {tokens}","contextUsage.tooltip.contextLimit":"컨텍스트 한도: {tokens}","contextUsage.tooltip.outputLimit":"출력 한도: {tokens}","contextSidebar.session.untitled":"제목 없는 세션","contextSidebar.empty.openSession":"컨텍스트를 볼 세션을 여세요.","contextSidebar.section.context":"컨텍스트","contextSidebar.section.lastAssistantMessage":"마지막 어시스턴트 메시지","contextSidebar.section.rawMessages":"원본 메시지","contextSidebar.context.percentUsed":"{percent}% 사용됨","contextSidebar.breakdown.user":"사용자","contextSidebar.breakdown.assistant":"어시스턴트","contextSidebar.breakdown.toolCalls":"도구 호출","contextSidebar.breakdown.other":"기타","contextSidebar.stats.messages":"메시지","contextSidebar.stats.user":"사용자","contextSidebar.stats.assistant":"어시스턴트","contextSidebar.stats.cost":"비용","contextSidebar.tokens.input":"입력","contextSidebar.tokens.output":"출력","contextSidebar.tokens.reasoning":"추론","contextSidebar.tokens.cacheRead":"캐시 읽기","contextSidebar.tokens.cacheWrite":"캐시 쓰기","contextSidebar.actions.copyJson":"JSON 복사","contextSidebar.actions.copy":"복사","contextSidebar.actions.copied":"복사됨","planView.file.defaultName":"plan","planView.title.default":"플랜","planView.error.saveFailed":"저장 실패","planView.error.previewUnavailable":"미리보기를 사용할 수 없음","planView.error.switchToEditMode":"문제를 수정하려면 편집 모드로 전환하세요.","planView.error.writeFailed":"쓰기 실패","planView.error.writePlanFileFailed":"플랜 파일 쓰기 실패({status})","planView.actions.improvePlanAria":"플랜 개선","planView.actions.improve":"개선","planView.actions.implementPlanAria":"플랜 구현","planView.actions.implement":"구현","planView.actions.sendToNewSession":"새 세션으로 보내기","planView.actions.sendToNewWorktreeSession":"새 워크트리 세션으로 보내기","planView.actions.copyPlanContents":"플랜 내용 복사","planView.state.loading":"로드 중…","diffView.binary.unavailable":"이 파일의 콘텐츠는 볼 수 없습니다.","diffView.change.untracked":"추적되지 않은 파일","diffView.change.new":"새 파일","diffView.change.deleted":"삭제된 파일","diffView.change.renamed":"이름 변경된 파일","diffView.change.copied":"복사된 파일","diffView.change.modified":"수정된 파일","diffView.mode.single.label":"단일 파일","diffView.mode.single.description":"파일을 하나씩 표시","diffView.mode.stacked.label":"모든 파일","diffView.mode.stacked.description":"수정된 파일을 모두 쌓아서 표시","diffView.selector.selectFile":"파일 선택","diffView.selector.viewMode":"보기 모드","diffView.image.original":"원본","diffView.image.modified":"수정됨","diffView.image.new":"새 파일","diffView.image.originalAlt":"원본: {path}","diffView.image.modifiedAlt":"수정본: {path}","diffView.section.files":"파일","diffView.state.selectSessionDirectory":"변경사항을 볼 세션 디렉터리를 선택하세요","diffView.state.loadingRepositoryStatus":"레포지토리 상태 로드 중…","diffView.state.notGitRepository":"Git 레포지토리가 아닙니다. Git 탭에서 초기화하거나 디렉터리를 변경하세요.","diffView.state.cleanWorkingTree":"워킹 트리가 깨끗합니다. 표시할 변경 사항이 없습니다.","diffView.state.failedToLoadDiff":"변경사항을 불러오지 못했습니다","diffView.state.loadingDiff":"변경사항 불러오는 중…","diffView.state.loadingChanges":"변경 사항 로드 중…","diffView.summary.changedFilesSingle":"파일 {count}개 변경됨","diffView.summary.changedFilesPlural":"파일 {count}개 변경됨","diffView.actions.retry":"다시 시도","diffView.actions.disableLineWrap":"줄 바꿈 끄기","diffView.actions.enableLineWrap":"줄 바꿈 켜기","diffView.actions.openFileInEditorAtChange":"변경 위치에서 이 파일을 에디터로 열기","diffView.actions.openFileAtFirstChangedLine":"첫 변경 줄에서 이 파일 열기","rightSidebar.contextNotesTodo.plan.defaultTitle":"플랜","rightSidebar.contextNotesTodo.empty.selectProject":"메모와 Todo를 추가할 프로젝트를 선택하세요.","rightSidebar.contextNotesTodo.notes.title":"빠른 메모 - {project}","rightSidebar.contextNotesTodo.notes.placeholder":"컨텍스트, 리마인더, 링크를 기록하세요","rightSidebar.contextNotesTodo.todo.title":"Todo","rightSidebar.contextNotesTodo.todo.itemsSingle":"{count}개 항목","rightSidebar.contextNotesTodo.todo.itemsPlural":"{count}개 항목","rightSidebar.contextNotesTodo.todo.clearCompleted":"완료 항목 지우기","rightSidebar.contextNotesTodo.todo.inputPlaceholder":"Todo 추가","rightSidebar.contextNotesTodo.todo.addAria":"Todo 추가","rightSidebar.contextNotesTodo.todo.empty":"아직 Todo가 없습니다. 이 프로젝트용 체크리스트를 추가해 보세요.","rightSidebar.contextNotesTodo.todo.actions.markComplete":'"{text}" 완료로 표시',"rightSidebar.contextNotesTodo.todo.actions.collapse":'접기 todo "{text}"',"rightSidebar.contextNotesTodo.todo.actions.expand":'펼치기 todo "{text}"',"rightSidebar.contextNotesTodo.todo.actions.delete":'"{text}" 삭제',"rightSidebar.contextNotesTodo.todo.actions.send":'보내기 "{text}"',"rightSidebar.contextNotesTodo.todo.actions.reorder":'재정렬 "{text}"',"rightSidebar.contextNotesTodo.todo.resizeAria":"할 일 목록 크기 조정","rightSidebar.contextNotesTodo.todo.sendMenu.currentSession":"현재 세션으로 보내기","rightSidebar.contextNotesTodo.todo.sendMenu.newSession":"새 세션으로 보내기","rightSidebar.contextNotesTodo.todo.sendMenu.newWorktreeSession":"새 워크트리 세션으로 보내기","rightSidebar.contextNotesTodo.plans.title":"플랜","rightSidebar.contextNotesTodo.plans.filesSingle":"{count} 파일","rightSidebar.contextNotesTodo.plans.filesPlural":"{count} 파일","rightSidebar.contextNotesTodo.plans.importFromFile":"파일에서 플랜 가져오기","rightSidebar.contextNotesTodo.plans.empty":"아직 저장된 플랜 없음","rightSidebar.contextNotesTodo.plans.deletePlan":"플랜 삭제","rightSidebar.contextNotesTodo.plans.deletePlanWithTitle":'플랜 "{title}" 삭제',"rightSidebar.contextNotesTodo.sendDialog.title.newSession":"새 세션으로 보내기","rightSidebar.contextNotesTodo.sendDialog.title.newWorktree":"새 워크트리로 보내기","rightSidebar.contextNotesTodo.sendDialog.variant.default":"기본값","rightSidebar.contextNotesTodo.sendDialog.actions.cancel":"취소","rightSidebar.contextNotesTodo.sendDialog.actions.send":"보내기","rightSidebar.contextNotesTodo.sendDialog.actions.sending":"보내는 중…","rightSidebar.contextNotesTodo.toast.saveNotesFailed":"프로젝트 메모 저장 실패","rightSidebar.contextNotesTodo.toast.loadNotesFailed":"프로젝트 메모 로드 실패","rightSidebar.contextNotesTodo.toast.noActiveSession":"활성 세션이 선택되지 않음","rightSidebar.contextNotesTodo.toast.sentToCurrentSession":"Todo를 현재 세션으로 보냄","rightSidebar.contextNotesTodo.toast.worktreeRequiresGitRepo":"워크트리 작업은 Git 레포지토리에서만 사용할 수 있습니다","rightSidebar.contextNotesTodo.toast.createSessionFailed":"세션 생성 실패","rightSidebar.contextNotesTodo.toast.sentToNewSession":"할 일을 새 세션으로 보냈습니다","rightSidebar.contextNotesTodo.toast.sentToNewWorktreeSession":"할 일을 새 워크트리 세션으로 보냈습니다","rightSidebar.contextNotesTodo.toast.sendTodoFailed":"Todo 전송 실패","rightSidebar.contextNotesTodo.toast.deletePlanFailed":"플랜 삭제 실패","rightSidebar.contextNotesTodo.toast.planFileEmpty":"플랜 파일이 비어 있음","rightSidebar.contextNotesTodo.toast.importPlanFailed":"플랜 가져오기 실패","rightSidebar.contextNotesTodo.toast.planImported":"플랜 가져옴","rightSidebar.contextNotesTodo.toast.readPlanFileFailed":"플랜 파일 읽기 실패","inlineComment.range.lines":"줄 {start}-{end}","inlineComment.input.placeholder":"댓글 추가… (Cmd+Enter로 저장)","inlineComment.actions.cancel":"취소","inlineComment.actions.save":"저장","inlineComment.actions.comment":"댓글","inlineComment.actions.showLess":"간단히 보기","inlineComment.actions.showMore":"더 보기","inlineComment.actions.editComment":"편집 댓글","inlineComment.actions.deleteComment":"댓글 삭제","inlineComment.toast.selectSessionToSave":"댓글을 저장할 세션을 선택하세요","header.github.connectedWithLogin":"GitHub: {login}","header.github.connected":"GitHub 연결됨","header.github.avatarWithLogin":"{login} 아바타","header.github.avatar":"GitHub 아바타","header.github.accountsTitle":"GitHub 계정","header.services.openWithCurrent":"인스턴스, 사용량, MCP 열기(현재: {current})","header.services.open":"서비스, 사용량, MCP 열기","header.services.tooltip.currentInstanceWithShortcuts":"현재 인스턴스: {current} ({toggle}; 다음 탭 {nextTab})","header.services.tooltip.servicesWithShortcuts":"서비스 ({toggle}; 다음 탭 {nextTab})","header.services.title":"서비스","header.services.viewAria":"서비스 보기","header.services.closeAria":"서비스 닫기","header.services.rateLimits":"레이트 리밋","header.services.refreshRateLimitsAria":"레이트 리밋 새로고침","header.services.noRateLimits":"사용 가능한 레이트 리밋이 없습니다.","header.services.noRateLimitsReported":"보고된 레이트 리밋이 없습니다.","header.services.used":"사용됨","header.services.remaining":"남은 양","header.services.modelFamily.other":"기타","header.actions.openPlanAria":"플랜 열기","header.actions.planWithShortcut":"플랜 ({shortcut})","header.actions.terminalPanelWithShortcut":"터미널 패널 ({shortcut})","header.actions.toggleTerminalPanelAria":"토글 터미널 패널","terminalView.stream.processExitedMessage":`\r
|
|
12
12
|
[Process exited{exitCodeSegment}{signalSegment}]\r
|
|
13
13
|
`,"terminalView.stream.processExitedWithCode":", 종료 코드 {exitCode}","terminalView.stream.processExitedWithSignal":" (시그널 {signal})","terminalView.error.sessionEnded":"터미널 세션이 종료되었습니다","terminalView.error.connectionFailed":"연결 실패: {message}","terminalView.error.startSessionFailed":"터미널 세션 시작에 실패했습니다","terminalView.error.restartFailed":"터미널 재시작에 실패했습니다","terminalView.error.sendInputFailed":"입력 전송에 실패했습니다","terminalView.empty.noWorkingDirectory":"터미널에서 사용할 작업 디렉터리가 없습니다.","terminalView.empty.selectSession":"터미널을 열 세션을 선택하세요.","terminalView.empty.noWorkingDirectoryForSession":"이 세션에서 사용할 작업 디렉터리가 없습니다.","terminalView.actions.retry":"다시 시도","terminalView.actions.hardRestart":"강제 재시작","terminalView.actions.hardRestartTitle":"강제 종료 후 새 세션을 생성합니다","terminalView.quickKeys.escape":"Esc","terminalView.quickKeys.tabAria":"Tab","terminalView.quickKeys.controlLabel":"Ctrl","terminalView.quickKeys.controlModifierAria":"Control 수정키","terminalView.quickKeys.commandModifierAria":"Command 수정키","terminalView.quickKeys.arrowUpAria":"위쪽 화살표","terminalView.quickKeys.arrowLeftAria":"왼쪽 화살표","terminalView.quickKeys.arrowDownAria":"아래쪽 화살표","terminalView.quickKeys.arrowRightAria":"오른쪽 화살표","terminalView.quickKeys.enterAria":"Enter","terminalView.tabs.closeTabTitle":"탭 닫기","terminalView.tabs.newTabTitle":"새 탭","terminalView.bottomDock.resizeAria":"터미널 패널 크기 조정","terminalView.bottomDock.restoreTitle":"터미널 패널 높이 복원","terminalView.bottomDock.restoreAria":"터미널 패널 높이 복원","terminalView.bottomDock.expandTitle":"펼치기 터미널 패널","terminalView.bottomDock.expandAria":"펼치기 터미널 패널","terminalView.bottomDock.closeTitle":"터미널 패널 닫기","terminalView.bottomDock.closeAria":"터미널 패널 닫기","terminalView.viewport.inputAria":"터미널 입력","directoryExplorerDialog.title":"프로젝트 디렉터리 추가","directoryExplorerDialog.description":"프로젝트로 추가할 폴더를 선택하세요.","directoryExplorerDialog.toggle.showHidden":"숨김 항목 표시","directoryExplorerDialog.pathInput.placeholder":"경로를 입력하거나 트리에서 선택…","directoryExplorerDialog.actions.openingFinder":"여는 중...","directoryExplorerDialog.actions.openInFinder":"Finder에서 열기","directoryExplorerDialog.actions.adding":"추가 중…","directoryExplorerDialog.actions.addProject":"프로젝트 추가","directoryExplorerDialog.actions.addLocalProject":"로컬 프로젝트 추가","directoryExplorerDialog.actions.newFolder":"새 폴더","directoryExplorerDialog.newFolder.placeholder":"폴더 이름...","directoryExplorerDialog.newFolder.confirm":"폴더 생성","directoryExplorerDialog.newFolder.cancel":"취소","directoryExplorerDialog.toast.folderCreated":"폴더를 성공적으로 생성했습니다","directoryExplorerDialog.toast.failedToCreateFolder":"폴더 생성에 실패했습니다","directoryExplorerDialog.actions.cloneRepository":"저장소 복제","directoryExplorerDialog.actions.cloneAndAdd":"복제하고 추가","directoryExplorerDialog.actions.cloning":"복제 중...","directoryExplorerDialog.actions.createAndAdd":"생성하고 추가","directoryExplorerDialog.actions.alreadyAdded":"이미 추가됨","directoryExplorerDialog.clone.remoteUrlPlaceholder":"저장소 URL (HTTPS 또는 SSH)","directoryExplorerDialog.browse.directories":"디렉터리","directoryExplorerDialog.browse.loading":"디렉터리 로드 중...","directoryExplorerDialog.browse.empty":"일치하는 디렉터리가 없습니다.","directoryExplorerDialog.browse.parentDirectory":"상위 디렉터리","directoryExplorerDialog.browse.addedBadge":"추가됨","directoryExplorerDialog.footer.navigate":"탐색","directoryExplorerDialog.footer.select":"선택","directoryExplorerDialog.footer.add":"추가","directoryExplorerDialog.shortcut.enter":"Enter","directoryExplorerDialog.toast.unableToAccessDirectory":"디렉터리에 접근할 수 없음","directoryExplorerDialog.toast.desktopDeniedAccess":"데스크톱에서 디렉터리 접근이 거부되었습니다.","directoryExplorerDialog.toast.failedToOpenDirectory":"디렉터리를 열지 못했습니다","directoryExplorerDialog.toast.desktopCouldNotGrantAccess":"데스크톱에서 파일 접근 권한을 부여하지 못했습니다.","directoryExplorerDialog.toast.failedToAddProject":"프로젝트 추가 실패","directoryExplorerDialog.toast.cloneUrlRequired":"복제하기 전에 저장소 URL을 입력하세요.","directoryExplorerDialog.toast.selectValidDirectoryPath":"유효한 디렉터리 경로를 선택하세요.","directoryExplorerDialog.toast.failedToSelectDirectory":"디렉터리 선택 실패","directoryExplorerDialog.toast.unknownError":"알 수 없는 오류가 발생했습니다.","directoryTree.actions.createNewDirectory":"새 디렉터리 만들기","directoryTree.actions.pinDirectory":"디렉터리 고정","directoryTree.actions.unpinDirectory":"디렉터리 고정 해제","directoryTree.actions.createDirectory":"디렉터리 생성","directoryTree.actions.cancel":"취소","directoryTree.actions.selectWorkingDirectoryAria":"작업 디렉터리 선택","directoryTree.state.locatingHomeDirectory":"홈 디렉터리 찾는 중…","directoryTree.state.loading":"로드 중…","directoryTree.state.noDirectoriesFound":"디렉터리 없음","directoryTree.section.pinned":"고정됨","directoryTree.section.browse":"찾아보기","aboutDialog.versionLabel":"버전 {version}","aboutDialog.vinciVersionLabel":"Vinci 버전 {version}","aboutDialog.openCodeVersionLabel":"OpenCode 버전 {version}","aboutDialog.actions.copyDiagnostics":"진단 정보 복사","aboutDialog.actions.preparingDiagnostics":"진단 정보 준비 중…","aboutDialog.actions.diagnosticsCopied":"진단 정보 복사됨","aboutDialog.diagnosticsDescription":"Vinci 상태, OpenCode 상태, 디렉터리 및 프로젝트를 포함합니다.","aboutDialog.footerNote":"커뮤니티를 위해 정성껏 만들었습니다","aboutDialog.toast.copyFailed":"복사 실패","aboutDialog.toast.diagnosticsNotReady":"진단 정보가 아직 준비되지 않았습니다. 잠시 후 다시 시도하세요.","aboutDialog.toast.diagnosticsCopied":"진단 정보 복사됨","helpDialog.title":"키보드 단축키","helpDialog.description":"이 단축키로 Vinci를 빠르게 탐색하세요","helpDialog.section.navigationCommands":"내비게이션 및 명령","helpDialog.section.sessionManagement":"세션 관리","helpDialog.section.panels":"패널","helpDialog.section.interface":"인터페이스","helpDialog.item.openCommandPalette":"명령 팔레트 열기","helpDialog.item.showKeyboardShortcuts":"키보드 단축키 보기(이 대화상자)","helpDialog.item.toggleSessionSidebar":"토글 세션 사이드바","helpDialog.item.cycleAgent":"에이전트 순환(채팅 입력)","helpDialog.item.openModelSelector":"모델 선택기 열기","helpDialog.item.navigateModels":"모델 이동(선택기)","helpDialog.item.adjustThinkingMode":"추론 모드 조정(지원되는 선택기)","helpDialog.item.cycleThinkingVariant":"추론 변형 순환(전역 단축키)","helpDialog.item.newWindow":"새 창(데스크톱 전용)","helpDialog.item.createNewSession":"새 세션 만들기","helpDialog.item.createNewWorktreeDraft":"새 워크트리 드래프트 만들기","helpDialog.item.focusChatInput":"채팅 입력창으로 포커스 이동","helpDialog.item.abortActiveRun":"활성 실행 중단(두 번 누르기)","helpDialog.item.toggleRightSidebar":"오른쪽 사이드바 전환","helpDialog.item.openRightSidebarGitTab":"오른쪽 사이드바 Git 탭 열기","helpDialog.item.openRightSidebarFilesTab":"오른쪽 사이드바 파일 탭 열기","helpDialog.item.cycleRightSidebarTab":"오른쪽 사이드바 탭 순환","helpDialog.item.toggleTerminalDock":"터미널 독 전환","helpDialog.item.toggleTerminalExpanded":"터미널 펼치기/접기","helpDialog.item.togglePlanContextPanel":"플랜 컨텍스트 패널 전환","helpDialog.item.cycleTheme":"테마 순환(라이트 → 다크 → 시스템)","helpDialog.item.switchProject":"프로젝트 전환","helpDialog.item.toggleServicesMenu":"서비스 메뉴 전환","helpDialog.item.cycleServicesTab":"서비스 탭 순환","helpDialog.item.openSettings":"설정 열기","helpDialog.keyCombiner.or":"또는","helpDialog.proTips.title":"팁:","helpDialog.proTips.commandPalette":"명령 팔레트({shortcut})로 모든 작업에 빠르게 접근하세요","helpDialog.proTips.recentSessions":"최근 세션 5개가 명령 팔레트에 표시됩니다","helpDialog.proTips.themeCycling":"테마 순환은 세션 간에도 선호 설정을 기억합니다","header.actions.rightSidebarWithShortcut":"오른쪽 사이드바 ({shortcut})","header.actions.toggleRightSidebarAria":"오른쪽 사이드바 토글","header.actions.openSessionsWithShortcut":"세션 ({shortcut}) 열기","header.actions.openSessionsAria":"세션 열기","header.actions.closeSessionsAria":"세션 닫기","header.actions.newSessionAria":"새 세션","header.actions.newSessionWithShortcut":"새 세션 ({shortcut})","header.actions.backAria":"뒤로","header.navigation.mainAria":"메인 내비게이션","header.sessions.title":"세션","header.changes.availableAria":"변경사항 있음","session.githubIssuePicker.error.noActiveProject":"활성 프로젝트가 없습니다","session.githubIssuePicker.error.runtimeUnavailable":"GitHub 런타임 API를 사용할 수 없습니다","session.githubIssuePicker.error.notConnected":"GitHub에 연결되어 있지 않습니다","session.githubIssuePicker.error.repoNotResolvable":"저장소를 확인할 수 없습니다","session.githubIssuePicker.error.repoMustBeGithub":"origin 리모트는 GitHub URL이어야 합니다","session.githubIssuePicker.error.issueNotFound":"이슈를 찾을 수 없습니다","session.githubIssuePicker.error.noModelSelected":"선택된 모델이 없습니다","session.githubIssuePicker.toast.loadMoreFailed":"이슈를 더 불러오지 못했습니다","session.githubIssuePicker.toast.loadIssueDetailsFailed":"이슈 상세 정보를 불러오지 못했습니다","session.githubIssuePicker.toast.sendContextFailed":"이슈 컨텍스트 전송에 실패했습니다","session.githubIssuePicker.toast.sessionCreated":"이슈에서 세션을 생성했습니다","session.githubIssuePicker.toast.startSessionFailed":"세션 시작에 실패했습니다","session.githubIssuePicker.title.select":"GitHub 이슈 연결","session.githubIssuePicker.title.createSession":"GitHub 이슈로 새 세션 만들기","session.githubIssuePicker.description.select":"이 세션에 연결할 이슈를 선택하세요.","session.githubIssuePicker.description.createSession":"제목, 본문, 라벨, 댓글을 숨겨진 이슈 컨텍스트로 새 세션에 추가합니다.","session.githubIssuePicker.searchPlaceholder":"제목 또는 #123으로 검색하거나 이슈 URL을 붙여넣으세요","session.githubIssuePicker.empty.noActiveProject":"선택된 활성 프로젝트가 없습니다","session.githubIssuePicker.empty.runtimeUnavailable":"GitHub 런타임 API를 사용할 수 없습니다.","session.githubIssuePicker.empty.notConnected":"GitHub에 연결되지 않았습니다. 설정에서 GitHub 계정을 연결하세요.","session.githubIssuePicker.empty.noIssuesFound":"이슈 없음","session.githubIssuePicker.empty.noOpenIssuesFound":"열린 이슈가 없습니다","session.githubIssuePicker.loading.issues":"이슈 로드 중…","session.githubIssuePicker.loading.more":"로드 중…","session.githubIssuePicker.actions.openSettings":"설정 열기","session.githubIssuePicker.actions.useIssue":"이슈 #{number} 사용","session.githubIssuePicker.actions.openInGitHubAria":"GitHub에서 열기","session.githubIssuePicker.actions.loadMore":"더 불러오기","session.githubIssuePicker.actions.sectionTitle":"작업","session.githubIssuePicker.actions.toggleWorktreeAria":"토글 워크트리","session.githubIssuePicker.actions.createInWorktree":"워크트리에서 생성","session.githubIssuePicker.actions.openRepo":"레포지토리 열기","session.githubIssuePicker.actions.refresh":"새로고침","session.githubPrPicker.error.noActiveProject":"활성 프로젝트가 없습니다","session.githubPrPicker.error.runtimeUnavailable":"GitHub 런타임 API를 사용할 수 없습니다","session.githubPrPicker.error.notConnected":"GitHub에 연결되어 있지 않습니다","session.githubPrPicker.error.prNotFound":"PR을 찾을 수 없습니다","session.githubPrPicker.error.repoNotResolvable":"저장소를 확인할 수 없습니다","session.githubPrPicker.error.repoMustBeGithub":"origin 리모트는 GitHub URL이어야 합니다","session.githubPrPicker.toast.loadMoreFailed":"PR을 더 불러오지 못했습니다","session.githubPrPicker.toast.loadDetailsFailed":"PR 상세 정보를 불러오지 못했습니다","session.githubPrPicker.title":"GitHub PR 연결","session.githubPrPicker.description":"이 메시지에 리뷰 컨텍스트로 첨부할 PR을 선택하세요.","session.githubPrPicker.searchPlaceholder":"제목 또는 #123으로 검색하거나 PR URL을 붙여넣으세요","session.githubPrPicker.includeDiffAria":"PR 변경사항을 첨부 컨텍스트에 포함","session.githubPrPicker.includeDiff":"PR 변경사항 포함","session.githubPrPicker.empty.noActiveProject":"선택된 활성 프로젝트가 없습니다","session.githubPrPicker.empty.runtimeUnavailable":"GitHub 런타임 API를 사용할 수 없습니다.","session.githubPrPicker.empty.notConnected":"GitHub에 연결되지 않았습니다. 설정에서 GitHub 계정을 연결하세요.","session.githubPrPicker.empty.noPullRequestsFound":"PR이 없습니다","session.githubPrPicker.empty.noOpenPullRequestsFound":"열린 PR이 없습니다","session.githubPrPicker.loading.pullRequests":"PR 불러오는 중…","session.githubPrPicker.loading.more":"로드 중…","session.githubPrPicker.actions.openSettings":"설정 열기","session.githubPrPicker.actions.usePullRequest":"PR #{number} 사용","session.githubPrPicker.actions.openInGitHubAria":"GitHub에서 열기","session.githubPrPicker.actions.loadMore":"더 불러오기","session.newWorktree.title":"새 워크트리","session.newWorktree.mode.newBranch":"새 브랜치","session.newWorktree.mode.existingBranch":"기존 브랜치","session.newWorktree.selectBranch":"브랜치 선택","session.newWorktree.chooseBranch":"브랜치 선택…","session.newWorktree.fetchBranches":"브랜치 가져오기","session.newWorktree.searchBranches":"브랜치 검색…","session.newWorktree.loadingBranches":"브랜치 불러오는 중…","session.newWorktree.noBranchesFound":"브랜치가 없습니다","session.newWorktree.matchingBranches":"일치하는 브랜치","session.newWorktree.noMatchingBranches":"일치하는 브랜치가 없습니다","session.newWorktree.localBranches":"로컬 브랜치","session.newWorktree.remoteBranches":"리모트 브랜치","session.newWorktree.otherLocalBranches":"기타 로컬 브랜치","session.newWorktree.otherRemoteBranches":"기타 리모트 브랜치","session.newWorktree.branchName":"브랜치 이름","session.newWorktree.branchNamePlaceholder":"feature/my-awesome-feature","session.newWorktree.actions.change":"변경","session.newWorktree.actions.startFromGitHubIssuePr":"GitHub 이슈/PR에서 시작","session.newWorktree.usingPrBranch":"PR 브랜치 사용 중: {branch}","session.newWorktree.fromIssue":"이슈 #{number}에서: {title}","session.newWorktree.worktreeDirectory":"워크트리 디렉터리","session.newWorktree.worktreeDirectoryPlaceholder":"my-워크트리-디렉터리","session.newWorktree.resetToMatchBranchName":"브랜치 이름에 맞게 초기화","session.newWorktree.sourceBranch":"원본 브랜치","session.newWorktree.selectSourceBranch":"원본 브랜치 선택","session.newWorktree.selectSourceBranchPlaceholder":"원본 브랜치 선택...","session.newWorktree.newBranchFromSource":"{source}에서 새 브랜치가 생성됩니다","session.newWorktree.issueNumber":"이슈 #{number}","session.newWorktree.prNumber":"PR #{number}","session.newWorktree.includeDiffBadge":"+diff","session.newWorktree.newSessionTitle":"새 세션","session.newWorktree.fromSource":"{source}에서","session.newWorktree.actions.cancel":"취소","session.newWorktree.actions.creating":"생성 중…","session.newWorktree.actions.createWorktree":"워크트리 생성","session.newWorktree.actions.reset":"초기화","session.newWorktree.error.noModelSelected":"선택된 모델이 없습니다","session.newWorktree.error.noActiveProject":"활성 프로젝트가 없습니다","session.newWorktree.error.branchNameRequired":"브랜치 이름은 필수입니다","session.newWorktree.error.worktreeDirectoryRequired":"워크트리 디렉터리 필수","session.newWorktree.error.sendGitHubContextFailed":"GitHub 컨텍스트 전송에 실패했습니다","session.newWorktree.error.createWorktreeFailed":"워크트리 생성에 실패했습니다","session.newWorktree.toast.sessionFromIssue":"이슈에서 세션을 생성했습니다","session.newWorktree.toast.sessionFromPr":"PR에서 세션을 생성했습니다","session.newWorktree.toast.worktreeCreated":"워크트리를 생성했습니다","session.newWorktree.toast.worktreeCreatedDescription":"{target} - 백그라운드에서 초기 설정 중","session.githubIntegration.title":"GitHub에서 선택","session.githubIntegration.tabs.issues":"이슈","session.githubIntegration.tabs.pullRequests":"PR","session.githubIntegration.connect.title":"GitHub에 연결","session.githubIntegration.connect.description":"이슈 또는 PR을 연결해 워크트리 정보를 자동으로 채웁니다","session.githubIntegration.connect.action":"GitHub 연결","session.githubIntegration.search.issuesPlaceholder":"이슈 검색 또는 #123 입력…","session.githubIntegration.search.prsPlaceholder":"PR 검색 또는 #456 입력…","session.githubIntegration.empty.noIssuesFound":"이슈 없음","session.githubIntegration.empty.noPullRequestsFound":"PR이 없습니다","session.githubIntegration.actions.loadMore":"더 불러오기","session.githubIntegration.actions.cancel":"취소","session.githubIntegration.actions.select":"선택","session.githubIntegration.selected.issueNumber":"이슈 #{number}","session.githubIntegration.selected.prNumber":"PR #{number}","session.githubIntegration.includeDiffAria":"PR 변경사항을 세션 컨텍스트에 포함","session.githubIntegration.includeDiff":"PR 변경사항 포함","session.githubIntegration.error.notConnected":"GitHub에 연결되어 있지 않습니다","session.githubIntegration.error.loadDataFailed":"데이터를 불러오지 못했습니다","session.githubIntegration.validation.branchAlreadyCheckedOut":"브랜치가 이미 워크트리에 체크아웃되어 있습니다","session.githubIntegration.validation.branchAlreadyExists":"브랜치가 이미 로컬에 있습니다","session.githubIntegration.validation.failed":"유효성 검사에 실패했습니다","chat.fileAttachment.toast.attachFailed":"첨부 파일 실패","chat.fileAttachment.toast.someFilesSkipped":`일부 파일을 건너뛰었습니다:
|
|
14
14
|
{summary}`,"chat.fileAttachment.toast.vscodePickFailed":"VS Code에서 파일 선택에 실패했습니다","chat.fileAttachment.fileFallback":"파일","chat.fileAttachment.skippedFallback":"건너뜀","chat.fileAttachment.actions.attachAria":"파일 첨부","chat.fileAttachment.actions.attach":"파일 첨부","chat.fileAttachment.actions.removeNamed":"{name} 제거","chat.fileAttachment.actions.removeImage":"이미지 제거","chat.fileAttachment.activeEditor.addFile":"컨텍스트에 파일 추가:{name}","chat.fileAttachment.activeEditor.pinSelection":"컨텍스트에 선택 고정","chat.fileAttachment.activeEditor.remove":"컨텍스트에서 제거","chat.pendingChanges.fileCountSingle":"{count} 파일","chat.pendingChanges.fileCountPlural":"{count} 파일","chat.pendingChanges.changedInWorkspace":"워크스페이스에서 변경됨","chat.changedFiles.title":"변경된 파일","chat.changedFiles.actions.openFileTitle":"{path} 열기","chat.emptyState.opencodeUnreachable":"OpenCode에 연결할 수 없음","chat.emptyState.startNewChat":"새 채팅 시작","chat.scrollToBottom.aria":"맨 아래로 스크롤","chat.timeline.relative.justNow":"방금 전","chat.timeline.relative.minutesAgo":"{count}분 전","chat.timeline.relative.hoursAgo":"{count}시간 전","chat.timeline.relative.daysAgo":"{count}일 전","chat.timeline.title":"대화 타임라인","chat.timeline.description":"대화의 원하는 지점으로 이동하거나 새 세션으로 분기하세요","chat.timeline.searchPlaceholder":"메시지 검색…","chat.timeline.empty.search":"메시지 없음","chat.timeline.empty.session":"아직 이 세션에 메시지 없음","chat.timeline.noTextContent":"[텍스트 내용 없음]","chat.timeline.actions.title":"작업","chat.timeline.actions.revertFromHere":"여기부터 되돌리기","chat.timeline.actions.forkFromHere":"여기서 분기 시작","chat.timeline.actions.previousTurn":"이전 턴","chat.timeline.actions.latest":"최신","chat.timeline.help.clickMessage":"메시지를 클릭하면 대화의 해당 위치로 이동합니다","chat.timeline.help.undoToPoint":"이 지점으로 되돌립니다(메시지 텍스트가 입력창에 채워집니다)","chat.timeline.help.createSessionFromHere":"여기서 새 세션 생성","chat.statusRow.todo.status.inProgress":"진행 중","chat.statusRow.todo.status.pending":"대기 중","chat.statusRow.todo.status.completed":"완료됨","chat.statusRow.todo.status.cancelled":"취소됨","chat.statusRow.todo.priority.high":"높은 우선순위","chat.statusRow.todo.priority.medium":"중간 우선순위","chat.statusRow.todo.priority.low":"낮은 우선순위","chat.statusRow.actions.stopGeneratingAria":"생성 중지","chat.statusRow.tasksTitle":"작업","chat.statusRow.summary.activeLeft":"{active}개 활성 · {left}개 남음","chat.statusRow.aborted":"중단됨","chat.revertIndicator.redo":"다시 실행","chat.revertIndicator.redoAria":"다시 실행 — 되돌린 메시지 복원","chat.revertPopover.title":"되돌림","chat.revertPopover.noTextContent":"텍스트 없음","chat.revertPopover.forkFromHere":"여기서 분기","chat.revertPopover.forkFromMessage":"이 메시지에서 분기","chat.revertPopover.restoreAll":"모두 복원","chat.revertPopover.restore":"복원","chat.revertPopover.revert":"되돌리기","chat.revertPopover.fork":"분기","chat.revert.toast.undo":"{preview}(으)로 되돌림","chat.revert.toast.redo":"다시 실행","chat.revert.toast.restored":"모든 메시지 복원됨","chat.errorBoundary.title":"채팅 오류","chat.errorBoundary.description":"채팅 인터페이스에서 오류가 발생했습니다. 일시적인 네트워크 이슈 또는 손상된 메시지 데이터 때문일 수 있습니다.","chat.errorBoundary.sessionLabel":"세션","chat.errorBoundary.detailsSummary":"오류 상세","chat.errorBoundary.resetAction":"채팅 초기화","chat.errorBoundary.persistentHint":"문제가 계속되면 페이지를 새로고침해 보세요.","chat.autocomplete.tabs.commands":"명령","chat.autocomplete.tabs.agents":"에이전트","chat.autocomplete.tabs.files":"파일","chat.autocomplete.keyboardHint":"↑↓ 이동 • Enter 선택 • Esc 닫기","chat.commandAutocomplete.command.initDescription":"AGENTS.md 파일 생성/업데이트","chat.commandAutocomplete.command.undoDescription":"마지막 메시지 실행 취소","chat.commandAutocomplete.command.redoDescription":"이전에 실행 취소한 메시지 다시 실행","chat.commandAutocomplete.command.timelineDescription":"대화 타임라인 열기","chat.commandAutocomplete.command.compactDescription":"AI로 세션 기록을 압축해 컨텍스트 크기를 줄입니다","chat.commandAutocomplete.command.summaryDescription":"세션 기록을 안전하게 요약합니다. 명령 뒤에 선택적으로 주제 힌트를 넣을 수 있습니다.","chat.commandAutocomplete.command.workspaceReviewDescription":"현재 워크스페이스 변경 사항에서 중요한 이슈만 리뷰합니다.","chat.commandAutocomplete.badge.skill":"스킬","chat.commandAutocomplete.badge.command":"명령","chat.commandAutocomplete.badge.system":"system","chat.commandAutocomplete.empty":"명령 없음","chat.agentMentionAutocomplete.badge.system":"system","chat.agentMentionAutocomplete.empty":"에이전트 없음","chat.fileMentionAutocomplete.searchMoreAgents":"입력해 에이전트를 더 검색하세요","chat.fileMentionAutocomplete.empty":"일치하는 항목 없음","chat.queuedMessage.attachments":"+{count} 파일(s)","chat.queuedMessage.empty":"(비어 있음)","chat.queuedMessage.removeAria":"큐에서 제거","chat.container.returnToParent.aria":"상위 세션으로 돌아가기","chat.container.returnToParent.titleNamed":"돌아가기: {title}","chat.container.returnToParent.title":"상위 세션으로 돌아가기","chat.container.returnToParent.label":"상위","chat.container.readOnlySubagentPromptBanner":"하위 에이전트 세션에는 프롬프트를 보낼 수 없습니다.","chat.unifiedControls.title":"컨트롤","chat.unifiedControls.model.title":"모델","chat.unifiedControls.model.noRecent":"최근 모델 없음","chat.unifiedControls.model.moreAria":"모델 더 보기","chat.unifiedControls.effort.title":"추론 강도","chat.unifiedControls.effort.moreAria":"추론 강도 옵션 더 보기","chat.questionCard.summaryTab":"요약","chat.questionCard.noAnswer":"(답변 없음)","chat.questionCard.inputNeeded":"입력 필요","chat.questionCard.fromSubagent":"서브 에이전트에서","chat.questionCard.questionFallback":"질문 {index}","chat.questionCard.selectMultiple":"여러 개 선택","chat.questionCard.recommended":"추천","chat.questionCard.other":"기타…","chat.questionCard.yourAnswer":"내 답변","chat.questionCard.submit":"제출","chat.questionCard.next":"다음","chat.questionCard.dismiss":"닫기","chat.questionCard.copyMarkdown":"Markdown으로 복사","chat.questionCard.copyJson":"JSON으로 복사","chat.questionCard.copiedMarkdown":"질문을 Markdown으로 복사했습니다","chat.questionCard.copiedJson":"질문을 JSON으로 복사했습니다","chat.questionCard.copyFailed":"질문 복사에 실패했습니다","chat.textSelection.toast.noProject":"이 세션의 프로젝트를 찾을 수 없음","chat.textSelection.toast.addToNotesFailed":"메모 추가 실패","chat.textSelection.toast.addToNotesSuccess":"선택한 텍스트를 메모에 추가함","chat.textSelection.toast.addToNotesSummaryFailed":"선택 영역을 요약할 수 없어 선택한 텍스트를 메모에 추가함","chat.textSelection.actions.addToChat":"채팅에 추가","chat.textSelection.actions.newSession":"새 세션","chat.textSelection.actions.copy":"복사","chat.textSelection.actions.addToNotes":"메모에 추가","chat.textSelection.title.addToCurrentChat":"현재 채팅에 추가","chat.textSelection.title.newSessionWithSelection":"선택한 내용으로 새 세션 생성","chat.textSelection.title.saveInsightToNotes":"선택한 텍스트를 메모에 저장","chat.messageBody.actions.revertAria":"이 메시지로 되돌리기","chat.messageBody.actions.revert":"여기부터 되돌리기","chat.messageBody.actions.forkAria":"이 메시지에서 분기","chat.messageBody.actions.fork":"여기서 분기 시작","chat.messageBody.actions.copyMessageAria":"메시지 텍스트 복사","chat.messageBody.actions.copyMessage":"메시지 복사","chat.messageBody.actions.copyAnswer":"답변 복사","chat.messageBody.actions.savingImage":"이미지 저장 중…","chat.messageBody.actions.saveAsImage":"이미지로 저장","chat.messageBody.actions.saveAsPlan":"플랜으로 저장","chat.messageBody.actions.startNewSession":"이 응답에서 새 세션 시작","chat.messageBody.actions.startNewMultiRun":"이 응답에서 새 멀티런 시작","chat.generatedResult.actions.copy":"복사","chat.generatedResult.actions.copied":"복사됨","chat.generatedResult.commit.title":"생성된 커밋 메시지","chat.generatedResult.commit.highlights":"하이라이트","chat.generatedResult.pullRequest.title":"생성된 Pull Request","chat.generatedResult.pullRequest.titleLabel":"제목","chat.generatedResult.pullRequest.bodyLabel":"본문","chat.messageBody.tts.stopSpeaking":"읽기 중지","chat.messageBody.tts.readAloud":"소리 내어 읽기","chat.messageBody.tts.readAloudWithProvider":"소리 내어 읽기({provider} 음성)","chat.messageBody.toast.noProject":"이 세션의 프로젝트를 찾을 수 없음","chat.messageBody.toast.savePlanFailed":"플랜 저장 실패","chat.messageBody.toast.planSaved":"플랜이 저장되었습니다","chat.messageBody.toast.imageSaved":"이미지 저장된","chat.messageBody.toast.generateImageFailed":"이미지 생성 실패","chat.chatInput.actions.commands":"명령","chat.chatInput.actions.attachFiles":"파일 첨부","chat.chatInput.actions.addAttachment":"첨부 파일 추가","chat.chatInput.actions.linkGithubIssue":"GitHub 이슈 연결","chat.chatInput.actions.linkGithubPr":"GitHub PR 연결","chat.chatInput.actions.modelAgentSettings":"모델 및 에이전트 설정","chat.chatInput.actions.sendMessageAria":"보내기 메시지","chat.chatInput.actions.queueMessageAria":"메시지 대기열에 추가","chat.chatInput.actions.stopGeneratingAria":"생성 중지","chat.chatInput.focusMode.toggleAria":"집중 모드 전환","chat.chatInput.focusMode.label":"집중 모드","chat.chatInput.permissionAutoAccept.disable":"권한 자동 승인 끄기","chat.chatInput.permissionAutoAccept.enable":"권한 자동 승인 켜기","chat.chatInput.permissionAutoAccept.on":"권한 자동 승인: 켜짐","chat.chatInput.permissionAutoAccept.off":"권한 자동 승인: 꺼짐","chat.chatInput.linked.byAuthor":"작성자: {author}","chat.chatInput.linked.issue.openInBrowserAria":"브라우저에서 이슈 열기","chat.chatInput.linked.issue.removeAria":"연결된 이슈 제거","chat.chatInput.linked.pr.number":"PR #{number}","chat.chatInput.linked.pr.openInBrowserAria":"브라우저에서 PR 열기","chat.chatInput.linked.pr.removeAria":"연결된 PR 제거","chat.chatInput.placeholder.shell":"셸 명령 입력…","chat.chatInput.placeholder.chat":"@파일/에이전트 선택, /명령 실행, !셸 명령 실행","chat.chatInput.placeholder.selectSession":"채팅을 시작할 세션을 선택하거나 새로 만드세요","chat.chatInput.toast.compactFailed":"세션 압축 실패","chat.chatInput.toast.summaryFailed":"요약 생성 실패","chat.chatInput.toast.reviewFailed":"변경사항 검토 실패","chat.chatInput.toast.attachmentsTooLarge":"첨부 파일이 너무 커서 보낼 수 없습니다. 이미지 수나 크기를 줄여 보세요.","chat.chatInput.toast.sendAttachmentsFailed":"첨부 파일 전송 실패. 파일 수나 이미지 크기를 줄여 보세요.","chat.chatInput.toast.messageSendFailed":"메시지 전송에 실패했습니다. 첨부 파일을 복원했습니다.","chat.chatInput.toast.clipboardAttachFailed":"클립보드 이미지 첨부 실패","chat.chatInput.toast.addedFileMentions":"파일 멘션 {count}개 추가됨","chat.chatInput.toast.attachFileFailed":"첨부 파일 실패","chat.chatInput.toast.attachNamedFailed":"첨부 {name} 실패","chat.chatInput.toast.someFilesSkipped":`일부 파일을 건너뛰었습니다:
|