@sleekcms/sync 3.0.0 → 3.1.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 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",`
|
|
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(e){let t=process.platform==="win32"?`where ${e}`:`which ${e}`;try{return Ye(t,{stdio:"ignore"}),!0}catch{return!1}}function Ke(e){if(process.platform!=="darwin")return!1;try{return Ye(`osascript -e 'id of application "${e}"'`,{stdio:"ignore"}),!0}catch{return!1}}function Ot(e,t){let n={detached:!0,stdio:"ignore",windowsHide:!0};process.platform==="win32"?B("cmd.exe",["/c",e,...t],n).unref():B(e,t,n).unref()}var ze=[{name:"VS Code",cmd:"code",args:e=>["-n",e]},{name:"Cursor",cmd:"cursor",args:e=>["-n",e]}];function qe(e,t){let r=(t?ze.filter(s=>s.cmd===t):ze).find(s=>R(s.cmd));return r?(Ot(r.cmd,r.args(e)),r.name):null}function It(e){if(process.platform==="darwin")return B("open",["-a","Terminal",e],{detached:!0,stdio:"ignore"}).unref(),!0;if(process.platform==="win32"){if(R("wt"))B("wt.exe",["-d",e],{detached:!0,stdio:"ignore"}).unref();else{let t=R("powershell")?"powershell.exe":"cmd.exe";B("cmd.exe",["/c","start","",t],{cwd:e,detached:!0,stdio:"ignore"}).unref()}return!0}return!1}function Nt(e){return Ke("iTerm")?(B("open",["-a","iTerm",e],{detached:!0,stdio:"ignore"}).unref(),!0):!1}function Wt(e){return`'${e.replace(/'/g,"'\\''")}'`}var Gt=[{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 Ve(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 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",e,"cmd","/k",t],{detached:!0,stdio:"ignore"}).unref():B("cmd.exe",["/c","start","","cmd","/k",t],{cwd:e,detached:!0,stdio:"ignore"}).unref(),!0;let n=`cd ${Wt(e)} && ${t}; exec bash`;for(let r of Gt)if(R(r.cmd))try{return B(r.cmd,r.args(n),{cwd:e,detached:!0,stdio:"ignore"}).unref(),!0}catch{}return!1}function Ut(e){return Ve(e,"claude")}function Jt(e){return Ve(e,"pi")}function ae(e){if(!e)return!1;try{let t=process.platform==="darwin"?B("open",[e],{detached:!0,stdio:"ignore"}):process.platform==="win32"?B("cmd.exe",["/c","start","",e],{detached:!0,stdio:"ignore",windowsHide:!0}):B("xdg-open",[e],{detached:!0,stdio:"ignore"});return t.on("error",()=>{}),t.unref(),!0}catch{return!1}}function Qe(){let e=process.platform==="darwin",t=process.platform==="win32",n=[];return(e||t)&&n.push({key:"terminal",label:"terminal",run:It}),Ke("iTerm")&&n.push({key:"iterm",label:"iterm",run:Nt}),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:Ut}),R("pi")&&n.push({key:"pi",label:"pi",run:Jt}),n}import{EventEmitter as Cn}from"node:events";import{spawn as Mn}from"node:child_process";import Z from"fs-extra";import Ce from"path";import Rn from"chokidar";import{createHash as zt}from"crypto";import f from"fs-extra";import qt 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"},Yt=["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(t,n,r){super(t),this.status=n,this.body=r}};async function ce(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 X(`${n} ${r} \u2192 ${i.status}: ${d}`,i.status,d)}return i.json()}var Xt=["AGENT.md","CLAUDE.md",b.join(".vscode","copilot-instructions.md")],Kt="mrmlnc.vscode-json5";async function Vt(e,t){t&&(await f.outputFile(b.join(e,"AGENTS.md"),t),await Promise.all(Xt.map(n=>f.remove(b.join(e,n))))),await f.outputFile(b.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 f.outputFile(b.join(e,".vscode","extensions.json"),JSON.stringify({recommendations:[Kt]},null,2))}async function Qt(e,t){if(!t)return;let n=b.join(e,"build.mjs"),r=t.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,t)}async function Zt(e,t,n,r){let s=b.join(e,".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(e)),await f.outputJson(s,n),await f.outputFile(b.join(e,".cache","token"),t)}function en(e,t){let n=`${t.name.substr(0,20)} ${t.id}`.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,""),r=e||b.join(qt.homedir(),"SleekCMS");return b.resolve(r,n)}async function ve(e){let t=(e.token||"").trim();if(!t)throw new Error("syncSite: token is required");let n=e.log??(S=>console.log(S)),r=e.onProgress,s=(e.env||"production").toLowerCase(),i=Ze[s]||Ze.production,d=await ce(i,t,"GET","/get_site"),l=e.viewsDir?b.resolve(e.viewsDir):en(e.path,d);await f.ensureDir(l),await Zt(l,t,{env:s,slug:String(d.id)},n),await Promise.all(Yt.map(S=>f.ensureDir(b.join(l,S)))),await Qt(l,e.buildScript);let y=b.join(l,".cache","state.json");e.flush&&await f.remove(y);let v=!await f.pathExists(y),u=v?{}:(await f.readJson(y)).fileMap||{},m=0,w=0,h=0;if(v)({fileMap:u,pulled:w}=await fn(l,i,t,n,r)),await Vt(l,e.agentMd);else{let S=await hn(l,u,i,t,n);h=S.renamed,m=await nn(l,u,i,t,n,r,S.held)}return await f.outputJson(y,{fileMap:u},{spaces:2}),{viewsDir:l,site:d,isFirstRun:v,pushed:m,pulled:w,renamed:h}}var K=e=>zt("sha1").update(e).digest("hex"),tn=new Set([".DS_Store","Thumbs.db","desktop.ini"]);async function Se(e){let t=b.join(e,"src");if(!await f.pathExists(t))return[];let n=[];async function r(s){let i=await f.readdir(s,{withFileTypes:!0});for(let d of i){if(tn.has(d.name))continue;let l=b.join(s,d.name);d.isDirectory()?await r(l):d.isFile()&&n.push(b.relative(e,l).replace(/\\/g,"/"))}}return await r(t),n}async function nn(e,t,n,r,s,i,d=new Set){let l=[];for(let w of await Se(e)){if(d.has(w))continue;let h=b.join(e,w),S=t[w],E=await f.stat(h);if(S&&S.mtimeMs===E.mtimeMs){S.hash||(S.hash=K(await f.readFile(h,"utf-8")));continue}let I=await f.readFile(h,"utf-8");I.trim()&&l.push({rel:w,full:h,stat:E,content:I,prior:S})}if(l.length===0)return 0;let y;try{y=await ce(n,r,"POST","/save_files",l.map(w=>({path:w.rel,content:w.content})))}catch(w){let h=w;return s(`\u274C Error saving files: ${h.body||h.message}`),0}let v=await nt(e),u=0,m=rn(y);for(let w=0;w<l.length;w++){let h=l[w],S=sn(h,w,y,m);if(i?.(w+1,l.length),!S){let E="No save response returned";v[h.rel]=E,s(`\u274C Error saving ${h.rel}: ${E}`);continue}if(S.error){v[h.rel]=S.error,s(`\u274C Error saving ${h.rel}: ${S.error}`);continue}delete v[h.rel],t[h.rel]={mtimeMs:h.stat.mtimeMs,hash:K(h.content)},s(`\u2705 ${h.prior?"Updated":"Created"} ${h.rel}`),u++}return await rt(e,v),u}function rn(e){let t=new Map;for(let n of e)n.path&&t.set(n.path,n);return t}function sn(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 et=/^src\/(?:(?:models|views)\/(?:pages|entries|blocks)|content\/(?:pages|entries))\//,on={PAGE:"pages",ENTRY:"entries",BLOCK:"blocks"},an=e=>e.split("/").slice(0,3).join("/");function cn(e,t,n){let r=new Map,s=(i,d)=>{let l=`${an(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 ln(e,t){let n=new Map,r=(s,i,d,l,y)=>{let v=n.get(s);v?(v.pairs.push(y),i<v.rank&&Object.assign(v,{from:d,to:l,rank:i})):n.set(s,{from:d,to:l,rank:i,pairs:[y]})};for(let s of e){let[,i,d,...l]=s.from.split("/"),y=s.to.split("/").slice(3);if(i==="content"&&d==="pages"&&l.length>1){let[u,...m]=l,[w,...h]=y;if(h.length===0)continue;w===u?r(`record:${s.from}`,0,s.from,s.to,s):m.join("/")===h.join("/")&&![...t].some(S=>S.startsWith(`src/content/pages/${u}/`))&&r(`pages:${u}`,3,`src/content/pages/${u}`,`src/content/pages/${w}`,s);continue}let v=l.join("/").replace(/\.[^./]+$/,"");r(`${d}:${v}`,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 tt(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=on[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}${b.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 un(e,t){let n=e;for(;n.startsWith(t+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 dn(e,t,n,r){let s=u=>b.join(e,u),i=b.join(e,"src"),d=u=>b.resolve(e,u).startsWith(i+b.sep),l=async(u,m)=>{t[u]={mtimeMs:(await f.stat(s(u))).mtimeMs,hash:m}},y=u=>un(b.dirname(s(u)),b.join(e,...u.split("/").slice(0,3))),v=[];for(let u of r){let m=tt(n.rename,u.from)??u.to;d(m)&&(m!==u.to&&(await f.move(s(u.to),s(m),{overwrite:!0}),await y(u.to),v.push(u.to)),delete t[u.from],v.push(u.from),await l(m,u.hash))}for(let u of new Set([...await Se(e),...Object.keys(t)])){let m=tt(n.rename,u);if(!m||!d(m))continue;let w=await f.pathExists(s(u));if(w&&await f.pathExists(s(m)))continue;let h=t[u];if(delete t[u],v.push(u),!w)continue;let S=!!h?.hash&&h.mtimeMs===(await f.stat(s(u))).mtimeMs;await f.move(s(u),s(m)),S&&await l(m,h.hash),await y(u)}for(let u of n.files||[]){let m=t[u.path];if(!m||!d(u.path))continue;let w=await f.stat(s(u.path)).catch(()=>null);!w||w.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 v}function gn(e){try{let t=JSON.parse(e.body).message;if(t)return t}catch{}return(e.body||e.message||String(e)).slice(0,300)}async function hn(e,t,n,r,s){let i=new Set,d=await Se(e),l=new Set(d),y=Object.keys(t).filter(h=>!l.has(h)&&t[h].hash&&et.test(h));if(y.length===0)return{renamed:0,held:i};let v=new Map;for(let h of d){if(t[h]||!et.test(h))continue;let S=await f.readFile(b.join(e,h),"utf-8");S.trim()&&v.set(h,K(S))}let u=ln(cn(y,v,t),l);if(u.length===0)return{renamed:0,held:i};let m=await nt(e),w=0;for(let h of u){let S;try{S=await ce(n,r,"POST","/rename",{from:h.from,to:h.to})}catch(C){let M=C,H=gn(M);if(M.status>=400&&M.status<500)s(`\u26A0\uFE0F Couldn't rename ${h.from} \u2192 ${h.to}: ${H} Saving it as a new file.`);else{for(let D of h.pairs)i.add(D.to),m[D.to]=`rename from ${D.from} failed: ${H}`;s(`\u274C Error renaming ${h.from} \u2192 ${h.to}: ${H}`)}continue}let E=await dn(e,t,S,h.pairs);for(let C of[...E,...h.pairs.map(M=>M.to)])delete m[C];let[I,...pe]=S.message.split(`
|
|
7
|
-
`);s(`\u{1F500} ${I}`);for(let
|
|
8
|
-
`)){let i=s.indexOf(": ");i>0&&(r[s.slice(0,i)]=s.slice(i+2))}return r}async function
|
|
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(`
|
|
9
9
|
`)+`
|
|
10
|
-
`)}async function fn(e,t,n,r,s){be.delete(b.resolve(e)),await f.remove(b.join(e,xe)),r("\u{1F4E5} Fetching files...");let i=await ce(t,n,"GET","/get_files"),d={},l=0;for(let y of i){let v=b.join(e,y.path);await f.outputFile(v,y.content);let u=(await f.stat(v)).mtimeMs;l++,s?.(l,i.length),d[y.path]={mtimeMs:u,hash:K(y.content)}}return r(`\u2714\uFE0F Synced ${i.length} file(s).`),{fileMap:d,pulled:l}}import mn from"path";import wn from"chokidar";var yn=5e3,bn=/(^|[/\\])(\.DS_Store|Thumbs\.db|desktop\.ini)$/,V=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??yn}start(){if(this.watcher)return;let t=mn.join(this.viewsDir,"src");this.watcher=wn.watch([t],{persistent:!0,ignoreInitial:!0,ignored:bn}).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 Te from"fs-extra";import vn from"os";import it from"path";var st={localhost:"http://app.sleekcms.test/api",development:"https://app.sleekcms.dev/api",production:"https://app.sleekcms.com/api"};function Q(e){return st[e]||st.production}function $e(e){return Q(e).replace(/\/api$/,"")}var Sn=it.join(vn.homedir(),"SleekCMS"),U=it.join(Sn,"auth.json"),ke=class extends Error{status;body;constructor(t,n,r=""){super(t),this.name="ApiError",this.status=n,this.body=r}};async function le(e=U){let t=null;try{t=await Te.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 ot(e,t=U){await Te.outputJson(t,{sites:e},{spaces:2});try{await Te.chmod(t,384)}catch{}}async function Be(e,t=U){let{sites:n}=await le(t),r=[...n.filter(s=>!(s.env===e.env&&s.siteId===e.siteId)),e];return await ot(r,t),r}async function Pe(e,t,n=U){let{sites:r}=await le(n),s=r.filter(i=>!(i.env===e&&i.siteId===t));return await ot(s,n),s}async function Ee(e,t,n,r){let s=await fetch(Q(e)+r,{method:n,headers:{Authorization:`Bearer ${t}`}});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 xn(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:"",y=n&&r&&r!==n?` (on page ${r})`:"";if(s)return`${s}${i}${d}${y}: ${l||"(no message)"}`;if(l)return l;try{return JSON.stringify(e)}catch{return"(unknown error)"}}async function at(e,t){let n;try{n=await Ee(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(xn):[];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 Tn,randomBytes as kn}from"crypto";var $n="urn:sleekcms:grant-type:cli_poll",Bn="SleekCMS Sync",ct=e=>e.toString("base64").replace(/=+$/,"").replace(/\+/g,"-").replace(/\//g,"_");function lt(){let e=ct(kn(32)),t=ct(Tn("sha256").update(e).digest());return{verifier:e,challenge:t}}function ut(e){let t=e.replace(/[^A-Za-z0-9]/g,"").slice(0,8).toUpperCase();return`${t.slice(0,4)}-${t.slice(4)}`}async function dt(e,t=fetch){let n={origin:$e(e),authorizeEndpoint:`${Q(e)}/oauth/authorize`};try{let r=await t(`${$e(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 gt(e,t){let n=new URLSearchParams({response_type:"code",client_name:Bn,redirect_uri:`${e.origin}/oauth/cli-done`,code_challenge:t,code_challenge_method:"S256",resource:`${e.origin}/mcp/`});return`${e.authorizeEndpoint}?${n.toString()}`}var J=class extends Error{constructor(t){super(t),this.name="SignInError"}},Pn=e=>new Promise(t=>setTimeout(t,e));async function ht(e,t,n={}){let{timeoutMs:r=10*6e4,signal:s,fetchImpl:i=fetch,sleep:d=Pn}=n,l=n.intervalMs??2e3,y=Date.now()+r,v=`${Q(e)}/oauth/token`;for(;;){if(s?.aborted)throw new J("Cancelled.");let u=null;try{u=await i(v,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({grant_type:$n,code_verifier:t})})}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>y)throw new J("Timed out waiting for approval in the browser.");await d(l)}}function En(e){let t=e.split(".")[1];if(!t)throw new J("The server returned a token this version can't read.");return JSON.parse(Buffer.from(t,"base64url").toString("utf8"))}async function pt(e,t){let n=En(t),r=await Ee(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 ft=500;function Ln(){return new Date().toTimeString().slice(0,8)}function Dn(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 mt(e){return e instanceof X&&e.status===401}var jn=e=>({id:e.siteId,name:e.name,slug:e.slug});async function wt(e){e&&(await Z.remove(Ce.join(e,"src")),await Z.remove(Ce.join(e,".cache","state.json")))}var ue=class extends Cn{env="production";saved=[];synced=new Map;connecting=null;message;messageIsError=!1;agentMd;buildScript;configPath;isShuttingDown=!1;basePath;pollOptions={};openBrowser=ae;constructor(t,n,r=U){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:Ln(),text:n}),r.logs.length>ft&&r.logs.splice(0,r.logs.length-ft),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 le(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}=lt(),r=new AbortController;this.connecting={code:ut(n),url:"",abort:r},this.changed();let s=gt(await dt(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 ht(this.env,t,{...this.pollOptions,signal:r.signal});i=await pt(this.env,l)}catch(l){this.connecting=null,r.signal.aborted?this.changed():this.flash(Dn(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(t){let n=jn(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 ve({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 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(mt(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,Be({...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 Pe(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 Pe(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 wt(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()}),Mn("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 Ce.join(t,".cache","build.json")}async readBuildFile(t){try{let n=await Z.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 Z.outputJson(s,n),await Z.rename(s,r)}catch{}}watchBuildStatus(t){let n=this.synced.get(t);!n||!n.viewsDir||(n.buildWatcher=Rn.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 at(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 ve({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(mt(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 V({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 wt(t.viewsDir)}async exit(){this.isShuttingDown||(this.isShuttingDown=!0,await this.cleanupAll(),this.emit("exit"))}};import{useInput as Xn}from"ink";import{Fragment as Fn,useEffect as ee,useMemo as _n,useRef as On,useState as L}from"react";import{Box as p,Text as c,useInput as In,useStdout as Nn}from"ink";import Wn from"ink-text-input";import An from"node:os";function Me(e){if(!e)return"\u2014";let t=An.homedir();return e.startsWith(t)?"~"+e.slice(t.length):e}function Re(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 ge(e){return!e||e.total<=0?null:Math.round(e.done/e.total*100)}var de=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"];function Le(e){return de[(e%de.length+de.length)%de.length]}function he(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 yt(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 De,jsx as o,jsxs as g}from"react/jsx-runtime";var Gn=(e,t)=>t<=0?0:Math.max(0,Math.min(e,t-1)),Un=16,Jn=5,Hn="greenBright",bt="blueBright",vt="magentaBright";function St({k:e,bg:t=Hn}){return o(c,{color:"black",backgroundColor:t,children:` ${e} `})}function F({k:e,label:t,width:n=16,bg:r}){return g(p,{width:n,children:[o(St,{k:e,bg:r}),o(c,{color:"gray",children:` ${t}`})]})}function $({k:e,label:t,bg:n}){return g(p,{marginBottom:1,children:[o(p,{width:9,children:o(St,{k:e,bg:n})}),o(c,{color:"gray",children:t})]})}function zn({launchers:e}){return g(p,{flexDirection:"column",borderStyle:"round",borderColor:"green",paddingX:2,paddingY:1,width:66,children:[g(p,{justifyContent:"space-between",children:[o(c,{color:"green",bold:!0,children:"KEYBOARD SHORTCUTS"}),o(c,{color:"gray",children:"? or esc to close"})]}),g(p,{marginTop:1,children:[g(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:bt}),o($,{k:"ctrl+c",label:"quit"})]}),g(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"}),e.map((t,n)=>o($,{k:String(n+1),label:`open in ${t.label}`,bg:vt},t.key))]})]})]})}function qn({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 Yn({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 xt({controller:e}){let{stdout:t}=Nn(),n=_n(()=>Qe(),[]),[,r]=L(0),[s,i]=L(()=>new Date),[d,l]=L(null),[y,v]=L(""),[u,m]=L(!1),[w,h]=L(0),[S,E]=L(!1),[I,pe]=L(!1),[C,M]=L("list"),[H,D]=L(0),Fe=()=>r(a=>a+1);ee(()=>(e.on("change",Fe),()=>{e.off("change",Fe)}),[e]),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=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,x)=>(a.entry?0:1)-(x.entry?0:1)),N=e.connecting,_=y.trim().toLowerCase(),P=_?z.filter(a=>a.site.name.toLowerCase().includes(_)||(a.org.name||a.org.subdomain||"").toLowerCase().includes(_)):z,W=P.findIndex(a=>a.site.id===d);W<0&&(W=0);let k=P[W],T=k?.entry,te=Math.max(3,(t?.rows??30)-26),O=T?.logs??[],fe=Math.max(0,O.length-te),Bt=Math.min(H,fe),ne=O.length-Bt,_e=O.slice(Math.max(0,ne-te),ne),Pt=k?.site.id;ee(()=>D(0),[Pt]);let j=T?.lastBuild,me=j?.status==="building",we=yt(j),re=me||!!N;if(!re){for(let a of e.synced.values())if(a.status==="syncing"){re=!0;break}}ee(()=>{if(!re)return;let a=setInterval(()=>h(x=>x+1),120);return()=>clearInterval(a)},[re]);let Oe=P.findIndex(a=>!a.entry),G=Math.max(Jn,(t?.rows??30)-Un),q=P.length,se=q>G,Et=Math.floor(G/2),Y=se?Math.max(0,Math.min(W-Et,q-G)):0,ye=Math.min(q,Y+G),Ct=P.slice(Y,ye),Ie=On(!1);ee(()=>{Ie.current||(Ie.current=!0,e.saved.length===0&&!e.connecting&&e.connectSite())},[e]);let ie=a=>{if(P.length===0)return;let x=Gn(W+a,P.length);l(P[x].site.id)},Mt=()=>{if(k){if(k.entry){e.flash("Already syncing \u2014 press d to disconnect.");return}e.startSite(k.saved)}},Rt=()=>{k?.entry&&e.removeSite(k.site.id)},Lt=()=>{k&&e.forgetSite(k.site.id)},Dt=a=>{if(!T){e.flash("Press s to start syncing this site first.",!0);return}pe(!0);let x=a.run(T.viewsDir);e.flash(x?`Opened ${a.label} at ${Me(T.viewsDir)}`:`Couldn't open ${a.label}.`,!x)},jt=()=>{if(!T){e.flash("Press s to start syncing this site first.",!0);return}e.togglePause(T.site.id)},Ne=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")},At=()=>{let a=T?.lastBuild?.url;if(!a){e.flash("No build URL yet \u2014 press b to build.",!0);return}e.flash(ae(a)?`Opening ${a}`:"Couldn't open the browser.",!1)};In((a,x)=>{if(S){(a==="?"||x.escape)&&E(!1);return}if(N&&x.escape)return void e.cancelConnect();if(u){x.escape?(m(!1),v(""),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,fe));if(x.downArrow)return void D(A=>Math.max(0,A-1))}if(x.escape){v(""),l(null);return}if(a==="?")return void E(!0);if(a==="/")return M("list"),void m(!0);if(a==="a"||a==="n")return void e.connectSite();if(x.upArrow)return ie(-1);if(x.downArrow)return ie(1);if(a==="s")return Mt();if(a==="d")return Rt();if(a==="x")return Lt();if(a==="p")return jt();if(a==="b")return Ne(!1);if(a==="B")return Ne(!0);if(a==="o")return At();if(a>="1"&&a<="9"){let A=n[parseInt(a,10)-1];if(A)return Dt(A)}});let We=g(p,{justifyContent:"space-between",paddingX:1,children:[g(p,{children:[o(c,{color:"green",bold:!0,children:"\u25C6 SleekCMS"}),o(c,{color:"gray",children:" \u2502 "}),o(c,{children:e.env==="production"?"Sync":`Sync \xB7 ${e.env}`})]}),g(p,{children:[g(c,{color:"gray",children:[_?`${P.length}/${z.length}`:z.length," sites \xB7 "]}),g(c,{color:"green",children:[e.watchingCount()," watching"]}),o(c,{color:"gray",children:` \xB7 ${s.toTimeString().slice(0,5)}`})]})]});return S?g(p,{flexDirection:"column",children:[We,o(p,{marginTop:1,justifyContent:"center",children:o(zn,{launchers:n})})]}):g(p,{flexDirection:"column",children:[We,g(p,{children:[g(p,{flexDirection:"column",borderStyle:"round",borderColor:"green",width:38,paddingX:1,children:[g(p,{justifyContent:"space-between",children:[o(c,{color:"green",bold:!0,children:"SITE WORKSPACES"}),z.length>G&&!u&&!_?o(c,{color:"gray",children:"/ filter"}):null]}),u?g(p,{children:[o(c,{color:"cyan",children:"/ "}),o(Wn,{value:y,onChange:v,onSubmit:()=>m(!1),placeholder:"type to filter\u2026"})]}):_?o(c,{color:"gray",children:`/ ${y} \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:_?`no matches for \u201C${y}\u201D`:"no sites yet \u2014 press a to add one"}):g(De,{children:[se?o(c,{color:"gray",children:Y>0?` \u2191 ${Y} more`:" "}):null,Ct.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),Ft=a.entry?a.entry.status==="syncing"&&Ue!=null?`${Ue}%`:a.entry.status==="paused"?"paused":"--":"",oe=A===W,_t=A===Oe&&Oe>0;return g(Fn,{children:[_t?o(c,{color:"gray",children:"\u2500".repeat(34)}):null,g(p,{justifyContent:"space-between",children:[g(p,{children:[o(c,{color:oe?"green":"gray",children:oe?"\u276F ":" "}),g(c,{color:a.entry?.status==="watching"||a.entry?.status==="syncing"?"green":Ge.color,children:[a.entry?.status==="syncing"?Le(w):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:Ft})]})]},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"})})]}),g(p,{flexDirection:"column",flexGrow:1,marginLeft:1,children:[o(p,{flexDirection:"column",borderStyle:"round",borderColor:"gray",paddingX:1,children:k?g(De,{children:[g(c,{children:[k.org.name||k.org.subdomain?g(c,{color:"gray",children:[k.org.name||k.org.subdomain," / "]}):null,o(c,{color:"cyan",bold:!0,children:k.site.name})]}),g(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)"})]}),g(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]}),g(p,{children:[o(c,{color:"gray",children:"path "}),o(c,{wrap:"truncate-end",children:T?.viewsDir?Me(T.viewsDir):"\u2014"})]}),g(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(qn,{percent:T?T.status==="syncing"?ge(T.progress)??0:T.status==="watching"?100:0:0})}),T?g(De,{children:[g(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)})]}),g(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?g(p,{children:[o(c,{color:"red",children:"\u258C "}),o(c,{color:"red",wrap:"truncate-end",children:`\u2717 ${j.errors[0]}`})]}):null,me?g(p,{children:[o(Yn,{frame:w}),o(c,{color:"gray",children:` ${j?.stage??"building"}`})]}):null]}):null]}):o(c,{color:"gray",children:"No site selected."})}),N?g(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."}),g(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."}),g(p,{marginTop:1,children:[g(c,{color:"yellow",children:[Le(w)," "]}),o(c,{color:"gray",children:"waiting for approval \xB7 esc to cancel"})]})]}):g(p,{flexDirection:"column",borderStyle:"round",borderColor:C==="logs"?"green":"gray",paddingX:1,marginTop:1,height:te+4,flexShrink:0,overflowY:"hidden",children:[g(p,{justifyContent:"space-between",children:[g(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${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"}):_e.map((a,x)=>g(c,{wrap:"truncate-end",children:[g(c,{color:"gray",children:[a.time," "]}),a.text]},ne-_e.length+x))})]})]})]}),N?.url?g(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,e.message?o(p,{paddingX:1,children:g(c,{color:e.messageIsError?"red":"gray",wrap:"truncate-end",children:[e.messageIsError?"\u2717 ":"",e.message]})}):null,g(p,{flexDirection:"column",marginTop:1,children:[g(p,{paddingX:1,justifyContent:"space-between",children:[g(p,{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:bt})]}),!I&&n.length>0?o(p,{paddingX:1,marginTop:1,flexWrap:"wrap",children:n.map((a,x)=>o(F,{k:String(x+1),label:a.label,bg:vt},a.key))}):null]})]})}import{jsx as Kn}from"react/jsx-runtime";function Tt({controller:e}){return Xn((t,n)=>{n.ctrl&&t==="c"&&e.exit()}),Kn(xt,{controller:e})}import{jsx as sr}from"react/jsx-runtime";var er=Qn(import.meta.url),je=Xe();if(je.version){let e=er("../package.json");console.log(e.version),process.exit(0)}var $t=Ae.dirname(Vn(import.meta.url)),tr=kt(Ae.join($t,"AGENTS.md"),"utf-8"),nr=kt(Ae.join($t,"build.mjs"),"utf-8");async function rr(){let e=new ue(tr,nr);e.basePath=je.path,await e.init((je.env??"production").toLowerCase()),process.stdout.isTTY&&process.stdout.write("\x1B[2J\x1B[3J\x1B[H");let t=Zn(sr(Tt,{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()}rr().catch(e=>{let t=e;console.error("\u274C",t.body||t.message),process.exit(1)});
|
|
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)});
|