@emailthing/cli 0.0.0-alpha.2 → 0.0.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/agent.js CHANGED
@@ -3,11 +3,11 @@
3
3
  import {
4
4
  EmailThingCLI,
5
5
  syncData
6
- } from "./index-xp4bqj3r.js";
6
+ } from "./index-6p9vvb4b.js";
7
7
  import {
8
8
  getDB,
9
9
  loadAuth
10
- } from "./index-9968g90t.js";
10
+ } from "./index-3r08bcy6.js";
11
11
  import"./index-3t2e65zf.js";
12
12
 
13
13
  // src/agent.ts
@@ -22,7 +22,7 @@ async function main() {
22
22
  strict: !1,
23
23
  allowNegative: !0
24
24
  }), agentIndex = rootPositionals.findIndex((arg) => arg === "--agent" || arg === "agent"), subcmd = rootPositionals[agentIndex + 1], subcmdArgs = rootPositionals.slice(agentIndex + 2);
25
- if (globalValues.help || !subcmd || !["list", "email", "sync"].includes(subcmd)) {
25
+ if (globalValues.help || !subcmd || !["list", "email", "mailboxes", "send", "sync"].includes(subcmd)) {
26
26
  let nowIso = (/* @__PURE__ */ new Date()).toISOString();
27
27
  console.log(`
28
28
  EmailThing CLI - Agent Mode
@@ -35,6 +35,8 @@ Usage:
35
35
  Subcommands:
36
36
  list List recent emails (default: 25)
37
37
  email <id> Show full email by ID (body, etc)
38
+ mailboxes List mailboxes with their aliases
39
+ send Send an email from an alias
38
40
  sync Force fresh sync from server
39
41
 
40
42
  \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
@@ -61,6 +63,19 @@ agent email <id>:
61
63
  --fields=a,b,c Show only those fields
62
64
  --sync Force sync before showing email details
63
65
 
66
+ agent mailboxes:
67
+ Lists your available mailboxes and their aliases.
68
+ (No options)
69
+
70
+ agent send:
71
+ Send an email. Reads body from stdin (e.g. pipe from echo or file).
72
+ --from=<alias@domain.com> Alias email you control (see \`agent mailboxes\` for valid aliases)
73
+ --to=<email@domain.com>... Recipient email address (multiple supported)
74
+ --cc=<email@domain.com>... CC Recipient email address
75
+ --bcc=<email@domain.com>... BCC Recipient email address
76
+ --subject=<text> Subject line
77
+ --html Treat stdin as HTML
78
+
64
79
  agent sync:
65
80
  Triggers sync with server to update local cache
66
81
  (No other options needed)
@@ -73,6 +88,7 @@ Examples:
73
88
  bunx @emailthing/cli agent list --unread --limit=10 --sync
74
89
  bunx @emailthing/cli agent email abc123xyz789example456id --json --sync
75
90
  bunx @emailthing/cli agent sync
91
+ echo "The text/plain body" | bunx @emailthing/cli agent send --from=me@myalias.com --to=friend@site.com --to=another@friend.com --subject="Hello"
76
92
 
77
93
  Output Format:
78
94
  List mode:
@@ -97,6 +113,10 @@ Output Format:
97
113
  Body:
98
114
  Your verification code is: 123456
99
115
  This code expires in 10 minutes.
116
+ Mailboxes mode:
117
+ Mailbox: abcd123
118
+ Alias: Someone@emailthing.xyz (default) Name: My Personal Email
119
+ Alias: Custom@domain.com
100
120
  `), process.exit(0);
101
121
  }
102
122
  let db = getDB(), client = new EmailThingCLI, auth = loadAuth(db);
@@ -353,6 +373,87 @@ ${hasMore ? `Next page: --offset=${offset + limit} --limit=${limit}` : "No more
353
373
  }), db2.close();
354
374
  return;
355
375
  }
376
+ if (subcmd === "send") {
377
+ let values = { ...parseArgs({
378
+ options: {
379
+ from: { type: "string" },
380
+ to: { type: "string", multiple: !0 },
381
+ cc: { type: "string", multiple: !0 },
382
+ bcc: { type: "string", multiple: !0 },
383
+ subject: { type: "string" },
384
+ html: { type: "boolean", default: !1 }
385
+ },
386
+ allowPositionals: !0,
387
+ strict: !0,
388
+ allowNegative: !0
389
+ }).values };
390
+ if (!values.from || typeof values.from !== "string" || !values.to || !Array.isArray(values.to) || values.to.length === 0)
391
+ console.error(`Error: --from and --to are required.
392
+ Run 'bunx @emailthing/cli agent mailboxes' to see available aliases.`), process.exit(1);
393
+ async function readStdin() {
394
+ if (process.stdin.isTTY)
395
+ return null;
396
+ try {
397
+ return (await Bun.stdin.text()).trim() || null;
398
+ } catch {
399
+ return null;
400
+ }
401
+ }
402
+ let stdin = await readStdin();
403
+ if (!stdin || !stdin.trim())
404
+ console.error("Error: No message body detected from stdin. Pipe body or use echo."), process.exit(1);
405
+ let db2 = getDB(), aliasRow = db2.query("SELECT mailboxId, alias FROM mailbox_aliases WHERE alias = ? AND isDeleted = 0").get(values.from);
406
+ if (!aliasRow)
407
+ console.error(`Error: Alias '${values.from}' not found or not valid for sending.
408
+ Run 'bunx @emailthing/cli agent mailboxes' to see your aliases.`), db2.close(), process.exit(1);
409
+ let mailboxId = aliasRow.mailboxId, client2 = new EmailThingCLI, auth2 = loadAuth(db2);
410
+ if (!auth2)
411
+ console.error("Error: Not authenticated. Please run the CLI first to login."), db2.close(), process.exit(1);
412
+ client2.setAuth(auth2.token, auth2.refreshToken, auth2.tokenExpiresAt);
413
+ try {
414
+ let to = [
415
+ ...values.to.map((address) => ({ address, type: "to" })),
416
+ ...(values.cc || []).map((address) => ({ address, type: "cc" })),
417
+ ...(values.bcc || []).map((address) => ({ address, type: "bcc" }))
418
+ ], sendResult = await client2.sendDraft({
419
+ mailboxId,
420
+ body: values.html ? void 0 : stdin,
421
+ html: values.html ? stdin : void 0,
422
+ subject: values.subject || "(no subject)",
423
+ from: values.from,
424
+ to
425
+ });
426
+ if (console.log(`Send successful! Email sent from ${values.from} to ${to.map((t) => t.type === "cc" ? `${t.address} (cc)` : t.type === "bcc" ? `${t.address} (bcc)` : t.address).join(", ")}`), console.log(sendResult), sendResult && sendResult.sync.draftSync)
427
+ console.log(` Email id: ${sendResult.sync.emails[0].id} (should appear as sent email shortly)`);
428
+ } catch (err) {
429
+ console.error("Email sending failed:", err?.message || err);
430
+ }
431
+ db2.close();
432
+ return;
433
+ }
434
+ if (subcmd === "mailboxes") {
435
+ let db2 = getDB(), client2 = new EmailThingCLI, auth2 = loadAuth(db2);
436
+ if (!auth2)
437
+ console.error("Error: Not authenticated. Please run the CLI first to login."), process.exit(1);
438
+ client2.setAuth(auth2.token, auth2.refreshToken, auth2.tokenExpiresAt);
439
+ let mailboxes = db2.query("SELECT m.id, a.alias, a.name, a.`default` FROM mailboxes m\n INNER JOIN mailbox_aliases a ON m.id = a.mailboxId\n WHERE m.isDeleted = 0 AND a.isDeleted = 0\n ORDER BY m.id, a.`default` DESC, a.alias").all();
440
+ if (mailboxes.length === 0) {
441
+ console.log("No mailboxes found."), db2.close();
442
+ return;
443
+ }
444
+ let grouped = {};
445
+ mailboxes.forEach((row) => {
446
+ if (!grouped[row.id])
447
+ grouped[row.id] = [];
448
+ grouped[row.id].push(row);
449
+ }), Object.entries(grouped).forEach(([mbId, aliases]) => {
450
+ let mbInfo = aliases[0];
451
+ console.log(`Mailbox: ${mbId}`), aliases.forEach((a) => {
452
+ console.log(` Alias: ${a.alias}${a.default ? " (default)" : ""}${a.name ? " Name: " + a.name : ""}`);
453
+ }), console.log("");
454
+ }), db2.close();
455
+ return;
456
+ }
356
457
  }
357
458
  main().catch((error) => {
358
459
  console.error("Error:", error.message, error instanceof Error ? error.stack : error), process.exit(1);
@@ -8,7 +8,7 @@ import {
8
8
  loadAuth,
9
9
  resetDB,
10
10
  saveAuth
11
- } from "./index-9968g90t.js";
11
+ } from "./index-3r08bcy6.js";
12
12
  import"./index-3t2e65zf.js";
13
13
  export {
14
14
  saveAuth,
@@ -35,6 +35,7 @@ function initDB(dbPath) {
35
35
  snippet TEXT,
36
36
  isRead BOOLEAN DEFAULT FALSE,
37
37
  isStarred BOOLEAN DEFAULT FALSE,
38
+ isSender BOOLEAN DEFAULT FALSE,
38
39
  createdAt TEXT NOT NULL,
39
40
  headers TEXT,
40
41
  raw TEXT,
@@ -90,11 +91,14 @@ function initDB(dbPath) {
90
91
  CREATE INDEX IF NOT EXISTS idx_emails_mailbox ON emails(mailboxId);
91
92
  CREATE INDEX IF NOT EXISTS idx_emails_created ON emails(createdAt);
92
93
  CREATE INDEX IF NOT EXISTS idx_categories_mailbox ON categories(mailboxId);
93
- `), currentVersion < 1) {
94
+ `), currentVersion < 2) {
94
95
  try {
95
96
  db.run("ALTER TABLE emails ADD COLUMN categoryId TEXT");
96
97
  } catch (e) {}
97
- db.run("PRAGMA user_version = 1");
98
+ try {
99
+ db.run("ALTER TABLE emails ADD COLUMN isSender BOOLEAN DEFAULT FALSE");
100
+ } catch (e) {}
101
+ db.run("PRAGMA user_version = 2");
98
102
  }
99
103
  return db;
100
104
  }
@@ -76,7 +76,7 @@ class EmailThingCLI {
76
76
  return res.json();
77
77
  }
78
78
  async sendDraft(draft) {
79
- await this.refreshTokenIfNeeded();
79
+ await this.refreshTokenIfNeeded(), draft.draftId ||= "new";
80
80
  let res = await this.internalFetch("/send-draft", "POST", draft);
81
81
  if (!res.ok)
82
82
  throw Error(`Send failed: ${await res.text()}`);
@@ -132,12 +132,12 @@ async function syncData(client, db, silent = !1) {
132
132
  if (db.run("BEGIN TRANSACTION"), !silent)
133
133
  console.error("Inserting emails...");
134
134
  let emailStmt = db.prepare(`
135
- INSERT OR REPLACE INTO emails (id, mailboxId, subject, from_addr, to_addr, cc, bcc, replyTo, body, html, snippet, isRead, isStarred, createdAt, headers, categoryId, isDeleted)
136
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
135
+ INSERT OR REPLACE INTO emails (id, mailboxId, subject, from_addr, to_addr, cc, bcc, replyTo, body, html, snippet, isRead, isStarred, createdAt, headers, categoryId, isDeleted, isSender)
136
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
137
137
  `);
138
138
  for (let email of syncData2.emails) {
139
139
  let from = email.sender?.address || "", to = email.recipients?.[0]?.address || "", cc = email.recipients?.filter((r) => r.cc).map((r) => r.address).join(", ") || null;
140
- emailStmt.run(email.id, email.mailboxId, email.subject || null, from, to, cc, email.bcc || null, email.replyTo || null, email.body || null, email.html || null, email.snippet || null, email.isRead ? !0 : !1, email.isStarred ? !0 : !1, email.createdAt, email.headers ? JSON.stringify(email.headers) : null, email.categoryId || null, email.isDeleted ? !0 : !1);
140
+ emailStmt.run(email.id, email.mailboxId, email.subject || null, from, to, cc, email.bcc || null, email.replyTo || null, email.body || null, email.html || null, email.snippet || null, email.isRead ? !0 : !1, email.isStarred ? !0 : !1, email.createdAt, email.headers ? JSON.stringify(email.headers) : null, email.categoryId || null, email.isDeleted ? !0 : !1, email.isSender ? !0 : !1);
141
141
  }
142
142
  if (!silent)
143
143
  console.error("Inserting mailboxes...");
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
 
7
7
  // src/index.ts
8
8
  if (process.argv.includes("logout")) {
9
- let { getDB, clearAuth, resetDB } = await import("./config-te78n8sf.js"), db = getDB();
9
+ let { getDB, clearAuth, resetDB } = await import("./config-4f9b0snt.js"), db = getDB();
10
10
  clearAuth(db), resetDB(db), console.log("Logged out successfully. Run again to login."), db.close();
11
11
  } else if (process.argv.includes("agent") || (process.env.CLAUDECODE || process.env.OPENCODE || process.env.AGENT) === "1")
12
12
  await import("./agent.js");
package/dist/main.js CHANGED
@@ -3,12 +3,12 @@
3
3
  import {
4
4
  EmailThingCLI,
5
5
  syncData
6
- } from "./index-xp4bqj3r.js";
6
+ } from "./index-6p9vvb4b.js";
7
7
  import {
8
8
  getDB,
9
9
  loadAuth,
10
10
  saveAuth
11
- } from "./index-9968g90t.js";
11
+ } from "./index-3r08bcy6.js";
12
12
  import {
13
13
  __callDispose,
14
14
  __require,
@@ -1017,7 +1017,7 @@ async function main() {
1017
1017
  case "switch": {
1018
1018
  let newMailboxId = await mailboxSwitcher(db, route.mailboxId);
1019
1019
  if (newMailboxId === "switch-user") {
1020
- let { clearAuth, resetDB } = await import("./config-te78n8sf.js");
1020
+ let { clearAuth, resetDB } = await import("./config-4f9b0snt.js");
1021
1021
  return clearAuth(db), resetDB(db), main();
1022
1022
  } else if (newMailboxId)
1023
1023
  route = { route: "list", mailboxId: newMailboxId };
@@ -1030,7 +1030,6 @@ async function main() {
1030
1030
  if (composeData)
1031
1031
  try {
1032
1032
  console.log("Sending email..."), await client.sendDraft({
1033
- draftId: crypto.randomUUID(),
1034
1033
  mailboxId: route.mailboxId,
1035
1034
  body: composeData.body,
1036
1035
  subject: composeData.subject,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emailthing/cli",
3
- "version": "0.0.0-alpha.2",
3
+ "version": "0.0.0-alpha.4",
4
4
  "description": "An interactive command-line interface for managing your EmailThing emails!",
5
5
  "type": "module",
6
6
  "repository": {