@sleekcms/sync 2.9.1 → 2.10.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/AGENT.md +11 -2
- package/dist/build.mjs +44 -29
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/AGENT.md
CHANGED
|
@@ -33,12 +33,21 @@ Pages and entries are either **single** (one record) or a **collection** (many r
|
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
35
|
node build.mjs # build + validate; prints the PREVIEW url, or build errors
|
|
36
|
-
node build.mjs --deploy # build + publish LIVE; prints the live url
|
|
37
36
|
```
|
|
38
37
|
|
|
39
|
-
- On success it prints `✅ Build
|
|
38
|
+
- On success it prints `✅ Build succeeded (preview) → <url>` — **give that URL to the user** so they can view the result.
|
|
40
39
|
- On failure it prints `❌ Build failed:` followed by the errors (e.g. `views/pages/home.ejs:14: …`). Fix them and build again.
|
|
41
40
|
- This is a *whole-site* check (templates, links, references) that `sync-errors.log` does not cover. Every build is also appended to `build.log`.
|
|
41
|
+
- Building never changes the live site. It is safe to run as often as you like.
|
|
42
|
+
5. **Publish** only when the user asks to go live:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
node build.mjs --publish # make the current state live; prints the live url
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- It reuses the build from step 4 when nothing changed since, so building then publishing costs one build, not two. Re-running either command while a build is still going just reports its progress — it never starts a second build.
|
|
49
|
+
- On success it prints `✅ Published (live) → <url>`. On build errors it prints `❌ Publish failed — nothing went live:` and the site stays on its previous version.
|
|
50
|
+
- Rarely needed: add `--rebuild` to compile from scratch instead of reusing that build.
|
|
42
51
|
|
|
43
52
|
Never guess at why something isn't rendering — read `sync-errors.log` first, then run `node build.mjs` and read its output.
|
|
44
53
|
|
package/dist/build.mjs
CHANGED
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// build.mjs
|
|
2
|
+
// build.mjs v3 — SleekCMS workspace build/publish script.
|
|
3
3
|
/**
|
|
4
4
|
* Self-contained (no `npm install` needed). Run from anywhere inside a synced
|
|
5
5
|
* SleekCMS workspace — the one `@sleekcms/sync` created, containing `.cache/token`.
|
|
6
6
|
*
|
|
7
|
-
* node build.mjs Build + validate the whole site
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* node build.mjs Build + validate the whole site, WITHOUT touching
|
|
8
|
+
* the live site. Prints the PREVIEW URL on success,
|
|
9
|
+
* or the build errors to fix.
|
|
10
|
+
* node build.mjs --publish Publish: make the current state live. Reuses the
|
|
11
|
+
* build above when nothing changed since. Prints the
|
|
12
|
+
* live URL.
|
|
13
|
+
* --rebuild Compile from scratch instead of reusing the build
|
|
14
|
+
* already made for the current state (rarely needed).
|
|
10
15
|
*
|
|
11
|
-
* It calls POST /api/mcp/
|
|
12
|
-
* cms-agent build loop). Results go to three places:
|
|
16
|
+
* It calls POST /api/mcp/build (or /api/mcp/publish) and polls it to a terminal
|
|
17
|
+
* state (mirrors the cms-agent build loop). Results go to three places:
|
|
13
18
|
* - stdout — for you / your AI agent to read directly,
|
|
14
19
|
* - ./build.log — appended history of every build,
|
|
15
20
|
* - ./.cache/build.json — the single source of truth the `sleekcms` dashboard watches.
|
|
16
21
|
*
|
|
17
|
-
* Exit codes: 0 = built/
|
|
22
|
+
* Exit codes: 0 = built/published, 1 = build errors, 2 = couldn't run / still building.
|
|
18
23
|
*/
|
|
19
24
|
|
|
20
25
|
import fs from "node:fs";
|
|
@@ -61,7 +66,7 @@ export function stageFor(status, poll) {
|
|
|
61
66
|
return "building";
|
|
62
67
|
}
|
|
63
68
|
|
|
64
|
-
/** Coerce the
|
|
69
|
+
/** Coerce the build/publish endpoint's error entries to plain strings. */
|
|
65
70
|
export function toErrorStrings(errors) {
|
|
66
71
|
if (!Array.isArray(errors)) return [];
|
|
67
72
|
return errors.map((e) =>
|
|
@@ -69,35 +74,41 @@ export function toErrorStrings(errors) {
|
|
|
69
74
|
);
|
|
70
75
|
}
|
|
71
76
|
|
|
72
|
-
class
|
|
77
|
+
class BuildError extends Error {
|
|
73
78
|
constructor(message, httpStatus) {
|
|
74
79
|
super(message);
|
|
75
80
|
this.httpStatus = httpStatus;
|
|
76
81
|
}
|
|
77
82
|
}
|
|
78
83
|
|
|
79
|
-
async function
|
|
80
|
-
const res = await fetchImpl(base +
|
|
84
|
+
async function callEndpoint(base, token, path, body, fetchImpl) {
|
|
85
|
+
const res = await fetchImpl(base + path, {
|
|
81
86
|
method: "POST",
|
|
82
87
|
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
|
|
83
|
-
body: JSON.stringify(
|
|
88
|
+
body: JSON.stringify(body),
|
|
84
89
|
});
|
|
85
90
|
if (!res.ok) {
|
|
86
91
|
const text = await res.text().catch(() => "");
|
|
87
|
-
throw new
|
|
92
|
+
throw new BuildError(`${path} → ${res.status}: ${text}`, res.status);
|
|
88
93
|
}
|
|
89
94
|
return res.json();
|
|
90
95
|
}
|
|
91
96
|
|
|
92
97
|
/**
|
|
93
|
-
* Trigger a build, then poll
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
98
|
+
* Trigger a build (or a publish), then poll it to a terminal state. Both
|
|
99
|
+
* endpoints work off the build for the current content state, so every call
|
|
100
|
+
* after the first reports that same build's progress — polling is just the same
|
|
101
|
+
* request again, with no argument. `rebuild` (first call only) compiles from
|
|
102
|
+
* scratch instead. `onPoll(status, poll)` fires after each response so the
|
|
103
|
+
* caller can surface progress.
|
|
97
104
|
*/
|
|
98
105
|
export async function buildAndPoll(opts) {
|
|
99
|
-
const {
|
|
100
|
-
|
|
106
|
+
const {
|
|
107
|
+
base, token, publish = false, rebuild = false,
|
|
108
|
+
maxPolls = DEFAULT_MAX_POLLS, fetchImpl = fetch, onPoll,
|
|
109
|
+
} = opts;
|
|
110
|
+
const path = publish ? "/publish" : "/build";
|
|
111
|
+
let r = await callEndpoint(base, token, path, rebuild ? { rebuild: true } : {}, fetchImpl);
|
|
101
112
|
let poll = 0;
|
|
102
113
|
if (onPoll) onPoll(r.status, poll);
|
|
103
114
|
while (
|
|
@@ -106,7 +117,7 @@ export async function buildAndPoll(opts) {
|
|
|
106
117
|
poll < maxPolls
|
|
107
118
|
) {
|
|
108
119
|
poll++;
|
|
109
|
-
r = await
|
|
120
|
+
r = await callEndpoint(base, token, path, {}, fetchImpl);
|
|
110
121
|
if (onPoll) onPoll(r.status, poll);
|
|
111
122
|
}
|
|
112
123
|
return r;
|
|
@@ -116,11 +127,13 @@ export async function buildAndPoll(opts) {
|
|
|
116
127
|
// CLI
|
|
117
128
|
// ---------------------------------------------------------------------------
|
|
118
129
|
|
|
119
|
-
function parseFlags(argv) {
|
|
120
|
-
const flags = {
|
|
130
|
+
export function parseFlags(argv) {
|
|
131
|
+
const flags = { publish: false, rebuild: false, env: undefined };
|
|
121
132
|
for (let i = 0; i < argv.length; i++) {
|
|
122
133
|
const a = argv[i];
|
|
123
|
-
|
|
134
|
+
// --deploy / --live are the old names for --publish.
|
|
135
|
+
if (a === "--publish" || a === "--deploy" || a === "--live") flags.publish = true;
|
|
136
|
+
else if (a === "--rebuild" || a === "--force") flags.rebuild = true;
|
|
124
137
|
else if (a === "--env") flags.env = argv[++i];
|
|
125
138
|
else if (a.startsWith("--env=")) flags.env = a.slice("--env=".length);
|
|
126
139
|
}
|
|
@@ -147,7 +160,7 @@ function appendLog(ws, line) {
|
|
|
147
160
|
|
|
148
161
|
async function main() {
|
|
149
162
|
const flags = parseFlags(process.argv.slice(2));
|
|
150
|
-
const mode = flags.
|
|
163
|
+
const mode = flags.publish ? "live" : "preview";
|
|
151
164
|
|
|
152
165
|
const ws = findWorkspace(process.cwd());
|
|
153
166
|
if (!ws) {
|
|
@@ -173,7 +186,7 @@ async function main() {
|
|
|
173
186
|
const base = mcpBase(env);
|
|
174
187
|
const maxPolls = Number(process.env.SLEEKCMS_MAX_BUILD_POLLS) || DEFAULT_MAX_POLLS;
|
|
175
188
|
|
|
176
|
-
console.log(`⏳ ${flags.
|
|
189
|
+
console.log(`⏳ ${flags.publish ? "Publishing" : "Building"} site…`);
|
|
177
190
|
writeStatus(ws, { status: "building", mode, stage: "queued", at: Date.now() });
|
|
178
191
|
|
|
179
192
|
let r;
|
|
@@ -181,7 +194,8 @@ async function main() {
|
|
|
181
194
|
r = await buildAndPoll({
|
|
182
195
|
base,
|
|
183
196
|
token,
|
|
184
|
-
|
|
197
|
+
publish: flags.publish,
|
|
198
|
+
rebuild: flags.rebuild,
|
|
185
199
|
maxPolls,
|
|
186
200
|
onPoll: (status, poll) => {
|
|
187
201
|
if (!TERMINAL.has(status)) {
|
|
@@ -203,7 +217,7 @@ async function main() {
|
|
|
203
217
|
// 1) Build failed (compile errors, or the job itself failed/expired).
|
|
204
218
|
if (errors.length > 0 || r.status === "FAILED" || r.status === "EXPIRED") {
|
|
205
219
|
const list = errors.length ? errors : [r.message || "Build failed."];
|
|
206
|
-
console.error("❌ Build failed:");
|
|
220
|
+
console.error(flags.publish ? "❌ Publish failed — nothing went live:" : "❌ Build failed:");
|
|
207
221
|
for (const e of list) console.error(` - ${e}`);
|
|
208
222
|
writeStatus(ws, { status: "error", mode, errors: list, at: Date.now() });
|
|
209
223
|
appendLog(ws, `${new Date().toISOString()}\t${mode}\tFAILED\n${list.map((e) => ` - ${e}`).join("\n")}`);
|
|
@@ -213,7 +227,7 @@ async function main() {
|
|
|
213
227
|
// 2) Success.
|
|
214
228
|
if (r.status === "COMPLETED") {
|
|
215
229
|
const url = r.url || "";
|
|
216
|
-
console.log(
|
|
230
|
+
console.log(`${flags.publish ? "✅ Published (live)" : "✅ Build succeeded (preview)"}${url ? ` → ${url}` : ""}`);
|
|
217
231
|
writeStatus(ws, { status: "success", mode, url: url || undefined, at: Date.now() });
|
|
218
232
|
appendLog(ws, `${new Date().toISOString()}\t${mode}\tSUCCESS\t${url}`);
|
|
219
233
|
process.exit(0);
|
|
@@ -222,7 +236,8 @@ async function main() {
|
|
|
222
236
|
// 3) Still running after the poll budget — surface the preview URL, leave it
|
|
223
237
|
// as building; re-running (or the dashboard) will resolve the final state.
|
|
224
238
|
const url = r.url || "";
|
|
225
|
-
|
|
239
|
+
const again = flags.publish ? "node build.mjs --publish" : "node build.mjs";
|
|
240
|
+
console.log(`⏳ Still building${url ? ` → ${url}` : ""}. Re-run \`${again}\` to check again.`);
|
|
226
241
|
writeStatus(ws, { status: "building", mode, stage: "finalizing", url: url || undefined, at: Date.now() });
|
|
227
242
|
appendLog(ws, `${new Date().toISOString()}\t${mode}\t${r.status}\t${url}`);
|
|
228
243
|
process.exit(2);
|
package/dist/index.js
CHANGED
|
@@ -6,4 +6,4 @@ Examples:
|
|
|
6
6
|
`).parse(process.argv),Yt.opts()}function D(t){let e=process.platform==="win32"?`where ${t}`:`which ${t}`;try{return Zt(e,{stdio:"ignore"}),!0}catch{return!1}}function ee(t){if(process.platform!=="darwin")return!1;try{return Zt(`osascript -e 'id of application "${t}"'`,{stdio:"ignore"}),!0}catch{return!1}}function Qe(t,e){let n={detached:!0,stdio:"ignore",windowsHide:!0};process.platform==="win32"?P("cmd.exe",["/c",t,...e],n).unref():P(t,e,n).unref()}var Vt=[{name:"VS Code",cmd:"code",args:t=>["-n",t]},{name:"Cursor",cmd:"cursor",args:t=>["-n",t]}];function Qt(t,e){let r=(e?Vt.filter(s=>s.cmd===e):Vt).find(s=>D(s.cmd));return r?(Qe(r.cmd,r.args(t)),r.name):null}function Ze(t){if(process.platform==="darwin")return P("open",["-a","Terminal",t],{detached:!0,stdio:"ignore"}).unref(),!0;if(process.platform==="win32"){if(D("wt"))P("wt.exe",["-d",t],{detached:!0,stdio:"ignore"}).unref();else{let e=D("powershell")?"powershell.exe":"cmd.exe";P("cmd.exe",["/c","start","",e],{cwd:t,detached:!0,stdio:"ignore"}).unref()}return!0}return!1}function tn(t){return ee("iTerm")?(P("open",["-a","iTerm",t],{detached:!0,stdio:"ignore"}).unref(),!0):!1}function en(t){return`'${t.replace(/'/g,"'\\''")}'`}var nn=[{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 ne(t,e){if(!D(e))return!1;if(process.platform==="darwin"){let r=`tell application "Terminal" to do script ("cd " & quoted form of "${t}" & " && ${e}")`;return P("osascript",["-e",r,"-e",'tell application "Terminal" to activate'],{detached:!0,stdio:"ignore"}).unref(),!0}if(process.platform==="win32")return D("wt")?P("wt.exe",["-d",t,"cmd","/k",e],{detached:!0,stdio:"ignore"}).unref():P("cmd.exe",["/c","start","","cmd","/k",e],{cwd:t,detached:!0,stdio:"ignore"}).unref(),!0;let n=`cd ${en(t)} && ${e}; exec bash`;for(let r of nn)if(D(r.cmd))try{return P(r.cmd,r.args(n),{cwd:t,detached:!0,stdio:"ignore"}).unref(),!0}catch{}return!1}function rn(t){return ne(t,"claude")}function sn(t){return ne(t,"pi")}function re(t){if(!t)return!1;try{return process.platform==="darwin"?P("open",[t],{detached:!0,stdio:"ignore"}).unref():process.platform==="win32"?P("cmd.exe",["/c","start","",t],{detached:!0,stdio:"ignore",windowsHide:!0}).unref():P("xdg-open",[t],{detached:!0,stdio:"ignore"}).unref(),!0}catch{return!1}}function se(){let t=process.platform==="darwin",e=process.platform==="win32",n=[];return(t||e)&&n.push({key:"terminal",label:"terminal",run:Ze}),ee("iTerm")&&n.push({key:"iterm",label:"iterm",run:tn}),D("code")&&n.push({key:"code",label:"vscode",run:r=>Qt(r,"code")!==null}),D("cursor")&&n.push({key:"cursor",label:"cursor",run:r=>Qt(r,"cursor")!==null}),D("claude")&&n.push({key:"claude",label:"claude",run:rn}),D("pi")&&n.push({key:"pi",label:"pi",run:sn}),n}import{EventEmitter as Mn}from"node:events";import{spawn as On}from"node:child_process";import Q from"fs-extra";import At from"path";import Dn from"chokidar";import m from"fs-extra";import an from"os";import S from"path";var ie={localhost:"http://app.sleekcms.test/api/mcp",development:"https://app.sleekcms.dev/api/mcp",production:"https://app.sleekcms.com/api/mcp"},cn=["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"],Bt=class extends Error{status;body;constructor(e,n,r){super(e),this.status=n,this.body=r}};async function Ct(t,e,n,r,s){let o=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(!o.ok){let c=await o.text();throw new Bt(`${n} ${r} \u2192 ${o.status}: ${c}`,o.status,c)}return o.json()}async function ln(t,e){e&&(await m.outputFile(S.join(t,"AGENT.md"),e),await m.outputFile(S.join(t,"CLAUDE.md"),e),await m.outputFile(S.join(t,".vscode","copilot-instructions.md"),e)),await m.outputFile(S.join(t,".vscode","settings.json"),JSON.stringify({"files.associations":{"*.model":"javascript"},"[javascript]":{"editor.defaultFormatter":"esbenp.prettier-vscode"},"js/ts.validate.enabled":!1},null,2))}async function un(t,e){if(!e)return;let n=S.join(t,"build.mjs"),r=e.match(/build\.mjs v\d+/)?.[0];if(await m.pathExists(n)){let s=(await m.readFile(n,"utf-8")).match(/build\.mjs v\d+/)?.[0];if(s&&s===r)return}await m.outputFile(n,e)}async function dn(t,e,n){let r=S.join(t,".cache","token");if(await m.pathExists(r)){if((await m.readFile(r,"utf-8")).trim()===e)return;n?.("\u267B\uFE0F Workspace was tied to a different site \u2014 recreating it."),await m.emptyDir(t)}await m.outputFile(r,e)}function gn(t,e){let n=`${e.name.substr(0,20)} ${e.id}`.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,""),r=t||S.join(an.homedir(),"SleekCMS");return S.resolve(r,n)}async function Pt(t){let e=(t.token||"").trim();if(!e)throw new Error("syncSite: token is required");let n=t.log??(v=>console.log(v)),r=t.onProgress,s=(t.env||e.split("-")[2]||"production").toLowerCase(),o=ie[s]||ie.production,c=await Ct(o,e,"GET","/get_site"),h=t.viewsDir?S.resolve(t.viewsDir):gn(t.path,c);await m.ensureDir(h),await dn(h,e,n),await Promise.all(cn.map(v=>m.ensureDir(S.join(h,v)))),await un(h,t.buildScript);let p=S.join(h,".cache","state.json");t.flush&&await m.remove(p);let x=!await m.pathExists(p),w=x?{}:(await m.readJson(p)).fileMap||{},f=0,b=0;return x?({fileMap:w,pulled:b}=await Sn(h,o,e,n,r),await ln(h,t.agentMd)):f=await fn(h,w,o,e,n,r),await m.outputJson(p,{fileMap:w},{spaces:2}),{viewsDir:h,site:c,isFirstRun:x,pushed:f,pulled:b}}var hn=new Set([".DS_Store","Thumbs.db","desktop.ini"]);async function pn(t){let e=S.join(t,"src");if(!await m.pathExists(e))return[];let n=[];async function r(s){let o=await m.readdir(s,{withFileTypes:!0});for(let c of o){if(hn.has(c.name))continue;let h=S.join(s,c.name);c.isDirectory()?await r(h):c.isFile()&&n.push(S.relative(t,h).replace(/\\/g,"/"))}}return await r(e),n}async function fn(t,e,n,r,s,o){let c=[];for(let f of await pn(t)){let b=S.join(t,f),v=e[f],O=await m.stat(b);if(v&&v.mtimeMs===O.mtimeMs)continue;let R=await m.readFile(b,"utf-8");R.trim()&&c.push({rel:f,full:b,stat:O,content:R,prior:v})}if(c.length===0)return 0;let h;try{h=await Ct(n,r,"POST","/save_files",c.map(f=>({path:f.rel,content:f.content})))}catch(f){let b=f;return s(`\u274C Error saving files: ${b.body||b.message}`),0}let p=await wn(t),x=0,w=mn(h);for(let f=0;f<c.length;f++){let b=c[f],v=yn(b,f,h,w);if(o?.(f+1,c.length),!v){let O="No save response returned";p[b.rel]=O,s(`\u274C Error saving ${b.rel}: ${O}`);continue}if(v.error){p[b.rel]=v.error,s(`\u274C Error saving ${b.rel}: ${v.error}`);continue}delete p[b.rel],e[b.rel]={mtimeMs:b.stat.mtimeMs},s(`\u2705 ${b.prior?"Updated":"Created"} ${b.rel}`),x++}return await xn(t,p),x}function mn(t){let e=new Map;for(let n of t)n.path&&e.set(n.path,n);return e}function yn(t,e,n,r){let s=r.get(t.rel);if(s)return s;let o=n[e];if(!o?.path||o.path===t.rel)return o}var $t="sync-errors.log",Et=new Map;async function wn(t){let e=S.resolve(t),n=Et.get(e);if(n)return n;let r=await bn(e);return Et.set(e,r),r}async function bn(t){let e=S.join(t,$t);if(!await m.pathExists(e))return{};let n=await m.readFile(e,"utf-8"),r={};for(let s of n.split(`
|
|
7
7
|
`)){let o=s.indexOf(": ");o>0&&(r[s.slice(0,o)]=s.slice(o+2))}return r}async function xn(t,e){let n=S.join(t,$t),r=Object.entries(e);if(r.length===0){await m.remove(n);return}await m.outputFile(n,r.map(([s,o])=>`${s}: ${o}`).join(`
|
|
8
8
|
`)+`
|
|
9
|
-
`)}async function Sn(t,e,n,r,s){Et.delete(S.resolve(t)),await m.remove(S.join(t,$t)),r("\u{1F4E5} Fetching files...");let o=await Ct(e,n,"GET","/get_files"),c={},h=0;for(let p of o){let x=S.join(t,p.path);await m.outputFile(x,p.content);let w=(await m.stat(x)).mtimeMs;h++,s?.(h,o.length),c[p.path]={mtimeMs:w}}return r(`\u2714\uFE0F Synced ${o.length} file(s).`),{fileMap:c,pulled:h}}import vn from"path";import Tn from"chokidar";var kn=5e3,Bn=/(^|[/\\])(\.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??kn}start(){if(this.watcher)return;let e=vn.join(this.viewsDir,"src");this.watcher=Tn.watch([e],{persistent:!0,ignoreInitial:!0,ignored:Bn}).on("change",()=>this.scheduleSync()).on("add",()=>this.scheduleSync()).on("unlink",()=>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 gt from"fs-extra";import En from"os";import ae from"path";var oe={localhost:"http://app.sleekcms.test/api",development:"https://app.sleekcms.dev/api",production:"https://app.sleekcms.com/api"};function Ot(t){return oe[t]||oe.production}var Cn=ae.join(En.homedir(),"SleekCMS"),ht=ae.join(Cn,"auth.json"),Mt;function ce(t){Mt=t||void 0}function Dt(t){let e=[];return t&&e.push(`_auth=${t}`),Mt&&e.push(`_dev=${Mt}`),e.length?e.join("; "):void 0}var L=class extends Error{status;body;constructor(e,n,r=""){super(e),this.name="UserAuthError",this.status=n,this.body=r}};async function le(){try{let t=await gt.readJson(ht);return t&&t.userToken?t:null}catch{return null}}async function ue(t){await gt.outputJson(ht,t,{spaces:2});try{await gt.chmod(ht,384)}catch{}}async function de(){await gt.remove(ht)}async function q(t){let e={},n=Dt(t.userToken);n&&(e.Cookie=n),t.subdomain&&(e["x-subdomain"]=t.subdomain),t.slug&&(e.site=t.slug),t.body!==void 0&&(e["Content-Type"]="application/json");let r=await fetch(Ot(t.env)+t.path,{method:t.method,headers:e,body:t.body!==void 0?JSON.stringify(t.body):void 0});if(!r.ok){let s=await r.text().catch(()=>"");throw new L(`${t.method} ${t.path} \u2192 ${r.status}: ${s}`,r.status,s)}return r.json()}async function ge(t,e){let n={"Content-Type":"application/json"},r=Dt();r&&(n.Cookie=r);let s=await fetch(Ot(t)+"/auth/otp",{method:"PUT",headers:n,body:JSON.stringify({email:e})});if(!s.ok){let c=await s.text().catch(()=>"");throw new L(`Failed to send OTP \u2192 ${s.status}: ${c}`,s.status,c)}return{otp:(await s.json().catch(()=>({}))).do_not_use_in_code}}async function Lt(t,e,n){let r={"Content-Type":"application/json"},s=Dt();s&&(r.Cookie=s);let o=await fetch(Ot(t)+"/auth/login",{method:"POST",headers:r,body:JSON.stringify({email:e,otp:n})});if(!o.ok){let p=await o.text().catch(()=>"");throw new L(`Login failed \u2192 ${o.status}: ${p}`,o.status,p)}let c=o.headers.getSetCookie?.()??[],h=Pn(c);if(!h)throw new L("Login succeeded but no _auth cookie was returned.",500);return h}function Pn(t){for(let e of t){let n=e.match(/(?:^|;\s*)_auth=([^;]+)/);if(n&&n[1])return decodeURIComponent(n[1])}return null}async function Rt(t,e){return q({env:t,userToken:e,method:"GET",path:"/org"})}async function he(t,e,n){return q({env:t,userToken:e,method:"GET",path:"/site",subdomain:n})}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,o=e.line!=null?`:${e.line}`:"",c=e.column!=null?`:${e.column}`:"",h=typeof e.message=="string"&&e.message?e.message:typeof e.name=="string"&&e.name?e.name:"",p=n&&r&&r!==n?` (on page ${r})`:"";if(s)return`${s}${o}${c}${p}: ${h||"(no message)"}`;if(h)return h;try{return JSON.stringify(t)}catch{return"(unknown error)"}}async function pe(t,e,n,r){let s;try{s=await q({env:t,userToken:e,method:"GET",path:"/site_build",subdomain:n,slug:r})}catch{return null}if(!Array.isArray(s)||s.length===0)return null;let o=s[0],c=s.find(p=>typeof p.url=="string"&&p.url.length>0),h=Array.isArray(o.errors)?o.errors.map($n):[];return h.length>0?{status:"error",mode:"preview",errors:h,url:c?.url||void 0,at:o.updated_at?Date.parse(o.updated_at):void 0}:c?{status:"success",mode:"preview",url:c.url||void 0,at:c.updated_at?Date.parse(c.updated_at):void 0}:null}async function fe(t,e,n,r){let{token:s}=await q({env:t,userToken:e,method:"POST",path:"/site_user/api_token",subdomain:n,slug:r,body:{refresh:!1}});return s}async function me(t,e,n){let r=await q({env:t,userToken:e,method:"POST",path:"/org",body:n?{name:n}:{}});return{id:r.id,name:r.name,subdomain:r.subdomain}}async function ye(t,e,n,r){let s=await q({env:t,userToken:e,method:"POST",path:"/site",subdomain:n,body:{name:r}});return{id:s.id,name:s.name,slug:s.slug}}var we=500;function Ln(){return new Date().toTimeString().slice(0,8)}function pt(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}async function be(t){t&&(await Q.remove(At.join(t,"src")),await Q.remove(At.join(t,".cache","state.json")))}var ft=class extends Mn{env="production";userToken="";email;catalog=[];synced=new Map;message;messageIsError=!1;agentMd;buildScript;isShuttingDown=!1;constructor(e,n){super(),this.agentMd=e,this.buildScript=n}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:Ln(),text:n}),r.logs.length>we&&r.logs.splice(0,r.logs.length-we),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,n,r){this.env=e,this.userToken=n,r&&(this.email=r);let s=await Rt(e,n);await this.buildCatalog(s)}async buildCatalog(e){let n=[];for(let r of e)try{n.push({org:r,sites:await he(this.env,this.userToken,r.subdomain)})}catch(s){if(s instanceof L&&s.status===401)throw s;n.push({org:r,sites:[]})}this.catalog=n,this.changed()}isSynced(e){return this.synced.has(e)}availableSites(){let e=[];for(let n of this.catalog)for(let r of n.sites)this.synced.has(r.id)||e.push({org:n.org,site:r});return e}async addSite(e,n){if(this.synced.has(n.id))return;let r;try{r=await fe(this.env,this.userToken,e.subdomain,n.slug)}catch(o){this.flash(`Failed to authorize "${n.name}": ${pt(o)}`,!0);return}let s={org:e,site:n,siteToken:r,viewsDir:"",status:"syncing",logs:[]};this.synced.set(n.id,s),this.appendLog(n.id,"\u2795 added \u2014 pulling files"),this.changed();try{let o=await Pt({token:r,env:this.env,agentMd:this.agentMd,buildScript:this.buildScript,log:c=>this.appendLog(n.id,c),onProgress:(c,h)=>{s.progress={done:c,total:h},this.changed()}});s.viewsDir=o.viewsDir,s.progress=void 0,s.status="watching",s.lastSyncedAt=Date.now(),s.lastMsg=`pulled ${o.pulled} file(s)`,s.watcher=new V({viewsDir:o.viewsDir,onSync:()=>this.runSync(n.id)}),s.watcher.start(),this.watchBuildStatus(n.id),this.seedLastBuild(n.id),this.appendLog(n.id,"\u{1F440} watching for changes")}catch(o){let c=o;s.status="error",s.progress=void 0,s.lastMsg=c.body||c.message,this.appendLog(n.id,`\u274C ${c.body||c.message}`)}this.changed()}async removeSite(e){let n=this.synced.get(e);n&&(n.watcher?.setShuttingDown(!0),await n.watcher?.stop(),await n.buildWatcher?.close(),await be(n.viewsDir),this.synced.delete(e),this.changed())}buildSite(e,n=!1){let r=this.synced.get(e);if(!r||!r.viewsDir)return;let s=n?"live":"preview";this.writeBuildFile(r.viewsDir,{status:"building",mode:s,stage:"queued",url:r.lastBuild?.url,at:Date.now()}),On("node",n?["build.mjs","--deploy"]:["build.mjs"],{cwd:r.viewsDir,stdio:"ignore"}).on("error",h=>{this.writeBuildFile(r.viewsDir,{status:"error",mode:s,errors:[h.message],url:r.lastBuild?.url,at:Date.now()}),this.appendLog(e,`\u274C build: ${h.message}`)}),this.appendLog(e,n?"\u{1F680} deploying\u2026":"\u{1F528} building\u2026")}buildFile(e){return At.join(e,".cache","build.json")}async readBuildFile(e){try{let n=await Q.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 Q.outputJson(s,n),await Q.rename(s,r)}catch{}}watchBuildStatus(e){let n=this.synced.get(e);!n||!n.viewsDir||(n.buildWatcher=Dn.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 pe(this.env,this.userToken,n.org.subdomain,n.site.slug);if(!r)return;let s=this.synced.get(e);if(!s)return;let o=await this.readBuildFile(s.viewsDir);o?.at!=null&&(r.at==null||o.at>=r.at)||await this.writeBuildFile(s.viewsDir,r)}async ensureOrg(e){if(e)return e;if(this.catalog[0])return this.catalog[0].org;let n;try{n=await Rt(this.env,this.userToken)}catch(r){return this.flash(`Couldn't check your organizations: ${pt(r)}`,!0),null}if(n.length>0){try{await this.buildCatalog(n)}catch{}return n[0]}try{let r=this.email?`${this.email.split("@")[0]}'s Sites`:"My Sites";this.flash("No organization yet \u2014 creating one\u2026");let s=await me(this.env,this.userToken,r);return this.catalog=[...this.catalog,{org:s,sites:[]}],this.changed(),s}catch(r){return this.flash(`Could not create an organization: ${pt(r)}`,!0),null}}async createNewSite(e,n){let r=await this.ensureOrg(n);if(!r)return;let s;try{s=await ye(this.env,this.userToken,r.subdomain,e)}catch(c){this.flash(`Could not create "${e}": ${pt(c)}`,!0);return}let o=this.catalog.find(c=>c.org.id===r.id);o&&!o.sites.some(c=>c.id===s.id)&&(o.sites=[...o.sites,s]),this.flash(`Created "${s.name}".`),await this.addSite(r,s)}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 Pt({token:r.siteToken,env:this.env,viewsDir:r.viewsDir,agentMd:this.agentMd,buildScript:this.buildScript,flush:n.flush,log:o=>this.appendLog(e,o),onProgress:(o,c)=>{r.progress={done:o,total:c},this.changed()}});r.progress=void 0,r.status="watching",r.lastSyncedAt=Date.now(),n.flush?r.lastMsg=`re-fetched ${s.pulled} file(s)`:r.lastMsg=s.pushed>0?`pushed ${s.pushed} file(s)`:"up to date"}catch(s){let o=s;r.status="error",r.progress=void 0,r.lastMsg=o.body||o.message,this.appendLog(e,`\u274C ${o.body||o.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(){for(let e of this.synced.values())e.watcher?.setShuttingDown(!0),await e.watcher?.stop(),await e.buildWatcher?.close(),await be(e.viewsDir)}async exit(){this.isShuttingDown||(this.isShuttingDown=!0,await this.cleanupAll(),this.emit("exit"))}async logout(){this.isShuttingDown||(this.isShuttingDown=!0,await de(),await this.cleanupAll(),this.emit("logout"))}};import{useEffect as Hn,useState as Me}from"react";import{Box as Jn,Text as Xn,useInput as Kn}from"ink";import{useState as Z}from"react";import{Box as tt,Text as H}from"ink";import xe from"ink-text-input";import{jsx as N,jsxs as J}from"react/jsx-runtime";function Se(t){let e=t;return e?.body||e?.message||String(t)}function ve({env:t,initialError:e,onAuthed:n}){let[r,s]=Z("email"),[o,c]=Z(""),[h,p]=Z(""),[x,w]=Z(e),[f,b]=Z(),v=async R=>{let E=R.trim();if(E){w(void 0),s("busy");try{let{otp:$}=await ge(t,E);if(c(E),$){let X=await Lt(t,E,$);await n(X,E);return}b(`OTP sent to ${E}`),s("otp")}catch($){w(Se($)),s("email")}}},O=async R=>{let E=R.trim();if(E){w(void 0),s("busy");try{let $=await Lt(t,o,E);await n($,o)}catch($){w(Se($)),p(""),s("otp")}}};return J(tt,{flexDirection:"column",children:[J(H,{bold:!0,children:["\u25C6 SleekCMS \u2014 sign in",t!=="production"?` (${t})`:""]}),x?J(H,{color:"red",children:["\u2717 ",x]}):null,r==="email"&&J(tt,{marginTop:1,children:[N(H,{children:"Email: "}),N(xe,{value:o,onChange:c,onSubmit:v,placeholder:"you@example.com"})]}),r==="otp"&&J(tt,{flexDirection:"column",marginTop:1,children:[f?N(H,{color:"green",children:f}):null,J(tt,{children:[N(H,{children:"Enter OTP: "}),N(xe,{value:h,onChange:p,onSubmit:O})]})]}),r==="busy"&&N(tt,{marginTop:1,children:N(H,{children:"Working\u2026"})})]})}import{Fragment as An,useEffect as et,useMemo as Fn,useState as C}from"react";import{Box as g,Text as l,useInput as jn,useStdout as _n}from"ink";import Be from"ink-text-input";import Rn from"node:os";function Ft(t){if(!t)return"\u2014";let e=Rn.homedir();return t.startsWith(e)?"~"+t.slice(e.length):t}function jt(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 yt(t){return!t||t.total<=0?null:Math.round(t.done/t.total*100)}var mt=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"];function Te(t){return mt[(t%mt.length+mt.length)%mt.length]}function wt(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 ke(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 nt,jsx as i,jsxs as u}from"react/jsx-runtime";var U=(t,e)=>e<=0?0:Math.max(0,Math.min(t,e-1)),In=16,Nn=5,Un="greenBright",Ee="blueBright",Ce="magentaBright";function Pe({k:t,bg:e=Un}){return i(l,{color:"black",backgroundColor:e,children:` ${t} `})}function j({k:t,label:e,width:n=16,bg:r}){return u(g,{width:n,children:[i(Pe,{k:t,bg:r}),i(l,{color:"gray",children:` ${e}`})]})}function B({k:t,label:e,bg:n}){return u(g,{marginBottom:1,children:[i(g,{width:9,children:i(Pe,{k:t,bg:n})}),i(l,{color:"gray",children:e})]})}function Wn({launchers:t}){return u(g,{flexDirection:"column",borderStyle:"round",borderColor:"green",paddingX:2,paddingY:1,width:66,children:[u(g,{justifyContent:"space-between",children:[i(l,{color:"green",bold:!0,children:"KEYBOARD SHORTCUTS"}),i(l,{color:"gray",children:"? or esc to close"})]}),u(g,{marginTop:1,children:[u(g,{flexDirection:"column",width:34,children:[i(l,{color:"cyan",bold:!0,children:"Navigate"}),i(B,{k:"\u2191\u2193",label:"move selection"}),i(B,{k:"tab",label:"focus logs \xB7 \u2191\u2193 scroll"}),i(B,{k:"esc",label:"clear filter / back"}),i(g,{marginTop:1,children:i(l,{color:"cyan",bold:!0,children:"Global"})}),i(B,{k:"/",label:"search sites"}),i(B,{k:"n",label:"new site"}),i(B,{k:"?",label:"toggle this help",bg:Ee}),i(B,{k:"q",label:"logout"}),i(B,{k:"ctrl+c",label:"quit"})]}),u(g,{flexDirection:"column",flexGrow:1,children:[i(l,{color:"cyan",bold:!0,children:"Site actions"}),i(B,{k:"s",label:"start sync"}),i(B,{k:"d",label:"disconnect"}),i(B,{k:"p",label:"pause / resume sync"}),i(B,{k:"b",label:"build preview"}),i(B,{k:"B",label:"deploy live"}),i(B,{k:"o",label:"open preview url"}),t.map((e,n)=>i(B,{k:String(n+1),label:`open in ${e.label}`,bg:Ce},e.key))]})]})]})}function Gn({percent:t,width:e=28}){let n=Math.round(Math.max(0,Math.min(100,t))/100*e);return u(l,{children:[i(l,{color:"green",children:"\u2588".repeat(n)}),i(l,{color:"gray",children:"\u2591".repeat(Math.max(0,e-n))})]})}function qn({frame:t,width:e=24,seg:n=6}){let r=e+n,s=t%r-n,o="";for(let c=0;c<e;c++)o+=c>=s&&c<s+n?"\u25AE":"\u25AF";return i(l,{color:"yellow",children:o})}function $e({controller:t}){let{stdout:e}=_n(),n=Fn(()=>se(),[]),[,r]=C(0),[s,o]=C(()=>new Date),[c,h]=C(null),[p,x]=C(()=>t.synced.size>0||t.catalog.some(d=>d.sites.length>0)?"dashboard":t.catalog.length<=1?"newName":"newOrg"),[w,f]=C(0),[b,v]=C(""),[O,R]=C(!1),[E,$]=C(""),[X,rt]=C(!1),[Nt,Ae]=C(0),[Ut,Wt]=C(!1),[Fe,je]=C(!1),[st,it]=C("list"),[_e,K]=C(0),Gt=()=>r(a=>a+1);et(()=>(t.on("change",Gt),()=>{t.off("change",Gt)}),[t]),et(()=>{let a,d=()=>{o(new Date),a=setTimeout(d,6e4-Date.now()%6e4)};return a=setTimeout(d,6e4-Date.now()%6e4),()=>clearTimeout(a)},[]);let F=t.catalog.flatMap(a=>a.sites.map(d=>({org:a.org,site:d,entry:t.synced.get(d.id)}))).sort((a,d)=>(a.entry?0:1)-(d.entry?0:1)),_=E.trim().toLowerCase(),M=_?F.filter(a=>a.site.name.toLowerCase().includes(_)||(a.org.name||a.org.subdomain||"").toLowerCase().includes(_)):F,W=M.findIndex(a=>a.site.id===c);W<0&&(W=0);let T=M[W],y=T?.entry,ot=Math.max(3,(e?.rows??30)-26),I=y?.logs??[],xt=Math.max(0,I.length-ot),Ie=Math.min(_e,xt),at=I.length-Ie,qt=I.slice(Math.max(0,at-ot),at),Ne=T?.site.id;et(()=>K(0),[Ne]);let A=y?.lastBuild,St=A?.status==="building",vt=ke(A),ct=St;if(!ct){for(let a of t.synced.values())if(a.status==="syncing"){ct=!0;break}}et(()=>{if(!ct)return;let a=setInterval(()=>Ae(d=>d+1),120);return()=>clearInterval(a)},[ct]);let Ht=M.findIndex(a=>!a.entry),G=Math.max(Nn,(e?.rows??30)-In),z=M.length,lt=z>G,Ue=Math.floor(G/2),Y=lt?Math.max(0,Math.min(W-Ue,z-G)):0,Tt=Math.min(z,Y+G),We=M.slice(Y,Tt);et(()=>{p!=="dashboard"||O||F.length>0||(v(""),t.catalog.length<=1?x("newName"):(f(0),x("newOrg")))},[F.length,p,O,t.catalog.length]);let ut=a=>{if(M.length===0)return;let d=U(W+a,M.length);h(M[d].site.id)},Ge=()=>{if(T){if(T.entry){t.flash("Already syncing \u2014 press d to disconnect.");return}t.addSite(T.org,T.site)}},qe=()=>{T?.entry&&t.removeSite(T.site.id)},He=()=>{v(""),t.catalog.length<=1?x("newName"):(f(0),x("newOrg"))},Je=a=>{if(!y){t.flash("Press s to start syncing this site first.",!0);return}je(!0);let d=a.run(y.viewsDir);t.flash(d?`Opened ${a.label} at ${Ft(y.viewsDir)}`:`Couldn't open ${a.label}.`,!d)},Xe=()=>{if(!y){t.flash("Press s to start syncing this site first.",!0);return}t.togglePause(y.site.id)},Jt=a=>{if(!y){t.flash("Press s to start syncing this site first.",!0);return}t.buildSite(y.site.id,a),t.flash(a?"Deploying \u2014 building live\u2026":"Building preview\u2026")},Ke=()=>{let a=y?.lastBuild?.url;if(!a){t.flash("No build URL yet \u2014 press b to build.",!0);return}t.flash(re(a)?`Opening ${a}`:"Couldn't open the browser.",!1)};jn((a,d)=>{if(Ut){(a==="?"||d.escape)&&Wt(!1);return}if(p==="newOrg"){d.escape?x("dashboard"):d.upArrow?f(k=>U(k-1,t.catalog.length)):d.downArrow?f(k=>U(k+1,t.catalog.length)):d.return&&x("newName");return}if(X){d.escape?(rt(!1),$(""),h(null)):d.return?rt(!1):d.upArrow?ut(-1):d.downArrow&&ut(1);return}if(d.tab){st==="logs"?it("list"):y&&it("logs"),K(0);return}if(st==="logs"){if(d.escape){it("list"),K(0);return}if(d.upArrow)return void K(k=>Math.min(k+1,xt));if(d.downArrow)return void K(k=>Math.max(0,k-1))}if(d.escape){$(""),h(null);return}if(a==="?")return void Wt(!0);if(a==="/")return it("list"),void rt(!0);if(a==="n")return void He();if(a==="q")return void t.logout();if(d.upArrow)return ut(-1);if(d.downArrow)return ut(1);if(a==="s")return Ge();if(a==="d")return qe();if(a==="p")return Xe();if(a==="b")return Jt(!1);if(a==="B")return Jt(!0);if(a==="o")return Ke();if(a>="1"&&a<="9"){let k=n[parseInt(a,10)-1];if(k)return Je(k)}},{isActive:p!=="newName"});let ze=async a=>{let d=a.trim();if(!d){x("dashboard");return}let k=t.catalog[U(w,t.catalog.length)]?.org??t.catalog[0]?.org;R(!0),x("dashboard"),await t.createNewSite(d,k),R(!1)},Xt=u(g,{justifyContent:"space-between",paddingX:1,children:[u(g,{children:[i(l,{color:"green",bold:!0,children:"\u25C6 SleekCMS"}),i(l,{color:"gray",children:" \u2502 "}),i(l,{children:t.email??"signed in"})]}),u(g,{children:[u(l,{color:"gray",children:[_?`${M.length}/${F.length}`:F.length," sites \xB7 "]}),u(l,{color:"green",children:[t.watchingCount()," watching"]}),i(l,{color:"gray",children:` \xB7 ${s.toTimeString().slice(0,5)}`})]})]});return Ut?u(g,{flexDirection:"column",children:[Xt,i(g,{marginTop:1,justifyContent:"center",children:i(Wn,{launchers:n})})]}):u(g,{flexDirection:"column",children:[Xt,u(g,{children:[u(g,{flexDirection:"column",borderStyle:"round",borderColor:"green",width:38,paddingX:1,children:[u(g,{justifyContent:"space-between",children:[i(l,{color:"green",bold:!0,children:"SITE WORKSPACES"}),F.length>G&&!X&&!_?i(l,{color:"gray",children:"/ filter"}):null]}),X?u(g,{children:[i(l,{color:"cyan",children:"/ "}),i(Be,{value:E,onChange:$,onSubmit:()=>rt(!1),placeholder:"type to filter\u2026"})]}):_?i(l,{color:"gray",children:`/ ${E} \xB7 ${M.length} match${M.length===1?"":"es"}`}):null,i(g,{flexDirection:"column",marginTop:1,minHeight:lt?G+3:void 0,children:M.length===0?i(l,{color:"gray",children:_?`no matches for \u201C${E}\u201D`:"no sites \u2014 press n to create one"}):u(nt,{children:[lt?i(l,{color:"gray",children:Y>0?` \u2191 ${Y} more`:" "}):null,We.map((a,d)=>{let k=Y+d,Kt=a.entry?wt(a.entry.status):{dot:"\xB7",color:"gray",label:"idle"},zt=yt(a.entry?.progress),Ye=a.entry?a.entry.status==="syncing"&&zt!=null?`${zt}%`:a.entry.status==="paused"?"paused":"--":"",dt=k===W,Ve=k===Ht&&Ht>0;return u(An,{children:[Ve?i(l,{color:"gray",children:"\u2500".repeat(34)}):null,u(g,{justifyContent:"space-between",children:[u(g,{children:[i(l,{color:dt?"green":"gray",children:dt?"\u276F ":" "}),u(l,{color:a.entry?.status==="watching"||a.entry?.status==="syncing"?"green":Kt.color,children:[a.entry?.status==="syncing"?Te(Nt):a.entry?.status==="watching"?"\u25CF":Kt.dot," "]}),i(l,{color:dt?"white":a.entry?void 0:"gray",bold:dt,children:a.site.name})]}),i(l,{color:a.entry?.status==="syncing"?"green":"gray",children:Ye})]})]},a.site.id)}),lt?i(l,{color:"gray",children:Tt<z?` \u2193 ${z-Tt} more`:" "}):null]})}),i(g,{marginTop:1,children:i(l,{color:"gray",children:"+ new site \xB7 n"})})]}),u(g,{flexDirection:"column",flexGrow:1,marginLeft:1,children:[i(g,{flexDirection:"column",borderStyle:"round",borderColor:"gray",paddingX:1,children:T?u(nt,{children:[u(l,{children:[T.org.name||T.org.subdomain?u(l,{color:"gray",children:[T.org.name||T.org.subdomain," / "]}):null,i(l,{color:"cyan",bold:!0,children:T.site.name})]}),u(g,{marginTop:1,children:[i(l,{color:"gray",children:"status "}),y?i(l,{color:wt(y.status).color,children:`: ${wt(y.status).label}`}):i(l,{color:"gray",children:": idle \u2014 not syncing (press s to start)"})]}),u(g,{children:[i(l,{color:"gray",children:"path "}),i(l,{wrap:"truncate-end",children:y?.viewsDir?Ft(y.viewsDir):"\u2014"})]}),u(g,{children:[i(l,{color:"gray",children:"synced "}),i(l,{children:jt(y?.lastSyncedAt)}),i(l,{color:"gray",children:" progress "}),i(l,{color:y?.status==="syncing"?"green":"gray",children:y?.status==="syncing"?`${yt(y.progress)??0}%`:"\u2014"})]}),i(g,{marginTop:1,children:i(Gn,{percent:y?y.status==="syncing"?yt(y.progress)??0:y.status==="watching"?100:0:0})}),y?u(nt,{children:[u(g,{marginTop:1,children:[i(l,{color:"gray",children:"build "}),i(l,{color:vt.color,children:`${vt.dot} ${vt.label}`}),i(l,{color:"gray",children:" last "}),i(l,{children:St?"in progress":jt(A?.at)})]}),u(g,{children:[i(l,{color:"gray",children:"url "}),A?.url?i(l,{color:"cyan",wrap:"truncate-end",children:A.url}):i(l,{color:"gray",children:"\u2014"})]}),A?.status==="error"&&A.errors?.length?u(g,{children:[i(l,{color:"red",children:"\u258C "}),i(l,{color:"red",wrap:"truncate-end",children:`\u2717 ${A.errors[0]}`})]}):null,St?u(g,{children:[i(qn,{frame:Nt}),i(l,{color:"gray",children:` ${A?.stage??"building"}`})]}):null]}):null]}):i(l,{color:"gray",children:"No site selected."})}),p==="dashboard"?u(g,{flexDirection:"column",borderStyle:"round",borderColor:st==="logs"?"green":"gray",paddingX:1,marginTop:1,height:ot+4,flexShrink:0,overflowY:"hidden",children:[u(g,{justifyContent:"space-between",children:[u(l,{children:[i(l,{color:"cyan",bold:!0,children:"LOGS \xB7 "}),i(l,{color:"white",children:T?.site.name??"\u2014"})]}),y&&I.length>0?st==="logs"?i(l,{color:"green",children:`\u2191\u2193 scroll \xB7 esc back${xt>0?` \xB7 ${at}/${I.length}`:""}`}):I.length>ot?i(l,{color:"gray",children:"tab to scroll"}):null:null]}),i(g,{flexDirection:"column",marginTop:1,children:!y||I.length===0?i(l,{color:"gray",children:"no activity yet"}):qt.map((a,d)=>u(l,{wrap:"truncate-end",children:[u(l,{color:"gray",children:[a.time," "]}),a.text]},at-qt.length+d))})]}):u(g,{flexDirection:"column",borderStyle:"round",borderColor:"blue",paddingX:1,marginTop:1,flexGrow:1,children:[p==="newOrg"&&u(nt,{children:[i(l,{color:"cyan",bold:!0,children:"CREATE SITE \u2014 PICK ORG"}),i(l,{color:"gray",children:"\u2191/\u2193 select \xB7 \u23CE next \xB7 esc cancel"}),i(g,{flexDirection:"column",marginTop:1,children:t.catalog.map((a,d)=>u(l,{color:d===U(w,t.catalog.length)?"blue":void 0,bold:d===U(w,t.catalog.length),children:[d===U(w,t.catalog.length)?"\u276F ":" ",a.org.name||a.org.subdomain]},a.org.id))})]}),p==="newName"&&u(nt,{children:[i(l,{color:"cyan",bold:!0,children:"CREATE SITE"}),u(g,{marginTop:1,children:[i(l,{children:"New site name: "}),i(Be,{value:b,onChange:v,onSubmit:ze})]}),i(l,{color:"gray",children:"\u23CE create \xB7 empty + \u23CE to cancel"})]})]})]})]}),t.message?i(g,{paddingX:1,children:u(l,{color:t.messageIsError?"red":"gray",wrap:"truncate-end",children:[t.messageIsError?"\u2717 ":"",t.message]})}):null,u(g,{flexDirection:"column",marginTop:1,children:[u(g,{paddingX:1,justifyContent:"space-between",children:[u(g,{flexWrap:"wrap",children:[i(j,{k:"\u2191\u2193",label:"select"}),i(j,{k:"/",label:"search"}),i(j,{k:"s",label:"start sync"}),i(j,{k:"d",label:"disconnect"}),F.length===0?i(j,{k:"n",label:"new site"}):null,i(j,{k:"ctrl+c",label:"quit",width:14})]}),i(j,{k:"?",label:"all keys",width:12,bg:Ee})]}),!Fe&&n.length>0?i(g,{paddingX:1,marginTop:1,flexWrap:"wrap",children:n.map((a,d)=>i(j,{k:String(d+1),label:a.label,bg:Ce},a.key))}):null]})]})}import{jsx as bt}from"react/jsx-runtime";function Oe(t){let e=t;return e?.body||e?.message||String(t)}function De({controller:t,env:e,devSecret:n,savedToken:r,savedEmail:s}){let[o,c]=Me(r?"loading":"auth"),[h,p]=Me();Kn((w,f)=>{f.ctrl&&w==="c"&&t.exit()}),Hn(()=>{r&&t.init(e,r,s).then(()=>c("manage")).catch(w=>{w instanceof L&&w.status===401?p("Saved session expired \u2014 please sign in again."):p(Oe(w)),c("auth")})},[]);let x=async(w,f)=>{p(void 0),await ue({env:e,userToken:w,devSecret:n,email:f}),c("loading");try{await t.init(e,w,f),c("manage")}catch(b){p(Oe(b)),c("auth")}};return o==="auth"?bt(ve,{env:e,initialError:h,onAuthed:x}):o==="loading"?bt(Jn,{children:bt(Xn,{children:"Loading your sites\u2026 "})}):bt($e,{controller:t})}import{jsx as nr}from"react/jsx-runtime";var Qn=Yn(import.meta.url),_t=te();if(_t.version){let t=Qn("../package.json");console.log(t.version),process.exit(0)}var Re=It.dirname(zn(import.meta.url)),Zn=Le(It.join(Re,"AGENT.md"),"utf-8"),tr=Le(It.join(Re,"build.mjs"),"utf-8");async function er(){let t=new ft(Zn,tr),e=await le(),n=(_t.env??e?.env??"production").toLowerCase(),r=_t.dev??process.env.SLEEKCMS_DEV_SECRET??e?.devSecret;ce(r),process.stdout.isTTY&&process.stdout.write("\x1B[2J\x1B[3J\x1B[H");let s=Vn(nr(De,{controller:t,env:n,devSecret:r,savedToken:e?.userToken,savedEmail:e?.email}),{exitOnCtrlC:!1}),o=c=>{s.unmount(),console.log(c),process.exit(0)};t.once("exit",()=>o("\u2713 Stopped. Local site files were cleaned up.")),t.once("logout",()=>o("\u{1F44B} Logged out. Run `sleekcms` to sign in again.")),process.on("SIGINT",()=>{t.exit()}),process.on("SIGTERM",()=>{t.exit()}),await s.waitUntilExit()}er().catch(t=>{let e=t;console.error("\u274C",e.body||e.message),process.exit(1)});
|
|
9
|
+
`)}async function Sn(t,e,n,r,s){Et.delete(S.resolve(t)),await m.remove(S.join(t,$t)),r("\u{1F4E5} Fetching files...");let o=await Ct(e,n,"GET","/get_files"),c={},h=0;for(let p of o){let x=S.join(t,p.path);await m.outputFile(x,p.content);let w=(await m.stat(x)).mtimeMs;h++,s?.(h,o.length),c[p.path]={mtimeMs:w}}return r(`\u2714\uFE0F Synced ${o.length} file(s).`),{fileMap:c,pulled:h}}import vn from"path";import Tn from"chokidar";var kn=5e3,Bn=/(^|[/\\])(\.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??kn}start(){if(this.watcher)return;let e=vn.join(this.viewsDir,"src");this.watcher=Tn.watch([e],{persistent:!0,ignoreInitial:!0,ignored:Bn}).on("change",()=>this.scheduleSync()).on("add",()=>this.scheduleSync()).on("unlink",()=>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 gt from"fs-extra";import En from"os";import ae from"path";var oe={localhost:"http://app.sleekcms.test/api",development:"https://app.sleekcms.dev/api",production:"https://app.sleekcms.com/api"};function Ot(t){return oe[t]||oe.production}var Cn=ae.join(En.homedir(),"SleekCMS"),ht=ae.join(Cn,"auth.json"),Mt;function ce(t){Mt=t||void 0}function Dt(t){let e=[];return t&&e.push(`_auth=${t}`),Mt&&e.push(`_dev=${Mt}`),e.length?e.join("; "):void 0}var L=class extends Error{status;body;constructor(e,n,r=""){super(e),this.name="UserAuthError",this.status=n,this.body=r}};async function le(){try{let t=await gt.readJson(ht);return t&&t.userToken?t:null}catch{return null}}async function ue(t){await gt.outputJson(ht,t,{spaces:2});try{await gt.chmod(ht,384)}catch{}}async function de(){await gt.remove(ht)}async function q(t){let e={},n=Dt(t.userToken);n&&(e.Cookie=n),t.subdomain&&(e["x-subdomain"]=t.subdomain),t.slug&&(e.site=t.slug),t.body!==void 0&&(e["Content-Type"]="application/json");let r=await fetch(Ot(t.env)+t.path,{method:t.method,headers:e,body:t.body!==void 0?JSON.stringify(t.body):void 0});if(!r.ok){let s=await r.text().catch(()=>"");throw new L(`${t.method} ${t.path} \u2192 ${r.status}: ${s}`,r.status,s)}return r.json()}async function ge(t,e){let n={"Content-Type":"application/json"},r=Dt();r&&(n.Cookie=r);let s=await fetch(Ot(t)+"/auth/otp",{method:"PUT",headers:n,body:JSON.stringify({email:e})});if(!s.ok){let c=await s.text().catch(()=>"");throw new L(`Failed to send OTP \u2192 ${s.status}: ${c}`,s.status,c)}return{otp:(await s.json().catch(()=>({}))).do_not_use_in_code}}async function Lt(t,e,n){let r={"Content-Type":"application/json"},s=Dt();s&&(r.Cookie=s);let o=await fetch(Ot(t)+"/auth/login",{method:"POST",headers:r,body:JSON.stringify({email:e,otp:n})});if(!o.ok){let p=await o.text().catch(()=>"");throw new L(`Login failed \u2192 ${o.status}: ${p}`,o.status,p)}let c=o.headers.getSetCookie?.()??[],h=Pn(c);if(!h)throw new L("Login succeeded but no _auth cookie was returned.",500);return h}function Pn(t){for(let e of t){let n=e.match(/(?:^|;\s*)_auth=([^;]+)/);if(n&&n[1])return decodeURIComponent(n[1])}return null}async function Rt(t,e){return q({env:t,userToken:e,method:"GET",path:"/org"})}async function he(t,e,n){return q({env:t,userToken:e,method:"GET",path:"/site",subdomain:n})}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,o=e.line!=null?`:${e.line}`:"",c=e.column!=null?`:${e.column}`:"",h=typeof e.message=="string"&&e.message?e.message:typeof e.name=="string"&&e.name?e.name:"",p=n&&r&&r!==n?` (on page ${r})`:"";if(s)return`${s}${o}${c}${p}: ${h||"(no message)"}`;if(h)return h;try{return JSON.stringify(t)}catch{return"(unknown error)"}}async function pe(t,e,n,r){let s;try{s=await q({env:t,userToken:e,method:"GET",path:"/site_build",subdomain:n,slug:r})}catch{return null}if(!Array.isArray(s)||s.length===0)return null;let o=s[0],c=s.find(p=>typeof p.url=="string"&&p.url.length>0),h=Array.isArray(o.errors)?o.errors.map($n):[];return h.length>0?{status:"error",mode:"preview",errors:h,url:c?.url||void 0,at:o.updated_at?Date.parse(o.updated_at):void 0}:c?{status:"success",mode:"preview",url:c.url||void 0,at:c.updated_at?Date.parse(c.updated_at):void 0}:null}async function fe(t,e,n,r){let{token:s}=await q({env:t,userToken:e,method:"POST",path:"/site_user/api_token",subdomain:n,slug:r,body:{refresh:!1}});return s}async function me(t,e,n){let r=await q({env:t,userToken:e,method:"POST",path:"/org",body:n?{name:n}:{}});return{id:r.id,name:r.name,subdomain:r.subdomain}}async function ye(t,e,n,r){let s=await q({env:t,userToken:e,method:"POST",path:"/site",subdomain:n,body:{name:r}});return{id:s.id,name:s.name,slug:s.slug}}var we=500;function Ln(){return new Date().toTimeString().slice(0,8)}function pt(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}async function be(t){t&&(await Q.remove(At.join(t,"src")),await Q.remove(At.join(t,".cache","state.json")))}var ft=class extends Mn{env="production";userToken="";email;catalog=[];synced=new Map;message;messageIsError=!1;agentMd;buildScript;isShuttingDown=!1;constructor(e,n){super(),this.agentMd=e,this.buildScript=n}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:Ln(),text:n}),r.logs.length>we&&r.logs.splice(0,r.logs.length-we),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,n,r){this.env=e,this.userToken=n,r&&(this.email=r);let s=await Rt(e,n);await this.buildCatalog(s)}async buildCatalog(e){let n=[];for(let r of e)try{n.push({org:r,sites:await he(this.env,this.userToken,r.subdomain)})}catch(s){if(s instanceof L&&s.status===401)throw s;n.push({org:r,sites:[]})}this.catalog=n,this.changed()}isSynced(e){return this.synced.has(e)}availableSites(){let e=[];for(let n of this.catalog)for(let r of n.sites)this.synced.has(r.id)||e.push({org:n.org,site:r});return e}async addSite(e,n){if(this.synced.has(n.id))return;let r;try{r=await fe(this.env,this.userToken,e.subdomain,n.slug)}catch(o){this.flash(`Failed to authorize "${n.name}": ${pt(o)}`,!0);return}let s={org:e,site:n,siteToken:r,viewsDir:"",status:"syncing",logs:[]};this.synced.set(n.id,s),this.appendLog(n.id,"\u2795 added \u2014 pulling files"),this.changed();try{let o=await Pt({token:r,env:this.env,agentMd:this.agentMd,buildScript:this.buildScript,log:c=>this.appendLog(n.id,c),onProgress:(c,h)=>{s.progress={done:c,total:h},this.changed()}});s.viewsDir=o.viewsDir,s.progress=void 0,s.status="watching",s.lastSyncedAt=Date.now(),s.lastMsg=`pulled ${o.pulled} file(s)`,s.watcher=new V({viewsDir:o.viewsDir,onSync:()=>this.runSync(n.id)}),s.watcher.start(),this.watchBuildStatus(n.id),this.seedLastBuild(n.id),this.appendLog(n.id,"\u{1F440} watching for changes")}catch(o){let c=o;s.status="error",s.progress=void 0,s.lastMsg=c.body||c.message,this.appendLog(n.id,`\u274C ${c.body||c.message}`)}this.changed()}async removeSite(e){let n=this.synced.get(e);n&&(n.watcher?.setShuttingDown(!0),await n.watcher?.stop(),await n.buildWatcher?.close(),await be(n.viewsDir),this.synced.delete(e),this.changed())}buildSite(e,n=!1){let r=this.synced.get(e);if(!r||!r.viewsDir)return;let s=n?"live":"preview";this.writeBuildFile(r.viewsDir,{status:"building",mode:s,stage:"queued",url:r.lastBuild?.url,at:Date.now()}),On("node",n?["build.mjs","--publish"]:["build.mjs"],{cwd:r.viewsDir,stdio:"ignore"}).on("error",h=>{this.writeBuildFile(r.viewsDir,{status:"error",mode:s,errors:[h.message],url:r.lastBuild?.url,at:Date.now()}),this.appendLog(e,`\u274C build: ${h.message}`)}),this.appendLog(e,n?"\u{1F680} publishing\u2026":"\u{1F528} building\u2026")}buildFile(e){return At.join(e,".cache","build.json")}async readBuildFile(e){try{let n=await Q.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 Q.outputJson(s,n),await Q.rename(s,r)}catch{}}watchBuildStatus(e){let n=this.synced.get(e);!n||!n.viewsDir||(n.buildWatcher=Dn.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 pe(this.env,this.userToken,n.org.subdomain,n.site.slug);if(!r)return;let s=this.synced.get(e);if(!s)return;let o=await this.readBuildFile(s.viewsDir);o?.at!=null&&(r.at==null||o.at>=r.at)||await this.writeBuildFile(s.viewsDir,r)}async ensureOrg(e){if(e)return e;if(this.catalog[0])return this.catalog[0].org;let n;try{n=await Rt(this.env,this.userToken)}catch(r){return this.flash(`Couldn't check your organizations: ${pt(r)}`,!0),null}if(n.length>0){try{await this.buildCatalog(n)}catch{}return n[0]}try{let r=this.email?`${this.email.split("@")[0]}'s Sites`:"My Sites";this.flash("No organization yet \u2014 creating one\u2026");let s=await me(this.env,this.userToken,r);return this.catalog=[...this.catalog,{org:s,sites:[]}],this.changed(),s}catch(r){return this.flash(`Could not create an organization: ${pt(r)}`,!0),null}}async createNewSite(e,n){let r=await this.ensureOrg(n);if(!r)return;let s;try{s=await ye(this.env,this.userToken,r.subdomain,e)}catch(c){this.flash(`Could not create "${e}": ${pt(c)}`,!0);return}let o=this.catalog.find(c=>c.org.id===r.id);o&&!o.sites.some(c=>c.id===s.id)&&(o.sites=[...o.sites,s]),this.flash(`Created "${s.name}".`),await this.addSite(r,s)}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 Pt({token:r.siteToken,env:this.env,viewsDir:r.viewsDir,agentMd:this.agentMd,buildScript:this.buildScript,flush:n.flush,log:o=>this.appendLog(e,o),onProgress:(o,c)=>{r.progress={done:o,total:c},this.changed()}});r.progress=void 0,r.status="watching",r.lastSyncedAt=Date.now(),n.flush?r.lastMsg=`re-fetched ${s.pulled} file(s)`:r.lastMsg=s.pushed>0?`pushed ${s.pushed} file(s)`:"up to date"}catch(s){let o=s;r.status="error",r.progress=void 0,r.lastMsg=o.body||o.message,this.appendLog(e,`\u274C ${o.body||o.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(){for(let e of this.synced.values())e.watcher?.setShuttingDown(!0),await e.watcher?.stop(),await e.buildWatcher?.close(),await be(e.viewsDir)}async exit(){this.isShuttingDown||(this.isShuttingDown=!0,await this.cleanupAll(),this.emit("exit"))}async logout(){this.isShuttingDown||(this.isShuttingDown=!0,await de(),await this.cleanupAll(),this.emit("logout"))}};import{useEffect as Hn,useState as Me}from"react";import{Box as Jn,Text as Xn,useInput as Kn}from"ink";import{useState as Z}from"react";import{Box as tt,Text as H}from"ink";import xe from"ink-text-input";import{jsx as N,jsxs as J}from"react/jsx-runtime";function Se(t){let e=t;return e?.body||e?.message||String(t)}function ve({env:t,initialError:e,onAuthed:n}){let[r,s]=Z("email"),[o,c]=Z(""),[h,p]=Z(""),[x,w]=Z(e),[f,b]=Z(),v=async R=>{let E=R.trim();if(E){w(void 0),s("busy");try{let{otp:$}=await ge(t,E);if(c(E),$){let X=await Lt(t,E,$);await n(X,E);return}b(`OTP sent to ${E}`),s("otp")}catch($){w(Se($)),s("email")}}},O=async R=>{let E=R.trim();if(E){w(void 0),s("busy");try{let $=await Lt(t,o,E);await n($,o)}catch($){w(Se($)),p(""),s("otp")}}};return J(tt,{flexDirection:"column",children:[J(H,{bold:!0,children:["\u25C6 SleekCMS \u2014 sign in",t!=="production"?` (${t})`:""]}),x?J(H,{color:"red",children:["\u2717 ",x]}):null,r==="email"&&J(tt,{marginTop:1,children:[N(H,{children:"Email: "}),N(xe,{value:o,onChange:c,onSubmit:v,placeholder:"you@example.com"})]}),r==="otp"&&J(tt,{flexDirection:"column",marginTop:1,children:[f?N(H,{color:"green",children:f}):null,J(tt,{children:[N(H,{children:"Enter OTP: "}),N(xe,{value:h,onChange:p,onSubmit:O})]})]}),r==="busy"&&N(tt,{marginTop:1,children:N(H,{children:"Working\u2026"})})]})}import{Fragment as An,useEffect as et,useMemo as Fn,useState as C}from"react";import{Box as g,Text as l,useInput as jn,useStdout as _n}from"ink";import Be from"ink-text-input";import Rn from"node:os";function Ft(t){if(!t)return"\u2014";let e=Rn.homedir();return t.startsWith(e)?"~"+t.slice(e.length):t}function jt(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 yt(t){return!t||t.total<=0?null:Math.round(t.done/t.total*100)}var mt=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"];function Te(t){return mt[(t%mt.length+mt.length)%mt.length]}function wt(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 ke(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 nt,jsx as i,jsxs as u}from"react/jsx-runtime";var U=(t,e)=>e<=0?0:Math.max(0,Math.min(t,e-1)),In=16,Nn=5,Un="greenBright",Ee="blueBright",Ce="magentaBright";function Pe({k:t,bg:e=Un}){return i(l,{color:"black",backgroundColor:e,children:` ${t} `})}function j({k:t,label:e,width:n=16,bg:r}){return u(g,{width:n,children:[i(Pe,{k:t,bg:r}),i(l,{color:"gray",children:` ${e}`})]})}function B({k:t,label:e,bg:n}){return u(g,{marginBottom:1,children:[i(g,{width:9,children:i(Pe,{k:t,bg:n})}),i(l,{color:"gray",children:e})]})}function Wn({launchers:t}){return u(g,{flexDirection:"column",borderStyle:"round",borderColor:"green",paddingX:2,paddingY:1,width:66,children:[u(g,{justifyContent:"space-between",children:[i(l,{color:"green",bold:!0,children:"KEYBOARD SHORTCUTS"}),i(l,{color:"gray",children:"? or esc to close"})]}),u(g,{marginTop:1,children:[u(g,{flexDirection:"column",width:34,children:[i(l,{color:"cyan",bold:!0,children:"Navigate"}),i(B,{k:"\u2191\u2193",label:"move selection"}),i(B,{k:"tab",label:"focus logs \xB7 \u2191\u2193 scroll"}),i(B,{k:"esc",label:"clear filter / back"}),i(g,{marginTop:1,children:i(l,{color:"cyan",bold:!0,children:"Global"})}),i(B,{k:"/",label:"search sites"}),i(B,{k:"n",label:"new site"}),i(B,{k:"?",label:"toggle this help",bg:Ee}),i(B,{k:"q",label:"logout"}),i(B,{k:"ctrl+c",label:"quit"})]}),u(g,{flexDirection:"column",flexGrow:1,children:[i(l,{color:"cyan",bold:!0,children:"Site actions"}),i(B,{k:"s",label:"start sync"}),i(B,{k:"d",label:"disconnect"}),i(B,{k:"p",label:"pause / resume sync"}),i(B,{k:"b",label:"build preview"}),i(B,{k:"B",label:"publish live"}),i(B,{k:"o",label:"open preview url"}),t.map((e,n)=>i(B,{k:String(n+1),label:`open in ${e.label}`,bg:Ce},e.key))]})]})]})}function Gn({percent:t,width:e=28}){let n=Math.round(Math.max(0,Math.min(100,t))/100*e);return u(l,{children:[i(l,{color:"green",children:"\u2588".repeat(n)}),i(l,{color:"gray",children:"\u2591".repeat(Math.max(0,e-n))})]})}function qn({frame:t,width:e=24,seg:n=6}){let r=e+n,s=t%r-n,o="";for(let c=0;c<e;c++)o+=c>=s&&c<s+n?"\u25AE":"\u25AF";return i(l,{color:"yellow",children:o})}function $e({controller:t}){let{stdout:e}=_n(),n=Fn(()=>se(),[]),[,r]=C(0),[s,o]=C(()=>new Date),[c,h]=C(null),[p,x]=C(()=>t.synced.size>0||t.catalog.some(d=>d.sites.length>0)?"dashboard":t.catalog.length<=1?"newName":"newOrg"),[w,f]=C(0),[b,v]=C(""),[O,R]=C(!1),[E,$]=C(""),[X,rt]=C(!1),[Nt,Ae]=C(0),[Ut,Wt]=C(!1),[Fe,je]=C(!1),[st,it]=C("list"),[_e,K]=C(0),Gt=()=>r(a=>a+1);et(()=>(t.on("change",Gt),()=>{t.off("change",Gt)}),[t]),et(()=>{let a,d=()=>{o(new Date),a=setTimeout(d,6e4-Date.now()%6e4)};return a=setTimeout(d,6e4-Date.now()%6e4),()=>clearTimeout(a)},[]);let F=t.catalog.flatMap(a=>a.sites.map(d=>({org:a.org,site:d,entry:t.synced.get(d.id)}))).sort((a,d)=>(a.entry?0:1)-(d.entry?0:1)),_=E.trim().toLowerCase(),M=_?F.filter(a=>a.site.name.toLowerCase().includes(_)||(a.org.name||a.org.subdomain||"").toLowerCase().includes(_)):F,W=M.findIndex(a=>a.site.id===c);W<0&&(W=0);let T=M[W],y=T?.entry,ot=Math.max(3,(e?.rows??30)-26),I=y?.logs??[],xt=Math.max(0,I.length-ot),Ie=Math.min(_e,xt),at=I.length-Ie,qt=I.slice(Math.max(0,at-ot),at),Ne=T?.site.id;et(()=>K(0),[Ne]);let A=y?.lastBuild,St=A?.status==="building",vt=ke(A),ct=St;if(!ct){for(let a of t.synced.values())if(a.status==="syncing"){ct=!0;break}}et(()=>{if(!ct)return;let a=setInterval(()=>Ae(d=>d+1),120);return()=>clearInterval(a)},[ct]);let Ht=M.findIndex(a=>!a.entry),G=Math.max(Nn,(e?.rows??30)-In),z=M.length,lt=z>G,Ue=Math.floor(G/2),Y=lt?Math.max(0,Math.min(W-Ue,z-G)):0,Tt=Math.min(z,Y+G),We=M.slice(Y,Tt);et(()=>{p!=="dashboard"||O||F.length>0||(v(""),t.catalog.length<=1?x("newName"):(f(0),x("newOrg")))},[F.length,p,O,t.catalog.length]);let ut=a=>{if(M.length===0)return;let d=U(W+a,M.length);h(M[d].site.id)},Ge=()=>{if(T){if(T.entry){t.flash("Already syncing \u2014 press d to disconnect.");return}t.addSite(T.org,T.site)}},qe=()=>{T?.entry&&t.removeSite(T.site.id)},He=()=>{v(""),t.catalog.length<=1?x("newName"):(f(0),x("newOrg"))},Je=a=>{if(!y){t.flash("Press s to start syncing this site first.",!0);return}je(!0);let d=a.run(y.viewsDir);t.flash(d?`Opened ${a.label} at ${Ft(y.viewsDir)}`:`Couldn't open ${a.label}.`,!d)},Xe=()=>{if(!y){t.flash("Press s to start syncing this site first.",!0);return}t.togglePause(y.site.id)},Jt=a=>{if(!y){t.flash("Press s to start syncing this site first.",!0);return}t.buildSite(y.site.id,a),t.flash(a?"Publishing \u2014 making this live\u2026":"Building preview\u2026")},Ke=()=>{let a=y?.lastBuild?.url;if(!a){t.flash("No build URL yet \u2014 press b to build.",!0);return}t.flash(re(a)?`Opening ${a}`:"Couldn't open the browser.",!1)};jn((a,d)=>{if(Ut){(a==="?"||d.escape)&&Wt(!1);return}if(p==="newOrg"){d.escape?x("dashboard"):d.upArrow?f(k=>U(k-1,t.catalog.length)):d.downArrow?f(k=>U(k+1,t.catalog.length)):d.return&&x("newName");return}if(X){d.escape?(rt(!1),$(""),h(null)):d.return?rt(!1):d.upArrow?ut(-1):d.downArrow&&ut(1);return}if(d.tab){st==="logs"?it("list"):y&&it("logs"),K(0);return}if(st==="logs"){if(d.escape){it("list"),K(0);return}if(d.upArrow)return void K(k=>Math.min(k+1,xt));if(d.downArrow)return void K(k=>Math.max(0,k-1))}if(d.escape){$(""),h(null);return}if(a==="?")return void Wt(!0);if(a==="/")return it("list"),void rt(!0);if(a==="n")return void He();if(a==="q")return void t.logout();if(d.upArrow)return ut(-1);if(d.downArrow)return ut(1);if(a==="s")return Ge();if(a==="d")return qe();if(a==="p")return Xe();if(a==="b")return Jt(!1);if(a==="B")return Jt(!0);if(a==="o")return Ke();if(a>="1"&&a<="9"){let k=n[parseInt(a,10)-1];if(k)return Je(k)}},{isActive:p!=="newName"});let ze=async a=>{let d=a.trim();if(!d){x("dashboard");return}let k=t.catalog[U(w,t.catalog.length)]?.org??t.catalog[0]?.org;R(!0),x("dashboard"),await t.createNewSite(d,k),R(!1)},Xt=u(g,{justifyContent:"space-between",paddingX:1,children:[u(g,{children:[i(l,{color:"green",bold:!0,children:"\u25C6 SleekCMS"}),i(l,{color:"gray",children:" \u2502 "}),i(l,{children:t.email??"signed in"})]}),u(g,{children:[u(l,{color:"gray",children:[_?`${M.length}/${F.length}`:F.length," sites \xB7 "]}),u(l,{color:"green",children:[t.watchingCount()," watching"]}),i(l,{color:"gray",children:` \xB7 ${s.toTimeString().slice(0,5)}`})]})]});return Ut?u(g,{flexDirection:"column",children:[Xt,i(g,{marginTop:1,justifyContent:"center",children:i(Wn,{launchers:n})})]}):u(g,{flexDirection:"column",children:[Xt,u(g,{children:[u(g,{flexDirection:"column",borderStyle:"round",borderColor:"green",width:38,paddingX:1,children:[u(g,{justifyContent:"space-between",children:[i(l,{color:"green",bold:!0,children:"SITE WORKSPACES"}),F.length>G&&!X&&!_?i(l,{color:"gray",children:"/ filter"}):null]}),X?u(g,{children:[i(l,{color:"cyan",children:"/ "}),i(Be,{value:E,onChange:$,onSubmit:()=>rt(!1),placeholder:"type to filter\u2026"})]}):_?i(l,{color:"gray",children:`/ ${E} \xB7 ${M.length} match${M.length===1?"":"es"}`}):null,i(g,{flexDirection:"column",marginTop:1,minHeight:lt?G+3:void 0,children:M.length===0?i(l,{color:"gray",children:_?`no matches for \u201C${E}\u201D`:"no sites \u2014 press n to create one"}):u(nt,{children:[lt?i(l,{color:"gray",children:Y>0?` \u2191 ${Y} more`:" "}):null,We.map((a,d)=>{let k=Y+d,Kt=a.entry?wt(a.entry.status):{dot:"\xB7",color:"gray",label:"idle"},zt=yt(a.entry?.progress),Ye=a.entry?a.entry.status==="syncing"&&zt!=null?`${zt}%`:a.entry.status==="paused"?"paused":"--":"",dt=k===W,Ve=k===Ht&&Ht>0;return u(An,{children:[Ve?i(l,{color:"gray",children:"\u2500".repeat(34)}):null,u(g,{justifyContent:"space-between",children:[u(g,{children:[i(l,{color:dt?"green":"gray",children:dt?"\u276F ":" "}),u(l,{color:a.entry?.status==="watching"||a.entry?.status==="syncing"?"green":Kt.color,children:[a.entry?.status==="syncing"?Te(Nt):a.entry?.status==="watching"?"\u25CF":Kt.dot," "]}),i(l,{color:dt?"white":a.entry?void 0:"gray",bold:dt,children:a.site.name})]}),i(l,{color:a.entry?.status==="syncing"?"green":"gray",children:Ye})]})]},a.site.id)}),lt?i(l,{color:"gray",children:Tt<z?` \u2193 ${z-Tt} more`:" "}):null]})}),i(g,{marginTop:1,children:i(l,{color:"gray",children:"+ new site \xB7 n"})})]}),u(g,{flexDirection:"column",flexGrow:1,marginLeft:1,children:[i(g,{flexDirection:"column",borderStyle:"round",borderColor:"gray",paddingX:1,children:T?u(nt,{children:[u(l,{children:[T.org.name||T.org.subdomain?u(l,{color:"gray",children:[T.org.name||T.org.subdomain," / "]}):null,i(l,{color:"cyan",bold:!0,children:T.site.name})]}),u(g,{marginTop:1,children:[i(l,{color:"gray",children:"status "}),y?i(l,{color:wt(y.status).color,children:`: ${wt(y.status).label}`}):i(l,{color:"gray",children:": idle \u2014 not syncing (press s to start)"})]}),u(g,{children:[i(l,{color:"gray",children:"path "}),i(l,{wrap:"truncate-end",children:y?.viewsDir?Ft(y.viewsDir):"\u2014"})]}),u(g,{children:[i(l,{color:"gray",children:"synced "}),i(l,{children:jt(y?.lastSyncedAt)}),i(l,{color:"gray",children:" progress "}),i(l,{color:y?.status==="syncing"?"green":"gray",children:y?.status==="syncing"?`${yt(y.progress)??0}%`:"\u2014"})]}),i(g,{marginTop:1,children:i(Gn,{percent:y?y.status==="syncing"?yt(y.progress)??0:y.status==="watching"?100:0:0})}),y?u(nt,{children:[u(g,{marginTop:1,children:[i(l,{color:"gray",children:"build "}),i(l,{color:vt.color,children:`${vt.dot} ${vt.label}`}),i(l,{color:"gray",children:" last "}),i(l,{children:St?"in progress":jt(A?.at)})]}),u(g,{children:[i(l,{color:"gray",children:"url "}),A?.url?i(l,{color:"cyan",wrap:"truncate-end",children:A.url}):i(l,{color:"gray",children:"\u2014"})]}),A?.status==="error"&&A.errors?.length?u(g,{children:[i(l,{color:"red",children:"\u258C "}),i(l,{color:"red",wrap:"truncate-end",children:`\u2717 ${A.errors[0]}`})]}):null,St?u(g,{children:[i(qn,{frame:Nt}),i(l,{color:"gray",children:` ${A?.stage??"building"}`})]}):null]}):null]}):i(l,{color:"gray",children:"No site selected."})}),p==="dashboard"?u(g,{flexDirection:"column",borderStyle:"round",borderColor:st==="logs"?"green":"gray",paddingX:1,marginTop:1,height:ot+4,flexShrink:0,overflowY:"hidden",children:[u(g,{justifyContent:"space-between",children:[u(l,{children:[i(l,{color:"cyan",bold:!0,children:"LOGS \xB7 "}),i(l,{color:"white",children:T?.site.name??"\u2014"})]}),y&&I.length>0?st==="logs"?i(l,{color:"green",children:`\u2191\u2193 scroll \xB7 esc back${xt>0?` \xB7 ${at}/${I.length}`:""}`}):I.length>ot?i(l,{color:"gray",children:"tab to scroll"}):null:null]}),i(g,{flexDirection:"column",marginTop:1,children:!y||I.length===0?i(l,{color:"gray",children:"no activity yet"}):qt.map((a,d)=>u(l,{wrap:"truncate-end",children:[u(l,{color:"gray",children:[a.time," "]}),a.text]},at-qt.length+d))})]}):u(g,{flexDirection:"column",borderStyle:"round",borderColor:"blue",paddingX:1,marginTop:1,flexGrow:1,children:[p==="newOrg"&&u(nt,{children:[i(l,{color:"cyan",bold:!0,children:"CREATE SITE \u2014 PICK ORG"}),i(l,{color:"gray",children:"\u2191/\u2193 select \xB7 \u23CE next \xB7 esc cancel"}),i(g,{flexDirection:"column",marginTop:1,children:t.catalog.map((a,d)=>u(l,{color:d===U(w,t.catalog.length)?"blue":void 0,bold:d===U(w,t.catalog.length),children:[d===U(w,t.catalog.length)?"\u276F ":" ",a.org.name||a.org.subdomain]},a.org.id))})]}),p==="newName"&&u(nt,{children:[i(l,{color:"cyan",bold:!0,children:"CREATE SITE"}),u(g,{marginTop:1,children:[i(l,{children:"New site name: "}),i(Be,{value:b,onChange:v,onSubmit:ze})]}),i(l,{color:"gray",children:"\u23CE create \xB7 empty + \u23CE to cancel"})]})]})]})]}),t.message?i(g,{paddingX:1,children:u(l,{color:t.messageIsError?"red":"gray",wrap:"truncate-end",children:[t.messageIsError?"\u2717 ":"",t.message]})}):null,u(g,{flexDirection:"column",marginTop:1,children:[u(g,{paddingX:1,justifyContent:"space-between",children:[u(g,{flexWrap:"wrap",children:[i(j,{k:"\u2191\u2193",label:"select"}),i(j,{k:"/",label:"search"}),i(j,{k:"s",label:"start sync"}),i(j,{k:"d",label:"disconnect"}),F.length===0?i(j,{k:"n",label:"new site"}):null,i(j,{k:"ctrl+c",label:"quit",width:14})]}),i(j,{k:"?",label:"all keys",width:12,bg:Ee})]}),!Fe&&n.length>0?i(g,{paddingX:1,marginTop:1,flexWrap:"wrap",children:n.map((a,d)=>i(j,{k:String(d+1),label:a.label,bg:Ce},a.key))}):null]})]})}import{jsx as bt}from"react/jsx-runtime";function Oe(t){let e=t;return e?.body||e?.message||String(t)}function De({controller:t,env:e,devSecret:n,savedToken:r,savedEmail:s}){let[o,c]=Me(r?"loading":"auth"),[h,p]=Me();Kn((w,f)=>{f.ctrl&&w==="c"&&t.exit()}),Hn(()=>{r&&t.init(e,r,s).then(()=>c("manage")).catch(w=>{w instanceof L&&w.status===401?p("Saved session expired \u2014 please sign in again."):p(Oe(w)),c("auth")})},[]);let x=async(w,f)=>{p(void 0),await ue({env:e,userToken:w,devSecret:n,email:f}),c("loading");try{await t.init(e,w,f),c("manage")}catch(b){p(Oe(b)),c("auth")}};return o==="auth"?bt(ve,{env:e,initialError:h,onAuthed:x}):o==="loading"?bt(Jn,{children:bt(Xn,{children:"Loading your sites\u2026 "})}):bt($e,{controller:t})}import{jsx as nr}from"react/jsx-runtime";var Qn=Yn(import.meta.url),_t=te();if(_t.version){let t=Qn("../package.json");console.log(t.version),process.exit(0)}var Re=It.dirname(zn(import.meta.url)),Zn=Le(It.join(Re,"AGENT.md"),"utf-8"),tr=Le(It.join(Re,"build.mjs"),"utf-8");async function er(){let t=new ft(Zn,tr),e=await le(),n=(_t.env??e?.env??"production").toLowerCase(),r=_t.dev??process.env.SLEEKCMS_DEV_SECRET??e?.devSecret;ce(r),process.stdout.isTTY&&process.stdout.write("\x1B[2J\x1B[3J\x1B[H");let s=Vn(nr(De,{controller:t,env:n,devSecret:r,savedToken:e?.userToken,savedEmail:e?.email}),{exitOnCtrlC:!1}),o=c=>{s.unmount(),console.log(c),process.exit(0)};t.once("exit",()=>o("\u2713 Stopped. Local site files were cleaned up.")),t.once("logout",()=>o("\u{1F44B} Logged out. Run `sleekcms` to sign in again.")),process.on("SIGINT",()=>{t.exit()}),process.on("SIGTERM",()=>{t.exit()}),await s.waitUntilExit()}er().catch(t=>{let e=t;console.error("\u274C",e.body||e.message),process.exit(1)});
|