lindoai-cli 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.cjs +622 -27
  2. package/dist/index.js +622 -27
  3. package/package.json +2 -2
package/dist/index.cjs CHANGED
@@ -1,23 +1,23 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';var Ee=require('http'),w=require('fs'),j=require('path'),de=require('os'),commander=require('commander'),lindoai=require('lindoai'),child_process=require('child_process'),url=require('url'),De=require('crypto');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var Ee__namespace=/*#__PURE__*/_interopNamespace(Ee);var w__namespace=/*#__PURE__*/_interopNamespace(w);var j__namespace=/*#__PURE__*/_interopNamespace(j);var de__namespace=/*#__PURE__*/_interopNamespace(de);var De__namespace=/*#__PURE__*/_interopNamespace(De);var Me=Object.defineProperty;var Be=(o,t)=>()=>(o&&(t=o(o=0)),t);var He=(o,t)=>{for(var n in t)Me(o,n,{get:t[n],enumerable:true});};var pe={};He(pe,{LIVE_RELOAD_SCRIPT:()=>me,injectLiveReload:()=>Le,startLivePreviewServer:()=>xt});function Le(o){let t=/<\/body>/i,n=o.match(t);return n&&n.index!==void 0?o.slice(0,n.index)+me+o.slice(n.index):o+me}function xt(o){return new Promise((t,n)=>{let e=j__namespace.resolve(o),i=new Set,a=null,l=100;function m(){for(let u of i)try{u.write(`data: reload
2
+ 'use strict';var tt=require('http'),k=require('fs'),M=require('path'),$e=require('os'),commander=require('commander'),lindoai=require('lindoai'),child_process=require('child_process'),url=require('url'),dt=require('crypto');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var tt__namespace=/*#__PURE__*/_interopNamespace(tt);var k__namespace=/*#__PURE__*/_interopNamespace(k);var M__namespace=/*#__PURE__*/_interopNamespace(M);var $e__namespace=/*#__PURE__*/_interopNamespace($e);var dt__namespace=/*#__PURE__*/_interopNamespace(dt);var kt=Object.defineProperty;var Ct=(o,e)=>()=>(o&&(e=o(o=0)),e);var _t=(o,e)=>{for(var n in e)kt(o,n,{get:e[n],enumerable:true});};var Pe={};_t(Pe,{LIVE_RELOAD_SCRIPT:()=>Te,injectLiveReload:()=>ot,startLivePreviewServer:()=>ao});function ot(o){let e=/<\/body>/i,n=o.match(e);return n&&n.index!==void 0?o.slice(0,n.index)+Te+o.slice(n.index):o+Te}function ao(o){return new Promise((e,n)=>{let t=M__namespace.resolve(o),i=new Set,a=null,l=100;function c(){for(let g of i)try{g.write(`data: reload
3
3
 
4
- `);}catch{i.delete(u);}}function p(){a&&clearTimeout(a),a=setTimeout(()=>{m(),a=null;},l);}function b(u,f){let S=u.url||"/";if((u.method||"GET")!=="GET"){f.writeHead(405,{"Content-Type":"text/plain"}),f.end("Method Not Allowed");return}if(S==="/__live-reload"){f.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":"*"}),f.write(`data: connected
4
+ `);}catch{i.delete(g);}}function u(){a&&clearTimeout(a),a=setTimeout(()=>{c(),a=null;},l);}function b(g,w){let p=g.url||"/";if((g.method||"GET")!=="GET"){w.writeHead(405,{"Content-Type":"text/plain"}),w.end("Method Not Allowed");return}if(p==="/__live-reload"){w.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":"*"}),w.write(`data: connected
5
5
 
6
- `),i.add(f),u.on("close",()=>{i.delete(f);});return}if(S==="/"||S==="/index.html"){try{let _=w__namespace.readFileSync(e,"utf-8"),G=Le(_);f.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-cache"}),f.end(G);}catch(_){let G=_ instanceof Error?_.message:"Unknown error";f.writeHead(500,{"Content-Type":"text/html; charset=utf-8"}),f.end(`<!DOCTYPE html>
6
+ `),i.add(w),g.on("close",()=>{i.delete(w);});return}if(p==="/"||p==="/index.html"){try{let y=k__namespace.readFileSync(t,"utf-8"),f=ot(y);w.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-cache"}),w.end(f);}catch(y){let f=y instanceof Error?y.message:"Unknown error";w.writeHead(500,{"Content-Type":"text/html; charset=utf-8"}),w.end(`<!DOCTYPE html>
7
7
  <html>
8
8
  <head><title>Error</title></head>
9
9
  <body>
10
10
  <h1>Error loading file</h1>
11
- <p>${G}</p>
11
+ <p>${f}</p>
12
12
  </body>
13
- </html>`);}return}f.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),f.end(`<!DOCTYPE html>
13
+ </html>`);}return}w.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),w.end(`<!DOCTYPE html>
14
14
  <html>
15
15
  <head><title>Not Found</title></head>
16
16
  <body>
17
17
  <h1>404 Not Found</h1>
18
18
  <p>The requested resource was not found.</p>
19
19
  </body>
20
- </html>`);}let g=Ee__namespace.createServer(b),v=null;g.on("error",u=>{n(new Error(`Failed to start preview server: ${u.message}`));}),g.listen(0,"127.0.0.1",()=>{let u=g.address();if(!u||typeof u=="string"){n(new Error("Failed to get server address"));return}let f=u.port;try{v=w__namespace.watch(e,k=>{k==="change"&&p();}),v.on("error",k=>{console.error(`[Live Preview] File watcher error: ${k.message}`);});}catch(k){let _=k instanceof Error?k.message:"Unknown error";console.error(`[Live Preview] Failed to watch file: ${_}`);}let S=()=>{v&&(v.close(),v=null),a&&(clearTimeout(a),a=null);for(let G of i)try{G.end();}catch{}i.clear();let k=j__namespace.join(de__namespace.tmpdir(),"lindoai-pages-preview.pid"),_=j__namespace.join(de__namespace.tmpdir(),"lindoai-pages-preview.port");try{w__namespace.existsSync(k)&&w__namespace.unlinkSync(k);}catch{}try{w__namespace.existsSync(_)&&w__namespace.unlinkSync(_);}catch{}g.close(()=>{process.exit(0);}),setTimeout(()=>{process.exit(0);},1e3);};process.on("SIGTERM",S),process.on("SIGINT",S),t(f);});})}var me,ue=Be(()=>{me=`<script>
20
+ </html>`);}let v=tt__namespace.createServer(b),x=null;v.on("error",g=>{n(new Error(`Failed to start preview server: ${g.message}`));}),v.listen(0,"127.0.0.1",()=>{let g=v.address();if(!g||typeof g=="string"){n(new Error("Failed to get server address"));return}let w=g.port;try{x=k__namespace.watch(t,h=>{h==="change"&&u();}),x.on("error",h=>{console.error(`[Live Preview] File watcher error: ${h.message}`);});}catch(h){let y=h instanceof Error?h.message:"Unknown error";console.error(`[Live Preview] Failed to watch file: ${y}`);}let p=()=>{x&&(x.close(),x=null),a&&(clearTimeout(a),a=null);for(let f of i)try{f.end();}catch{}i.clear();let h=M__namespace.join($e__namespace.tmpdir(),"lindoai-pages-preview.pid"),y=M__namespace.join($e__namespace.tmpdir(),"lindoai-pages-preview.port");try{k__namespace.existsSync(h)&&k__namespace.unlinkSync(h);}catch{}try{k__namespace.existsSync(y)&&k__namespace.unlinkSync(y);}catch{}v.close(()=>{process.exit(0);}),setTimeout(()=>{process.exit(0);},1e3);};process.on("SIGTERM",p),process.on("SIGINT",p),e(w);});})}var Te,Ae=Ct(()=>{Te=`<script>
21
21
  (function() {
22
22
  var eventSource = new EventSource('/__live-reload');
23
23
  eventSource.onmessage = function(event) {
@@ -29,15 +29,206 @@
29
29
  console.log('[Live Reload] Connection lost, attempting to reconnect...');
30
30
  };
31
31
  })();
32
- </script>`;});var Ge="LINDO_API_KEY",Ye="LINDO_BASE_URL",Je=".lindo",Ve="config.json",ze="https://api.lindo.ai";function ke(){return j__namespace.join(de__namespace.homedir(),Je)}function T(){return j__namespace.join(ke(),Ve)}function ee(){let o=T();try{if(w__namespace.existsSync(o)){let t=w__namespace.readFileSync(o,"utf-8");return JSON.parse(t)}}catch{}return {}}function Ie(o){let t=ke(),n=T();w__namespace.existsSync(t)||w__namespace.mkdirSync(t,{recursive:true}),w__namespace.writeFileSync(n,JSON.stringify(o,null,2),"utf-8");}function h(){let o=ee(),t=process.env[Ge]||o.apiKey,n=process.env[Ye]||o.baseUrl||ze;return {apiKey:t,baseUrl:n}}function Pe(o){let t=ee();t.apiKey=o,Ie(t);}function Fe(o,t){let n=ee();switch(o){case "apiKey":n.apiKey=t;break;case "baseUrl":n.baseUrl=t;break;default:throw new Error(`Unknown configuration key: ${o}`)}Ie(n);}function _e(o){let t=h();switch(o){case "apiKey":return t.apiKey;case "baseUrl":return t.baseUrl;default:return}}function C(){return !!h().apiKey}var $={reset:"\x1B[0m",red:"\x1B[31m",green:"\x1B[32m",blue:"\x1B[34m",cyan:"\x1B[36m",gray:"\x1B[90m",bold:"\x1B[1m"};function Qe(){return !process.env.NO_COLOR&&process.stdout.isTTY!==false}function E(o,t){return Qe()?`${t}${o}${$.reset}`:o}function d(o){console.log(E(`\u2713 ${o}`,$.green));}function r(o){console.error(E(`\u2717 ${o}`,$.red));}function s(o){console.log(E(`\u2139 ${o}`,$.blue));}function Xe(o){return JSON.stringify(o,null,2)}function Ze(o){if(o==null)return "";if(Array.isArray(o)){if(o.length===0)return "No data";let t=new Set;for(let e of o)typeof e=="object"&&e!==null&&Object.keys(e).forEach(i=>t.add(i));if(t.size===0)return o.map(e=>String(e)).join(`
33
- `);let n=Array.from(t);return et(n,o)}if(typeof o=="object"){let n=Object.entries(o);if(n.length===0)return "No data";let e=Math.max(...n.map(([i])=>i.length));return n.map(([i,a])=>{let l=i.padEnd(e),m=te(a);return `${E(l,$.cyan)} ${m}`}).join(`
34
- `)}return String(o)}function et(o,t){let n={};for(let l of o)n[l]=l.length;for(let l of t)if(typeof l=="object"&&l!==null){let m=l;for(let p of o){let b=te(m[p]);n[p]=Math.max(n[p],b.length);}}let e=o.map(l=>E(l.padEnd(n[l]),$.bold)).join(" "),i=o.map(l=>"-".repeat(n[l])).join(" "),a=t.map(l=>{if(typeof l=="object"&&l!==null){let m=l;return o.map(p=>te(m[p]).padEnd(n[p])).join(" ")}return String(l)});return [e,i,...a].join(`
35
- `)}function te(o){return o==null?E("-",$.gray):typeof o=="boolean"?o?E("true",$.green):E("false",$.red):typeof o=="number"?String(o):typeof o=="object"?Array.isArray(o)?`[${o.length} items]`:JSON.stringify(o):String(o)}function c(o,t){console.log(t==="json"?Xe(o):Ze(o));}var Ae=["apiKey","baseUrl"];function ne(){let o=new commander.Command("config").description("Manage CLI configuration");return o.command("set <key> <value>").description("Set a configuration value").action((t,n)=>{Ae.includes(t)||(r(`Invalid configuration key: ${t}`),s(`Valid keys: ${Ae.join(", ")}`),process.exit(1));try{Fe(t,n),d(`Configuration saved: ${t}`),s(`Config file: ${T()}`);}catch(e){r(`Failed to save configuration: ${e instanceof Error?e.message:String(e)}`),process.exit(1);}}),o.command("get <key>").description("Get a configuration value").option("-f, --format <format>","Output format (json, table)","table").action((t,n)=>{let e=_e(t);if(e===void 0){n.format==="json"?c({key:t,value:null},n.format):s(`Configuration key '${t}' is not set`);return}if(n.format==="json")c({key:t,value:e},n.format);else {let i=t==="apiKey"?oe(e):e;console.log(`${t}: ${i}`);}}),o.command("list").description("List all configuration values").option("-f, --format <format>","Output format (json, table)","table").action(t=>{let n=h(),e={apiKey:n.apiKey?oe(n.apiKey):"(not set)",baseUrl:n.baseUrl,configFile:T()};t.format==="json"?c({apiKey:n.apiKey?oe(n.apiKey):null,baseUrl:n.baseUrl,configFile:T()},t.format):c(e,t.format);}),o.command("path").description("Show the config file path").action(()=>{console.log(T());}),o}function oe(o){return o.length<=8?"*".repeat(o.length):`${o.slice(0,4)}${"*".repeat(o.length-8)}${o.slice(-4)}`}function ie(){let o=new commander.Command("agents").description("Run AI agents");return o.command("run <agent-id>").description("Run an AI agent").option("-i, --input <json>","Input data as JSON string","{}").option("-s, --stream","Stream the response",false).option("-f, --format <format>","Output format (json, table)","table").action(async(t,n)=>{C()||(r("API key not configured"),s("Run: lindo config set apiKey <your-api-key>"),s("Or set the LINDO_API_KEY environment variable"),process.exit(1));let e=h(),i=new lindoai.LindoClient({apiKey:e.apiKey,baseUrl:e.baseUrl}),a;try{a=JSON.parse(n.input);}catch{r("Invalid JSON input"),s(`Example: --input '{"prompt": "Hello!"}'`),process.exit(1);}try{s(`Running agent: ${t}`);let l=await i.agents.run({agent_id:t,input:a,stream:n.stream});l.success?(d("Agent run completed"),c(l,n.format)):(r(`Agent run failed: ${l.error||"Unknown error"}`),c(l,n.format),process.exit(1));}catch(l){rt(l);}}),o}function rt(o){o instanceof lindoai.AuthenticationError&&(r("Authentication failed"),s("Your API key may be invalid or expired"),s("Run: lindo config set apiKey <your-api-key>"),process.exit(1)),o instanceof Error?r(o.message):r("An unexpected error occurred"),process.exit(1);}function re(){let o=new commander.Command("workflows").description("Manage workflows");return o.command("list").description("List workflow logs").option("-n, --name <name>","Filter by workflow name").option("-s, --status <status>","Filter by status").option("-w, --website <id>","Filter by website ID").option("-c, --client <id>","Filter by client ID").option("-l, --limit <number>","Maximum number of results","50").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=M();try{let e=await n.workflows.list({workflow_name:t.name,status:t.status,website_id:t.website,client_id:t.client,limit:parseInt(t.limit)});e.success?c(e.data,t.format):(r("Failed to list workflows"),process.exit(1));}catch(e){B(e);}}),o.command("start <workflow-name>").description("Start a workflow").option("-p, --params <json>","Workflow parameters as JSON string","{}").option("-f, --format <format>","Output format (json, table)","table").action(async(t,n)=>{let e=M(),i;try{i=JSON.parse(n.params);}catch{r("Invalid JSON params"),s(`Example: --params '{"page_id": "page-123"}'`),process.exit(1);}try{s(`Starting workflow: ${t}`);let a=await e.workflows.start({workflow_name:t,params:i});a.success?(d(`Workflow started: ${a.instance_id}`),c(a,n.format)):(r("Failed to start workflow"),c(a,n.format),process.exit(1));}catch(a){B(a);}}),o.command("status <instance-id>").description("Get workflow status").option("-f, --format <format>","Output format (json, table)","table").action(async(t,n)=>{let e=M();try{let i=await e.workflows.getStatus(t);c(i,n.format);}catch(i){B(i);}}),o.command("pause <instance-id>").description("Pause a running workflow").option("-f, --format <format>","Output format (json, table)","table").action(async(t,n)=>{let e=M();try{s(`Pausing workflow: ${t}`);let i=await e.workflows.pause(t);i.success?d(i.message):(r(i.message),process.exit(1)),c(i,n.format);}catch(i){B(i);}}),o.command("resume <instance-id>").description("Resume a paused workflow").option("-f, --format <format>","Output format (json, table)","table").action(async(t,n)=>{let e=M();try{s(`Resuming workflow: ${t}`);let i=await e.workflows.resume(t);i.success?d(i.message):(r(i.message),process.exit(1)),c(i,n.format);}catch(i){B(i);}}),o.command("terminate <instance-id>").description("Terminate a workflow").option("-f, --format <format>","Output format (json, table)","table").action(async(t,n)=>{let e=M();try{s(`Terminating workflow: ${t}`);let i=await e.workflows.terminate(t);i.success?d(i.message):(r(i.message),process.exit(1)),c(i,n.format);}catch(i){B(i);}}),o}function M(){C()||(r("API key not configured"),s("Run: lindo config set apiKey <your-api-key>"),s("Or set the LINDO_API_KEY environment variable"),process.exit(1));let o=h();return new lindoai.LindoClient({apiKey:o.apiKey,baseUrl:o.baseUrl})}function B(o){o instanceof lindoai.AuthenticationError&&(r("Authentication failed"),s("Your API key may be invalid or expired"),s("Run: lindo config set apiKey <your-api-key>"),process.exit(1)),o instanceof Error?r(o.message):r("An unexpected error occurred"),process.exit(1);}function se(){let o=new commander.Command("workspace").description("Workspace operations");return o.command("get").description("Get workspace details").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=I();try{let e=await n.workspace.get();c(e,t.format);}catch(e){P(e);}}),o.command("credits").description("Get workspace credit balance").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=I();try{let e=await n.workspace.getCredits();c(e,t.format);}catch(e){P(e);}}),o.command("client-credits").description("Get credit balance for a specific client").requiredOption("-c, --client <id>","Client ID").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=I();try{let e=await n.workspace.getClientCredits(t.client);c(e,t.format);}catch(e){P(e);}}),o.command("update").description("Update workspace settings").option("-n, --name <name>","Workspace name").option("-l, --language <lang>","Workspace language").option("-w, --webhook <url>","Webhook URL").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=I();try{let e=await n.workspace.update({workspace_name:t.name,workspace_language:t.language,webhook_url:t.webhook});e.success&&d("Workspace updated"),c(e,t.format);}catch(e){P(e);}}),o.command("team-add").description("Add a team member to the workspace").requiredOption("-e, --email <email>","Team member email").option("-r, --role <role>","Role (Team)","Team").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=I();try{let e=await n.workspace.addTeamMember(t.email,t.role);e.success&&d("Team member added"),c(e,t.format);}catch(e){P(e);}}),o.command("team-remove").description("Remove a team member from the workspace").requiredOption("-m, --member <id>","Member ID").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=I();try{let e=await n.workspace.removeTeamMember(t.member);e.success&&d("Team member removed"),c(e,t.format);}catch(e){P(e);}}),o.command("integration-add").description("Add an integration to the workspace").requiredOption("-t, --type <type>","Integration type (e.g., matomo)").requiredOption("-c, --config <json>","Integration config as JSON").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=I(),e;try{e=JSON.parse(t.config);}catch{r("Invalid JSON config"),process.exit(1);}try{let i=await n.workspace.addIntegration({integration_type:t.type,config:e});i.success&&d("Integration added"),c(i,t.format);}catch(i){P(i);}}),o.command("integration-remove").description("Remove an integration from the workspace").requiredOption("-t, --type <type>","Integration type").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=I();try{let e=await n.workspace.removeIntegration(t.type);e.success&&d("Integration removed"),c(e,t.format);}catch(e){P(e);}}),o.command("whitelabel").description("Setup or update whitelabel settings").option("-d, --domain <domain>","Custom domain").option("-s, --subdomain <domain>","Subdomain domain").option("-e, --email-sender <email>","Email sender address").option("--enable-register","Enable client registration").option("--disable-register","Disable client registration").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=I();try{let e=await n.workspace.setupWhitelabel({domain:t.domain,subdomain_domain:t.subdomain,email_sender:t.emailSender,wl_client_register:t.enableRegister?!0:t.disableRegister?!1:void 0});e.success&&d("Whitelabel settings updated"),c(e,t.format);}catch(e){P(e);}}),o.command("appearance").description("Update workspace appearance settings").option("-p, --primary <color>","Primary color (hex)").option("-s, --secondary <color>","Secondary color (hex)").option("-m, --mode <mode>","Theme mode (light/dark)").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=I();try{let e=await n.workspace.updateAppearance({primary_color:t.primary,secondary_color:t.secondary,theme_mode:t.mode});e.success&&d("Appearance settings updated"),c(e,t.format);}catch(e){P(e);}}),o}function I(){C()||(r("API key not configured"),s("Run: lindo config set apiKey <your-api-key>"),s("Or set the LINDO_API_KEY environment variable"),process.exit(1));let o=h();return new lindoai.LindoClient({apiKey:o.apiKey,baseUrl:o.baseUrl})}function P(o){o instanceof lindoai.AuthenticationError&&(r("Authentication failed"),s("Your API key may be invalid or expired"),s("Run: lindo config set apiKey <your-api-key>"),process.exit(1)),o instanceof Error?r(o.message):r("An unexpected error occurred"),process.exit(1);}function ae(){let o=new commander.Command("analytics").description("Analytics operations");return o.command("workspace").description("Get workspace analytics").option("--from <date>","Start date (ISO format)").option("--to <date>","End date (ISO format)").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=Te();try{let e=await n.analytics.getWorkspace({from:t.from,to:t.to});c(e,t.format);}catch(e){$e(e);}}),o.command("website").description("Get website analytics").requiredOption("-w, --website <id>","Website ID (required)").option("--from <date>","Start date (ISO format)").option("--to <date>","End date (ISO format)").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=Te();try{let e=await n.analytics.getWebsite({website_id:t.website,from:t.from,to:t.to});c(e,t.format);}catch(e){$e(e);}}),o}function Te(){C()||(r("API key not configured"),s("Run: lindo config set apiKey <your-api-key>"),s("Or set the LINDO_API_KEY environment variable"),process.exit(1));let o=h();return new lindoai.LindoClient({apiKey:o.apiKey,baseUrl:o.baseUrl})}function $e(o){o instanceof lindoai.AuthenticationError&&(r("Authentication failed"),s("Your API key may be invalid or expired"),s("Run: lindo config set apiKey <your-api-key>"),process.exit(1)),o instanceof Error?r(o.message):r("An unexpected error occurred"),process.exit(1);}function ce(){let o=new commander.Command("clients").description("Client management operations");return o.command("list").description("List all workspace clients").option("-p, --page <page>","Page number","1").option("-s, --search <search>","Search term").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=Y();try{let e=await n.clients.list({page:parseInt(t.page,10),search:t.search});if(t.format==="json")c(e,"json");else if(e.clients&&e.clients.length>0){console.log(`
36
- Clients:`),console.log("--------");for(let i of e.clients)console.log(` ID: ${i.record_id}`),console.log(` Email: ${i.email}`),console.log(` Website Limit: ${i.website_limit??"N/A"}`),console.log(` Suspended: ${i.suspended??!1}`),console.log("");console.log(`Total: ${e.total??e.clients.length}`);}else s("No clients found");}catch(e){J(e);}}),o.command("create").description("Create a new workspace client").requiredOption("-e, --email <email>","Client email address").option("-l, --limit <limit>","Website limit","5").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=Y();try{let e=await n.clients.create({email:t.email,website_limit:parseInt(t.limit,10)});if(e.success&&e.client)d(`Client created: ${e.client.record_id}`),c(e.client,t.format);else if(r("Failed to create client"),e.errors)for(let i of e.errors)r(` ${i}`);}catch(e){J(e);}}),o.command("update").description("Update a workspace client").requiredOption("-i, --id <id>","Client ID").option("-l, --limit <limit>","Website limit").option("--suspend","Suspend the client").option("--unsuspend","Unsuspend the client").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=Y();try{let e=await n.clients.update({client_id:t.id,website_limit:t.limit?parseInt(t.limit,10):void 0,suspended:t.suspend?!0:t.unsuspend?!1:void 0});if(e.success)d("Client updated"),e.client&&c(e.client,t.format);else if(r("Failed to update client"),e.errors)for(let i of e.errors)r(` ${i}`);}catch(e){J(e);}}),o.command("delete").description("Delete a workspace client").requiredOption("-i, --id <id>","Client ID").action(async t=>{let n=Y();try{let e=await n.clients.delete(t.id);if(e.success)d("Client deleted");else if(r("Failed to delete client"),e.errors)for(let i of e.errors)r(` ${i}`);}catch(e){J(e);}}),o.command("magic-link").description("Create a magic link for client authentication").requiredOption("-e, --email <email>","Client email address").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=Y();try{let e=await n.clients.createMagicLink(t.email);if(e.success)d("Magic link created"),c(e,t.format);else if(r("Failed to create magic link"),e.errors)for(let i of e.errors)r(` ${i}`);}catch(e){J(e);}}),o}function Y(){C()||(r("API key not configured"),s("Run: lindo config set apiKey <your-api-key>"),s("Or set the LINDO_API_KEY environment variable"),process.exit(1));let o=h();return new lindoai.LindoClient({apiKey:o.apiKey,baseUrl:o.baseUrl})}function J(o){o instanceof lindoai.AuthenticationError&&(r("Authentication failed"),s("Your API key may be invalid or expired"),s("Run: lindo config set apiKey <your-api-key>"),process.exit(1)),o instanceof Error?r(o.message):r("An unexpected error occurred"),process.exit(1);}function le(){let o=new commander.Command("websites").description("Website management operations");return o.command("list").description("List all workspace websites").option("-p, --page <page>","Page number","1").option("-s, --search <search>","Search term").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=O();try{let e=await n.websites.list({page:parseInt(t.page,10),search:t.search});if(t.format==="json")c(e,"json");else {let i=e.result?.list??[];if(i.length>0){console.log(`
37
- Websites:`),console.log("---------");for(let a of i)console.log(` ID: ${a.website_id}`),console.log(` Name: ${a.website_name??"N/A"}`),console.log(` Domain: ${a.domain??"N/A"}`),console.log(` Activated: ${a.activated??!1}`),console.log("");console.log(`Total: ${e.result?.total??i.length}`);}else s("No websites found");}}catch(e){x(e);}}),o.command("get").description("Get website details").requiredOption("-i, --id <id>","Website ID").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=O();try{let e=await n.websites.getDetails(t.id);c(e,t.format);}catch(e){x(e);}}),o.command("update").description("Update a website").requiredOption("-i, --id <id>","Website ID").option("-n, --name <name>","Business name").option("--activate","Activate the website").option("--deactivate","Deactivate the website").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=O();try{let e=await n.websites.update({website_id:t.id,business_name:t.name,activated:t.activate?!0:t.deactivate?!1:void 0});if(e.success)d("Website updated"),e.website&&c(e.website,t.format);else if(r("Failed to update website"),e.errors)for(let i of e.errors)r(` ${i}`);}catch(e){x(e);}}),o.command("settings").description("Update website settings").requiredOption("-i, --id <id>","Website ID").option("-n, --name <name>","Business name").option("-l, --language <lang>","Language").option("-d, --description <desc>","Business description").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=O();try{let e=await n.websites.updateSettings(t.id,{business_name:t.name,language:t.language,business_description:t.description});e.success&&d("Website settings updated"),c(e,t.format);}catch(e){x(e);}}),o.command("delete").description("Delete a website").requiredOption("-i, --id <id>","Website ID").action(async t=>{let n=O();try{let e=await n.websites.delete(t.id);if(e.success)d("Website deleted");else if(r("Failed to delete website"),e.errors)for(let i of e.errors)r(` ${i}`);}catch(e){x(e);}}),o.command("assign").description("Assign a website to a client").requiredOption("-w, --website <id>","Website ID").requiredOption("-c, --client <id>","Client ID").action(async t=>{let n=O();try{let e=await n.websites.assign({website_id:t.website,client_id:t.client});if(e.success)d("Website assigned to client");else if(r("Failed to assign website"),e.errors)for(let i of e.errors)r(` ${i}`);}catch(e){x(e);}}),o.command("domain-add").description("Add a custom domain to a website").requiredOption("-i, --id <id>","Website ID").requiredOption("-d, --domain <domain>","Custom domain").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=O();try{let e=await n.websites.addDomain(t.id,t.domain);if(e.success&&(d("Domain added"),e.result?.dns_records)){console.log(`
38
- DNS Records to configure:`);for(let i of e.result.dns_records)console.log(` ${i.record_type} ${i.host} -> ${i.value}`);}c(e,t.format);}catch(e){x(e);}}),o.command("domain-remove").description("Remove a custom domain from a website").requiredOption("-i, --id <id>","Website ID").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=O();try{let e=await n.websites.removeDomain(t.id);e.success&&d("Domain removed"),c(e,t.format);}catch(e){x(e);}}),o.command("integration-add").description("Add an integration to a website").requiredOption("-i, --id <id>","Website ID").requiredOption("-t, --type <type>","Integration type (e.g., matomo)").requiredOption("-c, --config <json>","Integration config as JSON").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=O(),e;try{e=JSON.parse(t.config);}catch{r("Invalid JSON config"),process.exit(1);}try{let i=await n.websites.addIntegration(t.id,{integration_type:t.type,config:e});i.success&&d("Integration added"),c(i,t.format);}catch(i){x(i);}}),o.command("integration-remove").description("Remove an integration from a website").requiredOption("-i, --id <id>","Website ID").requiredOption("-t, --type <type>","Integration type").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=O();try{let e=await n.websites.removeIntegration(t.id,t.type);e.success&&d("Integration removed"),c(e,t.format);}catch(e){x(e);}}),o.command("team-add").description("Add a team member to a website").requiredOption("-i, --id <id>","Website ID").requiredOption("-e, --email <email>","Team member email").requiredOption("-r, --role <role>","Role (Editor or Commenter)").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=O();try{let e=await n.websites.addTeamMember(t.id,t.email,t.role);e.success&&d("Team member added"),c(e,t.format);}catch(e){x(e);}}),o.command("team-remove").description("Remove a team member from a website").requiredOption("-i, --id <id>","Website ID").requiredOption("-m, --member <memberId>","Member ID").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=O();try{let e=await n.websites.removeTeamMember(t.id,t.member);e.success&&d("Team member removed"),c(e,t.format);}catch(e){x(e);}}),o}function O(){C()||(r("API key not configured"),s("Run: lindo config set apiKey <your-api-key>"),s("Or set the LINDO_API_KEY environment variable"),process.exit(1));let o=h();return new lindoai.LindoClient({apiKey:o.apiKey,baseUrl:o.baseUrl})}function x(o){o instanceof lindoai.AuthenticationError&&(r("Authentication failed"),s("Your API key may be invalid or expired"),s("Run: lindo config set apiKey <your-api-key>"),process.exit(1)),o instanceof Error?r(o.message):r("An unexpected error occurred"),process.exit(1);}function L(o){return new Promise(t=>{let n=de.platform(),e;switch(n){case "darwin":e=`open "${o}"`;break;case "win32":e=`start "" "${o}"`;break;default:e=`xdg-open "${o}"`;break}child_process.exec(e,i=>{t(!i);});})}var N=j__namespace.join(de__namespace.tmpdir(),"lindoai-pages-preview.pid"),z=j__namespace.join(de__namespace.tmpdir(),"lindoai-pages-preview.port");function he(){let o=new commander.Command("pages").description("Page management operations");return o.command("list").description("List all pages for a website").requiredOption("-w, --website <id>","Website ID").option("-p, --page <page>","Page number","1").option("-s, --search <search>","Search term").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=D();try{let e=await n.pages.list(t.website,{page:parseInt(t.page,10),search:t.search});if(t.format==="json")c(e,"json");else {let i=e.result;if(i?.list&&i.list.length>0){console.log(`
39
- Pages:`),console.log("------");for(let a of i.list)console.log(` ID: ${a.page_id}`),console.log(` Name: ${a.name??"N/A"}`),console.log(` Path: ${a.path??"N/A"}`),console.log(` Status: ${a.status??"N/A"}`),console.log(` Published: ${a.publish_date?new Date(a.publish_date*1e3).toISOString():"No"}`),console.log("");console.log(`Total: ${i.total??i.list.length}`);}else s("No pages found");}}catch(e){R(e);}}),o.command("get").description("Get details of a specific page").requiredOption("-w, --website <id>","Website ID").requiredOption("-i, --id <id>","Page ID").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=D();try{let e=await n.pages.get(t.website,t.id);if(t.format==="json")c(e,"json");else {let i=e.result;i?(console.log(`
40
- Page Details:`),console.log("-------------"),console.log(` ID: ${i.page_id}`),console.log(` Name: ${i.name??"N/A"}`),console.log(` Path: ${i.path??"N/A"}`),console.log(` Status: ${i.status??"N/A"}`),console.log(` Published: ${i.publish_date?new Date(i.publish_date*1e3).toISOString():"No"}`),console.log(` Created: ${i.created_date??"N/A"}`)):r("Page not found");}}catch(e){R(e);}}),o.command("publish").description("Publish a page").requiredOption("-w, --website <id>","Website ID").requiredOption("-i, --id <id>","Page ID").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=D();try{let e=await n.pages.publish(t.website,t.id);t.format==="json"?c(e,"json"):e.success?(d("Page published successfully"),console.log(` Page ID: ${e.result?.page_id}`),console.log(` Published at: ${e.result?.publish_date?new Date(e.result.publish_date*1e3).toISOString():"N/A"}`)):r("Failed to publish page");}catch(e){R(e);}}),o.command("unpublish").description("Unpublish a page").requiredOption("-w, --website <id>","Website ID").requiredOption("-i, --id <id>","Page ID").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=D();try{let e=await n.pages.unpublish(t.website,t.id);t.format==="json"?c(e,"json"):e.success?(d("Page unpublished successfully"),console.log(` Page ID: ${e.result?.page_id}`)):r("Failed to unpublish page");}catch(e){R(e);}}),o.command("delete").description("Delete a page").requiredOption("-w, --website <id>","Website ID").requiredOption("-i, --id <id>","Page ID").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=D();try{let e=await n.pages.delete(t.website,t.id);if(t.format==="json")c(e,"json");else if(e.success){if(d("Page deleted successfully"),console.log(` Page ID: ${e.result?.page_id}`),e.result?.warnings&&e.result.warnings.length>0){console.log(" Warnings:");for(let i of e.result.warnings)console.log(` - ${i}`);}}else r("Failed to delete page");}catch(e){R(e);}}),o.command("edit").description("Edit a page with live preview").argument("<website_id>","Website ID").argument("<page_id>","Page ID").option("--file <path>","Output file path","./page.html").option("--background","Run preview server in background").action(async(t,n,e)=>{let i=D();try{s("Fetching page details...");let a=await i.pages.get(t,n);a.result||(r("Page not found"),process.exit(1));let l=a.result.path,m=await i.websites.getDetails(t);m.result||(r("Website not found"),process.exit(1));let p=m.result.custom_domain||m.result.verified_domain||m.result.preview_url;p||(r("Could not determine website URL"),process.exit(1));let b=`https://${p}${l}`;s(`Fetching HTML from ${b}...`);let g=await fetch(b);g.ok||(r(`Failed to fetch page HTML: ${g.status} ${g.statusText}`),s("Make sure the page is published before editing"),process.exit(1));let v=await g.text(),u=j__namespace.resolve(e.file);w__namespace.writeFileSync(u,v,"utf-8"),d(`HTML saved to ${u}`),await Ft(),e.background?await _t(u):await At(u);}catch(a){R(a);}}),o.command("update").description("Update a page").argument("<website_id>","Website ID").argument("<page_id>","Page ID").option("--html-file <path>","Path to local HTML file to upload").option("-f, --format <format>","Output format (json, table)","table").action(async(t,n,e)=>{let i=D(),a=h();try{e.htmlFile||(r("--html-file option is required"),s("Usage: lindoai pages update <website_id> <page_id> --html-file <path>"),process.exit(1));let l=j__namespace.resolve(e.htmlFile);w__namespace.existsSync(l)||(r(`File not found: ${l}`),process.exit(1));let m=w__namespace.readFileSync(l,"utf-8");s(`Read ${m.length} bytes from ${l}`);let p=await i.pages.get(t,n);p.result||(r("Page not found"),process.exit(1));let b=p.result.path;s("Updating page...");let v=`${a.baseUrl||"https://api.lindo.ai"}/v1/workspace/website/${t}/pages/${n}/update`,f=await(await fetch(v,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${a.apiKey}`},body:JSON.stringify({html:m,path:b})})).json();if(e.format==="json")c(f,"json");else if(f.success)d("Page updated successfully"),console.log(` Page ID: ${f.result?.page_id}`),f.result?.publish_date&&console.log(` Published at: ${new Date(f.result.publish_date*1e3).toISOString()}`);else if(r("Failed to update page"),f.errors)for(let S of f.errors)console.log(` ${S}`);}catch(l){R(l);}}),o.command("stop-preview").description("Stop the background preview server").action(async()=>{try{if(!w__namespace.existsSync(N)){s("No preview server is running");return}let t=parseInt(w__namespace.readFileSync(N,"utf-8").trim(),10);if(isNaN(t)){r("Invalid PID file"),fe();return}try{process.kill(t,"SIGTERM"),d(`Preview server (PID ${t}) stopped`);}catch(n){n.code==="ESRCH"?s("Preview server process not found (may have already stopped)"):r(`Failed to stop preview server: ${n.message}`);}fe();}catch(t){t instanceof Error?r(t.message):r("An unexpected error occurred"),process.exit(1);}}),o}function D(){C()||(r("API key not configured"),s("Run: lindo config set apiKey <your-api-key>"),s("Or set the LINDO_API_KEY environment variable"),process.exit(1));let o=h();return new lindoai.LindoClient({apiKey:o.apiKey,baseUrl:o.baseUrl})}function R(o){o instanceof lindoai.AuthenticationError&&(r("Authentication failed"),s("Your API key may be invalid or expired"),s("Run: lindo config set apiKey <your-api-key>"),process.exit(1)),o instanceof Error?r(o.message):r("An unexpected error occurred"),process.exit(1);}function fe(){try{w__namespace.existsSync(N)&&w__namespace.unlinkSync(N);}catch{}try{w__namespace.existsSync(z)&&w__namespace.unlinkSync(z);}catch{}}async function Ft(){if(w__namespace.existsSync(N)){try{let o=parseInt(w__namespace.readFileSync(N,"utf-8").trim(),10);if(!isNaN(o))try{process.kill(o,"SIGTERM"),s(`Terminated existing preview server (PID ${o})`),await new Promise(t=>setTimeout(t,500));}catch{}}catch{}fe();}}async function _t(o){let t=j__namespace.resolve(o),n=`
32
+ </script>`;});var St="LINDO_API_KEY",Ot="LINDO_BASE_URL",It=".lindo",Ft="config.json",$t="https://api.lindo.ai";function Ge(){return M__namespace.join($e__namespace.homedir(),It)}function N(){return M__namespace.join(Ge(),Ft)}function be(){let o=N();try{if(k__namespace.existsSync(o)){let e=k__namespace.readFileSync(o,"utf-8");return JSON.parse(e)}}catch{}return {}}function Ye(o){let e=Ge(),n=N();k__namespace.existsSync(e)||k__namespace.mkdirSync(e,{recursive:true}),k__namespace.writeFileSync(n,JSON.stringify(o,null,2),"utf-8");}function _(){let o=be(),e=process.env[St]||o.apiKey,n=process.env[Ot]||o.baseUrl||$t;return {apiKey:e,baseUrl:n}}function ze(o){let e=be();e.apiKey=o,Ye(e);}function Ve(o,e){let n=be();switch(o){case "apiKey":n.apiKey=e;break;case "baseUrl":n.baseUrl=e;break;default:throw new Error(`Unknown configuration key: ${o}`)}Ye(n);}function Je(o){let e=_();switch(o){case "apiKey":return e.apiKey;case "baseUrl":return e.baseUrl;default:return}}function F(){return !!_().apiKey}var U={reset:"\x1B[0m",red:"\x1B[31m",green:"\x1B[32m",blue:"\x1B[34m",cyan:"\x1B[36m",gray:"\x1B[90m",bold:"\x1B[1m"};function Tt(){return !process.env.NO_COLOR&&process.stdout.isTTY!==false}function K(o,e){return Tt()?`${e}${o}${U.reset}`:o}function m(o){console.log(K(`\u2713 ${o}`,U.green));}function s(o){console.error(K(`\u2717 ${o}`,U.red));}function r(o){console.log(K(`\u2139 ${o}`,U.blue));}function Pt(o){return JSON.stringify(o,null,2)}function At(o){if(o==null)return "";if(Array.isArray(o)){if(o.length===0)return "No data";let e=new Set;for(let t of o)typeof t=="object"&&t!==null&&Object.keys(t).forEach(i=>e.add(i));if(e.size===0)return o.map(t=>String(t)).join(`
33
+ `);let n=Array.from(e);return Et(n,o)}if(typeof o=="object"){let n=Object.entries(o);if(n.length===0)return "No data";let t=Math.max(...n.map(([i])=>i.length));return n.map(([i,a])=>{let l=i.padEnd(t),c=we(a);return `${K(l,U.cyan)} ${c}`}).join(`
34
+ `)}return String(o)}function Et(o,e){let n={};for(let l of o)n[l]=l.length;for(let l of e)if(typeof l=="object"&&l!==null){let c=l;for(let u of o){let b=we(c[u]);n[u]=Math.max(n[u],b.length);}}let t=o.map(l=>K(l.padEnd(n[l]),U.bold)).join(" "),i=o.map(l=>"-".repeat(n[l])).join(" "),a=e.map(l=>{if(typeof l=="object"&&l!==null){let c=l;return o.map(u=>we(c[u]).padEnd(n[u])).join(" ")}return String(l)});return [t,i,...a].join(`
35
+ `)}function we(o){return o==null?K("-",U.gray):typeof o=="boolean"?o?K("true",U.green):K("false",U.red):typeof o=="number"?String(o):typeof o=="object"?Array.isArray(o)?`[${o.length} items]`:JSON.stringify(o):String(o)}function d(o,e){console.log(e==="json"?Pt(o):At(o));}var Xe=["apiKey","baseUrl"];function ve(){let o=new commander.Command("config").description("Manage CLI configuration");return o.command("set <key> <value>").description("Set a configuration value").action((e,n)=>{Xe.includes(e)||(s(`Invalid configuration key: ${e}`),r(`Valid keys: ${Xe.join(", ")}`),process.exit(1));try{Ve(e,n),m(`Configuration saved: ${e}`),r(`Config file: ${N()}`);}catch(t){s(`Failed to save configuration: ${t instanceof Error?t.message:String(t)}`),process.exit(1);}}),o.command("get <key>").description("Get a configuration value").option("-f, --format <format>","Output format (json, table)","table").action((e,n)=>{let t=Je(e);if(t===void 0){n.format==="json"?d({key:e,value:null},n.format):r(`Configuration key '${e}' is not set`);return}if(n.format==="json")d({key:e,value:t},n.format);else {let i=e==="apiKey"?ye(t):t;console.log(`${e}: ${i}`);}}),o.command("list").description("List all configuration values").option("-f, --format <format>","Output format (json, table)","table").action(e=>{let n=_(),t={apiKey:n.apiKey?ye(n.apiKey):"(not set)",baseUrl:n.baseUrl,configFile:N()};e.format==="json"?d({apiKey:n.apiKey?ye(n.apiKey):null,baseUrl:n.baseUrl,configFile:N()},e.format):d(t,e.format);}),o.command("path").description("Show the config file path").action(()=>{console.log(N());}),o}function ye(o){return o.length<=8?"*".repeat(o.length):`${o.slice(0,4)}${"*".repeat(o.length-8)}${o.slice(-4)}`}function xe(){let o=new commander.Command("agents").description("Run AI agents");return o.command("run <agent-id>").description("Run an AI agent").option("-i, --input <json>","Input data as JSON string","{}").option("-s, --stream","Stream the response",false).option("-f, --format <format>","Output format (json, table)","table").action(async(e,n)=>{F()||(s("API key not configured"),r("Run: lindo config set apiKey <your-api-key>"),r("Or set the LINDO_API_KEY environment variable"),process.exit(1));let t=_(),i=new lindoai.LindoClient({apiKey:t.apiKey,baseUrl:t.baseUrl}),a;try{a=JSON.parse(n.input);}catch{s("Invalid JSON input"),r(`Example: --input '{"prompt": "Hello!"}'`),process.exit(1);}try{r(`Running agent: ${e}`);let l=await i.agents.run({agent_id:e,input:a,stream:n.stream});l.success?(m("Agent run completed"),d(l,n.format)):(s(`Agent run failed: ${l.error||"Unknown error"}`),d(l,n.format),process.exit(1));}catch(l){Nt(l);}}),o}function Nt(o){o instanceof lindoai.AuthenticationError&&(s("Authentication failed"),r("Your API key may be invalid or expired"),r("Run: lindo config set apiKey <your-api-key>"),process.exit(1)),o instanceof Error?s(o.message):s("An unexpected error occurred"),process.exit(1);}function ke(){let o=new commander.Command("workflows").description("Manage workflows");return o.command("list").description("List workflow logs").option("-n, --name <name>","Filter by workflow name").option("-s, --status <status>","Filter by status").option("-w, --website <id>","Filter by website ID").option("-c, --client <id>","Filter by client ID").option("-l, --limit <number>","Maximum number of results","50").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=oe();try{let t=await n.workflows.list({workflow_name:e.name,status:e.status,website_id:e.website,client_id:e.client,limit:parseInt(e.limit)});t.success?d(t.data,e.format):(s("Failed to list workflows"),process.exit(1));}catch(t){ne(t);}}),o.command("start <workflow-name>").description("Start a workflow").option("-p, --params <json>","Workflow parameters as JSON string","{}").option("-f, --format <format>","Output format (json, table)","table").action(async(e,n)=>{let t=oe(),i;try{i=JSON.parse(n.params);}catch{s("Invalid JSON params"),r(`Example: --params '{"page_id": "page-123"}'`),process.exit(1);}try{r(`Starting workflow: ${e}`);let a=await t.workflows.start({workflow_name:e,params:i});a.success?(m(`Workflow started: ${a.instance_id}`),d(a,n.format)):(s("Failed to start workflow"),d(a,n.format),process.exit(1));}catch(a){ne(a);}}),o.command("status <instance-id>").description("Get workflow status").option("-f, --format <format>","Output format (json, table)","table").action(async(e,n)=>{let t=oe();try{let i=await t.workflows.getStatus(e);d(i,n.format);}catch(i){ne(i);}}),o.command("pause <instance-id>").description("Pause a running workflow").option("-f, --format <format>","Output format (json, table)","table").action(async(e,n)=>{let t=oe();try{r(`Pausing workflow: ${e}`);let i=await t.workflows.pause(e);i.success?m(i.message):(s(i.message),process.exit(1)),d(i,n.format);}catch(i){ne(i);}}),o.command("resume <instance-id>").description("Resume a paused workflow").option("-f, --format <format>","Output format (json, table)","table").action(async(e,n)=>{let t=oe();try{r(`Resuming workflow: ${e}`);let i=await t.workflows.resume(e);i.success?m(i.message):(s(i.message),process.exit(1)),d(i,n.format);}catch(i){ne(i);}}),o.command("terminate <instance-id>").description("Terminate a workflow").option("-f, --format <format>","Output format (json, table)","table").action(async(e,n)=>{let t=oe();try{r(`Terminating workflow: ${e}`);let i=await t.workflows.terminate(e);i.success?m(i.message):(s(i.message),process.exit(1)),d(i,n.format);}catch(i){ne(i);}}),o}function oe(){F()||(s("API key not configured"),r("Run: lindo config set apiKey <your-api-key>"),r("Or set the LINDO_API_KEY environment variable"),process.exit(1));let o=_();return new lindoai.LindoClient({apiKey:o.apiKey,baseUrl:o.baseUrl})}function ne(o){o instanceof lindoai.AuthenticationError&&(s("Authentication failed"),r("Your API key may be invalid or expired"),r("Run: lindo config set apiKey <your-api-key>"),process.exit(1)),o instanceof Error?s(o.message):s("An unexpected error occurred"),process.exit(1);}function Ce(){let o=new commander.Command("workspace").description("Workspace operations");return o.command("get").description("Get workspace details").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=L();try{let t=await n.workspace.get();d(t,e.format);}catch(t){R(t);}}),o.command("credits").description("Get workspace credit balance").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=L();try{let t=await n.workspace.getCredits();d(t,e.format);}catch(t){R(t);}}),o.command("client-credits").description("Get credit balance for a specific client").requiredOption("-c, --client <id>","Client ID").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=L();try{let t=await n.workspace.getClientCredits(e.client);d(t,e.format);}catch(t){R(t);}}),o.command("update").description("Update workspace settings").option("-n, --name <name>","Workspace name").option("-l, --language <lang>","Workspace language").option("-w, --webhook <url>","Webhook URL").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=L();try{let t=await n.workspace.update({workspace_name:e.name,workspace_language:e.language,webhook_url:e.webhook});t.success&&m("Workspace updated"),d(t,e.format);}catch(t){R(t);}}),o.command("team-add").description("Add a team member to the workspace").requiredOption("-e, --email <email>","Team member email").option("-r, --role <role>","Role (Team)","Team").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=L();try{let t=await n.workspace.addTeamMember(e.email,e.role);t.success&&m("Team member added"),d(t,e.format);}catch(t){R(t);}}),o.command("team-remove").description("Remove a team member from the workspace").requiredOption("-m, --member <id>","Member ID").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=L();try{let t=await n.workspace.removeTeamMember(e.member);t.success&&m("Team member removed"),d(t,e.format);}catch(t){R(t);}}),o.command("integration-add").description("Add an integration to the workspace").requiredOption("-t, --type <type>","Integration type (e.g., matomo)").requiredOption("-c, --config <json>","Integration config as JSON").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=L(),t;try{t=JSON.parse(e.config);}catch{s("Invalid JSON config"),process.exit(1);}try{let i=await n.workspace.addIntegration({integration_type:e.type,config:t});i.success&&m("Integration added"),d(i,e.format);}catch(i){R(i);}}),o.command("integration-remove").description("Remove an integration from the workspace").requiredOption("-t, --type <type>","Integration type").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=L();try{let t=await n.workspace.removeIntegration(e.type);t.success&&m("Integration removed"),d(t,e.format);}catch(t){R(t);}}),o.command("whitelabel").description("Setup or update whitelabel settings").option("-d, --domain <domain>","Custom domain").option("-s, --subdomain <domain>","Subdomain domain").option("-e, --email-sender <email>","Email sender address").option("--enable-register","Enable client registration").option("--disable-register","Disable client registration").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=L();try{let t=await n.workspace.setupWhitelabel({domain:e.domain,subdomain_domain:e.subdomain,email_sender:e.emailSender,wl_client_register:e.enableRegister?!0:e.disableRegister?!1:void 0});t.success&&m("Whitelabel settings updated"),d(t,e.format);}catch(t){R(t);}}),o.command("appearance").description("Update workspace appearance settings").option("-p, --primary <color>","Primary color (hex)").option("-s, --secondary <color>","Secondary color (hex)").option("-m, --mode <mode>","Theme mode (light/dark)").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=L();try{let t=await n.workspace.updateAppearance({primary_color:e.primary,secondary_color:e.secondary,theme_mode:e.mode});t.success&&m("Appearance settings updated"),d(t,e.format);}catch(t){R(t);}}),o}function L(){F()||(s("API key not configured"),r("Run: lindo config set apiKey <your-api-key>"),r("Or set the LINDO_API_KEY environment variable"),process.exit(1));let o=_();return new lindoai.LindoClient({apiKey:o.apiKey,baseUrl:o.baseUrl})}function R(o){o instanceof lindoai.AuthenticationError&&(s("Authentication failed"),r("Your API key may be invalid or expired"),r("Run: lindo config set apiKey <your-api-key>"),process.exit(1)),o instanceof Error?s(o.message):s("An unexpected error occurred"),process.exit(1);}function _e(){let o=new commander.Command("analytics").description("Analytics operations");return o.command("workspace").description("Get workspace analytics").option("--from <date>","Start date (ISO format)").option("--to <date>","End date (ISO format)").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=Qe();try{let t=await n.analytics.getWorkspace({from:e.from,to:e.to});d(t,e.format);}catch(t){Ze(t);}}),o.command("website").description("Get website analytics").requiredOption("-w, --website <id>","Website ID (required)").option("--from <date>","Start date (ISO format)").option("--to <date>","End date (ISO format)").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=Qe();try{let t=await n.analytics.getWebsite({website_id:e.website,from:e.from,to:e.to});d(t,e.format);}catch(t){Ze(t);}}),o}function Qe(){F()||(s("API key not configured"),r("Run: lindo config set apiKey <your-api-key>"),r("Or set the LINDO_API_KEY environment variable"),process.exit(1));let o=_();return new lindoai.LindoClient({apiKey:o.apiKey,baseUrl:o.baseUrl})}function Ze(o){o instanceof lindoai.AuthenticationError&&(s("Authentication failed"),r("Your API key may be invalid or expired"),r("Run: lindo config set apiKey <your-api-key>"),process.exit(1)),o instanceof Error?s(o.message):s("An unexpected error occurred"),process.exit(1);}function Se(){let o=new commander.Command("clients").description("Client management operations");return o.command("list").description("List all workspace clients").option("-p, --page <page>","Page number","1").option("-s, --search <search>","Search term").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=ae();try{let t=await n.clients.list({page:parseInt(e.page,10),search:e.search});if(e.format==="json")d(t,"json");else if(t.clients&&t.clients.length>0){console.log(`
36
+ Clients:`),console.log("--------");for(let i of t.clients)console.log(` ID: ${i.record_id}`),console.log(` Email: ${i.email}`),console.log(` Website Limit: ${i.website_limit??"N/A"}`),console.log(` Suspended: ${i.suspended??!1}`),console.log("");console.log(`Total: ${t.total??t.clients.length}`);}else r("No clients found");}catch(t){se(t);}}),o.command("create").description("Create a new workspace client").requiredOption("-e, --email <email>","Client email address").option("-l, --limit <limit>","Website limit","5").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=ae();try{let t=await n.clients.create({email:e.email,website_limit:parseInt(e.limit,10)});if(t.success&&t.client)m(`Client created: ${t.client.record_id}`),d(t.client,e.format);else if(s("Failed to create client"),t.errors)for(let i of t.errors)s(` ${i}`);}catch(t){se(t);}}),o.command("update").description("Update a workspace client").requiredOption("-i, --id <id>","Client ID").option("-l, --limit <limit>","Website limit").option("--suspend","Suspend the client").option("--unsuspend","Unsuspend the client").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=ae();try{let t=await n.clients.update({client_id:e.id,website_limit:e.limit?parseInt(e.limit,10):void 0,suspended:e.suspend?!0:e.unsuspend?!1:void 0});if(t.success)m("Client updated"),t.client&&d(t.client,e.format);else if(s("Failed to update client"),t.errors)for(let i of t.errors)s(` ${i}`);}catch(t){se(t);}}),o.command("delete").description("Delete a workspace client").requiredOption("-i, --id <id>","Client ID").action(async e=>{let n=ae();try{let t=await n.clients.delete(e.id);if(t.success)m("Client deleted");else if(s("Failed to delete client"),t.errors)for(let i of t.errors)s(` ${i}`);}catch(t){se(t);}}),o.command("magic-link").description("Create a magic link for client authentication").requiredOption("-e, --email <email>","Client email address").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=ae();try{let t=await n.clients.createMagicLink(e.email);if(t.success)m("Magic link created"),d(t,e.format);else if(s("Failed to create magic link"),t.errors)for(let i of t.errors)s(` ${i}`);}catch(t){se(t);}}),o}function ae(){F()||(s("API key not configured"),r("Run: lindo config set apiKey <your-api-key>"),r("Or set the LINDO_API_KEY environment variable"),process.exit(1));let o=_();return new lindoai.LindoClient({apiKey:o.apiKey,baseUrl:o.baseUrl})}function se(o){o instanceof lindoai.AuthenticationError&&(s("Authentication failed"),r("Your API key may be invalid or expired"),r("Run: lindo config set apiKey <your-api-key>"),process.exit(1)),o instanceof Error?s(o.message):s("An unexpected error occurred"),process.exit(1);}function Oe(){let o=new commander.Command("websites").description("Website management operations");return o.command("list").description("List all workspace websites").option("-p, --page <page>","Page number","1").option("-s, --search <search>","Search term").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=P();try{let t=await n.websites.list({page:parseInt(e.page,10),search:e.search});if(e.format==="json")d(t,"json");else {let i=t.result?.list??[];if(i.length>0){console.log(`
37
+ Websites:`),console.log("---------");for(let a of i)console.log(` ID: ${a.website_id}`),console.log(` Name: ${a.website_name??"N/A"}`),console.log(` Domain: ${a.domain??"N/A"}`),console.log(` Activated: ${a.activated??!1}`),console.log("");console.log(`Total: ${t.result?.total??i.length}`);}else r("No websites found");}}catch(t){A(t);}}),o.command("get").description("Get website details").requiredOption("-i, --id <id>","Website ID").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=P();try{let t=await n.websites.getDetails(e.id);d(t,e.format);}catch(t){A(t);}}),o.command("update").description("Update a website").requiredOption("-i, --id <id>","Website ID").option("-n, --name <name>","Business name").option("--activate","Activate the website").option("--deactivate","Deactivate the website").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=P();try{let t=await n.websites.update({website_id:e.id,business_name:e.name,activated:e.activate?!0:e.deactivate?!1:void 0});if(t.success)m("Website updated"),t.website&&d(t.website,e.format);else if(s("Failed to update website"),t.errors)for(let i of t.errors)s(` ${i}`);}catch(t){A(t);}}),o.command("settings").description("Update website settings").requiredOption("-i, --id <id>","Website ID").option("-n, --name <name>","Business name").option("-l, --language <lang>","Language").option("-d, --description <desc>","Business description").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=P();try{let t=await n.websites.updateSettings(e.id,{business_name:e.name,language:e.language,business_description:e.description});t.success&&m("Website settings updated"),d(t,e.format);}catch(t){A(t);}}),o.command("delete").description("Delete a website").requiredOption("-i, --id <id>","Website ID").action(async e=>{let n=P();try{let t=await n.websites.delete(e.id);if(t.success)m("Website deleted");else if(s("Failed to delete website"),t.errors)for(let i of t.errors)s(` ${i}`);}catch(t){A(t);}}),o.command("assign").description("Assign a website to a client").requiredOption("-w, --website <id>","Website ID").requiredOption("-c, --client <id>","Client ID").action(async e=>{let n=P();try{let t=await n.websites.assign({website_id:e.website,client_id:e.client});if(t.success)m("Website assigned to client");else if(s("Failed to assign website"),t.errors)for(let i of t.errors)s(` ${i}`);}catch(t){A(t);}}),o.command("domain-add").description("Add a custom domain to a website").requiredOption("-i, --id <id>","Website ID").requiredOption("-d, --domain <domain>","Custom domain").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=P();try{let t=await n.websites.addDomain(e.id,e.domain);if(t.success&&(m("Domain added"),t.result?.dns_records)){console.log(`
38
+ DNS Records to configure:`);for(let i of t.result.dns_records)console.log(` ${i.record_type} ${i.host} -> ${i.value}`);}d(t,e.format);}catch(t){A(t);}}),o.command("domain-remove").description("Remove a custom domain from a website").requiredOption("-i, --id <id>","Website ID").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=P();try{let t=await n.websites.removeDomain(e.id);t.success&&m("Domain removed"),d(t,e.format);}catch(t){A(t);}}),o.command("integration-add").description("Add an integration to a website").requiredOption("-i, --id <id>","Website ID").requiredOption("-t, --type <type>","Integration type (e.g., matomo)").requiredOption("-c, --config <json>","Integration config as JSON").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=P(),t;try{t=JSON.parse(e.config);}catch{s("Invalid JSON config"),process.exit(1);}try{let i=await n.websites.addIntegration(e.id,{integration_type:e.type,config:t});i.success&&m("Integration added"),d(i,e.format);}catch(i){A(i);}}),o.command("integration-remove").description("Remove an integration from a website").requiredOption("-i, --id <id>","Website ID").requiredOption("-t, --type <type>","Integration type").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=P();try{let t=await n.websites.removeIntegration(e.id,e.type);t.success&&m("Integration removed"),d(t,e.format);}catch(t){A(t);}}),o.command("team-add").description("Add a team member to a website").requiredOption("-i, --id <id>","Website ID").requiredOption("-e, --email <email>","Team member email").requiredOption("-r, --role <role>","Role (Editor or Commenter)").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=P();try{let t=await n.websites.addTeamMember(e.id,e.email,e.role);t.success&&m("Team member added"),d(t,e.format);}catch(t){A(t);}}),o.command("team-remove").description("Remove a team member from a website").requiredOption("-i, --id <id>","Website ID").requiredOption("-m, --member <memberId>","Member ID").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=P();try{let t=await n.websites.removeTeamMember(e.id,e.member);t.success&&m("Team member removed"),d(t,e.format);}catch(t){A(t);}}),o}function P(){F()||(s("API key not configured"),r("Run: lindo config set apiKey <your-api-key>"),r("Or set the LINDO_API_KEY environment variable"),process.exit(1));let o=_();return new lindoai.LindoClient({apiKey:o.apiKey,baseUrl:o.baseUrl})}function A(o){o instanceof lindoai.AuthenticationError&&(s("Authentication failed"),r("Your API key may be invalid or expired"),r("Run: lindo config set apiKey <your-api-key>"),process.exit(1)),o instanceof Error?s(o.message):s("An unexpected error occurred"),process.exit(1);}function B(o){return new Promise(e=>{let n=$e.platform(),t;switch(n){case "darwin":t=`open "${o}"`;break;case "win32":t=`start "" "${o}"`;break;default:t=`xdg-open "${o}"`;break}child_process.exec(t,i=>{e(!i);});})}function oo(o){let e=o.filter(t=>!!(t&&t.trim()));return e.length===0?"":`https://fonts.googleapis.com/css2?family=${e.map(t=>`${t.trim().replace(/ /g,"+")}:wght@300;400;700`).join("&family=")}&display=swap`}function le(o){let e=[o.font,o.title_font].filter(Boolean);if(e.length===0)return "";let n=oo(e);if(!n)return "";let t=o.font||o.title_font,i=o.title_font||o.font,a=`
39
+ <style>
40
+ /* Apply website fonts from theme */
41
+ body, main, .prose {
42
+ font-family: '${t}', system-ui, sans-serif !important;
43
+ }
44
+ h1, h2, h3, h4, h5, h6, .font-display, .font-serif {
45
+ font-family: '${i}', system-ui, serif !important;
46
+ }
47
+ </style>`;return `<link rel="preconnect" href="https://fonts.googleapis.com">
48
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
49
+ <link href="${n}" rel="stylesheet">${a}`}var no="_global_header0000",io="_global_footer0000";function et(o,e){let n=new RegExp(`<(\\w+)\\s+[^>]*lindo-section\\s*=\\s*["']${ro(e)}["'][^>]*>`,"i"),t=o.match(n);if(!t||t.index===void 0)return {section:void 0,remainingHtml:o};let i=t[1].toLowerCase(),a=t.index,l=a+t[0].length,c=1,u=new RegExp(`<${i}\\b`,"gi"),b=new RegExp(`</${i}>`,"gi"),v=`</${i}>`,x=o.slice(l),g=[],w=[],p;for(;(p=u.exec(x))!==null;)g.push(p.index+l);for(;(p=b.exec(x))!==null;)w.push(p.index+l);let h=[...g.map(O=>({pos:O,type:"open"})),...w.map(O=>({pos:O,type:"close"}))].sort((O,$)=>O.pos-$.pos),y=-1;for(let O of h)if(O.type==="open")c++;else if(c--,c===0){y=O.pos+v.length;break}if(y===-1)return {section:void 0,remainingHtml:o};let f=o.slice(a,y),C=o.slice(0,a),T=o.slice(y),I=(C+T).replace(/\n\s*\n\s*\n/g,`
50
+
51
+ `);return {section:f,remainingHtml:I}}function ro(o){return o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Ie(o){let e=et(o,no),n=et(e.remainingHtml,io);return {globalHeader:e.section,globalFooter:n.section,mainContent:n.remainingHtml.trim()}}function Fe(o,e,n){let t=[];return e&&e.trim()&&t.push(e.trim()),o.trim()&&t.push(o.trim()),n&&n.trim()&&t.push(n.trim()),t.join(`
52
+ `)}var Q=M__namespace.join($e__namespace.tmpdir(),"lindoai-pages-preview.pid"),de=M__namespace.join($e__namespace.tmpdir(),"lindoai-pages-preview.port");function Re(){let o=new commander.Command("pages").description("Page management operations");return o.command("list").description("List all pages for a website").requiredOption("-w, --website <id>","Website ID").option("-p, --page <page>","Page number","1").option("-s, --search <search>","Search term").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=J();try{let t=await n.pages.list(e.website,{page:parseInt(e.page,10),search:e.search});if(e.format==="json")d(t,"json");else {let i=t.result;if(i?.list&&i.list.length>0){console.log(`
53
+ Pages:`),console.log("------");for(let a of i.list)console.log(` ID: ${a.page_id}`),console.log(` Name: ${a.name??"N/A"}`),console.log(` Path: ${a.path??"N/A"}`),console.log(` Status: ${a.status??"N/A"}`),console.log(` Published: ${a.publish_date?"Yes":"No"}`),console.log("");console.log(`Total: ${i.total??i.list.length}`);}else r("No pages found");}}catch(t){X(t);}}),o.command("get").description("Get details of a specific page").requiredOption("-w, --website <id>","Website ID").requiredOption("-i, --id <id>","Page ID").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=J();try{let t=await n.pages.get(e.website,e.id);if(e.format==="json")d(t,"json");else {let i=t.result;i?(console.log(`
54
+ Page Details:`),console.log("-------------"),console.log(` ID: ${i.page_id}`),console.log(` Name: ${i.name??"N/A"}`),console.log(` Path: ${i.path??"N/A"}`),console.log(` Status: ${i.status??"N/A"}`),console.log(` Published: ${i.publish_date?"Yes":"No"}`),console.log(` Created: ${i.created_date??"N/A"}`)):s("Page not found");}}catch(t){X(t);}}),o.command("unpublish").description("Unpublish a page").requiredOption("-w, --website <id>","Website ID").requiredOption("-i, --id <id>","Page ID").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=J();try{let t=await n.pages.unpublish(e.website,e.id);e.format==="json"?d(t,"json"):t.success?(m("Page unpublished successfully"),console.log(` Page ID: ${t.result?.page_id}`)):s("Failed to unpublish page");}catch(t){X(t);}}),o.command("delete").description("Delete a page").requiredOption("-w, --website <id>","Website ID").requiredOption("-i, --id <id>","Page ID").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=J();try{let t=await n.pages.deletePage(e.website,e.id);if(e.format==="json")d(t,"json");else if(t.success){if(m("Page deleted successfully"),console.log(` Page ID: ${t.result?.page_id}`),t.result?.warnings&&t.result.warnings.length>0){console.log(" Warnings:");for(let i of t.result.warnings)console.log(` - ${i}`);}}else s("Failed to delete page");}catch(t){X(t);}}),o.command("create").description("Create a new page with live preview").argument("<website_id>","Website ID").argument("<path>","URL path for the page (e.g., /about-us)").option("--title <title>","Page title","New Page").option("--file <path>","Output file path","./page.html").option("--background","Run preview server in background").action(async(e,n,t)=>{let i=J();try{r("Fetching website details...");let l=(await i.websites.getDetails(e)).result,c=l?.theme||{},u=l?.global_header||null,b=l?.global_footer||null,v=l?.custom_codes||{header:null,footer:null},x={font:c.font,title_font:c.title_font},g=t.title,w=`<!-- Hero Section -->
55
+ <section class="relative min-h-[80vh] flex items-center justify-center bg-gradient-to-br from-neutral-50 to-neutral-100 dark:from-neutral-900 dark:to-neutral-800">
56
+ <div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
57
+ <h1 class="text-4xl sm:text-5xl lg:text-6xl font-bold text-neutral-900 dark:text-white mb-6">
58
+ ${g}
59
+ </h1>
60
+ <p class="text-lg sm:text-xl text-neutral-600 dark:text-neutral-300 mb-8 max-w-2xl mx-auto">
61
+ Start building your page by editing this template. Add sections, customize styles, and create something amazing.
62
+ </p>
63
+ <div class="flex flex-col sm:flex-row gap-4 justify-center">
64
+ <a href="#features" class="inline-flex items-center justify-center px-6 py-3 bg-emerald-600 hover:bg-emerald-700 text-white font-medium rounded-lg transition">
65
+ Get Started
66
+ </a>
67
+ <a href="#contact" class="inline-flex items-center justify-center px-6 py-3 border border-neutral-300 dark:border-neutral-600 text-neutral-700 dark:text-neutral-200 font-medium rounded-lg hover:bg-neutral-100 dark:hover:bg-neutral-700 transition">
68
+ Learn More
69
+ </a>
70
+ </div>
71
+ </div>
72
+ </section>
73
+
74
+ <!-- Features Section -->
75
+ <section id="features" class="py-20 bg-white dark:bg-neutral-900">
76
+ <div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
77
+ <div class="text-center mb-16">
78
+ <h2 class="text-3xl sm:text-4xl font-bold text-neutral-900 dark:text-white mb-4">
79
+ Features
80
+ </h2>
81
+ <p class="text-lg text-neutral-600 dark:text-neutral-300 max-w-2xl mx-auto">
82
+ Discover what makes us different.
83
+ </p>
84
+ </div>
85
+ <div class="grid md:grid-cols-3 gap-8">
86
+ <div class="p-6 bg-neutral-50 dark:bg-neutral-800 rounded-xl">
87
+ <div class="w-12 h-12 bg-emerald-100 dark:bg-emerald-900 rounded-lg flex items-center justify-center mb-4">
88
+ <svg class="w-6 h-6 text-emerald-600 dark:text-emerald-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
89
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/>
90
+ </svg>
91
+ </div>
92
+ <h3 class="text-xl font-semibold text-neutral-900 dark:text-white mb-2">Feature One</h3>
93
+ <p class="text-neutral-600 dark:text-neutral-300">Description of your first amazing feature goes here.</p>
94
+ </div>
95
+ <div class="p-6 bg-neutral-50 dark:bg-neutral-800 rounded-xl">
96
+ <div class="w-12 h-12 bg-emerald-100 dark:bg-emerald-900 rounded-lg flex items-center justify-center mb-4">
97
+ <svg class="w-6 h-6 text-emerald-600 dark:text-emerald-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
98
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4"/>
99
+ </svg>
100
+ </div>
101
+ <h3 class="text-xl font-semibold text-neutral-900 dark:text-white mb-2">Feature Two</h3>
102
+ <p class="text-neutral-600 dark:text-neutral-300">Description of your second amazing feature goes here.</p>
103
+ </div>
104
+ <div class="p-6 bg-neutral-50 dark:bg-neutral-800 rounded-xl">
105
+ <div class="w-12 h-12 bg-emerald-100 dark:bg-emerald-900 rounded-lg flex items-center justify-center mb-4">
106
+ <svg class="w-6 h-6 text-emerald-600 dark:text-emerald-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
107
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/>
108
+ </svg>
109
+ </div>
110
+ <h3 class="text-xl font-semibold text-neutral-900 dark:text-white mb-2">Feature Three</h3>
111
+ <p class="text-neutral-600 dark:text-neutral-300">Description of your third amazing feature goes here.</p>
112
+ </div>
113
+ </div>
114
+ </div>
115
+ </section>
116
+
117
+ <!-- Contact Section -->
118
+ <section id="contact" class="py-20 bg-neutral-50 dark:bg-neutral-800">
119
+ <div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
120
+ <h2 class="text-3xl sm:text-4xl font-bold text-neutral-900 dark:text-white mb-4">
121
+ Get in Touch
122
+ </h2>
123
+ <p class="text-lg text-neutral-600 dark:text-neutral-300 mb-8">
124
+ Have questions? We'd love to hear from you.
125
+ </p>
126
+ <a href="mailto:hello@example.com" class="inline-flex items-center justify-center px-8 py-4 bg-emerald-600 hover:bg-emerald-700 text-white font-medium rounded-lg transition text-lg">
127
+ Contact Us
128
+ </a>
129
+ </div>
130
+ </section>`,p={theme:{mode:"Dark",direction:"ltr",main_classes:"bg-white dark:bg-neutral-900 text-neutral-900 dark:text-neutral-100",animations_deactivated:!1},should_convert:!0},h={page_title:g,meta_description:"",social_title:g,social_description:"",noindex:!1,nofollow:!1};r("Creating page...");let y=await i.pages.create(e,{html:w,path:n,settings:p,template_name:g,seo:h});y.success||(s("Failed to create page"),process.exit(1));let f=y.result.page_id;m(`Page created: ${f}`);let C=le(x),T=Fe(w,u??void 0,b??void 0),I={header:v.header||"",footer:v.footer||""},O=`<!DOCTYPE html>
131
+ <html class="dark" lang="en">
132
+ <head>
133
+ <meta charset="UTF-8">
134
+ <meta name="robots" content="max-snippet:-1, max-image-preview:large, max-video-preview:-1">
135
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
136
+
137
+ <title>${g}</title>
138
+ <meta name="description" content="">
139
+
140
+ <meta property="og:title" content="${g}">
141
+ <meta property="og:description" content="">
142
+ <meta property="og:type" content="website">
143
+
144
+ <meta name="twitter:card" content="summary_large_image">
145
+ <meta name="twitter:title" content="${g}">
146
+ <meta name="twitter:description" content="">
147
+
148
+ <!-- Google Fonts -->
149
+ ${C}
150
+
151
+ <!-- Tailwind CSS v4 CDN for preview -->
152
+ <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
153
+
154
+ <!-- Motion for animations -->
155
+ <script src="https://cdn.jsdelivr.net/npm/motion@latest/dist/motion.js"></script>
156
+ <script src="https://lnui.pages.dev/motion-animate.js"></script>
157
+
158
+ <!-- Page Custom Code (Header) -->
159
+ ${I.header}
160
+
161
+ </head>
162
+ <body>
163
+ <!-- ========== MAIN CONTENT ========== -->
164
+ <main dir="ltr" lindo-main-content id="content" role="main" class="bg-white dark:bg-neutral-900 text-neutral-900 dark:text-neutral-100">
165
+
166
+ ${T}
167
+
168
+ </main>
169
+ <!-- ========== END MAIN CONTENT ========== -->
170
+
171
+ <!-- Config script -->
172
+ <script src="https://cdn.ln-cdn.com/staging/js/config2.js"></script>
173
+
174
+ <!-- Page Custom Code (Footer) -->
175
+ ${I.footer}
176
+ </body>
177
+ </html>`,$=M__namespace.resolve(t.file);k__namespace.writeFileSync($,O,"utf-8"),m(`HTML saved to ${$}`),await nt(),t.background?await it($):await rt($),console.log(""),r(`To save changes: lindoai pages update ${e} ${f} --html-file ${t.file}`);}catch(a){X(a);}}),o.command("edit").description("Edit a page with live preview").argument("<website_id>","Website ID").argument("<page_id>","Page ID").option("--file <path>","Output file path","./page.html").option("--background","Run preview server in background").action(async(e,n,t)=>{let i=J();try{r("Fetching page HTML...");let a=await i.pages.getHtml(e,n);a.result||(s("Page not found"),process.exit(1));let l=a.result.html;l||(s("Page has no HTML content"),r("Make sure the page has been created with HTML content"),process.exit(1)),r("Fetching website details...");let u=(await i.websites.getDetails(e)).result,b=u?.theme||{},v=u?.global_header||null,x=u?.global_footer||null,g=u?.custom_codes||{header:null,footer:null},w=a.result.name||"Page",p=a.result.seo||{},h=a.result.settings||{},y=a.result.custom_codes||{},f={header:y.header||g.header||"",footer:y.footer||g.footer||""},C=h.theme||{},T=C.mode!=="Light",I=C.direction||"ltr",O=C.main_classes||"",$=C.animations_deactivated||!1,z={font:C.font||b.font,title_font:C.title_font||b.title_font},ee=le(z),te=Ie(l).mainContent,H=Fe(te,v??void 0,x??void 0),re=`<!DOCTYPE html>
178
+ <html class="${T?"dark":""}" lang="en">
179
+ <head>
180
+ <meta charset="UTF-8">
181
+ <meta name="robots" content="max-snippet:-1, max-image-preview:large, max-video-preview:-1 ${p.noindex?"noindex":""} ${p.nofollow?"nofollow":""}">
182
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
183
+
184
+ <title>${p.page_title||w}</title>
185
+ <meta name="description" content="${p.meta_description||""}">
186
+
187
+ <meta property="og:title" content="${p.social_title||p.page_title||w}">
188
+ <meta property="og:description" content="${p.social_description||p.meta_description||""}">
189
+ ${p.social_image?`<meta property="og:image" content="${p.social_image}">`:""}
190
+ <meta property="og:type" content="website">
191
+ ${p.canonical_url?`<meta property="og:url" content="${p.canonical_url}">`:""}
192
+
193
+ <meta name="twitter:card" content="summary_large_image">
194
+ <meta name="twitter:title" content="${p.social_title||p.page_title||w}">
195
+ <meta name="twitter:description" content="${p.social_description||p.meta_description||""}">
196
+ ${p.social_image?`<meta name="twitter:image" content="${p.social_image}">`:""}
197
+
198
+ <!-- Google Fonts -->
199
+ ${ee}
200
+
201
+ <!-- Tailwind CSS v4 CDN for preview -->
202
+ <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
203
+
204
+ ${$?"":`
205
+ <!-- Motion for animations -->
206
+ <script src="https://cdn.jsdelivr.net/npm/motion@latest/dist/motion.js"></script>
207
+ <script src="https://lnui.pages.dev/motion-animate.js"></script>
208
+ `}
209
+
210
+ ${p.canonical_url?`<link rel="canonical" href="${p.canonical_url}">`:""}
211
+
212
+ <!-- Page Custom Code (Header) -->
213
+ ${f.header}
214
+
215
+ </head>
216
+ <body>
217
+ <!-- ========== MAIN CONTENT ========== -->
218
+ <main dir="${I}" lindo-main-content id="content" role="main" class="${O}">
219
+
220
+ ${H}
221
+
222
+ </main>
223
+ <!-- ========== END MAIN CONTENT ========== -->
224
+
225
+ <!-- Config script -->
226
+ <script src="https://cdn.ln-cdn.com/staging/js/config2.js"></script>
227
+
228
+ <!-- Page Custom Code (Footer) -->
229
+ ${f.footer}
230
+ </body>
231
+ </html>`,W=M__namespace.resolve(t.file);k__namespace.writeFileSync(W,re,"utf-8"),m(`HTML saved to ${W}`),await nt(),t.background?await it(W):await rt(W);}catch(a){X(a);}}),o.command("update").description("Update a page from HTML file (note: global header/footer changes are page-specific only)").argument("<website_id>","Website ID").argument("<page_id>","Page ID").option("--html-file <path>","Path to local HTML file to upload").option("-f, --format <format>","Output format (json, table)","table").action(async(e,n,t)=>{let i=J();try{t.htmlFile||(s("--html-file option is required"),r("Usage: lindoai pages update <website_id> <page_id> --html-file <path>"),process.exit(1));let a=M__namespace.resolve(t.htmlFile);k__namespace.existsSync(a)||(s(`File not found: ${a}`),process.exit(1));let l=k__namespace.readFileSync(a,"utf-8");r(`Read ${l.length} bytes from ${a}`);let c=l.match(/<main[^>]*>([\s\S]*)<\/main>/i),u=c?c[1].trim():l;c&&r("Extracted content from <main> tag");let b=Ie(u),v=b.mainContent,x=b.globalHeader,g=b.globalFooter;x&&r("Detected global header section"),g&&r("Detected global footer section");let w=l.match(/<title>([^<]*)<\/title>/i),p=w?w[1].trim():void 0;p&&r(`Extracted page title: ${p}`);let h="",y="",f=l.match(/<!-- Page Custom Code \(Header\) -->\s*([\s\S]*?)\s*<\/head>/i);f&&f[1].trim()&&(h=f[1].trim(),r("Extracted header custom code"));let C=l.match(/<!-- Page Custom Code \(Footer\) -->\s*([\s\S]*?)\s*<\/body>/i);C&&C[1].trim()&&(y=C[1].trim(),r("Extracted footer custom code"));let T=l.match(/<html[^>]*class="([^"]*)"/i),I=T?T[1].includes("dark"):!0,O=l.match(/<main[^>]*>/i),$="ltr",z="";if(O){let Ke=O[0].match(/dir="([^"]*)"/i);Ke&&($=Ke[1]);let Be=O[0].match(/class="([^"]*)"/i);Be&&(z=Be[1]);}let ee=!l.includes("motion@latest"),V=l.match(/<meta\s+name="description"\s+content="([^"]*)"/i),te=l.match(/<meta\s+property="og:title"\s+content="([^"]*)"/i),H=l.match(/<meta\s+property="og:description"\s+content="([^"]*)"/i),re=l.match(/<meta\s+property="og:image"\s+content="([^"]*)"/i),W=l.match(/<link\s+rel="canonical"\s+href="([^"]*)"/i),wt=l.match(/noindex/i),yt=l.match(/nofollow/i),E={};p&&(E.page_title=p),V&&V[1]&&(E.meta_description=V[1]),te&&te[1]&&(E.social_title=te[1]),H&&H[1]&&(E.social_description=H[1]),re&&re[1]&&(E.social_image=re[1]),W&&W[1]&&(E.canonical_url=W[1]),E.noindex=!!wt,E.nofollow=!!yt,Object.keys(E).length>2&&r("Extracted SEO metadata");let pe=await i.pages.get(e,n);pe.result||(s("Page not found"),process.exit(1));let vt=pe.result.path,xt={...pe.result.settings||{},theme:{...pe.result.settings?.theme||{},mode:I?"Dark":"Light",direction:$,main_classes:z,animations_deactivated:ee},should_convert:!0},ue={};h&&(ue.header=h),y&&(ue.footer=y),r("Updating page...");let fe=await i.pages.publish(e,n,{html:v,path:vt,settings:xt,template_name:p,custom_codes:Object.keys(ue).length>0?ue:void 0,seo:Object.keys(E).length>0?E:void 0,global_header:x,global_footer:g});t.format==="json"?d(fe,"json"):fe.success?(m("Page updated successfully"),console.log(` Page ID: ${fe.result?.page_id}`)):s("Failed to update page");}catch(a){X(a);}}),o.command("stop-preview").description("Stop the background preview server").action(async()=>{try{if(!k__namespace.existsSync(Q)){r("No preview server is running");return}let e=parseInt(k__namespace.readFileSync(Q,"utf-8").trim(),10);if(isNaN(e)){s("Invalid PID file"),Ee();return}try{process.kill(e,"SIGTERM"),m(`Preview server (PID ${e}) stopped`);}catch(n){n.code==="ESRCH"?r("Preview server process not found (may have already stopped)"):s(`Failed to stop preview server: ${n.message}`);}Ee();}catch(e){e instanceof Error?s(e.message):s("An unexpected error occurred"),process.exit(1);}}),o}function J(){F()||(s("API key not configured"),r("Run: lindo config set apiKey <your-api-key>"),r("Or set the LINDO_API_KEY environment variable"),process.exit(1));let o=_();return new lindoai.LindoClient({apiKey:o.apiKey,baseUrl:o.baseUrl})}function X(o){o instanceof lindoai.AuthenticationError&&(s("Authentication failed"),r("Your API key may be invalid or expired"),r("Run: lindo config set apiKey <your-api-key>"),process.exit(1)),o instanceof Error?s(o.message):s("An unexpected error occurred"),process.exit(1);}function Ee(){try{k__namespace.existsSync(Q)&&k__namespace.unlinkSync(Q);}catch{}try{k__namespace.existsSync(de)&&k__namespace.unlinkSync(de);}catch{}}async function nt(){if(k__namespace.existsSync(Q)){try{let o=parseInt(k__namespace.readFileSync(Q,"utf-8").trim(),10);if(!isNaN(o))try{process.kill(o,"SIGTERM"),r(`Terminated existing preview server (PID ${o})`),await new Promise(e=>setTimeout(e,500));}catch{}}catch{}Ee();}}async function it(o){let e=M__namespace.resolve(o),n=`
41
232
  const http = require('node:http');
42
233
  const fs = require('node:fs');
43
234
  const path = require('node:path');
@@ -57,7 +248,7 @@ Page Details:`),console.log("-------------"),console.log(` ID: ${i.page_id}`),c
57
248
  })();
58
249
  </script>\`;
59
250
 
60
- const filePath = ${JSON.stringify(t)};
251
+ const filePath = ${JSON.stringify(e)};
61
252
  const pidFile = path.join(os.tmpdir(), 'lindoai-pages-preview.pid');
62
253
  const portFile = path.join(os.tmpdir(), 'lindoai-pages-preview.port');
63
254
  const sseClients = new Set();
@@ -157,9 +348,31 @@ Page Details:`),console.log("-------------"),console.log(` ID: ${i.page_id}`),c
157
348
  });
158
349
  } catch {}
159
350
  });
160
- `,e=child_process.spawn(process.execPath,["-e",n],{detached:true,stdio:"ignore"});e.unref();let i=null;for(let m=0;m<50;m++)if(await new Promise(p=>setTimeout(p,100)),w__namespace.existsSync(z))try{if(i=parseInt(w__namespace.readFileSync(z,"utf-8").trim(),10),!isNaN(i))break}catch{}i||(r("Failed to start preview server"),process.exit(1));let a=`http://127.0.0.1:${i}/`;await L(a)||s(`Could not open browser. Visit: ${a}`),d("Preview server started in background"),console.log(` URL: ${a}`),console.log(` PID: ${e.pid}`),console.log(""),s("To update the page: lindoai pages update <website_id> <page_id> --html-file <path>"),s("To stop the server: lindoai pages stop-preview");}async function At(o){let{startLivePreviewServer:t}=await Promise.resolve().then(()=>(ue(),pe));s("Starting preview server...");let n=await t(o),e=`http://127.0.0.1:${n}/`;w__namespace.writeFileSync(N,process.pid.toString(),"utf-8"),w__namespace.writeFileSync(z,n.toString(),"utf-8"),await L(e)||s(`Could not open browser. Visit: ${e}`),d("Preview server started"),console.log(` URL: ${e}`),console.log(""),s("Press Ctrl+C to stop the server"),s("Edit the HTML file and save to see changes in the browser");}var q=j__namespace.join(de__namespace.tmpdir(),"lindoai-blogs-preview.pid"),Q=j__namespace.join(de__namespace.tmpdir(),"lindoai-blogs-preview.port");function ye(){let o=new commander.Command("blogs").description("Blog management operations");return o.command("list").description("List all blogs for a website").requiredOption("-w, --website <id>","Website ID").option("-p, --page <page>","Page number","1").option("-s, --search <search>","Search term").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=U();try{let e=await n.blogs.list(t.website,{page:parseInt(t.page,10),search:t.search});if(t.format==="json")c(e,"json");else {let i=e.result;if(i?.list&&i.list.length>0){console.log(`
161
- Blogs:`),console.log("------");for(let a of i.list)console.log(` ID: ${a.blog_id}`),console.log(` Name: ${a.name??"N/A"}`),console.log(` Path: ${a.path??"N/A"}`),console.log(` Status: ${a.status??"N/A"}`),console.log(` Published: ${a.publish_date?new Date(a.publish_date*1e3).toISOString():"No"}`),console.log("");console.log(`Total: ${i.total??i.list.length}`);}else s("No blogs found");}}catch(e){K(e);}}),o.command("get").description("Get details of a specific blog").requiredOption("-w, --website <id>","Website ID").requiredOption("-i, --id <id>","Blog ID").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=U();try{let e=await n.blogs.get(t.website,t.id);if(t.format==="json")c(e,"json");else {let i=e.result;i?(console.log(`
162
- Blog Details:`),console.log("-------------"),console.log(` ID: ${i.blog_id}`),console.log(` Name: ${i.name??"N/A"}`),console.log(` Path: ${i.path??"N/A"}`),console.log(` Status: ${i.status??"N/A"}`),console.log(` Published: ${i.publish_date?new Date(i.publish_date*1e3).toISOString():"No"}`),console.log(` Created: ${i.created_date??"N/A"}`)):r("Blog not found");}}catch(e){K(e);}}),o.command("publish").description("Publish a blog").requiredOption("-w, --website <id>","Website ID").requiredOption("-i, --id <id>","Blog ID").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=U();try{let e=await n.blogs.publish(t.website,t.id);t.format==="json"?c(e,"json"):e.success?(d("Blog published successfully"),console.log(` Blog ID: ${e.result?.blog_id}`),console.log(` Published at: ${e.result?.publish_date?new Date(e.result.publish_date*1e3).toISOString():"N/A"}`)):r("Failed to publish blog");}catch(e){K(e);}}),o.command("unpublish").description("Unpublish a blog").requiredOption("-w, --website <id>","Website ID").requiredOption("-i, --id <id>","Blog ID").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=U();try{let e=await n.blogs.unpublish(t.website,t.id);t.format==="json"?c(e,"json"):e.success?(d("Blog unpublished successfully"),console.log(` Blog ID: ${e.result?.blog_id}`)):r("Failed to unpublish blog");}catch(e){K(e);}}),o.command("delete").description("Delete a blog").requiredOption("-w, --website <id>","Website ID").requiredOption("-i, --id <id>","Blog ID").option("-f, --format <format>","Output format (json, table)","table").action(async t=>{let n=U();try{let e=await n.blogs.delete(t.website,t.id);if(t.format==="json")c(e,"json");else if(e.success){if(d("Blog deleted successfully"),console.log(` Blog ID: ${e.result?.blog_id}`),e.result?.warnings&&e.result.warnings.length>0){console.log(" Warnings:");for(let i of e.result.warnings)console.log(` - ${i}`);}}else r("Failed to delete blog");}catch(e){K(e);}}),o.command("edit").description("Edit a blog with live preview").argument("<website_id>","Website ID").argument("<blog_id>","Blog ID").option("--file <path>","Output file path","./blog.html").option("--background","Run preview server in background").action(async(t,n,e)=>{let i=U();try{s("Fetching blog details...");let a=await i.blogs.get(t,n);a.result||(r("Blog not found"),process.exit(1));let l=a.result.path,m=await i.websites.getDetails(t);m.result||(r("Website not found"),process.exit(1));let p=m.result.custom_domain||m.result.verified_domain||m.result.preview_url;p||(r("Could not determine website URL"),process.exit(1));let b=`https://${p}${l}`;s(`Fetching HTML from ${b}...`);let g=await fetch(b);g.ok||(r(`Failed to fetch blog HTML: ${g.status} ${g.statusText}`),s("Make sure the blog is published before editing"),process.exit(1));let v=await g.text(),u=j__namespace.resolve(e.file);w__namespace.writeFileSync(u,v,"utf-8"),d(`HTML saved to ${u}`),await Dt(),e.background?await Rt(u):await jt(u);}catch(a){K(a);}}),o.command("update").description("Update a blog").argument("<website_id>","Website ID").argument("<blog_id>","Blog ID").option("--html-file <path>","Path to local HTML file to upload").option("-f, --format <format>","Output format (json, table)","table").action(async(t,n,e)=>{let i=U(),a=h();try{e.htmlFile||(r("--html-file option is required"),s("Usage: lindoai blogs update <website_id> <blog_id> --html-file <path>"),process.exit(1));let l=j__namespace.resolve(e.htmlFile);w__namespace.existsSync(l)||(r(`File not found: ${l}`),process.exit(1));let m=w__namespace.readFileSync(l,"utf-8");s(`Read ${m.length} bytes from ${l}`);let p=await i.blogs.get(t,n);p.result||(r("Blog not found"),process.exit(1));let b=p.result.path;s("Updating blog...");let v=`${a.baseUrl||"https://api.lindo.ai"}/v1/workspace/website/${t}/blogs/${n}/update`,f=await(await fetch(v,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${a.apiKey}`},body:JSON.stringify({html:m,path:b})})).json();if(e.format==="json")c(f,"json");else if(f.success)d("Blog updated successfully"),console.log(` Blog ID: ${f.result?.blog_id}`),f.result?.publish_date&&console.log(` Published at: ${new Date(f.result.publish_date*1e3).toISOString()}`);else if(r("Failed to update blog"),f.errors)for(let S of f.errors)console.log(` ${S}`);}catch(l){K(l);}}),o.command("stop-preview").description("Stop the background preview server").action(async()=>{try{if(!w__namespace.existsSync(q)){s("No preview server is running");return}let t=parseInt(w__namespace.readFileSync(q,"utf-8").trim(),10);if(isNaN(t)){r("Invalid PID file"),be();return}try{process.kill(t,"SIGTERM"),d(`Preview server (PID ${t}) stopped`);}catch(n){n.code==="ESRCH"?s("Preview server process not found (may have already stopped)"):r(`Failed to stop preview server: ${n.message}`);}be();}catch(t){t instanceof Error?r(t.message):r("An unexpected error occurred"),process.exit(1);}}),o}function U(){C()||(r("API key not configured"),s("Run: lindo config set apiKey <your-api-key>"),s("Or set the LINDO_API_KEY environment variable"),process.exit(1));let o=h();return new lindoai.LindoClient({apiKey:o.apiKey,baseUrl:o.baseUrl})}function K(o){o instanceof lindoai.AuthenticationError&&(r("Authentication failed"),s("Your API key may be invalid or expired"),s("Run: lindo config set apiKey <your-api-key>"),process.exit(1)),o instanceof Error?r(o.message):r("An unexpected error occurred"),process.exit(1);}function be(){try{w__namespace.existsSync(q)&&w__namespace.unlinkSync(q);}catch{}try{w__namespace.existsSync(Q)&&w__namespace.unlinkSync(Q);}catch{}}async function Dt(){if(w__namespace.existsSync(q)){try{let o=parseInt(w__namespace.readFileSync(q,"utf-8").trim(),10);if(!isNaN(o))try{process.kill(o,"SIGTERM"),s(`Terminated existing preview server (PID ${o})`),await new Promise(t=>setTimeout(t,500));}catch{}}catch{}be();}}async function Rt(o){let t=j__namespace.resolve(o),n=`
351
+ `,t=child_process.spawn(process.execPath,["-e",n],{detached:true,stdio:"ignore"});t.unref();let i=null;for(let c=0;c<50;c++)if(await new Promise(u=>setTimeout(u,100)),k__namespace.existsSync(de))try{if(i=parseInt(k__namespace.readFileSync(de,"utf-8").trim(),10),!isNaN(i))break}catch{}i||(s("Failed to start preview server"),process.exit(1));let a=`http://127.0.0.1:${i}/`;await B(a)||r(`Could not open browser. Visit: ${a}`),m("Preview server started in background"),console.log(` URL: ${a}`),console.log(` PID: ${t.pid}`),console.log(""),r("To update the page: lindoai pages update <website_id> <page_id> --html-file <path>"),r("To stop the server: lindoai pages stop-preview");}async function rt(o){let{startLivePreviewServer:e}=await Promise.resolve().then(()=>(Ae(),Pe));r("Starting preview server...");let n=await e(o),t=`http://127.0.0.1:${n}/`;k__namespace.writeFileSync(Q,process.pid.toString(),"utf-8"),k__namespace.writeFileSync(de,n.toString(),"utf-8"),await B(t)||r(`Could not open browser. Visit: ${t}`),m("Preview server started"),console.log(` URL: ${t}`),console.log(""),r("Press Ctrl+C to stop the server"),r("Edit the HTML file and save to see changes in the browser");}var Z=M__namespace.join($e__namespace.tmpdir(),"lindoai-blogs-preview.pid"),me=M__namespace.join($e__namespace.tmpdir(),"lindoai-blogs-preview.port");function Ne(){let o=new commander.Command("blogs").description("Blog management operations");return o.command("list").description("List all blogs for a website").requiredOption("-w, --website <id>","Website ID").option("-p, --page <page>","Page number","1").option("-s, --search <search>","Search term").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=G();try{let t=await n.blogs.list(e.website,{page:parseInt(e.page,10),search:e.search});if(e.format==="json")d(t,"json");else {let i=t.result;if(i?.list&&i.list.length>0){console.log(`
352
+ Blogs:`),console.log("------");for(let a of i.list)console.log(` ID: ${a.blog_id}`),console.log(` Name: ${a.name??"N/A"}`),console.log(` Path: ${a.path??"N/A"}`),console.log(` Status: ${a.status??"N/A"}`),console.log(` Published: ${a.publish_date?new Date(a.publish_date*1e3).toISOString():"No"}`),console.log("");console.log(`Total: ${i.total??i.list.length}`);}else r("No blogs found");}}catch(t){Y(t);}}),o.command("get").description("Get details of a specific blog").requiredOption("-w, --website <id>","Website ID").requiredOption("-i, --id <id>","Blog ID").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=G();try{let t=await n.blogs.get(e.website,e.id);if(e.format==="json")d(t,"json");else {let i=t.result;i?(console.log(`
353
+ Blog Details:`),console.log("-------------"),console.log(` ID: ${i.blog_id}`),console.log(` Name: ${i.name??"N/A"}`),console.log(` Path: ${i.path??"N/A"}`),console.log(` Status: ${i.status??"N/A"}`),console.log(` Published: ${i.publish_date?new Date(i.publish_date*1e3).toISOString():"No"}`),console.log(` Created: ${i.created_date??"N/A"}`)):s("Blog not found");}}catch(t){Y(t);}}),o.command("publish").description("Publish a blog").requiredOption("-w, --website <id>","Website ID").requiredOption("-i, --id <id>","Blog ID").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=G();try{let t=await n.blogs.publish(e.website,e.id);e.format==="json"?d(t,"json"):t.success?(m("Blog published successfully"),console.log(` Blog ID: ${t.result?.blog_id}`),console.log(` Published at: ${t.result?.publish_date?new Date(t.result.publish_date*1e3).toISOString():"N/A"}`)):s("Failed to publish blog");}catch(t){Y(t);}}),o.command("unpublish").description("Unpublish a blog").requiredOption("-w, --website <id>","Website ID").requiredOption("-i, --id <id>","Blog ID").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=G();try{let t=await n.blogs.unpublish(e.website,e.id);e.format==="json"?d(t,"json"):t.success?(m("Blog unpublished successfully"),console.log(` Blog ID: ${t.result?.blog_id}`)):s("Failed to unpublish blog");}catch(t){Y(t);}}),o.command("delete").description("Delete a blog").requiredOption("-w, --website <id>","Website ID").requiredOption("-i, --id <id>","Blog ID").option("-f, --format <format>","Output format (json, table)","table").action(async e=>{let n=G();try{let t=await n.blogs.delete(e.website,e.id);if(e.format==="json")d(t,"json");else if(t.success){if(m("Blog deleted successfully"),console.log(` Blog ID: ${t.result?.blog_id}`),t.result?.warnings&&t.result.warnings.length>0){console.log(" Warnings:");for(let i of t.result.warnings)console.log(` - ${i}`);}}else s("Failed to delete blog");}catch(t){Y(t);}}),o.command("edit").description("Edit a blog with live preview").argument("<website_id>","Website ID").argument("<blog_id>","Blog ID").option("--file <path>","Output file path","./blog.html").option("--background","Run preview server in background").action(async(e,n,t)=>{let i=G();try{r("Fetching blog content...");let a=await i.blogs.getHtml(e,n);a.result||(s("Blog not found"),process.exit(1));let l=a.result,c=await i.websites.getDetails(e);c.result||(s("Website not found"),process.exit(1));let u=c.result,b=u,v=b?.theme||{},x=b?.custom_codes||{header:null,footer:null},g={font:v.font,title_font:v.title_font},w=l.seo||{},p=l.blog_settings||{},h=l.blog_content||"<p>Start writing your blog content here...</p>",y=ct({seo:w,blogSettings:p,blogContent:h,websiteName:u.business_name||"Blog",blogPath:v.blog_path||"blog",websiteTheme:g,customCodes:{header:x.header||void 0,footer:x.footer||void 0}}),f=M__namespace.resolve(t.file);k__namespace.writeFileSync(f,y,"utf-8"),m(`HTML saved to ${f}`),await at(),t.background?await st(f):await lt(f),console.log(""),r(`To save changes: lindoai blogs update ${e} ${n} --html-file ${t.file}`);}catch(a){Y(a);}}),o.command("update").description("Update a blog from HTML file").argument("<website_id>","Website ID").argument("<blog_id>","Blog ID").option("--html-file <path>","Path to local HTML file").option("--md-file <path>","Path to local Markdown file").option("-f, --format <format>","Output format (json, table)","table").action(async(e,n,t)=>{let i=G();try{!t.htmlFile&&!t.mdFile&&(s("Either --html-file or --md-file option is required"),r("Usage: lindoai blogs update <website_id> <blog_id> --html-file <path>"),r(" or: lindoai blogs update <website_id> <blog_id> --md-file <path>"),process.exit(1));let a,l={},c={};if(t.mdFile){let p=M__namespace.resolve(t.mdFile);k__namespace.existsSync(p)||(s(`File not found: ${p}`),process.exit(1));let h=k__namespace.readFileSync(p,"utf-8");r(`Read ${h.length} bytes from ${p}`);let{content:y,frontmatter:f}=bo(h);a=wo(y),f.title&&(l.page_title=f.title),f.description&&(l.meta_description=f.description),f.image&&(l.social_image=f.image),f.author&&(c.author=f.author),f.excerpt&&(c.excerpt=f.excerpt),f.category&&(c.category=f.category),f.date&&(c.publish_date=f.date);}else {let p=M__namespace.resolve(t.htmlFile);k__namespace.existsSync(p)||(s(`File not found: ${p}`),process.exit(1));let h=k__namespace.readFileSync(p,"utf-8");r(`Read ${h.length} bytes from ${p}`);let y=h.match(/<article[^>]*class="[^"]*prose[^"]*"[^>]*>([\s\S]*?)<\/article>/i);a=y?y[1].trim():"",a||(s("Could not extract blog content from HTML"),r('Make sure the blog content is inside <article class="...prose...">...</article>'),process.exit(1));let f=h.match(/<title>([^<]*)<\/title>/i),C=h.match(/<meta\s+name="description"\s+content="([^"]*)"/i),T=h.match(/<meta\s+property="og:image"\s+content="([^"]*)"/i);f&&(l.page_title=f[1].trim()),C&&(l.meta_description=C[1]),T&&(l.social_image=T[1]);let I=h.match(/id="blog-author-display"[^>]*>([\s\S]*?)<\/span>/i),O=h.match(/class="[^"]*bg-blue-500\/10[^"]*"[^>]*>([^<]*)</i),$=h.match(/class="[^"]*border-l-4 border-blue-500[^"]*"[^>]*>([\s\S]*?)<\/div>/i),z=h.match(/<time[^>]*>([^<]*)<\/time>/i),ee=h.match(/<span>(\d+\s*min\s*read)<\/span>/i),V=h.match(/<div class="aspect-video[^"]*"[^>]*>\s*<img[^>]*src="([^"]*)"/i);if(I){let H=I[1].replace(/<[^>]*>/g,"").trim();H&&(c.author=H);}O&&(c.category=O[1].trim()),$&&(c.excerpt=$[1].trim()),z&&(c.publish_date=z[1].trim()),ee&&(c.read_time=ee[1].trim()),V&&!l.social_image&&(l.social_image=V[1]),r("Extracted blog content and metadata");}let u=await i.blogs.get(e,n);u.result||(s("Blog not found"),process.exit(1));let b=u.result,v=b.path,x={page_title:l.page_title||b.seo?.page_title||"Untitled",meta_description:l.meta_description||b.seo?.meta_description,social_title:l.social_title||b.seo?.social_title,social_description:l.social_description||b.seo?.social_description,social_image:l.social_image||b.seo?.social_image},g={author:c.author||b.blog_settings?.author||"Anonymous",excerpt:c.excerpt||b.blog_settings?.excerpt,category:c.category||b.blog_settings?.category,publish_date:c.publish_date||b.blog_settings?.publish_date,read_time:c.read_time||b.blog_settings?.read_time,author_image:c.author_image||b.blog_settings?.author_image};r("Updating blog...");let w=await i.blogs.publish(e,n,{path:v,blog_content:a,seo:x,blog_settings:g});t.format==="json"?d(w,"json"):w.success?(m("Blog updated successfully"),console.log(` Blog ID: ${w.result?.blog_id}`)):s("Failed to update blog");}catch(a){Y(a);}}),o.command("create").description("Create a new blog with live preview").argument("<website_id>","Website ID").argument("<path>","URL path for the blog (e.g., /blog/my-first-post)").option("--title <title>","Blog title","New Blog Post").option("--author <author>","Author name","Anonymous").option("--file <path>","Output file path","./blog.html").option("--background","Run preview server in background").action(async(e,n,t)=>{let i=G();try{let a=await i.websites.getDetails(e);a.result||(s("Website not found"),process.exit(1));let l=a.result,c=l,u=c?.theme||{},b=c?.custom_codes||{header:null,footer:null},v={font:u.font,title_font:u.title_font},x=t.title,g=t.author,w=new Date().toLocaleDateString("en-US",{year:"numeric",month:"long",day:"numeric"}),p=`<h2>Introduction</h2>
354
+ <p>Welcome to your new blog post! This is a starter template to help you get started. Edit this content to create your own amazing blog post.</p>
355
+
356
+ <h2>Getting Started</h2>
357
+ <p>Here are some tips for writing great blog content:</p>
358
+ <ul>
359
+ <li>Start with a compelling introduction that hooks your readers</li>
360
+ <li>Break up your content with headings and subheadings</li>
361
+ <li>Use bullet points and numbered lists for easy scanning</li>
362
+ <li>Include relevant images to illustrate your points</li>
363
+ <li>End with a clear call-to-action or conclusion</li>
364
+ </ul>
365
+
366
+ <h2>Adding Code Examples</h2>
367
+ <p>If you're writing technical content, you can include code blocks:</p>
368
+ <pre><code>function greet(name) {
369
+ return \`Hello, \${name}!\`;
370
+ }
371
+
372
+ console.log(greet('World'));</code></pre>
373
+
374
+ <h2>Conclusion</h2>
375
+ <p>Now it's your turn! Replace this content with your own ideas and publish your blog post to share it with the world.</p>`,h={page_title:x,meta_description:`Read ${x} by ${g}`,social_title:x,social_description:`Read ${x} by ${g}`},y={author:g,excerpt:"A new blog post. Edit this excerpt to provide a summary of your content.",publish_date:w,read_time:"3 min read"};r("Creating blog...");let f=await i.blogs.create(e,{path:n,blog_content:p,seo:h,blog_settings:y});f.success||(s("Failed to create blog"),process.exit(1));let C=f.result.blog_id;m(`Blog created: ${C}`);let T=ct({seo:h,blogSettings:y,blogContent:p,websiteName:l.business_name||"Blog",blogPath:u.blog_path||"blog",websiteTheme:v,customCodes:{header:b.header||void 0,footer:b.footer||void 0}}),I=M__namespace.resolve(t.file);k__namespace.writeFileSync(I,T,"utf-8"),m(`HTML saved to ${I}`),await at(),t.background?await st(I):await lt(I),console.log(""),r(`To save changes: lindoai blogs update ${e} ${C} --html-file ${t.file}`);}catch(a){Y(a);}}),o.command("stop-preview").description("Stop the background preview server").action(async()=>{try{if(!k__namespace.existsSync(Z)){r("No preview server is running");return}let e=parseInt(k__namespace.readFileSync(Z,"utf-8").trim(),10);if(isNaN(e)){s("Invalid PID file"),De();return}try{process.kill(e,"SIGTERM"),m(`Preview server (PID ${e}) stopped`);}catch(n){n.code==="ESRCH"?r("Preview server process not found (may have already stopped)"):s(`Failed to stop preview server: ${n.message}`);}De();}catch(e){e instanceof Error?s(e.message):s("An unexpected error occurred"),process.exit(1);}}),o}function G(){F()||(s("API key not configured"),r("Run: lindo config set apiKey <your-api-key>"),r("Or set the LINDO_API_KEY environment variable"),process.exit(1));let o=_();return new lindoai.LindoClient({apiKey:o.apiKey,baseUrl:o.baseUrl})}function Y(o){o instanceof lindoai.AuthenticationError&&(s("Authentication failed"),r("Your API key may be invalid or expired"),r("Run: lindo config set apiKey <your-api-key>"),process.exit(1)),o instanceof Error?s(o.message):s("An unexpected error occurred"),process.exit(1);}function De(){try{k__namespace.existsSync(Z)&&k__namespace.unlinkSync(Z);}catch{}try{k__namespace.existsSync(me)&&k__namespace.unlinkSync(me);}catch{}}async function at(){if(k__namespace.existsSync(Z)){try{let o=parseInt(k__namespace.readFileSync(Z,"utf-8").trim(),10);if(!isNaN(o))try{process.kill(o,"SIGTERM"),r(`Terminated existing preview server (PID ${o})`),await new Promise(e=>setTimeout(e,500));}catch{}}catch{}De();}}async function st(o){let e=M__namespace.resolve(o),n=`
163
376
  const http = require('node:http');
164
377
  const fs = require('node:fs');
165
378
  const path = require('node:path');
@@ -179,7 +392,7 @@ Blog Details:`),console.log("-------------"),console.log(` ID: ${i.blog_id}`),c
179
392
  })();
180
393
  </script>\`;
181
394
 
182
- const filePath = ${JSON.stringify(t)};
395
+ const filePath = ${JSON.stringify(e)};
183
396
  const pidFile = path.join(os.tmpdir(), 'lindoai-blogs-preview.pid');
184
397
  const portFile = path.join(os.tmpdir(), 'lindoai-blogs-preview.port');
185
398
  const sseClients = new Set();
@@ -279,7 +492,196 @@ Blog Details:`),console.log("-------------"),console.log(` ID: ${i.blog_id}`),c
279
492
  });
280
493
  } catch {}
281
494
  });
282
- `,e=child_process.spawn(process.execPath,["-e",n],{detached:true,stdio:"ignore"});e.unref();let i=null;for(let m=0;m<50;m++)if(await new Promise(p=>setTimeout(p,100)),w__namespace.existsSync(Q))try{if(i=parseInt(w__namespace.readFileSync(Q,"utf-8").trim(),10),!isNaN(i))break}catch{}i||(r("Failed to start preview server"),process.exit(1));let a=`http://127.0.0.1:${i}/`;await L(a)||s(`Could not open browser. Visit: ${a}`),d("Preview server started in background"),console.log(` URL: ${a}`),console.log(` PID: ${e.pid}`),console.log(""),s("To update the blog: lindoai blogs update <website_id> <blog_id> --html-file <path>"),s("To stop the server: lindoai blogs stop-preview");}async function jt(o){let{startLivePreviewServer:t}=await Promise.resolve().then(()=>(ue(),pe));s("Starting preview server...");let n=await t(o),e=`http://127.0.0.1:${n}/`;w__namespace.writeFileSync(q,process.pid.toString(),"utf-8"),w__namespace.writeFileSync(Q,n.toString(),"utf-8"),await L(e)||s(`Could not open browser. Visit: ${e}`),d("Preview server started"),console.log(` URL: ${e}`),console.log(""),s("Press Ctrl+C to stop the server"),s("Edit the HTML file and save to see changes in the browser");}function Re(){return De__namespace.randomBytes(32).toString("hex")}function je(o,t){return o===t}function Ut(o){try{let t=o.startsWith("http")?o:`http://localhost${o}`,e=new url.URL(t).searchParams;return {key:e.get("key")??void 0,state:e.get("state")??void 0,error:e.get("error")??void 0,message:e.get("message")??void 0}}catch{return {}}}function Kt(){return `<!DOCTYPE html>
495
+ `,t=child_process.spawn(process.execPath,["-e",n],{detached:true,stdio:"ignore"});t.unref();let i=null;for(let c=0;c<50;c++)if(await new Promise(u=>setTimeout(u,100)),k__namespace.existsSync(me))try{if(i=parseInt(k__namespace.readFileSync(me,"utf-8").trim(),10),!isNaN(i))break}catch{}i||(s("Failed to start preview server"),process.exit(1));let a=`http://127.0.0.1:${i}/`;await B(a)||r(`Could not open browser. Visit: ${a}`),m("Preview server started in background"),console.log(` URL: ${a}`),console.log(` PID: ${t.pid}`),console.log(""),r("To update the blog: lindoai blogs update <website_id> <blog_id> --html-file <path>"),r("To stop the server: lindoai blogs stop-preview");}async function lt(o){let{startLivePreviewServer:e}=await Promise.resolve().then(()=>(Ae(),Pe));r("Starting preview server...");let n=await e(o),t=`http://127.0.0.1:${n}/`;k__namespace.writeFileSync(Z,process.pid.toString(),"utf-8"),k__namespace.writeFileSync(me,n.toString(),"utf-8"),await B(t)||r(`Could not open browser. Visit: ${t}`),m("Preview server started"),console.log(` URL: ${t}`),console.log(""),r("Press Ctrl+C to stop the server"),r("Edit the HTML file and save to see changes in the browser");}function ho(o){return o?o.split(" ").map(e=>e.charAt(0).toUpperCase()).slice(0,2).join(""):"?"}function ct(o){let{seo:e,blogSettings:n,blogContent:t,websiteName:i,blogPath:a,websiteTheme:l,customCodes:c}=o,u=l?le(l):"";return `<!DOCTYPE html>
496
+ <html class="dark" lang="en">
497
+ <head>
498
+ <meta charset="UTF-8">
499
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
500
+
501
+ <title>${e.page_title||"Blog Post"}</title>
502
+ <meta name="description" content="${e.meta_description||""}">
503
+
504
+ <meta property="og:title" content="${e.social_title||e.page_title||""}">
505
+ <meta property="og:description" content="${e.social_description||e.meta_description||""}">
506
+ ${e.social_image?`<meta property="og:image" content="${e.social_image}">`:""}
507
+ <meta property="og:type" content="article">
508
+
509
+ <meta name="twitter:card" content="summary_large_image">
510
+ <meta name="twitter:title" content="${e.social_title||e.page_title||""}">
511
+ <meta name="twitter:description" content="${e.social_description||e.meta_description||""}">
512
+ ${e.social_image?`<meta name="twitter:image" content="${e.social_image}">`:""}
513
+
514
+ <!-- Google Fonts -->
515
+ ${u}
516
+
517
+ <!-- Tailwind CSS v4 CDN for preview -->
518
+ <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
519
+
520
+ <!-- Custom Code (Header) -->
521
+ ${c?.header||""}
522
+
523
+ <style>
524
+ /* Required default styles for content */
525
+ blockquote, dd, dl, figure, h1, h2, h3, h4, h5, h6, hr, p, pre {
526
+ margin: revert;
527
+ }
528
+ menu, ol, ul {
529
+ list-style: revert;
530
+ margin: revert;
531
+ padding: revert;
532
+ }
533
+ /* Reading progress bar */
534
+ #reading-progress {
535
+ position: fixed;
536
+ top: 0;
537
+ left: 0;
538
+ width: 0%;
539
+ height: 3px;
540
+ background: linear-gradient(90deg, #3b82f6, #8b5cf6);
541
+ z-index: 1000;
542
+ transition: width 0.25s ease;
543
+ }
544
+ /* Custom scrollbar for dark mode */
545
+ .dark ::-webkit-scrollbar { width: 8px; }
546
+ .dark ::-webkit-scrollbar-track { background: #1f2937; }
547
+ .dark ::-webkit-scrollbar-thumb { background: #4b5563; border-radius: 4px; }
548
+ .dark ::-webkit-scrollbar-thumb:hover { background: #6b7280; }
549
+ </style>
550
+ </head>
551
+ <body>
552
+ <div class="bg-white dark:bg-neutral-950 text-gray-900 dark:text-neutral-100 font-sans antialiased min-h-screen">
553
+ <!-- Reading Progress Bar -->
554
+ <div id="reading-progress"></div>
555
+
556
+ <!-- Navigation -->
557
+ <nav class="fixed w-full top-0 z-50 bg-white/90 dark:bg-neutral-950/90 backdrop-blur-lg border-b border-gray-200 dark:border-neutral-800">
558
+ <div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
559
+ <div class="flex justify-between items-center py-4">
560
+ <div class="flex items-center space-x-2">
561
+ <a href="/${a}" class="flex items-center space-x-2 text-gray-600 dark:text-neutral-300 hover:text-gray-900 dark:hover:text-white transition-colors">
562
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
563
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
564
+ </svg>
565
+ </a>
566
+ </div>
567
+ <div class="flex items-center space-x-4">
568
+ <button onclick="copyLink()" class="text-gray-500 dark:text-neutral-400 hover:text-green-500 dark:hover:text-green-400 transition-colors">
569
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
570
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
571
+ </svg>
572
+ </button>
573
+ <button onclick="toggleTheme()" class="text-gray-500 dark:text-neutral-400 hover:text-gray-900 dark:hover:text-white p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-neutral-800 transition-all hover:scale-110">
574
+ <svg class="w-5 h-5 hidden dark:block" fill="none" stroke="currentColor" viewBox="0 0 24 24">
575
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path>
576
+ </svg>
577
+ <svg class="w-5 h-5 block dark:hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24">
578
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path>
579
+ </svg>
580
+ </button>
581
+ </div>
582
+ </div>
583
+ </div>
584
+ </nav>
585
+
586
+ <!-- Article Header -->
587
+ <header class="pt-24 pb-8 px-4 sm:px-6 lg:px-8">
588
+ <article class="max-w-4xl mx-auto">
589
+ ${n.category?`
590
+ <div class="mb-6">
591
+ <span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-blue-500/10 text-blue-600 dark:text-blue-400 border border-blue-500/20">
592
+ ${n.category}
593
+ </span>
594
+ </div>
595
+ `:""}
596
+
597
+ <h1 class="text-3xl sm:text-4xl lg:text-5xl font-bold font-display leading-tight mb-6 text-gray-900 dark:text-neutral-100">
598
+ ${e.page_title||"Untitled"}
599
+ </h1>
600
+
601
+ <div class="flex flex-wrap items-center gap-4 text-sm text-gray-500 dark:text-neutral-400 mb-8">
602
+ <div class="flex items-center space-x-2">
603
+ <div id="blog-author-avatar" class="w-8 h-8 rounded-full bg-blue-500 flex items-center justify-center text-white text-xs font-semibold">
604
+ ${ho(n.author||"Anonymous")}
605
+ </div>
606
+ <span id="blog-author-display" class="font-medium text-neutral-200">
607
+ ${n.author||"Anonymous"}
608
+ </span>
609
+ </div>
610
+ <span>\u2022</span>
611
+ <time>${n.publish_date||new Date().toLocaleDateString("en-US",{year:"numeric",month:"long",day:"numeric"})}</time>
612
+ <span>\u2022</span>
613
+ <span>${n.read_time||"4 min read"}</span>
614
+ </div>
615
+
616
+ ${e.social_image?`
617
+ <div class="aspect-video rounded-xl overflow-hidden mb-8">
618
+ <img src="${e.social_image}" alt="" class="w-full h-full object-cover">
619
+ </div>
620
+ `:""}
621
+
622
+ ${n.excerpt?`
623
+ <div class="text-xl text-gray-700 dark:text-neutral-300 leading-relaxed mb-8 italic border-l-4 border-blue-500 pl-6">
624
+ ${n.excerpt}
625
+ </div>
626
+ `:""}
627
+ </article>
628
+ </header>
629
+
630
+ <!-- Article Content -->
631
+ <main class="px-4 sm:px-6 lg:px-8 pb-16">
632
+ <article class="max-w-3xl mx-auto prose prose-lg prose-gray dark:prose-invert">
633
+ ${t}
634
+ </article>
635
+ </main>
636
+
637
+ <!-- Footer -->
638
+ <footer class="bg-gray-50 dark:bg-neutral-900 border-t border-gray-200 dark:border-neutral-800 py-8 px-4 sm:px-6 lg:px-8">
639
+ <div class="max-w-4xl mx-auto text-center">
640
+ <p class="text-gray-600 dark:text-neutral-400">&copy; ${new Date().getFullYear()}. ${i}.</p>
641
+ </div>
642
+ </footer>
643
+ </div>
644
+
645
+ <script>
646
+ function toggleTheme() {
647
+ const html = document.documentElement;
648
+ if (html.classList.contains('dark')) {
649
+ html.classList.remove('dark');
650
+ localStorage.setItem('theme', 'light');
651
+ } else {
652
+ html.classList.add('dark');
653
+ localStorage.setItem('theme', 'dark');
654
+ }
655
+ }
656
+ document.addEventListener('DOMContentLoaded', () => {
657
+ const savedTheme = localStorage.getItem('theme');
658
+ if (savedTheme === 'dark' || !savedTheme) {
659
+ document.documentElement.classList.add('dark');
660
+ }
661
+ });
662
+ window.addEventListener('scroll', () => {
663
+ const scrollTop = window.pageYOffset;
664
+ const docHeight = document.documentElement.scrollHeight - window.innerHeight;
665
+ const scrollPercent = (scrollTop / docHeight) * 100;
666
+ document.getElementById('reading-progress').style.width = scrollPercent + '%';
667
+ });
668
+ function copyLink() {
669
+ navigator.clipboard.writeText(window.location.href).then(() => {
670
+ alert('Link copied to clipboard!');
671
+ });
672
+ }
673
+ </script>
674
+
675
+ <!-- Config script -->
676
+ <script src="https://cdn.ln-cdn.com/staging/js/config2.js"></script>
677
+
678
+ <!-- Custom Code (Footer) -->
679
+ ${c?.footer||""}
680
+ </body>
681
+ </html>`}function bo(o){let e={},n=o;if(o.startsWith("---")){let t=o.indexOf("---",3);if(t!==-1){let i=o.slice(3,t).trim();n=o.slice(t+3).trim();for(let a of i.split(`
682
+ `)){let l=a.indexOf(":");if(l!==-1){let c=a.slice(0,l).trim(),u=a.slice(l+1).trim();(u.startsWith('"')&&u.endsWith('"')||u.startsWith("'")&&u.endsWith("'"))&&(u=u.slice(1,-1)),e[c]=u;}}}}return {content:n,frontmatter:e}}function wo(o){let e=o;return e=e.replace(/^### (.+)$/gm,"<h3>$1</h3>"),e=e.replace(/^## (.+)$/gm,"<h2>$1</h2>"),e=e.replace(/^# (.+)$/gm,"<h1>$1</h1>"),e=e.replace(/\*\*\*(.+?)\*\*\*/g,"<strong><em>$1</em></strong>"),e=e.replace(/\*\*(.+?)\*\*/g,"<strong>$1</strong>"),e=e.replace(/\*(.+?)\*/g,"<em>$1</em>"),e=e.replace(/```(\w*)\n([\s\S]*?)```/g,"<pre><code>$2</code></pre>"),e=e.replace(/`([^`]+)`/g,"<code>$1</code>"),e=e.replace(/\[([^\]]+)\]\(([^)]+)\)/g,'<a href="$2">$1</a>'),e=e.replace(/!\[([^\]]*)\]\(([^)]+)\)/g,'<img src="$2" alt="$1">'),e=e.replace(/^- (.+)$/gm,"<li>$1</li>"),e=e.replace(/(<li>.*<\/li>\n?)+/g,"<ul>$&</ul>"),e=e.replace(/^\d+\. (.+)$/gm,"<li>$1</li>"),e=e.split(`
683
+ `).map(i=>{let a=i.trim();return a?a.startsWith("<")?i:`<p>${a}</p>`:""}).join(`
684
+ `),e=e.replace(/<p><\/p>/g,""),e}function mt(){return dt__namespace.randomBytes(32).toString("hex")}function pt(o,e){return o===e}function vo(o){try{let e=o.startsWith("http")?o:`http://localhost${o}`,t=new url.URL(e).searchParams;return {key:t.get("key")??void 0,state:t.get("state")??void 0,error:t.get("error")??void 0,message:t.get("message")??void 0}}catch{return {}}}function xo(){return `<!DOCTYPE html>
283
685
  <html lang="en">
284
686
  <head>
285
687
  <meta charset="UTF-8">
@@ -325,7 +727,7 @@ Blog Details:`),console.log("-------------"),console.log(` ID: ${i.blog_id}`),c
325
727
  <p>You can close this window and return to your terminal.</p>
326
728
  </div>
327
729
  </body>
328
- </html>`}function X(o){return `<!DOCTYPE html>
730
+ </html>`}function ge(o){return `<!DOCTYPE html>
329
731
  <html lang="en">
330
732
  <head>
331
733
  <meta charset="UTF-8">
@@ -380,7 +782,7 @@ Blog Details:`),console.log("-------------"),console.log(` ID: ${i.blog_id}`),c
380
782
  <div class="error-message">${o.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}</div>
381
783
  </div>
382
784
  </body>
383
- </html>`}function Wt(){return `<!DOCTYPE html>
785
+ </html>`}function ko(){return `<!DOCTYPE html>
384
786
  <html lang="en">
385
787
  <head>
386
788
  <meta charset="UTF-8">
@@ -418,13 +820,13 @@ Blog Details:`),console.log("-------------"),console.log(` ID: ${i.blog_id}`),c
418
820
  <p>This endpoint is not available.</p>
419
821
  </div>
420
822
  </body>
421
- </html>`}function Ue(){let o=null,t=null;function n(e,i){let a=e.url||"/",l=e.method||"GET",m=a==="/callback"||a.startsWith("/callback?");if(l!=="GET"||!m){i.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),i.end(Wt());return}let p=Ut(a);if(!t){i.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),i.end(X("No pending authorization request"));return}let{expectedState:b,resolve:g,timeoutId:v}=t;if(clearTimeout(v),t=null,p.error){let u=p.message||p.error;i.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),i.end(X(u)),g({success:false,error:u});return}if(!p.state||!je(p.state,b)){let u="State token mismatch - possible CSRF attack";i.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),i.end(X(u)),g({success:false,error:u});return}if(!p.key){let u="No API key received";i.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),i.end(X(u)),g({success:false,error:u});return}i.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),i.end(Kt()),g({success:true,apiKey:p.key});}return {async start(){return new Promise((e,i)=>{o=Ee__namespace.createServer(n),o.on("error",a=>{i(new Error(`Failed to start callback server: ${a.message}`));}),o.listen(0,"127.0.0.1",()=>{let a=o.address();if(!a||typeof a=="string"){i(new Error("Failed to get server address"));return}let l=a.port,m=`http://127.0.0.1:${l}/callback`;e({port:l,url:m});});})},waitForCallback(e,i){return new Promise(a=>{let l=setTimeout(()=>{t&&(t=null,a({success:false,error:"Login timed out waiting for authorization"}));},i);t={expectedState:e,resolve:a,timeoutId:l};})},async stop(){return new Promise(e=>{t&&(clearTimeout(t.timeoutId),t=null),o?o.close(()=>{o=null,e();}):e();})}}}var Mt="https://app.lindo.ai",Bt=120;function Ht(o,t){let n=`http://127.0.0.1:${t}/callback`,e=new URLSearchParams({state:o,callback_url:n});return `${Mt}/cli/authorize?${e.toString()}`}function ve(){return new commander.Command("login").description("Authenticate via browser to configure your API key").option("-t, --timeout <seconds>","Timeout in seconds for the login flow",String(Bt)).option("--no-browser","Display the authorization URL without opening the browser").action(async t=>{let n=parseInt(t.timeout,10),e=n*1e3,i=t.browser,a=Ue(),l=false;try{s("Starting authentication flow...");let{port:m}=await a.start();l=!0;let p=Re(),b=Ht(p,m);i?(s("Opening browser for authorization..."),await L(b)||(s("Could not open browser automatically."),console.log(`
823
+ </html>`}function gt(){let o=null,e=null;function n(t,i){let a=t.url||"/",l=t.method||"GET",c=a==="/callback"||a.startsWith("/callback?");if(l!=="GET"||!c){i.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),i.end(ko());return}let u=vo(a);if(!e){i.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),i.end(ge("No pending authorization request"));return}let{expectedState:b,resolve:v,timeoutId:x}=e;if(clearTimeout(x),e=null,u.error){let g=u.message||u.error;i.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),i.end(ge(g)),v({success:false,error:g});return}if(!u.state||!pt(u.state,b)){let g="State token mismatch - possible CSRF attack";i.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),i.end(ge(g)),v({success:false,error:g});return}if(!u.key){let g="No API key received";i.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),i.end(ge(g)),v({success:false,error:g});return}i.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),i.end(xo()),v({success:true,apiKey:u.key});}return {async start(){return new Promise((t,i)=>{o=tt__namespace.createServer(n),o.on("error",a=>{i(new Error(`Failed to start callback server: ${a.message}`));}),o.listen(0,"127.0.0.1",()=>{let a=o.address();if(!a||typeof a=="string"){i(new Error("Failed to get server address"));return}let l=a.port,c=`http://127.0.0.1:${l}/callback`;t({port:l,url:c});});})},waitForCallback(t,i){return new Promise(a=>{let l=setTimeout(()=>{e&&(e=null,a({success:false,error:"Login timed out waiting for authorization"}));},i);e={expectedState:t,resolve:a,timeoutId:l};})},async stop(){return new Promise(t=>{e&&(clearTimeout(e.timeoutId),e=null),o?o.close(()=>{o=null,t();}):t();})}}}var _o="https://app.lindo.ai",So=120;function Oo(o,e){let n=`http://127.0.0.1:${e}/callback`,t=new URLSearchParams({state:o,callback_url:n});return `${_o}/cli/authorize?${t.toString()}`}function Ue(){return new commander.Command("login").description("Authenticate via browser to configure your API key").option("-t, --timeout <seconds>","Timeout in seconds for the login flow",String(So)).option("--no-browser","Display the authorization URL without opening the browser").action(async e=>{let n=parseInt(e.timeout,10),t=n*1e3,i=e.browser,a=gt(),l=false;try{r("Starting authentication flow...");let{port:c}=await a.start();l=!0;let u=mt(),b=Oo(u,c);i?(r("Opening browser for authorization..."),await B(b)||(r("Could not open browser automatically."),console.log(`
422
824
  Please open this URL in your browser:`),console.log(`
423
825
  ${b}
424
826
  `))):(console.log(`
425
827
  Please open this URL in your browser:`),console.log(`
426
828
  ${b}
427
- `)),s(`Waiting for authorization (timeout: ${n}s)...`);let g=await a.waitForCallback(p,e);g.success&&g.apiKey?(Pe(g.apiKey),d("Successfully authenticated!"),s(`API key saved to: ${T()}`)):(r(g.error||"Authentication failed"),process.exit(1));}catch(m){r(m instanceof Error?m.message:"An unexpected error occurred"),process.exit(1);}finally{l&&await a.stop();}})}var Ce=j__namespace.join(de__namespace.homedir(),".config","opencode","skills","lindoai"),qe=j__namespace.join(Ce,"SKILL.md"),Jt=`---
829
+ `)),r(`Waiting for authorization (timeout: ${n}s)...`);let v=await a.waitForCallback(u,t);v.success&&v.apiKey?(ze(v.apiKey),m("Successfully authenticated!"),r(`API key saved to: ${N()}`)):(s(v.error||"Authentication failed"),process.exit(1));}catch(c){s(c instanceof Error?c.message:"An unexpected error occurred"),process.exit(1);}finally{l&&await a.stop();}})}var Me=M__namespace.join($e__namespace.homedir(),".config","opencode","skills","lindoai"),bt=M__namespace.join(Me,"SKILL.md"),$o=`---
428
830
  name: lindoai
429
831
  description: Lindo AI CLI - Command-line interface for the Lindo API
430
832
  ---
@@ -498,6 +900,16 @@ lindoai pages update <website_id> <page_id> --html-file ./page.html
498
900
  lindoai pages stop-preview
499
901
  \`\`\`
500
902
 
903
+ ### Important: Global Header/Footer Limitation
904
+
905
+ **Global header and footer sections cannot be updated via the CLI.** When you edit a page locally:
906
+ - The preview shows the website's global header/footer for visual context
907
+ - Any changes you make to global sections are saved with the page only
908
+ - Changes do NOT propagate to other pages or the website settings
909
+ - To update global header/footer across all pages, use the Lindo webapp
910
+
911
+ This is by design - global sections are website-wide settings managed through the webapp.
912
+
501
913
  ## Blog Management
502
914
 
503
915
  ### List Blogs
@@ -592,5 +1004,188 @@ lindoai config set baseUrl <value>
592
1004
  3. **Run preview servers in background mode** (\`--background\`) to keep the terminal available.
593
1005
  4. **Remember to stop preview servers** when done editing with \`stop-preview\`.
594
1006
  5. **Use JSON format** (\`--format json\`) when you need to parse command output programmatically.
595
- `;function Vt(){try{let o=process.platform==="win32"?"where opencode":"which opencode";return child_process.execSync(o,{stdio:"ignore"}),!0}catch{return false}}function zt(){try{return s("Installing OpenCode..."),child_process.execSync("npm install -g opencode-ai@latest",{stdio:"inherit"}),!0}catch{return false}}function Qt(){w__namespace.existsSync(Ce)||w__namespace.mkdirSync(Ce,{recursive:true}),w__namespace.writeFileSync(qe,Jt,"utf-8");}function xe(){return new commander.Command("agent").description("Launch an AI agent that understands all CLI commands").option("--install","Install OpenCode if not already installed").option("--model <model>","Specify the model to use with OpenCode").action(async t=>{Vt()||(t.install?(zt()||(r("Failed to install OpenCode"),s("Please install manually: npm install -g opencode-ai@latest"),process.exit(1)),d("OpenCode installed successfully")):(r("OpenCode is not installed"),s(""),s("To install OpenCode, run one of the following:"),s(" lindoai agent --install"),s(" npm install -g opencode-ai@latest"),process.exit(1)));try{Qt(),s(`Skill file installed to: ${qe}`);}catch(i){r(`Failed to install skill file: ${i instanceof Error?i.message:"Unknown error"}`),process.exit(1);}let n=[];t.model&&n.push("--model",t.model),s("Launching OpenCode...");let e=child_process.spawn("opencode",n,{stdio:"inherit",shell:true});e.on("error",i=>{r(`Failed to launch OpenCode: ${i.message}`),process.exit(1);}),e.on("close",i=>{process.exit(i??0);});})}var eo="1.0.0";function to(){let o=new commander.Command;return o.name("lindo").description("Command-line interface for the Lindo API").version(eo,"-v, --version","Output the current version").helpOption("-h, --help","Display help for command"),o.addCommand(ne()),o.addCommand(ie()),o.addCommand(re()),o.addCommand(se()),o.addCommand(ae()),o.addCommand(ce()),o.addCommand(le()),o.addCommand(he()),o.addCommand(ye()),o.addCommand(ve()),o.addCommand(xe()),o.exitOverride(t=>{throw t.code==="commander.help"&&process.exit(0),t.code==="commander.version"&&process.exit(0),t.code==="commander.missingArgument"&&(r(t.message),process.exit(1)),t.code==="commander.unknownCommand"&&(r(t.message),s('Run "lindo --help" for available commands'),process.exit(1)),t}),o}function oo(o){r("Authentication failed"),s(""),s("Your API key may be invalid or expired."),s(""),s("To configure your API key:"),s(" 1. Run: lindo config set apiKey <your-api-key>"),s(" 2. Or set the LINDO_API_KEY environment variable"),s(""),s("To get an API key:"),s(" Visit https://app.lindo.ai/settings/api-keys");}async function no(){let o=to();try{await o.parseAsync(process.argv);}catch(t){throw t instanceof lindoai.AuthenticationError&&(oo(),process.exit(1)),t}}no().catch(o=>{o instanceof Error?r(`Unexpected error: ${o.message}`):r("An unexpected error occurred"),process.exit(1);});
596
- exports.createProgram=to;
1007
+
1008
+ ## Page Building Guidelines
1009
+
1010
+ ### Structure Requirements
1011
+
1012
+ When building or editing Lindo pages, follow these structure requirements:
1013
+
1014
+ - **Output ONLY content HTML**: Generate only \`<header>\`, \`<section>\` elements, and \`<footer>\`
1015
+ - **NO document wrapper tags**: Do NOT include \`<!DOCTYPE html>\`, \`<html>\`, \`<head>\`, or \`<body>\` tags
1016
+ - **Unique section IDs**: Each section must have a unique id following the pattern: \`_block_name_###\` (e.g., \`_hero_001\`, \`_features_002\`)
1017
+ - **Semantic structure**: Use proper HTML5 semantic elements for accessibility
1018
+
1019
+ Example structure:
1020
+ \`\`\`html
1021
+ <header id="_header_001" class="...">
1022
+ <!-- Navigation content -->
1023
+ </header>
1024
+
1025
+ <section id="_hero_001" class="...">
1026
+ <!-- Hero content -->
1027
+ </section>
1028
+
1029
+ <section id="_features_002" class="...">
1030
+ <!-- Features content -->
1031
+ </section>
1032
+
1033
+ <footer id="_footer_001" class="...">
1034
+ <!-- Footer content -->
1035
+ </footer>
1036
+ \`\`\`
1037
+
1038
+ ### Tailwind CSS v3.4 Usage
1039
+
1040
+ Lindo pages use Tailwind CSS v3.4 for styling:
1041
+
1042
+ - **Utility-first approach**: Use Tailwind utility classes for all styling
1043
+ - **No custom CSS**: Avoid writing custom CSS; use Tailwind utilities instead
1044
+ - **NO font family classes**: Do NOT use \`font-sans\`, \`font-serif\`, \`font-mono\`, or any \`font-[family]\` classes - fonts are managed by the theme system
1045
+ - **Responsive design**: Use responsive prefixes (\`sm:\`, \`md:\`, \`lg:\`, \`xl:\`, \`2xl:\`) for all breakpoints
1046
+ - **Dark mode support**: Always include dark mode variants using the \`dark:\` prefix
1047
+ - **Neutral shades**: Use neutral color shades for text and surfaces (e.g., \`text-neutral-900 dark:text-neutral-100\`)
1048
+
1049
+ Example:
1050
+ \`\`\`html
1051
+ <div class="px-4 py-8 md:px-8 lg:px-16 bg-white dark:bg-neutral-900">
1052
+ <h1 class="text-3xl md:text-4xl lg:text-5xl text-neutral-900 dark:text-white">
1053
+ Welcome
1054
+ </h1>
1055
+ </div>
1056
+ \`\`\`
1057
+
1058
+ ### Animation System
1059
+
1060
+ Lindo uses a custom animation system with \`data-motion\` attributes for scroll-triggered animations:
1061
+
1062
+ **Available animation types:**
1063
+ - \`fade\` - Simple fade in
1064
+ - \`fade-up\` - Fade in while moving up
1065
+ - \`fade-down\` - Fade in while moving down
1066
+ - \`fade-left\` - Fade in while moving from left
1067
+ - \`fade-right\` - Fade in while moving from right
1068
+ - \`scale\` - Scale up while fading in
1069
+ - \`card\` - Card entrance animation
1070
+ - \`heading\` - Heading text animation
1071
+ - \`text\` - Body text animation
1072
+ - \`image\` - Image reveal animation
1073
+ - \`button\` - Button entrance animation
1074
+
1075
+ **Usage:**
1076
+ \`\`\`html
1077
+ <section data-motion="fade-up">
1078
+ <h2 data-motion="heading">Section Title</h2>
1079
+ <p data-motion="text">Section description text.</p>
1080
+ <img data-motion="image" src="..." alt="..." />
1081
+ <button data-motion="button">Click Me</button>
1082
+ </section>
1083
+ \`\`\`
1084
+
1085
+ **Animation delays:** Use \`data-motion-delay\` for staggered animations:
1086
+ \`\`\`html
1087
+ <div data-motion="fade-up" data-motion-delay="0">First item</div>
1088
+ <div data-motion="fade-up" data-motion-delay="100">Second item</div>
1089
+ <div data-motion="fade-up" data-motion-delay="200">Third item</div>
1090
+ \`\`\`
1091
+
1092
+ ### Logo Requirements
1093
+
1094
+ When adding logos to pages, use the \`lindo-image-logo\` attribute:
1095
+
1096
+ **Logo types:**
1097
+ - \`full\` - Full logo (icon + text)
1098
+ - \`icon\` - Icon only
1099
+ - \`text\` - Text only
1100
+
1101
+ **Usage:**
1102
+ \`\`\`html
1103
+ <!-- Full logo -->
1104
+ <img lindo-image-logo="full" src="https://cdn.ln-cdn.com/image/placeholder-logo-full.png" alt="Logo" class="h-8" />
1105
+
1106
+ <!-- Icon only -->
1107
+ <img lindo-image-logo="icon" src="https://cdn.ln-cdn.com/image/placeholder-logo-icon.png" alt="Logo" class="h-8 w-8" />
1108
+
1109
+ <!-- Text only -->
1110
+ <img lindo-image-logo="text" src="https://cdn.ln-cdn.com/image/placeholder-logo-text.png" alt="Logo" class="h-6" />
1111
+ \`\`\`
1112
+
1113
+ **Important:**
1114
+ - Do NOT add text or brand names as logo alternatives
1115
+ - Always use the \`lindo-image-logo\` attribute for logos
1116
+ - The actual logo will be replaced with the website's configured logo
1117
+
1118
+ ### Theme Guidelines
1119
+
1120
+ Follow these theme guidelines for consistent light and dark mode support:
1121
+
1122
+ **Light and Dark Mode:**
1123
+ - Every element must specify both light and dark styles
1124
+ - Use the \`dark:\` prefix for dark mode variants
1125
+ - Test both modes to ensure readability and contrast
1126
+
1127
+ **Color Palette:**
1128
+ - Use Tailwind's default color palette
1129
+ - Primary colors: Use brand colors from the theme
1130
+ - Text colors: \`text-neutral-900 dark:text-white\` for headings, \`text-neutral-600 dark:text-neutral-400\` for body text
1131
+ - Background colors: \`bg-white dark:bg-neutral-900\` for main backgrounds
1132
+ - Surface colors: \`bg-neutral-50 dark:bg-neutral-800\` for cards and elevated surfaces
1133
+
1134
+ **Gradients:**
1135
+ - Apply gradient backgrounds where appropriate for visual interest
1136
+ - Example: \`bg-gradient-to-br from-blue-500 to-purple-600\`
1137
+
1138
+ **Example with full theme support:**
1139
+ \`\`\`html
1140
+ <section class="py-16 bg-white dark:bg-neutral-900">
1141
+ <div class="container mx-auto px-4">
1142
+ <h2 class="text-3xl text-neutral-900 dark:text-white mb-4">
1143
+ Section Title
1144
+ </h2>
1145
+ <p class="text-neutral-600 dark:text-neutral-400 mb-8">
1146
+ Section description with proper contrast in both modes.
1147
+ </p>
1148
+ <div class="bg-neutral-50 dark:bg-neutral-800 rounded-lg p-6">
1149
+ <p class="text-neutral-700 dark:text-neutral-300">
1150
+ Card content with elevated surface.
1151
+ </p>
1152
+ </div>
1153
+ </div>
1154
+ </section>
1155
+ \`\`\`
1156
+
1157
+ ### Core Rules
1158
+
1159
+ Follow these core rules when building pages:
1160
+
1161
+ 1. **No font family classes**: Never use \`font-sans\`, \`font-serif\`, \`font-mono\`, or custom font classes. The theme system manages fonts.
1162
+
1163
+ 2. **Responsive design is required**: All pages must be fully responsive. Use Tailwind's responsive prefixes:
1164
+ - Mobile first: Start with base styles
1165
+ - \`sm:\` - Small screens (640px+)
1166
+ - \`md:\` - Medium screens (768px+)
1167
+ - \`lg:\` - Large screens (1024px+)
1168
+ - \`xl:\` - Extra large screens (1280px+)
1169
+ - \`2xl:\` - 2X large screens (1536px+)
1170
+
1171
+ 3. **Accessibility considerations**:
1172
+ - Use semantic HTML elements (\`<header>\`, \`<nav>\`, \`<main>\`, \`<section>\`, \`<footer>\`)
1173
+ - Include \`alt\` attributes on all images
1174
+ - Ensure sufficient color contrast (WCAG AA minimum)
1175
+ - Use proper heading hierarchy (h1 \u2192 h2 \u2192 h3)
1176
+ - Add \`aria-label\` attributes to interactive elements without visible text
1177
+
1178
+ 4. **Image handling**:
1179
+ - Use responsive images with appropriate sizes
1180
+ - Include descriptive \`alt\` text
1181
+ - Use lazy loading for below-the-fold images: \`loading="lazy"\`
1182
+
1183
+ 5. **Link handling**:
1184
+ - Use descriptive link text (avoid "click here")
1185
+ - External links should have \`target="_blank"\` and \`rel="noopener noreferrer"\`
1186
+
1187
+ 6. **Container patterns**:
1188
+ - Use \`container mx-auto px-4\` for consistent content width
1189
+ - Apply consistent vertical padding: \`py-12 md:py-16 lg:py-20\`
1190
+ `;function To(){try{let o=process.platform==="win32"?"where opencode":"which opencode";return child_process.execSync(o,{stdio:"ignore"}),!0}catch{return false}}function Po(){try{return r("Installing OpenCode..."),child_process.execSync("npm install -g opencode-ai@latest",{stdio:"inherit"}),!0}catch{return false}}function Ao(){k__namespace.existsSync(Me)||k__namespace.mkdirSync(Me,{recursive:true}),k__namespace.writeFileSync(bt,$o,"utf-8");}function We(){return new commander.Command("agent").description("Launch an AI agent that understands all CLI commands").option("--install","Install OpenCode if not already installed").option("--model <model>","Specify the model to use with OpenCode").action(async e=>{To()||(e.install?(Po()||(s("Failed to install OpenCode"),r("Please install manually: npm install -g opencode-ai@latest"),process.exit(1)),m("OpenCode installed successfully")):(s("OpenCode is not installed"),r(""),r("To install OpenCode, run one of the following:"),r(" lindoai agent --install"),r(" npm install -g opencode-ai@latest"),process.exit(1)));try{Ao(),r(`Skill file installed to: ${bt}`);}catch(i){s(`Failed to install skill file: ${i instanceof Error?i.message:"Unknown error"}`),process.exit(1);}let n=[];e.model&&n.push("--model",e.model),r("Launching OpenCode...");let t=child_process.spawn("opencode",n,{stdio:"inherit",shell:true});t.on("error",i=>{s(`Failed to launch OpenCode: ${i.message}`),process.exit(1);}),t.on("close",i=>{process.exit(i??0);});})}var Ro="1.0.0";function Do(){let o=new commander.Command;return o.name("lindo").description("Command-line interface for the Lindo API").version(Ro,"-v, --version","Output the current version").helpOption("-h, --help","Display help for command"),o.addCommand(ve()),o.addCommand(xe()),o.addCommand(ke()),o.addCommand(Ce()),o.addCommand(_e()),o.addCommand(Se()),o.addCommand(Oe()),o.addCommand(Re()),o.addCommand(Ne()),o.addCommand(Ue()),o.addCommand(We()),o.exitOverride(e=>{throw e.code==="commander.help"&&process.exit(0),e.code==="commander.version"&&process.exit(0),e.code==="commander.missingArgument"&&(s(e.message),process.exit(1)),e.code==="commander.unknownCommand"&&(s(e.message),r('Run "lindo --help" for available commands'),process.exit(1)),e}),o}function jo(o){s("Authentication failed"),r(""),r("Your API key may be invalid or expired."),r(""),r("To configure your API key:"),r(" 1. Run: lindo config set apiKey <your-api-key>"),r(" 2. Or set the LINDO_API_KEY environment variable"),r(""),r("To get an API key:"),r(" Visit https://app.lindo.ai/settings/api-keys");}async function No(){let o=Do();try{await o.parseAsync(process.argv);}catch(e){throw e instanceof lindoai.AuthenticationError&&(jo(),process.exit(1)),e}}No().catch(o=>{o instanceof Error?s(`Unexpected error: ${o.message}`):s("An unexpected error occurred"),process.exit(1);});
1191
+ exports.createProgram=Do;