@sleekcms/sync 3.2.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +5 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import{readFileSync as Bt}from"node:fs";import{fileURLToPath as er}from"node:url";import{createRequire as tr}from"node:module";import Ae from"node:path";import{render as nr}from"ink";import{execSync as Ye,spawn as B}from"child_process";import{program as Je,Option as He}from"commander";function Xe(){return Je.name("cms-sync").description("SleekCMS CLI tool to sync and edit CMS templates locally. Add each site you want to sync by approving it in your browser \u2014 changes are watched and pushed automatically.").addOption(new He("-v, --version","output the version number").hideHelp()).addOption(new He("-e, --env <env>","Environment (localhost, development, production)").default("production").hideHelp()).option("-p, --path <path>","Directory path for files (default: ~/SleekCMS)").addHelpText("after",`
2
+ import{readFileSync as Pt}from"node:fs";import{fileURLToPath as rr}from"node:url";import _e from"node:path";import{render as sr}from"ink";import{execSync as Xe,spawn as B}from"child_process";import{program as He,Option as ze}from"commander";function Ke(){return He.name("cms-sync").description("SleekCMS CLI tool to sync and edit CMS templates locally. Add each site you want to sync by approving it in your browser \u2014 changes are watched and pushed automatically.").addOption(new ze("-v, --version","output the version number").hideHelp()).addOption(new ze("-e, --env <env>","Environment (localhost, development, production)").default("production").hideHelp()).option("-p, --path <path>","Directory path for files (default: ~/SleekCMS)").addHelpText("after",`
3
3
  Examples:
4
4
  $ sleekcms # add sites in your browser, pick which to sync
5
5
  $ sleekcms -e development # use a non-production backend
6
- `).parse(process.argv),Je.opts()}function R(t){let e=process.platform==="win32"?`where ${t}`:`which ${t}`;try{return Ye(e,{stdio:"ignore"}),!0}catch{return!1}}function Ke(t){if(process.platform!=="darwin")return!1;try{return Ye(`osascript -e 'id of application "${t}"'`,{stdio:"ignore"}),!0}catch{return!1}}function Nt(t,e){let n={detached:!0,stdio:"ignore",windowsHide:!0};process.platform==="win32"?B("cmd.exe",["/c",t,...e],n).unref():B(t,e,n).unref()}var ze=[{name:"VS Code",cmd:"code",args:t=>["-n",t]},{name:"Cursor",cmd:"cursor",args:t=>["-n",t]}];function qe(t,e){let r=(e?ze.filter(s=>s.cmd===e):ze).find(s=>R(s.cmd));return r?(Nt(r.cmd,r.args(t)),r.name):null}function Wt(t){if(process.platform==="darwin")return B("open",["-a","Terminal",t],{detached:!0,stdio:"ignore"}).unref(),!0;if(process.platform==="win32"){if(R("wt"))B("wt.exe",["-d",t],{detached:!0,stdio:"ignore"}).unref();else{let e=R("powershell")?"powershell.exe":"cmd.exe";B("cmd.exe",["/c","start","",e],{cwd:t,detached:!0,stdio:"ignore"}).unref()}return!0}return!1}function Gt(t){return Ke("iTerm")?(B("open",["-a","iTerm",t],{detached:!0,stdio:"ignore"}).unref(),!0):!1}function Ut(t){return`'${t.replace(/'/g,"'\\''")}'`}var Jt=[{cmd:"x-terminal-emulator",args:t=>["-e","bash","-c",t]},{cmd:"gnome-terminal",args:t=>["--","bash","-c",t]},{cmd:"konsole",args:t=>["-e","bash","-c",t]},{cmd:"xfce4-terminal",args:t=>["-x","bash","-c",t]},{cmd:"kitty",args:t=>["bash","-c",t]},{cmd:"alacritty",args:t=>["-e","bash","-c",t]},{cmd:"xterm",args:t=>["-e","bash","-c",t]}];function Ve(t,e){if(!R(e))return!1;if(process.platform==="darwin"){let r=`tell application "Terminal" to do script ("cd " & quoted form of "${t}" & " && ${e}")`;return B("osascript",["-e",r,"-e",'tell application "Terminal" to activate'],{detached:!0,stdio:"ignore"}).unref(),!0}if(process.platform==="win32")return R("wt")?B("wt.exe",["-d",t,"cmd","/k",e],{detached:!0,stdio:"ignore"}).unref():B("cmd.exe",["/c","start","","cmd","/k",e],{cwd:t,detached:!0,stdio:"ignore"}).unref(),!0;let n=`cd ${Ut(t)} && ${e}; exec bash`;for(let r of Jt)if(R(r.cmd))try{return B(r.cmd,r.args(n),{cwd:t,detached:!0,stdio:"ignore"}).unref(),!0}catch{}return!1}function Ht(t){return Ve(t,"claude")}function zt(t){return Ve(t,"pi")}function ae(t){if(!t)return!1;try{let e=process.platform==="darwin"?B("open",[t],{detached:!0,stdio:"ignore"}):process.platform==="win32"?B("cmd.exe",["/c","start","",t],{detached:!0,stdio:"ignore",windowsHide:!0}):B("xdg-open",[t],{detached:!0,stdio:"ignore"});return e.on("error",()=>{}),e.unref(),!0}catch{return!1}}function Qe(){let t=process.platform==="darwin",e=process.platform==="win32",n=[];return(t||e)&&n.push({key:"terminal",label:"terminal",run:Wt}),Ke("iTerm")&&n.push({key:"iterm",label:"iterm",run:Gt}),R("code")&&n.push({key:"code",label:"vscode",run:r=>qe(r,"code")!==null}),R("cursor")&&n.push({key:"cursor",label:"cursor",run:r=>qe(r,"cursor")!==null}),R("claude")&&n.push({key:"claude",label:"claude",run:Ht}),R("pi")&&n.push({key:"pi",label:"pi",run:zt}),n}import{EventEmitter as Ln}from"node:events";import{spawn as Dn}from"node:child_process";import Z from"fs-extra";import Ee from"path";import jn from"chokidar";import{createHash as Yt}from"crypto";import f from"fs-extra";import Xt from"os";import b from"path";var Ze={localhost:"http://app.sleekcms.test/api/mcp",development:"https://app.sleekcms.dev/api/mcp",production:"https://app.sleekcms.com/api/mcp"},Kt=["src/views/blocks","src/views/entries","src/views/pages","src/views/layouts","src/models/blocks","src/models/entries","src/models/pages","src/content/pages","src/content/entries","src/public/js","src/public/css"],X=class extends Error{status;body;constructor(e,n,r){super(e),this.status=n,this.body=r}};async function ce(t,e,n,r,s){let i=await fetch(t+r,{method:n,headers:{Authorization:`Bearer ${e}`,...s!==void 0?{"Content-Type":"application/json"}:{}},body:s!==void 0?JSON.stringify(s):void 0});if(!i.ok){let d=await i.text();throw new X(`${n} ${r} \u2192 ${i.status}: ${d}`,i.status,d)}return i.json()}var Vt=["AGENT.md","CLAUDE.md",b.join(".vscode","copilot-instructions.md")],Qt="mrmlnc.vscode-json5";async function Zt(t,e){e&&(await f.outputFile(b.join(t,"AGENTS.md"),e),await Promise.all(Vt.map(n=>f.remove(b.join(t,n))))),await f.outputFile(b.join(t,".vscode","settings.json"),JSON.stringify({"files.associations":{"*.model":"javascript","**/src/**/*.json":"json5"},"[javascript]":{"editor.defaultFormatter":"esbenp.prettier-vscode"},"js/ts.validate.enabled":!1},null,2)),await f.outputFile(b.join(t,".vscode","extensions.json"),JSON.stringify({recommendations:[Qt]},null,2))}async function en(t,e){if(!e)return;let n=b.join(t,"build.mjs"),r=e.match(/build\.mjs v\d+/)?.[0];if(await f.pathExists(n)){let s=(await f.readFile(n,"utf-8")).match(/build\.mjs v\d+/)?.[0];if(s&&s===r)return}await f.outputFile(n,e)}async function tn(t,e,n,r){let s=b.join(t,".cache","site.json"),i=await f.readJson(s).catch(()=>null);i&&(i.env!==n.env||i.slug!==n.slug)&&(r?.("\u267B\uFE0F Workspace was tied to a different site \u2014 recreating it."),await f.emptyDir(t)),await f.outputJson(s,n),await f.outputFile(b.join(t,".cache","token"),e)}function nn(t,e){let n=`${e.name.substr(0,20)} ${e.id}`.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,""),r=t||b.join(Xt.homedir(),"SleekCMS");return b.resolve(r,n)}async function ve(t){let e=(t.token||"").trim();if(!e)throw new Error("syncSite: token is required");let n=t.log??(y=>console.log(y)),r=t.onProgress,s=(t.env||"production").toLowerCase(),i=Ze[s]||Ze.production,d=await ce(i,e,"GET","/get_site"),l=t.viewsDir?b.resolve(t.viewsDir):nn(t.path,d);await f.ensureDir(l),await tn(l,e,{env:s,slug:String(d.id)},n),await Promise.all(Kt.map(y=>f.ensureDir(b.join(l,y)))),await en(l,t.buildScript);let w=b.join(l,".cache","state.json");t.flush&&await f.remove(w);let S=!await f.pathExists(w),u=S?{}:(await f.readJson(w)).fileMap||{},m=0,v=0,g=0;if(S)({fileMap:u,pulled:v}=await yn(l,i,e,n,r)),await Zt(l,t.agentMd);else{let y=await mn(l,u,i,e,n);g=y.renamed,m=await on(l,u,i,e,n,r,y.held)}return await f.outputJson(w,{fileMap:u},{spaces:2}),{viewsDir:l,site:d,isFirstRun:S,pushed:m,pulled:v,renamed:g}}var K=t=>Yt("sha1").update(t).digest("hex"),rn=new Set([".DS_Store","Thumbs.db","desktop.ini"]);async function Se(t){let e=b.join(t,"src");if(!await f.pathExists(e))return[];let n=[];async function r(s){let i=await f.readdir(s,{withFileTypes:!0});for(let d of i){if(rn.has(d.name))continue;let l=b.join(s,d.name);d.isDirectory()?await r(l):d.isFile()&&n.push(b.relative(t,l).replace(/\\/g,"/"))}}return await r(e),n}function et(t){let e=t.split(b.sep).join("/");return e==="src/setup.json"?0:e==="src/content/images.json"?1:e==="src/content/videos.json"?2:e.startsWith("src/models/")?3:e.startsWith("src/content/")?4:5}var tt=10;function sn(t){let e=[];for(let n=0;n<t.length;n+=tt)e.push(t.slice(n,n+tt));return e}async function on(t,e,n,r,s,i,d=new Set){let l=[];for(let v of await Se(t)){if(d.has(v))continue;let g=b.join(t,v),y=e[v],C=await f.stat(g);if(y&&y.mtimeMs===C.mtimeMs){y.hash||(y.hash=K(await f.readFile(g,"utf-8")));continue}let I=await f.readFile(g,"utf-8");I.trim()&&l.push({rel:v,full:g,stat:C,content:I,prior:y})}if(l.length===0)return 0;l.sort((v,g)=>et(v.rel)-et(g.rel));let w=[];for(let v of sn(l))try{w.push(...await ce(n,r,"POST","/save_files",v.map(g=>({path:g.rel,content:g.content}))))}catch(g){let y=g;s(`\u274C Error saving files: ${y.body||y.message}`),l.length=w.length;break}if(w.length===0)return 0;let S=await st(t),u=0,m=an(w);for(let v=0;v<l.length;v++){let g=l[v],y=cn(g,v,w,m);if(i?.(v+1,l.length),!y){let C="No save response returned";S[g.rel]=C,s(`\u274C Error saving ${g.rel}: ${C}`);continue}if(y.error){S[g.rel]=y.error,s(`\u274C Error saving ${g.rel}: ${y.error}`);continue}delete S[g.rel],e[g.rel]={mtimeMs:g.stat.mtimeMs,hash:K(g.content)},s(`\u2705 ${g.prior?"Updated":"Created"} ${g.rel}`),u++}return await it(t,S),u}function an(t){let e=new Map;for(let n of t)n.path&&e.set(n.path,n);return e}function cn(t,e,n,r){let s=r.get(t.rel);if(s)return s;let i=n[e];if(!i?.path||i.path===t.rel)return i}var nt=/^src\/(?:(?:models|views)\/(?:pages|entries|blocks)|content\/(?:pages|entries))\//,ln={PAGE:"pages",ENTRY:"entries",BLOCK:"blocks"},un=t=>t.split("/").slice(0,3).join("/");function dn(t,e,n){let r=new Map,s=(i,d)=>{let l=`${un(i)}|${d}`;return r.has(l)||r.set(l,{from:[],to:[],hash:d}),r.get(l)};for(let i of t)s(i,n[i].hash).from.push(i);for(let[i,d]of e)s(i,d).to.push(i);return[...r.values()].filter(i=>i.from.length===1&&i.to.length===1).map(i=>({from:i.from[0],to:i.to[0],hash:i.hash}))}function gn(t,e){let n=new Map,r=(s,i,d,l,w)=>{let S=n.get(s);S?(S.pairs.push(w),i<S.rank&&Object.assign(S,{from:d,to:l,rank:i})):n.set(s,{from:d,to:l,rank:i,pairs:[w]})};for(let s of t){let[,i,d,...l]=s.from.split("/"),w=s.to.split("/").slice(3);if(i==="content"&&d==="pages"&&l.length>1){let[u,...m]=l,[v,...g]=w;if(g.length===0)continue;v===u?r(`record:${s.from}`,0,s.from,s.to,s):m.join("/")===g.join("/")&&![...e].some(y=>y.startsWith(`src/content/pages/${u}/`))&&r(`pages:${u}`,3,`src/content/pages/${u}`,`src/content/pages/${v}`,s);continue}let S=l.join("/").replace(/\.[^./]+$/,"");r(`${d}:${S}`,i==="models"?0:i==="views"?1:2,s.from,s.to,s)}return[...n.values()].map(({from:s,to:i,pairs:d})=>({from:s,to:i,pairs:d}))}function rt(t,e){if(t.slug!==void 0&&t.new_slug!==void 0){let d=`src/content/pages/${t.key}/`,l=e.startsWith(d)?e.slice(d.length).match(/^(.+)\.(json|md)$/):null;return l&&l[1].toLowerCase()===t.slug.toLowerCase()?`${d}${t.new_slug}.${l[2]}`:null}let n=ln[t.type],{key:r,new_key:s}=t;if(!n||!s)return null;if(e===`src/models/${n}/${r}.model`)return`src/models/${n}/${s}.model`;if(e===`src/views/${n}/${r}.ejs`)return`src/views/${n}/${s}.ejs`;if(n!=="blocks"&&(e===`src/content/${n}/${r}.json`||e===`src/content/${n}/${r}.md`))return`src/content/${n}/${s}${b.extname(e)}`;let i=`src/content/pages/${r}/`;return n==="pages"&&r.endsWith("+")&&e.startsWith(i)?`src/content/pages/${s}/${e.slice(i.length)}`:null}async function hn(t,e){let n=t;for(;n.startsWith(e+b.sep);){let r=await f.readdir(n).catch(()=>null);if(!r||r.length>0)return;await f.remove(n),n=b.dirname(n)}}async function pn(t,e,n,r){let s=u=>b.join(t,u),i=b.join(t,"src"),d=u=>b.resolve(t,u).startsWith(i+b.sep),l=async(u,m)=>{e[u]={mtimeMs:(await f.stat(s(u))).mtimeMs,hash:m}},w=u=>hn(b.dirname(s(u)),b.join(t,...u.split("/").slice(0,3))),S=[];for(let u of r){let m=rt(n.rename,u.from)??u.to;d(m)&&(m!==u.to&&(await f.move(s(u.to),s(m),{overwrite:!0}),await w(u.to),S.push(u.to)),delete e[u.from],S.push(u.from),await l(m,u.hash))}for(let u of new Set([...await Se(t),...Object.keys(e)])){let m=rt(n.rename,u);if(!m||!d(m))continue;let v=await f.pathExists(s(u));if(v&&await f.pathExists(s(m)))continue;let g=e[u];if(delete e[u],S.push(u),!v)continue;let y=!!g?.hash&&g.mtimeMs===(await f.stat(s(u))).mtimeMs;await f.move(s(u),s(m)),y&&await l(m,g.hash),await w(u)}for(let u of n.files||[]){let m=e[u.path];if(!m||!d(u.path))continue;let v=await f.stat(s(u.path)).catch(()=>null);!v||v.mtimeMs!==m.mtimeMs||await f.readFile(s(u.path),"utf-8")!==u.content&&(await f.outputFile(s(u.path),u.content),await l(u.path,K(u.content)))}return S}function fn(t){try{let e=JSON.parse(t.body).message;if(e)return e}catch{}return(t.body||t.message||String(t)).slice(0,300)}async function mn(t,e,n,r,s){let i=new Set,d=await Se(t),l=new Set(d),w=Object.keys(e).filter(g=>!l.has(g)&&e[g].hash&&nt.test(g));if(w.length===0)return{renamed:0,held:i};let S=new Map;for(let g of d){if(e[g]||!nt.test(g))continue;let y=await f.readFile(b.join(t,g),"utf-8");y.trim()&&S.set(g,K(y))}let u=gn(dn(w,S,e),l);if(u.length===0)return{renamed:0,held:i};let m=await st(t),v=0;for(let g of u){let y;try{y=await ce(n,r,"POST","/rename",{from:g.from,to:g.to})}catch(E){let M=E,H=fn(M);if(M.status>=400&&M.status<500)s(`\u26A0\uFE0F Couldn't rename ${g.from} \u2192 ${g.to}: ${H} Saving it as a new file.`);else{for(let D of g.pairs)i.add(D.to),m[D.to]=`rename from ${D.from} failed: ${H}`;s(`\u274C Error renaming ${g.from} \u2192 ${g.to}: ${H}`)}continue}let C=await pn(t,e,y,g.pairs);for(let E of[...C,...g.pairs.map(M=>M.to)])delete m[E];let[I,...pe]=y.message.split(`
7
- `);s(`\u{1F500} ${I}`);for(let E of pe)s(` ${E}`);v++}return await it(t,m),{renamed:v,held:i}}var xe="sync-errors.log",be=new Map;async function st(t){let e=b.resolve(t),n=be.get(e);if(n)return n;let r=await wn(e);return be.set(e,r),r}async function wn(t){let e=b.join(t,xe);if(!await f.pathExists(e))return{};let n=await f.readFile(e,"utf-8"),r={};for(let s of n.split(`
8
- `)){let i=s.indexOf(": ");i>0&&(r[s.slice(0,i)]=s.slice(i+2))}return r}async function it(t,e){let n=b.join(t,xe),r=Object.entries(e);if(r.length===0){await f.remove(n);return}await f.outputFile(n,r.map(([s,i])=>`${s}: ${i}`).join(`
6
+ `).parse(process.argv),He.opts()}function R(t){let e=process.platform==="win32"?`where ${t}`:`which ${t}`;try{return Xe(e,{stdio:"ignore"}),!0}catch{return!1}}function Ve(t){if(process.platform!=="darwin")return!1;try{return Xe(`osascript -e 'id of application "${t}"'`,{stdio:"ignore"}),!0}catch{return!1}}function Wt(t,e){let n={detached:!0,stdio:"ignore",windowsHide:!0};process.platform==="win32"?B("cmd.exe",["/c",t,...e],n).unref():B(t,e,n).unref()}var qe=[{name:"VS Code",cmd:"code",args:t=>["-n",t]},{name:"Cursor",cmd:"cursor",args:t=>["-n",t]}];function Ye(t,e){let r=(e?qe.filter(s=>s.cmd===e):qe).find(s=>R(s.cmd));return r?(Wt(r.cmd,r.args(t)),r.name):null}function Gt(t){if(process.platform==="darwin")return B("open",["-a","Terminal",t],{detached:!0,stdio:"ignore"}).unref(),!0;if(process.platform==="win32"){if(R("wt"))B("wt.exe",["-d",t],{detached:!0,stdio:"ignore"}).unref();else{let e=R("powershell")?"powershell.exe":"cmd.exe";B("cmd.exe",["/c","start","",e],{cwd:t,detached:!0,stdio:"ignore"}).unref()}return!0}return!1}function Ut(t){return Ve("iTerm")?(B("open",["-a","iTerm",t],{detached:!0,stdio:"ignore"}).unref(),!0):!1}function Jt(t){return`'${t.replace(/'/g,"'\\''")}'`}var Ht=[{cmd:"x-terminal-emulator",args:t=>["-e","bash","-c",t]},{cmd:"gnome-terminal",args:t=>["--","bash","-c",t]},{cmd:"konsole",args:t=>["-e","bash","-c",t]},{cmd:"xfce4-terminal",args:t=>["-x","bash","-c",t]},{cmd:"kitty",args:t=>["bash","-c",t]},{cmd:"alacritty",args:t=>["-e","bash","-c",t]},{cmd:"xterm",args:t=>["-e","bash","-c",t]}];function Qe(t,e){if(!R(e))return!1;if(process.platform==="darwin"){let r=`tell application "Terminal" to do script ("cd " & quoted form of "${t}" & " && ${e}")`;return B("osascript",["-e",r,"-e",'tell application "Terminal" to activate'],{detached:!0,stdio:"ignore"}).unref(),!0}if(process.platform==="win32")return R("wt")?B("wt.exe",["-d",t,"cmd","/k",e],{detached:!0,stdio:"ignore"}).unref():B("cmd.exe",["/c","start","","cmd","/k",e],{cwd:t,detached:!0,stdio:"ignore"}).unref(),!0;let n=`cd ${Jt(t)} && ${e}; exec bash`;for(let r of Ht)if(R(r.cmd))try{return B(r.cmd,r.args(n),{cwd:t,detached:!0,stdio:"ignore"}).unref(),!0}catch{}return!1}function zt(t){return Qe(t,"claude")}function qt(t){return Qe(t,"pi")}function ae(t){if(!t)return!1;try{let e=process.platform==="darwin"?B("open",[t],{detached:!0,stdio:"ignore"}):process.platform==="win32"?B("cmd.exe",["/c","start","",t],{detached:!0,stdio:"ignore",windowsHide:!0}):B("xdg-open",[t],{detached:!0,stdio:"ignore"});return e.on("error",()=>{}),e.unref(),!0}catch{return!1}}function Ze(){let t=process.platform==="darwin",e=process.platform==="win32",n=[];return(t||e)&&n.push({key:"terminal",label:"terminal",run:Gt}),Ve("iTerm")&&n.push({key:"iterm",label:"iterm",run:Ut}),R("code")&&n.push({key:"code",label:"vscode",run:r=>Ye(r,"code")!==null}),R("cursor")&&n.push({key:"cursor",label:"cursor",run:r=>Ye(r,"cursor")!==null}),R("claude")&&n.push({key:"claude",label:"claude",run:zt}),R("pi")&&n.push({key:"pi",label:"pi",run:qt}),n}import{EventEmitter as Dn}from"node:events";import{spawn as jn}from"node:child_process";import Z from"fs-extra";import Me from"path";import An from"chokidar";import{createHash as Xt}from"crypto";import f from"fs-extra";import Kt from"os";import b from"path";var et={localhost:"http://app.sleekcms.test/api/mcp",development:"https://app.sleekcms.dev/api/mcp",production:"https://app.sleekcms.com/api/mcp"},Vt=["src/views/blocks","src/views/entries","src/views/pages","src/views/layouts","src/models/blocks","src/models/entries","src/models/pages","src/content/pages","src/content/entries","src/public/js","src/public/css"],X=class extends Error{status;body;constructor(e,n,r){super(e),this.status=n,this.body=r}};async function ce(t,e,n,r,s){let i=await fetch(t+r,{method:n,headers:{Authorization:`Bearer ${e}`,...s!==void 0?{"Content-Type":"application/json"}:{}},body:s!==void 0?JSON.stringify(s):void 0});if(!i.ok){let d=await i.text();throw new X(`${n} ${r} \u2192 ${i.status}: ${d}`,i.status,d)}return i.json()}var Qt=["AGENT.md","CLAUDE.md",b.join(".vscode","copilot-instructions.md")],Zt="mrmlnc.vscode-json5";async function en(t,e){e&&(await f.outputFile(b.join(t,"AGENTS.md"),e),await Promise.all(Qt.map(n=>f.remove(b.join(t,n))))),await f.outputFile(b.join(t,".vscode","settings.json"),JSON.stringify({"files.associations":{"*.model":"javascript","**/src/**/*.json":"json5"},"[javascript]":{"editor.defaultFormatter":"esbenp.prettier-vscode"},"js/ts.validate.enabled":!1},null,2)),await f.outputFile(b.join(t,".vscode","extensions.json"),JSON.stringify({recommendations:[Zt]},null,2))}async function tn(t,e){if(!e)return;let n=b.join(t,"build.mjs"),r=e.match(/build\.mjs v\d+/)?.[0];if(await f.pathExists(n)){let s=(await f.readFile(n,"utf-8")).match(/build\.mjs v\d+/)?.[0];if(s&&s===r)return}await f.outputFile(n,e)}async function nn(t,e,n,r){let s=b.join(t,".cache","site.json"),i=await f.readJson(s).catch(()=>null);i&&(i.env!==n.env||i.slug!==n.slug)&&(r?.("\u267B\uFE0F Workspace was tied to a different site \u2014 recreating it."),await f.emptyDir(t)),await f.outputJson(s,n),await f.outputFile(b.join(t,".cache","token"),e)}function rn(t,e){let n=`${e.name.substr(0,20)} ${e.id}`.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,""),r=t||b.join(Kt.homedir(),"SleekCMS");return b.resolve(r,n)}async function Se(t){let e=(t.token||"").trim();if(!e)throw new Error("syncSite: token is required");let n=t.log??(y=>console.log(y)),r=t.onProgress,s=(t.env||"production").toLowerCase(),i=et[s]||et.production,d=await ce(i,e,"GET","/get_site"),l=t.viewsDir?b.resolve(t.viewsDir):rn(t.path,d);await f.ensureDir(l),await nn(l,e,{env:s,slug:String(d.id)},n),await Promise.all(Vt.map(y=>f.ensureDir(b.join(l,y)))),await tn(l,t.buildScript);let w=b.join(l,".cache","state.json");t.flush&&await f.remove(w);let S=!await f.pathExists(w),u=S?{}:(await f.readJson(w)).fileMap||{},m=0,v=0,g=0;if(S)({fileMap:u,pulled:v}=await bn(l,i,e,n,r)),await en(l,t.agentMd);else{let y=await wn(l,u,i,e,n);g=y.renamed,m=await an(l,u,i,e,n,r,y.held)}return await f.outputJson(w,{fileMap:u},{spaces:2}),{viewsDir:l,site:d,isFirstRun:S,pushed:m,pulled:v,renamed:g}}var K=t=>Xt("sha1").update(t).digest("hex"),sn=new Set([".DS_Store","Thumbs.db","desktop.ini"]);async function xe(t){let e=b.join(t,"src");if(!await f.pathExists(e))return[];let n=[];async function r(s){let i=await f.readdir(s,{withFileTypes:!0});for(let d of i){if(sn.has(d.name))continue;let l=b.join(s,d.name);d.isDirectory()?await r(l):d.isFile()&&n.push(b.relative(t,l).replace(/\\/g,"/"))}}return await r(e),n}function tt(t){let e=t.split(b.sep).join("/");return e==="src/setup.json"?0:e==="src/content/images.json"?1:e==="src/content/videos.json"?2:e.startsWith("src/models/")?3:e.startsWith("src/content/")?4:5}var nt=10;function on(t){let e=[];for(let n=0;n<t.length;n+=nt)e.push(t.slice(n,n+nt));return e}async function an(t,e,n,r,s,i,d=new Set){let l=[];for(let v of await xe(t)){if(d.has(v))continue;let g=b.join(t,v),y=e[v],E=await f.stat(g);if(y&&y.mtimeMs===E.mtimeMs){y.hash||(y.hash=K(await f.readFile(g,"utf-8")));continue}let I=await f.readFile(g,"utf-8");I.trim()&&l.push({rel:v,full:g,stat:E,content:I,prior:y})}if(l.length===0)return 0;l.sort((v,g)=>tt(v.rel)-tt(g.rel));let w=[];for(let v of on(l))try{w.push(...await ce(n,r,"POST","/save_files",v.map(g=>({path:g.rel,content:g.content}))))}catch(g){let y=g;s(`\u274C Error saving files: ${y.body||y.message}`),l.length=w.length;break}if(w.length===0)return 0;let S=await it(t),u=0,m=cn(w);for(let v=0;v<l.length;v++){let g=l[v],y=ln(g,v,w,m);if(i?.(v+1,l.length),!y){let E="No save response returned";S[g.rel]=E,s(`\u274C Error saving ${g.rel}: ${E}`);continue}if(y.error){S[g.rel]=y.error,s(`\u274C Error saving ${g.rel}: ${y.error}`);continue}delete S[g.rel],e[g.rel]={mtimeMs:g.stat.mtimeMs,hash:K(g.content)},s(`\u2705 ${g.prior?"Updated":"Created"} ${g.rel}`),u++}return await ot(t,S),u}function cn(t){let e=new Map;for(let n of t)n.path&&e.set(n.path,n);return e}function ln(t,e,n,r){let s=r.get(t.rel);if(s)return s;let i=n[e];if(!i?.path||i.path===t.rel)return i}var rt=/^src\/(?:(?:models|views)\/(?:pages|entries|blocks)|content\/(?:pages|entries))\//,un={PAGE:"pages",ENTRY:"entries",BLOCK:"blocks"},dn=t=>t.split("/").slice(0,3).join("/");function gn(t,e,n){let r=new Map,s=(i,d)=>{let l=`${dn(i)}|${d}`;return r.has(l)||r.set(l,{from:[],to:[],hash:d}),r.get(l)};for(let i of t)s(i,n[i].hash).from.push(i);for(let[i,d]of e)s(i,d).to.push(i);return[...r.values()].filter(i=>i.from.length===1&&i.to.length===1).map(i=>({from:i.from[0],to:i.to[0],hash:i.hash}))}function hn(t,e){let n=new Map,r=(s,i,d,l,w)=>{let S=n.get(s);S?(S.pairs.push(w),i<S.rank&&Object.assign(S,{from:d,to:l,rank:i})):n.set(s,{from:d,to:l,rank:i,pairs:[w]})};for(let s of t){let[,i,d,...l]=s.from.split("/"),w=s.to.split("/").slice(3);if(i==="content"&&d==="pages"&&l.length>1){let[u,...m]=l,[v,...g]=w;if(g.length===0)continue;v===u?r(`record:${s.from}`,0,s.from,s.to,s):m.join("/")===g.join("/")&&![...e].some(y=>y.startsWith(`src/content/pages/${u}/`))&&r(`pages:${u}`,3,`src/content/pages/${u}`,`src/content/pages/${v}`,s);continue}let S=l.join("/").replace(/\.[^./]+$/,"");r(`${d}:${S}`,i==="models"?0:i==="views"?1:2,s.from,s.to,s)}return[...n.values()].map(({from:s,to:i,pairs:d})=>({from:s,to:i,pairs:d}))}function st(t,e){if(t.slug!==void 0&&t.new_slug!==void 0){let d=`src/content/pages/${t.key}/`,l=e.startsWith(d)?e.slice(d.length).match(/^(.+)\.(json|md)$/):null;return l&&l[1].toLowerCase()===t.slug.toLowerCase()?`${d}${t.new_slug}.${l[2]}`:null}let n=un[t.type],{key:r,new_key:s}=t;if(!n||!s)return null;if(e===`src/models/${n}/${r}.model`)return`src/models/${n}/${s}.model`;if(e===`src/views/${n}/${r}.ejs`)return`src/views/${n}/${s}.ejs`;if(n!=="blocks"&&(e===`src/content/${n}/${r}.json`||e===`src/content/${n}/${r}.md`))return`src/content/${n}/${s}${b.extname(e)}`;let i=`src/content/pages/${r}/`;return n==="pages"&&r.endsWith("+")&&e.startsWith(i)?`src/content/pages/${s}/${e.slice(i.length)}`:null}async function pn(t,e){let n=t;for(;n.startsWith(e+b.sep);){let r=await f.readdir(n).catch(()=>null);if(!r||r.length>0)return;await f.remove(n),n=b.dirname(n)}}async function fn(t,e,n,r){let s=u=>b.join(t,u),i=b.join(t,"src"),d=u=>b.resolve(t,u).startsWith(i+b.sep),l=async(u,m)=>{e[u]={mtimeMs:(await f.stat(s(u))).mtimeMs,hash:m}},w=u=>pn(b.dirname(s(u)),b.join(t,...u.split("/").slice(0,3))),S=[];for(let u of r){let m=st(n.rename,u.from)??u.to;d(m)&&(m!==u.to&&(await f.move(s(u.to),s(m),{overwrite:!0}),await w(u.to),S.push(u.to)),delete e[u.from],S.push(u.from),await l(m,u.hash))}for(let u of new Set([...await xe(t),...Object.keys(e)])){let m=st(n.rename,u);if(!m||!d(m))continue;let v=await f.pathExists(s(u));if(v&&await f.pathExists(s(m)))continue;let g=e[u];if(delete e[u],S.push(u),!v)continue;let y=!!g?.hash&&g.mtimeMs===(await f.stat(s(u))).mtimeMs;await f.move(s(u),s(m)),y&&await l(m,g.hash),await w(u)}for(let u of n.files||[]){let m=e[u.path];if(!m||!d(u.path))continue;let v=await f.stat(s(u.path)).catch(()=>null);!v||v.mtimeMs!==m.mtimeMs||await f.readFile(s(u.path),"utf-8")!==u.content&&(await f.outputFile(s(u.path),u.content),await l(u.path,K(u.content)))}return S}function mn(t){try{let e=JSON.parse(t.body).message;if(e)return e}catch{}return(t.body||t.message||String(t)).slice(0,300)}async function wn(t,e,n,r,s){let i=new Set,d=await xe(t),l=new Set(d),w=Object.keys(e).filter(g=>!l.has(g)&&e[g].hash&&rt.test(g));if(w.length===0)return{renamed:0,held:i};let S=new Map;for(let g of d){if(e[g]||!rt.test(g))continue;let y=await f.readFile(b.join(t,g),"utf-8");y.trim()&&S.set(g,K(y))}let u=hn(gn(w,S,e),l);if(u.length===0)return{renamed:0,held:i};let m=await it(t),v=0;for(let g of u){let y;try{y=await ce(n,r,"POST","/rename",{from:g.from,to:g.to})}catch(C){let M=C,H=mn(M);if(M.status>=400&&M.status<500)s(`\u26A0\uFE0F Couldn't rename ${g.from} \u2192 ${g.to}: ${H} Saving it as a new file.`);else{for(let D of g.pairs)i.add(D.to),m[D.to]=`rename from ${D.from} failed: ${H}`;s(`\u274C Error renaming ${g.from} \u2192 ${g.to}: ${H}`)}continue}let E=await fn(t,e,y,g.pairs);for(let C of[...E,...g.pairs.map(M=>M.to)])delete m[C];let[I,...fe]=y.message.split(`
7
+ `);s(`\u{1F500} ${I}`);for(let C of fe)s(` ${C}`);v++}return await ot(t,m),{renamed:v,held:i}}var Te="sync-errors.log",ve=new Map;async function it(t){let e=b.resolve(t),n=ve.get(e);if(n)return n;let r=await yn(e);return ve.set(e,r),r}async function yn(t){let e=b.join(t,Te);if(!await f.pathExists(e))return{};let n=await f.readFile(e,"utf-8"),r={};for(let s of n.split(`
8
+ `)){let i=s.indexOf(": ");i>0&&(r[s.slice(0,i)]=s.slice(i+2))}return r}async function ot(t,e){let n=b.join(t,Te),r=Object.entries(e);if(r.length===0){await f.remove(n);return}await f.outputFile(n,r.map(([s,i])=>`${s}: ${i}`).join(`
9
9
  `)+`
10
- `)}async function yn(t,e,n,r,s){be.delete(b.resolve(t)),await f.remove(b.join(t,xe)),r("\u{1F4E5} Fetching files...");let i=await ce(e,n,"GET","/get_files"),d={},l=0;for(let w of i){let S=b.join(t,w.path);await f.outputFile(S,w.content);let u=(await f.stat(S)).mtimeMs;l++,s?.(l,i.length),d[w.path]={mtimeMs:u,hash:K(w.content)}}return r(`\u2714\uFE0F Synced ${i.length} file(s).`),{fileMap:d,pulled:l}}import bn from"path";import vn from"chokidar";var Sn=5e3,xn=/(^|[/\\])(\.DS_Store|Thumbs\.db|desktop\.ini)$/,V=class{viewsDir;onSync;debounceMs;watcher=null;debounceTimer=null;isShuttingDown=!1;dirty=!1;syncInFlight=!1;constructor(e){this.viewsDir=e.viewsDir,this.onSync=e.onSync,this.debounceMs=e.debounceMs??Sn}start(){if(this.watcher)return;let e=bn.join(this.viewsDir,"src");this.watcher=vn.watch([e],{persistent:!0,ignoreInitial:!0,ignored:xn}).on("change",()=>this.scheduleSync()).on("add",()=>this.scheduleSync()).on("unlink",()=>this.scheduleSync()).on("addDir",()=>this.scheduleSync()).on("unlinkDir",()=>this.scheduleSync())}setShuttingDown(e){this.isShuttingDown=e}async stop(){this.debounceTimer&&(clearTimeout(this.debounceTimer),this.debounceTimer=null),this.watcher&&(await this.watcher.close(),this.watcher=null)}scheduleSync(){this.isShuttingDown||(this.dirty=!0,this.debounceTimer&&clearTimeout(this.debounceTimer),this.debounceTimer=setTimeout(()=>this.flush(),this.debounceMs))}async flush(){if(this.debounceTimer=null,!(!this.dirty||this.isShuttingDown)){if(this.syncInFlight){this.debounceTimer=setTimeout(()=>this.flush(),this.debounceMs);return}this.dirty=!1,this.syncInFlight=!0;try{await this.onSync()}catch(e){let n=e;console.error("\u274C Sync failed:",n.body||n.message)}finally{this.syncInFlight=!1}}}};import Te from"fs-extra";import Tn from"os";import at from"path";var ot={localhost:"http://app.sleekcms.test/api",development:"https://app.sleekcms.dev/api",production:"https://app.sleekcms.com/api"};function Q(t){return ot[t]||ot.production}function $e(t){return Q(t).replace(/\/api$/,"")}var kn=at.join(Tn.homedir(),"SleekCMS"),U=at.join(kn,"auth.json"),ke=class extends Error{status;body;constructor(e,n,r=""){super(e),this.name="ApiError",this.status=n,this.body=r}};async function le(t=U){let e=null;try{e=await Te.readJson(t)}catch{return{sites:[],hadLegacyLogin:!1}}return{sites:Array.isArray(e?.sites)?e.sites.filter(r=>r&&typeof r.token=="string"&&typeof r.siteId=="number"):[],hadLegacyLogin:typeof e?.userToken=="string"}}async function ct(t,e=U){await Te.outputJson(e,{sites:t},{spaces:2});try{await Te.chmod(e,384)}catch{}}async function Be(t,e=U){let{sites:n}=await le(e),r=[...n.filter(s=>!(s.env===t.env&&s.siteId===t.siteId)),t];return await ct(r,e),r}async function Pe(t,e,n=U){let{sites:r}=await le(n),s=r.filter(i=>!(i.env===t&&i.siteId===e));return await ct(s,n),s}async function Ce(t,e,n,r){let s=await fetch(Q(t)+r,{method:n,headers:{Authorization:`Bearer ${e}`}});if(!s.ok){let i=await s.text().catch(()=>"");throw new ke(`${n} ${r} \u2192 ${s.status}: ${i}`,s.status,i)}return s.json()}function $n(t){if(t==null)return"(unknown error)";if(typeof t=="string")return t;if(typeof t!="object")return String(t);let e=t,n=typeof e.file_path=="string"?e.file_path:"",r=typeof e.path=="string"?e.path:typeof e.filename=="string"?e.filename:"",s=n||r,i=e.line!=null?`:${e.line}`:"",d=e.column!=null?`:${e.column}`:"",l=typeof e.message=="string"&&e.message?e.message:typeof e.name=="string"&&e.name?e.name:"",w=n&&r&&r!==n?` (on page ${r})`:"";if(s)return`${s}${i}${d}${w}: ${l||"(no message)"}`;if(l)return l;try{return JSON.stringify(t)}catch{return"(unknown error)"}}async function lt(t,e){let n;try{n=await Ce(t,e,"GET","/site_build")}catch{return null}if(!Array.isArray(n)||n.length===0)return null;let r=n[0],s=n.find(d=>typeof d.url=="string"&&d.url.length>0),i=Array.isArray(r.errors)?r.errors.map($n):[];return i.length>0?{status:"error",mode:"preview",errors:i,url:s?.url||void 0,at:r.updated_at?Date.parse(r.updated_at):void 0}:s?{status:"success",mode:"preview",url:s.url||void 0,at:s.updated_at?Date.parse(s.updated_at):void 0}:null}import{createHash as Bn,randomBytes as Pn}from"crypto";var Cn="urn:sleekcms:grant-type:cli_poll",En="SleekCMS Sync",ut=t=>t.toString("base64").replace(/=+$/,"").replace(/\+/g,"-").replace(/\//g,"_");function dt(){let t=ut(Pn(32)),e=ut(Bn("sha256").update(t).digest());return{verifier:t,challenge:e}}function gt(t){let e=t.replace(/[^A-Za-z0-9]/g,"").slice(0,8).toUpperCase();return`${e.slice(0,4)}-${e.slice(4)}`}async function ht(t,e=fetch){let n={origin:$e(t),authorizeEndpoint:`${Q(t)}/oauth/authorize`};try{let r=await e(`${$e(t)}/.well-known/oauth-authorization-server`);if(!r.ok)return n;let s=await r.json();if(typeof s.issuer=="string"&&typeof s.authorization_endpoint=="string")return{origin:s.issuer.replace(/\/+$/,""),authorizeEndpoint:s.authorization_endpoint}}catch{}return n}function pt(t,e){let n=new URLSearchParams({response_type:"code",client_name:En,redirect_uri:`${t.origin}/oauth/cli-done`,code_challenge:e,code_challenge_method:"S256",resource:`${t.origin}/mcp/`});return`${t.authorizeEndpoint}?${n.toString()}`}var J=class extends Error{constructor(e){super(e),this.name="SignInError"}},Mn=t=>new Promise(e=>setTimeout(e,t));async function ft(t,e,n={}){let{timeoutMs:r=10*6e4,signal:s,fetchImpl:i=fetch,sleep:d=Mn}=n,l=n.intervalMs??2e3,w=Date.now()+r,S=`${Q(t)}/oauth/token`;for(;;){if(s?.aborted)throw new J("Cancelled.");let u=null;try{u=await i(S,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({grant_type:Cn,code_verifier:e})})}catch{u=null}if(u){let m=await u.json().catch(()=>({}));if(u.ok&&m.access_token)return m.access_token;if(u.status===429)l=Math.min(l*2,3e4);else if(m.error!=="authorization_pending")throw new J(m.error==="invalid_grant"?"That approval can no longer be used. Add the site again.":`Sign-in failed: ${m.error||`HTTP ${u.status}`}`)}if(Date.now()+l>w)throw new J("Timed out waiting for approval in the browser.");await d(l)}}function Rn(t){let e=t.split(".")[1];if(!e)throw new J("The server returned a token this version can't read.");return JSON.parse(Buffer.from(e,"base64url").toString("utf8"))}async function mt(t,e){let n=Rn(e),r=await Ce(t,e,"GET","/mcp/get_site");return{env:t,siteId:n.sid,slug:n.slug,name:r.name,org:{name:r.org,subdomain:r.subdomain||n.sub},role:r.role||void 0,token:e,addedAt:Date.now()}}var wt=500;function An(){return new Date().toTimeString().slice(0,8)}function _n(t){let e=t;if(e.body){try{let n=JSON.parse(e.body);if(n&&typeof n.message=="string")return n.message;if(n&&typeof n.error=="string")return n.error}catch{}return e.body}return e.message}function yt(t){return t instanceof X&&t.status===401}var Fn=t=>({id:t.siteId,name:t.name,slug:t.slug});async function bt(t){t&&(await Z.remove(Ee.join(t,"src")),await Z.remove(Ee.join(t,".cache","state.json")))}var ue=class extends Ln{env="production";saved=[];synced=new Map;connecting=null;message;messageIsError=!1;agentMd;buildScript;configPath;isShuttingDown=!1;basePath;pollOptions={};openBrowser=ae;constructor(e,n,r=U){super(),this.agentMd=e,this.buildScript=n,this.configPath=r}changed(){this.emit("change")}flash(e,n=!1){this.message=e,this.messageIsError=n,this.changed()}appendLog(e,n){let r=this.synced.get(e);r&&(r.logs.push({time:An(),text:n}),r.logs.length>wt&&r.logs.splice(0,r.logs.length-wt),this.changed())}siteCount(){return this.synced.size}syncingCount(){let e=0;for(let n of this.synced.values())n.status==="syncing"&&e++;return e}watchingCount(){let e=0;for(let n of this.synced.values())(n.status==="watching"||n.status==="syncing")&&e++;return e}async init(e){this.env=e;let{sites:n,hadLegacyLogin:r}=await le(this.configPath);this.saved=n.filter(s=>s.env===e),r&&this.flash("SleekCMS Sync now connects one site at a time \u2014 press a to add a site in your browser."),this.changed()}isSynced(e){return this.synced.has(e)}async connectSite(){if(this.connecting)return;let{verifier:e,challenge:n}=dt(),r=new AbortController;this.connecting={code:gt(n),url:"",abort:r},this.changed();let s=pt(await ht(this.env),n);if(r.signal.aborted){this.connecting=null,this.changed();return}this.connecting.url=s,this.message=void 0,this.changed(),this.openBrowser(s)||this.flash("Couldn't open a browser \u2014 open the address shown to continue.",!0);let i;try{let l=await ft(this.env,e,{...this.pollOptions,signal:r.signal});i=await mt(this.env,l)}catch(l){this.connecting=null,r.signal.aborted?this.changed():this.flash(_n(l),!0);return}this.connecting=null;let d=await Be(i,this.configPath);this.saved=d.filter(l=>l.env===this.env),this.flash(`Added "${i.name}".`),this.synced.has(i.siteId)||await this.startSite(i)}cancelConnect(){this.connecting?.abort.abort()}async startSite(e){let n=Fn(e);if(this.synced.has(n.id))return;let r={org:e.org,site:n,siteToken:e.token,role:e.role,viewsDir:"",status:"syncing",logs:[]};this.synced.set(n.id,r),this.appendLog(n.id,"\u2795 added \u2014 pulling files"),this.changed();try{let s=await ve({token:e.token,env:this.env,path:this.basePath,agentMd:this.agentMd,buildScript:this.buildScript,log:i=>this.appendLog(n.id,i),onProgress:(i,d)=>{r.progress={done:i,total:d},this.changed()}});this.noteRole(n.id,s.site.role),r.viewsDir=s.viewsDir,r.progress=void 0,r.status="watching",r.lastSyncedAt=Date.now(),r.lastMsg=`pulled ${s.pulled} file(s)`,r.watcher=new V({viewsDir:s.viewsDir,onSync:()=>this.runSync(n.id)}),r.watcher.start(),this.watchBuildStatus(n.id),this.seedLastBuild(n.id),this.appendLog(n.id,"\u{1F440} watching for changes")}catch(s){if(yt(s))return void await this.revoke(n.id);let i=s;r.status="error",r.progress=void 0,r.lastMsg=i.body||i.message,this.appendLog(n.id,`\u274C ${i.body||i.message}`)}this.changed()}noteRole(e,n){let r=this.synced.get(e);if(!n||!r||r.role===n)return;r.role=n;let s=this.saved.find(i=>i.siteId===e);s&&(s.role=n,Be({...s},this.configPath).catch(()=>{}))}async revoke(e){let n=this.synced.get(e),r=n?.site.name??this.saved.find(d=>d.siteId===e)?.name??"this site";n&&(n.watcher?.setShuttingDown(!0),await n.watcher?.stop(),await n.buildWatcher?.close(),this.synced.delete(e));let s=await Pe(this.env,e,this.configPath);this.saved=s.filter(d=>d.env===this.env);let i=n?.viewsDir?` Local files kept in ${n.viewsDir}.`:"";this.flash(`Access to "${r}" was revoked \u2014 press a to add it again.${i}`,!0)}async forgetSite(e){if(this.synced.has(e)){this.flash("Disconnect it first (d), then press x to forget it.",!0);return}let n=this.saved.find(s=>s.siteId===e)?.name??"the site",r=await Pe(this.env,e,this.configPath);this.saved=r.filter(s=>s.env===this.env),this.flash(`Forgot "${n}". To revoke its access everywhere, log out of all sessions in SleekCMS.`)}async removeSite(e){let n=this.synced.get(e);n&&(n.watcher?.setShuttingDown(!0),await n.watcher?.stop(),await n.buildWatcher?.close(),await bt(n.viewsDir),this.synced.delete(e),this.changed())}buildSite(e,n=!1){let r=this.synced.get(e);if(!r||!r.viewsDir)return;if(r.role&&r.role!=="ADMIN"){this.flash(`Building and publishing are for site ADMINs \u2014 you're ${r.role} on "${r.site.name}".`,!0);return}let s=n?"live":"preview";this.writeBuildFile(r.viewsDir,{status:"building",mode:s,stage:"queued",url:r.lastBuild?.url,at:Date.now()}),Dn("node",n?["build.mjs","--publish"]:["build.mjs"],{cwd:r.viewsDir,stdio:"ignore"}).on("error",l=>{this.writeBuildFile(r.viewsDir,{status:"error",mode:s,errors:[l.message],url:r.lastBuild?.url,at:Date.now()}),this.appendLog(e,`\u274C build: ${l.message}`)}),this.appendLog(e,n?"\u{1F680} publishing\u2026":"\u{1F528} building\u2026")}buildFile(e){return Ee.join(e,".cache","build.json")}async readBuildFile(e){try{let n=await Z.readJson(this.buildFile(e));return n&&n.status?n:null}catch{return null}}async writeBuildFile(e,n){let r=this.buildFile(e),s=`${r}.tmp`;try{await Z.outputJson(s,n),await Z.rename(s,r)}catch{}}watchBuildStatus(e){let n=this.synced.get(e);!n||!n.viewsDir||(n.buildWatcher=jn.watch(this.buildFile(n.viewsDir),{ignoreInitial:!1}).on("add",()=>{this.readBuildStatus(e)}).on("change",()=>{this.readBuildStatus(e)}))}async readBuildStatus(e){let n=this.synced.get(e);if(!n)return;let r=await this.readBuildFile(n.viewsDir);if(!r)return;let s=n.lastBuild?.url;n.lastBuild={status:r.status,mode:r.mode??"preview",url:r.url??(r.status==="success"?void 0:s),errors:r.errors,stage:r.stage,at:r.at},this.changed()}async seedLastBuild(e){let n=this.synced.get(e);if(!n)return;let r=await lt(this.env,n.siteToken);if(!r)return;let s=this.synced.get(e);if(!s)return;let i=await this.readBuildFile(s.viewsDir);i?.at!=null&&(r.at==null||i.at>=r.at)||await this.writeBuildFile(s.viewsDir,r)}async refetch(e){await this.runSync(e,{flush:!0})}async runSync(e,n={}){let r=this.synced.get(e);if(!(!r||!r.viewsDir||r.status==="paused")){r.status="syncing",this.changed();try{let s=await ve({token:r.siteToken,env:this.env,viewsDir:r.viewsDir,agentMd:this.agentMd,buildScript:this.buildScript,flush:n.flush,log:i=>this.appendLog(e,i),onProgress:(i,d)=>{r.progress={done:i,total:d},this.changed()}});if(this.noteRole(e,s.site.role),r.progress=void 0,r.status="watching",r.lastSyncedAt=Date.now(),n.flush)r.lastMsg=`re-fetched ${s.pulled} file(s)`;else{let i=[s.renamed>0?`renamed ${s.renamed}`:"",s.pushed>0?`pushed ${s.pushed} file(s)`:""].filter(Boolean);r.lastMsg=i.length>0?i.join(", "):"up to date"}}catch(s){if(yt(s))return void await this.revoke(e);let i=s;r.status="error",r.progress=void 0,r.lastMsg=i.body||i.message,this.appendLog(e,`\u274C ${i.body||i.message}`)}this.changed()}}async togglePause(e){let n=this.synced.get(e);!n||!n.viewsDir||(n.status==="paused"?(n.watcher=new V({viewsDir:n.viewsDir,onSync:()=>this.runSync(e)}),n.watcher.start(),n.status="watching",this.appendLog(e,"\u25B6 resumed \u2014 watching for changes")):(n.watcher?.setShuttingDown(!0),await n.watcher?.stop(),n.watcher=void 0,n.progress=void 0,n.status="paused",this.appendLog(e,"\u23F8 paused")),this.changed())}async cleanupAll(){this.cancelConnect();for(let e of this.synced.values())e.watcher?.setShuttingDown(!0),await e.watcher?.stop(),await e.buildWatcher?.close(),await bt(e.viewsDir)}async exit(){this.isShuttingDown||(this.isShuttingDown=!0,await this.cleanupAll(),this.emit("exit"))}};import{useInput as Qn}from"ink";import{Fragment as In,useEffect as ee,useMemo as Nn,useRef as Wn,useState as L}from"react";import{Box as p,Text as c,useInput as Gn,useStdout as Un}from"ink";import Jn from"ink-text-input";import On from"node:os";function Me(t){if(!t)return"\u2014";let e=On.homedir();return t.startsWith(e)?"~"+t.slice(e.length):t}function Re(t){if(!t)return"\u2014";let e=Math.floor((Date.now()-t)/1e3);if(e<5)return"just now";if(e<60)return`${e}s ago`;let n=Math.floor(e/60);if(n<60)return`${n}m ago`;let r=Math.floor(n/60);return r<24?`${r}h ago`:`${Math.floor(r/24)}d ago`}function ge(t){return!t||t.total<=0?null:Math.round(t.done/t.total*100)}var de=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"];function Le(t){return de[(t%de.length+de.length)%de.length]}function he(t){switch(t){case"syncing":return{dot:"\u25CF",color:"green",label:"syncing"};case"watching":return{dot:"\u25CB",color:"gray",label:"watching"};case"paused":return{dot:"\u2016",color:"yellow",label:"paused"};case"error":return{dot:"\u2717",color:"red",label:"error"}}}function vt(t){if(!t)return{dot:"\xB7",color:"gray",label:"\u2014"};switch(t.status){case"building":return{dot:"\u2234",color:"yellow",label:"building"};case"error":return{dot:"\u2717",color:"red",label:"failed"};case"success":return{dot:"\u2713",color:"green",label:t.mode==="live"?"live":"preview"}}}import{Fragment as De,jsx as o,jsxs as h}from"react/jsx-runtime";var Hn=(t,e)=>e<=0?0:Math.max(0,Math.min(t,e-1)),zn=16,qn=5,Yn="greenBright",St="blueBright",xt="magentaBright";function Tt({k:t,bg:e=Yn}){return o(c,{color:"black",backgroundColor:e,children:` ${t} `})}function _({k:t,label:e,width:n=16,bg:r}){return h(p,{width:n,children:[o(Tt,{k:t,bg:r}),o(c,{color:"gray",children:` ${e}`})]})}function $({k:t,label:e,bg:n}){return h(p,{marginBottom:1,children:[o(p,{width:9,children:o(Tt,{k:t,bg:n})}),o(c,{color:"gray",children:e})]})}function Xn({launchers:t}){return h(p,{flexDirection:"column",borderStyle:"round",borderColor:"green",paddingX:2,paddingY:1,width:66,children:[h(p,{justifyContent:"space-between",children:[o(c,{color:"green",bold:!0,children:"KEYBOARD SHORTCUTS"}),o(c,{color:"gray",children:"? or esc to close"})]}),h(p,{marginTop:1,children:[h(p,{flexDirection:"column",width:34,children:[o(c,{color:"cyan",bold:!0,children:"Navigate"}),o($,{k:"\u2191\u2193",label:"move selection"}),o($,{k:"tab",label:"focus logs \xB7 \u2191\u2193 scroll"}),o($,{k:"esc",label:"clear filter / back"}),o(p,{marginTop:1,children:o(c,{color:"cyan",bold:!0,children:"Global"})}),o($,{k:"/",label:"search sites"}),o($,{k:"a",label:"add a site (browser)"}),o($,{k:"?",label:"toggle this help",bg:St}),o($,{k:"ctrl+c",label:"quit"})]}),h(p,{flexDirection:"column",flexGrow:1,children:[o(c,{color:"cyan",bold:!0,children:"Site actions"}),o($,{k:"s",label:"start sync"}),o($,{k:"d",label:"disconnect"}),o($,{k:"x",label:"forget site"}),o($,{k:"p",label:"pause / resume sync"}),o($,{k:"b",label:"build preview"}),o($,{k:"B",label:"publish live"}),o($,{k:"o",label:"open preview url"}),t.map((e,n)=>o($,{k:String(n+1),label:`open in ${e.label}`,bg:xt},e.key))]})]})]})}function Kn({percent:t,width:e=28}){let n=Math.round(Math.max(0,Math.min(100,t))/100*e);return h(c,{children:[o(c,{color:"green",children:"\u2588".repeat(n)}),o(c,{color:"gray",children:"\u2591".repeat(Math.max(0,e-n))})]})}function Vn({frame:t,width:e=24,seg:n=6}){let r=e+n,s=t%r-n,i="";for(let d=0;d<e;d++)i+=d>=s&&d<s+n?"\u25AE":"\u25AF";return o(c,{color:"yellow",children:i})}function kt({controller:t}){let{stdout:e}=Un(),n=Nn(()=>Qe(),[]),[,r]=L(0),[s,i]=L(()=>new Date),[d,l]=L(null),[w,S]=L(""),[u,m]=L(!1),[v,g]=L(0),[y,C]=L(!1),[I,pe]=L(!1),[E,M]=L("list"),[H,D]=L(0),_e=()=>r(a=>a+1);ee(()=>(t.on("change",_e),()=>{t.off("change",_e)}),[t]),ee(()=>{let a,x=()=>{i(new Date),a=setTimeout(x,6e4-Date.now()%6e4)};return a=setTimeout(x,6e4-Date.now()%6e4),()=>clearTimeout(a)},[]);let z=t.saved.map(a=>({org:a.org,site:{id:a.siteId,name:a.name,slug:a.slug},saved:a,entry:t.synced.get(a.siteId)})).sort((a,x)=>(a.entry?0:1)-(x.entry?0:1)),N=t.connecting,F=w.trim().toLowerCase(),P=F?z.filter(a=>a.site.name.toLowerCase().includes(F)||(a.org.name||a.org.subdomain||"").toLowerCase().includes(F)):z,W=P.findIndex(a=>a.site.id===d);W<0&&(W=0);let k=P[W],T=k?.entry,te=Math.max(3,(e?.rows??30)-26),O=T?.logs??[],fe=Math.max(0,O.length-te),Ct=Math.min(H,fe),ne=O.length-Ct,Fe=O.slice(Math.max(0,ne-te),ne),Et=k?.site.id;ee(()=>D(0),[Et]);let j=T?.lastBuild,me=j?.status==="building",we=vt(j),re=me||!!N;if(!re){for(let a of t.synced.values())if(a.status==="syncing"){re=!0;break}}ee(()=>{if(!re)return;let a=setInterval(()=>g(x=>x+1),120);return()=>clearInterval(a)},[re]);let Oe=P.findIndex(a=>!a.entry),G=Math.max(qn,(e?.rows??30)-zn),q=P.length,se=q>G,Mt=Math.floor(G/2),Y=se?Math.max(0,Math.min(W-Mt,q-G)):0,ye=Math.min(q,Y+G),Rt=P.slice(Y,ye),Ie=Wn(!1);ee(()=>{Ie.current||(Ie.current=!0,t.saved.length===0&&!t.connecting&&t.connectSite())},[t]);let ie=a=>{if(P.length===0)return;let x=Hn(W+a,P.length);l(P[x].site.id)},Lt=()=>{if(k){if(k.entry){t.flash("Already syncing \u2014 press d to disconnect.");return}t.startSite(k.saved)}},Dt=()=>{k?.entry&&t.removeSite(k.site.id)},jt=()=>{k&&t.forgetSite(k.site.id)},At=a=>{if(!T){t.flash("Press s to start syncing this site first.",!0);return}pe(!0);let x=a.run(T.viewsDir);t.flash(x?`Opened ${a.label} at ${Me(T.viewsDir)}`:`Couldn't open ${a.label}.`,!x)},_t=()=>{if(!T){t.flash("Press s to start syncing this site first.",!0);return}t.togglePause(T.site.id)},Ne=a=>{if(!T){t.flash("Press s to start syncing this site first.",!0);return}t.buildSite(T.site.id,a),t.flash(a?"Publishing \u2014 making this live\u2026":"Building preview\u2026")},Ft=()=>{let a=T?.lastBuild?.url;if(!a){t.flash("No build URL yet \u2014 press b to build.",!0);return}t.flash(ae(a)?`Opening ${a}`:"Couldn't open the browser.",!1)};Gn((a,x)=>{if(y){(a==="?"||x.escape)&&C(!1);return}if(N&&x.escape)return void t.cancelConnect();if(u){x.escape?(m(!1),S(""),l(null)):x.return?m(!1):x.upArrow?ie(-1):x.downArrow&&ie(1);return}if(x.tab){E==="logs"?M("list"):T&&M("logs"),D(0);return}if(E==="logs"){if(x.escape){M("list"),D(0);return}if(x.upArrow)return void D(A=>Math.min(A+1,fe));if(x.downArrow)return void D(A=>Math.max(0,A-1))}if(x.escape){S(""),l(null);return}if(a==="?")return void C(!0);if(a==="/")return M("list"),void m(!0);if(a==="a"||a==="n")return void t.connectSite();if(x.upArrow)return ie(-1);if(x.downArrow)return ie(1);if(a==="s")return Lt();if(a==="d")return Dt();if(a==="x")return jt();if(a==="p")return _t();if(a==="b")return Ne(!1);if(a==="B")return Ne(!0);if(a==="o")return Ft();if(a>="1"&&a<="9"){let A=n[parseInt(a,10)-1];if(A)return At(A)}});let We=h(p,{justifyContent:"space-between",paddingX:1,children:[h(p,{children:[o(c,{color:"green",bold:!0,children:"\u25C6 SleekCMS"}),o(c,{color:"gray",children:" \u2502 "}),o(c,{children:t.env==="production"?"Sync":`Sync \xB7 ${t.env}`})]}),h(p,{children:[h(c,{color:"gray",children:[F?`${P.length}/${z.length}`:z.length," sites \xB7 "]}),h(c,{color:"green",children:[t.watchingCount()," watching"]}),o(c,{color:"gray",children:` \xB7 ${s.toTimeString().slice(0,5)}`})]})]});return y?h(p,{flexDirection:"column",children:[We,o(p,{marginTop:1,justifyContent:"center",children:o(Xn,{launchers:n})})]}):h(p,{flexDirection:"column",children:[We,h(p,{children:[h(p,{flexDirection:"column",borderStyle:"round",borderColor:"green",width:38,paddingX:1,children:[h(p,{justifyContent:"space-between",children:[o(c,{color:"green",bold:!0,children:"SITE WORKSPACES"}),z.length>G&&!u&&!F?o(c,{color:"gray",children:"/ filter"}):null]}),u?h(p,{children:[o(c,{color:"cyan",children:"/ "}),o(Jn,{value:w,onChange:S,onSubmit:()=>m(!1),placeholder:"type to filter\u2026"})]}):F?o(c,{color:"gray",children:`/ ${w} \xB7 ${P.length} match${P.length===1?"":"es"}`}):null,o(p,{flexDirection:"column",marginTop:1,minHeight:se?G+3:void 0,children:P.length===0?o(c,{color:"gray",children:F?`no matches for \u201C${w}\u201D`:"no sites yet \u2014 press a to add one"}):h(De,{children:[se?o(c,{color:"gray",children:Y>0?` \u2191 ${Y} more`:" "}):null,Rt.map((a,x)=>{let A=Y+x,Ge=a.entry?he(a.entry.status):{dot:"\xB7",color:"gray",label:"idle"},Ue=ge(a.entry?.progress),Ot=a.entry?a.entry.status==="syncing"&&Ue!=null?`${Ue}%`:a.entry.status==="paused"?"paused":"--":"",oe=A===W,It=A===Oe&&Oe>0;return h(In,{children:[It?o(c,{color:"gray",children:"\u2500".repeat(34)}):null,h(p,{justifyContent:"space-between",children:[h(p,{children:[o(c,{color:oe?"green":"gray",children:oe?"\u276F ":" "}),h(c,{color:a.entry?.status==="watching"||a.entry?.status==="syncing"?"green":Ge.color,children:[a.entry?.status==="syncing"?Le(v):a.entry?.status==="watching"?"\u25CF":Ge.dot," "]}),o(c,{color:oe?"white":a.entry?void 0:"gray",bold:oe,children:a.site.name})]}),o(c,{color:a.entry?.status==="syncing"?"green":"gray",children:Ot})]})]},a.site.id)}),se?o(c,{color:"gray",children:ye<q?` \u2193 ${q-ye} more`:" "}):null]})}),o(p,{marginTop:1,children:o(c,{color:"gray",children:"+ add site \xB7 a"})})]}),h(p,{flexDirection:"column",flexGrow:1,marginLeft:1,children:[o(p,{flexDirection:"column",borderStyle:"round",borderColor:"gray",paddingX:1,children:k?h(De,{children:[h(c,{children:[k.org.name||k.org.subdomain?h(c,{color:"gray",children:[k.org.name||k.org.subdomain," / "]}):null,o(c,{color:"cyan",bold:!0,children:k.site.name})]}),h(p,{marginTop:1,children:[o(c,{color:"gray",children:"status "}),T?o(c,{color:he(T.status).color,children:`: ${he(T.status).label}`}):o(c,{color:"gray",children:": idle \u2014 not syncing (press s to start)"})]}),h(p,{children:[o(c,{color:"gray",children:"role "}),o(c,{children:T?.role??k.saved.role??"\u2014"}),(T?.role??k.saved.role??"ADMIN")!=="ADMIN"?o(c,{color:"gray",children:" \xB7 build & publish need ADMIN"}):null]}),h(p,{children:[o(c,{color:"gray",children:"path "}),o(c,{wrap:"truncate-end",children:T?.viewsDir?Me(T.viewsDir):"\u2014"})]}),h(p,{children:[o(c,{color:"gray",children:"synced "}),o(c,{children:Re(T?.lastSyncedAt)}),o(c,{color:"gray",children:" progress "}),o(c,{color:T?.status==="syncing"?"green":"gray",children:T?.status==="syncing"?`${ge(T.progress)??0}%`:"\u2014"})]}),o(p,{marginTop:1,children:o(Kn,{percent:T?T.status==="syncing"?ge(T.progress)??0:T.status==="watching"?100:0:0})}),T?h(De,{children:[h(p,{marginTop:1,children:[o(c,{color:"gray",children:"build "}),o(c,{color:we.color,children:`${we.dot} ${we.label}`}),o(c,{color:"gray",children:" last "}),o(c,{children:me?"in progress":Re(j?.at)})]}),h(p,{children:[o(c,{color:"gray",children:"url "}),j?.url?o(c,{color:"cyan",wrap:"truncate-end",children:j.url}):o(c,{color:"gray",children:"\u2014"})]}),j?.status==="error"&&j.errors?.length?h(p,{children:[o(c,{color:"red",children:"\u258C "}),o(c,{color:"red",wrap:"truncate-end",children:`\u2717 ${j.errors[0]}`})]}):null,me?h(p,{children:[o(Vn,{frame:v}),o(c,{color:"gray",children:` ${j?.stage??"building"}`})]}):null]}):null]}):o(c,{color:"gray",children:"No site selected."})}),N?h(p,{flexDirection:"column",borderStyle:"round",borderColor:"blue",paddingX:1,marginTop:1,flexGrow:1,children:[o(c,{color:"cyan",bold:!0,children:"ADD A SITE"}),o(c,{children:"Approve it in your browser: pick a site, or create one."}),h(p,{marginTop:1,children:[o(c,{color:"gray",children:"Check the page shows "}),o(c,{color:"cyan",bold:!0,children:N.code})]}),o(c,{color:"gray",children:"Only approve a page that shows this code."}),h(p,{marginTop:1,children:[h(c,{color:"yellow",children:[Le(v)," "]}),o(c,{color:"gray",children:"waiting for approval \xB7 esc to cancel"})]})]}):h(p,{flexDirection:"column",borderStyle:"round",borderColor:E==="logs"?"green":"gray",paddingX:1,marginTop:1,height:te+4,flexShrink:0,overflowY:"hidden",children:[h(p,{justifyContent:"space-between",children:[h(c,{children:[o(c,{color:"cyan",bold:!0,children:"LOGS \xB7 "}),o(c,{color:"white",children:k?.site.name??"\u2014"})]}),T&&O.length>0?E==="logs"?o(c,{color:"green",children:`\u2191\u2193 scroll \xB7 esc back${fe>0?` \xB7 ${ne}/${O.length}`:""}`}):O.length>te?o(c,{color:"gray",children:"tab to scroll"}):null:null]}),o(p,{flexDirection:"column",marginTop:1,children:!T||O.length===0?o(c,{color:"gray",children:"no activity yet"}):Fe.map((a,x)=>h(c,{wrap:"truncate-end",children:[h(c,{color:"gray",children:[a.time," "]}),a.text]},ne-Fe.length+x))})]})]})]}),N?.url?h(p,{flexDirection:"column",paddingX:1,marginTop:1,children:[o(c,{color:"gray",children:"No browser? Open this address on any device:"}),o(c,{color:"cyan",children:N.url})]}):null,t.message?o(p,{paddingX:1,children:h(c,{color:t.messageIsError?"red":"gray",wrap:"truncate-end",children:[t.messageIsError?"\u2717 ":"",t.message]})}):null,h(p,{flexDirection:"column",marginTop:1,children:[h(p,{paddingX:1,justifyContent:"space-between",children:[h(p,{flexWrap:"wrap",children:[o(_,{k:"\u2191\u2193",label:"select"}),o(_,{k:"/",label:"search"}),o(_,{k:"s",label:"start sync"}),o(_,{k:"d",label:"disconnect"}),o(_,{k:"a",label:"add site"}),o(_,{k:"ctrl+c",label:"quit",width:14})]}),o(_,{k:"?",label:"all keys",width:12,bg:St})]}),!I&&n.length>0?o(p,{paddingX:1,marginTop:1,flexWrap:"wrap",children:n.map((a,x)=>o(_,{k:String(x+1),label:a.label,bg:xt},a.key))}):null]})]})}import{jsx as Zn}from"react/jsx-runtime";function $t({controller:t}){return Qn((e,n)=>{n.ctrl&&e==="c"&&t.exit()}),Zn(kt,{controller:t})}import{jsx as ar}from"react/jsx-runtime";var rr=tr(import.meta.url),je=Xe();if(je.version){let t=rr("../package.json");console.log(t.version),process.exit(0)}var Pt=Ae.dirname(er(import.meta.url)),sr=Bt(Ae.join(Pt,"AGENTS.md"),"utf-8"),ir=Bt(Ae.join(Pt,"build.mjs"),"utf-8");async function or(){let t=new ue(sr,ir);t.basePath=je.path,await t.init((je.env??"production").toLowerCase()),process.stdout.isTTY&&process.stdout.write("\x1B[2J\x1B[3J\x1B[H");let e=nr(ar($t,{controller:t}),{exitOnCtrlC:!1}),n=r=>{e.unmount(),console.log(r),process.exit(0)};t.once("exit",()=>n("\u2713 Stopped. Local site files were cleaned up.")),process.on("SIGINT",()=>{t.exit()}),process.on("SIGTERM",()=>{t.exit()}),await e.waitUntilExit()}or().catch(t=>{let e=t;console.error("\u274C",e.body||e.message),process.exit(1)});
10
+ `)}async function bn(t,e,n,r,s){ve.delete(b.resolve(t)),await f.remove(b.join(t,Te)),r("\u{1F4E5} Fetching files...");let i=await ce(e,n,"GET","/get_files"),d={},l=0;for(let w of i){let S=b.join(t,w.path);await f.outputFile(S,w.content);let u=(await f.stat(S)).mtimeMs;l++,s?.(l,i.length),d[w.path]={mtimeMs:u,hash:K(w.content)}}return r(`\u2714\uFE0F Synced ${i.length} file(s).`),{fileMap:d,pulled:l}}import vn from"path";import Sn from"chokidar";var xn=5e3,Tn=/(^|[/\\])(\.DS_Store|Thumbs\.db|desktop\.ini)$/,V=class{viewsDir;onSync;debounceMs;watcher=null;debounceTimer=null;isShuttingDown=!1;dirty=!1;syncInFlight=!1;constructor(e){this.viewsDir=e.viewsDir,this.onSync=e.onSync,this.debounceMs=e.debounceMs??xn}start(){if(this.watcher)return;let e=vn.join(this.viewsDir,"src");this.watcher=Sn.watch([e],{persistent:!0,ignoreInitial:!0,ignored:Tn}).on("change",()=>this.scheduleSync()).on("add",()=>this.scheduleSync()).on("unlink",()=>this.scheduleSync()).on("addDir",()=>this.scheduleSync()).on("unlinkDir",()=>this.scheduleSync())}setShuttingDown(e){this.isShuttingDown=e}async stop(){this.debounceTimer&&(clearTimeout(this.debounceTimer),this.debounceTimer=null),this.watcher&&(await this.watcher.close(),this.watcher=null)}scheduleSync(){this.isShuttingDown||(this.dirty=!0,this.debounceTimer&&clearTimeout(this.debounceTimer),this.debounceTimer=setTimeout(()=>this.flush(),this.debounceMs))}async flush(){if(this.debounceTimer=null,!(!this.dirty||this.isShuttingDown)){if(this.syncInFlight){this.debounceTimer=setTimeout(()=>this.flush(),this.debounceMs);return}this.dirty=!1,this.syncInFlight=!0;try{await this.onSync()}catch(e){let n=e;console.error("\u274C Sync failed:",n.body||n.message)}finally{this.syncInFlight=!1}}}};import ke from"fs-extra";import kn from"os";import ct from"path";var at={localhost:"http://app.sleekcms.test/api",development:"https://app.sleekcms.dev/api",production:"https://app.sleekcms.com/api"};function Q(t){return at[t]||at.production}function Be(t){return Q(t).replace(/\/api$/,"")}var $n=ct.join(kn.homedir(),"SleekCMS"),U=ct.join($n,"auth.json"),$e=class extends Error{status;body;constructor(e,n,r=""){super(e),this.name="ApiError",this.status=n,this.body=r}};async function le(t=U){let e=null;try{e=await ke.readJson(t)}catch{return{sites:[],hadLegacyLogin:!1}}return{sites:Array.isArray(e?.sites)?e.sites.filter(r=>r&&typeof r.token=="string"&&typeof r.siteId=="number"):[],hadLegacyLogin:typeof e?.userToken=="string"}}async function lt(t,e=U){await ke.outputJson(e,{sites:t},{spaces:2});try{await ke.chmod(e,384)}catch{}}async function Pe(t,e=U){let{sites:n}=await le(e),r=[...n.filter(s=>!(s.env===t.env&&s.siteId===t.siteId)),t];return await lt(r,e),r}async function Ee(t,e,n=U){let{sites:r}=await le(n),s=r.filter(i=>!(i.env===t&&i.siteId===e));return await lt(s,n),s}async function Ce(t,e,n,r){let s=await fetch(Q(t)+r,{method:n,headers:{Authorization:`Bearer ${e}`}});if(!s.ok){let i=await s.text().catch(()=>"");throw new $e(`${n} ${r} \u2192 ${s.status}: ${i}`,s.status,i)}return s.json()}function Bn(t){if(t==null)return"(unknown error)";if(typeof t=="string")return t;if(typeof t!="object")return String(t);let e=t,n=typeof e.file_path=="string"?e.file_path:"",r=typeof e.path=="string"?e.path:typeof e.filename=="string"?e.filename:"",s=n||r,i=e.line!=null?`:${e.line}`:"",d=e.column!=null?`:${e.column}`:"",l=typeof e.message=="string"&&e.message?e.message:typeof e.name=="string"&&e.name?e.name:"",w=n&&r&&r!==n?` (on page ${r})`:"";if(s)return`${s}${i}${d}${w}: ${l||"(no message)"}`;if(l)return l;try{return JSON.stringify(t)}catch{return"(unknown error)"}}async function ut(t,e){let n;try{n=await Ce(t,e,"GET","/site_build")}catch{return null}if(!Array.isArray(n)||n.length===0)return null;let r=n[0],s=n.find(d=>typeof d.url=="string"&&d.url.length>0),i=Array.isArray(r.errors)?r.errors.map(Bn):[];return i.length>0?{status:"error",mode:"preview",errors:i,url:s?.url||void 0,at:r.updated_at?Date.parse(r.updated_at):void 0}:s?{status:"success",mode:"preview",url:s.url||void 0,at:s.updated_at?Date.parse(s.updated_at):void 0}:null}import{createHash as Pn,randomBytes as En}from"crypto";var Cn="urn:sleekcms:grant-type:cli_poll",Mn="SleekCMS Sync",dt=t=>t.toString("base64").replace(/=+$/,"").replace(/\+/g,"-").replace(/\//g,"_");function gt(){let t=dt(En(32)),e=dt(Pn("sha256").update(t).digest());return{verifier:t,challenge:e}}function ht(t){let e=t.replace(/[^A-Za-z0-9]/g,"").slice(0,8).toUpperCase();return`${e.slice(0,4)}-${e.slice(4)}`}async function pt(t,e=fetch){let n={origin:Be(t),authorizeEndpoint:`${Q(t)}/oauth/authorize`};try{let r=await e(`${Be(t)}/.well-known/oauth-authorization-server`);if(!r.ok)return n;let s=await r.json();if(typeof s.issuer=="string"&&typeof s.authorization_endpoint=="string")return{origin:s.issuer.replace(/\/+$/,""),authorizeEndpoint:s.authorization_endpoint}}catch{}return n}function ft(t,e){let n=new URLSearchParams({response_type:"code",client_name:Mn,redirect_uri:`${t.origin}/oauth/cli-done`,code_challenge:e,code_challenge_method:"S256",resource:`${t.origin}/mcp/`});return`${t.authorizeEndpoint}?${n.toString()}`}var J=class extends Error{constructor(e){super(e),this.name="SignInError"}},Rn=t=>new Promise(e=>setTimeout(e,t));async function mt(t,e,n={}){let{timeoutMs:r=10*6e4,signal:s,fetchImpl:i=fetch,sleep:d=Rn}=n,l=n.intervalMs??2e3,w=Date.now()+r,S=`${Q(t)}/oauth/token`;for(;;){if(s?.aborted)throw new J("Cancelled.");let u=null;try{u=await i(S,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({grant_type:Cn,code_verifier:e})})}catch{u=null}if(u){let m=await u.json().catch(()=>({}));if(u.ok&&m.access_token)return m.access_token;if(u.status===429)l=Math.min(l*2,3e4);else if(m.error!=="authorization_pending")throw new J(m.error==="invalid_grant"?"That approval can no longer be used. Add the site again.":`Sign-in failed: ${m.error||`HTTP ${u.status}`}`)}if(Date.now()+l>w)throw new J("Timed out waiting for approval in the browser.");await d(l)}}function Ln(t){let e=t.split(".")[1];if(!e)throw new J("The server returned a token this version can't read.");return JSON.parse(Buffer.from(e,"base64url").toString("utf8"))}async function wt(t,e){let n=Ln(e),r=await Ce(t,e,"GET","/mcp/get_site");return{env:t,siteId:n.sid,slug:n.slug,name:r.name,org:{name:r.org,subdomain:r.subdomain||n.sub},role:r.role||void 0,token:e,addedAt:Date.now()}}var yt=500;function _n(){return new Date().toTimeString().slice(0,8)}function Fn(t){let e=t;if(e.body){try{let n=JSON.parse(e.body);if(n&&typeof n.message=="string")return n.message;if(n&&typeof n.error=="string")return n.error}catch{}return e.body}return e.message}function bt(t){return t instanceof X&&t.status===401}var On=t=>({id:t.siteId,name:t.name,slug:t.slug});async function vt(t){t&&(await Z.remove(Me.join(t,"src")),await Z.remove(Me.join(t,".cache","state.json")))}var ue=class extends Dn{env="production";saved=[];synced=new Map;connecting=null;message;messageIsError=!1;agentMd;buildScript;configPath;isShuttingDown=!1;basePath;pollOptions={};openBrowser=ae;constructor(e,n,r=U){super(),this.agentMd=e,this.buildScript=n,this.configPath=r}changed(){this.emit("change")}flash(e,n=!1){this.message=e,this.messageIsError=n,this.changed()}appendLog(e,n){let r=this.synced.get(e);r&&(r.logs.push({time:_n(),text:n}),r.logs.length>yt&&r.logs.splice(0,r.logs.length-yt),this.changed())}siteCount(){return this.synced.size}syncingCount(){let e=0;for(let n of this.synced.values())n.status==="syncing"&&e++;return e}watchingCount(){let e=0;for(let n of this.synced.values())(n.status==="watching"||n.status==="syncing")&&e++;return e}async init(e){this.env=e;let{sites:n,hadLegacyLogin:r}=await le(this.configPath);this.saved=n.filter(s=>s.env===e),r&&this.flash("SleekCMS Sync now connects one site at a time \u2014 press a to add a site in your browser."),this.changed()}isSynced(e){return this.synced.has(e)}async connectSite(){if(this.connecting)return;let{verifier:e,challenge:n}=gt(),r=new AbortController;this.connecting={code:ht(n),url:"",abort:r},this.changed();let s=ft(await pt(this.env),n);if(r.signal.aborted){this.connecting=null,this.changed();return}this.connecting.url=s,this.message=void 0,this.changed(),this.openBrowser(s)||this.flash("Couldn't open a browser \u2014 open the address shown to continue.",!0);let i;try{let l=await mt(this.env,e,{...this.pollOptions,signal:r.signal});i=await wt(this.env,l)}catch(l){this.connecting=null,r.signal.aborted?this.changed():this.flash(Fn(l),!0);return}this.connecting=null;let d=await Pe(i,this.configPath);this.saved=d.filter(l=>l.env===this.env),this.flash(`Added "${i.name}".`),this.synced.has(i.siteId)||await this.startSite(i)}cancelConnect(){this.connecting?.abort.abort()}async startSite(e){let n=On(e);if(this.synced.has(n.id))return;let r={org:e.org,site:n,siteToken:e.token,role:e.role,viewsDir:"",status:"syncing",logs:[]};this.synced.set(n.id,r),this.appendLog(n.id,"\u2795 added \u2014 pulling files"),this.changed();try{let s=await Se({token:e.token,env:this.env,path:this.basePath,agentMd:this.agentMd,buildScript:this.buildScript,log:i=>this.appendLog(n.id,i),onProgress:(i,d)=>{r.progress={done:i,total:d},this.changed()}});this.noteRole(n.id,s.site.role),r.viewsDir=s.viewsDir,r.progress=void 0,r.status="watching",r.lastSyncedAt=Date.now(),r.lastMsg=`pulled ${s.pulled} file(s)`,r.watcher=new V({viewsDir:s.viewsDir,onSync:()=>this.runSync(n.id)}),r.watcher.start(),this.watchBuildStatus(n.id),this.seedLastBuild(n.id),this.appendLog(n.id,"\u{1F440} watching for changes")}catch(s){if(bt(s))return void await this.revoke(n.id);let i=s;r.status="error",r.progress=void 0,r.lastMsg=i.body||i.message,this.appendLog(n.id,`\u274C ${i.body||i.message}`)}this.changed()}noteRole(e,n){let r=this.synced.get(e);if(!n||!r||r.role===n)return;r.role=n;let s=this.saved.find(i=>i.siteId===e);s&&(s.role=n,Pe({...s},this.configPath).catch(()=>{}))}async revoke(e){let n=this.synced.get(e),r=n?.site.name??this.saved.find(d=>d.siteId===e)?.name??"this site";n&&(n.watcher?.setShuttingDown(!0),await n.watcher?.stop(),await n.buildWatcher?.close(),this.synced.delete(e));let s=await Ee(this.env,e,this.configPath);this.saved=s.filter(d=>d.env===this.env);let i=n?.viewsDir?` Local files kept in ${n.viewsDir}.`:"";this.flash(`Access to "${r}" was revoked \u2014 press a to add it again.${i}`,!0)}async forgetSite(e){if(this.synced.has(e)){this.flash("Disconnect it first (d), then press x to forget it.",!0);return}let n=this.saved.find(s=>s.siteId===e)?.name??"the site",r=await Ee(this.env,e,this.configPath);this.saved=r.filter(s=>s.env===this.env),this.flash(`Forgot "${n}". To revoke its access everywhere, log out of all sessions in SleekCMS.`)}async removeSite(e){let n=this.synced.get(e);n&&(n.watcher?.setShuttingDown(!0),await n.watcher?.stop(),await n.buildWatcher?.close(),await vt(n.viewsDir),this.synced.delete(e),this.changed())}buildSite(e,n=!1){let r=this.synced.get(e);if(!r||!r.viewsDir)return;if(r.role&&r.role!=="ADMIN"){this.flash(`Building and publishing are for site ADMINs \u2014 you're ${r.role} on "${r.site.name}".`,!0);return}let s=n?"live":"preview";this.writeBuildFile(r.viewsDir,{status:"building",mode:s,stage:"queued",url:r.lastBuild?.url,at:Date.now()}),jn("node",n?["build.mjs","--publish"]:["build.mjs"],{cwd:r.viewsDir,stdio:"ignore"}).on("error",l=>{this.writeBuildFile(r.viewsDir,{status:"error",mode:s,errors:[l.message],url:r.lastBuild?.url,at:Date.now()}),this.appendLog(e,`\u274C build: ${l.message}`)}),this.appendLog(e,n?"\u{1F680} publishing\u2026":"\u{1F528} building\u2026")}buildFile(e){return Me.join(e,".cache","build.json")}async readBuildFile(e){try{let n=await Z.readJson(this.buildFile(e));return n&&n.status?n:null}catch{return null}}async writeBuildFile(e,n){let r=this.buildFile(e),s=`${r}.tmp`;try{await Z.outputJson(s,n),await Z.rename(s,r)}catch{}}watchBuildStatus(e){let n=this.synced.get(e);!n||!n.viewsDir||(n.buildWatcher=An.watch(this.buildFile(n.viewsDir),{ignoreInitial:!1}).on("add",()=>{this.readBuildStatus(e)}).on("change",()=>{this.readBuildStatus(e)}))}async readBuildStatus(e){let n=this.synced.get(e);if(!n)return;let r=await this.readBuildFile(n.viewsDir);if(!r)return;let s=n.lastBuild?.url;n.lastBuild={status:r.status,mode:r.mode??"preview",url:r.url??(r.status==="success"?void 0:s),errors:r.errors,stage:r.stage,at:r.at},this.changed()}async seedLastBuild(e){let n=this.synced.get(e);if(!n)return;let r=await ut(this.env,n.siteToken);if(!r)return;let s=this.synced.get(e);if(!s)return;let i=await this.readBuildFile(s.viewsDir);i?.at!=null&&(r.at==null||i.at>=r.at)||await this.writeBuildFile(s.viewsDir,r)}async refetch(e){await this.runSync(e,{flush:!0})}async runSync(e,n={}){let r=this.synced.get(e);if(!(!r||!r.viewsDir||r.status==="paused")){r.status="syncing",this.changed();try{let s=await Se({token:r.siteToken,env:this.env,viewsDir:r.viewsDir,agentMd:this.agentMd,buildScript:this.buildScript,flush:n.flush,log:i=>this.appendLog(e,i),onProgress:(i,d)=>{r.progress={done:i,total:d},this.changed()}});if(this.noteRole(e,s.site.role),r.progress=void 0,r.status="watching",r.lastSyncedAt=Date.now(),n.flush)r.lastMsg=`re-fetched ${s.pulled} file(s)`;else{let i=[s.renamed>0?`renamed ${s.renamed}`:"",s.pushed>0?`pushed ${s.pushed} file(s)`:""].filter(Boolean);r.lastMsg=i.length>0?i.join(", "):"up to date"}}catch(s){if(bt(s))return void await this.revoke(e);let i=s;r.status="error",r.progress=void 0,r.lastMsg=i.body||i.message,this.appendLog(e,`\u274C ${i.body||i.message}`)}this.changed()}}async togglePause(e){let n=this.synced.get(e);!n||!n.viewsDir||(n.status==="paused"?(n.watcher=new V({viewsDir:n.viewsDir,onSync:()=>this.runSync(e)}),n.watcher.start(),n.status="watching",this.appendLog(e,"\u25B6 resumed \u2014 watching for changes")):(n.watcher?.setShuttingDown(!0),await n.watcher?.stop(),n.watcher=void 0,n.progress=void 0,n.status="paused",this.appendLog(e,"\u23F8 paused")),this.changed())}async cleanupAll(){this.cancelConnect();for(let e of this.synced.values())e.watcher?.setShuttingDown(!0),await e.watcher?.stop(),await e.buildWatcher?.close(),await vt(e.viewsDir)}async exit(){this.isShuttingDown||(this.isShuttingDown=!0,await this.cleanupAll(),this.emit("exit"))}};import{useInput as tr}from"ink";import{Fragment as Gn,useEffect as ee,useMemo as Un,useRef as Jn,useState as L}from"react";import{Box as p,Text as c,useInput as Hn,useStdout as zn}from"ink";import qn from"ink-text-input";import{createRequire as In}from"node:module";var Nn=In(import.meta.url),de=Nn("../package.json").version;import Wn from"node:os";function Re(t){if(!t)return"\u2014";let e=Wn.homedir();return t.startsWith(e)?"~"+t.slice(e.length):t}function Le(t){if(!t)return"\u2014";let e=Math.floor((Date.now()-t)/1e3);if(e<5)return"just now";if(e<60)return`${e}s ago`;let n=Math.floor(e/60);if(n<60)return`${n}m ago`;let r=Math.floor(n/60);return r<24?`${r}h ago`:`${Math.floor(r/24)}d ago`}function he(t){return!t||t.total<=0?null:Math.round(t.done/t.total*100)}var ge=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"];function De(t){return ge[(t%ge.length+ge.length)%ge.length]}function pe(t){switch(t){case"syncing":return{dot:"\u25CF",color:"green",label:"syncing"};case"watching":return{dot:"\u25CB",color:"gray",label:"watching"};case"paused":return{dot:"\u2016",color:"yellow",label:"paused"};case"error":return{dot:"\u2717",color:"red",label:"error"}}}function St(t){if(!t)return{dot:"\xB7",color:"gray",label:"\u2014"};switch(t.status){case"building":return{dot:"\u2234",color:"yellow",label:"building"};case"error":return{dot:"\u2717",color:"red",label:"failed"};case"success":return{dot:"\u2713",color:"green",label:t.mode==="live"?"live":"preview"}}}import{Fragment as je,jsx as o,jsxs as h}from"react/jsx-runtime";var Yn=(t,e)=>e<=0?0:Math.max(0,Math.min(t,e-1)),Xn=16,Kn=5,Vn="greenBright",xt="blueBright",Tt="magentaBright";function kt({k:t,bg:e=Vn}){return o(c,{color:"black",backgroundColor:e,children:` ${t} `})}function _({k:t,label:e,width:n=16,bg:r}){return h(p,{width:n,children:[o(kt,{k:t,bg:r}),o(c,{color:"gray",children:` ${e}`})]})}function $({k:t,label:e,bg:n}){return h(p,{marginBottom:1,children:[o(p,{width:9,children:o(kt,{k:t,bg:n})}),o(c,{color:"gray",children:e})]})}function Qn({launchers:t}){return h(p,{flexDirection:"column",borderStyle:"round",borderColor:"green",paddingX:2,paddingY:1,width:66,children:[h(p,{justifyContent:"space-between",children:[o(c,{color:"green",bold:!0,children:"KEYBOARD SHORTCUTS"}),o(c,{color:"gray",children:"? or esc to close"})]}),h(p,{marginTop:1,children:[h(p,{flexDirection:"column",width:34,children:[o(c,{color:"cyan",bold:!0,children:"Navigate"}),o($,{k:"\u2191\u2193",label:"move selection"}),o($,{k:"tab",label:"focus logs \xB7 \u2191\u2193 scroll"}),o($,{k:"esc",label:"clear filter / back"}),o(p,{marginTop:1,children:o(c,{color:"cyan",bold:!0,children:"Global"})}),o($,{k:"/",label:"search sites"}),o($,{k:"a",label:"add a site (browser)"}),o($,{k:"?",label:"toggle this help",bg:xt}),o($,{k:"ctrl+c",label:"quit"})]}),h(p,{flexDirection:"column",flexGrow:1,children:[o(c,{color:"cyan",bold:!0,children:"Site actions"}),o($,{k:"s",label:"start sync"}),o($,{k:"d",label:"disconnect"}),o($,{k:"x",label:"forget site"}),o($,{k:"p",label:"pause / resume sync"}),o($,{k:"b",label:"build preview"}),o($,{k:"B",label:"publish live"}),o($,{k:"o",label:"open preview url"}),t.map((e,n)=>o($,{k:String(n+1),label:`open in ${e.label}`,bg:Tt},e.key))]})]})]})}function Zn({percent:t,width:e=28}){let n=Math.round(Math.max(0,Math.min(100,t))/100*e);return h(c,{children:[o(c,{color:"green",children:"\u2588".repeat(n)}),o(c,{color:"gray",children:"\u2591".repeat(Math.max(0,e-n))})]})}function er({frame:t,width:e=24,seg:n=6}){let r=e+n,s=t%r-n,i="";for(let d=0;d<e;d++)i+=d>=s&&d<s+n?"\u25AE":"\u25AF";return o(c,{color:"yellow",children:i})}function $t({controller:t}){let{stdout:e}=zn(),n=Un(()=>Ze(),[]),[,r]=L(0),[s,i]=L(()=>new Date),[d,l]=L(null),[w,S]=L(""),[u,m]=L(!1),[v,g]=L(0),[y,E]=L(!1),[I,fe]=L(!1),[C,M]=L("list"),[H,D]=L(0),Fe=()=>r(a=>a+1);ee(()=>(t.on("change",Fe),()=>{t.off("change",Fe)}),[t]),ee(()=>{let a,x=()=>{i(new Date),a=setTimeout(x,6e4-Date.now()%6e4)};return a=setTimeout(x,6e4-Date.now()%6e4),()=>clearTimeout(a)},[]);let z=t.saved.map(a=>({org:a.org,site:{id:a.siteId,name:a.name,slug:a.slug},saved:a,entry:t.synced.get(a.siteId)})).sort((a,x)=>(a.entry?0:1)-(x.entry?0:1)),N=t.connecting,F=w.trim().toLowerCase(),P=F?z.filter(a=>a.site.name.toLowerCase().includes(F)||(a.org.name||a.org.subdomain||"").toLowerCase().includes(F)):z,W=P.findIndex(a=>a.site.id===d);W<0&&(W=0);let k=P[W],T=k?.entry,te=Math.max(3,(e?.rows??30)-26),O=T?.logs??[],me=Math.max(0,O.length-te),Ct=Math.min(H,me),ne=O.length-Ct,Oe=O.slice(Math.max(0,ne-te),ne),Mt=k?.site.id;ee(()=>D(0),[Mt]);let j=T?.lastBuild,we=j?.status==="building",ye=St(j),re=we||!!N;if(!re){for(let a of t.synced.values())if(a.status==="syncing"){re=!0;break}}ee(()=>{if(!re)return;let a=setInterval(()=>g(x=>x+1),120);return()=>clearInterval(a)},[re]);let Ie=P.findIndex(a=>!a.entry),G=Math.max(Kn,(e?.rows??30)-Xn),q=P.length,se=q>G,Rt=Math.floor(G/2),Y=se?Math.max(0,Math.min(W-Rt,q-G)):0,be=Math.min(q,Y+G),Lt=P.slice(Y,be),Ne=Jn(!1);ee(()=>{Ne.current||(Ne.current=!0,t.saved.length===0&&!t.connecting&&t.connectSite())},[t]);let ie=a=>{if(P.length===0)return;let x=Yn(W+a,P.length);l(P[x].site.id)},Dt=()=>{if(k){if(k.entry){t.flash("Already syncing \u2014 press d to disconnect.");return}t.startSite(k.saved)}},jt=()=>{k?.entry&&t.removeSite(k.site.id)},At=()=>{k&&t.forgetSite(k.site.id)},_t=a=>{if(!T){t.flash("Press s to start syncing this site first.",!0);return}fe(!0);let x=a.run(T.viewsDir);t.flash(x?`Opened ${a.label} at ${Re(T.viewsDir)}`:`Couldn't open ${a.label}.`,!x)},Ft=()=>{if(!T){t.flash("Press s to start syncing this site first.",!0);return}t.togglePause(T.site.id)},We=a=>{if(!T){t.flash("Press s to start syncing this site first.",!0);return}t.buildSite(T.site.id,a),t.flash(a?"Publishing \u2014 making this live\u2026":"Building preview\u2026")},Ot=()=>{let a=T?.lastBuild?.url;if(!a){t.flash("No build URL yet \u2014 press b to build.",!0);return}t.flash(ae(a)?`Opening ${a}`:"Couldn't open the browser.",!1)};Hn((a,x)=>{if(y){(a==="?"||x.escape)&&E(!1);return}if(N&&x.escape)return void t.cancelConnect();if(u){x.escape?(m(!1),S(""),l(null)):x.return?m(!1):x.upArrow?ie(-1):x.downArrow&&ie(1);return}if(x.tab){C==="logs"?M("list"):T&&M("logs"),D(0);return}if(C==="logs"){if(x.escape){M("list"),D(0);return}if(x.upArrow)return void D(A=>Math.min(A+1,me));if(x.downArrow)return void D(A=>Math.max(0,A-1))}if(x.escape){S(""),l(null);return}if(a==="?")return void E(!0);if(a==="/")return M("list"),void m(!0);if(a==="a"||a==="n")return void t.connectSite();if(x.upArrow)return ie(-1);if(x.downArrow)return ie(1);if(a==="s")return Dt();if(a==="d")return jt();if(a==="x")return At();if(a==="p")return Ft();if(a==="b")return We(!1);if(a==="B")return We(!0);if(a==="o")return Ot();if(a>="1"&&a<="9"){let A=n[parseInt(a,10)-1];if(A)return _t(A)}});let Ge=h(p,{justifyContent:"space-between",paddingX:1,children:[h(p,{children:[o(c,{color:"green",bold:!0,children:"\u25C6 SleekCMS"}),o(c,{color:"gray",children:` v${de} \u2502 `}),o(c,{children:t.env==="production"?"Sync":`Sync \xB7 ${t.env}`})]}),h(p,{children:[h(c,{color:"gray",children:[F?`${P.length}/${z.length}`:z.length," sites \xB7 "]}),h(c,{color:"green",children:[t.watchingCount()," watching"]}),o(c,{color:"gray",children:` \xB7 ${s.toTimeString().slice(0,5)}`})]})]});return y?h(p,{flexDirection:"column",children:[Ge,o(p,{marginTop:1,justifyContent:"center",children:o(Qn,{launchers:n})})]}):h(p,{flexDirection:"column",children:[Ge,h(p,{children:[h(p,{flexDirection:"column",borderStyle:"round",borderColor:"green",width:38,paddingX:1,children:[h(p,{justifyContent:"space-between",children:[o(c,{color:"green",bold:!0,children:"SITE WORKSPACES"}),z.length>G&&!u&&!F?o(c,{color:"gray",children:"/ filter"}):null]}),u?h(p,{children:[o(c,{color:"cyan",children:"/ "}),o(qn,{value:w,onChange:S,onSubmit:()=>m(!1),placeholder:"type to filter\u2026"})]}):F?o(c,{color:"gray",children:`/ ${w} \xB7 ${P.length} match${P.length===1?"":"es"}`}):null,o(p,{flexDirection:"column",marginTop:1,minHeight:se?G+3:void 0,children:P.length===0?o(c,{color:"gray",children:F?`no matches for \u201C${w}\u201D`:"no sites yet \u2014 press a to add one"}):h(je,{children:[se?o(c,{color:"gray",children:Y>0?` \u2191 ${Y} more`:" "}):null,Lt.map((a,x)=>{let A=Y+x,Ue=a.entry?pe(a.entry.status):{dot:"\xB7",color:"gray",label:"idle"},Je=he(a.entry?.progress),It=a.entry?a.entry.status==="syncing"&&Je!=null?`${Je}%`:a.entry.status==="paused"?"paused":"--":"",oe=A===W,Nt=A===Ie&&Ie>0;return h(Gn,{children:[Nt?o(c,{color:"gray",children:"\u2500".repeat(34)}):null,h(p,{justifyContent:"space-between",children:[h(p,{children:[o(c,{color:oe?"green":"gray",children:oe?"\u276F ":" "}),h(c,{color:a.entry?.status==="watching"||a.entry?.status==="syncing"?"green":Ue.color,children:[a.entry?.status==="syncing"?De(v):a.entry?.status==="watching"?"\u25CF":Ue.dot," "]}),o(c,{color:oe?"white":a.entry?void 0:"gray",bold:oe,children:a.site.name})]}),o(c,{color:a.entry?.status==="syncing"?"green":"gray",children:It})]})]},a.site.id)}),se?o(c,{color:"gray",children:be<q?` \u2193 ${q-be} more`:" "}):null]})}),o(p,{marginTop:1,children:o(c,{color:"gray",children:"+ add site \xB7 a"})})]}),h(p,{flexDirection:"column",flexGrow:1,marginLeft:1,children:[o(p,{flexDirection:"column",borderStyle:"round",borderColor:"gray",paddingX:1,children:k?h(je,{children:[h(c,{children:[k.org.name||k.org.subdomain?h(c,{color:"gray",children:[k.org.name||k.org.subdomain," / "]}):null,o(c,{color:"cyan",bold:!0,children:k.site.name})]}),h(p,{marginTop:1,children:[o(c,{color:"gray",children:"status "}),T?o(c,{color:pe(T.status).color,children:`: ${pe(T.status).label}`}):o(c,{color:"gray",children:": idle \u2014 not syncing (press s to start)"})]}),h(p,{children:[o(c,{color:"gray",children:"role "}),o(c,{children:T?.role??k.saved.role??"\u2014"}),(T?.role??k.saved.role??"ADMIN")!=="ADMIN"?o(c,{color:"gray",children:" \xB7 build & publish need ADMIN"}):null]}),h(p,{children:[o(c,{color:"gray",children:"path "}),o(c,{wrap:"truncate-end",children:T?.viewsDir?Re(T.viewsDir):"\u2014"})]}),h(p,{children:[o(c,{color:"gray",children:"synced "}),o(c,{children:Le(T?.lastSyncedAt)}),o(c,{color:"gray",children:" progress "}),o(c,{color:T?.status==="syncing"?"green":"gray",children:T?.status==="syncing"?`${he(T.progress)??0}%`:"\u2014"})]}),o(p,{marginTop:1,children:o(Zn,{percent:T?T.status==="syncing"?he(T.progress)??0:T.status==="watching"?100:0:0})}),T?h(je,{children:[h(p,{marginTop:1,children:[o(c,{color:"gray",children:"build "}),o(c,{color:ye.color,children:`${ye.dot} ${ye.label}`}),o(c,{color:"gray",children:" last "}),o(c,{children:we?"in progress":Le(j?.at)})]}),h(p,{children:[o(c,{color:"gray",children:"url "}),j?.url?o(c,{color:"cyan",wrap:"truncate-end",children:j.url}):o(c,{color:"gray",children:"\u2014"})]}),j?.status==="error"&&j.errors?.length?h(p,{children:[o(c,{color:"red",children:"\u258C "}),o(c,{color:"red",wrap:"truncate-end",children:`\u2717 ${j.errors[0]}`})]}):null,we?h(p,{children:[o(er,{frame:v}),o(c,{color:"gray",children:` ${j?.stage??"building"}`})]}):null]}):null]}):o(c,{color:"gray",children:"No site selected."})}),N?h(p,{flexDirection:"column",borderStyle:"round",borderColor:"blue",paddingX:1,marginTop:1,flexGrow:1,children:[o(c,{color:"cyan",bold:!0,children:"ADD A SITE"}),o(c,{children:"Approve it in your browser: pick a site, or create one."}),h(p,{marginTop:1,children:[o(c,{color:"gray",children:"Check the page shows "}),o(c,{color:"cyan",bold:!0,children:N.code})]}),o(c,{color:"gray",children:"Only approve a page that shows this code."}),h(p,{marginTop:1,children:[h(c,{color:"yellow",children:[De(v)," "]}),o(c,{color:"gray",children:"waiting for approval \xB7 esc to cancel"})]})]}):h(p,{flexDirection:"column",borderStyle:"round",borderColor:C==="logs"?"green":"gray",paddingX:1,marginTop:1,height:te+4,flexShrink:0,overflowY:"hidden",children:[h(p,{justifyContent:"space-between",children:[h(c,{children:[o(c,{color:"cyan",bold:!0,children:"LOGS \xB7 "}),o(c,{color:"white",children:k?.site.name??"\u2014"})]}),T&&O.length>0?C==="logs"?o(c,{color:"green",children:`\u2191\u2193 scroll \xB7 esc back${me>0?` \xB7 ${ne}/${O.length}`:""}`}):O.length>te?o(c,{color:"gray",children:"tab to scroll"}):null:null]}),o(p,{flexDirection:"column",marginTop:1,children:!T||O.length===0?o(c,{color:"gray",children:"no activity yet"}):Oe.map((a,x)=>h(c,{wrap:"truncate-end",children:[h(c,{color:"gray",children:[a.time," "]}),a.text]},ne-Oe.length+x))})]})]})]}),N?.url?h(p,{flexDirection:"column",paddingX:1,marginTop:1,children:[o(c,{color:"gray",children:"No browser? Open this address on any device:"}),o(c,{color:"cyan",children:N.url})]}):null,t.message?o(p,{paddingX:1,children:h(c,{color:t.messageIsError?"red":"gray",wrap:"truncate-end",children:[t.messageIsError?"\u2717 ":"",t.message]})}):null,h(p,{flexDirection:"column",marginTop:1,children:[h(p,{paddingX:1,justifyContent:"space-between",children:[h(p,{flexWrap:"wrap",children:[o(_,{k:"\u2191\u2193",label:"select"}),o(_,{k:"/",label:"search"}),o(_,{k:"s",label:"start sync"}),o(_,{k:"d",label:"disconnect"}),o(_,{k:"a",label:"add site"}),o(_,{k:"ctrl+c",label:"quit",width:14})]}),o(_,{k:"?",label:"all keys",width:12,bg:xt})]}),!I&&n.length>0?o(p,{paddingX:1,marginTop:1,flexWrap:"wrap",children:n.map((a,x)=>o(_,{k:String(x+1),label:a.label,bg:Tt},a.key))}):null]})]})}import{jsx as nr}from"react/jsx-runtime";function Bt({controller:t}){return tr((e,n)=>{n.ctrl&&e==="c"&&t.exit()}),nr($t,{controller:t})}import{jsx as cr}from"react/jsx-runtime";var Ae=Ke();Ae.version&&(console.log(de),process.exit(0));var Et=_e.dirname(rr(import.meta.url)),ir=Pt(_e.join(Et,"AGENTS.md"),"utf-8"),or=Pt(_e.join(Et,"build.mjs"),"utf-8");async function ar(){let t=new ue(ir,or);t.basePath=Ae.path,await t.init((Ae.env??"production").toLowerCase()),process.stdout.isTTY&&process.stdout.write("\x1B[2J\x1B[3J\x1B[H");let e=sr(cr(Bt,{controller:t}),{exitOnCtrlC:!1}),n=r=>{e.unmount(),console.log(r),process.exit(0)};t.once("exit",()=>n("\u2713 Stopped. Local site files were cleaned up.")),process.on("SIGINT",()=>{t.exit()}),process.on("SIGTERM",()=>{t.exit()}),await e.waitUntilExit()}ar().catch(t=>{let e=t;console.error("\u274C",e.body||e.message),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sleekcms/sync",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
4
4
  "description": "Edit SleekCMS sites locally — models, content, templates, images — with live two-way sync and AI agent support.",
5
5
  "keywords": [
6
6
  "sleekcms",