@sleekcms/sync 2.9.0 → 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 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 … → <url>` — **give that URL to the user** so they can view the result.
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 v2 — SleekCMS workspace build/deploy script.
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. Prints the PREVIEW
8
- * URL on success, or the build errors to fix.
9
- * node build.mjs --deploy Build + publish LIVE. Prints the live URL.
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/deploy and polls it to a terminal state (mirrors the
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/deployed, 1 = build errors, 2 = couldn't run / still building.
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 deploy endpoint's error entries to plain strings. */
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 DeployError extends Error {
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 callDeploy(base, token, deploy, force, fetchImpl) {
80
- const res = await fetchImpl(base + "/deploy", {
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({ build_only: !deploy, force }),
88
+ body: JSON.stringify(body),
84
89
  });
85
90
  if (!res.ok) {
86
91
  const text = await res.text().catch(() => "");
87
- throw new DeployError(`/deploy → ${res.status}: ${text}`, res.status);
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 the SAME job to a terminal state. Mirrors
94
- * cms-agent's build_site(): first call force=true (enqueue a fresh build),
95
- * subsequent polls force=false (don't re-trigger). `onPoll(status, poll)` fires
96
- * after each response so the caller can surface progress.
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 { base, token, deploy = false, maxPolls = DEFAULT_MAX_POLLS, fetchImpl = fetch, onPoll } = opts;
100
- let r = await callDeploy(base, token, deploy, true, fetchImpl);
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 callDeploy(base, token, deploy, false, fetchImpl);
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 = { deploy: false, env: undefined };
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
- if (a === "--deploy" || a === "--live") flags.deploy = true;
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.deploy ? "live" : "preview";
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.deploy ? "Deploying" : "Building"} site…`);
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
- deploy: flags.deploy,
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(`✅ Build ${flags.deploy ? "deployed (live)" : "succeeded (preview)"}${url ? ` → ${url}` : ""}`);
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
- console.log(`⏳ Still building${url ? ` → ${url}` : ""}. Re-run \`node build.mjs\` to check again.`);
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
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import{readFileSync as Le}from"node:fs";import{fileURLToPath as Xr}from"node:url";import{createRequire as Kr}from"node:module";import It from"node:path";import{render as zr}from"ink";import{execSync as Zt,spawn as P}from"child_process";import{program as Yt,Option as kt}from"commander";function te(){return Yt.name("cms-sync").description("SleekCMS CLI tool to sync and edit CMS templates locally. Log in once, then add the sites you want to sync \u2014 changes are watched and pushed automatically.").addOption(new kt("-v, --version","output the version number").hideHelp()).addOption(new kt("-e, --env <env>","Environment (localhost, development, production)").default("production").hideHelp()).addOption(new kt("-d, --dev <secret>","Dev secret for non-production envs (sent as the _dev cookie; enables OTP-in-response). Falls back to SLEEKCMS_DEV_SECRET.").hideHelp()).option("-p, --path <path>","Directory path for files (default: ~/SleekCMS)").addHelpText("after",`
2
+ import{readFileSync as Le}from"node:fs";import{fileURLToPath as zn}from"node:url";import{createRequire as Yn}from"node:module";import It from"node:path";import{render as Vn}from"ink";import{execSync as Zt,spawn as P}from"child_process";import{program as Yt,Option as kt}from"commander";function te(){return Yt.name("cms-sync").description("SleekCMS CLI tool to sync and edit CMS templates locally. Log in once, then add the sites you want to sync \u2014 changes are watched and pushed automatically.").addOption(new kt("-v, --version","output the version number").hideHelp()).addOption(new kt("-e, --env <env>","Environment (localhost, development, production)").default("production").hideHelp()).addOption(new kt("-d, --dev <secret>","Dev secret for non-production envs (sent as the _dev cookie; enables OTP-in-response). Falls back to SLEEKCMS_DEV_SECRET.").hideHelp()).option("-p, --path <path>","Directory path for files (default: ~/SleekCMS)").addHelpText("after",`
3
3
  Examples:
4
4
  $ sleekcms # log in and pick sites to sync
5
5
  $ sleekcms -e development # use a non-production backend
6
- `).parse(process.argv),Yt.opts()}function $(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 r={detached:!0,stdio:"ignore",windowsHide:!0};process.platform==="win32"?P("cmd.exe",["/c",t,...e],r).unref():P(t,e,r).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 n=(e?Vt.filter(i=>i.cmd===e):Vt).find(i=>$(i.cmd));return n?(Qe(n.cmd,n.args(t)),n.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($("wt"))P("wt.exe",["-d",t],{detached:!0,stdio:"ignore"}).unref();else{let e=$("powershell")?"powershell.exe":"cmd.exe";P("cmd.exe",["/c","start","",e],{cwd:t,detached:!0,stdio:"ignore"}).unref()}return!0}return!1}function tr(t){return ee("iTerm")?(P("open",["-a","iTerm",t],{detached:!0,stdio:"ignore"}).unref(),!0):!1}function er(t){return`'${t.replace(/'/g,"'\\''")}'`}var rr=[{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 re(t,e){if(!$(e))return!1;if(process.platform==="darwin"){let n=`tell application "Terminal" to do script ("cd " & quoted form of "${t}" & " && ${e}")`;return P("osascript",["-e",n,"-e",'tell application "Terminal" to activate'],{detached:!0,stdio:"ignore"}).unref(),!0}if(process.platform==="win32")return $("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 r=`cd ${er(t)} && ${e}; exec bash`;for(let n of rr)if($(n.cmd))try{return P(n.cmd,n.args(r),{cwd:t,detached:!0,stdio:"ignore"}).unref(),!0}catch{}return!1}function nr(t){return re(t,"claude")}function ir(t){return re(t,"pi")}function ne(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 ie(){let t=process.platform==="darwin",e=process.platform==="win32",r=[];return(t||e)&&r.push({key:"terminal",label:"terminal",run:Ze}),ee("iTerm")&&r.push({key:"iterm",label:"iterm",run:tr}),$("code")&&r.push({key:"code",label:"vscode",run:n=>Qt(n,"code")!==null}),$("cursor")&&r.push({key:"cursor",label:"cursor",run:n=>Qt(n,"cursor")!==null}),$("claude")&&r.push({key:"claude",label:"claude",run:nr}),$("pi")&&r.push({key:"pi",label:"pi",run:ir}),r}import{EventEmitter as Pr}from"node:events";import{spawn as Mr}from"node:child_process";import Q from"fs-extra";import At from"path";import Dr from"chokidar";import f from"fs-extra";import or from"os";import S from"path";var se={localhost:"http://app.sleekcms.test/api/mcp",development:"https://app.sleekcms.dev/api/mcp",production:"https://app.sleekcms.com/api/mcp"},ar=["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,r,n){super(e),this.status=r,this.body=n}};async function Ct(t,e,r,n,i){let o=await fetch(t+n,{method:r,headers:{Authorization:`Bearer ${e}`,...i!==void 0?{"Content-Type":"application/json"}:{}},body:i!==void 0?JSON.stringify(i):void 0});if(!o.ok){let l=await o.text();throw new Bt(`${r} ${n} \u2192 ${o.status}: ${l}`,o.status,l)}return o.json()}async function cr(t,e){e&&(await f.outputFile(S.join(t,"AGENT.md"),e),await f.outputFile(S.join(t,"CLAUDE.md"),e),await f.outputFile(S.join(t,".vscode","copilot-instructions.md"),e)),await f.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 lr(t,e){if(!e)return;let r=S.join(t,"build.mjs"),n=e.match(/build\.mjs v\d+/)?.[0];if(await f.pathExists(r)){let i=(await f.readFile(r,"utf-8")).match(/build\.mjs v\d+/)?.[0];if(i&&i===n)return}await f.outputFile(r,e)}async function ur(t,e,r){let n=S.join(t,".cache","token");if(await f.pathExists(n)){if((await f.readFile(n,"utf-8")).trim()===e)return;r?.("\u267B\uFE0F Workspace was tied to a different site \u2014 recreating it."),await f.emptyDir(t)}await f.outputFile(n,e)}function dr(t,e){let r=`${e.name.substr(0,20)} ${e.id}`.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,""),n=t||S.join(or.homedir(),"SleekCMS");return S.resolve(n,r)}async function Pt(t){let e=(t.token||"").trim();if(!e)throw new Error("syncSite: token is required");let r=t.log??(v=>console.log(v)),n=t.onProgress,i=(t.env||e.split("-")[2]||"production").toLowerCase(),o=se[i]||se.production,l=await Ct(o,e,"GET","/get_site"),h=t.viewsDir?S.resolve(t.viewsDir):dr(t.path,l);await f.ensureDir(h),await ur(h,e,r),await Promise.all(ar.map(v=>f.ensureDir(S.join(h,v)))),await lr(h,t.buildScript);let p=S.join(h,".cache","state.json");t.flush&&await f.remove(p);let x=!await f.pathExists(p),w=x?{}:(await f.readJson(p)).fileMap||{},m=0,b=0;return x?({fileMap:w,pulled:b}=await xr(h,o,e,r,n),await cr(h,t.agentMd)):m=await pr(h,w,o,e,r,n),await f.outputJson(p,{fileMap:w},{spaces:2}),{viewsDir:h,site:l,isFirstRun:x,pushed:m,pulled:b}}var gr=new Set([".DS_Store","Thumbs.db","desktop.ini"]);async function hr(t){let e=S.join(t,"src");if(!await f.pathExists(e))return[];let r=[];async function n(i){let o=await f.readdir(i,{withFileTypes:!0});for(let l of o){if(gr.has(l.name))continue;let h=S.join(i,l.name);l.isDirectory()?await n(h):l.isFile()&&r.push(S.relative(t,h).replace(/\\/g,"/"))}}return await n(e),r}async function pr(t,e,r,n,i,o){let l=[];for(let m of await hr(t)){let b=S.join(t,m),v=e[m],O=await f.stat(b);if(v&&v.mtimeMs===O.mtimeMs)continue;let R=await f.readFile(b,"utf-8");R.trim()&&l.push({rel:m,full:b,stat:O,content:R,prior:v})}if(l.length===0)return 0;let h;try{h=await Ct(r,n,"POST","/save_files",l.map(m=>({path:m.rel,content:m.content})))}catch(m){let b=m;return i(`\u274C Error saving files: ${b.body||b.message}`),0}let p=await yr(t),x=0,w=mr(h);for(let m=0;m<l.length;m++){let b=l[m],v=fr(b,m,h,w);if(o?.(m+1,l.length),!v){let O="No save response returned";p[b.rel]=O,i(`\u274C Error saving ${b.rel}: ${O}`);continue}if(v.error){p[b.rel]=v.error,i(`\u274C Error saving ${b.rel}: ${v.error}`);continue}delete p[b.rel],e[b.rel]={mtimeMs:b.stat.mtimeMs},i(`\u2705 ${b.prior?"Updated":"Created"} ${b.rel}`),x++}return await br(t,p),x}function mr(t){let e=new Map;for(let r of t)r.path&&e.set(r.path,r);return e}function fr(t,e,r,n){let i=n.get(t.rel);if(i)return i;let o=r[e];if(!o?.path||o.path===t.rel)return o}var Mt="sync-errors.log",Et=new Map;async function yr(t){let e=S.resolve(t),r=Et.get(e);if(r)return r;let n=await wr(e);return Et.set(e,n),n}async function wr(t){let e=S.join(t,Mt);if(!await f.pathExists(e))return{};let r=await f.readFile(e,"utf-8"),n={};for(let i of r.split(`
7
- `)){let o=i.indexOf(": ");o>0&&(n[i.slice(0,o)]=i.slice(o+2))}return n}async function br(t,e){let r=S.join(t,Mt),n=Object.entries(e);if(n.length===0){await f.remove(r);return}await f.outputFile(r,n.map(([i,o])=>`${i}: ${o}`).join(`
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
+ `)){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 xr(t,e,r,n,i){Et.delete(S.resolve(t)),await f.remove(S.join(t,Mt)),n("\u{1F4E5} Fetching files...");let o=await Ct(e,r,"GET","/get_files"),l={},h=0;for(let p of o){let x=S.join(t,p.path);await f.outputFile(x,p.content);let w=(await f.stat(x)).mtimeMs;h++,i?.(h,o.length),l[p.path]={mtimeMs:w}}return n(`\u2714\uFE0F Synced ${o.length} file(s).`),{fileMap:l,pulled:h}}import Sr from"path";import vr from"chokidar";var Tr=5e3,kr=/(^|[/\\])(\.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??Tr}start(){if(this.watcher)return;let e=Sr.join(this.viewsDir,"src");this.watcher=vr.watch([e],{persistent:!0,ignoreInitial:!0,ignored:kr}).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 r=e;console.error("\u274C Sync failed:",r.body||r.message)}finally{this.syncInFlight=!1}}}};import gt from"fs-extra";import Br 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 Er=ae.join(Br.homedir(),"SleekCMS"),ht=ae.join(Er,"auth.json"),Dt;function ce(t){Dt=t||void 0}function $t(t){let e=[];return t&&e.push(`_auth=${t}`),Dt&&e.push(`_dev=${Dt}`),e.length?e.join("; "):void 0}var L=class extends Error{status;body;constructor(e,r,n=""){super(e),this.name="UserAuthError",this.status=r,this.body=n}};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={},r=$t(t.userToken);r&&(e.Cookie=r),t.subdomain&&(e["x-subdomain"]=t.subdomain),t.slug&&(e.site=t.slug),t.body!==void 0&&(e["Content-Type"]="application/json");let n=await fetch(Ot(t.env)+t.path,{method:t.method,headers:e,body:t.body!==void 0?JSON.stringify(t.body):void 0});if(!n.ok){let i=await n.text().catch(()=>"");throw new L(`${t.method} ${t.path} \u2192 ${n.status}: ${i}`,n.status,i)}return n.json()}async function ge(t,e){let r={"Content-Type":"application/json"},n=$t();n&&(r.Cookie=n);let i=await fetch(Ot(t)+"/auth/otp",{method:"PUT",headers:r,body:JSON.stringify({email:e})});if(!i.ok){let l=await i.text().catch(()=>"");throw new L(`Failed to send OTP \u2192 ${i.status}: ${l}`,i.status,l)}return{otp:(await i.json().catch(()=>({}))).do_not_use_in_code}}async function Lt(t,e,r){let n={"Content-Type":"application/json"},i=$t();i&&(n.Cookie=i);let o=await fetch(Ot(t)+"/auth/login",{method:"POST",headers:n,body:JSON.stringify({email:e,otp:r})});if(!o.ok){let p=await o.text().catch(()=>"");throw new L(`Login failed \u2192 ${o.status}: ${p}`,o.status,p)}let l=o.headers.getSetCookie?.()??[],h=Cr(l);if(!h)throw new L("Login succeeded but no _auth cookie was returned.",500);return h}function Cr(t){for(let e of t){let r=e.match(/(?:^|;\s*)_auth=([^;]+)/);if(r&&r[1])return decodeURIComponent(r[1])}return null}async function Rt(t,e){return q({env:t,userToken:e,method:"GET",path:"/org"})}async function he(t,e,r){return q({env:t,userToken:e,method:"GET",path:"/site",subdomain:r})}async function pe(t,e,r,n){let i;try{i=await q({env:t,userToken:e,method:"GET",path:"/site_build",subdomain:r,slug:n})}catch{return null}if(!Array.isArray(i)||i.length===0)return null;let o=i[0],l=i.find(p=>typeof p.url=="string"&&p.url.length>0),h=Array.isArray(o.errors)?o.errors.map(p=>String(p)):[];return h.length>0?{status:"error",mode:"preview",errors:h,url:l?.url||void 0,at:o.updated_at?Date.parse(o.updated_at):void 0}:l?{status:"success",mode:"preview",url:l.url||void 0,at:l.updated_at?Date.parse(l.updated_at):void 0}:null}async function me(t,e,r,n){let{token:i}=await q({env:t,userToken:e,method:"POST",path:"/site_user/api_token",subdomain:r,slug:n,body:{refresh:!1}});return i}async function fe(t,e,r){let n=await q({env:t,userToken:e,method:"POST",path:"/org",body:r?{name:r}:{}});return{id:n.id,name:n.name,subdomain:n.subdomain}}async function ye(t,e,r,n){let i=await q({env:t,userToken:e,method:"POST",path:"/site",subdomain:r,body:{name:n}});return{id:i.id,name:i.name,slug:i.slug}}var we=500;function Or(){return new Date().toTimeString().slice(0,8)}function pt(t){let e=t;if(e.body){try{let r=JSON.parse(e.body);if(r&&typeof r.message=="string")return r.message;if(r&&typeof r.error=="string")return r.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 mt=class extends Pr{env="production";userToken="";email;catalog=[];synced=new Map;message;messageIsError=!1;agentMd;buildScript;isShuttingDown=!1;constructor(e,r){super(),this.agentMd=e,this.buildScript=r}changed(){this.emit("change")}flash(e,r=!1){this.message=e,this.messageIsError=r,this.changed()}appendLog(e,r){let n=this.synced.get(e);n&&(n.logs.push({time:Or(),text:r}),n.logs.length>we&&n.logs.splice(0,n.logs.length-we),this.changed())}siteCount(){return this.synced.size}syncingCount(){let e=0;for(let r of this.synced.values())r.status==="syncing"&&e++;return e}watchingCount(){let e=0;for(let r of this.synced.values())(r.status==="watching"||r.status==="syncing")&&e++;return e}async init(e,r,n){this.env=e,this.userToken=r,n&&(this.email=n);let i=await Rt(e,r);await this.buildCatalog(i)}async buildCatalog(e){let r=[];for(let n of e)try{r.push({org:n,sites:await he(this.env,this.userToken,n.subdomain)})}catch(i){if(i instanceof L&&i.status===401)throw i;r.push({org:n,sites:[]})}this.catalog=r,this.changed()}isSynced(e){return this.synced.has(e)}availableSites(){let e=[];for(let r of this.catalog)for(let n of r.sites)this.synced.has(n.id)||e.push({org:r.org,site:n});return e}async addSite(e,r){if(this.synced.has(r.id))return;let n;try{n=await me(this.env,this.userToken,e.subdomain,r.slug)}catch(o){this.flash(`Failed to authorize "${r.name}": ${pt(o)}`,!0);return}let i={org:e,site:r,siteToken:n,viewsDir:"",status:"syncing",logs:[]};this.synced.set(r.id,i),this.appendLog(r.id,"\u2795 added \u2014 pulling files"),this.changed();try{let o=await Pt({token:n,env:this.env,agentMd:this.agentMd,buildScript:this.buildScript,log:l=>this.appendLog(r.id,l),onProgress:(l,h)=>{i.progress={done:l,total:h},this.changed()}});i.viewsDir=o.viewsDir,i.progress=void 0,i.status="watching",i.lastSyncedAt=Date.now(),i.lastMsg=`pulled ${o.pulled} file(s)`,i.watcher=new V({viewsDir:o.viewsDir,onSync:()=>this.runSync(r.id)}),i.watcher.start(),this.watchBuildStatus(r.id),this.seedLastBuild(r.id),this.appendLog(r.id,"\u{1F440} watching for changes")}catch(o){let l=o;i.status="error",i.progress=void 0,i.lastMsg=l.body||l.message,this.appendLog(r.id,`\u274C ${l.body||l.message}`)}this.changed()}async removeSite(e){let r=this.synced.get(e);r&&(r.watcher?.setShuttingDown(!0),await r.watcher?.stop(),await r.buildWatcher?.close(),await be(r.viewsDir),this.synced.delete(e),this.changed())}buildSite(e,r=!1){let n=this.synced.get(e);if(!n||!n.viewsDir)return;let i=r?"live":"preview";this.writeBuildFile(n.viewsDir,{status:"building",mode:i,stage:"queued",url:n.lastBuild?.url,at:Date.now()}),Mr("node",r?["build.mjs","--deploy"]:["build.mjs"],{cwd:n.viewsDir,stdio:"ignore"}).on("error",h=>{this.writeBuildFile(n.viewsDir,{status:"error",mode:i,errors:[h.message],url:n.lastBuild?.url,at:Date.now()}),this.appendLog(e,`\u274C build: ${h.message}`)}),this.appendLog(e,r?"\u{1F680} deploying\u2026":"\u{1F528} building\u2026")}buildFile(e){return At.join(e,".cache","build.json")}async readBuildFile(e){try{let r=await Q.readJson(this.buildFile(e));return r&&r.status?r:null}catch{return null}}async writeBuildFile(e,r){let n=this.buildFile(e),i=`${n}.tmp`;try{await Q.outputJson(i,r),await Q.rename(i,n)}catch{}}watchBuildStatus(e){let r=this.synced.get(e);!r||!r.viewsDir||(r.buildWatcher=Dr.watch(this.buildFile(r.viewsDir),{ignoreInitial:!1}).on("add",()=>{this.readBuildStatus(e)}).on("change",()=>{this.readBuildStatus(e)}))}async readBuildStatus(e){let r=this.synced.get(e);if(!r)return;let n=await this.readBuildFile(r.viewsDir);if(!n)return;let i=r.lastBuild?.url;r.lastBuild={status:n.status,mode:n.mode??"preview",url:n.url??(n.status==="success"?void 0:i),errors:n.errors,stage:n.stage,at:n.at},this.changed()}async seedLastBuild(e){let r=this.synced.get(e);if(!r)return;let n=await pe(this.env,this.userToken,r.org.subdomain,r.site.slug);if(!n)return;let i=this.synced.get(e);if(!i)return;let o=await this.readBuildFile(i.viewsDir);o?.at!=null&&(n.at==null||o.at>=n.at)||await this.writeBuildFile(i.viewsDir,n)}async ensureOrg(e){if(e)return e;if(this.catalog[0])return this.catalog[0].org;let r;try{r=await Rt(this.env,this.userToken)}catch(n){return this.flash(`Couldn't check your organizations: ${pt(n)}`,!0),null}if(r.length>0){try{await this.buildCatalog(r)}catch{}return r[0]}try{let n=this.email?`${this.email.split("@")[0]}'s Sites`:"My Sites";this.flash("No organization yet \u2014 creating one\u2026");let i=await fe(this.env,this.userToken,n);return this.catalog=[...this.catalog,{org:i,sites:[]}],this.changed(),i}catch(n){return this.flash(`Could not create an organization: ${pt(n)}`,!0),null}}async createNewSite(e,r){let n=await this.ensureOrg(r);if(!n)return;let i;try{i=await ye(this.env,this.userToken,n.subdomain,e)}catch(l){this.flash(`Could not create "${e}": ${pt(l)}`,!0);return}let o=this.catalog.find(l=>l.org.id===n.id);o&&!o.sites.some(l=>l.id===i.id)&&(o.sites=[...o.sites,i]),this.flash(`Created "${i.name}".`),await this.addSite(n,i)}async refetch(e){await this.runSync(e,{flush:!0})}async runSync(e,r={}){let n=this.synced.get(e);if(!(!n||!n.viewsDir||n.status==="paused")){n.status="syncing",this.changed();try{let i=await Pt({token:n.siteToken,env:this.env,viewsDir:n.viewsDir,agentMd:this.agentMd,buildScript:this.buildScript,flush:r.flush,log:o=>this.appendLog(e,o),onProgress:(o,l)=>{n.progress={done:o,total:l},this.changed()}});n.progress=void 0,n.status="watching",n.lastSyncedAt=Date.now(),r.flush?n.lastMsg=`re-fetched ${i.pulled} file(s)`:n.lastMsg=i.pushed>0?`pushed ${i.pushed} file(s)`:"up to date"}catch(i){let o=i;n.status="error",n.progress=void 0,n.lastMsg=o.body||o.message,this.appendLog(e,`\u274C ${o.body||o.message}`)}this.changed()}}async togglePause(e){let r=this.synced.get(e);!r||!r.viewsDir||(r.status==="paused"?(r.watcher=new V({viewsDir:r.viewsDir,onSync:()=>this.runSync(e)}),r.watcher.start(),r.status="watching",this.appendLog(e,"\u25B6 resumed \u2014 watching for changes")):(r.watcher?.setShuttingDown(!0),await r.watcher?.stop(),r.watcher=void 0,r.progress=void 0,r.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 Gr,useState as De}from"react";import{Box as qr,Text as Hr,useInput as Jr}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:r}){let[n,i]=Z("email"),[o,l]=Z(""),[h,p]=Z(""),[x,w]=Z(e),[m,b]=Z(),v=async R=>{let E=R.trim();if(E){w(void 0),i("busy");try{let{otp:M}=await ge(t,E);if(l(E),M){let X=await Lt(t,E,M);await r(X,E);return}b(`OTP sent to ${E}`),i("otp")}catch(M){w(Se(M)),i("email")}}},O=async R=>{let E=R.trim();if(E){w(void 0),i("busy");try{let M=await Lt(t,o,E);await r(M,o)}catch(M){w(Se(M)),p(""),i("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,n==="email"&&J(tt,{marginTop:1,children:[N(H,{children:"Email: "}),N(xe,{value:o,onChange:l,onSubmit:v,placeholder:"you@example.com"})]}),n==="otp"&&J(tt,{flexDirection:"column",marginTop:1,children:[m?N(H,{color:"green",children:m}):null,J(tt,{children:[N(H,{children:"Enter OTP: "}),N(xe,{value:h,onChange:p,onSubmit:O})]})]}),n==="busy"&&N(tt,{marginTop:1,children:N(H,{children:"Working\u2026"})})]})}import{Fragment as Lr,useEffect as et,useMemo as Rr,useState as C}from"react";import{Box as g,Text as c,useInput as Ar,useStdout as Fr}from"ink";import Be from"ink-text-input";import $r from"node:os";function Ft(t){if(!t)return"\u2014";let e=$r.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 r=Math.floor(e/60);if(r<60)return`${r}m ago`;let n=Math.floor(r/60);return n<24?`${n}h ago`:`${Math.floor(n/24)}d ago`}function yt(t){return!t||t.total<=0?null:Math.round(t.done/t.total*100)}var ft=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"];function Te(t){return ft[(t%ft.length+ft.length)%ft.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 rt,jsx as s,jsxs as u}from"react/jsx-runtime";var U=(t,e)=>e<=0?0:Math.max(0,Math.min(t,e-1)),jr=16,_r=5,Ir="greenBright",Ee="blueBright",Ce="magentaBright";function Pe({k:t,bg:e=Ir}){return s(c,{color:"black",backgroundColor:e,children:` ${t} `})}function j({k:t,label:e,width:r=16,bg:n}){return u(g,{width:r,children:[s(Pe,{k:t,bg:n}),s(c,{color:"gray",children:` ${e}`})]})}function B({k:t,label:e,bg:r}){return u(g,{marginBottom:1,children:[s(g,{width:9,children:s(Pe,{k:t,bg:r})}),s(c,{color:"gray",children:e})]})}function Nr({launchers:t}){return u(g,{flexDirection:"column",borderStyle:"round",borderColor:"green",paddingX:2,paddingY:1,width:66,children:[u(g,{justifyContent:"space-between",children:[s(c,{color:"green",bold:!0,children:"KEYBOARD SHORTCUTS"}),s(c,{color:"gray",children:"? or esc to close"})]}),u(g,{marginTop:1,children:[u(g,{flexDirection:"column",width:34,children:[s(c,{color:"cyan",bold:!0,children:"Navigate"}),s(B,{k:"\u2191\u2193",label:"move selection"}),s(B,{k:"tab",label:"focus logs \xB7 \u2191\u2193 scroll"}),s(B,{k:"esc",label:"clear filter / back"}),s(g,{marginTop:1,children:s(c,{color:"cyan",bold:!0,children:"Global"})}),s(B,{k:"/",label:"search sites"}),s(B,{k:"n",label:"new site"}),s(B,{k:"?",label:"toggle this help",bg:Ee}),s(B,{k:"q",label:"logout"}),s(B,{k:"ctrl+c",label:"quit"})]}),u(g,{flexDirection:"column",flexGrow:1,children:[s(c,{color:"cyan",bold:!0,children:"Site actions"}),s(B,{k:"s",label:"start sync"}),s(B,{k:"d",label:"disconnect"}),s(B,{k:"p",label:"pause / resume sync"}),s(B,{k:"b",label:"build preview"}),s(B,{k:"B",label:"deploy live"}),s(B,{k:"o",label:"open preview url"}),t.map((e,r)=>s(B,{k:String(r+1),label:`open in ${e.label}`,bg:Ce},e.key))]})]})]})}function Ur({percent:t,width:e=28}){let r=Math.round(Math.max(0,Math.min(100,t))/100*e);return u(c,{children:[s(c,{color:"green",children:"\u2588".repeat(r)}),s(c,{color:"gray",children:"\u2591".repeat(Math.max(0,e-r))})]})}function Wr({frame:t,width:e=24,seg:r=6}){let n=e+r,i=t%n-r,o="";for(let l=0;l<e;l++)o+=l>=i&&l<i+r?"\u25AE":"\u25AF";return s(c,{color:"yellow",children:o})}function Me({controller:t}){let{stdout:e}=Fr(),r=Rr(()=>ie(),[]),[,n]=C(0),[i,o]=C(()=>new Date),[l,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,m]=C(0),[b,v]=C(""),[O,R]=C(!1),[E,M]=C(""),[X,nt]=C(!1),[Nt,Ae]=C(0),[Ut,Wt]=C(!1),[Fe,je]=C(!1),[it,st]=C("list"),[_e,K]=C(0),Gt=()=>n(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(),D=_?F.filter(a=>a.site.name.toLowerCase().includes(_)||(a.org.name||a.org.subdomain||"").toLowerCase().includes(_)):F,W=D.findIndex(a=>a.site.id===l);W<0&&(W=0);let T=D[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=D.findIndex(a=>!a.entry),G=Math.max(_r,(e?.rows??30)-jr),z=D.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=D.slice(Y,Tt);et(()=>{p!=="dashboard"||O||F.length>0||(v(""),t.catalog.length<=1?x("newName"):(m(0),x("newOrg")))},[F.length,p,O,t.catalog.length]);let ut=a=>{if(D.length===0)return;let d=U(W+a,D.length);h(D[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"):(m(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(ne(a)?`Opening ${a}`:"Couldn't open the browser.",!1)};Ar((a,d)=>{if(Ut){(a==="?"||d.escape)&&Wt(!1);return}if(p==="newOrg"){d.escape?x("dashboard"):d.upArrow?m(k=>U(k-1,t.catalog.length)):d.downArrow?m(k=>U(k+1,t.catalog.length)):d.return&&x("newName");return}if(X){d.escape?(nt(!1),M(""),h(null)):d.return?nt(!1):d.upArrow?ut(-1):d.downArrow&&ut(1);return}if(d.tab){it==="logs"?st("list"):y&&st("logs"),K(0);return}if(it==="logs"){if(d.escape){st("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){M(""),h(null);return}if(a==="?")return void Wt(!0);if(a==="/")return st("list"),void nt(!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=r[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:[s(c,{color:"green",bold:!0,children:"\u25C6 SleekCMS"}),s(c,{color:"gray",children:" \u2502 "}),s(c,{children:t.email??"signed in"})]}),u(g,{children:[u(c,{color:"gray",children:[_?`${D.length}/${F.length}`:F.length," sites \xB7 "]}),u(c,{color:"green",children:[t.watchingCount()," watching"]}),s(c,{color:"gray",children:` \xB7 ${i.toTimeString().slice(0,5)}`})]})]});return Ut?u(g,{flexDirection:"column",children:[Xt,s(g,{marginTop:1,justifyContent:"center",children:s(Nr,{launchers:r})})]}):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:[s(c,{color:"green",bold:!0,children:"SITE WORKSPACES"}),F.length>G&&!X&&!_?s(c,{color:"gray",children:"/ filter"}):null]}),X?u(g,{children:[s(c,{color:"cyan",children:"/ "}),s(Be,{value:E,onChange:M,onSubmit:()=>nt(!1),placeholder:"type to filter\u2026"})]}):_?s(c,{color:"gray",children:`/ ${E} \xB7 ${D.length} match${D.length===1?"":"es"}`}):null,s(g,{flexDirection:"column",marginTop:1,minHeight:lt?G+3:void 0,children:D.length===0?s(c,{color:"gray",children:_?`no matches for \u201C${E}\u201D`:"no sites \u2014 press n to create one"}):u(rt,{children:[lt?s(c,{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(Lr,{children:[Ve?s(c,{color:"gray",children:"\u2500".repeat(34)}):null,u(g,{justifyContent:"space-between",children:[u(g,{children:[s(c,{color:dt?"green":"gray",children:dt?"\u276F ":" "}),u(c,{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," "]}),s(c,{color:dt?"white":a.entry?void 0:"gray",bold:dt,children:a.site.name})]}),s(c,{color:a.entry?.status==="syncing"?"green":"gray",children:Ye})]})]},a.site.id)}),lt?s(c,{color:"gray",children:Tt<z?` \u2193 ${z-Tt} more`:" "}):null]})}),s(g,{marginTop:1,children:s(c,{color:"gray",children:"+ new site \xB7 n"})})]}),u(g,{flexDirection:"column",flexGrow:1,marginLeft:1,children:[s(g,{flexDirection:"column",borderStyle:"round",borderColor:"gray",paddingX:1,children:T?u(rt,{children:[u(c,{children:[T.org.name||T.org.subdomain?u(c,{color:"gray",children:[T.org.name||T.org.subdomain," / "]}):null,s(c,{color:"cyan",bold:!0,children:T.site.name})]}),u(g,{marginTop:1,children:[s(c,{color:"gray",children:"status "}),y?s(c,{color:wt(y.status).color,children:`: ${wt(y.status).label}`}):s(c,{color:"gray",children:": idle \u2014 not syncing (press s to start)"})]}),u(g,{children:[s(c,{color:"gray",children:"path "}),s(c,{wrap:"truncate-end",children:y?.viewsDir?Ft(y.viewsDir):"\u2014"})]}),u(g,{children:[s(c,{color:"gray",children:"synced "}),s(c,{children:jt(y?.lastSyncedAt)}),s(c,{color:"gray",children:" progress "}),s(c,{color:y?.status==="syncing"?"green":"gray",children:y?.status==="syncing"?`${yt(y.progress)??0}%`:"\u2014"})]}),s(g,{marginTop:1,children:s(Ur,{percent:y?y.status==="syncing"?yt(y.progress)??0:y.status==="watching"?100:0:0})}),y?u(rt,{children:[u(g,{marginTop:1,children:[s(c,{color:"gray",children:"build "}),s(c,{color:vt.color,children:`${vt.dot} ${vt.label}`}),s(c,{color:"gray",children:" last "}),s(c,{children:St?"in progress":jt(A?.at)})]}),u(g,{children:[s(c,{color:"gray",children:"url "}),A?.url?s(c,{color:"cyan",wrap:"truncate-end",children:A.url}):s(c,{color:"gray",children:"\u2014"})]}),A?.status==="error"&&A.errors?.length?u(g,{children:[s(c,{color:"red",children:"\u258C "}),s(c,{color:"red",wrap:"truncate-end",children:`\u2717 ${A.errors[0]}`})]}):null,St?u(g,{children:[s(Wr,{frame:Nt}),s(c,{color:"gray",children:` ${A?.stage??"building"}`})]}):null]}):null]}):s(c,{color:"gray",children:"No site selected."})}),p==="dashboard"?u(g,{flexDirection:"column",borderStyle:"round",borderColor:it==="logs"?"green":"gray",paddingX:1,marginTop:1,height:ot+4,flexShrink:0,overflowY:"hidden",children:[u(g,{justifyContent:"space-between",children:[u(c,{children:[s(c,{color:"cyan",bold:!0,children:"LOGS \xB7 "}),s(c,{color:"white",children:T?.site.name??"\u2014"})]}),y&&I.length>0?it==="logs"?s(c,{color:"green",children:`\u2191\u2193 scroll \xB7 esc back${xt>0?` \xB7 ${at}/${I.length}`:""}`}):I.length>ot?s(c,{color:"gray",children:"tab to scroll"}):null:null]}),s(g,{flexDirection:"column",marginTop:1,children:!y||I.length===0?s(c,{color:"gray",children:"no activity yet"}):qt.map((a,d)=>u(c,{wrap:"truncate-end",children:[u(c,{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(rt,{children:[s(c,{color:"cyan",bold:!0,children:"CREATE SITE \u2014 PICK ORG"}),s(c,{color:"gray",children:"\u2191/\u2193 select \xB7 \u23CE next \xB7 esc cancel"}),s(g,{flexDirection:"column",marginTop:1,children:t.catalog.map((a,d)=>u(c,{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(rt,{children:[s(c,{color:"cyan",bold:!0,children:"CREATE SITE"}),u(g,{marginTop:1,children:[s(c,{children:"New site name: "}),s(Be,{value:b,onChange:v,onSubmit:ze})]}),s(c,{color:"gray",children:"\u23CE create \xB7 empty + \u23CE to cancel"})]})]})]})]}),t.message?s(g,{paddingX:1,children:u(c,{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:[s(j,{k:"\u2191\u2193",label:"select"}),s(j,{k:"/",label:"search"}),s(j,{k:"s",label:"start sync"}),s(j,{k:"d",label:"disconnect"}),F.length===0?s(j,{k:"n",label:"new site"}):null,s(j,{k:"ctrl+c",label:"quit",width:14})]}),s(j,{k:"?",label:"all keys",width:12,bg:Ee})]}),!Fe&&r.length>0?s(g,{paddingX:1,marginTop:1,flexWrap:"wrap",children:r.map((a,d)=>s(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 $e({controller:t,env:e,devSecret:r,savedToken:n,savedEmail:i}){let[o,l]=De(n?"loading":"auth"),[h,p]=De();Jr((w,m)=>{m.ctrl&&w==="c"&&t.exit()}),Gr(()=>{n&&t.init(e,n,i).then(()=>l("manage")).catch(w=>{w instanceof L&&w.status===401?p("Saved session expired \u2014 please sign in again."):p(Oe(w)),l("auth")})},[]);let x=async(w,m)=>{p(void 0),await ue({env:e,userToken:w,devSecret:r,email:m}),l("loading");try{await t.init(e,w,m),l("manage")}catch(b){p(Oe(b)),l("auth")}};return o==="auth"?bt(ve,{env:e,initialError:h,onAuthed:x}):o==="loading"?bt(qr,{children:bt(Hr,{children:"Loading your sites\u2026 "})}):bt(Me,{controller:t})}import{jsx as tn}from"react/jsx-runtime";var Yr=Kr(import.meta.url),_t=te();if(_t.version){let t=Yr("../package.json");console.log(t.version),process.exit(0)}var Re=It.dirname(Xr(import.meta.url)),Vr=Le(It.join(Re,"AGENT.md"),"utf-8"),Qr=Le(It.join(Re,"build.mjs"),"utf-8");async function Zr(){let t=new mt(Vr,Qr),e=await le(),r=(_t.env??e?.env??"production").toLowerCase(),n=_t.dev??process.env.SLEEKCMS_DEV_SECRET??e?.devSecret;ce(n),process.stdout.isTTY&&process.stdout.write("\x1B[2J\x1B[3J\x1B[H");let i=zr(tn($e,{controller:t,env:r,devSecret:n,savedToken:e?.userToken,savedEmail:e?.email}),{exitOnCtrlC:!1}),o=l=>{i.unmount(),console.log(l),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 i.waitUntilExit()}Zr().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)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sleekcms/sync",
3
- "version": "2.9.0",
3
+ "version": "2.10.0",
4
4
  "description": "Edit SleekCMS sites locally — models, content, templates, images — with live two-way sync and AI agent support.",
5
5
  "keywords": [
6
6
  "sleekcms",