mouaif 0.3.0 → 0.3.2

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.
Files changed (37) hide show
  1. package/README.md +1 -1
  2. package/bin/mouaif.js +1 -5
  3. package/frontend/dist/assets/{AgentFilePicker-CcKLJorU.js → AgentFilePicker-ZW6vm5Hy.js} +1 -1
  4. package/frontend/dist/assets/{CliModal-Hs5phmNZ.js → CliModal-D2cX4W0a.js} +1 -1
  5. package/frontend/dist/assets/{DictationPage-BI23lp42.js → DictationPage-Dwb6gGNi.js} +1 -1
  6. package/frontend/dist/assets/{FileEditor-DDl31c6d.js → FileEditor-BqgbeJHy.js} +1 -1
  7. package/frontend/dist/assets/{GitModal-3EC_gpJ5.js → GitModal-BPaOnX1a.js} +1 -1
  8. package/frontend/dist/assets/{Inspector-Ba3R1w04.js → Inspector-C88hoEcC.js} +1 -1
  9. package/frontend/dist/assets/{SettingsAbout-bvZGDEDw.js → SettingsAbout-D5gHujOy.js} +1 -1
  10. package/frontend/dist/assets/{SettingsActions-Dk6WX9jv.js → SettingsActions-YrcVF8D3.js} +1 -1
  11. package/frontend/dist/assets/{SettingsAgents-BNV0MgDB.js → SettingsAgents-BVwBxPbO.js} +1 -1
  12. package/frontend/dist/assets/{SettingsDefaults-DbMmQbzc.js → SettingsDefaults-CMSIeSt8.js} +1 -1
  13. package/frontend/dist/assets/{SettingsHiddenContent-BZ2sloH1.js → SettingsHiddenContent-XE1HiHzN.js} +1 -1
  14. package/frontend/dist/assets/{SettingsMcp-DOrfbQd1.js → SettingsMcp-BAK8U0e4.js} +1 -1
  15. package/frontend/dist/assets/{SettingsMcpEdit-BGMQ2CWC.js → SettingsMcpEdit-j21BWCAH.js} +1 -1
  16. package/frontend/dist/assets/{SettingsMcpRegistry-BywXee_A.js → SettingsMcpRegistry-DH5YAigF.js} +1 -1
  17. package/frontend/dist/assets/{SettingsNotifications-B0LEs11a.js → SettingsNotifications-DJt0f8Jn.js} +1 -1
  18. package/frontend/dist/assets/{SettingsPricing-BAg33iVF.js → SettingsPricing-Csy5MjG-.js} +1 -1
  19. package/frontend/dist/assets/{SettingsProject-DNrKhCcZ.js → SettingsProject-Cry5UltF.js} +1 -1
  20. package/frontend/dist/assets/{SettingsProjects-IqkBfDcm.js → SettingsProjects-d3wgiADv.js} +1 -1
  21. package/frontend/dist/assets/{SettingsPrompts-BgeiASuk.js → SettingsPrompts-B9ECDKEa.js} +1 -1
  22. package/frontend/dist/assets/{SettingsProviders-k0xJN0IK.js → SettingsProviders-BalA35c9.js} +1 -1
  23. package/frontend/dist/assets/{SettingsTags-B5kjFdQi.js → SettingsTags-D_1AgCwY.js} +1 -1
  24. package/frontend/dist/assets/index-BDkCsON6.js +61 -0
  25. package/frontend/dist/assets/index-FzhcinOk.css +1 -0
  26. package/frontend/dist/index.html +2 -2
  27. package/frontend/dist/sw.js +1 -1
  28. package/package.json +6 -7
  29. package/src/access-auth.js +1 -86
  30. package/src/http-server.js +2 -9
  31. package/src/pty.js +189 -0
  32. package/src/server-handlers-access.js +1 -101
  33. package/src/server-handlers-tools.js +25 -36
  34. package/src/server-shared.js +1 -14
  35. package/src/statusBar.js +19 -8
  36. package/frontend/dist/assets/index-BGvI4n0T.js +0 -61
  37. package/frontend/dist/assets/index-CANPYzQg.css +0 -1
package/README.md CHANGED
@@ -4,7 +4,7 @@ mouaif is a mobile-first AI coding assistant for local projects. Connect your pr
4
4
 
5
5
  ## Requirements
6
6
 
7
- - Node.js 18 or newer
7
+ - Node.js 20 or newer
8
8
  - A supported AI provider account, or a local Ollama installation
9
9
 
10
10
  ## Install
package/bin/mouaif.js CHANGED
@@ -157,11 +157,7 @@ function runWorker(options) {
157
157
  console.log(` REST: POST /data — update data`);
158
158
  console.log(` SSE: GET /events — subscribe to events`);
159
159
  console.log(` CDP: /api/inspector/ + WS /api/inspector/proxy`);
160
- if (authEnabled && accessAuth.disabled()) {
161
- console.log('');
162
- console.log('🔓 App access is disabled from the app (Settings → Access & passkeys).');
163
- console.log(' Re-enable it in Settings, or restart with --auth-setup to re-assert protection.');
164
- } else if (authEnabled && (options.authSetup || !accessAuth.configured())) {
160
+ if (authEnabled && (options.authSetup || !accessAuth.configured())) {
165
161
  const setup = accessAuth.createSetupCode();
166
162
  const setupUrl = servedOrigin + '/#/setup?code=' + encodeURIComponent(setup.code);
167
163
  console.log('');
@@ -1 +1 @@
1
- import{d as f,h as M,u as B,k as a,f as T}from"./index-BGvI4n0T.js";async function D(e,o){const s=new URLSearchParams;e&&s.set("projectDir",e),o&&s.set("dir",o);const i=await T("/api/files?"+s.toString());return i.status!==200?{error:i.body&&i.body.error||"HTTP "+i.status}:{body:i.body}}function H(e){const o=e.projectDir||"",s=e.onPick||(()=>{}),i=e.onClose||(()=>{}),[d,m]=f(o||""),[u,C]=f(""),[b,h]=f([]),[k,p]=f(!1),[_,y]=f("");async function l(t){const n=typeof t=="string"&&t?t:o||"";p(!0),y("");const r=await D(o,n);if(r.error){y(r.error),h([]),p(!1);return}m(r.body.dir),C(r.body.browseTop||""),h(Array.isArray(r.body.entries)?r.body.entries:[]),p(!1)}M(()=>{l(o)},[o]);const x=B({onClose:()=>{i&&i()}});function w(){const t=d||"";if(!t)return;const n=u||"";if(n&&t===n)return;const r=t.replace(/[\\/]+$/,""),c=Math.max(r.lastIndexOf("\\"),r.lastIndexOf("/"));if(c<=0){l(n);return}const v=r.slice(0,c);if(n&&v===n){l(n);return}l(v)}function g(t){if(t.type==="dir"){l(t.path);return}t.binary||s(t.relPath)}function P(){const t=d||"";if(!t)return null;const n=u||"";if(n&&t===n)return null;const r=t.replace(/[\\/]+$/,""),c=Math.max(r.lastIndexOf("\\"),r.lastIndexOf("/"));return c>0?r.slice(0,c):n||null}return a("div",{class:"afp__overlay",role:"dialog","aria-modal":"true","aria-label":e.label||"Pick an agent file",onClick:t=>{t.target===t.currentTarget&&i()}},a("div",{class:"afp__sheet",ref:x},a("div",{class:"afp__head"},a("div",{class:"afp__title"},"Pick a file"),a("div",{class:"afp__sub"},e.description||"Tapping a file adds its project-relative path to the list."),a("div",{class:"afp__path-row"},a("button",{class:"icon-btn afp__iconbtn",type:"button",onClick:w,"aria-label":"Up one folder",title:"Up"},a("svg",{viewBox:"0 0 24 24",width:16,height:16,"aria-hidden":"true"},a("path",{d:"M12 4 4 12l8 8 1.4-1.4L8.8 14H20v-2H8.8l4.6-4.6L12 4Z",fill:"currentColor",transform:"rotate(-90 12 12)"}))),a("div",{class:"afp__path"},d||"project"),a("button",{class:"icon-btn icon-btn--close afp__iconbtn",type:"button",onClick:i,"aria-label":"Close",title:"Close"},a("svg",{viewBox:"0 0 24 24",width:16,height:16,"aria-hidden":"true"},a("path",{d:"M18.3 5.71 12 12l6.3 6.29-1.41 1.42L10.59 13.4 4.3 19.71 2.88 18.3 9.17 12 2.88 5.71 4.3 4.3l6.29 6.29 6.3-6.29 1.41 1.41Z",fill:"currentColor"}))))),a("div",{class:"afp__body"},_?a("p",{class:"afp__err"},_):a("ul",{class:"afp__list","aria-label":"Files and folders"},b.length===0?a("li",{class:"afp__empty"},k?"loading…":"no files here"):b.map(t=>a("li",{key:t.path,class:"afp__row"+(t.binary?" afp__row--binary":""),role:"button",tabindex:t.binary?-1:0,"aria-disabled":t.binary?"true":"false",title:t.binary?"binary file — cannot be picked here":t.relPath||t.path,onClick:()=>g(t),onKeydown:n=>{t.binary||(n.key==="Enter"||n.key===" ")&&(n.preventDefault(),g(t))}},a("span",{class:"afp__row-icon","aria-hidden":"true"},t.type==="dir"?a("svg",{viewBox:"0 0 24 24",width:16,height:16},a("path",{d:"M3 6a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6Z",fill:"currentColor"})):a("svg",{viewBox:"0 0 24 24",width:16,height:16},a("path",{d:"M6 2h8l4 4v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2Zm7 1.5V7h3.5L13 3.5Z",fill:"currentColor"}))),a("span",{class:"afp__row-name"},t.name),t.type==="dir"?a("span",{class:"afp__row-meta"},t.hasChildren?"…":"·"):a("span",{class:"afp__row-meta"},t.binary?"binary":t.size<1024?t.size+" B":Math.round(t.size/1024)+" KB")))),a("div",{class:"afp__foot"},P()?a("button",{class:"btn btn--ghost afp__up",type:"button",onClick:w},"↑ Up"):null,a("button",{class:"btn",type:"button",onClick:i},"Cancel")))))}export{H as A};
1
+ import{d as f,h as M,u as B,k as a,f as T}from"./index-BDkCsON6.js";async function D(e,o){const s=new URLSearchParams;e&&s.set("projectDir",e),o&&s.set("dir",o);const i=await T("/api/files?"+s.toString());return i.status!==200?{error:i.body&&i.body.error||"HTTP "+i.status}:{body:i.body}}function H(e){const o=e.projectDir||"",s=e.onPick||(()=>{}),i=e.onClose||(()=>{}),[d,m]=f(o||""),[u,C]=f(""),[b,h]=f([]),[k,p]=f(!1),[_,y]=f("");async function l(t){const n=typeof t=="string"&&t?t:o||"";p(!0),y("");const r=await D(o,n);if(r.error){y(r.error),h([]),p(!1);return}m(r.body.dir),C(r.body.browseTop||""),h(Array.isArray(r.body.entries)?r.body.entries:[]),p(!1)}M(()=>{l(o)},[o]);const x=B({onClose:()=>{i&&i()}});function w(){const t=d||"";if(!t)return;const n=u||"";if(n&&t===n)return;const r=t.replace(/[\\/]+$/,""),c=Math.max(r.lastIndexOf("\\"),r.lastIndexOf("/"));if(c<=0){l(n);return}const v=r.slice(0,c);if(n&&v===n){l(n);return}l(v)}function g(t){if(t.type==="dir"){l(t.path);return}t.binary||s(t.relPath)}function P(){const t=d||"";if(!t)return null;const n=u||"";if(n&&t===n)return null;const r=t.replace(/[\\/]+$/,""),c=Math.max(r.lastIndexOf("\\"),r.lastIndexOf("/"));return c>0?r.slice(0,c):n||null}return a("div",{class:"afp__overlay",role:"dialog","aria-modal":"true","aria-label":e.label||"Pick an agent file",onClick:t=>{t.target===t.currentTarget&&i()}},a("div",{class:"afp__sheet",ref:x},a("div",{class:"afp__head"},a("div",{class:"afp__title"},"Pick a file"),a("div",{class:"afp__sub"},e.description||"Tapping a file adds its project-relative path to the list."),a("div",{class:"afp__path-row"},a("button",{class:"icon-btn afp__iconbtn",type:"button",onClick:w,"aria-label":"Up one folder",title:"Up"},a("svg",{viewBox:"0 0 24 24",width:16,height:16,"aria-hidden":"true"},a("path",{d:"M12 4 4 12l8 8 1.4-1.4L8.8 14H20v-2H8.8l4.6-4.6L12 4Z",fill:"currentColor",transform:"rotate(-90 12 12)"}))),a("div",{class:"afp__path"},d||"project"),a("button",{class:"icon-btn icon-btn--close afp__iconbtn",type:"button",onClick:i,"aria-label":"Close",title:"Close"},a("svg",{viewBox:"0 0 24 24",width:16,height:16,"aria-hidden":"true"},a("path",{d:"M18.3 5.71 12 12l6.3 6.29-1.41 1.42L10.59 13.4 4.3 19.71 2.88 18.3 9.17 12 2.88 5.71 4.3 4.3l6.29 6.29 6.3-6.29 1.41 1.41Z",fill:"currentColor"}))))),a("div",{class:"afp__body"},_?a("p",{class:"afp__err"},_):a("ul",{class:"afp__list","aria-label":"Files and folders"},b.length===0?a("li",{class:"afp__empty"},k?"loading…":"no files here"):b.map(t=>a("li",{key:t.path,class:"afp__row"+(t.binary?" afp__row--binary":""),role:"button",tabindex:t.binary?-1:0,"aria-disabled":t.binary?"true":"false",title:t.binary?"binary file — cannot be picked here":t.relPath||t.path,onClick:()=>g(t),onKeydown:n=>{t.binary||(n.key==="Enter"||n.key===" ")&&(n.preventDefault(),g(t))}},a("span",{class:"afp__row-icon","aria-hidden":"true"},t.type==="dir"?a("svg",{viewBox:"0 0 24 24",width:16,height:16},a("path",{d:"M3 6a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6Z",fill:"currentColor"})):a("svg",{viewBox:"0 0 24 24",width:16,height:16},a("path",{d:"M6 2h8l4 4v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2Zm7 1.5V7h3.5L13 3.5Z",fill:"currentColor"}))),a("span",{class:"afp__row-name"},t.name),t.type==="dir"?a("span",{class:"afp__row-meta"},t.hasChildren?"…":"·"):a("span",{class:"afp__row-meta"},t.binary?"binary":t.size<1024?t.size+" B":Math.round(t.size/1024)+" KB")))),a("div",{class:"afp__foot"},P()?a("button",{class:"btn btn--ghost afp__up",type:"button",onClick:w},"↑ Up"):null,a("button",{class:"btn",type:"button",onClick:i},"Cancel")))))}export{H as A};
@@ -1,4 +1,4 @@
1
- import{d as s,A as a,am as D,a3 as C,h as T,f as S,u as A,k as t}from"./index-BGvI4n0T.js";function U(E){const{projectDir:i,onClose:p}=E,[I,_]=s(!0),[w,L]=s(""),[H,B]=s(""),[x,J]=s(i||""),[N,R]=s(!1),[O,P]=s(!1),l=a(null),u=a(null),h=a(null),K=a(null),[f,j]=s(""),c=a(null);c.current||(c.current=new D);const y=a(!0),m=C((e,r)=>{if(c.current||(c.current=new D),r==="exit"){c.current.write(`\r
1
+ import{d as s,A as a,am as D,a3 as C,h as T,f as S,u as A,k as t}from"./index-BDkCsON6.js";function U(E){const{projectDir:i,onClose:p}=E,[I,_]=s(!0),[w,L]=s(""),[H,B]=s(""),[x,J]=s(i||""),[N,R]=s(!1),[O,P]=s(!1),l=a(null),u=a(null),h=a(null),K=a(null),[f,j]=s(""),c=a(null);c.current||(c.current=new D);const y=a(!0),m=C((e,r)=>{if(c.current||(c.current=new D),r==="exit"){c.current.write(`\r
2
2
   └─ process exited with code `+e+`
3
3
  `),j(c.current.render());return}c.current.write(String(e||"")),j(c.current.render())},[]);T(()=>{const e=l.current;if(!e)return;const r=e.scrollHeight-e.scrollTop-e.clientHeight<48;if(c.current?c.current.isFullScreen:!1){const n=e.scrollTop,g=e.scrollHeight;e.textContent=f,y.current||r?e.scrollTop=e.scrollHeight:e.scrollTop=n+(e.scrollHeight-g)}else if(y.current||r)e.textContent=f,e.scrollTop=e.scrollHeight;else{const n=e.scrollTop;e.textContent=f,e.scrollTop=n}},[f]);const M=C(e=>{if(l.current&&l.current._onScroll&&l.current.removeEventListener("scroll",l.current._onScroll),l.current=e,e){const r=()=>{y.current=e.scrollHeight-e.scrollTop-e.clientHeight<48};e._onScroll=r,e.addEventListener("scroll",r,{passive:!0})}},[]);T(()=>()=>{l.current&&l.current._onScroll&&l.current.removeEventListener("scroll",l.current._onScroll)},[]),T(()=>{let e=!1,r=null;async function o(){try{const n=await S("/api/tools/cli/session?projectDir="+encodeURIComponent(i||""));if(e)return;if(n.status!==200){L(n.body&&n.body.error||"HTTP "+n.status),_(!1);return}h.current=n.body.id,B(n.body.shell||""),P(!!n.body.interactive),n.body.projectDir&&J(n.body.projectDir),r=new EventSource("/events"),K.current=r,r.addEventListener("cli_output",g=>{let d;try{d=JSON.parse(g.data)}catch{return}!d||d.id!==h.current||m(d.data,d.stream)}),_(!1),u.current&&u.current.focus()}catch(n){e||(L(String(n)),_(!1))}}return o(),()=>{e=!0,r&&r.close(),h.current&&S("/api/tools/cli/close",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:i})}).catch(()=>{})}},[i]);const q=A({onClose:()=>{p&&p()}}),[v,b]=s(""),k=C(async(e,r)=>{R(!0);try{const o=await S("/api/tools/cli/command",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:i,cmd:e,raw:!!r})});o.status!==200&&m(`
4
4
  `+(o.body&&o.body.error||"HTTP "+o.status)+`
@@ -1,2 +1,2 @@
1
- import{d as o,b as R,h as W,f as T,X as Bt,A as f,Y as he,Z as $,a0 as Et,a1 as Nt,a2 as me,a3 as tt,a4 as ye,a5 as be,a6 as ve,a7 as ge,k as e,a8 as _e,a9 as et,aa as Ot,R as we,ab as ke,ac as Te,ad as Re,ae as Ce,af as Me,ag as Ie,ah as Pe,ai as Ae,aj as Se,ak as je,al as De,p as Le,s as xe}from"./index-BGvI4n0T.js";const rt="dictation";function Ue(){const[l,p]=o([]),[m,Ft]=o([]),[y,nt]=o(""),[A,at]=o(""),[ot,Ut]=o(""),[st,Ht]=o(""),[Kt,it]=o(!0),[w,ct]=o(!0),[lt,dt]=o(""),[ut,zt]=o(()=>({dir:R.value&&R.value.dir||"",name:R.value&&R.value.name||""})),u=ut.dir;W(()=>{if(u)return;let t=!1;return(async()=>{try{const r=await T("/api/projects/registered"),a=r.status===200&&Array.isArray(r.body&&r.body.projects)?r.body.projects[0]:null;!t&&a&&zt({dir:a.path||"",name:a.name||a.path||""})}catch{}})(),()=>{t=!0}},[u]);const[pt]=o(()=>Bt()),[_,S]=o(!1),[ft,ht]=o(0),[mt,yt]=o(0),[g,bt]=o(null),[vt,gt]=o(""),[C,Y]=o(""),[M,j]=o(!1),[_t,D]=o(""),[Wt,i]=o(""),[Yt,c]=o(""),[q,qt]=o(null),wt=f(""),L=f(null),x=f(null),I=f([]),B=f(0),E=f(null),N=f(null),O=f(null),F=f(null),J=f(null),V=f(null),[k,U]=o(!1),[kt,Jt]=o([]),[Tt,Vt]=o([]);function X(t,r,a){const s=!!(a&&a.onlyIfEmpty),n=t.models;p(n),Ft(t.kinds),Jt(Array.isArray(t.liveFailures)?t.liveFailures:[]),Vt(Array.isArray(t.providers)?t.providers:[]);const d=Re(n,r);d&&(!s||!wt.current)&&(nt(d.modelId),at(d.providerId))}W(()=>{let t=!1;return(async()=>{ct(!0),dt("");let r={};try{const n=await T("/api/settings");n.status===200&&n.body&&n.body.app&&(r=n.body.app[rt]||{})}catch{}t||it(he(r));let a={models:[],kinds:[],total:0};try{a=await $(u,{live:!1})}catch(n){t||dt(n&&n.message?n.message:"Could not load models")}if(t)return;X(a,r);const s=Array.isArray(a.providers)&&a.providers.length>0;if(ct(!1),!(!u||!s)){U(!0);try{const n=await $(u);t||X(n,r,{onlyIfEmpty:!0})}catch{}finally{t||U(!1)}}})(),()=>{t=!0}},[u]);const Rt=f(null),[Xt,Ct]=o(()=>new Set),[Gt,Mt]=o([]);function P(){const t=Rt.current||{props:{projectDir:""},recentModels:[]};return Rt.current=t,t.props.projectDir=u,t}W(()=>{let t=!1;return Ct(Et(P())),Mt(Nt(P())),me(P()).then(r=>{!t&&r&&Mt(Nt(P()))}),()=>{t=!0}},[u]);function Qt(t){const r=P();je(r,t.provider||"",t.id),Ct(Et(r))}const H=tt(()=>{E.current&&(clearInterval(E.current),E.current=null),N.current&&(clearInterval(N.current),N.current=null),O.current&&(clearTimeout(O.current),O.current=null)},[]),G=tt(()=>{const t=x.current;if(x.current=null,t&&typeof t.getTracks=="function")for(const r of t.getTracks())try{r.stop()}catch{}if(F.current){try{F.current.close()}catch{}F.current=null}J.current=null,V.current=null,yt(0)},[]),It=tt(()=>{H();const t=L.current;if(t&&t.state!=="inactive")try{t.stop()}catch{}S(!1)},[H]);W(()=>()=>{H();const t=L.current;if(t&&t.state!=="inactive")try{t.stop()}catch{}const r=x.current;if(r&&typeof r.getTracks=="function")for(const a of r.getTracks())try{a.stop()}catch{}},[H]);function Zt(t,r){try{const a=r.AudioContext||r.webkitAudioContext;if(!a)return;const s=new a,n=s.createMediaStreamSource(t),d=s.createAnalyser();d.fftSize=1024,n.connect(d),F.current=s,J.current=d,V.current=new Uint8Array(d.fftSize),N.current=setInterval(()=>{const z=J.current,h=V.current;if(!z||!h)return;z.getByteTimeDomainData(h);let Lt=0;for(let Z=0;Z<h.length;Z++){const xt=(h[Z]-128)/128;Lt+=xt*xt}yt(Math.min(1,Math.sqrt(Lt/h.length)*Math.SQRT2))},250)}catch{}}async function $t(){i(""),c("");const t=typeof window<"u"?window:null;if(!t||!Bt(t)){i("This browser cannot record audio."),c("error");return}let r;try{r=await t.navigator.mediaDevices.getUserMedia({audio:!0})}catch(n){i(n&&n.name==="NotAllowedError"?"Microphone permission was refused. Allow it in the browser, then tap again.":"Could not open the microphone: "+(n&&n.message||n)),c("error");return}x.current=r;const a=Me(t.MediaRecorder,t);let s;try{s=a?new t.MediaRecorder(r,{mimeType:a}):new t.MediaRecorder(r)}catch{try{s=new t.MediaRecorder(r)}catch(n){G(),i("Could not start the recorder: "+(n&&n.message||n)),c("error");return}}I.current=[],s.ondataavailable=n=>{n&&n.data&&n.data.size&&I.current.push(n.data)},s.onstop=()=>{const n=s.mimeType||a||"audio/webm",d=I.current.length?new Blob(I.current,{type:n}):null;I.current=[],L.current=null,G(),S(!1),d&&d.size?(bt(d),gt(n),i("Recorded "+et(Date.now()-B.current)+". Ready to transcribe."),c("success")):(i("Nothing was captured — check that the microphone is not muted."),c("error"))},s.onerror=()=>{G(),S(!1),i("The recorder stopped unexpectedly."),c("error")},L.current=s,B.current=Date.now(),bt(null),gt(""),ht(0),S(!0),s.start(),E.current=setInterval(()=>ht(Date.now()-B.current),200),O.current=setTimeout(()=>It(),Ot),Zt(r,t)}async function te(){if(!y){i("Pick a dictation model first."),c("error");return}if(!g){i("Record something first."),c("error");return}j(!0),D("transcribe"),i("Transcribing with "+y+"…"),c("busy");try{const t=await Ie(g),r=await Pe({projectDir:u,modelId:y,providerId:A,kind:v&&v.kind||"",audioBase64:t,mimeType:vt||g.type||"audio/webm",filename:Ae(vt||g.type,B.current),language:ot,prompt:st});Y(r.text||""),qt({model:r.model,kind:r.kind,bytes:r.bytes,durationMs:r.durationMs,usage:r.usage||null,costLabel:Se(r).label}),i("Transcribed with "+(r.model&&r.model.id||y)+"."),c("success")}catch(t){i(t&&t.message||"Transcription failed"),c("error")}finally{j(!1),D("")}}async function ee(){try{await navigator.clipboard.writeText(C),i("Transcript copied."),c("success")}catch{i("Could not copy — long-press the text instead."),c("error")}}async function re(t){const r=u;if(!r){i("Open a project first, then this can hand the text to a chat."),c("error");return}j(!0),D("handoff");try{const a=await T("/api/chats?projectDir="+encodeURIComponent(r)+"&limit=1");if(a.status!==200)throw new Error(a.body&&a.body.error||"HTTP "+a.status);const s=a.body&&a.body.chats&&a.body.chats[0]||null;if(!s)throw new Error("This project has no chat yet — start one in the Chats tab.");const n=await T("/api/chats/"+encodeURIComponent(s.id)+"?projectDir="+encodeURIComponent(r));if(n.status!==200||!n.body||!n.body.chat)throw new Error(n.body&&n.body.error||"HTTP "+n.status);const d=typeof n.body.chat.draft=="string"?n.body.chat.draft:"",z=d.trim()?d.replace(/\s+$/,"")+`
1
+ import{d as o,b as R,h as W,f as T,X as Bt,A as f,Y as he,Z as $,a0 as Et,a1 as Nt,a2 as me,a3 as tt,a4 as ye,a5 as be,a6 as ve,a7 as ge,k as e,a8 as _e,a9 as et,aa as Ot,R as we,ab as ke,ac as Te,ad as Re,ae as Ce,af as Me,ag as Ie,ah as Pe,ai as Ae,aj as Se,ak as je,al as De,p as Le,s as xe}from"./index-BDkCsON6.js";const rt="dictation";function Ue(){const[l,p]=o([]),[m,Ft]=o([]),[y,nt]=o(""),[A,at]=o(""),[ot,Ut]=o(""),[st,Ht]=o(""),[Kt,it]=o(!0),[w,ct]=o(!0),[lt,dt]=o(""),[ut,zt]=o(()=>({dir:R.value&&R.value.dir||"",name:R.value&&R.value.name||""})),u=ut.dir;W(()=>{if(u)return;let t=!1;return(async()=>{try{const r=await T("/api/projects/registered"),a=r.status===200&&Array.isArray(r.body&&r.body.projects)?r.body.projects[0]:null;!t&&a&&zt({dir:a.path||"",name:a.name||a.path||""})}catch{}})(),()=>{t=!0}},[u]);const[pt]=o(()=>Bt()),[_,S]=o(!1),[ft,ht]=o(0),[mt,yt]=o(0),[g,bt]=o(null),[vt,gt]=o(""),[C,Y]=o(""),[M,j]=o(!1),[_t,D]=o(""),[Wt,i]=o(""),[Yt,c]=o(""),[q,qt]=o(null),wt=f(""),L=f(null),x=f(null),I=f([]),B=f(0),E=f(null),N=f(null),O=f(null),F=f(null),J=f(null),V=f(null),[k,U]=o(!1),[kt,Jt]=o([]),[Tt,Vt]=o([]);function X(t,r,a){const s=!!(a&&a.onlyIfEmpty),n=t.models;p(n),Ft(t.kinds),Jt(Array.isArray(t.liveFailures)?t.liveFailures:[]),Vt(Array.isArray(t.providers)?t.providers:[]);const d=Re(n,r);d&&(!s||!wt.current)&&(nt(d.modelId),at(d.providerId))}W(()=>{let t=!1;return(async()=>{ct(!0),dt("");let r={};try{const n=await T("/api/settings");n.status===200&&n.body&&n.body.app&&(r=n.body.app[rt]||{})}catch{}t||it(he(r));let a={models:[],kinds:[],total:0};try{a=await $(u,{live:!1})}catch(n){t||dt(n&&n.message?n.message:"Could not load models")}if(t)return;X(a,r);const s=Array.isArray(a.providers)&&a.providers.length>0;if(ct(!1),!(!u||!s)){U(!0);try{const n=await $(u);t||X(n,r,{onlyIfEmpty:!0})}catch{}finally{t||U(!1)}}})(),()=>{t=!0}},[u]);const Rt=f(null),[Xt,Ct]=o(()=>new Set),[Gt,Mt]=o([]);function P(){const t=Rt.current||{props:{projectDir:""},recentModels:[]};return Rt.current=t,t.props.projectDir=u,t}W(()=>{let t=!1;return Ct(Et(P())),Mt(Nt(P())),me(P()).then(r=>{!t&&r&&Mt(Nt(P()))}),()=>{t=!0}},[u]);function Qt(t){const r=P();je(r,t.provider||"",t.id),Ct(Et(r))}const H=tt(()=>{E.current&&(clearInterval(E.current),E.current=null),N.current&&(clearInterval(N.current),N.current=null),O.current&&(clearTimeout(O.current),O.current=null)},[]),G=tt(()=>{const t=x.current;if(x.current=null,t&&typeof t.getTracks=="function")for(const r of t.getTracks())try{r.stop()}catch{}if(F.current){try{F.current.close()}catch{}F.current=null}J.current=null,V.current=null,yt(0)},[]),It=tt(()=>{H();const t=L.current;if(t&&t.state!=="inactive")try{t.stop()}catch{}S(!1)},[H]);W(()=>()=>{H();const t=L.current;if(t&&t.state!=="inactive")try{t.stop()}catch{}const r=x.current;if(r&&typeof r.getTracks=="function")for(const a of r.getTracks())try{a.stop()}catch{}},[H]);function Zt(t,r){try{const a=r.AudioContext||r.webkitAudioContext;if(!a)return;const s=new a,n=s.createMediaStreamSource(t),d=s.createAnalyser();d.fftSize=1024,n.connect(d),F.current=s,J.current=d,V.current=new Uint8Array(d.fftSize),N.current=setInterval(()=>{const z=J.current,h=V.current;if(!z||!h)return;z.getByteTimeDomainData(h);let Lt=0;for(let Z=0;Z<h.length;Z++){const xt=(h[Z]-128)/128;Lt+=xt*xt}yt(Math.min(1,Math.sqrt(Lt/h.length)*Math.SQRT2))},250)}catch{}}async function $t(){i(""),c("");const t=typeof window<"u"?window:null;if(!t||!Bt(t)){i("This browser cannot record audio."),c("error");return}let r;try{r=await t.navigator.mediaDevices.getUserMedia({audio:!0})}catch(n){i(n&&n.name==="NotAllowedError"?"Microphone permission was refused. Allow it in the browser, then tap again.":"Could not open the microphone: "+(n&&n.message||n)),c("error");return}x.current=r;const a=Me(t.MediaRecorder,t);let s;try{s=a?new t.MediaRecorder(r,{mimeType:a}):new t.MediaRecorder(r)}catch{try{s=new t.MediaRecorder(r)}catch(n){G(),i("Could not start the recorder: "+(n&&n.message||n)),c("error");return}}I.current=[],s.ondataavailable=n=>{n&&n.data&&n.data.size&&I.current.push(n.data)},s.onstop=()=>{const n=s.mimeType||a||"audio/webm",d=I.current.length?new Blob(I.current,{type:n}):null;I.current=[],L.current=null,G(),S(!1),d&&d.size?(bt(d),gt(n),i("Recorded "+et(Date.now()-B.current)+". Ready to transcribe."),c("success")):(i("Nothing was captured — check that the microphone is not muted."),c("error"))},s.onerror=()=>{G(),S(!1),i("The recorder stopped unexpectedly."),c("error")},L.current=s,B.current=Date.now(),bt(null),gt(""),ht(0),S(!0),s.start(),E.current=setInterval(()=>ht(Date.now()-B.current),200),O.current=setTimeout(()=>It(),Ot),Zt(r,t)}async function te(){if(!y){i("Pick a dictation model first."),c("error");return}if(!g){i("Record something first."),c("error");return}j(!0),D("transcribe"),i("Transcribing with "+y+"…"),c("busy");try{const t=await Ie(g),r=await Pe({projectDir:u,modelId:y,providerId:A,kind:v&&v.kind||"",audioBase64:t,mimeType:vt||g.type||"audio/webm",filename:Ae(vt||g.type,B.current),language:ot,prompt:st});Y(r.text||""),qt({model:r.model,kind:r.kind,bytes:r.bytes,durationMs:r.durationMs,usage:r.usage||null,costLabel:Se(r).label}),i("Transcribed with "+(r.model&&r.model.id||y)+"."),c("success")}catch(t){i(t&&t.message||"Transcription failed"),c("error")}finally{j(!1),D("")}}async function ee(){try{await navigator.clipboard.writeText(C),i("Transcript copied."),c("success")}catch{i("Could not copy — long-press the text instead."),c("error")}}async function re(t){const r=u;if(!r){i("Open a project first, then this can hand the text to a chat."),c("error");return}j(!0),D("handoff");try{const a=await T("/api/chats?projectDir="+encodeURIComponent(r)+"&limit=1");if(a.status!==200)throw new Error(a.body&&a.body.error||"HTTP "+a.status);const s=a.body&&a.body.chats&&a.body.chats[0]||null;if(!s)throw new Error("This project has no chat yet — start one in the Chats tab.");const n=await T("/api/chats/"+encodeURIComponent(s.id)+"?projectDir="+encodeURIComponent(r));if(n.status!==200||!n.body||!n.body.chat)throw new Error(n.body&&n.body.error||"HTTP "+n.status);const d=typeof n.body.chat.draft=="string"?n.body.chat.draft:"",z=d.trim()?d.replace(/\s+$/,"")+`
2
2
  `+C:C,h=await T("/api/chats/"+encodeURIComponent(s.id),{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:r,draft:z})});if(h.status!==200)throw new Error(h.body&&h.body.error||"HTTP "+h.status);i(t?'Draft filled in "'+(s.title||s.id)+'" — send it from the chat.':'Draft filled in "'+(s.title||s.id)+'".'),c("success")}catch(a){i(a&&a.message||"Could not reach the chat."),c("error")}finally{j(!1),D("")}}const ne=ye(l),ae=be(l).map(t=>({id:t.id,provider:t.provider||""})),oe=y?{providerId:A,modelId:y}:null,se=ve({text:C,chatId:u,hasRecording:!!g}),ie=l.filter(t=>t.source!=="live").length,ce=l.some(t=>t.source==="live"),Pt=Array.isArray(Tt)?Tt:[],b=Ce({catalogBusy:w,liveBusy:k,transcribing:M&&_t==="transcribe",handoff:M&&_t==="handoff"}),Q=De({catalogBusy:w,liveBusy:k,projectCount:ie,hasLive:ce});async function le(){if(!(k||w)){U(!0),i(""),c("");try{const t=await $(u,{refresh:!0});X(t,{modelId:y,providerId:A},{onlyIfEmpty:!1})}catch(t){i(t&&t.message||"Could not refresh the model list."),c("error")}finally{U(!1)}}}function de(t){const r=t?t.modelId:"",a=t?t.providerId:"";wt.current=r,nt(r),at(a),i(""),c(""),At({modelId:r,providerId:a})}const ue=f({record:null,chain:Promise.resolve()});async function At(t){const r=ue.current;return r.record=Object.assign({},r.record,t),r.chain=r.chain.then(async()=>{try{const a=await T("/api/settings"),s=a.status===200&&a.body&&a.body.app&&a.body.app[rt]||{},n=Object.assign({},s,r.record);r.record=n,await xe({[rt]:n})}catch{}}),r.chain}function pe(t){it(t),At({live:t})}const v=l.find(t=>t.id===y&&(t.provider||"")===A)||null,St=v&&v.source==="live"?ge(v):"",K=v&&v.kind||"",jt=Ee(ut,u),Dt=_?"Stop":ft?"Record again":"Record",fe=!!g&&!!y&&!M&&!_;return e("section",{class:"dictation"},e("div",{class:"view-head"},e("a",{href:"#/settings",class:"view-back","aria-label":"Back to settings"},"←"),e("h2",{class:"view-title"},"Dictation")),e("div",{class:"group"},e("div",{class:"group__title"},"Dictation model",jt?e("span",{class:"group__title-note"},jt):null),e("div",{class:"dictation__fields"},e("div",{class:"dictation__field"},e(we,{models:ne,value:oe,onChange:de,onOpen:()=>{},placeholder:w?"Loading models…":Be(l)||"Pick a model",ariaLabel:"Pick dictation model",recommended:ae,pinned:Xt,onTogglePin:Qt,recent:Gt,variant:"sheet",refreshEmpty:"No dictation models"})),v&&K?e("div",{class:"dictation__field"},e("span",{class:"label"},"Sends as"),e("span",{class:"dictation__kind-readout",title:ke(m,K)||K},Te(K))):null),e("ul",{class:"dictation__options"},e("li",null,e("label",{class:"dictation__option-row",for:"dictation-live"},e("span",{class:"dictation__option-body"},e("span",{class:"dictation__option-title"},"Live transcription"),e("span",{class:"dictation__option-note"},"In a chat, the composer fills in as you speak instead of waiting for you to stop. This page still records and transcribes once.")),e("span",{class:"switch"},e("input",{id:"dictation-live",type:"checkbox",checked:Kt,onChange:t=>pe(!!(t.target&&t.target.checked))}),e("span",{class:"switch__track","aria-hidden":"true"},e("span",{class:"switch__thumb"}))))),e("li",null,e("div",{class:"dictation__option-row"},e("span",{class:"dictation__option-body"},e("label",{class:"dictation__option-title",for:"dictation-language"},"Language"),e("span",{class:"dictation__option-note"},"Optional. An ISO-639-1 or BCP-47 code (en, fr, de) that biases decoding instead of leaving it to guess.")),e("input",{class:"input dictation__option-input",id:"dictation-language",type:"text",placeholder:"en, fr, de…",value:ot,onInput:t=>Ut(t.target.value.slice(0,20))}))),e("li",null,e("div",{class:"dictation__option-row"},e("span",{class:"dictation__option-body"},e("label",{class:"dictation__option-title",for:"dictation-prompt"},"Vocabulary hint"),e("span",{class:"dictation__option-note"},"Optional. Names and jargon the provider should expect — the OpenAI-style prompt field.")),e("input",{class:"input dictation__option-input",id:"dictation-prompt",type:"text",placeholder:"mouaif, MediaRecorder, SSE…",value:st,onInput:t=>Ht(t.target.value.slice(0,400))})))),e("div",{class:"dictation__catalog-note"},e("span",{class:"hint hint--compact dictation__catalog-line","aria-busy":Q.loading?"true":void 0},Q.loading?e("span",{class:"dictation__spinner","aria-hidden":"true"}):null,Q.text),u&&Pt.length?e("button",{class:"dictation__refresh",type:"button",disabled:k||w,onClick:le,"aria-label":"Refresh the model list from the provider"},k?"Refreshing…":"Refresh"):null),St?e("p",{class:"hint hint--compact dictation__selected-badge"},v.id+" — "+St):null,lt?e("p",{class:"hint hint--compact dictation__error"},"Could not read the model list: "+lt):null,kt.length?e("div",{class:"dictation__failures"},kt.map(t=>e("p",{key:t.provider,class:"hint hint--compact dictation__error"},"No models from "+Ne(t.provider)+" — "+t.error))):null,!w&&!k&&!l.length?e("p",{class:"hint hint--compact"},Pt.length?"Your providers returned no usable models. Check the connection in Settings → Providers, then tap Refresh.":"No models yet, and no provider connection to list them from. Connect a provider in Settings → Providers (or add a model to this project in .mouaif.json), then come back."):null),e("div",{class:"group"},e("div",{class:"group__title"},"Test"),e("div",{class:"dictation__card dictation__card--recorder"},e("div",{class:"dictation__clock"},e("span",{class:"dictation__time","aria-live":"polite"},et(ft)),e("span",{class:"dictation__limit"},"max "+et(Ot))),e("div",{class:"dictation__meter",role:"meter","aria-label":"Input level","aria-valuenow":Math.round(mt*100),"aria-valuemin":0,"aria-valuemax":100},e("span",{class:"dictation__meter-fill",style:{width:Math.round((_?mt:0)*100)+"%"}})),e("button",{class:"dictation__record"+(_?" is-recording":g?" is-secondary":""),type:"button",disabled:!pt||M,onClick:_?It:$t,"aria-busy":b==="handoff"?"true":void 0,"aria-label":_?"Stop recording":b==="handoff"?"Working…":Dt},b==="handoff"?e("span",{class:"dictation__spinner","aria-hidden":"true"}):e("span",{class:"dictation__record-dot","aria-hidden":"true"}),e("span",{class:"dictation__record-label"},b==="handoff"?"Working…":Dt)),g&&!_?e("div",{class:"dictation__recorder-actions"},e("span",{class:"dictation__ready"},"Recording ready"),e("button",{class:"dictation__transcribe",type:"button",disabled:!fe,onClick:te,"aria-busy":b==="transcribe"?"true":void 0,"aria-label":"Transcribe the recording"},b==="transcribe"?e("span",{class:"dictation__spinner dictation__spinner--on-accent","aria-hidden":"true"}):null,b==="transcribe"?"Transcribing…":"Transcribe")):null,pt?null:e("p",{class:"hint hint--compact"},"This browser cannot record audio. Dictation needs a browser with MediaRecorder and microphone access."))),e("div",{class:"group"},e("div",{class:"group__title"},"Transcript"),e("div",{class:"dictation__transcript","aria-busy":b==="transcribe"||b==="handoff"?"true":void 0},e("textarea",{class:"input dictation__textarea",rows:6,placeholder:"The transcript appears here and stays editable.",value:C,"aria-label":"Transcript",onInput:t=>Y(t.target.value)}),e("div",{class:"dictation__actions"},se.map(t=>e("button",{key:t.id,class:"btn"+(t.id==="send"?" btn--primary":"")+(t.id==="clear"?" btn--ghost":""),type:"button",disabled:t.disabled||M,onClick:()=>{if(t.id==="copy")return ee();if(t.id==="clear"){Y(""),i(""),c("");return}return re(t.id==="send")}},t.label)))),q?e("p",{class:"hint hint--compact dictation__last-run",title:Oe(q)},_e(q)):null),e("p",{class:"status dictation__status","aria-live":"polite","data-state":Yt||void 0},Wt))}function Be(l){return l&&l.length?"":"No models in this project"}function Ee(l,p){if(!p)return"no project";const m=R.value&&R.value.dir||"";return m&&m===p?"":l&&l.name||""}function Ne(l){const p=Le(l);return p&&p.label||l}function Oe(l){const p=l&&l.usage;if(!p)return"The provider reported no token counts for this run";const m=[];return p.promptTokens&&m.push("input "+p.promptTokens+" tok"),p.completionTokens&&m.push("output "+p.completionTokens+" tok"),m.length?"Provider usage: "+m.join(", "):"The provider reported no token counts for this run"}export{Ue as DictationView};
@@ -1,2 +1,2 @@
1
- import{A as S,d,a3 as y,h as D,_ as bt,k as e,S as M,D as pt,f as L}from"./index-BGvI4n0T.js";import{b as F,o as yt,l as mt,h as _t,H as vt,c as gt,d as wt,i as Ct,e as xt,f as kt,I as Pt,s as St,k as Dt,m as Mt,r as Lt,q as Ht,J as Tt,a as jt,z as Bt,A as zt,B as At,C as Et,F as Rt,v as Y,g as Zt}from"./codemirror-Bp6CUUFk.js";function Ft(l){if(!l)return null;const n=l.toLowerCase(),o=n.split("/").pop()||n;if(o==="dockerfile")return null;const a=(o.match(/\.[a-z0-9]+$/)||[""])[0];switch(a){case".js":case".jsx":case".mjs":case".cjs":return Y({jsx:a===".jsx"});case".ts":case".tsx":return Y({jsx:a===".tsx",typescript:!0});case".html":case".htm":case".svg":case".xml":case".mdx":return Rt();case".css":case".scss":case".sass":case".less":return Et();case".json":return At();case".md":case".markdown":return zt();case".py":return Bt();default:return null}}async function Ot(l,n){const o=new URLSearchParams;l&&o.set("projectDir",l),n&&o.set("dir",n);const a=await L("/api/files?"+o.toString());return a.status!==200?{error:a.body&&a.body.error||"HTTP "+a.status,code:a.body&&a.body.code}:{body:a.body}}async function Ut(l,n){const o=new URLSearchParams;l&&o.set("projectDir",l),o.set("path",n);const a=await L("/api/file?"+o.toString());return a.status!==200?{error:a.body&&a.body.error||"HTTP "+a.status,code:a.body&&a.body.code}:{body:a.body}}async function Vt(l,n,o){const a=await L("/api/file",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:l,path:n,content:o})});return a.status!==200?{error:a.body&&a.body.error||"HTTP "+a.status,code:a.body&&a.body.code}:{body:a.body}}async function It(l,n){const o=new URLSearchParams;l&&o.set("projectDir",l),o.set("path",n);const a=await L("/api/file-media?"+o.toString());return a.status!==200?{error:a.body&&a.body.error||"HTTP "+a.status,code:a.body&&a.body.code}:{body:a.body}}function qt(l){const n=l.projectDir||"",o=l.onClose||(()=>{}),a=S(n),[H,O]=d(n||""),[v,tt]=d(""),[U,V]=d([]),[et,T]=d(""),[rt,j]=d(!1),[c,I]=d(null),[u,x]=d(null),[Kt,K]=d(!1),[at,g]=d(""),[m,w]=d(!1),[k,G]=d(!1),[B,h]=d(""),[st,z]=d(!1),[nt,it]=d(null),A=S(null),i=S(null),[P,W]=d(!1),E=S(null),b=y(async t=>{const r=typeof t=="string"&&t?t:a.current||n;j(!0),T("loading…");const s=await Ot(n,r);if(s.error){T(s.error),V([]),j(!1);return}a.current=s.body.dir,O(s.body.dir),tt(s.body.browseTop||""),V(Array.isArray(s.body.entries)?s.body.entries:[]),T((s.body.entries?s.body.entries.length:0)+" items"),j(!1)},[n]);D(()=>{b(n)},[b,n]);const _=y(()=>m?window.confirm("Discard unsaved changes?"):!0,[m]),R=y(async t=>{if(!_())return;x(null),g(""),h("loading…");const r=await Ut(n,t);if(r.error){h(r.error);return}const s={relPath:r.body.relPath,absPath:r.body.path,content:r.body.content,size:r.body.size,ext:r.body.ext};I(s),w(!1),h(s.size+" bytes")},[n,_]),q=y(async(t,r)=>{if(r&&r.forceText)return R(t);K(!0),g("loading…");const s=await It(n,t);if(K(!1),s.error){g(s.error),x(null);return}I(null),w(!1),h(""),x({relPath:s.body.relPath,absPath:s.body.path,dataUrl:s.body.dataUrl,mime:s.body.mime,size:s.body.size,ext:s.body.ext}),g(s.body.size+" bytes · "+s.body.mime)},[n,R]);bt(()=>{c&&ot(c)},[c]);function ot(t){if(!A.current)return;i.current&&(i.current.destroy(),i.current=null);const r=Ft(t.relPath),s=[mt(),_t(),vt(),gt(),wt(),Ct(),xt(),kt(),Pt(),St(Zt),Dt.of([{key:"Mod-s",preventDefault:!0,run:()=>(E.current&&E.current(),!0)},Mt,...Lt,...Ht,...Tt]),F.lineWrapping,yt,F.updateListener.of(p=>{p.docChanged&&(m||w(!0),B&&B.indexOf("saved")!==0&&h("edited"))})];r&&s.push(r);const f=jt.create({doc:t.content,extensions:s});i.current=new F({state:f,parent:A.current}),requestAnimationFrame(()=>{i.current&&i.current.requestMeasure()})}D(()=>()=>{i.current&&(i.current.destroy(),i.current=null)},[]),D(()=>{u&&i.current&&(i.current.destroy(),i.current=null)},[u]);const Z=y(async()=>{if(!c||!i.current)return;G(!0),h("saving…");const t=i.current.state.doc.toString(),r=await Vt(n,c.relPath,t);if(G(!1),r.error){h("save failed: "+r.error);return}w(!1),h("saved · "+r.body.size+" bytes")},[c,n]);D(()=>{E.current=Z},[Z]);const lt=y(()=>{!c||!i.current||_()&&(i.current.dispatch({changes:{from:0,to:i.current.state.doc.length,insert:c.content}}),w(!1),h("reverted"))},[c,_]),J=y(()=>{_()&&o()},[_,o]);function $(){const t=a.current||"";if(!t)return;const r=v||"";if(r&&t===r)return;const s=t.replace(/[\\/]+$/,""),f=Math.max(s.lastIndexOf("\\"),s.lastIndexOf("/"));if(f<=0){b(r);return}const p=s.slice(0,f);if(r&&p===r){b(r);return}b(p)}function ct(t){if(t.key==="Enter"){t.preventDefault();const r=(H||"").trim();b(r||v||n)}}function dt(){const t=(H||"").trim();b(t||v||n)}function N(t){if(t.type==="dir"){b(t.path);return}if(t.image){q(t.relPath);return}t.binary||R(t.relPath)}function ut(){if(!c||!i.current)return;const t=i.current.state.selection.main;if(t.empty){h("Select code before using Draft Craft."),i.current.focus();return}const r=i.current.state.sliceDoc(t.from,t.to),s=i.current.state.doc.lineAt(t.from).number,f=i.current.state.doc.lineAt(t.to).number;it({projectDir:n,text:c.relPath+":"+s+(f!==s?"-"+f:"")+`
1
+ import{A as S,d,a3 as y,h as D,_ as bt,k as e,S as M,D as pt,f as L}from"./index-BDkCsON6.js";import{b as F,o as yt,l as mt,h as _t,H as vt,c as gt,d as wt,i as Ct,e as xt,f as kt,I as Pt,s as St,k as Dt,m as Mt,r as Lt,q as Ht,J as Tt,a as jt,z as Bt,A as zt,B as At,C as Et,F as Rt,v as Y,g as Zt}from"./codemirror-Bp6CUUFk.js";function Ft(l){if(!l)return null;const n=l.toLowerCase(),o=n.split("/").pop()||n;if(o==="dockerfile")return null;const a=(o.match(/\.[a-z0-9]+$/)||[""])[0];switch(a){case".js":case".jsx":case".mjs":case".cjs":return Y({jsx:a===".jsx"});case".ts":case".tsx":return Y({jsx:a===".tsx",typescript:!0});case".html":case".htm":case".svg":case".xml":case".mdx":return Rt();case".css":case".scss":case".sass":case".less":return Et();case".json":return At();case".md":case".markdown":return zt();case".py":return Bt();default:return null}}async function Ot(l,n){const o=new URLSearchParams;l&&o.set("projectDir",l),n&&o.set("dir",n);const a=await L("/api/files?"+o.toString());return a.status!==200?{error:a.body&&a.body.error||"HTTP "+a.status,code:a.body&&a.body.code}:{body:a.body}}async function Ut(l,n){const o=new URLSearchParams;l&&o.set("projectDir",l),o.set("path",n);const a=await L("/api/file?"+o.toString());return a.status!==200?{error:a.body&&a.body.error||"HTTP "+a.status,code:a.body&&a.body.code}:{body:a.body}}async function Vt(l,n,o){const a=await L("/api/file",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:l,path:n,content:o})});return a.status!==200?{error:a.body&&a.body.error||"HTTP "+a.status,code:a.body&&a.body.code}:{body:a.body}}async function It(l,n){const o=new URLSearchParams;l&&o.set("projectDir",l),o.set("path",n);const a=await L("/api/file-media?"+o.toString());return a.status!==200?{error:a.body&&a.body.error||"HTTP "+a.status,code:a.body&&a.body.code}:{body:a.body}}function qt(l){const n=l.projectDir||"",o=l.onClose||(()=>{}),a=S(n),[H,O]=d(n||""),[v,tt]=d(""),[U,V]=d([]),[et,T]=d(""),[rt,j]=d(!1),[c,I]=d(null),[u,x]=d(null),[Kt,K]=d(!1),[at,g]=d(""),[m,w]=d(!1),[k,G]=d(!1),[B,h]=d(""),[st,z]=d(!1),[nt,it]=d(null),A=S(null),i=S(null),[P,W]=d(!1),E=S(null),b=y(async t=>{const r=typeof t=="string"&&t?t:a.current||n;j(!0),T("loading…");const s=await Ot(n,r);if(s.error){T(s.error),V([]),j(!1);return}a.current=s.body.dir,O(s.body.dir),tt(s.body.browseTop||""),V(Array.isArray(s.body.entries)?s.body.entries:[]),T((s.body.entries?s.body.entries.length:0)+" items"),j(!1)},[n]);D(()=>{b(n)},[b,n]);const _=y(()=>m?window.confirm("Discard unsaved changes?"):!0,[m]),R=y(async t=>{if(!_())return;x(null),g(""),h("loading…");const r=await Ut(n,t);if(r.error){h(r.error);return}const s={relPath:r.body.relPath,absPath:r.body.path,content:r.body.content,size:r.body.size,ext:r.body.ext};I(s),w(!1),h(s.size+" bytes")},[n,_]),q=y(async(t,r)=>{if(r&&r.forceText)return R(t);K(!0),g("loading…");const s=await It(n,t);if(K(!1),s.error){g(s.error),x(null);return}I(null),w(!1),h(""),x({relPath:s.body.relPath,absPath:s.body.path,dataUrl:s.body.dataUrl,mime:s.body.mime,size:s.body.size,ext:s.body.ext}),g(s.body.size+" bytes · "+s.body.mime)},[n,R]);bt(()=>{c&&ot(c)},[c]);function ot(t){if(!A.current)return;i.current&&(i.current.destroy(),i.current=null);const r=Ft(t.relPath),s=[mt(),_t(),vt(),gt(),wt(),Ct(),xt(),kt(),Pt(),St(Zt),Dt.of([{key:"Mod-s",preventDefault:!0,run:()=>(E.current&&E.current(),!0)},Mt,...Lt,...Ht,...Tt]),F.lineWrapping,yt,F.updateListener.of(p=>{p.docChanged&&(m||w(!0),B&&B.indexOf("saved")!==0&&h("edited"))})];r&&s.push(r);const f=jt.create({doc:t.content,extensions:s});i.current=new F({state:f,parent:A.current}),requestAnimationFrame(()=>{i.current&&i.current.requestMeasure()})}D(()=>()=>{i.current&&(i.current.destroy(),i.current=null)},[]),D(()=>{u&&i.current&&(i.current.destroy(),i.current=null)},[u]);const Z=y(async()=>{if(!c||!i.current)return;G(!0),h("saving…");const t=i.current.state.doc.toString(),r=await Vt(n,c.relPath,t);if(G(!1),r.error){h("save failed: "+r.error);return}w(!1),h("saved · "+r.body.size+" bytes")},[c,n]);D(()=>{E.current=Z},[Z]);const lt=y(()=>{!c||!i.current||_()&&(i.current.dispatch({changes:{from:0,to:i.current.state.doc.length,insert:c.content}}),w(!1),h("reverted"))},[c,_]),J=y(()=>{_()&&o()},[_,o]);function $(){const t=a.current||"";if(!t)return;const r=v||"";if(r&&t===r)return;const s=t.replace(/[\\/]+$/,""),f=Math.max(s.lastIndexOf("\\"),s.lastIndexOf("/"));if(f<=0){b(r);return}const p=s.slice(0,f);if(r&&p===r){b(r);return}b(p)}function ct(t){if(t.key==="Enter"){t.preventDefault();const r=(H||"").trim();b(r||v||n)}}function dt(){const t=(H||"").trim();b(t||v||n)}function N(t){if(t.type==="dir"){b(t.path);return}if(t.image){q(t.relPath);return}t.binary||R(t.relPath)}function ut(){if(!c||!i.current)return;const t=i.current.state.selection.main;if(t.empty){h("Select code before using Draft Craft."),i.current.focus();return}const r=i.current.state.sliceDoc(t.from,t.to),s=i.current.state.doc.lineAt(t.from).number,f=i.current.state.doc.lineAt(t.to).number;it({projectDir:n,text:c.relPath+":"+s+(f!==s?"-"+f:"")+`
2
2
  `+r}),z(!0)}function ft(){const t=a.current||"";if(!t)return null;const r=v||"";if(r&&t===r)return null;const s=t.replace(/[\\/]+$/,""),f=Math.max(s.lastIndexOf("\\"),s.lastIndexOf("/"));return f>0?s.slice(0,f):r||null}function ht(){const t=v||n||"",r=a.current||t;if(!t||r===t)return e(M,null,e("span",{class:"fe__crumb fe__crumb--root"},t||"project"));const s=r.startsWith(t)?r.slice(t.length).replace(/^[\\/]+/,""):r,f=s?s.split(/[\\/]+/):[],p=[];p.push(e("button",{key:"root",type:"button",class:"fe__crumb fe__crumb--root",onClick:()=>b(t)},t.split(/[\\/]+/).pop()||t));let C=t;return f.forEach((Q,X)=>{C=C+(C.endsWith("\\")||C.endsWith("/")?"":"/")+Q,p.push(e("span",{key:"sep-"+X,class:"fe__crumb-sep","aria-hidden":"true"},"/")),p.push(e("button",{key:"seg-"+X,type:"button",class:"fe__crumb",onClick:()=>b(C)},Q))}),e(M,null,p)}return e("div",{class:"fe__overlay",role:"dialog","aria-modal":"true","aria-label":"File editor",onClick:t=>{}},e("div",{class:"fe__sheet"+(P?" fe__sheet--full":"")},e("div",{class:"fe__head"},P?e("div",{class:"fe__path-row"},e("button",{class:"icon-btn fe__iconbtn is-active",type:"button",onClick:()=>W(!1),"aria-label":"Show file list","aria-pressed":"true",title:"Show file list"},e("svg",{viewBox:"0 0 24 24",width:18,height:18,"aria-hidden":"true"},e("path",{d:"M4 4h7v16H4zM13 4h7v16h-7z",fill:"currentColor"}))),e("button",{class:"icon-btn icon-btn--close fe__iconbtn",type:"button",onClick:J,"aria-label":"Close",title:"Close"},e("svg",{viewBox:"0 0 24 24",width:16,height:16,"aria-hidden":"true"},e("path",{d:"M18.3 5.71 12 12l6.3 6.29-1.41 1.42L10.59 13.4 4.3 19.71 2.88 18.3 9.17 12 2.88 5.71 4.3 4.3l6.29 6.29 6.3-6.29 1.41 1.41Z",fill:"currentColor"})))):e("div",{class:"fe__path-row"},e("button",{class:"icon-btn fe__iconbtn",type:"button",onClick:$,"aria-label":"Up one folder",title:"Up"},e("svg",{viewBox:"0 0 24 24",width:16,height:16,"aria-hidden":"true"},e("path",{d:"M12 4 4 12l8 8 1.4-1.4L8.8 14H20v-2H8.8l4.6-4.6L12 4Z",fill:"currentColor",transform:"rotate(-90 12 12)"}))),e("div",{class:"fe__path-input-wrap"},e("input",{class:"input fe__path-input",type:"text",value:H,onInput:t=>O(t.currentTarget.value),onKeydown:ct,placeholder:"Folder path (absolute, or under this project)","aria-label":"Current folder",spellcheck:"false",autocomplete:"off"})),e("button",{class:"icon-btn fe__iconbtn",type:"button",onClick:dt,"aria-label":"Go to folder",title:"Go"},"Go"),e("button",{class:"icon-btn fe__iconbtn",type:"button",onClick:()=>b(a.current),"aria-label":"Refresh",title:"Refresh"},e("svg",{viewBox:"0 0 24 24",width:16,height:16,"aria-hidden":"true"},e("path",{d:"M12 4V1L7 6l5 5V7c3.31 0 6 2.69 6 6 0 1-.25 1.97-.7 2.8l1.46 1.46A7.93 7.93 0 0 0 20 13c0-4.42-3.58-8-8-8Zm-5.3 7.7A7.93 7.93 0 0 0 4 13c0 4.42 3.58 8 8 8v3l5-5-5-5v3c-3.31 0-6-2.69-6-6 0-1 .25-1.97.7-2.8L5.24 10.24Z",fill:"currentColor"}))),e("button",{class:"icon-btn fe__iconbtn",type:"button",onClick:()=>W(!0),"aria-label":"Hide file list","aria-pressed":"false",title:"Hide file list"},e("svg",{viewBox:"0 0 24 24",width:18,height:18,"aria-hidden":"true"},e("path",{d:"M3 5h18v14H3z",fill:"currentColor"}))),e("button",{class:"icon-btn icon-btn--close fe__iconbtn",type:"button",onClick:J,"aria-label":"Close",title:"Close"},e("svg",{viewBox:"0 0 24 24",width:16,height:16,"aria-hidden":"true"},e("path",{d:"M18.3 5.71 12 12l6.3 6.29-1.41 1.42L10.59 13.4 4.3 19.71 2.88 18.3 9.17 12 2.88 5.71 4.3 4.3l6.29 6.29 6.3-6.29 1.41 1.41Z",fill:"currentColor"})))),!P&&e("div",{class:"fe__crumbs","aria-label":"Breadcrumb"},ht()),!P&&e("div",{class:"fe__list-status"},e("span",{class:"status"},et||" "),ft()?e("button",{class:"btn btn--ghost fe__list-up",type:"button",onClick:$},"↑ Up"):null)),e("div",{class:"fe__body"},e("div",{class:"fe__list-wrap"},e("ul",{class:"fe__list","aria-label":"Files and folders"},U.length===0?e("li",{class:"fe__empty"},rt?"loading…":"no files here"):U.map(t=>e("li",{key:t.path,class:"fe__row"+(t.binary?" fe__row--binary":"")+(t.image?" fe__row--image":"")+(c&&c.relPath===t.relPath||u&&u.relPath===t.relPath?" is-open":""),role:"button",tabindex:t.binary?-1:0,"aria-disabled":t.binary?"true":"false",title:t.binary&&!t.image?"binary file — cannot be opened here":t.path,onClick:()=>N(t),onKeydown:r=>{t.binary&&!t.image||(r.key==="Enter"||r.key===" ")&&(r.preventDefault(),N(t))}},e("span",{class:"fe__row-icon","aria-hidden":"true"},t.type==="dir"?e("svg",{viewBox:"0 0 24 24",width:16,height:16},e("path",{d:"M3 6a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6Z",fill:"currentColor"})):t.image?e("svg",{viewBox:"0 0 24 24",width:16,height:16},e("path",{d:"M21 5H3a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h18a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2Zm-9 11-3-4-2.5 3L4 13.5V7h16v9l-4-3-4 3Zm-4-7a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Z",fill:"currentColor"})):e("svg",{viewBox:"0 0 24 24",width:16,height:16},e("path",{d:"M6 2h8l4 4v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2Zm7 1.5V7h3.5L13 3.5Z",fill:"currentColor"}))),e("span",{class:"fe__row-name"},t.name),t.type==="dir"?e("span",{class:"fe__row-meta"},t.hasChildren?"…":"·"):e("span",{class:"fe__row-meta"},t.image?"image":t.binary?"binary":t.size<1024?t.size+" B":Math.round(t.size/1024)+" KB"))))),e("div",{class:"fe__editor-wrap"},u?e(M,null,e("div",{class:"fe__editor-head"},e("div",{class:"fe__editor-path",title:u.absPath},u.relPath),e("div",{class:"fe__editor-actions"},u.ext===".svg"||u.mime==="image/svg+xml"?e("button",{class:"btn",type:"button",onClick:()=>q(u.relPath,{forceText:!0}),title:"Open this file in the code editor"},"Edit"):null,e("button",{class:"btn",type:"button",onClick:()=>{x(null),g("")},title:"Close preview"},"Close"))),e("div",{class:"fe__media-host"},e("img",{class:"fe__media-img",src:u.dataUrl,alt:u.relPath,draggable:"false"})),e("div",{class:"fe__editor-status"},e("span",{class:"status"},at||" "))):c?e(M,null,e("div",{class:"fe__editor-head"},e("div",{class:"fe__editor-path",title:c.absPath},c.relPath+(m?" •":"")),e("div",{class:"fe__editor-actions"},e("button",{class:"btn fe__draft-craft",type:"button",onClick:ut,disabled:k,title:"Add the selected code to any chat draft"},e("svg",{viewBox:"0 0 24 24",width:18,height:18,"aria-hidden":"true"},e("path",{d:"M4 4h16v13a3 3 0 0 1-3 3H7a3 3 0 0 1-3-3V4Zm2 2v9h4a2 2 0 0 0 4 0h4V6H6Z",fill:"currentColor"})),e("span",null,"Draft Craft")),e("button",{class:"btn",type:"button",onClick:lt,disabled:!m||k,title:"Revert to the last saved version"},"Revert"),e("button",{class:"btn btn--primary",type:"button",onClick:Z,disabled:!m||k,title:"Save (Ctrl/Cmd+S is wired to the editor save keymap via the browser default)","aria-label":"Save file"},k?"Saving…":"Save"))),e("div",{ref:A,class:"fe__editor-host"}),e("div",{class:"fe__editor-status"},e("span",{class:"status"},B||" "))):e("div",{class:"fe__editor-empty"},e("p",null,"Pick a file from the list to start editing, or tap an image to preview it."),e("p",{class:"fe__editor-hint"},"Tip: type a path above or use the breadcrumb to jump to a folder.")))),e(pt,{open:st,payload:nt,placement:"top",onClose:()=>z(!1),onAdded:t=>{z(!1),h("Selected code added with Draft Craft."),l.onDraftCraftAdded&&l.onDraftCraftAdded(t)}})))}export{qt as FileEditorView};
@@ -1,2 +1,2 @@
1
- import{d as m,a3 as H,h as gt,u as K,k as t,S as z,f as O,A as ht,c as pt}from"./index-BGvI4n0T.js";async function Q(s,a,n,o){const c=await O("/api/git",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:s,action:a,args:n||"",message:o||""})});return c.status!==200?{ok:!1,stderr:c.body&&c.body.error||"HTTP "+c.status}:c.body||{ok:!1,stderr:"no response"}}async function X(s,a,n){const o=await O("/api/git",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:s,action:a,files:n})});return o.status!==200?{ok:!1,stderr:o.body&&o.body.error||"HTTP "+o.status}:o.body||{ok:!1,stderr:"no response"}}function Y(s){return String(s||"").split(" -> ")[0]}function _t({diff:s}){if(!s)return null;const a=s.split(`
1
+ import{d as m,a3 as H,h as gt,u as K,k as t,S as z,f as O,A as ht,c as pt}from"./index-BDkCsON6.js";async function Q(s,a,n,o){const c=await O("/api/git",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:s,action:a,args:n||"",message:o||""})});return c.status!==200?{ok:!1,stderr:c.body&&c.body.error||"HTTP "+c.status}:c.body||{ok:!1,stderr:"no response"}}async function X(s,a,n){const o=await O("/api/git",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:s,action:a,files:n})});return o.status!==200?{ok:!1,stderr:o.body&&o.body.error||"HTTP "+o.status}:o.body||{ok:!1,stderr:"no response"}}function Y(s){return String(s||"").split(" -> ")[0]}function _t({diff:s}){if(!s)return null;const a=s.split(`
2
2
  `);return t("div",{class:"gm__diff"},t("pre",{class:"gm__diff-pre","aria-label":"Diff"},a.map((n,o)=>{let c="";return n.startsWith("@@")?c=" gm__diff-hunk":n.startsWith("+")&&!n.startsWith("+++")?c=" gm__diff-add":n.startsWith("-")&&!n.startsWith("---")?c=" gm__diff-del":n.startsWith("diff --git")&&(c=" gm__diff-file"),t("span",{key:o,class:"gm__diff-line"+c},n||" ")})))}function et({file:s,defaultOpen:a,action:n,onAction:o,busy:c}){const[h,r]=m(!!a),p=!!(s.diff&&s.diff.trim()),f=n==="unstage"?"Unstage":"Stage";return t("div",{class:"gm__file"},t("div",{class:"gm__file-head"},t("button",{class:"gm__file-toggle",type:"button",onClick:()=>r(!h),"aria-expanded":String(h),"aria-label":(p?"Toggle diff for ":"")+s.path},t("span",{class:"gm__file-status gm__file-status--"+s.status},s.statusText||s.status),t("span",{class:"gm__file-path",title:s.path},s.path),p?t("span",{class:"gm__file-caret","aria-hidden":"true"},h?"▾":"▸"):null),o?t("button",{class:"gm__file-action"+(n==="unstage"?" gm__file-action--unstage":""),type:"button",disabled:c,onClick:()=>o(s),"aria-label":f+" "+s.path,title:f+" "+s.path},f):null),h&&p?t(_t,{diff:s.diff}):null)}function ft({projectDir:s,commit:a,busy:n,onAction:o}){const[c,h]=m(!1),[r,p]=m(null),[f,l]=m(""),[g,w]=m(!1),[d,T]=m(""),y=H(async()=>{if(!(g||d===a.hash)){w(!0),l("");try{const _=new URLSearchParams;_.set("projectDir",s),_.set("hash",a.hash);const b=await O("/api/git/commit-files?"+_.toString());b.status===200&&b.body&&b.body.ok?(p(b.body.files||[]),T(a.hash)):l(b.body&&b.body.error||"HTTP "+b.status)}catch(_){l(String(_))}w(!1)}},[s,a.hash,g,d]);function C(){const _=!c;h(_),_&&d!==a.hash&&y()}return t("div",{class:"gm__commit"},t("div",{class:"gm__commit-row"},t("button",{class:"gm__commit-head"+(c?" is-open":""),type:"button",onClick:C,"aria-expanded":String(c),"aria-label":"Toggle commit "+a.short},t("span",{class:"gm__commit-caret","aria-hidden":"true"},c?"▾":"▸"),t("span",{class:"gm__commit-hash"},a.short),t("span",{class:"gm__commit-subject",title:a.subject},a.subject),t("span",{class:"gm__commit-meta"},a.author?t("span",{class:"gm__commit-author"},a.author):null,a.date?t("span",{class:"gm__commit-date"},yt(a.date)):null)),t(bt,{commit:a,busy:n,onAction:o})),c&&t("div",{class:"gm__commit-body"},g?t("div",{class:"gm__empty"},"Loading files…"):f?t("div",{class:"gm__error"},t("p",null,f),t("button",{class:"btn",type:"button",onClick:y},"Retry")):r===null?t("div",{class:"gm__empty"},"Loading files…"):r.length===0?t("div",{class:"gm__empty"},"No file changes in this commit"):r.map((_,b)=>t(et,{key:_.path+"-"+b,file:_}))))}async function $(s){try{return await navigator.clipboard.writeText(s||""),!0}catch{try{const n=document.createElement("textarea");n.value=s||"",n.style.position="fixed",n.style.opacity="0",document.body.appendChild(n),n.select();const o=document.execCommand("copy");return document.body.removeChild(n),o}catch{return!1}}}function bt({commit:s,busy:a,onAction:n}){const[o,c]=m(!1),h=ht(null);return pt(h,()=>c(!1),o),t("div",{ref:h,class:"gm__commit-menu"},t("button",{class:"gm__commit-menu-btn",type:"button","aria-haspopup":"true","aria-expanded":String(o),"aria-label":"Commit options for "+s.short,title:"Commit options",disabled:!!a,onClick:r=>{r.stopPropagation(),c(!o)}},"⋯"),t("div",{class:"gm__commit-menu-pop",hidden:!o,role:"menu",onClick:r=>r.stopPropagation()},t("button",{type:"button",onClick:()=>{c(!1),n(s,"copy-hash")}},"Copy hash"),t("button",{type:"button",onClick:()=>{c(!1),n(s,"copy-message")}},"Copy message"),t("div",{class:"gm__commit-menu-sep",role:"separator"}),t("button",{type:"button",disabled:!!a,onClick:()=>{c(!1),n(s,"checkout")}},"Checkout"),t("button",{type:"button",disabled:!!a,onClick:()=>{c(!1),n(s,"cherry-pick")}},"Cherry-pick"),t("button",{type:"button",disabled:!!a,onClick:()=>{c(!1),n(s,"revert")}},"Revert")))}function yt(s){if(!s)return"";const a=new Date(s);if(isNaN(a.getTime()))return s;const n={day:"numeric",month:"short",year:"numeric",hour:"2-digit",minute:"2-digit"};try{return a.toLocaleString(void 0,n)}catch{return s}}function Ct(s){const a=/stash@\{(\d+)\}/.exec(s||"");return a?a[1]:s}function St(s){const{projectDir:a,onClose:n}=s,[o,c]=m(null),[h,r]=m(""),[p,f]=m(!0),[l,g]=m(""),[w,d]=m(""),[T,y]=m(0),[C,_]=m([]),[b,G]=m(0),[M,W]=m(!1),[j,st]=m(!1),[A,at]=m(!1),[nt,Z]=m(!1),[E,V]=m(""),[P,L]=m(null),v=H(async()=>{if(!a){f(!1),r("No project selected");return}if(!nt){Z(!0),f(!0),r(""),d(""),_([]),y(0),G(0);try{const e=new URLSearchParams;e.set("projectDir",a);const i=await O("/api/git/info?"+e.toString());i.status!==200?r(i.body&&i.body.error||"HTTP "+i.status):i.body&&i.body.ok===!1?r(i.body&&i.body.error||"Not a git repository"):(c(i.body),_(i.body.commits||[]),y(i.body.commits&&i.body.commits.length||0))}catch(e){r(String(e))}f(!1),Z(!1)}},[a]);gt(()=>{v()},[v]);const F=H(()=>{L(e=>e?null:(n&&n(),e))},[n]),ot=K({onClose:F}),it=K({onClose:F,active:!!P});async function k(e,i,u){if(l)return;g(e),d("");const q=await Q(a,e,i,u);q.ok?(d("git "+e+" ok"),await v()):d((q.stderr||"git "+e+" failed").trim()||"git "+e+" failed"),g("")}async function U(e,i){if(l)return;g(e),d("");const u=await X(a,e,[Y(i.path)]);u.ok?(d(""),await v()):d((u.stderr||"git "+e+" failed").trim()||"git "+e+" failed"),g("")}async function ct(){if(l)return;g("add"),d("");const e=R.map(u=>Y(u.path));if(!e.length){g("");return}const i=await X(a,"add",e);i.ok?(d(""),await v()):d((i.stderr||"git add failed").trim()||"git add failed"),g("")}async function J(){if(l)return;const e=E.trim();if(!e){d("Enter a commit message");return}g("commit"),d("");const i=await Q(a,"commit","",e);i.ok?(V(""),d("Committed…"),await v()):d((i.stderr||"git commit failed").trim()||"git commit failed"),g("")}function lt(e){l||e===(o&&o.branch)||k("checkout",e)}async function rt(e,i){if(!l){if(i==="copy-hash"){const u=await $(e.hash);d(u?"Copied hash "+e.short:"Copy failed");return}if(i==="copy-message"){const u=await $(e.subject);d(u?"Copied message":"Copy failed");return}if(i==="checkout"){L({commit:e,action:"checkout"});return}if(i==="cherry-pick"){L({commit:e,action:"cherry-pick"});return}if(i==="revert"){L({commit:e,action:"revert"});return}}}function dt(){const e=P;L(null),e&&(e.action==="checkout"?k("checkout",e.commit.hash):e.action==="cherry-pick"?k("cherry-pick",e.commit.hash):e.action==="revert"&&k("revert",e.commit.hash))}async function mt(){if(!M){W(!0);try{const e=new URLSearchParams;e.set("projectDir",a),e.set("offset",String(T)),e.set("count","20");const i=await O("/api/git/commits?"+e.toString());i.status===200&&i.body&&i.body.ok&&(_(u=>u.concat(i.body.commits||[])),G(i.body.total||0),y(u=>u+(i.body.commits?i.body.commits.length:0)))}catch{}W(!1)}}const D=o&&o.staged||[],R=o&&o.unstaged||[],N=o&&o.stashes||[],B=o&&o.branch||"",I=o&&o.branches||[],S=o&&o.ahead||0,x=o&&o.behind||0,ut=b>0?C.length<b:C.length>=20;return t("div",{class:"gm__overlay",role:"dialog","aria-modal":"true","aria-label":"Git"},t("div",{class:"gm__sheet",ref:ot},t("div",{class:"gm__head"},t("label",{class:"gm__branch-wrap"},t("span",{class:"gm__branch-label"},"Branch"),t("select",{class:"gm__branch-select",value:B,disabled:l==="checkout",onChange:e=>lt(e.currentTarget.value),"aria-label":"Branch"},I.length===0?t("option",{value:B},B||"(none)"):I.map(e=>t("option",{key:e,value:e},e)))),t("button",{class:"icon-btn gm__iconbtn"+(x>0?" gm__iconbtn--has-count":""),type:"button",onClick:()=>k("pull"),disabled:!!l,"aria-label":"Pull from remote"+(x>0?" ("+x+" behind)":""),title:"Pull"+(x>0?" ("+x+" behind)":"")},x>0?t("span",{class:"gm__iconbtn-badge"},x):null,t("svg",{viewBox:"0 0 24 24",width:18,height:18,"aria-hidden":"true"},t("path",{d:"M11 3v9.6L8.4 10 7 11.4l5 5 5-5L15.6 10 13 12.6V3h-2Zm-7 15h16v2H4v-2Z",fill:"currentColor"}))),t("button",{class:"icon-btn gm__iconbtn"+(S>0?" gm__iconbtn--has-count":""),type:"button",onClick:()=>k("push"),disabled:!!l,"aria-label":"Push to remote"+(S>0?" ("+S+" ahead)":""),title:"Push"+(S>0?" ("+S+" ahead)":"")},S>0?t("span",{class:"gm__iconbtn-badge"},S):null,t("svg",{viewBox:"0 0 24 24",width:18,height:18,"aria-hidden":"true"},t("path",{d:"M12 3a1 1 0 0 1 .7.3l5 5-1.4 1.4L13 7.4V20h-2V7.4L7.7 9.7 6.3 8.3l5-5A1 1 0 0 1 12 3Z",fill:"currentColor"}))),t("button",{class:"icon-btn gm__iconbtn",type:"button",onClick:v,disabled:p||!!l,"aria-label":"Refresh git status",title:"Refresh"},t("svg",{viewBox:"0 0 24 24",width:16,height:16,"aria-hidden":"true"},t("path",{d:"M12 4V1L7 6l5 5V7c3.31 0 6 2.69 6 6 0 1-.25 1.97-.7 2.8l1.46 1.46A7.93 7.93 0 0 0 20 13c0-4.42-3.58-8-8-8Zm-5.3 7.7A7.93 7.93 0 0 0 4 13c0 4.42 3.58 8 8 8v3l5-5-5-5v3c-3.31 0-6-2.69-6-6 0-1 .25-1.97.7-2.8L5.24 10.24Z",fill:"currentColor"}))),t("button",{class:"icon-btn icon-btn--close gm__iconbtn",type:"button",onClick:n,"aria-label":"Close",title:"Close"},t("svg",{viewBox:"0 0 24 24",width:16,height:16,"aria-hidden":"true"},t("path",{d:"M18.3 5.71 12 12l6.3 6.29-1.41 1.42L10.59 13.4 4.3 19.71 2.88 18.3 9.17 12 2.88 5.71 4.3 4.3l6.29 6.29 6.3-6.29 1.41 1.41Z",fill:"currentColor"})))),w?t("div",{class:"gm__notice"},w):null,t("div",{class:"gm__body"},p?t("div",{class:"gm__empty"},"Loading git status…"):h?t("div",{class:"gm__error"},t("p",null,h),t("button",{class:"btn",type:"button",onClick:v},"Retry")):t(z,null,t("div",{class:"gm__section"},t("button",{class:"gm__section-head",type:"button",onClick:()=>at(!A),"aria-expanded":String(A),"aria-controls":"gm-section-stash"},t("span",{class:"gm__section-caret","aria-hidden":"true"},A?"▾":"▸"),t("span",{class:"gm__section-title"},"Stash"),t("span",{class:"gm__section-count"},N.length||"")),A&&t("div",{id:"gm-section-stash",class:"gm__section-body"},t("div",{class:"gm__stash-toolbar"},t("button",{class:"gm__stash-btn gm__stash-btn--stashup",type:"button",disabled:!!l,onClick:()=>k("stash"),"aria-label":"Stash working changes",title:"Stash up"},t("svg",{viewBox:"0 0 24 24",width:14,height:14,"aria-hidden":"true"},t("path",{d:"M12 4v9.6L9.4 11 8 12.4l5 5 5-5-1.4-1.4L14 13.6V4h-2ZM5 20h14v2H5v-2Z",fill:"currentColor"}))," Stash up")),N.length===0?t("div",{class:"gm__empty"},"No stashed changes"):N.map((e,i)=>t(vt,{key:i,stash:e,busy:l,onApply:u=>k("stash-apply",u),onPop:u=>k("stash-pop",u),onDrop:u=>k("stash-drop",u)})))),t(tt,{id:"staged",title:"Staged changes",files:D,defaultOpen:D.length>0,emptyText:"Nothing staged",action:"unstage",onAction:e=>U("unstage",e),busy:!!l,header:t("div",{class:"gm__commit-bar"},t("input",{class:"input gm__commit-input",type:"text",value:E,onInput:e=>V(e.currentTarget.value),placeholder:"Commit message","aria-label":"Commit message",disabled:!!l,onKeyDown:e=>{e.key==="Enter"&&(e.preventDefault(),J())}}),t("button",{class:"gm__commit-btn",type:"button",disabled:!!l||D.length===0,onClick:J,"aria-label":"Commit staged changes",title:"Commit staged changes"},l==="commit"?"Committing…":"Commit"))}),t(tt,{id:"unstaged",title:"Unstaged changes",files:R,defaultOpen:R.length>0,emptyText:"Working tree clean",action:"add",onAction:e=>U("add",e),busy:!!l}),D.length>0&&R.length>0?t("button",{class:"gm__stage-all",type:"button",disabled:!!l,onClick:ct,"aria-label":"Stage all unstaged changes",title:"Stage all unstaged changes"},"Stage all ("+R.length+")"):null,t("div",{class:"gm__section"},t("button",{class:"gm__section-head",type:"button",onClick:()=>st(!j),"aria-expanded":String(j),"aria-controls":"gm-section-commits"},t("span",{class:"gm__section-caret","aria-hidden":"true"},j?"▾":"▸"),t("span",{class:"gm__section-title"},"Recent commits"),t("span",{class:"gm__section-count"},b||C.length||"")),j&&t("div",{id:"gm-section-commits",class:"gm__section-body"},C.length===0?t("div",{class:"gm__empty"},"No commits yet"):t(z,null,C.map((e,i)=>t(ft,{key:e.hash||i,projectDir:a,commit:e,busy:!!l,onAction:rt})),ut?t("button",{class:"gm__load-more",type:"button",disabled:M,onClick:mt},M?"Loading…":"Load more"):null)))))),P?t(kt,{commit:P.commit,action:P.action,busy:!!l,sheetRef:it,onCancel:()=>L(null),onConfirm:dt}):null)}function kt({commit:s,action:a,busy:n,onCancel:o,onConfirm:c,sheetRef:h}){let r="Confirm git action",p="";a==="checkout"?(r="Checkout commit?",p="Check out "+s.short+" as a detached HEAD. Any current changes must be committed or stashed first."):a==="cherry-pick"?(r="Cherry-pick commit?",p="Apply "+s.short+(' "'+s.subject+'"')+" onto the current branch as a new commit."):a==="revert"&&(r="Revert commit?",p="Create a new commit that undoes "+s.short+(' "'+s.subject+'"')+".");const f=a==="checkout"?"Checkout":a==="cherry-pick"?"Cherry-pick":"Revert";return t("div",{class:"gm__overlay gm__confirm",role:"presentation",onClick:n?void 0:o},t("div",{class:"gm__sheet gm__confirm-sheet",role:"alertdialog","aria-modal":"true","aria-label":r,ref:h,onClick:l=>l.stopPropagation()},t("div",{class:"gm__confirm-body"},t("strong",{class:"gm__confirm-title"},r),t("p",{class:"gm__confirm-msg"},p),t("div",{class:"gm__confirm-actions"},t("button",{class:"btn gm__confirm-cancel",type:"button",disabled:n,onClick:o},"Cancel"),t("button",{class:"btn gm__confirm-go",type:"button","data-danger":"1",disabled:n,onClick:c},n?"Working…":f)))))}function tt({id:s,title:a,files:n,defaultOpen:o,emptyText:c,renderFile:h,action:r,onAction:p,busy:f,header:l}){const[g,w]=m(o),d=n?n.length:0,T=h||((y,C)=>t(et,{key:y.path+"-"+C,file:y,action:r,onAction:p,busy:f}));return t("div",{class:"gm__section"},t("button",{class:"gm__section-head"+(g?" is-open":""),type:"button",onClick:()=>w(!g),"aria-expanded":String(g),"aria-controls":"gm-section-"+s},t("span",{class:"gm__section-caret","aria-hidden":"true"},g?"▾":"▸"),t("span",{class:"gm__section-title"},a),t("span",{class:"gm__section-count"},d||"")),g&&t("div",{id:"gm-section-"+s,class:"gm__section-body"},l||null,d===0?t("div",{class:"gm__empty"},c||"Nothing here"):n.map((y,C)=>T(y,C))))}function vt({stash:s,busy:a,onApply:n,onPop:o,onDrop:c}){return t("div",{class:"gm__stash-row"},t("span",{class:"gm__stash-index"},Ct(s.index)),t("span",{class:"gm__stash-main"},t("span",{class:"gm__stash-subject",title:s.subject},s.subject),s.date?t("span",{class:"gm__stash-date"},s.date):null),t("div",{class:"gm__stash-actions"},t("button",{class:"gm__stash-btn",type:"button",disabled:!!a,onClick:()=>n(s.index),title:"Apply stash without removing it"},"Apply"),t("button",{class:"gm__stash-btn",type:"button",disabled:!!a,onClick:()=>o(s.index),title:"Apply stash and remove it"},"Pop"),t("button",{class:"gm__stash-btn gm__stash-btn--danger",type:"button",disabled:!!a,onClick:()=>c(s.index),title:"Delete stash"},"Drop")))}export{St as GitModal};
@@ -1,4 +1,4 @@
1
- import{A,h as ne,k as o,d as T,u as yo,$ as bn,S as nt,_ as vo,T as Er,D as wo,a as _o,f as $e,b as ko,c as yn}from"./index-BGvI4n0T.js";import{c as Mr}from"./virtual-list-6H9b4K51.js";import{E as So,a as xo,o as Co,b as en,l as Po,h as Ro,c as To,d as No,i as Eo,e as Mo,f as Ao,s as Io,g as Lo,k as Fo,j as Mn,m as zo,n as Oo,p as Do,q as Bo,r as jo,t as Ho,u as Vo,v as Uo,w as Wo}from"./codemirror-Bp6CUUFk.js";function vn(e){if(!e)return"";const t=new Date(e);if(isNaN(t.getTime()))return"";const n=String(t.getHours()).padStart(2,"0"),r=String(t.getMinutes()).padStart(2,"0"),i=String(t.getSeconds()).padStart(2,"0");return n+":"+r+":"+i}function wn(e){return e==="pending"?"···":e==="failed"?"FAIL":String(e)}function qo(e){if(e==="pending")return"pending";if(e==="failed")return"failed";const t=Number(e);return!isNaN(t)&&t>=400?"error":!isNaN(t)&&t>=300?"redirect":!isNaN(t)&&t>=200?"ok":"other"}function _t(e){return typeof e!="number"||isNaN(e)||e<0?"":e<1024?e+" B":e<1024*1024?(e/1024).toFixed(e<10240?1:0)+" KB":(e/(1024*1024)).toFixed(2)+" MB"}function _n(e){return typeof e!="number"||isNaN(e)||e<0?"":e<1e3?e+" ms":(e/1e3).toFixed(2)+" s"}function Zo(e,t){if(!t)return;const n=document.createElement("span");if(n.className="inspector__arg inspector__arg--"+(t.type||"unknown"),t.type==="object"&&t.preview&&Array.isArray(t.preview.properties)){const r=t.preview.properties,i=r.slice(0,5).map(l=>l.name+": "+(l.value!==void 0?l.value:l.type||"")).join(", ");n.textContent=(t.className==="Array"?"[":"{")+i+(r.length>5?", …":"")+(t.className==="Array"?"]":"}"),n.title=t.description||""}else t.type==="string"?n.textContent=String(t.value!==void 0?t.value:t.description||""):typeof t.value<"u"?n.textContent=String(t.value):typeof t.description<"u"?n.textContent=t.description:t.type==="function"?n.textContent="ƒ "+(t.description||""):n.textContent=t.type||"";e.appendChild(n)}function Ko(e){return e?typeof e.value<"u"?String(e.value):typeof e.description<"u"?e.description:e.type==="function"?"ƒ "+(e.description||""):e.type||"":""}const Go=[["window","global object","variable"],["document","the DOM document","variable"],["location","current URL","variable"],["history","session history","variable"],["navigator","browser/device info","variable"],["screen","screen metrics","variable"],["localStorage","persistent storage","variable"],["sessionStorage","session storage","variable"],["fetch","fetch network requests","function"],["alert","show an alert dialog","function"],["confirm","show a confirm dialog","function"],["prompt","show a prompt dialog","function"],["setTimeout","schedule after a delay","function"],["setInterval","schedule repeatedly","function"],["requestAnimationFrame","schedule before next paint","function"],["getComputedStyle","computed style of an element","function"],["matchMedia","media query match","function"],["getSelection","current text selection","function"],["structuredClone","deep clone a value","function"],["URL","URL constructor","class"],["URLSearchParams","query-string parsing","class"],["Date","date constructor","class"],["JSON","JSON helpers","variable"],["Math","math helpers","variable"],["Object","Object constructor","class"],["Array","Array constructor","class"],["Map","Map constructor","class"],["Set","Set constructor","class"],["Promise","Promise constructor","class"],["RegExp","regex constructor","class"],["Error","Error constructor","class"],["console","console API","variable"]].map(([e,t,n])=>({label:e,detail:t,type:n})),$o=[["$","last evaluated result","variable"],["$$","querySelectorAll shorthand","function"],["$x","XPath query shorthand","function"],["$0","currently selected element","variable"],["$1","previously selected element","variable"],["$_","most recent evaluated value","variable"],["inspect","open a value in DevTools","function"],["clear","clear the console","function"],["copy","copy a value to the clipboard","function"],["keys","object keys","function"],["values","object values","function"],["debug","set a breakpoint on a function","function"],["monitor","log calls to a function","function"]].map(([e,t,n])=>({label:e,detail:t,type:n}));[["async function","async function expression","keyword"],["arrow function","arrow function expression","keyword"],["class","class expression","keyword"],["for loop","for loop","keyword"],["function","function expression","keyword"],["if","if statement","keyword"],["try/catch","try/catch statement","keyword"],["while","while loop","keyword"]].map(([e,t,n])=>({label:e,detail:t,type:n}));const Xo=`(() => {
1
+ import{A,h as ne,k as o,d as T,u as yo,$ as bn,S as nt,_ as vo,T as Er,D as wo,a as _o,f as $e,b as ko,c as yn}from"./index-BDkCsON6.js";import{c as Mr}from"./virtual-list-6H9b4K51.js";import{E as So,a as xo,o as Co,b as en,l as Po,h as Ro,c as To,d as No,i as Eo,e as Mo,f as Ao,s as Io,g as Lo,k as Fo,j as Mn,m as zo,n as Oo,p as Do,q as Bo,r as jo,t as Ho,u as Vo,v as Uo,w as Wo}from"./codemirror-Bp6CUUFk.js";function vn(e){if(!e)return"";const t=new Date(e);if(isNaN(t.getTime()))return"";const n=String(t.getHours()).padStart(2,"0"),r=String(t.getMinutes()).padStart(2,"0"),i=String(t.getSeconds()).padStart(2,"0");return n+":"+r+":"+i}function wn(e){return e==="pending"?"···":e==="failed"?"FAIL":String(e)}function qo(e){if(e==="pending")return"pending";if(e==="failed")return"failed";const t=Number(e);return!isNaN(t)&&t>=400?"error":!isNaN(t)&&t>=300?"redirect":!isNaN(t)&&t>=200?"ok":"other"}function _t(e){return typeof e!="number"||isNaN(e)||e<0?"":e<1024?e+" B":e<1024*1024?(e/1024).toFixed(e<10240?1:0)+" KB":(e/(1024*1024)).toFixed(2)+" MB"}function _n(e){return typeof e!="number"||isNaN(e)||e<0?"":e<1e3?e+" ms":(e/1e3).toFixed(2)+" s"}function Zo(e,t){if(!t)return;const n=document.createElement("span");if(n.className="inspector__arg inspector__arg--"+(t.type||"unknown"),t.type==="object"&&t.preview&&Array.isArray(t.preview.properties)){const r=t.preview.properties,i=r.slice(0,5).map(l=>l.name+": "+(l.value!==void 0?l.value:l.type||"")).join(", ");n.textContent=(t.className==="Array"?"[":"{")+i+(r.length>5?", …":"")+(t.className==="Array"?"]":"}"),n.title=t.description||""}else t.type==="string"?n.textContent=String(t.value!==void 0?t.value:t.description||""):typeof t.value<"u"?n.textContent=String(t.value):typeof t.description<"u"?n.textContent=t.description:t.type==="function"?n.textContent="ƒ "+(t.description||""):n.textContent=t.type||"";e.appendChild(n)}function Ko(e){return e?typeof e.value<"u"?String(e.value):typeof e.description<"u"?e.description:e.type==="function"?"ƒ "+(e.description||""):e.type||"":""}const Go=[["window","global object","variable"],["document","the DOM document","variable"],["location","current URL","variable"],["history","session history","variable"],["navigator","browser/device info","variable"],["screen","screen metrics","variable"],["localStorage","persistent storage","variable"],["sessionStorage","session storage","variable"],["fetch","fetch network requests","function"],["alert","show an alert dialog","function"],["confirm","show a confirm dialog","function"],["prompt","show a prompt dialog","function"],["setTimeout","schedule after a delay","function"],["setInterval","schedule repeatedly","function"],["requestAnimationFrame","schedule before next paint","function"],["getComputedStyle","computed style of an element","function"],["matchMedia","media query match","function"],["getSelection","current text selection","function"],["structuredClone","deep clone a value","function"],["URL","URL constructor","class"],["URLSearchParams","query-string parsing","class"],["Date","date constructor","class"],["JSON","JSON helpers","variable"],["Math","math helpers","variable"],["Object","Object constructor","class"],["Array","Array constructor","class"],["Map","Map constructor","class"],["Set","Set constructor","class"],["Promise","Promise constructor","class"],["RegExp","regex constructor","class"],["Error","Error constructor","class"],["console","console API","variable"]].map(([e,t,n])=>({label:e,detail:t,type:n})),$o=[["$","last evaluated result","variable"],["$$","querySelectorAll shorthand","function"],["$x","XPath query shorthand","function"],["$0","currently selected element","variable"],["$1","previously selected element","variable"],["$_","most recent evaluated value","variable"],["inspect","open a value in DevTools","function"],["clear","clear the console","function"],["copy","copy a value to the clipboard","function"],["keys","object keys","function"],["values","object values","function"],["debug","set a breakpoint on a function","function"],["monitor","log calls to a function","function"]].map(([e,t,n])=>({label:e,detail:t,type:n}));[["async function","async function expression","keyword"],["arrow function","arrow function expression","keyword"],["class","class expression","keyword"],["for loop","for loop","keyword"],["function","function expression","keyword"],["if","if statement","keyword"],["try/catch","try/catch statement","keyword"],["while","while loop","keyword"]].map(([e,t,n])=>({label:e,detail:t,type:n}));const Xo=`(() => {
2
2
  const out = [];
3
3
  const ids = new Set();
4
4
  const push = (id) => { if (id && !ids.has(id)) { ids.add(id); out.push(id); } };
@@ -1 +1 @@
1
- import{d as s,h as d,k as e,S as f,l as g,J as m}from"./index-BGvI4n0T.js";function v(){const[n,c]=s("—"),[r,p]=s("—"),[u,o]=s(!1),[a,l]=s({message:"",type:""});async function i(){try{const t=await g({force:!0});t.home&&c(t.home),t.defaults&&p(JSON.stringify(t.defaults,null,2))}catch{}}async function h(){if(confirm("Reset ALL app-level settings to defaults? Every provider, model, account, and project you registered at the app level will be cleared. Project files on disk are not touched.")){o(!0),l({message:"resetting…",type:"busy"});try{await m(["providers","models","authAccounts","projects","promptSize","flags"]),l({message:"reset.",type:"success"}),await i()}catch(t){l({message:"reset failed: "+t.message,type:"error"})}o(!1)}}return d(()=>{i()},[]),e(f,null,e("div",{class:"view-head"},e("a",{href:"#/settings",class:"view-back","aria-label":"Back to settings"},"←"),e("h2",{class:"view-title"},"About")),e("section",null,e("h3",null,"Storage"),e("p",{class:"hint hint--compact"},"App-level settings and the account index live in this SQLite database:"),e("pre",{class:"settings__out"},n),e("h3",null,"Default values"),e("p",{class:"hint hint--compact"},"The merge floor for every project. Anything not set in app or project falls back to these."),e("pre",{class:"settings__out"},r),e("h3",null,"Destructive actions"),e("p",{class:"hint hint--compact"},"Reset all app-level keys. Project files on disk are not touched."),e("div",{class:"row row--actions"},e("button",{class:"btn btn--danger",type:"button",onClick:h,disabled:u},"Reset all app settings"),e("span",{class:`status${a.type?" status--"+a.type:""}`,"aria-live":"polite"},a.message))))}export{v as SettingsAboutView};
1
+ import{d as s,h as d,k as e,S as f,l as g,J as m}from"./index-BDkCsON6.js";function v(){const[n,c]=s("—"),[r,p]=s("—"),[u,o]=s(!1),[a,l]=s({message:"",type:""});async function i(){try{const t=await g({force:!0});t.home&&c(t.home),t.defaults&&p(JSON.stringify(t.defaults,null,2))}catch{}}async function h(){if(confirm("Reset ALL app-level settings to defaults? Every provider, model, account, and project you registered at the app level will be cleared. Project files on disk are not touched.")){o(!0),l({message:"resetting…",type:"busy"});try{await m(["providers","models","authAccounts","projects","promptSize","flags"]),l({message:"reset.",type:"success"}),await i()}catch(t){l({message:"reset failed: "+t.message,type:"error"})}o(!1)}}return d(()=>{i()},[]),e(f,null,e("div",{class:"view-head"},e("a",{href:"#/settings",class:"view-back","aria-label":"Back to settings"},"←"),e("h2",{class:"view-title"},"About")),e("section",null,e("h3",null,"Storage"),e("p",{class:"hint hint--compact"},"App-level settings and the account index live in this SQLite database:"),e("pre",{class:"settings__out"},n),e("h3",null,"Default values"),e("p",{class:"hint hint--compact"},"The merge floor for every project. Anything not set in app or project falls back to these."),e("pre",{class:"settings__out"},r),e("h3",null,"Destructive actions"),e("p",{class:"hint hint--compact"},"Reset all app-level keys. Project files on disk are not touched."),e("div",{class:"row row--actions"},e("button",{class:"btn btn--danger",type:"button",onClick:h,disabled:u},"Reset all app settings"),e("span",{class:`status${a.type?" status--"+a.type:""}`,"aria-live":"polite"},a.message))))}export{v as SettingsAboutView};
@@ -1 +1 @@
1
- import{d as b,h as w,f as v,k as t,S as y,n as T}from"./index-BGvI4n0T.js";function k(n,a=0){if(!n||typeof n!="object"||a>12)return null;if(Object.prototype.hasOwnProperty.call(n,"default"))return n.default;if(Object.prototype.hasOwnProperty.call(n,"const"))return n.const;if(Array.isArray(n.examples)&&n.examples.length)return n.examples[0];if(Array.isArray(n.enum)&&n.enum.length)return n.enum[0];const u=Array.isArray(n.oneOf)&&n.oneOf[0]||Array.isArray(n.anyOf)&&n.anyOf[0];if(u)return k(u,a+1);const i=Array.isArray(n.type)?n.type.find(c=>c!=="null"):n.type;if(i==="object"||n.properties){const c={};for(const[p,o]of Object.entries(n.properties||{}))c[p]=k(o,a+1);return c}return i==="array"?[]:i==="boolean"?!1:i==="integer"||i==="number"?0:i==="null"?null:""}function R(n){return JSON.stringify(k(n)||{},null,2)}function f(n){return"?projectDir="+encodeURIComponent(n||"")}function I(){return{id:"",label:"",description:"",kind:"cli",command:"",timeoutMs:"",serverId:"",toolName:"",argsText:"{}"}}function J(n){return{...I(),...n,timeoutMs:n.timeoutMs||"",argsText:JSON.stringify(n.args||{},null,2)}}function j({projectDir:n="",from:a=""}){const[u,i]=b([]),[c,p]=b("loading…");return w(()=>{let o=!1;return v("/api/actions?projectDir="+encodeURIComponent(n)).then(l=>{o||(l.status===200?(i(l.body.actions||[]),p("")):p(l.body&&l.body.error||"HTTP "+l.status))}).catch(l=>{o||p(String(l))}),()=>{o=!0}},[n]),t(y,null,t("div",{class:"view-head"},t("a",{href:"#/settings/project"+f(n)+(a?"&from="+encodeURIComponent(a):""),class:"view-back","aria-label":"Back to project settings"},"←"),t("h2",{class:"view-title"},"Custom actions")),t("section",null,t("p",{class:"hint hint--compact"},"Project shortcuts backed by a CLI command or MCP tool. Pick one by name from the composer menu or type ",t("code",null,"@action-id"),"."),t("ul",{class:"prompts__list","aria-label":"Custom actions"},u.length?u.map(o=>t("li",{key:o.id,class:"prompt-row"},t("a",{class:"prompt-row__main",href:"#/settings/actions/"+encodeURIComponent(o.id)+f(n)},t("div",{class:"prompt-row__title"},o.label||o.id),t("div",{class:"prompt-row__meta"},"@"+o.id+" · "+(o.kind==="mcp"?o.serverId+" / "+o.toolName:o.command)),t("div",{class:"prompt-row__chev","aria-hidden":"true"},"›")))):t("li",{class:"prompts__empty"},c||"No custom actions yet.")),t("div",{class:"row row--actions"},t("a",{class:"btn btn--primary",href:"#/settings/actions/new"+f(n)},"+ Add action"),t("span",{class:"status","aria-live":"polite"},c))))}function E({id:n="",projectDir:a="",from:u=""}){const i=!n||n==="new",c=u?"&from="+encodeURIComponent(u):"",p="#/settings/actions"+f(a)+c,[o,l]=b(I),[g,A]=b([]),[h,S]=b([]),[_,d]=b(i?"":"loading…");w(()=>{let e=!1;return Promise.all([v("/api/actions?projectDir="+encodeURIComponent(a)),v("/api/mcp/servers?projectDir="+encodeURIComponent(a))]).then(([s,r])=>{if(!e&&(r.status===200&&A(r.body.servers||[]),!i&&s.status===200)){const C=(s.body.actions||[]).find(P=>P.id===n);C?(l(J(C)),d("")):d("Action not found")}}).catch(s=>{e||d(String(s))}),()=>{e=!0}},[a,n,i]),w(()=>{const e=g.find(s=>s.id===o.serverId);S(e&&Array.isArray(e.tools)?e.tools:[])},[g,o.serverId]);function m(e,s){l(r=>({...r,[e]:s}))}function O(e){l(s=>({...s,serverId:e,toolName:"",argsText:"{}"}))}function M(e){const s=h.find(r=>r&&r.name===e);l(r=>({...r,toolName:e,argsText:s?R(s.inputSchema||s.parameters):"{}"}))}async function x(){let e={};if(o.kind==="mcp"){try{e=JSON.parse(o.argsText||"{}")}catch{d("MCP arguments must be valid JSON");return}if(!e||Array.isArray(e)||typeof e!="object"){d("MCP arguments must be a JSON object");return}}const s={id:o.id.trim(),label:o.label.trim(),description:o.description.trim(),kind:o.kind,...o.kind==="cli"?{command:o.command.trim(),...o.timeoutMs?{timeoutMs:Number(o.timeoutMs)}:{}}:{serverId:o.serverId,toolName:o.toolName,args:e}};d("saving…");const r=await v("/api/actions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:a,originalId:i?"":n,action:s})});if(r.status!==200){d(r.body&&r.body.error||"HTTP "+r.status);return}T("settings/actions"+f(a)+c)}async function N(){if(!confirm('Delete custom action "'+n+'"?'))return;const e=await v("/api/actions/"+encodeURIComponent(n)+f(a),{method:"DELETE"});e.status===200?T("settings/actions"+f(a)+c):d(e.body&&e.body.error||"HTTP "+e.status)}return t(y,null,t("div",{class:"view-head"},t("a",{href:p,class:"view-back","aria-label":"Back to custom actions"},"←"),t("h2",{class:"view-title"},i?"Add action":o.label||o.id||"Edit action")),t("section",null,t("div",{class:"row"},t("label",{class:"label",for:"action-id"},"Action ID"),t("input",{class:"input",id:"action-id",value:o.id,placeholder:"test",onInput:e=>m("id",e.currentTarget.value),autocapitalize:"off",spellcheck:!1}),t("p",{class:"hint hint--compact"},"Used as ",t("code",null,"@action-id"),". Letters, digits, dot, underscore, and dash only.")),t("div",{class:"row"},t("label",{class:"label",for:"action-label"},"Label"),t("input",{class:"input",id:"action-label",value:o.label,placeholder:"Run tests",onInput:e=>m("label",e.currentTarget.value)})),t("div",{class:"row"},t("label",{class:"label",for:"action-description"},"Description"),t("input",{class:"input",id:"action-description",value:o.description,placeholder:"What this action does",onInput:e=>m("description",e.currentTarget.value)})),t("div",{class:"row"},t("span",{class:"label"},"Runs with"),t("div",{class:"seg",role:"radiogroup","aria-label":"Action type"},[["cli","CLI"],["mcp","MCP"]].map(([e,s])=>t("label",{key:e,class:"seg__item"+(o.kind===e?" seg__item--on":"")},t("input",{type:"radio",name:"action-kind",value:e,checked:o.kind===e,onChange:()=>m("kind",e)}),t("span",{class:"seg__pill"},s))))),o.kind==="cli"?t(y,null,t("div",{class:"row"},t("label",{class:"label",for:"action-command"},"Command"),t("textarea",{class:"input settings-project__mono",id:"action-command",rows:4,value:o.command,placeholder:"npm test",onInput:e=>m("command",e.currentTarget.value),spellcheck:!1})),t("div",{class:"row"},t("label",{class:"label",for:"action-timeout"},"Timeout (ms, optional)"),t("input",{class:"input",id:"action-timeout",type:"number",min:1,max:6e5,inputmode:"numeric",value:o.timeoutMs,placeholder:"30000",onInput:e=>m("timeoutMs",e.currentTarget.value)}))):t(y,null,t("div",{class:"row"},t("label",{class:"label",for:"action-server"},"MCP server"),t("select",{class:"input",id:"action-server",value:o.serverId,onChange:e=>O(e.currentTarget.value)},t("option",{value:""},"Choose a server"),g.map(e=>t("option",{key:e.id,value:e.id},e.name||e.id)))),t("div",{class:"row"},t("label",{class:"label",for:"action-tool"},"MCP tool"),t("select",{class:"input",id:"action-tool",value:o.toolName,onChange:e=>M(e.currentTarget.value)},t("option",{value:""},h.length?"Choose a tool":"Start server to discover tools"),h.map(e=>t("option",{key:e.name,value:e.name},e.name)))),t("div",{class:"row"},t("label",{class:"label",for:"action-args"},"Arguments (JSON)"),t("textarea",{class:"input settings-project__mono",id:"action-args",rows:6,value:o.argsText,onInput:e=>m("argsText",e.currentTarget.value),spellcheck:!1}),t("p",{class:"hint hint--compact"},"Selecting a tool prefills this object from its input schema. Replace placeholder values before saving."))),t("div",{class:"row row--actions"},t("button",{class:"btn btn--primary",type:"button",onClick:x},"Save"),!i&&t("button",{class:"btn btn--danger",type:"button",onClick:N},"Delete"),t("span",{class:"status","aria-live":"polite"},_))))}export{E as SettingsActionEditView,j as SettingsActionsView};
1
+ import{d as b,h as w,f as v,k as t,S as y,n as T}from"./index-BDkCsON6.js";function k(n,a=0){if(!n||typeof n!="object"||a>12)return null;if(Object.prototype.hasOwnProperty.call(n,"default"))return n.default;if(Object.prototype.hasOwnProperty.call(n,"const"))return n.const;if(Array.isArray(n.examples)&&n.examples.length)return n.examples[0];if(Array.isArray(n.enum)&&n.enum.length)return n.enum[0];const u=Array.isArray(n.oneOf)&&n.oneOf[0]||Array.isArray(n.anyOf)&&n.anyOf[0];if(u)return k(u,a+1);const i=Array.isArray(n.type)?n.type.find(c=>c!=="null"):n.type;if(i==="object"||n.properties){const c={};for(const[p,o]of Object.entries(n.properties||{}))c[p]=k(o,a+1);return c}return i==="array"?[]:i==="boolean"?!1:i==="integer"||i==="number"?0:i==="null"?null:""}function R(n){return JSON.stringify(k(n)||{},null,2)}function f(n){return"?projectDir="+encodeURIComponent(n||"")}function I(){return{id:"",label:"",description:"",kind:"cli",command:"",timeoutMs:"",serverId:"",toolName:"",argsText:"{}"}}function J(n){return{...I(),...n,timeoutMs:n.timeoutMs||"",argsText:JSON.stringify(n.args||{},null,2)}}function j({projectDir:n="",from:a=""}){const[u,i]=b([]),[c,p]=b("loading…");return w(()=>{let o=!1;return v("/api/actions?projectDir="+encodeURIComponent(n)).then(l=>{o||(l.status===200?(i(l.body.actions||[]),p("")):p(l.body&&l.body.error||"HTTP "+l.status))}).catch(l=>{o||p(String(l))}),()=>{o=!0}},[n]),t(y,null,t("div",{class:"view-head"},t("a",{href:"#/settings/project"+f(n)+(a?"&from="+encodeURIComponent(a):""),class:"view-back","aria-label":"Back to project settings"},"←"),t("h2",{class:"view-title"},"Custom actions")),t("section",null,t("p",{class:"hint hint--compact"},"Project shortcuts backed by a CLI command or MCP tool. Pick one by name from the composer menu or type ",t("code",null,"@action-id"),"."),t("ul",{class:"prompts__list","aria-label":"Custom actions"},u.length?u.map(o=>t("li",{key:o.id,class:"prompt-row"},t("a",{class:"prompt-row__main",href:"#/settings/actions/"+encodeURIComponent(o.id)+f(n)},t("div",{class:"prompt-row__title"},o.label||o.id),t("div",{class:"prompt-row__meta"},"@"+o.id+" · "+(o.kind==="mcp"?o.serverId+" / "+o.toolName:o.command)),t("div",{class:"prompt-row__chev","aria-hidden":"true"},"›")))):t("li",{class:"prompts__empty"},c||"No custom actions yet.")),t("div",{class:"row row--actions"},t("a",{class:"btn btn--primary",href:"#/settings/actions/new"+f(n)},"+ Add action"),t("span",{class:"status","aria-live":"polite"},c))))}function E({id:n="",projectDir:a="",from:u=""}){const i=!n||n==="new",c=u?"&from="+encodeURIComponent(u):"",p="#/settings/actions"+f(a)+c,[o,l]=b(I),[g,A]=b([]),[h,S]=b([]),[_,d]=b(i?"":"loading…");w(()=>{let e=!1;return Promise.all([v("/api/actions?projectDir="+encodeURIComponent(a)),v("/api/mcp/servers?projectDir="+encodeURIComponent(a))]).then(([s,r])=>{if(!e&&(r.status===200&&A(r.body.servers||[]),!i&&s.status===200)){const C=(s.body.actions||[]).find(P=>P.id===n);C?(l(J(C)),d("")):d("Action not found")}}).catch(s=>{e||d(String(s))}),()=>{e=!0}},[a,n,i]),w(()=>{const e=g.find(s=>s.id===o.serverId);S(e&&Array.isArray(e.tools)?e.tools:[])},[g,o.serverId]);function m(e,s){l(r=>({...r,[e]:s}))}function O(e){l(s=>({...s,serverId:e,toolName:"",argsText:"{}"}))}function M(e){const s=h.find(r=>r&&r.name===e);l(r=>({...r,toolName:e,argsText:s?R(s.inputSchema||s.parameters):"{}"}))}async function x(){let e={};if(o.kind==="mcp"){try{e=JSON.parse(o.argsText||"{}")}catch{d("MCP arguments must be valid JSON");return}if(!e||Array.isArray(e)||typeof e!="object"){d("MCP arguments must be a JSON object");return}}const s={id:o.id.trim(),label:o.label.trim(),description:o.description.trim(),kind:o.kind,...o.kind==="cli"?{command:o.command.trim(),...o.timeoutMs?{timeoutMs:Number(o.timeoutMs)}:{}}:{serverId:o.serverId,toolName:o.toolName,args:e}};d("saving…");const r=await v("/api/actions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:a,originalId:i?"":n,action:s})});if(r.status!==200){d(r.body&&r.body.error||"HTTP "+r.status);return}T("settings/actions"+f(a)+c)}async function N(){if(!confirm('Delete custom action "'+n+'"?'))return;const e=await v("/api/actions/"+encodeURIComponent(n)+f(a),{method:"DELETE"});e.status===200?T("settings/actions"+f(a)+c):d(e.body&&e.body.error||"HTTP "+e.status)}return t(y,null,t("div",{class:"view-head"},t("a",{href:p,class:"view-back","aria-label":"Back to custom actions"},"←"),t("h2",{class:"view-title"},i?"Add action":o.label||o.id||"Edit action")),t("section",null,t("div",{class:"row"},t("label",{class:"label",for:"action-id"},"Action ID"),t("input",{class:"input",id:"action-id",value:o.id,placeholder:"test",onInput:e=>m("id",e.currentTarget.value),autocapitalize:"off",spellcheck:!1}),t("p",{class:"hint hint--compact"},"Used as ",t("code",null,"@action-id"),". Letters, digits, dot, underscore, and dash only.")),t("div",{class:"row"},t("label",{class:"label",for:"action-label"},"Label"),t("input",{class:"input",id:"action-label",value:o.label,placeholder:"Run tests",onInput:e=>m("label",e.currentTarget.value)})),t("div",{class:"row"},t("label",{class:"label",for:"action-description"},"Description"),t("input",{class:"input",id:"action-description",value:o.description,placeholder:"What this action does",onInput:e=>m("description",e.currentTarget.value)})),t("div",{class:"row"},t("span",{class:"label"},"Runs with"),t("div",{class:"seg",role:"radiogroup","aria-label":"Action type"},[["cli","CLI"],["mcp","MCP"]].map(([e,s])=>t("label",{key:e,class:"seg__item"+(o.kind===e?" seg__item--on":"")},t("input",{type:"radio",name:"action-kind",value:e,checked:o.kind===e,onChange:()=>m("kind",e)}),t("span",{class:"seg__pill"},s))))),o.kind==="cli"?t(y,null,t("div",{class:"row"},t("label",{class:"label",for:"action-command"},"Command"),t("textarea",{class:"input settings-project__mono",id:"action-command",rows:4,value:o.command,placeholder:"npm test",onInput:e=>m("command",e.currentTarget.value),spellcheck:!1})),t("div",{class:"row"},t("label",{class:"label",for:"action-timeout"},"Timeout (ms, optional)"),t("input",{class:"input",id:"action-timeout",type:"number",min:1,max:6e5,inputmode:"numeric",value:o.timeoutMs,placeholder:"30000",onInput:e=>m("timeoutMs",e.currentTarget.value)}))):t(y,null,t("div",{class:"row"},t("label",{class:"label",for:"action-server"},"MCP server"),t("select",{class:"input",id:"action-server",value:o.serverId,onChange:e=>O(e.currentTarget.value)},t("option",{value:""},"Choose a server"),g.map(e=>t("option",{key:e.id,value:e.id},e.name||e.id)))),t("div",{class:"row"},t("label",{class:"label",for:"action-tool"},"MCP tool"),t("select",{class:"input",id:"action-tool",value:o.toolName,onChange:e=>M(e.currentTarget.value)},t("option",{value:""},h.length?"Choose a tool":"Start server to discover tools"),h.map(e=>t("option",{key:e.name,value:e.name},e.name)))),t("div",{class:"row"},t("label",{class:"label",for:"action-args"},"Arguments (JSON)"),t("textarea",{class:"input settings-project__mono",id:"action-args",rows:6,value:o.argsText,onInput:e=>m("argsText",e.currentTarget.value),spellcheck:!1}),t("p",{class:"hint hint--compact"},"Selecting a tool prefills this object from its input schema. Replace placeholder values before saving."))),t("div",{class:"row row--actions"},t("button",{class:"btn btn--primary",type:"button",onClick:x},"Save"),!i&&t("button",{class:"btn btn--danger",type:"button",onClick:N},"Delete"),t("span",{class:"status","aria-live":"polite"},_))))}export{E as SettingsActionEditView,j as SettingsActionsView};
@@ -1 +1 @@
1
- import{A as q,d as v,h as E,f as _,O as Y,k as e,S as P,Q as fe,R as ge,U as he,q as me,b as $,n as X}from"./index-BGvI4n0T.js";import{b as be,a as G,c as ee}from"./agentNavigation-BiiCpFz5.js";function ve({name:l,save:n,onStatus:p,onSaved:c,delay:h=350}){let f=l,r={},g=null,s=null,a=!1;function m(){g!==null&&clearTimeout(g),g=null}async function O(){for(;Object.keys(r).length;){m();const I=r;r={},p({text:"saving…",kind:"busy"});let T;try{T=await n(f,I)}catch(U){return r={...I,...r},m(),a=!0,p({text:U.message||"Could not save",kind:"error"}),!1}f=T.name,Object.keys(r).length||(c(T),p({text:"saved",kind:"success"}))}return!0}function C(){return m(),s||(a=!1,s=O().finally(()=>{s=null}),s)}function R(I,T=!1){if(r={...r,...I},a=!1,m(),p({text:"unsaved changes",kind:"busy"}),T)return C();g=setTimeout(C,h)}return{enqueue:R,flush:C,get name(){return f},get failed(){return a}}}function te(l){return l&&l.projectDir?l.projectDir:$.value&&$.value.dir||""}const ye=[{value:"shell",label:"shell"},{value:"subagent",label:"subagent"},{value:"task",label:"task"},{value:"webpreview",label:"webpreview"},{value:"restart_app",label:"restart_app"},{value:"report_progress",label:"report_progress"},{value:"ask_user",label:"ask_user"},{value:"list_features",label:"list_features"},{value:"read_file",label:"read_file"},{value:"list_files",label:"list_files"},{value:"search_files",label:"search_files"},{value:"write_file",label:"write_file"},{value:"edit_file",label:"edit_file"}];function we(l){return ye.concat((l||[]).filter(n=>n&&n.id).map(n=>({value:"mcp__"+(n.slug||n.id),label:"MCP: "+(n.name||n.id)})))}function K(l,n,p,c){const h=c.map(a=>a.value),f=l!==void 0?l.slice():null;let r;f==null?r=p?h.slice():h.filter(a=>a!==n):r=p?f.concat(n):f.filter(a=>a!==n),r=Array.from(new Set(r));const s=r.length===h.length&&h.every(a=>r.includes(a))?[]:r;return{tools:s.length?s:void 0,send:s}}function ke(l,n,p,c){if(n.id.startsWith("mcp__"))return K(l,n.id,p,c);let h=l,f=l===void 0?[]:l.slice();for(const r of n.tools){const g=K(h,r.id,p,c);h=g.tools,f=g.send}return{tools:h,send:f}}function Ie(l){const n=te(l),p={...l,projectDir:n},[c,h]=v([]),[f,r]=v({text:"",kind:""});async function g(){if(!n){h([]),r({text:"open a chat to pick a project first",kind:"error"});return}r({text:"loading…",kind:"busy"});let s;try{s=await _("/api/agents?projectDir="+encodeURIComponent(n))}catch{r({text:"network error",kind:"error"});return}if(s.status!==200){r({text:"HTTP "+s.status,kind:"error"});return}const a=s.body.agents||[];h(a),r({text:a.length+(a.length===1?" agent":" agents"),kind:"success"})}return E(()=>{g()},[n]),n?e(P,null,e("div",{class:"view-head"},e("a",{href:"#/settings/project?"+ee(p),class:"view-back","aria-label":"Back to project"},"←"),e("h2",{class:"view-title"},"Agents")),e("section",null,e("p",{class:"hint hint--compact"},"Subagent delegation personas, saved in the project's .mouaif.json. The subagent tool and @-mentions can delegate to them."),e("p",{class:"hint hint--compact"},e("code",null,n)),e("ul",{class:"prompts__list","aria-label":"Agents"},c.length===0?e("li",{class:"prompts__empty"},'No agents yet. Tap "Add agent" to create your first one.'):c.map(s=>{const a=[];a.push(Array.isArray(s.tools)&&s.tools.length?s.tools.length+(s.tools.length===1?" tool":" tools"):"all tools"),s.modelId&&a.push(s.modelId);const m=(s.content||"").trim().replace(/\s+/g," ");return m&&a.push(m.length>48?m.slice(0,48)+"…":m),e("li",{key:s.name,class:"prompt-row"},e("a",{class:"prompt-row__main",href:"#/"+G(s.name,p)},e("div",{class:"prompt-row__title"},s.name),e("div",{class:"prompt-row__meta"},a.join(" · ")),e("div",{class:"prompt-row__chev"},"›")))})),e("div",{class:"row row--actions"},e("a",{href:"#/settings/agents/new?"+ee(p),class:"btn btn--primary"},"+ Add agent"),e("span",{class:"status"+(f.kind?" status--"+f.kind:""),"aria-live":"polite"},f.text)))):e(P,null,e("div",{class:"view-head"},e("a",{href:"#/settings",class:"view-back","aria-label":"Back to settings"},"←"),e("h2",{class:"view-title"},"Agents")),e("section",null,e("p",{class:"hint"},"No project selected. Open a chat to pick a project, or use the picker to add a new one."),e("div",{class:"row row--actions"},e("a",{href:"#/projects/new",class:"btn btn--primary"},"Open project picker"))))}function Te(l){const n=l.isNew??l.id==="new",p=n?"":l.id||"",c=te(l),h={...l,projectDir:c},f=be(h),r=l.returnTo==="project"?"Back to project settings":"Back to agents",g=q(!1),s=q(!1),a=q(!1),[m,O]=v([]),[C,R]=v([]),[I,T]=v([]),[U,ne]=v([]),[d,y]=v(null),[x,b]=v({text:"",kind:""}),[D,z]=v(!1),[M,J]=v(!1);E(()=>{let t=!1;async function o(){if(y(null),!!c){if(n){y({name:"",content:""});return}b({text:"loading…",kind:"busy"});try{const i=await _("/api/agents/"+encodeURIComponent(p)+"?projectDir="+encodeURIComponent(c));if(t)return;if(i.status!==200)throw new Error("HTTP "+i.status);y(i.body.agent),b({text:"",kind:""})}catch(i){t||b({text:i.message||"network error",kind:"error"})}}}return o(),()=>{t=!0}},[c,p,n]),E(()=>{let t=!1;async function o(){if(c)try{const[i,k,A,H]=await Promise.all([_("/api/ai/models?projectDir="+encodeURIComponent(c)),_("/api/ai/models/providers"),_("/api/mcp/servers?projectDir="+encodeURIComponent(c)),_("/api/tools/list?projectDir="+encodeURIComponent(c))]),W=i.status===200&&Array.isArray(i.body.models)?i.body.models:[],Z=k.status===200&&Array.isArray(k.body.providers)?k.body.providers.map(u=>u&&u.id).filter(Boolean):[];if(t)return;O(W),R(Z),A.status===200&&Array.isArray(A.body.servers)&&T(A.body.servers),H.status===200&&Array.isArray(H.body.tools)&&ne(H.body.tools);const pe=await Promise.all(Z.map(u=>Promise.all([Y(u).then(j=>({provider:u,models:j.models||[]})).catch(()=>({provider:u,models:[]})),Y(u,{purpose:"image"}).then(j=>({provider:u,models:j.models||[]})).catch(()=>({provider:u,models:[]}))]).then(j=>({provider:u,models:j.flatMap(N=>N.models)})))),S=new Map;for(const u of W)u&&u.id&&u.provider&&S.set(u.provider+"\0"+u.id,u);for(const u of pe)for(const j of u.models){if(!j||!j.id)continue;const N=u.provider+"\0"+j.id;S.has(N)||S.set(N,Object.assign({},j,{provider:u.provider}))}t||O(Array.from(S.values()))}catch{}}return o(),()=>{t=!0}},[c]);const[w]=v(()=>ve({name:p,save:async(t,o)=>{const i=await _("/api/agents/"+encodeURIComponent(t),{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:c,...o})});if(i.status!==200)throw new Error(i.body&&i.body.error||"HTTP "+i.status);return i.body.agent},onStatus:t=>{g.current&&b(t)},onSaved:t=>{g.current&&(y(t),s.current||window.history.replaceState(null,"","#/"+G(t.name,h)))}}));E(()=>(g.current=!0,()=>{g.current=!1,!n&&!w.failed&&w.flush()}),[w,n]);function V(t){n||w.enqueue(t)}function L(t){n||w.enqueue(t,!0)}async function F(t){if(!(t.button>0||t.metaKey||t.ctrlKey||t.shiftKey||t.altKey)&&(t.preventDefault(),!a.current)){if(s.current=!0,!n&&!await w.flush()){s.current=!1;return}g.current&&X(f)}}function se(t){y(o=>Object.assign({},o,{name:t})),V({name:t})}function ae(t){y(o=>Object.assign({},o,{content:t})),V({content:t})}function re(t){const o=t&&t.modelId||"",i=t&&t.providerId||"";y(k=>Object.assign({},k,{modelId:o||void 0,providerId:i||void 0})),L({modelId:o,providerId:i})}function oe(t){y(o=>Object.assign({},o,{thinkingLevel:t||void 0})),L({thinkingLevel:t||""})}function ie(t,o){const i=K(d&&d.tools,t,o,B);y(k=>Object.assign({},k,{tools:i.tools})),L({tools:i.send})}function le(t,o){const i=Q.find(A=>A.id===t);if(!i)return;const k=ke(d&&d.tools,i,o,B);y(A=>Object.assign({},A,{tools:k.tools})),L({tools:k.send})}async function ce(){if(a.current)return;if(!c){b({text:"no project selected",kind:"error"});return}const t=(d&&d.name||"").trim();if(!t){b({text:"name is required",kind:"error"});return}if(!/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(t)){b({text:"letters, digits, . _ - only; must start with a letter or digit",kind:"error"});return}a.current=!0,J(!0),b({text:"creating…",kind:"busy"});let o;try{o=await _("/api/agents",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:c,...d,name:t,content:d.content||""})})}catch{b({text:"network error",kind:"error"});return}finally{a.current=!1,J(!1)}if(g.current){if(o.status!==201){b({text:o.body&&o.body.error||"HTTP "+o.status,kind:"error"});return}window.location.replace("#/"+G(o.body.agent.name,h))}}async function de(){if(!(!p||a.current)&&confirm('Delete agent "'+w.name+'"?')){a.current=!0,z(!0);try{if(!await w.flush())return;b({text:"deleting…",kind:"busy"});const t=await _("/api/agents/"+encodeURIComponent(w.name)+"?projectDir="+encodeURIComponent(c),{method:"DELETE"});if(t.status!==200)throw new Error("HTTP "+t.status);g.current&&X(f)}catch(t){b({text:t.message||"network error",kind:"error"})}finally{a.current=!1,z(!1)}}}if(!c)return e(P,null,e("div",{class:"view-head"},e("a",{href:"#/settings/project",class:"view-back","aria-label":"Back"},"←"),e("h2",{class:"view-title"},n?"Add agent":"Edit agent")),e("section",null,e("p",{class:"hint"},"No project selected. Open a chat to pick a project, or use the picker to add a new one."),e("div",{class:"row row--actions"},e("a",{href:"#/projects/new",class:"btn btn--primary"},"Open project picker"))));if(!d)return e(P,null,e("div",{class:"view-head"},e("a",{href:"#/"+f,onClick:F,class:"view-back","aria-label":r},"←"),e("h2",{class:"view-title"},n?"Add agent":"Edit agent")),e("section",null,e("span",{class:"status"+(x.kind?" status--"+x.kind:""),"aria-live":"polite"},x.text||"loading…")));const ue=d.tools!==void 0,B=we(I),Q=fe({choices:B,restricted:ue,selected:t=>d.tools.includes(t),mcpServers:I,catalog:U});return e(P,null,e("div",{class:"view-head"},e("a",{href:"#/"+f,onClick:F,class:"view-back","aria-label":r},"←"),e("h2",{class:"view-title"},n?"Add agent":d.name)),e("section",{class:"agent-editor"},e("p",{class:"hint hint--compact"},e("code",null,c)),e("fieldset",{class:"agent-editor__fields",disabled:M||D},e("div",{class:"row"},e("label",{class:"label",for:"sae-name"},"Name"),e("input",{class:"input",id:"sae-name",type:"text",value:d.name||"",placeholder:"reviewer",maxLength:64,autoCapitalize:"none",spellcheck:!1,onInput:t=>se(t.target.value)}),e("p",{class:"hint hint--compact"},"Letters, digits, . _ - only; must start with a letter or digit.")),e("div",{class:"row"},e("label",{class:"label",for:"sae-content"},"Instructions"),e("textarea",{class:"input prompts__textarea",id:"sae-content",rows:6,value:d.content||"",onInput:t=>ae(t.target.value),placeholder:"You are an assistant who…"}),!n&&e("p",{class:"hint hint--compact"},"Saved automatically as you type.")),e("div",{class:"row"},e("span",{class:"label"},"Model"),e(ge,{models:m,value:d.modelId?{providerId:d.providerId||(m.find(t=>t.id===d.modelId)||{}).provider||"",modelId:d.modelId}:null,variant:"sheet",extraProviders:C,allowClear:!0,clearLabel:"Inherit chat model",placeholder:"Pick a model",disabled:M||D,ariaLabel:"Model for this agent",onChange:re})),e("div",{class:"row"},e("span",{class:"label"},"Thinking"),e(he,{value:d.thinkingLevel||"",descriptor:(m.find(t=>t.id===d.modelId&&(!d.providerId||t.provider===d.providerId))||{}).thinking,inheritLabel:"Inherit chat thinking",disabled:M||D,ariaLabel:"Thinking level for this agent",onChange:oe}),e("p",{class:"hint hint--compact"},`How much reasoning this agent does before answering. "Inherit chat thinking" follows the chat's current model.`)),e("div",{class:"row"},e("span",{class:"label"},"Tools"),e(me,{groups:Q,collapsedByDefault:!0,onToggleGroup:le,onToggleTool:(t,o,i)=>ie(o,i)}),e("p",{class:"hint hint--compact"},"All checked = the agent inherits the chat's full tool surface. Uncheck to build an explicit allowlist.")),e("div",{class:"row row--actions"},n&&e("button",{class:"btn btn--primary",type:"button",onClick:ce,disabled:M},"Create"),!n&&e("button",{class:"btn btn--danger",type:"button",onClick:de,disabled:D},"Delete"),!n&&x.kind==="error"&&e("button",{class:"btn",type:"button",onClick:()=>w.flush()},"Retry save"),e("span",{class:"status"+(x.kind?" status--"+x.kind:""),"aria-live":"polite"},x.text)))))}export{Te as SettingsAgentEditView,Ie as SettingsAgentsView,ke as toggleGroupInList,K as toggleToolInList};
1
+ import{A as q,d as v,h as E,f as _,O as Y,k as e,S as P,Q as fe,R as ge,U as he,q as me,b as $,n as X}from"./index-BDkCsON6.js";import{b as be,a as G,c as ee}from"./agentNavigation-BiiCpFz5.js";function ve({name:l,save:n,onStatus:p,onSaved:c,delay:h=350}){let f=l,r={},g=null,s=null,a=!1;function m(){g!==null&&clearTimeout(g),g=null}async function O(){for(;Object.keys(r).length;){m();const I=r;r={},p({text:"saving…",kind:"busy"});let T;try{T=await n(f,I)}catch(U){return r={...I,...r},m(),a=!0,p({text:U.message||"Could not save",kind:"error"}),!1}f=T.name,Object.keys(r).length||(c(T),p({text:"saved",kind:"success"}))}return!0}function C(){return m(),s||(a=!1,s=O().finally(()=>{s=null}),s)}function R(I,T=!1){if(r={...r,...I},a=!1,m(),p({text:"unsaved changes",kind:"busy"}),T)return C();g=setTimeout(C,h)}return{enqueue:R,flush:C,get name(){return f},get failed(){return a}}}function te(l){return l&&l.projectDir?l.projectDir:$.value&&$.value.dir||""}const ye=[{value:"shell",label:"shell"},{value:"subagent",label:"subagent"},{value:"task",label:"task"},{value:"webpreview",label:"webpreview"},{value:"restart_app",label:"restart_app"},{value:"report_progress",label:"report_progress"},{value:"ask_user",label:"ask_user"},{value:"list_features",label:"list_features"},{value:"read_file",label:"read_file"},{value:"list_files",label:"list_files"},{value:"search_files",label:"search_files"},{value:"write_file",label:"write_file"},{value:"edit_file",label:"edit_file"}];function we(l){return ye.concat((l||[]).filter(n=>n&&n.id).map(n=>({value:"mcp__"+(n.slug||n.id),label:"MCP: "+(n.name||n.id)})))}function K(l,n,p,c){const h=c.map(a=>a.value),f=l!==void 0?l.slice():null;let r;f==null?r=p?h.slice():h.filter(a=>a!==n):r=p?f.concat(n):f.filter(a=>a!==n),r=Array.from(new Set(r));const s=r.length===h.length&&h.every(a=>r.includes(a))?[]:r;return{tools:s.length?s:void 0,send:s}}function ke(l,n,p,c){if(n.id.startsWith("mcp__"))return K(l,n.id,p,c);let h=l,f=l===void 0?[]:l.slice();for(const r of n.tools){const g=K(h,r.id,p,c);h=g.tools,f=g.send}return{tools:h,send:f}}function Ie(l){const n=te(l),p={...l,projectDir:n},[c,h]=v([]),[f,r]=v({text:"",kind:""});async function g(){if(!n){h([]),r({text:"open a chat to pick a project first",kind:"error"});return}r({text:"loading…",kind:"busy"});let s;try{s=await _("/api/agents?projectDir="+encodeURIComponent(n))}catch{r({text:"network error",kind:"error"});return}if(s.status!==200){r({text:"HTTP "+s.status,kind:"error"});return}const a=s.body.agents||[];h(a),r({text:a.length+(a.length===1?" agent":" agents"),kind:"success"})}return E(()=>{g()},[n]),n?e(P,null,e("div",{class:"view-head"},e("a",{href:"#/settings/project?"+ee(p),class:"view-back","aria-label":"Back to project"},"←"),e("h2",{class:"view-title"},"Agents")),e("section",null,e("p",{class:"hint hint--compact"},"Subagent delegation personas, saved in the project's .mouaif.json. The subagent tool and @-mentions can delegate to them."),e("p",{class:"hint hint--compact"},e("code",null,n)),e("ul",{class:"prompts__list","aria-label":"Agents"},c.length===0?e("li",{class:"prompts__empty"},'No agents yet. Tap "Add agent" to create your first one.'):c.map(s=>{const a=[];a.push(Array.isArray(s.tools)&&s.tools.length?s.tools.length+(s.tools.length===1?" tool":" tools"):"all tools"),s.modelId&&a.push(s.modelId);const m=(s.content||"").trim().replace(/\s+/g," ");return m&&a.push(m.length>48?m.slice(0,48)+"…":m),e("li",{key:s.name,class:"prompt-row"},e("a",{class:"prompt-row__main",href:"#/"+G(s.name,p)},e("div",{class:"prompt-row__title"},s.name),e("div",{class:"prompt-row__meta"},a.join(" · ")),e("div",{class:"prompt-row__chev"},"›")))})),e("div",{class:"row row--actions"},e("a",{href:"#/settings/agents/new?"+ee(p),class:"btn btn--primary"},"+ Add agent"),e("span",{class:"status"+(f.kind?" status--"+f.kind:""),"aria-live":"polite"},f.text)))):e(P,null,e("div",{class:"view-head"},e("a",{href:"#/settings",class:"view-back","aria-label":"Back to settings"},"←"),e("h2",{class:"view-title"},"Agents")),e("section",null,e("p",{class:"hint"},"No project selected. Open a chat to pick a project, or use the picker to add a new one."),e("div",{class:"row row--actions"},e("a",{href:"#/projects/new",class:"btn btn--primary"},"Open project picker"))))}function Te(l){const n=l.isNew??l.id==="new",p=n?"":l.id||"",c=te(l),h={...l,projectDir:c},f=be(h),r=l.returnTo==="project"?"Back to project settings":"Back to agents",g=q(!1),s=q(!1),a=q(!1),[m,O]=v([]),[C,R]=v([]),[I,T]=v([]),[U,ne]=v([]),[d,y]=v(null),[x,b]=v({text:"",kind:""}),[D,z]=v(!1),[M,J]=v(!1);E(()=>{let t=!1;async function o(){if(y(null),!!c){if(n){y({name:"",content:""});return}b({text:"loading…",kind:"busy"});try{const i=await _("/api/agents/"+encodeURIComponent(p)+"?projectDir="+encodeURIComponent(c));if(t)return;if(i.status!==200)throw new Error("HTTP "+i.status);y(i.body.agent),b({text:"",kind:""})}catch(i){t||b({text:i.message||"network error",kind:"error"})}}}return o(),()=>{t=!0}},[c,p,n]),E(()=>{let t=!1;async function o(){if(c)try{const[i,k,A,H]=await Promise.all([_("/api/ai/models?projectDir="+encodeURIComponent(c)),_("/api/ai/models/providers"),_("/api/mcp/servers?projectDir="+encodeURIComponent(c)),_("/api/tools/list?projectDir="+encodeURIComponent(c))]),W=i.status===200&&Array.isArray(i.body.models)?i.body.models:[],Z=k.status===200&&Array.isArray(k.body.providers)?k.body.providers.map(u=>u&&u.id).filter(Boolean):[];if(t)return;O(W),R(Z),A.status===200&&Array.isArray(A.body.servers)&&T(A.body.servers),H.status===200&&Array.isArray(H.body.tools)&&ne(H.body.tools);const pe=await Promise.all(Z.map(u=>Promise.all([Y(u).then(j=>({provider:u,models:j.models||[]})).catch(()=>({provider:u,models:[]})),Y(u,{purpose:"image"}).then(j=>({provider:u,models:j.models||[]})).catch(()=>({provider:u,models:[]}))]).then(j=>({provider:u,models:j.flatMap(N=>N.models)})))),S=new Map;for(const u of W)u&&u.id&&u.provider&&S.set(u.provider+"\0"+u.id,u);for(const u of pe)for(const j of u.models){if(!j||!j.id)continue;const N=u.provider+"\0"+j.id;S.has(N)||S.set(N,Object.assign({},j,{provider:u.provider}))}t||O(Array.from(S.values()))}catch{}}return o(),()=>{t=!0}},[c]);const[w]=v(()=>ve({name:p,save:async(t,o)=>{const i=await _("/api/agents/"+encodeURIComponent(t),{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:c,...o})});if(i.status!==200)throw new Error(i.body&&i.body.error||"HTTP "+i.status);return i.body.agent},onStatus:t=>{g.current&&b(t)},onSaved:t=>{g.current&&(y(t),s.current||window.history.replaceState(null,"","#/"+G(t.name,h)))}}));E(()=>(g.current=!0,()=>{g.current=!1,!n&&!w.failed&&w.flush()}),[w,n]);function V(t){n||w.enqueue(t)}function L(t){n||w.enqueue(t,!0)}async function F(t){if(!(t.button>0||t.metaKey||t.ctrlKey||t.shiftKey||t.altKey)&&(t.preventDefault(),!a.current)){if(s.current=!0,!n&&!await w.flush()){s.current=!1;return}g.current&&X(f)}}function se(t){y(o=>Object.assign({},o,{name:t})),V({name:t})}function ae(t){y(o=>Object.assign({},o,{content:t})),V({content:t})}function re(t){const o=t&&t.modelId||"",i=t&&t.providerId||"";y(k=>Object.assign({},k,{modelId:o||void 0,providerId:i||void 0})),L({modelId:o,providerId:i})}function oe(t){y(o=>Object.assign({},o,{thinkingLevel:t||void 0})),L({thinkingLevel:t||""})}function ie(t,o){const i=K(d&&d.tools,t,o,B);y(k=>Object.assign({},k,{tools:i.tools})),L({tools:i.send})}function le(t,o){const i=Q.find(A=>A.id===t);if(!i)return;const k=ke(d&&d.tools,i,o,B);y(A=>Object.assign({},A,{tools:k.tools})),L({tools:k.send})}async function ce(){if(a.current)return;if(!c){b({text:"no project selected",kind:"error"});return}const t=(d&&d.name||"").trim();if(!t){b({text:"name is required",kind:"error"});return}if(!/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(t)){b({text:"letters, digits, . _ - only; must start with a letter or digit",kind:"error"});return}a.current=!0,J(!0),b({text:"creating…",kind:"busy"});let o;try{o=await _("/api/agents",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:c,...d,name:t,content:d.content||""})})}catch{b({text:"network error",kind:"error"});return}finally{a.current=!1,J(!1)}if(g.current){if(o.status!==201){b({text:o.body&&o.body.error||"HTTP "+o.status,kind:"error"});return}window.location.replace("#/"+G(o.body.agent.name,h))}}async function de(){if(!(!p||a.current)&&confirm('Delete agent "'+w.name+'"?')){a.current=!0,z(!0);try{if(!await w.flush())return;b({text:"deleting…",kind:"busy"});const t=await _("/api/agents/"+encodeURIComponent(w.name)+"?projectDir="+encodeURIComponent(c),{method:"DELETE"});if(t.status!==200)throw new Error("HTTP "+t.status);g.current&&X(f)}catch(t){b({text:t.message||"network error",kind:"error"})}finally{a.current=!1,z(!1)}}}if(!c)return e(P,null,e("div",{class:"view-head"},e("a",{href:"#/settings/project",class:"view-back","aria-label":"Back"},"←"),e("h2",{class:"view-title"},n?"Add agent":"Edit agent")),e("section",null,e("p",{class:"hint"},"No project selected. Open a chat to pick a project, or use the picker to add a new one."),e("div",{class:"row row--actions"},e("a",{href:"#/projects/new",class:"btn btn--primary"},"Open project picker"))));if(!d)return e(P,null,e("div",{class:"view-head"},e("a",{href:"#/"+f,onClick:F,class:"view-back","aria-label":r},"←"),e("h2",{class:"view-title"},n?"Add agent":"Edit agent")),e("section",null,e("span",{class:"status"+(x.kind?" status--"+x.kind:""),"aria-live":"polite"},x.text||"loading…")));const ue=d.tools!==void 0,B=we(I),Q=fe({choices:B,restricted:ue,selected:t=>d.tools.includes(t),mcpServers:I,catalog:U});return e(P,null,e("div",{class:"view-head"},e("a",{href:"#/"+f,onClick:F,class:"view-back","aria-label":r},"←"),e("h2",{class:"view-title"},n?"Add agent":d.name)),e("section",{class:"agent-editor"},e("p",{class:"hint hint--compact"},e("code",null,c)),e("fieldset",{class:"agent-editor__fields",disabled:M||D},e("div",{class:"row"},e("label",{class:"label",for:"sae-name"},"Name"),e("input",{class:"input",id:"sae-name",type:"text",value:d.name||"",placeholder:"reviewer",maxLength:64,autoCapitalize:"none",spellcheck:!1,onInput:t=>se(t.target.value)}),e("p",{class:"hint hint--compact"},"Letters, digits, . _ - only; must start with a letter or digit.")),e("div",{class:"row"},e("label",{class:"label",for:"sae-content"},"Instructions"),e("textarea",{class:"input prompts__textarea",id:"sae-content",rows:6,value:d.content||"",onInput:t=>ae(t.target.value),placeholder:"You are an assistant who…"}),!n&&e("p",{class:"hint hint--compact"},"Saved automatically as you type.")),e("div",{class:"row"},e("span",{class:"label"},"Model"),e(ge,{models:m,value:d.modelId?{providerId:d.providerId||(m.find(t=>t.id===d.modelId)||{}).provider||"",modelId:d.modelId}:null,variant:"sheet",extraProviders:C,allowClear:!0,clearLabel:"Inherit chat model",placeholder:"Pick a model",disabled:M||D,ariaLabel:"Model for this agent",onChange:re})),e("div",{class:"row"},e("span",{class:"label"},"Thinking"),e(he,{value:d.thinkingLevel||"",descriptor:(m.find(t=>t.id===d.modelId&&(!d.providerId||t.provider===d.providerId))||{}).thinking,inheritLabel:"Inherit chat thinking",disabled:M||D,ariaLabel:"Thinking level for this agent",onChange:oe}),e("p",{class:"hint hint--compact"},`How much reasoning this agent does before answering. "Inherit chat thinking" follows the chat's current model.`)),e("div",{class:"row"},e("span",{class:"label"},"Tools"),e(me,{groups:Q,collapsedByDefault:!0,onToggleGroup:le,onToggleTool:(t,o,i)=>ie(o,i)}),e("p",{class:"hint hint--compact"},"All checked = the agent inherits the chat's full tool surface. Uncheck to build an explicit allowlist.")),e("div",{class:"row row--actions"},n&&e("button",{class:"btn btn--primary",type:"button",onClick:ce,disabled:M},"Create"),!n&&e("button",{class:"btn btn--danger",type:"button",onClick:de,disabled:D},"Delete"),!n&&x.kind==="error"&&e("button",{class:"btn",type:"button",onClick:()=>w.flush()},"Retry save"),e("span",{class:"status"+(x.kind?" status--"+x.kind:""),"aria-live":"polite"},x.text)))))}export{Te as SettingsAgentEditView,Ie as SettingsAgentsView,ke as toggleGroupInList,K as toggleToolInList};
@@ -1 +1 @@
1
- import{d as i,A as j,h as k,l as W,z as q,B as Y,k as t,S as Z,s as J}from"./index-BGvI4n0T.js";const S=[{value:"very-small",label:"Very small — tool names only, no schemas"},{value:"average",label:"Average — full tools, recommended"},{value:"extensive",label:"Extensive — full tools + best-practice guidance"}];function K(r){const n=S.find(c=>c.value===r);return n?n.label.split(" — ")[0].toLowerCase():r||"average"}function U(){const[r,n]=i("average"),[c,h]=i(!0),[d,m]=i(!0),[g,_]=i(!1),[f,b]=i(!0),[v,w]=i(!0),[B,y]=i(""),[C,x]=i(""),[O,T]=i(""),[F,z]=i(""),[A,E]=i(""),[M,R]=i(""),o=j(!0);k(()=>()=>{o.current=!1},[]);const l=j({promptSize:0,enterForNewline:0,autoRetry:0,fileOrbButton:0,dictationButton:0,imageButton:0});k(()=>{(async()=>{try{const e=await W({force:!0});if(!o.current)return;n(e.app&&e.app.promptSize||"average"),h(e.app&&typeof e.app.enterForNewline=="boolean"?e.app.enterForNewline:!0),m(e.app&&typeof e.app.autoRetry=="boolean"?e.app.autoRetry:!0),_(q(e));const s=Y(e);b(s.dictation),w(s.image)}catch(e){o.current&&y("load failed: "+e.message)}})()},[]);async function a(e,s,p,L){const u=(l.current[e]||0)+1;l.current[e]=u,p("saving…");try{if(await J(s),!o.current||l.current[e]!==u)return;p(L)}catch(V){if(!o.current||l.current[e]!==u)return;p("save failed: "+V.message)}}function D(e){const s=e.currentTarget.value;n(s),a("promptSize",{promptSize:s},y,"set to "+K(s))}function N(e){const s=e.currentTarget.checked;h(s),a("enterForNewline",{enterForNewline:s},x,s?"Enter now adds a newline":"Enter now sends")}function P(e){const s=e.currentTarget.checked;m(s),a("autoRetry",{autoRetry:s},T,s?"auto-retry on":"auto-retry off")}function I(e){const s=e.currentTarget.checked;_(s),a("fileOrbButton",{fileOrbButton:s},z,s?"the file button is now a glass orb (open a chat to see it)":"the file button is back to the flat circle")}function H(e){const s=e.currentTarget.checked;b(s),a("dictationButton",{dictationButton:s},E,s?"the composer microphone is shown again":"the composer microphone is hidden (open a chat to see it)")}function G(e){const s=e.currentTarget.checked;w(s),a("imageButton",{imageButton:s},R,s?"the composer image button is shown again":"the composer image button is hidden (open a chat to see it)")}return t(Z,null,t("div",{class:"view-head"},t("a",{href:"#/settings",class:"view-back","aria-label":"Back to settings"},"←"),t("h2",{class:"view-title"},"App defaults")),t("div",{class:"group"},t("div",{class:"group__title"},"Chat defaults",t("span",{class:"group__title-note"},"Apply to every project")),t("p",{class:"hint hint--compact"},"How much tool schema and instruction text the model receives. Smaller = less context used, faster replies."),t("p",{class:"hint hint--compact"},"A project or a single chat can pick a different style for itself."),t("ul",{class:"group__list"},t("li",{class:"settings-project__item"},t("div",{class:"settings-project__item-main"},t("label",{class:"settings-project__item-title",for:"sd-prompt-size"},"Default prompt style"),t("div",{class:"settings-project__item-note"},"How much tool schema and instruction text the model receives. Smaller = less context used, faster replies."),t("div",{class:"settings-project__item-status","aria-live":"polite"},B)),t("select",{class:"input settings-project__select",id:"sd-prompt-size",value:r,onChange:D},S.map(e=>t("option",{value:e.value,key:e.value},e.label)))),t("li",{class:"settings-project__item settings-project__item--col"},t("div",{class:"settings-project__item-row"},t("div",{class:"settings-project__item-main"},t("label",{class:"settings-project__item-title",for:"sd-enter-newline"},"Enter inserts a newline instead of sending"),t("div",{class:"settings-project__item-note"},"When on, Enter adds a new line and you send with the send button or Ctrl/Cmd+Enter. Turn it off to send with Enter (Shift+Enter for a new line)."),t("div",{class:"settings-project__item-status","aria-live":"polite"},C)),t("label",{class:"switch"},t("input",{id:"sd-enter-newline",type:"checkbox",role:"switch","aria-checked":String(c),checked:c,onChange:N}),t("span",{class:"switch__track","aria-hidden":"true"},t("span",{class:"switch__thumb"}))))),t("li",{class:"settings-project__item settings-project__item--col"},t("div",{class:"settings-project__item-row"},t("div",{class:"settings-project__item-main"},t("label",{class:"settings-project__item-title",for:"sd-auto-retry"},"Auto-retry failed sends"),t("div",{class:"settings-project__item-note"},"When a message fails before a response starts (network error or HTTP rejection), automatically resend it once. You can still retry any failed message from its inline error card."),t("div",{class:"settings-project__item-status","aria-live":"polite"},O)),t("label",{class:"switch"},t("input",{id:"sd-auto-retry",type:"checkbox",role:"switch","aria-checked":String(d),checked:d,onChange:P}),t("span",{class:"switch__track","aria-hidden":"true"},t("span",{class:"switch__thumb"}))))),t("li",{class:"settings-project__item settings-project__item--col"},t("div",{class:"settings-project__item-row"},t("div",{class:"settings-project__item-main"},t("label",{class:"settings-project__item-title",for:"sd-file-orb"},"Glass orb file button"),t("div",{class:"settings-project__item-note"},"Draws the button beside the message box as a shaded glass orb: the file and git counts sit on a 3D folder that tilts slowly, and the sphere picks up a moving highlight. It opens the same Files / Preview / Git / Cli menu either way, and the tap target is unchanged. Off keeps the flat circle that matches the other composer buttons."),t("div",{class:"settings-project__item-status","aria-live":"polite"},F)),t("label",{class:"switch"},t("input",{id:"sd-file-orb",type:"checkbox",role:"switch","aria-checked":String(g),checked:g,onChange:I}),t("span",{class:"switch__track","aria-hidden":"true"},t("span",{class:"switch__thumb"}))))),t("li",{class:"settings-project__item settings-project__item--col"},t("div",{class:"settings-project__item-row"},t("div",{class:"settings-project__item-main"},t("label",{class:"settings-project__item-title",for:"sd-dictation-button"},"Dictation microphone in the composer"),t("div",{class:"settings-project__item-note"},"Draws the microphone button beside the message box. Turn it off if you never dictate: the composer keeps the button out of the row. Hiding it disables nothing — the dictation page and every other surface still work, and the dictation model you picked is untouched. On by default."),t("div",{class:"settings-project__item-status","aria-live":"polite"},A)),t("label",{class:"switch"},t("input",{id:"sd-dictation-button",type:"checkbox",role:"switch","aria-checked":String(f),checked:f,onChange:H}),t("span",{class:"switch__track","aria-hidden":"true"},t("span",{class:"switch__thumb"}))))),t("li",{class:"settings-project__item settings-project__item--col"},t("div",{class:"settings-project__item-row"},t("div",{class:"settings-project__item-main"},t("label",{class:"settings-project__item-title",for:"sd-image-button"},"Image button in the composer"),t("div",{class:"settings-project__item-note"},"Draws the picture-attachment button beside the message box. Turn it off if you never attach images. Hiding it disables nothing: pasting an image into the composer still attaches it. On by default."),t("div",{class:"settings-project__item-status","aria-live":"polite"},M)),t("label",{class:"switch"},t("input",{id:"sd-image-button",type:"checkbox",role:"switch","aria-checked":String(v),checked:v,onChange:G}),t("span",{class:"switch__track","aria-hidden":"true"},t("span",{class:"switch__thumb"})))))),t("p",{class:"hint hint--compact"},"Chats and messages are stored in the app database. To keep a chat history you can commit, turn on tracing for that chat in project settings — it writes a project-local trace file you can add to source control.")))}export{U as SettingsDefaultsView};
1
+ import{d as i,A as j,h as k,l as W,z as q,B as Y,k as t,S as Z,s as J}from"./index-BDkCsON6.js";const S=[{value:"very-small",label:"Very small — tool names only, no schemas"},{value:"average",label:"Average — full tools, recommended"},{value:"extensive",label:"Extensive — full tools + best-practice guidance"}];function K(r){const n=S.find(c=>c.value===r);return n?n.label.split(" — ")[0].toLowerCase():r||"average"}function U(){const[r,n]=i("average"),[c,h]=i(!0),[d,m]=i(!0),[g,_]=i(!1),[f,b]=i(!0),[v,w]=i(!0),[B,y]=i(""),[C,x]=i(""),[O,T]=i(""),[F,z]=i(""),[A,E]=i(""),[M,R]=i(""),o=j(!0);k(()=>()=>{o.current=!1},[]);const l=j({promptSize:0,enterForNewline:0,autoRetry:0,fileOrbButton:0,dictationButton:0,imageButton:0});k(()=>{(async()=>{try{const e=await W({force:!0});if(!o.current)return;n(e.app&&e.app.promptSize||"average"),h(e.app&&typeof e.app.enterForNewline=="boolean"?e.app.enterForNewline:!0),m(e.app&&typeof e.app.autoRetry=="boolean"?e.app.autoRetry:!0),_(q(e));const s=Y(e);b(s.dictation),w(s.image)}catch(e){o.current&&y("load failed: "+e.message)}})()},[]);async function a(e,s,p,L){const u=(l.current[e]||0)+1;l.current[e]=u,p("saving…");try{if(await J(s),!o.current||l.current[e]!==u)return;p(L)}catch(V){if(!o.current||l.current[e]!==u)return;p("save failed: "+V.message)}}function D(e){const s=e.currentTarget.value;n(s),a("promptSize",{promptSize:s},y,"set to "+K(s))}function N(e){const s=e.currentTarget.checked;h(s),a("enterForNewline",{enterForNewline:s},x,s?"Enter now adds a newline":"Enter now sends")}function P(e){const s=e.currentTarget.checked;m(s),a("autoRetry",{autoRetry:s},T,s?"auto-retry on":"auto-retry off")}function I(e){const s=e.currentTarget.checked;_(s),a("fileOrbButton",{fileOrbButton:s},z,s?"the file button is now a glass orb (open a chat to see it)":"the file button is back to the flat circle")}function H(e){const s=e.currentTarget.checked;b(s),a("dictationButton",{dictationButton:s},E,s?"the composer microphone is shown again":"the composer microphone is hidden (open a chat to see it)")}function G(e){const s=e.currentTarget.checked;w(s),a("imageButton",{imageButton:s},R,s?"the composer image button is shown again":"the composer image button is hidden (open a chat to see it)")}return t(Z,null,t("div",{class:"view-head"},t("a",{href:"#/settings",class:"view-back","aria-label":"Back to settings"},"←"),t("h2",{class:"view-title"},"App defaults")),t("div",{class:"group"},t("div",{class:"group__title"},"Chat defaults",t("span",{class:"group__title-note"},"Apply to every project")),t("p",{class:"hint hint--compact"},"How much tool schema and instruction text the model receives. Smaller = less context used, faster replies."),t("p",{class:"hint hint--compact"},"A project or a single chat can pick a different style for itself."),t("ul",{class:"group__list"},t("li",{class:"settings-project__item"},t("div",{class:"settings-project__item-main"},t("label",{class:"settings-project__item-title",for:"sd-prompt-size"},"Default prompt style"),t("div",{class:"settings-project__item-note"},"How much tool schema and instruction text the model receives. Smaller = less context used, faster replies."),t("div",{class:"settings-project__item-status","aria-live":"polite"},B)),t("select",{class:"input settings-project__select",id:"sd-prompt-size",value:r,onChange:D},S.map(e=>t("option",{value:e.value,key:e.value},e.label)))),t("li",{class:"settings-project__item settings-project__item--col"},t("div",{class:"settings-project__item-row"},t("div",{class:"settings-project__item-main"},t("label",{class:"settings-project__item-title",for:"sd-enter-newline"},"Enter inserts a newline instead of sending"),t("div",{class:"settings-project__item-note"},"When on, Enter adds a new line and you send with the send button or Ctrl/Cmd+Enter. Turn it off to send with Enter (Shift+Enter for a new line)."),t("div",{class:"settings-project__item-status","aria-live":"polite"},C)),t("label",{class:"switch"},t("input",{id:"sd-enter-newline",type:"checkbox",role:"switch","aria-checked":String(c),checked:c,onChange:N}),t("span",{class:"switch__track","aria-hidden":"true"},t("span",{class:"switch__thumb"}))))),t("li",{class:"settings-project__item settings-project__item--col"},t("div",{class:"settings-project__item-row"},t("div",{class:"settings-project__item-main"},t("label",{class:"settings-project__item-title",for:"sd-auto-retry"},"Auto-retry failed sends"),t("div",{class:"settings-project__item-note"},"When a message fails before a response starts (network error or HTTP rejection), automatically resend it once. You can still retry any failed message from its inline error card."),t("div",{class:"settings-project__item-status","aria-live":"polite"},O)),t("label",{class:"switch"},t("input",{id:"sd-auto-retry",type:"checkbox",role:"switch","aria-checked":String(d),checked:d,onChange:P}),t("span",{class:"switch__track","aria-hidden":"true"},t("span",{class:"switch__thumb"}))))),t("li",{class:"settings-project__item settings-project__item--col"},t("div",{class:"settings-project__item-row"},t("div",{class:"settings-project__item-main"},t("label",{class:"settings-project__item-title",for:"sd-file-orb"},"Glass orb file button"),t("div",{class:"settings-project__item-note"},"Draws the button beside the message box as a shaded glass orb: the file and git counts sit on a 3D folder that tilts slowly, and the sphere picks up a moving highlight. It opens the same Files / Preview / Git / Cli menu either way, and the tap target is unchanged. Off keeps the flat circle that matches the other composer buttons."),t("div",{class:"settings-project__item-status","aria-live":"polite"},F)),t("label",{class:"switch"},t("input",{id:"sd-file-orb",type:"checkbox",role:"switch","aria-checked":String(g),checked:g,onChange:I}),t("span",{class:"switch__track","aria-hidden":"true"},t("span",{class:"switch__thumb"}))))),t("li",{class:"settings-project__item settings-project__item--col"},t("div",{class:"settings-project__item-row"},t("div",{class:"settings-project__item-main"},t("label",{class:"settings-project__item-title",for:"sd-dictation-button"},"Dictation microphone in the composer"),t("div",{class:"settings-project__item-note"},"Draws the microphone button beside the message box. Turn it off if you never dictate: the composer keeps the button out of the row. Hiding it disables nothing — the dictation page and every other surface still work, and the dictation model you picked is untouched. On by default."),t("div",{class:"settings-project__item-status","aria-live":"polite"},A)),t("label",{class:"switch"},t("input",{id:"sd-dictation-button",type:"checkbox",role:"switch","aria-checked":String(f),checked:f,onChange:H}),t("span",{class:"switch__track","aria-hidden":"true"},t("span",{class:"switch__thumb"}))))),t("li",{class:"settings-project__item settings-project__item--col"},t("div",{class:"settings-project__item-row"},t("div",{class:"settings-project__item-main"},t("label",{class:"settings-project__item-title",for:"sd-image-button"},"Image button in the composer"),t("div",{class:"settings-project__item-note"},"Draws the picture-attachment button beside the message box. Turn it off if you never attach images. Hiding it disables nothing: pasting an image into the composer still attaches it. On by default."),t("div",{class:"settings-project__item-status","aria-live":"polite"},M)),t("label",{class:"switch"},t("input",{id:"sd-image-button",type:"checkbox",role:"switch","aria-checked":String(v),checked:v,onChange:G}),t("span",{class:"switch__track","aria-hidden":"true"},t("span",{class:"switch__thumb"})))))),t("p",{class:"hint hint--compact"},"Chats and messages are stored in the app database. To keep a chat history you can commit, turn on tracing for that chat in project settings — it writes a project-local trace file you can add to source control.")))}export{U as SettingsDefaultsView};
@@ -1 +1 @@
1
- import{d as S,A as D,h as I,f as K,k as n,S as W,b as _e,n as ee}from"./index-BGvI4n0T.js";import{A as Ce}from"./AgentFilePicker-CcKLJorU.js";import{S as Q,x as te,b as G,D as Y,y as ve,a as ne,o as we,l as Se,f as Le,h as Ae,s as ke,g as xe,G as je,z as Me,A as Ee,B as Ne,C as De,F as Re,v as re}from"./codemirror-Bp6CUUFk.js";function J(s){const e=s.map(({start:t,end:o})=>{const a=Number(t),b=Number(o);if(String(t).trim()===""||String(o).trim()===""||!Number.isSafeInteger(a)||!Number.isSafeInteger(b)||a<1||b<a)throw new Error("Enter whole line numbers: From must be at least 1, and To must not be before From.");return{start:a,end:b}}).sort((t,o)=>t.start-o.start),r=[];for(const t of e){const o=r[r.length-1];o&&t.start<=o.end+1?o.end=Math.max(o.end,t.end):r.push({...t})}return r}function ce(s,e){return s.some(({start:r,end:t})=>e>=r&&e<=t)}function $e(s,e){const r=J(s);return ce(r,e)?r.flatMap(t=>{if(e<t.start||e>t.end)return[t];const o=[];return t.start<e&&o.push({start:t.start,end:e-1}),e<t.end&&o.push({start:e+1,end:t.end}),o}):J([...r,{start:e,end:e}])}function He(s){return s.length?"Lines "+s.map(({start:e,end:r})=>e===r?e:`${e}–${r}`).join(", "):"No lines selected"}function le(s){if(!s||typeof s!="object")return!1;const{startLine:e,endLine:r,startCol:t,endCol:o}=s;return!(!Number.isInteger(e)||!Number.isInteger(r)||e<1||r<e||!Number.isInteger(t)||!Number.isInteger(o)||t<1||o<1||e===r&&o<t)}function P(s){const e=(Array.isArray(s)?s:[]).filter(le);if(!e.length)return[];const r=[];for(const t of e)if(!r.some(a=>a.startLine<=t.startLine&&a.endLine>=t.endLine&&(a.startLine!==a.endLine||a.startCol<=t.startCol&&a.endCol>=t.endCol))){if(t.startLine===t.endLine){const a=r.find(b=>b.startLine===t.startLine&&b.endLine===t.endLine);if(a){a.startCol=Math.min(a.startCol,t.startCol),a.endCol=Math.max(a.endCol,t.endCol);continue}}r.push({...t})}return r}function Oe(s,e){const r=P(s);return r.some(o=>o.startLine===e.startLine&&o.endLine===e.endLine&&o.startCol===e.startCol&&o.endCol===e.endCol)?r.filter(o=>!(o.startLine===e.startLine&&o.endLine===e.endLine&&o.startCol===e.startCol&&o.endCol===e.endCol)):P([...r,e])}function Te({startLine:s,endLine:e,startCol:r,endCol:t}){const o=s===e?`line ${s}`:`lines ${s}–${e}`,a=s===e?`, cols ${r}–${t}`:"";return`${o}${a}`}function de({ranges:s=[],chars:e=[]}={}){const r=Array.isArray(s)?s:[],t=P(e),o=[];return r.length&&o.push(He(r)),t.length&&o.push("Text on "+t.map(Te).join("; ")),o.join(" · ")||"Nothing hidden"}function se({projectDir:s="",from:e="",filePath:r=""}={}){const t=new URLSearchParams({projectDir:s});return e&&t.set("from",e),r&&t.set("file",r),"settings/project/hide?"+t.toString()}const U=new Map;function oe(s){if(!s)return null;const e=s.toLowerCase(),r=e.split("/").pop()||e;if(r==="dockerfile")return null;const t=(r.match(/\.[a-z0-9]+$/)||[""])[0];switch(t){case".js":case".jsx":case".mjs":case".cjs":return re({jsx:t===".jsx"});case".ts":case".tsx":return re({jsx:t===".tsx",typescript:!0});case".html":case".htm":case".svg":case".xml":case".mdx":return Re();case".css":case".scss":case".sass":case".less":return De();case".json":return Ne();case".md":case".markdown":return Ee();case".py":return Me();default:return null}}function ue(s,e,r){const t=Math.max(0,Math.min(e,r)),o=Math.min(s.length,Math.max(e,r));if(o<=t)return null;const a=s.lineAt(t),b=s.lineAt(o);return{startLine:a.number,endLine:b.number,startCol:t-a.from+1,endCol:o-b.from+1}}function ie(s){const e=s.state.selection.main;if(e.empty)return{hasSelection:!1,span:null};const r=ue(s.state.doc,e.from,e.to);return r?{hasSelection:!0,span:r}:{hasSelection:!1,span:null}}function ae(s){if(!s.root||typeof s.root.getSelection!="function")return null;const e=s.root.getSelection();if(!e||e.isCollapsed||!e.rangeCount)return null;const r=e.getRangeAt(0);if(!s.contentDOM.contains(r.startContainer)||!s.contentDOM.contains(r.endContainer))return null;try{return ue(s.state.doc,s.posAtDOM(r.startContainer,r.startOffset),s.posAtDOM(r.endContainer,r.endOffset))}catch{return null}}function Fe(s,e,r,t,o,a,b){const A=Q.define(),M=Q.define(),g=te.define({create:()=>r,update(f,l){for(const d of l.effects)if(d.is(A))return d.value;return f}}),j=te.define({create:()=>t,update(f,l){for(const d of l.effects)if(d.is(M))return d.value;return f}});class m extends je{constructor(l){super(),this.selected=l}eq(l){return l instanceof m&&l.selected===this.selected}toDOM(){const l=document.createElement("span");return l.className="hc__toggle-marker",l.textContent=this.selected?"✓":"+",l.setAttribute("aria-hidden","true"),l}}const z=G.decorations.compute([g],f=>{const l=[],d=f.doc.lines;for(const{start:v,end:w}of f.field(g)){if(!Number.isSafeInteger(v)||!Number.isSafeInteger(w)||v<1||w<v)continue;const L=v,c=Math.min(w,d);for(let h=L;h<=c;h++)l.push(Y.line({class:"hc__line-hidden"}).range(f.doc.line(h).from))}return Y.set(l,!0)}),T=G.decorations.compute([j],f=>{const l=[];for(const d of f.field(j)){if(!le(d))continue;const v=f.doc,w=Math.max(1,d.startLine),L=Math.min(v.lines,d.endLine);if(!(w>L))for(let c=w;c<=L;c++){const h=v.line(c);let p,_;d.startLine===d.endLine?(p=Math.min(d.startCol-1,h.length),_=Math.min(d.endCol,h.length)):c===d.startLine?(p=Math.min(d.startCol-1,h.length),_=h.length):c===d.endLine?(p=0,_=Math.min(d.endCol,h.length)):(p=0,_=h.length),!(_<=p)&&l.push(Y.mark({class:"hc__char-hidden"}).range(h.from+p,h.from+_))}}return Y.set(l,!0)}),F=ve({class:"hc__toggle",lineMarker(f,l){const d=f.state.doc.lineAt(l.from).number;return new m(ce(f.state.field(g),d))},lineMarkerChange(f){return f.docChanged||f.transactions.some(l=>l.effects.some(d=>d.is(A)))},domEventHandlers:{click(f,l){const d=f.state.doc.lineAt(l.from).number,v=$e(f.state.field(g),d);return f.dispatch({effects:A.of(v)}),o(v),!0}}}),k=ne.create({doc:s,extensions:[g,j,Se(),Le(),Ae(),F,z,T,ke(xe),ne.readOnly.of(!0),G.lineWrapping,...oe(e)?[oe(e)]:[],we]}),y=new G({state:k,parent:b});function E(){const f=ae(y)||ie(y).span;a(f?{hasSelection:!0,span:f}:{hasSelection:!1,span:null})}y.dispatch({effects:Q.appendConfig.of(G.updateListener.of(f=>{(f.selectionSet||f.docChanged)&&E()}))});const R=y.dom.ownerDocument;return R.addEventListener("selectionchange",E),requestAnimationFrame(()=>{y.dom.isConnected&&y.requestMeasure()}),E(),{view:y,setHidden:A,setChars:M,hiddenRangesField:g,hiddenCharsField:j,selectionSpan:()=>ae(y)||ie(y).span,destroy(){R.removeEventListener("selectionchange",E),y.destroy()}}}function Ie({projectDir:s,filePath:e,initialRule:r,onSave:t,onClose:o}){const a=JSON.stringify([s,e]),b=r&&Array.isArray(r.ranges)?r.ranges.map(i=>({...i})):[],A=r&&Array.isArray(r.chars)?r.chars.map(i=>({...i})):[],M=U.get(a),[g,j]=S(()=>M?M.ranges||[]:b),[m,z]=S(()=>M?M.chars||[]:A),[T,F]=S({hasSelection:!1,span:null}),[k,y]=S({loading:!0,content:null,error:""}),[E,R]=S(0),[f,l]=S(""),[d,v]=S(!1),w=D(!1),L=D(!0),c=D(null),h=D(null),p=D(null),_=D(null),$=D(0),x=JSON.stringify(g)!==JSON.stringify(b)||JSON.stringify(m)!==JSON.stringify(A);let H=[],B="";try{H=J(g)}catch(i){B=i.message}const V=H.reduce((i,u)=>i+u.end-u.start+1,0),q=P(m).length,fe=(V?`${V} ${V===1?"line":"lines"}`:"")+(V&&q?", ":"")+(q?`${q} ${q===1?"text span":"text spans"}`:"")||"Nothing hidden";I(()=>(L.current=!0,c.current?.focus(),()=>{L.current=!1}),[]),I(()=>{x?U.set(a,{ranges:g,chars:m}):U.delete(a)},[a,g,m,x]),I(()=>{if(!x)return;function i(u){u.preventDefault(),u.returnValue=""}return window.addEventListener("beforeunload",i),()=>window.removeEventListener("beforeunload",i)},[x]),I(()=>{const i=new AbortController;return y({loading:!0,content:null,error:""}),K("/api/file?"+new URLSearchParams({projectDir:s,path:e}),{signal:i.signal}).then(u=>{if(!i.signal.aborted){if(u.status!==200||typeof u.body.content!="string")throw new Error(u.body?.code==="ETOOLARGE"?"File exceeds the 1 MiB preview limit.":"Could not preview this file. It may be missing or unreadable.");y({loading:!1,content:u.body.content,error:""})}}).catch(u=>{i.signal.aborted||y({loading:!1,content:null,error:u.message})}),()=>i.abort()},[s,e,E]),I(()=>{if(!h.current||k.content===null)return;p.current&&(p.current.destroy(),p.current=null);let i=[];try{i=J(g)}catch{i=[]}const u=Fe(k.content,e,i,m,C=>{l(""),j(C)},C=>F(C),h.current);return p.current=u,()=>{p.current&&(p.current.destroy(),p.current=null)}},[k.content]),I(()=>{const i=p.current;if(!i)return;let u=[];try{u=J(g)}catch{u=[]}i.view.dispatch({effects:[i.setHidden.of(u),i.setChars.of(P(m))]})},[g,m]);function X(){return(p.current?p.current.selectionSpan():null)||(T.hasSelection?T.span:null)}function Z(i){return i?(l(""),z(Oe(m,i)),!0):!1}function he(i){if(i&&i.button>0)return;const u=X();_.current=u,Z(u)&&($.current=Date.now())}function pe(){if($.current&&Date.now()-$.current<1e3){$.current=0;return}$.current=0,Z(X()||_.current)}function ge(i,u,C){l(""),j(g.map((O,N)=>N===i?{...O,[u]:C}:O))}function me(){w.current||o()}function be(){w.current||x&&!window.confirm("Discard your unsaved line selection?")||(U.delete(a),o())}async function ye(i){if(i.preventDefault(),w.current)return;let u;try{u=J(g)}catch(N){l(N.message);return}const C=u.length||P(m).length,O=b.length||A.length;if(!(!C&&O&&!window.confirm("Stop hiding content in this file?"))){w.current=!0,v(!0),l("");try{await t(e,{ranges:u,chars:P(m)});const N=U.get(a);N&&N.ranges===g&&N.chars===m&&U.delete(a),L.current&&o()}catch(N){L.current&&l((N.message||"Could not save.")+" Your selection is kept; you can retry.")}finally{w.current=!1,L.current&&v(!1)}}}return n(W,null,n("div",{class:"view-head hidden-content__head"},n("button",{class:"view-back",type:"button",disabled:d,onClick:me,"aria-label":"Back to hidden files"},"←"),n("h2",{class:"view-title",tabIndex:-1,ref:c},"Select hidden content")),n("form",{class:"hidden-content",onSubmit:ye,noValidate:!0},n("p",{class:"hidden-content__path"},e),n("p",{class:"hidden-content__intro"},"Tap a line number in the left gutter to hide the whole line, or drag to select text and hide just that span. Either way, the redacted text is replaced with [hidden] for the agent file tools."),n("p",{class:"hidden-content__scope"},"Only read_file and search_files are filtered—not shell, MCP, or other access. This preview shows the original file to you; saving does not edit it."),n("fieldset",{class:"hidden-content__fields",disabled:d},n("legend",{class:"hidden-content__sr-only"},"Hidden content selection"),k.loading?n("p",{role:"status"},"Loading file preview…"):k.error?n("div",{class:"hidden-content__preview-error"},n("p",{role:"alert"},k.error+" You can still edit ranges manually."),n("button",{class:"btn",type:"button",onClick:()=>R(i=>i+1)},"Retry preview")):n(W,null,n("div",{class:"hidden-content__editor",ref:h,role:"region","aria-label":"Numbered file content","aria-describedby":"hidden-content-editor-help"}),n("div",{class:"hidden-content__toolbar"},n("p",{id:"hidden-content-editor-help",class:"hidden-content__muted"},"Tap a line in the gutter to hide or show it, or drag to select text and tap Hide selected text in the footer. The file is read-only."))),n("details",{class:"hidden-content__manual",open:!!k.error},n("summary",null,"Enter line ranges manually"),n("p",{class:"hidden-content__muted"},"From and To are inclusive. Use the same number to hide one line."),g.map((i,u)=>n("div",{class:"hidden-content__range",key:u},...["start","end"].map(C=>n("label",{key:C},C==="start"?"From":"To",n("input",{class:"input",type:"number",min:1,step:1,"aria-label":`${C==="start"?"From":"To"} line for range ${u+1}`,value:i[C],onInput:O=>ge(u,C,O.target.value)}))),n("button",{class:"btn",type:"button","aria-label":`Remove range ${u+1}`,onClick:()=>{l(""),j(g.filter((C,O)=>O!==u))}},"×"))),n("button",{class:"btn",type:"button",onClick:()=>{const i=H.length?H[H.length-1].end+1:1;j([...g,{start:i,end:i}])}},"+ Add range")),B&&n("p",{class:"hidden-content__error",role:"alert"},B)),n("footer",{class:"hidden-content__footer"},n("div",{class:"hidden-content__selection",role:"status"},n("strong",null,fe),n("span",{class:"hidden-content__muted"},B?"Fix the range values to continue.":V||q?de({ranges:H,chars:m}):"Tap a line number, or select text and tap Hide selected text."),x&&n("span",{class:"hidden-content__muted"},"Unsaved selection")),f&&n("p",{class:"hidden-content__error",role:"alert"},f),n("div",{class:"hidden-content__actions"},n("button",{class:"btn hidden-content__hide-action",type:"button",disabled:d||!T.hasSelection,onPointerDown:he,onClick:pe,"aria-label":"Hide selected text","aria-describedby":"hidden-content-editor-help"},"Hide selected text"),n("button",{class:"btn",type:"button",disabled:d,onClick:be},"Cancel"),n("button",{class:"btn btn--primary",type:"submit",disabled:d||!!B||!x&&!b.length},d?"Saving…":"Save")))))}function ze({projectDir:s="",from:e="",filePath:r=""}){const t=s||_e.value?.dir||"",[o,a]=S(null),[b,A]=S(""),[M,g]=S(""),[j,m]=S(!1),[z,T]=S(0),[F,k]=S(""),[y,E]=S(""),R=D(null),f=D(null);I(()=>{const c=new AbortController;if(a(null),A(""),!t){A("Open this page from a project’s settings.");return}return K("/api/settings/hide-file-content?"+new URLSearchParams({projectDir:t}),{signal:c.signal}).then(h=>{if(!c.signal.aborted){if(h.status!==200||!Array.isArray(h.body.rules))throw new Error("Could not load hidden files.");a(h.body.rules)}}).catch(h=>{c.signal.aborted||A(h.message)}),()=>c.abort()},[t,z]);function l(c){m(!1),g(""),ee(se({projectDir:t,from:e,filePath:c}))}function d(){ee(se({projectDir:t,from:e}))}async function v(c,{ranges:h,chars:p}){const _=o.filter(H=>H.path!==c),$=h.length||p.length;$&&_.push({path:c,ranges:h,chars:p});const x=await K("/api/settings/hide-file-content",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:t,rules:_})});if(x.status!==200||!Array.isArray(x.body.rules))throw new Error(`Could not save (HTTP ${x.status}).`);a(x.body.rules),g($?"Hidden content saved.":"File is no longer hidden.")}async function w(c,h){if(!F&&window.confirm(`Stop hiding content in ${c}?`)){E(""),g(""),k(c);try{const p=await K("/api/settings/hide-file-content",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:t,rules:o.filter(_=>_.path!==c)})});if(p.status!==200||!Array.isArray(p.body.rules))throw new Error(`Could not remove it (HTTP ${p.status}).`);a(p.body.rules),g(`${c} is no longer hidden.`),requestAnimationFrame(()=>{const _=R.current?R.current.querySelectorAll(".hidden-content__remove"):[];(_[Math.min(h,_.length-1)]||f.current)?.focus()})}catch(p){E((p.message||"Could not remove it.")+" Nothing changed; the file is still hidden.")}finally{k("")}}}if(r&&o)return n(Ie,{key:t+"|"+r,projectDir:t,filePath:r,initialRule:o.find(c=>c.path===r),onSave:v,onClose:d});const L=new URLSearchParams({projectDir:t});return e&&L.set("from",e),n(W,null,n("div",{class:"view-head hidden-content__head"},n("a",{class:"view-back",href:"#/settings/project?"+L,"aria-label":"Back to project settings"},"←"),n("h2",{class:"view-title"},"Hide file content")),n("section",{class:"hidden-content","aria-label":"Hidden files"},n("p",{class:"hidden-content__intro"},"Choose a file, then tap the line numbers you want hidden from the agent file tools, or select text and hide just that span. Your file stays unchanged."),n("p",{class:"hidden-content__scope"},n("strong",null,"Not a security boundary. "),"Only ",n("code",null,"read_file")," and ",n("code",null,"search_files")," are filtered. Shell, MCP, and other access can still read the original content."),b?n("div",{role:"alert"},n("p",null,b),t&&n("button",{class:"btn",onClick:()=>T(c=>c+1)},"Retry")):o===null?n("p",{role:"status"},"Loading hidden files…"):n(W,null,o.length?n("ul",{class:"hidden-content__files",ref:R},o.map((c,h)=>n("li",{key:c.path,class:"hidden-content__row"},n("button",{class:"hidden-content__file",type:"button",onClick:()=>l(c.path)},n("span",{class:"hidden-content__file-main"},n("span",{class:"hidden-content__path"},c.path),n("span",{class:"hidden-content__muted"},de(c))),n("span",{"aria-hidden":"true"},"›")),n("button",{class:"hidden-content__remove",type:"button",disabled:!!F,"aria-label":`Stop hiding content in ${c.path}`,onClick:()=>w(c.path,h)},F===c.path?"Removing…":"Remove")))):n("p",{class:"hidden-content__empty"},"Nothing hidden yet. Add a file to hide whole lines or selected text."),n("button",{class:"btn btn--primary",ref:f,onClick:()=>m(!0)},"+ Add file"),y&&n("p",{class:"hidden-content__error",role:"alert"},y),n("p",{role:"status",class:"hidden-content__notice"},M)),j&&n(Ce,{projectDir:t,onPick:l,onClose:()=>m(!1),label:"Choose a file to hide lines",description:"Choose a file to preview its contents and select hidden lines."})))}export{ze as SettingsHiddenContentView};
1
+ import{d as S,A as D,h as I,f as K,k as n,S as W,b as _e,n as ee}from"./index-BDkCsON6.js";import{A as Ce}from"./AgentFilePicker-ZW6vm5Hy.js";import{S as Q,x as te,b as G,D as Y,y as ve,a as ne,o as we,l as Se,f as Le,h as Ae,s as ke,g as xe,G as je,z as Me,A as Ee,B as Ne,C as De,F as Re,v as re}from"./codemirror-Bp6CUUFk.js";function J(s){const e=s.map(({start:t,end:o})=>{const a=Number(t),b=Number(o);if(String(t).trim()===""||String(o).trim()===""||!Number.isSafeInteger(a)||!Number.isSafeInteger(b)||a<1||b<a)throw new Error("Enter whole line numbers: From must be at least 1, and To must not be before From.");return{start:a,end:b}}).sort((t,o)=>t.start-o.start),r=[];for(const t of e){const o=r[r.length-1];o&&t.start<=o.end+1?o.end=Math.max(o.end,t.end):r.push({...t})}return r}function ce(s,e){return s.some(({start:r,end:t})=>e>=r&&e<=t)}function $e(s,e){const r=J(s);return ce(r,e)?r.flatMap(t=>{if(e<t.start||e>t.end)return[t];const o=[];return t.start<e&&o.push({start:t.start,end:e-1}),e<t.end&&o.push({start:e+1,end:t.end}),o}):J([...r,{start:e,end:e}])}function He(s){return s.length?"Lines "+s.map(({start:e,end:r})=>e===r?e:`${e}–${r}`).join(", "):"No lines selected"}function le(s){if(!s||typeof s!="object")return!1;const{startLine:e,endLine:r,startCol:t,endCol:o}=s;return!(!Number.isInteger(e)||!Number.isInteger(r)||e<1||r<e||!Number.isInteger(t)||!Number.isInteger(o)||t<1||o<1||e===r&&o<t)}function P(s){const e=(Array.isArray(s)?s:[]).filter(le);if(!e.length)return[];const r=[];for(const t of e)if(!r.some(a=>a.startLine<=t.startLine&&a.endLine>=t.endLine&&(a.startLine!==a.endLine||a.startCol<=t.startCol&&a.endCol>=t.endCol))){if(t.startLine===t.endLine){const a=r.find(b=>b.startLine===t.startLine&&b.endLine===t.endLine);if(a){a.startCol=Math.min(a.startCol,t.startCol),a.endCol=Math.max(a.endCol,t.endCol);continue}}r.push({...t})}return r}function Oe(s,e){const r=P(s);return r.some(o=>o.startLine===e.startLine&&o.endLine===e.endLine&&o.startCol===e.startCol&&o.endCol===e.endCol)?r.filter(o=>!(o.startLine===e.startLine&&o.endLine===e.endLine&&o.startCol===e.startCol&&o.endCol===e.endCol)):P([...r,e])}function Te({startLine:s,endLine:e,startCol:r,endCol:t}){const o=s===e?`line ${s}`:`lines ${s}–${e}`,a=s===e?`, cols ${r}–${t}`:"";return`${o}${a}`}function de({ranges:s=[],chars:e=[]}={}){const r=Array.isArray(s)?s:[],t=P(e),o=[];return r.length&&o.push(He(r)),t.length&&o.push("Text on "+t.map(Te).join("; ")),o.join(" · ")||"Nothing hidden"}function se({projectDir:s="",from:e="",filePath:r=""}={}){const t=new URLSearchParams({projectDir:s});return e&&t.set("from",e),r&&t.set("file",r),"settings/project/hide?"+t.toString()}const U=new Map;function oe(s){if(!s)return null;const e=s.toLowerCase(),r=e.split("/").pop()||e;if(r==="dockerfile")return null;const t=(r.match(/\.[a-z0-9]+$/)||[""])[0];switch(t){case".js":case".jsx":case".mjs":case".cjs":return re({jsx:t===".jsx"});case".ts":case".tsx":return re({jsx:t===".tsx",typescript:!0});case".html":case".htm":case".svg":case".xml":case".mdx":return Re();case".css":case".scss":case".sass":case".less":return De();case".json":return Ne();case".md":case".markdown":return Ee();case".py":return Me();default:return null}}function ue(s,e,r){const t=Math.max(0,Math.min(e,r)),o=Math.min(s.length,Math.max(e,r));if(o<=t)return null;const a=s.lineAt(t),b=s.lineAt(o);return{startLine:a.number,endLine:b.number,startCol:t-a.from+1,endCol:o-b.from+1}}function ie(s){const e=s.state.selection.main;if(e.empty)return{hasSelection:!1,span:null};const r=ue(s.state.doc,e.from,e.to);return r?{hasSelection:!0,span:r}:{hasSelection:!1,span:null}}function ae(s){if(!s.root||typeof s.root.getSelection!="function")return null;const e=s.root.getSelection();if(!e||e.isCollapsed||!e.rangeCount)return null;const r=e.getRangeAt(0);if(!s.contentDOM.contains(r.startContainer)||!s.contentDOM.contains(r.endContainer))return null;try{return ue(s.state.doc,s.posAtDOM(r.startContainer,r.startOffset),s.posAtDOM(r.endContainer,r.endOffset))}catch{return null}}function Fe(s,e,r,t,o,a,b){const A=Q.define(),M=Q.define(),g=te.define({create:()=>r,update(f,l){for(const d of l.effects)if(d.is(A))return d.value;return f}}),j=te.define({create:()=>t,update(f,l){for(const d of l.effects)if(d.is(M))return d.value;return f}});class m extends je{constructor(l){super(),this.selected=l}eq(l){return l instanceof m&&l.selected===this.selected}toDOM(){const l=document.createElement("span");return l.className="hc__toggle-marker",l.textContent=this.selected?"✓":"+",l.setAttribute("aria-hidden","true"),l}}const z=G.decorations.compute([g],f=>{const l=[],d=f.doc.lines;for(const{start:v,end:w}of f.field(g)){if(!Number.isSafeInteger(v)||!Number.isSafeInteger(w)||v<1||w<v)continue;const L=v,c=Math.min(w,d);for(let h=L;h<=c;h++)l.push(Y.line({class:"hc__line-hidden"}).range(f.doc.line(h).from))}return Y.set(l,!0)}),T=G.decorations.compute([j],f=>{const l=[];for(const d of f.field(j)){if(!le(d))continue;const v=f.doc,w=Math.max(1,d.startLine),L=Math.min(v.lines,d.endLine);if(!(w>L))for(let c=w;c<=L;c++){const h=v.line(c);let p,_;d.startLine===d.endLine?(p=Math.min(d.startCol-1,h.length),_=Math.min(d.endCol,h.length)):c===d.startLine?(p=Math.min(d.startCol-1,h.length),_=h.length):c===d.endLine?(p=0,_=Math.min(d.endCol,h.length)):(p=0,_=h.length),!(_<=p)&&l.push(Y.mark({class:"hc__char-hidden"}).range(h.from+p,h.from+_))}}return Y.set(l,!0)}),F=ve({class:"hc__toggle",lineMarker(f,l){const d=f.state.doc.lineAt(l.from).number;return new m(ce(f.state.field(g),d))},lineMarkerChange(f){return f.docChanged||f.transactions.some(l=>l.effects.some(d=>d.is(A)))},domEventHandlers:{click(f,l){const d=f.state.doc.lineAt(l.from).number,v=$e(f.state.field(g),d);return f.dispatch({effects:A.of(v)}),o(v),!0}}}),k=ne.create({doc:s,extensions:[g,j,Se(),Le(),Ae(),F,z,T,ke(xe),ne.readOnly.of(!0),G.lineWrapping,...oe(e)?[oe(e)]:[],we]}),y=new G({state:k,parent:b});function E(){const f=ae(y)||ie(y).span;a(f?{hasSelection:!0,span:f}:{hasSelection:!1,span:null})}y.dispatch({effects:Q.appendConfig.of(G.updateListener.of(f=>{(f.selectionSet||f.docChanged)&&E()}))});const R=y.dom.ownerDocument;return R.addEventListener("selectionchange",E),requestAnimationFrame(()=>{y.dom.isConnected&&y.requestMeasure()}),E(),{view:y,setHidden:A,setChars:M,hiddenRangesField:g,hiddenCharsField:j,selectionSpan:()=>ae(y)||ie(y).span,destroy(){R.removeEventListener("selectionchange",E),y.destroy()}}}function Ie({projectDir:s,filePath:e,initialRule:r,onSave:t,onClose:o}){const a=JSON.stringify([s,e]),b=r&&Array.isArray(r.ranges)?r.ranges.map(i=>({...i})):[],A=r&&Array.isArray(r.chars)?r.chars.map(i=>({...i})):[],M=U.get(a),[g,j]=S(()=>M?M.ranges||[]:b),[m,z]=S(()=>M?M.chars||[]:A),[T,F]=S({hasSelection:!1,span:null}),[k,y]=S({loading:!0,content:null,error:""}),[E,R]=S(0),[f,l]=S(""),[d,v]=S(!1),w=D(!1),L=D(!0),c=D(null),h=D(null),p=D(null),_=D(null),$=D(0),x=JSON.stringify(g)!==JSON.stringify(b)||JSON.stringify(m)!==JSON.stringify(A);let H=[],B="";try{H=J(g)}catch(i){B=i.message}const V=H.reduce((i,u)=>i+u.end-u.start+1,0),q=P(m).length,fe=(V?`${V} ${V===1?"line":"lines"}`:"")+(V&&q?", ":"")+(q?`${q} ${q===1?"text span":"text spans"}`:"")||"Nothing hidden";I(()=>(L.current=!0,c.current?.focus(),()=>{L.current=!1}),[]),I(()=>{x?U.set(a,{ranges:g,chars:m}):U.delete(a)},[a,g,m,x]),I(()=>{if(!x)return;function i(u){u.preventDefault(),u.returnValue=""}return window.addEventListener("beforeunload",i),()=>window.removeEventListener("beforeunload",i)},[x]),I(()=>{const i=new AbortController;return y({loading:!0,content:null,error:""}),K("/api/file?"+new URLSearchParams({projectDir:s,path:e}),{signal:i.signal}).then(u=>{if(!i.signal.aborted){if(u.status!==200||typeof u.body.content!="string")throw new Error(u.body?.code==="ETOOLARGE"?"File exceeds the 1 MiB preview limit.":"Could not preview this file. It may be missing or unreadable.");y({loading:!1,content:u.body.content,error:""})}}).catch(u=>{i.signal.aborted||y({loading:!1,content:null,error:u.message})}),()=>i.abort()},[s,e,E]),I(()=>{if(!h.current||k.content===null)return;p.current&&(p.current.destroy(),p.current=null);let i=[];try{i=J(g)}catch{i=[]}const u=Fe(k.content,e,i,m,C=>{l(""),j(C)},C=>F(C),h.current);return p.current=u,()=>{p.current&&(p.current.destroy(),p.current=null)}},[k.content]),I(()=>{const i=p.current;if(!i)return;let u=[];try{u=J(g)}catch{u=[]}i.view.dispatch({effects:[i.setHidden.of(u),i.setChars.of(P(m))]})},[g,m]);function X(){return(p.current?p.current.selectionSpan():null)||(T.hasSelection?T.span:null)}function Z(i){return i?(l(""),z(Oe(m,i)),!0):!1}function he(i){if(i&&i.button>0)return;const u=X();_.current=u,Z(u)&&($.current=Date.now())}function pe(){if($.current&&Date.now()-$.current<1e3){$.current=0;return}$.current=0,Z(X()||_.current)}function ge(i,u,C){l(""),j(g.map((O,N)=>N===i?{...O,[u]:C}:O))}function me(){w.current||o()}function be(){w.current||x&&!window.confirm("Discard your unsaved line selection?")||(U.delete(a),o())}async function ye(i){if(i.preventDefault(),w.current)return;let u;try{u=J(g)}catch(N){l(N.message);return}const C=u.length||P(m).length,O=b.length||A.length;if(!(!C&&O&&!window.confirm("Stop hiding content in this file?"))){w.current=!0,v(!0),l("");try{await t(e,{ranges:u,chars:P(m)});const N=U.get(a);N&&N.ranges===g&&N.chars===m&&U.delete(a),L.current&&o()}catch(N){L.current&&l((N.message||"Could not save.")+" Your selection is kept; you can retry.")}finally{w.current=!1,L.current&&v(!1)}}}return n(W,null,n("div",{class:"view-head hidden-content__head"},n("button",{class:"view-back",type:"button",disabled:d,onClick:me,"aria-label":"Back to hidden files"},"←"),n("h2",{class:"view-title",tabIndex:-1,ref:c},"Select hidden content")),n("form",{class:"hidden-content",onSubmit:ye,noValidate:!0},n("p",{class:"hidden-content__path"},e),n("p",{class:"hidden-content__intro"},"Tap a line number in the left gutter to hide the whole line, or drag to select text and hide just that span. Either way, the redacted text is replaced with [hidden] for the agent file tools."),n("p",{class:"hidden-content__scope"},"Only read_file and search_files are filtered—not shell, MCP, or other access. This preview shows the original file to you; saving does not edit it."),n("fieldset",{class:"hidden-content__fields",disabled:d},n("legend",{class:"hidden-content__sr-only"},"Hidden content selection"),k.loading?n("p",{role:"status"},"Loading file preview…"):k.error?n("div",{class:"hidden-content__preview-error"},n("p",{role:"alert"},k.error+" You can still edit ranges manually."),n("button",{class:"btn",type:"button",onClick:()=>R(i=>i+1)},"Retry preview")):n(W,null,n("div",{class:"hidden-content__editor",ref:h,role:"region","aria-label":"Numbered file content","aria-describedby":"hidden-content-editor-help"}),n("div",{class:"hidden-content__toolbar"},n("p",{id:"hidden-content-editor-help",class:"hidden-content__muted"},"Tap a line in the gutter to hide or show it, or drag to select text and tap Hide selected text in the footer. The file is read-only."))),n("details",{class:"hidden-content__manual",open:!!k.error},n("summary",null,"Enter line ranges manually"),n("p",{class:"hidden-content__muted"},"From and To are inclusive. Use the same number to hide one line."),g.map((i,u)=>n("div",{class:"hidden-content__range",key:u},...["start","end"].map(C=>n("label",{key:C},C==="start"?"From":"To",n("input",{class:"input",type:"number",min:1,step:1,"aria-label":`${C==="start"?"From":"To"} line for range ${u+1}`,value:i[C],onInput:O=>ge(u,C,O.target.value)}))),n("button",{class:"btn",type:"button","aria-label":`Remove range ${u+1}`,onClick:()=>{l(""),j(g.filter((C,O)=>O!==u))}},"×"))),n("button",{class:"btn",type:"button",onClick:()=>{const i=H.length?H[H.length-1].end+1:1;j([...g,{start:i,end:i}])}},"+ Add range")),B&&n("p",{class:"hidden-content__error",role:"alert"},B)),n("footer",{class:"hidden-content__footer"},n("div",{class:"hidden-content__selection",role:"status"},n("strong",null,fe),n("span",{class:"hidden-content__muted"},B?"Fix the range values to continue.":V||q?de({ranges:H,chars:m}):"Tap a line number, or select text and tap Hide selected text."),x&&n("span",{class:"hidden-content__muted"},"Unsaved selection")),f&&n("p",{class:"hidden-content__error",role:"alert"},f),n("div",{class:"hidden-content__actions"},n("button",{class:"btn hidden-content__hide-action",type:"button",disabled:d||!T.hasSelection,onPointerDown:he,onClick:pe,"aria-label":"Hide selected text","aria-describedby":"hidden-content-editor-help"},"Hide selected text"),n("button",{class:"btn",type:"button",disabled:d,onClick:be},"Cancel"),n("button",{class:"btn btn--primary",type:"submit",disabled:d||!!B||!x&&!b.length},d?"Saving…":"Save")))))}function ze({projectDir:s="",from:e="",filePath:r=""}){const t=s||_e.value?.dir||"",[o,a]=S(null),[b,A]=S(""),[M,g]=S(""),[j,m]=S(!1),[z,T]=S(0),[F,k]=S(""),[y,E]=S(""),R=D(null),f=D(null);I(()=>{const c=new AbortController;if(a(null),A(""),!t){A("Open this page from a project’s settings.");return}return K("/api/settings/hide-file-content?"+new URLSearchParams({projectDir:t}),{signal:c.signal}).then(h=>{if(!c.signal.aborted){if(h.status!==200||!Array.isArray(h.body.rules))throw new Error("Could not load hidden files.");a(h.body.rules)}}).catch(h=>{c.signal.aborted||A(h.message)}),()=>c.abort()},[t,z]);function l(c){m(!1),g(""),ee(se({projectDir:t,from:e,filePath:c}))}function d(){ee(se({projectDir:t,from:e}))}async function v(c,{ranges:h,chars:p}){const _=o.filter(H=>H.path!==c),$=h.length||p.length;$&&_.push({path:c,ranges:h,chars:p});const x=await K("/api/settings/hide-file-content",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:t,rules:_})});if(x.status!==200||!Array.isArray(x.body.rules))throw new Error(`Could not save (HTTP ${x.status}).`);a(x.body.rules),g($?"Hidden content saved.":"File is no longer hidden.")}async function w(c,h){if(!F&&window.confirm(`Stop hiding content in ${c}?`)){E(""),g(""),k(c);try{const p=await K("/api/settings/hide-file-content",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectDir:t,rules:o.filter(_=>_.path!==c)})});if(p.status!==200||!Array.isArray(p.body.rules))throw new Error(`Could not remove it (HTTP ${p.status}).`);a(p.body.rules),g(`${c} is no longer hidden.`),requestAnimationFrame(()=>{const _=R.current?R.current.querySelectorAll(".hidden-content__remove"):[];(_[Math.min(h,_.length-1)]||f.current)?.focus()})}catch(p){E((p.message||"Could not remove it.")+" Nothing changed; the file is still hidden.")}finally{k("")}}}if(r&&o)return n(Ie,{key:t+"|"+r,projectDir:t,filePath:r,initialRule:o.find(c=>c.path===r),onSave:v,onClose:d});const L=new URLSearchParams({projectDir:t});return e&&L.set("from",e),n(W,null,n("div",{class:"view-head hidden-content__head"},n("a",{class:"view-back",href:"#/settings/project?"+L,"aria-label":"Back to project settings"},"←"),n("h2",{class:"view-title"},"Hide file content")),n("section",{class:"hidden-content","aria-label":"Hidden files"},n("p",{class:"hidden-content__intro"},"Choose a file, then tap the line numbers you want hidden from the agent file tools, or select text and hide just that span. Your file stays unchanged."),n("p",{class:"hidden-content__scope"},n("strong",null,"Not a security boundary. "),"Only ",n("code",null,"read_file")," and ",n("code",null,"search_files")," are filtered. Shell, MCP, and other access can still read the original content."),b?n("div",{role:"alert"},n("p",null,b),t&&n("button",{class:"btn",onClick:()=>T(c=>c+1)},"Retry")):o===null?n("p",{role:"status"},"Loading hidden files…"):n(W,null,o.length?n("ul",{class:"hidden-content__files",ref:R},o.map((c,h)=>n("li",{key:c.path,class:"hidden-content__row"},n("button",{class:"hidden-content__file",type:"button",onClick:()=>l(c.path)},n("span",{class:"hidden-content__file-main"},n("span",{class:"hidden-content__path"},c.path),n("span",{class:"hidden-content__muted"},de(c))),n("span",{"aria-hidden":"true"},"›")),n("button",{class:"hidden-content__remove",type:"button",disabled:!!F,"aria-label":`Stop hiding content in ${c.path}`,onClick:()=>w(c.path,h)},F===c.path?"Removing…":"Remove")))):n("p",{class:"hidden-content__empty"},"Nothing hidden yet. Add a file to hide whole lines or selected text."),n("button",{class:"btn btn--primary",ref:f,onClick:()=>m(!0)},"+ Add file"),y&&n("p",{class:"hidden-content__error",role:"alert"},y),n("p",{role:"status",class:"hidden-content__notice"},M)),j&&n(Ce,{projectDir:t,onPick:l,onClose:()=>m(!1),label:"Choose a file to hide lines",description:"Choose a file to preview its contents and select hidden lines."})))}export{ze as SettingsHiddenContentView};