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