emailr-cli 1.7.2 → 1.7.3

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 (2) hide show
  1. package/dist/index.js +12 -12
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7,8 +7,8 @@ Set the EMAILR_API_KEY environment variable:
7
7
  Or create a config file at ~/.emailrrc:
8
8
  { "apiKey": "your-api-key" }
9
9
 
10
- Or run: emailr config set api-key <your-api-key>`)}function I(){let i=_.join(B.homedir(),".config","emailr");return _.join(i,"config.json")}function G(i){let t=I(),e=_.dirname(t);v.existsSync(e)||v.mkdirSync(e,{recursive:true});let o={};if(v.existsSync(t))try{o=JSON.parse(v.readFileSync(t,"utf-8"));}catch{}let r={...o,...i};v.writeFileSync(t,JSON.stringify(r,null,2)+`
11
- `);}function ne(i){try{return m()[i]?.toString()}catch{return}}function c(i,t="table"){t==="json"?console.log(JSON.stringify(i,null,2)):Me(i);}function Me(i){Array.isArray(i)?Le(i):typeof i=="object"&&i!==null?De(i):console.log(i);}function Le(i){if(i.length===0){console.log(S.gray("No results"));return}let t=i[0];if(typeof t!="object"||t===null){i.forEach(r=>console.log(r));return}let e=Object.keys(t),o=new re({head:e.map(r=>S.cyan(r)),style:{head:[],border:[]}});for(let r of i){let a=e.map(n=>{let s=r[n];return se(s)});o.push(a);}console.log(o.toString());}function De(i){let t=new re({style:{head:[],border:[]}});for(let[e,o]of Object.entries(i))t.push([S.cyan(e),se(o)]);console.log(t.toString());}function se(i){return i==null?S.gray("-"):typeof i=="boolean"?i?S.green("\u2713"):S.red("\u2717"):typeof i=="object"?JSON.stringify(i):String(i)}function d(i){console.log(S.green("\u2713"),i);}function l(i){console.error(S.red("\u2717"),i);}function k(i){console.warn(S.yellow("\u26A0"),i);}function u(i){console.log(S.blue("\u2139"),i);}function ce(){return new Command("send").description(`Send an email
10
+ Or run: emailr config set api-key <your-api-key>`)}function j(){let i=_.join(B.homedir(),".config","emailr");return _.join(i,"config.json")}function G(i){let t=j(),e=_.dirname(t);v.existsSync(e)||v.mkdirSync(e,{recursive:true});let o={};if(v.existsSync(t))try{o=JSON.parse(v.readFileSync(t,"utf-8"));}catch{}let r={...o,...i};v.writeFileSync(t,JSON.stringify(r,null,2)+`
11
+ `);}function ne(i){try{return m()[i]?.toString()}catch{return}}function c(i,t="table"){t==="json"?console.log(JSON.stringify(i,null,2)):Me(i);}function Me(i){Array.isArray(i)?Le(i):typeof i=="object"&&i!==null?De(i):console.log(i);}function Le(i){if(i.length===0){console.log(S.gray("No results"));return}let t=i[0];if(typeof t!="object"||t===null){i.forEach(r=>console.log(r));return}let e=Object.keys(t),o=new re({head:e.map(r=>S.cyan(r)),style:{head:[],border:[]}});for(let r of i){let a=e.map(n=>{let s=r[n];return se(s)});o.push(a);}console.log(o.toString());}function De(i){let t=new re({style:{head:[],border:[]}});for(let[e,o]of Object.entries(i))t.push([S.cyan(e),se(o)]);console.log(t.toString());}function se(i){return i==null?S.gray("-"):typeof i=="boolean"?i?S.green("\u2713"):S.red("\u2717"):typeof i=="object"?JSON.stringify(i):String(i)}function d(i){console.log(S.green("\u2713"),i);}function l(i){console.error(S.red("\u2717"),i);}function I(i){console.warn(S.yellow("\u26A0"),i);}function u(i){console.log(S.blue("\u2139"),i);}function ce(){return new Command("send").description(`Send an email
12
12
 
13
13
  USAGE
14
14
  emailr send --to <email_address> [options]
@@ -566,7 +566,7 @@ WARNING
566
566
 
567
567
  `);}catch{}});}async function Y(i,t){let e=_.resolve(i);return new Promise((o,r)=>{P=Je.createServer((a,n)=>{if(a.url==="/__live-reload"){n.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":"*"}),n.write(`data: connected
568
568
 
569
- `),R.push(n),a.on("close",()=>{R=R.filter(s=>s!==n);});return}if(a.method==="GET"){try{let s=v.readFileSync(e,"utf-8"),p=Ye(s);n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end(p);}catch(s){n.writeHead(500,{"Content-Type":"text/plain"}),n.end(`Error reading file: ${s instanceof Error?s.message:String(s)}`);}return}n.writeHead(405,{"Content-Type":"text/plain"}),n.end("Method Not Allowed");}),P.listen(0,"127.0.0.1",()=>{let a=P.address();if(a&&typeof a=="object"){z=a.port;let n=null;J=v.watch(e,s=>{s==="change"&&(n&&clearTimeout(n),n=setTimeout(()=>{Ze(),t?.();},100));}),o(z);}else r(new Error("Failed to get server address"));}),P.on("error",a=>{r(new Error(`Failed to start server: ${a.message}`));});})}async function Z(){if(J&&(J.close(),J=null),R.forEach(i=>{try{i.end();}catch{}}),R=[],P)return new Promise(i=>{P.close(()=>{P=null,z=null,i();});})}async function Te(i){try{let t=i.html_content??"";X(i.id,t);}catch(t){return k(`Could not save template for preview: ${t instanceof Error?t.message:String(t)}`),null}try{let t=await V(i.id);return t===null?(k("Could not start preview server"),null):t}catch(t){return k(`Could not generate preview URL: ${t instanceof Error?t.message:String(t)}`),null}}function Oe(){let i=new Command("templates").description(`Manage email templates
569
+ `),R.push(n),a.on("close",()=>{R=R.filter(s=>s!==n);});return}if(a.method==="GET"){try{let s=v.readFileSync(e,"utf-8"),p=Ye(s);n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end(p);}catch(s){n.writeHead(500,{"Content-Type":"text/plain"}),n.end(`Error reading file: ${s instanceof Error?s.message:String(s)}`);}return}n.writeHead(405,{"Content-Type":"text/plain"}),n.end("Method Not Allowed");}),P.listen(0,"127.0.0.1",()=>{let a=P.address();if(a&&typeof a=="object"){z=a.port;let n=null;J=v.watch(e,s=>{s==="change"&&(n&&clearTimeout(n),n=setTimeout(()=>{Ze(),t?.();},100));}),o(z);}else r(new Error("Failed to get server address"));}),P.on("error",a=>{r(new Error(`Failed to start server: ${a.message}`));});})}async function Z(){if(J&&(J.close(),J=null),R.forEach(i=>{try{i.end();}catch{}}),R=[],P)return new Promise(i=>{P.close(()=>{P=null,z=null,i();});})}async function Te(i){try{let t=i.html_content??"";X(i.id,t);}catch(t){return I(`Could not save template for preview: ${t instanceof Error?t.message:String(t)}`),null}try{let t=await V(i.id);return t===null?(I("Could not start preview server"),null):t}catch(t){return I(`Could not generate preview URL: ${t instanceof Error?t.message:String(t)}`),null}}function Oe(){let i=new Command("templates").description(`Manage email templates
570
570
 
571
571
  USAGE
572
572
  emailr templates <subcommand> [options]
@@ -1578,7 +1578,7 @@ EXAMPLES
1578
1578
 
1579
1579
  NOTE
1580
1580
  Environment variables (EMAILR_API_KEY, EMAILR_BASE_URL) take precedence
1581
- over config file values at runtime.`).action(async(t,e)=>{try{let o=["api-key","base-url","format"],r=t.toLowerCase();o.includes(r)||(l(`Invalid config key: ${t}`),u(`Valid keys: ${o.join(", ")}`),process.exit(1));let n={"api-key":"apiKey","base-url":"baseUrl",format:"format"}[r];r==="format"&&!["json","table"].includes(e)&&(l(`Invalid format value: ${e}`),u("Valid formats: json, table"),process.exit(1)),G({[n]:e}),d(`Configuration saved: ${t} = ${r==="api-key"?"***":e}`),u(`Config file: ${I()}`);}catch(o){l(o instanceof Error?o.message:"Failed to save configuration"),process.exit(1);}}),i.command("get <key>").description(`Get a configuration value
1581
+ over config file values at runtime.`).action(async(t,e)=>{try{let o=["api-key","base-url","format"],r=t.toLowerCase();o.includes(r)||(l(`Invalid config key: ${t}`),u(`Valid keys: ${o.join(", ")}`),process.exit(1));let n={"api-key":"apiKey","base-url":"baseUrl",format:"format"}[r];r==="format"&&!["json","table"].includes(e)&&(l(`Invalid format value: ${e}`),u("Valid formats: json, table"),process.exit(1)),G({[n]:e}),d(`Configuration saved: ${t} = ${r==="api-key"?"***":e}`),u(`Config file: ${j()}`);}catch(o){l(o instanceof Error?o.message:"Failed to save configuration"),process.exit(1);}}),i.command("get <key>").description(`Get a configuration value
1582
1582
 
1583
1583
  USAGE
1584
1584
  emailr config get <key>
@@ -1634,7 +1634,7 @@ EXAMPLES
1634
1634
 
1635
1635
  SEE ALSO
1636
1636
  emailr config get Get a single configuration value
1637
- emailr config path Show config file location`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),o={"api-key":e.apiKey?e.apiKey.substring(0,8)+"..."+e.apiKey.substring(e.apiKey.length-4):"(not set)","base-url":e.baseUrl||"(default)",format:e.format||"table"};if(t.format==="json")c(o,"json");else {let r=Object.entries(o).map(([a,n])=>({Key:a,Value:n}));c(r,"table");}console.log(""),u(`Config file: ${I()}`);}catch(e){e instanceof Error&&e.message.includes("No API key configured")?(u("No configuration found."),u("Run 'emailr config set api-key <your-api-key>' to get started.")):(l(e instanceof Error?e.message:"Failed to list configuration"),process.exit(1));}}),i.command("path").description(`Show the configuration file path
1637
+ emailr config path Show config file location`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),o={"api-key":e.apiKey?e.apiKey.substring(0,8)+"..."+e.apiKey.substring(e.apiKey.length-4):"(not set)","base-url":e.baseUrl||"(default)",format:e.format||"table"};if(t.format==="json")c(o,"json");else {let r=Object.entries(o).map(([a,n])=>({Key:a,Value:n}));c(r,"table");}console.log(""),u(`Config file: ${j()}`);}catch(e){e instanceof Error&&e.message.includes("No API key configured")?(u("No configuration found."),u("Run 'emailr config set api-key <your-api-key>' to get started.")):(l(e instanceof Error?e.message:"Failed to list configuration"),process.exit(1));}}),i.command("path").description(`Show the configuration file path
1638
1638
 
1639
1639
  USAGE
1640
1640
  emailr config path
@@ -1661,7 +1661,7 @@ EXAMPLES
1661
1661
  open $(emailr config path)
1662
1662
 
1663
1663
  # View config file contents
1664
- cat $(emailr config path)`).action(()=>{console.log(I());}),i.command("init").description(`Initialize configuration interactively
1664
+ cat $(emailr config path)`).action(()=>{console.log(j());}),i.command("init").description(`Initialize configuration interactively
1665
1665
 
1666
1666
  USAGE
1667
1667
  emailr config init [options]
@@ -1694,7 +1694,7 @@ ALTERNATIVE: ENVIRONMENT VARIABLES
1694
1694
 
1695
1695
  SEE ALSO
1696
1696
  emailr config set Set individual configuration values
1697
- emailr config list View current configuration`).option("--api-key <key>","API key to use").option("--base-url <url>","Base URL for API").action(async t=>{try{t.apiKey?(G({apiKey:t.apiKey,baseUrl:t.baseUrl}),d("Configuration initialized!"),u(`Config file: ${I()}`)):(u("Initialize your Emailr CLI configuration:"),console.log(""),u("Run with --api-key flag:"),console.log(" emailr config init --api-key <your-api-key>"),console.log(""),u("Or set environment variable:"),console.log(" export EMAILR_API_KEY=<your-api-key>"));}catch(e){l(e instanceof Error?e.message:"Failed to initialize configuration"),process.exit(1);}}),i}function je(){let i=new Command("broadcasts").description(`Manage broadcast campaigns
1697
+ emailr config list View current configuration`).option("--api-key <key>","API key to use").option("--base-url <url>","Base URL for API").action(async t=>{try{t.apiKey?(G({apiKey:t.apiKey,baseUrl:t.baseUrl}),d("Configuration initialized!"),u(`Config file: ${j()}`)):(u("Initialize your Emailr CLI configuration:"),console.log(""),u("Run with --api-key flag:"),console.log(" emailr config init --api-key <your-api-key>"),console.log(""),u("Or set environment variable:"),console.log(" export EMAILR_API_KEY=<your-api-key>"));}catch(e){l(e instanceof Error?e.message:"Failed to initialize configuration"),process.exit(1);}}),i}function Ne(){let i=new Command("broadcasts").description(`Manage broadcast campaigns
1698
1698
 
1699
1699
  USAGE
1700
1700
  emailr broadcasts <subcommand> [options]
@@ -1954,7 +1954,7 @@ EXAMPLES
1954
1954
 
1955
1955
  SEE ALSO
1956
1956
  emailr templates Create and manage email templates
1957
- emailr segments Create and manage contact segments`).requiredOption("--name <name>","Broadcast name").requiredOption("--subject <subject>","Email subject").requiredOption("--from <email>","Sender email address").option("--template <id>","Template ID to use").option("--segment <id>","Segment ID to target").option("--html <html>","HTML content").option("--text <text>","Plain text content").option("--schedule <datetime>","Schedule time (ISO 8601)").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r={name:t.name,subject:t.subject,from_email:t.from,template_id:t.template,segment_id:t.segment,html_content:t.html,text_content:t.text,scheduled_at:t.schedule};t.tags&&(r.tags=t.tags.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean));let a=await o.broadcasts.create(r);t.format==="json"?c(a,"json"):(d("Broadcast created successfully!"),c({ID:a.id,Name:a.name,Status:a.status,Tags:a.tags?.join(", ")||"-","Scheduled At":a.scheduled_at||"Not scheduled"},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create broadcast"),process.exit(1);}}),i.command("update <broadcast_id>").description("Update a draft or scheduled broadcast").option("--name <name>","Broadcast name").option("--subject <subject>","Email subject").option("--from <email>","Sender email address").option("--template <id>","Template ID").option("--segment <id>","Segment ID").option("--html <html>","HTML content").option("--text <text>","Plain text content").option("--schedule <datetime>","Schedule time (ISO 8601)").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a={};e.name&&(a.name=e.name),e.subject&&(a.subject=e.subject),e.from&&(a.from_email=e.from),e.template&&(a.template_id=e.template),e.segment&&(a.segment_id=e.segment),e.html&&(a.html_content=e.html),e.text&&(a.text_content=e.text),e.schedule&&(a.scheduled_at=new Date(e.schedule).toISOString()),e.tags&&(a.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let n=await r.broadcasts.update(t,a);e.format==="json"?c(n,"json"):(d("Broadcast updated successfully!"),c({ID:n.id,Name:n.name,Status:n.status,Tags:n.tags?.join(", ")||"-"},"table"));}catch(o){l(o instanceof Error?o.message:"Failed to update broadcast"),process.exit(1);}}),i.command("send <broadcast_id>").description(`Send a broadcast immediately
1957
+ emailr segments Create and manage contact segments`).requiredOption("--name <name>","Broadcast name").requiredOption("--subject <subject>","Email subject").requiredOption("--from <email>","Sender email address").option("--template <id>","Template ID to use").option("--segment <id>","Segment ID to target").option("--html <html>","HTML content").option("--text <text>","Plain text content").option("--schedule <datetime>","Schedule time (ISO 8601)").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r={name:t.name,subject:t.subject,from_email:t.from,template_id:t.template,segment_id:t.segment,html_content:t.html,text_content:t.text,scheduled_at:t.schedule};t.tags&&(r.tags=t.tags.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean));let a=await o.broadcasts.create(r);t.format==="json"?c(a,"json"):(d("Broadcast created successfully!"),c({ID:a.id,Name:a.name,Status:a.status,Tags:a.tags?.join(", ")||"-","Scheduled At":a.scheduled_at||"Not scheduled"},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create broadcast"),process.exit(1);}}),i.command("send <broadcast_id>").description(`Send a broadcast immediately
1958
1958
 
1959
1959
  USAGE
1960
1960
  emailr broadcasts send <broadcast_id> [options]
@@ -2138,7 +2138,7 @@ EXAMPLES
2138
2138
 
2139
2139
  WARNING
2140
2140
  This action is permanent and cannot be undone.
2141
- All delivery statistics will be lost.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.delete(t);e.format==="json"?c(a,"json"):d("Broadcast deleted successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to delete broadcast"),process.exit(1);}}),i}function Ne(){let i=new Command("webhooks").description(`Manage webhooks
2141
+ All delivery statistics will be lost.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.delete(t);e.format==="json"?c(a,"json"):d("Broadcast deleted successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to delete broadcast"),process.exit(1);}}),i}function je(){let i=new Command("webhooks").description(`Manage webhooks
2142
2142
 
2143
2143
  USAGE
2144
2144
  emailr webhooks <subcommand> [options]
@@ -2939,7 +2939,7 @@ TIP
2939
2939
  <p style="margin-top: 1rem;">Please close this window and try again.</p>
2940
2940
  </div>
2941
2941
  </body>
2942
- </html>`}function ke(){let i=null,t=0,e=null,o=null,r=null;return {async start(){return new Promise((a,n)=>{i=Je.createServer((s,p)=>{if(s.method!=="GET"||!s.url?.startsWith("/callback")){p.writeHead(404,{"Content-Type":"text/plain"}),p.end("Not Found");return}let b=st(s.url);if(r&&b.state!==r){p.writeHead(400,{"Content-Type":"text/html"}),p.end(ee("Security verification failed. State parameter mismatch.")),e&&e({success:false,error:"State parameter mismatch"});return}if(b.error){let h=b.message||b.error;p.writeHead(200,{"Content-Type":"text/html"}),p.end(ee(h)),e&&e({success:false,error:h});return}let T=b.key||b.code;if(T){p.writeHead(200,{"Content-Type":"text/html"}),p.end(lt()),e&&e({success:true,apiKey:T});return}p.writeHead(400,{"Content-Type":"text/html"}),p.end(ee("Invalid callback: missing required parameters.")),e&&e({success:false,error:"Invalid callback: missing required parameters"});}),i.listen(0,"127.0.0.1",()=>{let s=i.address();s&&typeof s=="object"?(t=s.port,a({port:t,url:`http://127.0.0.1:${t}/callback`})):n(new Error("Failed to get server address"));}),i.on("error",s=>{n(new Error(`Failed to start callback server: ${s.message}`));});})},async waitForCallback(a,n){return r=a,new Promise(s=>{e=s,o=setTimeout(()=>{e&&e({success:false,error:"Login timed out. Please try again."});},n);})},async stop(){if(o&&(clearTimeout(o),o=null),i)return new Promise(a=>{i.close(()=>{i=null,a();});})}}}function Ce(){return ct.randomBytes(32).toString("hex")}function Ue(i){return new Promise(t=>{let e=process.platform,o;switch(e){case "darwin":o=`open "${i}"`;break;case "win32":o=`start "" "${i}"`;break;default:o=`xdg-open "${i}"`;break}exec(o,r=>{t(!r);});})}var $=120,pt=process.env.EMAILR_WEB_URL||"https://app.emailr.dev";function ut(i,t){let e=`http://127.0.0.1:${t}/callback`,o=new URLSearchParams({state:i,callback_url:e});return `${pt}/consent/authorize?${o.toString()}`}function Pe(){return new Command("login").description("Log in to Emailr via browser authentication").option("-t, --timeout <seconds>","Timeout in seconds",String($)).option("--no-browser","Don't automatically open the browser").action(async t=>{await ft({timeout:parseInt(t.timeout,10)||$,noBrowser:t.browser===false});})}async function ft(i){let t=ke(),e=(i.timeout||$)*1e3;try{u("Starting authentication server...");let{port:o,url:r}=await t.start(),a=Ce(),n=ut(a,o);console.log(""),u("Authorization URL:"),console.log(` ${n}`),console.log(""),i.noBrowser?u("Please open the URL above in your browser to continue."):await Ue(n)?u("Browser opened. Please complete authentication in your browser."):(k("Could not open browser automatically."),u("Please open the URL above in your browser to continue.")),console.log(""),u(`Waiting for authentication (timeout: ${i.timeout||$}s)...`);let s=await t.waitForCallback(a,e);s.success&&s.apiKey?(G({apiKey:s.apiKey}),console.log(""),d("Login successful!"),u(`API key saved to: ${I()}`),u("You can now use the Emailr CLI.")):(console.log(""),l(s.error||"Authentication failed."),u("Please try again or use manual configuration:"),console.log(" emailr config set api-key <your-api-key>"),process.exit(1));}catch(o){console.log(""),l(o instanceof Error?o.message:"An unexpected error occurred."),u("Please try again or use manual configuration:"),console.log(" emailr config set api-key <your-api-key>"),process.exit(1);}finally{await t.stop();}}var ae=_.join(B.homedir(),".config","opencode","skills","emailr-cli"),wt=`---
2942
+ </html>`}function ke(){let i=null,t=0,e=null,o=null,r=null;return {async start(){return new Promise((a,n)=>{i=Je.createServer((s,p)=>{if(s.method!=="GET"||!s.url?.startsWith("/callback")){p.writeHead(404,{"Content-Type":"text/plain"}),p.end("Not Found");return}let b=st(s.url);if(r&&b.state!==r){p.writeHead(400,{"Content-Type":"text/html"}),p.end(ee("Security verification failed. State parameter mismatch.")),e&&e({success:false,error:"State parameter mismatch"});return}if(b.error){let h=b.message||b.error;p.writeHead(200,{"Content-Type":"text/html"}),p.end(ee(h)),e&&e({success:false,error:h});return}let T=b.key||b.code;if(T){p.writeHead(200,{"Content-Type":"text/html"}),p.end(lt()),e&&e({success:true,apiKey:T});return}p.writeHead(400,{"Content-Type":"text/html"}),p.end(ee("Invalid callback: missing required parameters.")),e&&e({success:false,error:"Invalid callback: missing required parameters"});}),i.listen(0,"127.0.0.1",()=>{let s=i.address();s&&typeof s=="object"?(t=s.port,a({port:t,url:`http://127.0.0.1:${t}/callback`})):n(new Error("Failed to get server address"));}),i.on("error",s=>{n(new Error(`Failed to start callback server: ${s.message}`));});})},async waitForCallback(a,n){return r=a,new Promise(s=>{e=s,o=setTimeout(()=>{e&&e({success:false,error:"Login timed out. Please try again."});},n);})},async stop(){if(o&&(clearTimeout(o),o=null),i)return new Promise(a=>{i.close(()=>{i=null,a();});})}}}function Ce(){return ct.randomBytes(32).toString("hex")}function Ue(i){return new Promise(t=>{let e=process.platform,o;switch(e){case "darwin":o=`open "${i}"`;break;case "win32":o=`start "" "${i}"`;break;default:o=`xdg-open "${i}"`;break}exec(o,r=>{t(!r);});})}var $=120,pt=process.env.EMAILR_WEB_URL||"https://app.emailr.dev";function ut(i,t){let e=`http://127.0.0.1:${t}/callback`,o=new URLSearchParams({state:i,callback_url:e});return `${pt}/consent/authorize?${o.toString()}`}function Pe(){return new Command("login").description("Log in to Emailr via browser authentication").option("-t, --timeout <seconds>","Timeout in seconds",String($)).option("--no-browser","Don't automatically open the browser").action(async t=>{await ft({timeout:parseInt(t.timeout,10)||$,noBrowser:t.browser===false});})}async function ft(i){let t=ke(),e=(i.timeout||$)*1e3;try{u("Starting authentication server...");let{port:o,url:r}=await t.start(),a=Ce(),n=ut(a,o);console.log(""),u("Authorization URL:"),console.log(` ${n}`),console.log(""),i.noBrowser?u("Please open the URL above in your browser to continue."):await Ue(n)?u("Browser opened. Please complete authentication in your browser."):(I("Could not open browser automatically."),u("Please open the URL above in your browser to continue.")),console.log(""),u(`Waiting for authentication (timeout: ${i.timeout||$}s)...`);let s=await t.waitForCallback(a,e);s.success&&s.apiKey?(G({apiKey:s.apiKey}),console.log(""),d("Login successful!"),u(`API key saved to: ${j()}`),u("You can now use the Emailr CLI.")):(console.log(""),l(s.error||"Authentication failed."),u("Please try again or use manual configuration:"),console.log(" emailr config set api-key <your-api-key>"),process.exit(1));}catch(o){console.log(""),l(o instanceof Error?o.message:"An unexpected error occurred."),u("Please try again or use manual configuration:"),console.log(" emailr config set api-key <your-api-key>"),process.exit(1);}finally{await t.stop();}}var ae=_.join(B.homedir(),".config","opencode","skills","emailr-cli"),wt=`---
2943
2943
  name: emailr-cli
2944
2944
  description: Operate the Emailr CLI to send emails, manage contacts, templates, domains, broadcasts, webhooks, and segments. Includes LIVE PREVIEW editing for templates with hot-reload.
2945
2945
  ---
@@ -2988,7 +2988,7 @@ The agent can help you:
2988
2988
  - Configure domains and webhooks
2989
2989
 
2990
2990
  The agent runs in your terminal with full access to the emailr CLI.`).option("--install","Install OpenCode if not already installed").option("--model <model>","Model to use (e.g., anthropic/claude-sonnet-4)").action(async t=>{yt()||(t.install?St()||(l("Failed to install OpenCode. Please install manually:"),console.log(" npm install -g opencode-ai@latest"),console.log(" # or"),console.log(" brew install anomalyco/tap/opencode"),process.exit(1)):(l("OpenCode AI agent is not installed."),console.log(`
2991
- Install it with one of:`),console.log(" emailr agent --install"),console.log(" npm install -g opencode-ai@latest"),console.log(" brew install anomalyco/tap/opencode"),process.exit(1)));try{vt(),d("Emailr CLI skill loaded");}catch(r){k(`Could not install skill: ${r instanceof Error?r.message:String(r)}`);}let e=[];t.model&&e.push("--model",t.model),console.log(`
2991
+ Install it with one of:`),console.log(" emailr agent --install"),console.log(" npm install -g opencode-ai@latest"),console.log(" brew install anomalyco/tap/opencode"),process.exit(1)));try{vt(),d("Emailr CLI skill loaded");}catch(r){I(`Could not install skill: ${r instanceof Error?r.message:String(r)}`);}let e=[];t.model&&e.push("--model",t.model),console.log(`
2992
2992
  Starting Emailr AI Agent...`),console.log("The agent has the emailr-cli skill loaded."),console.log(`Ask it to help with emails, templates, contacts, or broadcasts.
2993
2993
  `);let o=spawn("opencode",e,{stdio:"inherit",env:process.env});o.on("error",r=>{l(`Failed to start agent: ${r.message}`),process.exit(1);}),o.on("exit",r=>{process.exit(r??0);});})}var g=new Command;g.name("emailr").description(`Emailr CLI - Send emails and manage your email infrastructure
2994
2994
 
@@ -3076,4 +3076,4 @@ AGENTIC WORKFLOW
3076
3076
 
3077
3077
  MORE INFORMATION
3078
3078
  Run 'emailr <command> --help' for detailed help on any command.
3079
- Run 'emailr <command> <subcommand> --help' for subcommand details.`).version("1.5.4");g.addCommand(ce());g.addCommand(me());g.addCommand(Oe());g.addCommand(Ee());g.addCommand(je());g.addCommand(Ne());g.addCommand(Ie());g.addCommand(_e());g.addCommand(Pe());g.addCommand(xe());g.parse();
3079
+ Run 'emailr <command> <subcommand> --help' for subcommand details.`).version("1.5.4");g.addCommand(ce());g.addCommand(me());g.addCommand(Oe());g.addCommand(Ee());g.addCommand(Ne());g.addCommand(je());g.addCommand(Ie());g.addCommand(_e());g.addCommand(Pe());g.addCommand(xe());g.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emailr-cli",
3
- "version": "1.7.2",
3
+ "version": "1.7.3",
4
4
  "description": "Command-line interface for the Emailr email API",
5
5
  "type": "module",
6
6
  "bin": {