@wirecat/mail-cli 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +149 -0
- package/README.md +48 -13
- package/dist/bin/mail.js +2 -2
- package/dist/bundle/{all-profiles-GR5JXYEQ.js → all-profiles-SI67TKZM.js} +9 -9
- package/dist/bundle/{anthropic-REBXE65F.js → anthropic-DALMLC3Y.js} +6 -6
- package/dist/bundle/{app-server-QJ7ICQXZ.js → app-server-XOH327Z2.js} +46 -46
- package/dist/bundle/{bun-WAX4QHW5.js → bun-ORL67CJ6.js} +2 -2
- package/dist/bundle/{bun-sqlite-5S7TQ4SG.js → bun-sqlite-DGXFNFHI.js} +5 -5
- package/dist/bundle/{chunk-ZD3WUGR2.js → chunk-23IEVVL2.js} +4 -4
- package/dist/bundle/{chunk-B5WSIWY5.js → chunk-2M4K7HYR.js} +17 -17
- package/dist/bundle/{chunk-IWDOGGMY.js → chunk-35KD2CI2.js} +501 -301
- package/dist/bundle/{chunk-7A7BHABA.js → chunk-3GZK5GTU.js} +1 -1
- package/dist/bundle/{chunk-JJBQPA7D.js → chunk-3TYEJRMZ.js} +4 -4
- package/dist/bundle/{chunk-M6BDHZON.js → chunk-45KA5667.js} +26 -13
- package/dist/bundle/{chunk-LOA4X6JW.js → chunk-4NYWHINR.js} +6 -6
- package/dist/bundle/{dist-KJOAJ6NF.js → chunk-4ULY3GDL.js} +16 -116
- package/dist/bundle/{chunk-2FXVBCA3.js → chunk-5BSEGMNE.js} +4 -4
- package/dist/bundle/{chunk-HCMUGUAG.js → chunk-5JEYIHS6.js} +3 -3
- package/dist/bundle/{chunk-QXOSGGKS.js → chunk-6LK7KTWB.js} +1 -1
- package/dist/bundle/{chunk-ESNNQA7D.js → chunk-6RMMAUUW.js} +28 -28
- package/dist/bundle/{chunk-VXAZZGXE.js → chunk-6XNPXAJU.js} +33 -27
- package/dist/bundle/{chunk-5INWLYBD.js → chunk-73OJJGZE.js} +14 -3
- package/dist/bundle/{chunk-4XJ4AM3K.js → chunk-7K6KJWTO.js} +12 -12
- package/dist/bundle/{chunk-KIDF77MA.js → chunk-AP7V256W.js} +1 -1
- package/dist/bundle/{chunk-4BMNP2FT.js → chunk-BEMLGWY4.js} +1 -1
- package/dist/bundle/{chunk-BFJV4FWJ.js → chunk-BGUMGCUY.js} +2 -2
- package/dist/bundle/{chunk-5BVIWP3S.js → chunk-BM445GYF.js} +2 -2
- package/dist/bundle/{chunk-F3NYA4KN.js → chunk-CAKBG5FC.js} +6 -6
- package/dist/bundle/{chunk-EB3R2PV3.js → chunk-DKQWTQVY.js} +23 -23
- package/dist/bundle/{chunk-6TY3DGCC.js → chunk-DXGMPMFP.js} +4 -4
- package/dist/bundle/{chunk-LFRHIXCF.js → chunk-E3DRM6YP.js} +3 -3
- package/dist/bundle/{chunk-FSUNGHRI.js → chunk-EYT33MM3.js} +47 -46
- package/dist/bundle/{chunk-DXDQOZ2P.js → chunk-FPOGVDLS.js} +2 -2
- package/dist/bundle/{chunk-S677WGOQ.js → chunk-FTFNWGIR.js} +8 -8
- package/dist/bundle/{chunk-TI6VBZKJ.js → chunk-FUB3X25H.js} +4 -4
- package/dist/bundle/{chunk-7JCRQX56.js → chunk-GJUUTUK4.js} +8 -8
- package/dist/bundle/{chunk-BLS5YG77.js → chunk-HFJNEXU7.js} +2 -2
- package/dist/bundle/{chunk-YKPBC3NL.js → chunk-HV3EIYX4.js} +1 -1
- package/dist/bundle/{chunk-EL554DV2.js → chunk-IYZHM3ZN.js} +3 -3
- package/dist/bundle/{chunk-6EO7GVYJ.js → chunk-JFMUI4H6.js} +1 -1
- package/dist/bundle/{chunk-2YQNBIDQ.js → chunk-LZ5J3UXD.js} +4 -4
- package/dist/bundle/{chunk-WNCCYHRV.js → chunk-M2JCUVCJ.js} +116 -95
- package/dist/bundle/{chunk-7F3NDIYL.js → chunk-MCJ7LKYR.js} +6 -6
- package/dist/bundle/{chunk-VDAIJM5L.js → chunk-MHQKHWCJ.js} +88 -34
- package/dist/bundle/{chunk-SQ7KOBRA.js → chunk-MMXMVGA6.js} +10 -8
- package/dist/bundle/{chunk-AFCGOZR7.js → chunk-NNIXREJH.js} +7 -7
- package/dist/bundle/{chunk-LQ37ALDJ.js → chunk-NXJLC2WK.js} +8 -8
- package/dist/bundle/{chunk-6GE3EADU.js → chunk-OHTR4WFO.js} +2 -2
- package/dist/bundle/{chunk-PJCTWPJB.js → chunk-PDL4UREY.js} +8 -8
- package/dist/bundle/{chunk-J3QXTBD2.js → chunk-Q2C3VMSU.js} +20 -18
- package/dist/bundle/{chunk-SWJAG5IE.js → chunk-Q44AYEOB.js} +2 -2
- package/dist/bundle/{chunk-P7P5MNAU.js → chunk-QZBT6BOU.js} +1 -1
- package/dist/bundle/{chunk-IBYTYIYO.js → chunk-R5MML3FC.js} +61 -54
- package/dist/bundle/{chunk-CEAANMJ2.js → chunk-RQVWZBW3.js} +3 -3
- package/dist/bundle/{chunk-5CXAH4Y6.js → chunk-S4YUR4S3.js} +656 -572
- package/dist/bundle/{chunk-QX7RCLRS.js → chunk-SQLCCKEL.js} +1 -1
- package/dist/bundle/chunk-U6UJ3HRS.js +58 -0
- package/dist/bundle/{chunk-YRGBZZUW.js → chunk-V4TDG4KF.js} +14 -14
- package/dist/bundle/{chunk-5FK6RD4M.js → chunk-VBOMKZ4E.js} +73 -57
- package/dist/bundle/{chunk-MQUJEQTU.js → chunk-VKPWP3AK.js} +2 -2
- package/dist/bundle/{chunk-7XNPSIWD.js → chunk-VNJMO5F6.js} +2 -2
- package/dist/bundle/{chunk-MMDCL42A.js → chunk-VSHJWTX5.js} +12 -6
- package/dist/bundle/{chunk-2MRECWJZ.js → chunk-XQJWMBDY.js} +6 -6
- package/dist/bundle/{chunk-2U4IANVV.js → chunk-ZKCNMW7G.js} +2 -2
- package/dist/bundle/{chunk-LNS27BTB.js → chunk-ZKZABB4K.js} +3 -3
- package/dist/bundle/{chunk-WNI5BZFB.js → chunk-ZNGQ3NZ4.js} +9 -9
- package/dist/bundle/command-contract-CB5BII3S.js +34 -0
- package/dist/bundle/{decode-D7BDVIVB.js → decode-KOBURZIQ.js} +5 -5
- package/dist/bundle/{dispatch-EUKKT3PD.js → dispatch-GDAH4JHS.js} +8 -8
- package/dist/bundle/dist-T7HMT675.js +134 -0
- package/dist/bundle/{echarts-IVRX7XHP.js → echarts-LEWTQO6H.js} +2 -2
- package/dist/bundle/{embed-X527RBTG.js → embed-PUFE4BSQ.js} +6 -6
- package/dist/bundle/{embedder-F4PSJS6S.js → embedder-3G4BQQ6X.js} +9 -9
- package/dist/bundle/{failure-OAIC5VAP.js → failure-6COJAO7T.js} +2 -2
- package/dist/bundle/{first-run-M5CIX6NA.js → first-run-FLXOC53U.js} +11 -11
- package/dist/bundle/first-screen-VUZEDSQW.js +32 -0
- package/dist/bundle/{instructions-UX36BT5F.js → instructions-HGSXDCBT.js} +1 -1
- package/dist/bundle/mail.js +12 -11
- package/dist/bundle/{mcp-L7SRVDRN.js → mcp-GAPDLFWA.js} +2 -2
- package/dist/bundle/{node-OXT7WE2T.js → node-5Z7PS4F5.js} +2 -2
- package/dist/bundle/{node-sqlite-X2PSEHA4.js → node-sqlite-OAW7APIX.js} +5 -5
- package/dist/bundle/{oauth-MYK4BSYN.js → oauth-ZFZWPAJN.js} +7 -7
- package/dist/bundle/{open-GONIP2DH.js → open-ZQMBZVH4.js} +4 -4
- package/dist/bundle/{openai-YJFNUOQT.js → openai-XT2RIXAK.js} +14 -14
- package/dist/bundle/{process-7IEUUSRK.js → process-VVEQIHPE.js} +1 -1
- package/dist/bundle/{program-Q73TTG3E.js → program-RD3BBDNY.js} +21470 -7075
- package/dist/bundle/{prompt-SKQ72KN7.js → prompt-PU7GE4Z4.js} +5 -5
- package/dist/bundle/{recognize-GC7CU2DB.js → recognize-AG4A3KUK.js} +4 -4
- package/dist/bundle/{remote-UEXFZP2I.js → remote-D6TQ6T7F.js} +7 -7
- package/dist/bundle/{rerank-2U2NDEZP.js → rerank-GO24HJPF.js} +7 -7
- package/dist/bundle/{serve-OOGKFEWL.js → serve-WCHJAH6G.js} +9 -9
- package/dist/bundle/server-5KJJ3D6P.js +63 -0
- package/dist/bundle/{server-FZ3LFQTF.js → server-CAVNBG3P.js} +38 -38
- package/dist/bundle/{sqlite-runtime-GIQSW6LJ.js → sqlite-runtime-ANXC4AW2.js} +5 -5
- package/dist/bundle/{state-EMFXPQVZ.js → state-EGJ66A62.js} +6 -6
- package/dist/bundle/{store-BDU4UPNK.js → store-OON7FCMQ.js} +15 -15
- package/dist/bundle/{store-LDI62AUG.js → store-SBFA444C.js} +13 -13
- package/dist/bundle/store-maintenance-command-UEOJLYMJ.js +52 -0
- package/dist/commands/attachments.d.ts +3 -0
- package/dist/commands/attachments.d.ts.map +1 -0
- package/dist/commands/attachments.js +97 -0
- package/dist/commands/attachments.js.map +1 -0
- package/dist/commands/context.d.ts +21 -6
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +58 -7
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/drafts-send.d.ts +7 -0
- package/dist/commands/drafts-send.d.ts.map +1 -0
- package/dist/commands/drafts-send.js +58 -0
- package/dist/commands/drafts-send.js.map +1 -0
- package/dist/commands/drafts.d.ts +3 -0
- package/dist/commands/drafts.d.ts.map +1 -0
- package/dist/commands/drafts.js +243 -0
- package/dist/commands/drafts.js.map +1 -0
- package/dist/commands/export.d.ts +3 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +278 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/folders.d.ts.map +1 -1
- package/dist/commands/folders.js +120 -2
- package/dist/commands/folders.js.map +1 -1
- package/dist/commands/messages.d.ts +25 -0
- package/dist/commands/messages.d.ts.map +1 -0
- package/dist/commands/messages.js +506 -0
- package/dist/commands/messages.js.map +1 -0
- package/dist/commands/read.d.ts +4 -1
- package/dist/commands/read.d.ts.map +1 -1
- package/dist/commands/read.js +14 -3
- package/dist/commands/read.js.map +1 -1
- package/dist/commands/rules.d.ts +3 -0
- package/dist/commands/rules.d.ts.map +1 -0
- package/dist/commands/rules.js +292 -0
- package/dist/commands/rules.js.map +1 -0
- package/dist/commands/send.d.ts +39 -0
- package/dist/commands/send.d.ts.map +1 -0
- package/dist/commands/send.js +309 -0
- package/dist/commands/send.js.map +1 -0
- package/dist/commands/server-search.d.ts +8 -0
- package/dist/commands/server-search.d.ts.map +1 -0
- package/dist/commands/server-search.js +38 -0
- package/dist/commands/server-search.js.map +1 -0
- package/dist/commands/session-start.d.ts.map +1 -1
- package/dist/commands/session-start.js +107 -10
- package/dist/commands/session-start.js.map +1 -1
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +72 -9
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/stats.d.ts +3 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +89 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/status.js +2 -2
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/sync.d.ts +6 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +28 -20
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/tags.d.ts +3 -0
- package/dist/commands/tags.d.ts.map +1 -0
- package/dist/commands/tags.js +144 -0
- package/dist/commands/tags.js.map +1 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +52 -1
- package/dist/config.js.map +1 -1
- package/dist/export/format.d.ts +19 -0
- package/dist/export/format.d.ts.map +1 -0
- package/dist/export/format.js +40 -0
- package/dist/export/format.js.map +1 -0
- package/dist/export/journal.d.ts +32 -0
- package/dist/export/journal.d.ts.map +1 -0
- package/dist/export/journal.js +84 -0
- package/dist/export/journal.js.map +1 -0
- package/dist/export/write.d.ts +14 -0
- package/dist/export/write.d.ts.map +1 -0
- package/dist/export/write.js +42 -0
- package/dist/export/write.js.map +1 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +3 -0
- package/dist/identity.js.map +1 -1
- package/dist/mail/backend.d.ts +104 -2
- package/dist/mail/backend.d.ts.map +1 -1
- package/dist/mail/backend.js +4 -1
- package/dist/mail/backend.js.map +1 -1
- package/dist/mail/changes.d.ts +91 -0
- package/dist/mail/changes.d.ts.map +1 -0
- package/dist/mail/changes.js +198 -0
- package/dist/mail/changes.js.map +1 -0
- package/dist/mail/cleanup.d.ts +41 -0
- package/dist/mail/cleanup.d.ts.map +1 -0
- package/dist/mail/cleanup.js +119 -0
- package/dist/mail/cleanup.js.map +1 -0
- package/dist/mail/compose.d.ts +73 -0
- package/dist/mail/compose.d.ts.map +1 -0
- package/dist/mail/compose.js +110 -0
- package/dist/mail/compose.js.map +1 -0
- package/dist/mail/doctor.d.ts +67 -0
- package/dist/mail/doctor.d.ts.map +1 -0
- package/dist/mail/doctor.js +115 -0
- package/dist/mail/doctor.js.map +1 -0
- package/dist/mail/drafts.d.ts +54 -0
- package/dist/mail/drafts.d.ts.map +1 -0
- package/dist/mail/drafts.js +104 -0
- package/dist/mail/drafts.js.map +1 -0
- package/dist/mail/imap/connection.d.ts +13 -3
- package/dist/mail/imap/connection.d.ts.map +1 -1
- package/dist/mail/imap/connection.js +87 -18
- package/dist/mail/imap/connection.js.map +1 -1
- package/dist/mail/imap/index.d.ts +3 -3
- package/dist/mail/imap/index.d.ts.map +1 -1
- package/dist/mail/imap/index.js +14 -4
- package/dist/mail/imap/index.js.map +1 -1
- package/dist/mail/imap/messages.d.ts +5 -6
- package/dist/mail/imap/messages.d.ts.map +1 -1
- package/dist/mail/imap/messages.js +14 -28
- package/dist/mail/imap/messages.js.map +1 -1
- package/dist/mail/imap/read.d.ts.map +1 -1
- package/dist/mail/imap/read.js +27 -13
- package/dist/mail/imap/read.js.map +1 -1
- package/dist/mail/imap/search.d.ts +14 -0
- package/dist/mail/imap/search.d.ts.map +1 -0
- package/dist/mail/imap/search.js +55 -0
- package/dist/mail/imap/search.js.map +1 -0
- package/dist/mail/imap/write.d.ts +5 -0
- package/dist/mail/imap/write.d.ts.map +1 -0
- package/dist/mail/imap/write.js +93 -0
- package/dist/mail/imap/write.js.map +1 -0
- package/dist/mail/organise.d.ts +116 -0
- package/dist/mail/organise.d.ts.map +1 -0
- package/dist/mail/organise.js +531 -0
- package/dist/mail/organise.js.map +1 -0
- package/dist/mail/rethread.d.ts +1 -2
- package/dist/mail/rethread.d.ts.map +1 -1
- package/dist/mail/rethread.js +8 -3
- package/dist/mail/rethread.js.map +1 -1
- package/dist/mail/rules/apply.d.ts +40 -0
- package/dist/mail/rules/apply.d.ts.map +1 -0
- package/dist/mail/rules/apply.js +114 -0
- package/dist/mail/rules/apply.js.map +1 -0
- package/dist/mail/rules/file.d.ts +9 -0
- package/dist/mail/rules/file.d.ts.map +1 -0
- package/dist/mail/rules/file.js +51 -0
- package/dist/mail/rules/file.js.map +1 -0
- package/dist/mail/rules/filters.d.ts +11 -0
- package/dist/mail/rules/filters.d.ts.map +1 -0
- package/dist/mail/rules/filters.js +150 -0
- package/dist/mail/rules/filters.js.map +1 -0
- package/dist/mail/rules/folders.d.ts +11 -0
- package/dist/mail/rules/folders.d.ts.map +1 -0
- package/dist/mail/rules/folders.js +17 -0
- package/dist/mail/rules/folders.js.map +1 -0
- package/dist/mail/rules/query.d.ts +15 -0
- package/dist/mail/rules/query.d.ts.map +1 -0
- package/dist/mail/rules/query.js +103 -0
- package/dist/mail/rules/query.js.map +1 -0
- package/dist/mail/rules/store.d.ts +9 -0
- package/dist/mail/rules/store.d.ts.map +1 -0
- package/dist/mail/rules/store.js +17 -0
- package/dist/mail/rules/store.js.map +1 -0
- package/dist/mail/save.d.ts +9 -0
- package/dist/mail/save.d.ts.map +1 -0
- package/dist/mail/save.js +50 -0
- package/dist/mail/save.js.map +1 -0
- package/dist/mail/send.d.ts +67 -0
- package/dist/mail/send.d.ts.map +1 -0
- package/dist/mail/send.js +173 -0
- package/dist/mail/send.js.map +1 -0
- package/dist/mail/smtp.d.ts +4 -0
- package/dist/mail/smtp.d.ts.map +1 -0
- package/dist/mail/smtp.js +133 -0
- package/dist/mail/smtp.js.map +1 -0
- package/dist/oauth.d.ts +74 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +230 -0
- package/dist/oauth.js.map +1 -0
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +26 -4
- package/dist/program.js.map +1 -1
- package/dist/providers.d.ts +96 -9
- package/dist/providers.d.ts.map +1 -1
- package/dist/providers.js +69 -16
- package/dist/providers.js.map +1 -1
- package/dist/reasons.d.ts +9 -0
- package/dist/reasons.d.ts.map +1 -0
- package/dist/reasons.js +27 -0
- package/dist/reasons.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +7 -5
- package/skills/mail-cli/SKILL.md +30 -3
- package/dist/bundle/chunk-YD5WV757.js +0 -27
- package/dist/bundle/command-contract-GPUED3GT.js +0 -34
- package/dist/bundle/first-screen-M7MT776O.js +0 -32
- package/dist/bundle/server-4JMHDHZ7.js +0 -63
- package/dist/bundle/store-maintenance-command-OFRPORN2.js +0 -52
- /package/dist/bundle/{chunk-NPGVOZVK.js → chunk-WJWLHLQ7.js} +0 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { CliError } from "@wirecat/cli-base";
|
|
2
|
+
import { annotate } from "@wirecat/cli-base/commands";
|
|
3
|
+
import { formatReference, normalizeTag, parseReference } from "@wirecat/cli-core";
|
|
4
|
+
import { answerEntity, itemOf, LOCAL_READ, LOCAL_WRITE, listOf, outputFor, queryTerms, renderAnswer, termField, withQuery, } from "@wirecat/cli-core/cli";
|
|
5
|
+
import { Command } from "commander";
|
|
6
|
+
import * as v from "valibot";
|
|
7
|
+
import { IDENTITY } from "../identity.js";
|
|
8
|
+
import { openMailStore } from "../store.js";
|
|
9
|
+
import { contextOf } from "./context.js";
|
|
10
|
+
const TYPES = ["message", "chat"];
|
|
11
|
+
const TAG_QUERY = {
|
|
12
|
+
entity: "mail_tag",
|
|
13
|
+
backend: "native",
|
|
14
|
+
fields: [termField("tag", "kw", "tag:work"), termField("type", "enum", "type:message", { values: TYPES })],
|
|
15
|
+
};
|
|
16
|
+
const mailTag = v.strictObject({
|
|
17
|
+
tag: v.string(),
|
|
18
|
+
type: v.picklist(TYPES),
|
|
19
|
+
target: v.string(),
|
|
20
|
+
name: v.nullable(v.string()),
|
|
21
|
+
created_at: v.string(),
|
|
22
|
+
});
|
|
23
|
+
const tagChange = v.strictObject({
|
|
24
|
+
target: v.string(),
|
|
25
|
+
added: v.optional(v.array(v.string())),
|
|
26
|
+
removed: v.optional(v.array(v.string())),
|
|
27
|
+
unchanged: v.array(v.string()),
|
|
28
|
+
});
|
|
29
|
+
const REF = "msg:email/me%40example.com/t1/m1";
|
|
30
|
+
const LIST_LIMIT = 100;
|
|
31
|
+
const MAX_LIST = 1_000;
|
|
32
|
+
const limitOf = (value) => {
|
|
33
|
+
if (!/^\d+$/.test(value.trim()) || Number(value) < 1 || Number(value) > MAX_LIST)
|
|
34
|
+
throw new CliError("validation_error", `--limit takes a whole number from 1 to ${MAX_LIST}`, { param: "limit" });
|
|
35
|
+
return Number(value);
|
|
36
|
+
};
|
|
37
|
+
/** The profile's own mailbox in the shared store; the tags of mail go on its rows, as memo's do. */
|
|
38
|
+
const withMailbox = async (command, work) => {
|
|
39
|
+
const context = contextOf(command);
|
|
40
|
+
const address = context.settings.mailbox.address;
|
|
41
|
+
if (!address)
|
|
42
|
+
throw new CliError("configuration_error", `profile ${context.profile} has no address`);
|
|
43
|
+
const store = await openMailStore(context.env);
|
|
44
|
+
try {
|
|
45
|
+
return await work(store, { provider: "email", account: address.toLowerCase() });
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
await store.close();
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const targetOf = (key, { message, chat }) => {
|
|
52
|
+
if ((message === undefined) === (chat === undefined))
|
|
53
|
+
throw new CliError("validation_error", "name one email with --message, or one conversation with --chat");
|
|
54
|
+
const place = parseReference((message ?? chat));
|
|
55
|
+
if (message !== undefined && place.type !== "message")
|
|
56
|
+
throw new CliError("validation_error", `${message} names no email — give the msg:email/… reference`, {
|
|
57
|
+
param: "message",
|
|
58
|
+
});
|
|
59
|
+
if (chat !== undefined && place.type !== "chat")
|
|
60
|
+
throw new CliError("validation_error", `${chat} names no conversation — give the chat:email/… reference`, {
|
|
61
|
+
param: "chat",
|
|
62
|
+
});
|
|
63
|
+
if (place.type !== "message" && place.type !== "chat")
|
|
64
|
+
throw new CliError("validation_error", "no mail reference");
|
|
65
|
+
if (place.provider !== key.provider || place.account !== key.account)
|
|
66
|
+
throw new CliError("not_found", `${message ?? chat} is not mail of this profile's mailbox ${key.account}`);
|
|
67
|
+
return place.type === "message"
|
|
68
|
+
? { type: "message", chatId: place.chat, messageId: place.message }
|
|
69
|
+
: { type: "chat", chatId: place.chat };
|
|
70
|
+
};
|
|
71
|
+
const shown = (key, target) => target.type === "message"
|
|
72
|
+
? formatReference({ type: "message", ...key, chat: target.chatId, message: target.messageId })
|
|
73
|
+
: formatReference({ type: "chat", ...key, chat: target.chatId });
|
|
74
|
+
const change = (operation) => answerEntity(annotate(new Command(operation), {
|
|
75
|
+
effects: LOCAL_WRITE,
|
|
76
|
+
examples: [`${IDENTITY.command} ya tags ${operation} invoices --message ${REF}`],
|
|
77
|
+
}), "mail_tag_change", tagChange)
|
|
78
|
+
.summary(operation === "add" ? "tag one stored email or conversation" : "untag one stored email or conversation")
|
|
79
|
+
.description(operation === "add"
|
|
80
|
+
? "put your own tags on one stored email or conversation; they stay in the local store, never on the server"
|
|
81
|
+
: "take your own tags off one stored email or conversation")
|
|
82
|
+
.argument("<tag...>", "one or more tags: 1–32 letters a–z, digits and hyphens; upper case is lowered")
|
|
83
|
+
.option("--message <message>", "the email: its msg:email/… reference, as search messages shows it")
|
|
84
|
+
.option("--chat <chat>", "the conversation: its chat:email/… reference, as conversations list shows it")
|
|
85
|
+
.action(async function (given, options) {
|
|
86
|
+
const tags = [...new Set(given.map(normalizeTag))];
|
|
87
|
+
const done = await withMailbox(this, async (store, key) => {
|
|
88
|
+
const target = targetOf(key, options);
|
|
89
|
+
const changed = operation === "add"
|
|
90
|
+
? await store.tags.addTags(key, target, tags)
|
|
91
|
+
: await store.tags.removeTags(key, target, tags);
|
|
92
|
+
return { target: shown(key, target), changed };
|
|
93
|
+
});
|
|
94
|
+
const unchanged = tags.filter((tag) => !done.changed.includes(tag));
|
|
95
|
+
renderAnswer(this, outputFor(this), itemOf({
|
|
96
|
+
target: done.target,
|
|
97
|
+
...(operation === "add" ? { added: done.changed } : { removed: done.changed }),
|
|
98
|
+
unchanged,
|
|
99
|
+
}), () => `${done.target}: ${done.changed.length ? done.changed.join(", ") : "no tags changed"}\n`);
|
|
100
|
+
});
|
|
101
|
+
const listCommand = () => withQuery(answerEntity(annotate(new Command("list"), {
|
|
102
|
+
effects: LOCAL_READ,
|
|
103
|
+
examples: [`${IDENTITY.command} ya tags list`, `${IDENTITY.command} ya tags list tag:invoices`],
|
|
104
|
+
}), "mail_tag", mailTag)
|
|
105
|
+
.summary("your tagged emails and conversations")
|
|
106
|
+
.description("the emails and conversations of this mailbox you tagged; search messages tag:<tag> finds them too")
|
|
107
|
+
.option("--limit <n>", `at most this many (default ${LIST_LIMIT}, at most ${MAX_LIST})`, limitOf), TAG_QUERY).action(async function (words, options) {
|
|
108
|
+
const terms = queryTerms(words, TAG_QUERY, "tags list");
|
|
109
|
+
const tag = terms.get("tag");
|
|
110
|
+
const type = terms.get("type");
|
|
111
|
+
const limit = options.limit ?? LIST_LIMIT;
|
|
112
|
+
const items = await withMailbox(this, async (store, key) => {
|
|
113
|
+
const rows = (await Promise.all((type === undefined ? TYPES : [type]).map((one) => store.tags.tags(key, {
|
|
114
|
+
...(tag === undefined ? {} : { tag: normalizeTag(tag) }),
|
|
115
|
+
type: one,
|
|
116
|
+
window: { limit: limit + 1, offset: 0 },
|
|
117
|
+
})))).flat();
|
|
118
|
+
return rows.map((row) => {
|
|
119
|
+
const target = row.type === "message"
|
|
120
|
+
? { type: "message", chatId: row.chatId, messageId: row.messageId }
|
|
121
|
+
: { type: "chat", chatId: row.chatId };
|
|
122
|
+
return {
|
|
123
|
+
tag: row.tag,
|
|
124
|
+
type: target.type,
|
|
125
|
+
target: shown(key, target),
|
|
126
|
+
name: row.chatTitle ?? null,
|
|
127
|
+
created_at: row.createdAt,
|
|
128
|
+
};
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
renderAnswer(this, outputFor(this), listOf("tags list", { items: items.slice(0, limit), limit, has_more: items.length > limit }), () => items.length === 0
|
|
132
|
+
? "nothing is tagged — tags add <tag> --message <ref> tags an email\n"
|
|
133
|
+
: `${items
|
|
134
|
+
.slice(0, limit)
|
|
135
|
+
.map((one) => `${one.tag} ${one.type} ${one.target}`)
|
|
136
|
+
.join("\n")}\n`);
|
|
137
|
+
});
|
|
138
|
+
export const tagsCommand = () => annotate(new Command("tags"), { effects: LOCAL_READ })
|
|
139
|
+
.summary("your own tags on stored mail, local only, shared with memo")
|
|
140
|
+
.description("your own tags on stored mail, kept in the local store and shared with memo; never sent to the server")
|
|
141
|
+
.addCommand(change("add"))
|
|
142
|
+
.addCommand(change("remove"))
|
|
143
|
+
.addCommand(listCommand());
|
|
144
|
+
//# sourceMappingURL=tags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tags.js","sourceRoot":"","sources":["../../src/commands/tags.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
import { type Settings } from "@wirecat/cli-core/cli";
|
|
2
2
|
import * as v from "valibot";
|
|
3
|
+
/** Checked beside `messages.send` and `messages.forward` when the mail reaches anyone but the owner. */
|
|
4
|
+
export declare const SEND_OTHERS_KEY = "messages.send.others";
|
|
5
|
+
/** Where the app password goes, which app signs in, and who an agent may mail: an agent holding `mcp.authority` changes neither. */
|
|
6
|
+
export declare const OWNER_ONLY: {
|
|
7
|
+
settings: string[];
|
|
8
|
+
permissions: string[];
|
|
9
|
+
};
|
|
3
10
|
export interface Mailbox {
|
|
4
11
|
address?: string;
|
|
5
12
|
login?: string;
|
|
6
13
|
host?: string;
|
|
7
14
|
port?: number;
|
|
8
15
|
security?: "tls" | "starttls";
|
|
16
|
+
/** The submission server, for a mailbox whose provider the registry does not know. */
|
|
17
|
+
smtp?: {
|
|
18
|
+
host?: string;
|
|
19
|
+
port?: number;
|
|
20
|
+
security?: "tls" | "starttls";
|
|
21
|
+
};
|
|
9
22
|
/** How the profile signs in; a profile saved before this key existed uses an app password. */
|
|
10
23
|
auth: "app-password" | "oauth";
|
|
24
|
+
/** The owner's own Microsoft app, in place of WireCat's, for every OAuth sign-in after it is set. */
|
|
25
|
+
microsoftClientId?: string;
|
|
11
26
|
folders?: string[];
|
|
12
27
|
}
|
|
13
28
|
export declare const configuration: {
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,QAAQ,EAAe,MAAM,uBAAuB,CAAA;AACtF,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,QAAQ,EAAe,MAAM,uBAAuB,CAAA;AACtF,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAG5B,wGAAwG;AACxG,eAAO,MAAM,eAAe,yBAAyB,CAAA;AAErD,oIAAoI;AACpI,eAAO,MAAM,UAAU;IACrB,QAAQ;IAYR,WAAW;CACZ,CAAA;AAgBD,MAAM,WAAW,OAAO;IACtB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,KAAK,GAAG,UAAU,CAAA;IAC7B,sFAAsF;IACtF,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,KAAK,GAAG,UAAU,CAAA;KAAE,CAAA;IACtE,8FAA8F;IAC9F,IAAI,EAAE,cAAc,GAAG,OAAO,CAAA;IAC9B,qGAAqG;IACrG,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CACnB;AAED,eAAO,MAAM,aAAa;;iBAA0B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiEzD,CAAA;AAEF,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAA"}
|
package/dist/config.js
CHANGED
|
@@ -1,17 +1,50 @@
|
|
|
1
1
|
import { commandPermissions, settingsFor } from "@wirecat/cli-core/cli";
|
|
2
2
|
import * as v from "valibot";
|
|
3
3
|
import { IDENTITY } from "./identity.js";
|
|
4
|
+
/** Checked beside `messages.send` and `messages.forward` when the mail reaches anyone but the owner. */
|
|
5
|
+
export const SEND_OTHERS_KEY = "messages.send.others";
|
|
6
|
+
/** Where the app password goes, which app signs in, and who an agent may mail: an agent holding `mcp.authority` changes neither. */
|
|
7
|
+
export const OWNER_ONLY = {
|
|
8
|
+
settings: [
|
|
9
|
+
"address",
|
|
10
|
+
"login",
|
|
11
|
+
"imap_host",
|
|
12
|
+
"imap_port",
|
|
13
|
+
"imap_security",
|
|
14
|
+
"smtp_host",
|
|
15
|
+
"smtp_port",
|
|
16
|
+
"smtp_security",
|
|
17
|
+
"auth",
|
|
18
|
+
"microsoft_client_id",
|
|
19
|
+
],
|
|
20
|
+
permissions: [SEND_OTHERS_KEY],
|
|
21
|
+
};
|
|
4
22
|
const PROFILE_ENTRIES = {
|
|
5
23
|
address: v.optional(v.string()),
|
|
6
24
|
login: v.optional(v.string()),
|
|
7
25
|
imap_host: v.optional(v.string()),
|
|
8
26
|
imap_port: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1), v.maxValue(65535))),
|
|
9
27
|
imap_security: v.optional(v.picklist(["tls", "starttls"])),
|
|
28
|
+
smtp_host: v.optional(v.string()),
|
|
29
|
+
smtp_port: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1), v.maxValue(65535))),
|
|
30
|
+
smtp_security: v.optional(v.picklist(["tls", "starttls"])),
|
|
10
31
|
auth: v.optional(v.picklist(["app-password", "oauth"])),
|
|
32
|
+
microsoft_client_id: v.optional(v.pipe(v.string(), v.trim(), v.minLength(1))),
|
|
11
33
|
folders: v.optional(v.array(v.string())),
|
|
12
34
|
};
|
|
13
35
|
export const configuration = settingsFor(IDENTITY, {
|
|
14
|
-
|
|
36
|
+
// An ordinary change goes ahead, as tg's and drive's do; a deletion or a change of many asks (WC-PERM-22, NEED-2067 A).
|
|
37
|
+
// Mail to anyone but the owner asks, and the owner may allow it (NEED-1898); WC-PERM-22 would make it deny.
|
|
38
|
+
permissions: commandPermissions({
|
|
39
|
+
extra: ["messages.bulk", "messages.server-search", SEND_OTHERS_KEY],
|
|
40
|
+
defaults: {
|
|
41
|
+
"messages.delete": "ask",
|
|
42
|
+
"folders.delete": "ask",
|
|
43
|
+
"messages.bulk": "ask",
|
|
44
|
+
"drafts.delete": "ask",
|
|
45
|
+
[SEND_OTHERS_KEY]: "ask",
|
|
46
|
+
},
|
|
47
|
+
}),
|
|
15
48
|
profile: PROFILE_ENTRIES,
|
|
16
49
|
resolve: ({ fromLayers }) => {
|
|
17
50
|
const pick = (key) => fromLayers(key, undefined);
|
|
@@ -21,7 +54,11 @@ export const configuration = settingsFor(IDENTITY, {
|
|
|
21
54
|
const port = pick("imap_port");
|
|
22
55
|
const security = pick("imap_security");
|
|
23
56
|
const folders = pick("folders");
|
|
57
|
+
const smtpHost = pick("smtp_host");
|
|
58
|
+
const smtpPort = pick("smtp_port");
|
|
59
|
+
const smtpSecurity = pick("smtp_security");
|
|
24
60
|
const auth = pick("auth");
|
|
61
|
+
const microsoftClientId = pick("microsoft_client_id");
|
|
25
62
|
const defined = (key, value) => (value === undefined ? {} : { [key]: value });
|
|
26
63
|
return {
|
|
27
64
|
values: {
|
|
@@ -32,7 +69,17 @@ export const configuration = settingsFor(IDENTITY, {
|
|
|
32
69
|
...defined("port", port.value),
|
|
33
70
|
...defined("security", security.value),
|
|
34
71
|
...defined("folders", folders.value),
|
|
72
|
+
...(smtpHost.value === undefined && smtpPort.value === undefined && smtpSecurity.value === undefined
|
|
73
|
+
? {}
|
|
74
|
+
: {
|
|
75
|
+
smtp: {
|
|
76
|
+
...defined("host", smtpHost.value),
|
|
77
|
+
...defined("port", smtpPort.value),
|
|
78
|
+
...defined("security", smtpSecurity.value),
|
|
79
|
+
},
|
|
80
|
+
}),
|
|
35
81
|
auth: auth.value ?? "app-password",
|
|
82
|
+
...defined("microsoftClientId", microsoftClientId.value),
|
|
36
83
|
},
|
|
37
84
|
},
|
|
38
85
|
sources: {
|
|
@@ -42,7 +89,11 @@ export const configuration = settingsFor(IDENTITY, {
|
|
|
42
89
|
imap_port: port.from,
|
|
43
90
|
imap_security: security.from,
|
|
44
91
|
folders: folders.from,
|
|
92
|
+
smtp_host: smtpHost.from,
|
|
93
|
+
smtp_port: smtpPort.from,
|
|
94
|
+
smtp_security: smtpSecurity.from,
|
|
45
95
|
auth: auth.from,
|
|
96
|
+
microsoft_client_id: microsoftClientId.from,
|
|
46
97
|
},
|
|
47
98
|
};
|
|
48
99
|
},
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAiB,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACtF,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC,MAAM,eAAe,GAAG;IACtB,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC/B,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC7B,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACjC,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IACxF,aAAa,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC;IAC1D,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC;IACvD,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;CACzC,CAAA;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type ExportFormat = "mbox" | "maildir";
|
|
2
|
+
/**
|
|
3
|
+
* One message as mboxrd writes it (https://www.rfc-editor.org/rfc/rfc4155#appendix-A): a `From ` line, the bytes with
|
|
4
|
+
* every line that starts `From ` or `>…From ` pushed one `>` deeper so a reader can undo it, and a blank line after.
|
|
5
|
+
* The message keeps its own line endings, so a signature over the bytes still holds.
|
|
6
|
+
*/
|
|
7
|
+
export declare const mboxEntry: (raw: Uint8Array, receivedAt: number | null) => Buffer;
|
|
8
|
+
/** `Archive/2025` becomes `Archive.2025.mbox`; one file per folder, flat in the destination. */
|
|
9
|
+
export declare const mboxFile: (folder: string) => string;
|
|
10
|
+
/**
|
|
11
|
+
* Maildir++ (as Dovecot, mbsync, mu and notmuch read it): INBOX is the top directory and every other folder a
|
|
12
|
+
* `.Name` directory beside it, with `.` between levels.
|
|
13
|
+
*/
|
|
14
|
+
export declare const maildirDir: (folder: string) => string;
|
|
15
|
+
/** Windows file names cannot hold a colon, so the info separator is a semicolon there, as mbsync's Windows builds use. */
|
|
16
|
+
export declare const INFO_SEPARATOR: string;
|
|
17
|
+
/** Unique and the same on every run for one message, so a resumed export finds what it already wrote. */
|
|
18
|
+
export declare const maildirName: (receivedAt: number | null, validity: string, uid: number, read: boolean | null, flagged: boolean | null) => string;
|
|
19
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/export/format.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,CAAA;AAa7C;;;;GAIG;AACH,eAAO,MAAM,SAAS,QAAS,UAAU,cAAc,MAAM,GAAG,IAAI,KAAG,MAQtE,CAAA;AAID,gGAAgG;AAChG,eAAO,MAAM,QAAQ,WAAY,MAAM,KAAG,MAA+C,CAAA;AAEzF;;;GAGG;AACH,eAAO,MAAM,UAAU,WAAY,MAAM,KAAG,MACmD,CAAA;AAE/F,0HAA0H;AAC1H,eAAO,MAAM,cAAc,QAA2C,CAAA;AAItE,yGAAyG;AACzG,eAAO,MAAM,WAAW,eACV,MAAM,GAAG,IAAI,YACf,MAAM,OACX,MAAM,QACL,OAAO,GAAG,IAAI,WACX,OAAO,GAAG,IAAI,KACtB,MAIF,CAAA"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { hostname } from "node:os";
|
|
2
|
+
const ASCTIME_DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
3
|
+
const ASCTIME_MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
4
|
+
const asctime = (at) => {
|
|
5
|
+
const two = (n) => String(n).padStart(2, "0");
|
|
6
|
+
return (`${ASCTIME_DAYS[at.getUTCDay()]} ${ASCTIME_MONTHS[at.getUTCMonth()]} ${String(at.getUTCDate()).padStart(2, " ")} ` +
|
|
7
|
+
`${two(at.getUTCHours())}:${two(at.getUTCMinutes())}:${two(at.getUTCSeconds())} ${at.getUTCFullYear()}`);
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* One message as mboxrd writes it (https://www.rfc-editor.org/rfc/rfc4155#appendix-A): a `From ` line, the bytes with
|
|
11
|
+
* every line that starts `From ` or `>…From ` pushed one `>` deeper so a reader can undo it, and a blank line after.
|
|
12
|
+
* The message keeps its own line endings, so a signature over the bytes still holds.
|
|
13
|
+
*/
|
|
14
|
+
export const mboxEntry = (raw, receivedAt) => {
|
|
15
|
+
const body = Buffer.from(raw)
|
|
16
|
+
.toString("latin1")
|
|
17
|
+
.replace(/^(>*From )/gm, ">$1");
|
|
18
|
+
const eol = body.includes("\r\n") ? "\r\n" : "\n";
|
|
19
|
+
const closed = body.endsWith("\n") ? body : body + eol;
|
|
20
|
+
const date = receivedAt === null ? new Date(0) : new Date(receivedAt);
|
|
21
|
+
return Buffer.from(`From MAILER-DAEMON ${asctime(date)}${eol}${closed}${eol}`, "latin1");
|
|
22
|
+
};
|
|
23
|
+
const unsafe = /[\0/\\:*?"<>|]/g;
|
|
24
|
+
/** `Archive/2025` becomes `Archive.2025.mbox`; one file per folder, flat in the destination. */
|
|
25
|
+
export const mboxFile = (folder) => `${folder.replace(unsafe, ".")}.mbox`;
|
|
26
|
+
/**
|
|
27
|
+
* Maildir++ (as Dovecot, mbsync, mu and notmuch read it): INBOX is the top directory and every other folder a
|
|
28
|
+
* `.Name` directory beside it, with `.` between levels.
|
|
29
|
+
*/
|
|
30
|
+
export const maildirDir = (folder) => folder.toUpperCase() === "INBOX" ? "" : `.${folder.replace(unsafe, ".").replace(/^\.+/, "")}`;
|
|
31
|
+
/** Windows file names cannot hold a colon, so the info separator is a semicolon there, as mbsync's Windows builds use. */
|
|
32
|
+
export const INFO_SEPARATOR = process.platform === "win32" ? ";" : ":";
|
|
33
|
+
const flagsOf = (read, flagged) => `${flagged ? "F" : ""}${read ? "S" : ""}`;
|
|
34
|
+
/** Unique and the same on every run for one message, so a resumed export finds what it already wrote. */
|
|
35
|
+
export const maildirName = (receivedAt, validity, uid, read, flagged) => {
|
|
36
|
+
const host = hostname().replace(/[^A-Za-z0-9-]/g, "-") || "localhost";
|
|
37
|
+
const seconds = Math.floor((receivedAt ?? 0) / 1000);
|
|
38
|
+
return `${seconds}.V${validity}U${uid}.${host}${INFO_SEPARATOR}2,${flagsOf(read, flagged)}`;
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/export/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ExportFormat } from "./format.js";
|
|
2
|
+
export declare const JOURNAL = ".mail-export.jsonl";
|
|
3
|
+
/** One finished batch: the messages now safely in the destination, and for mbox how long the folder's file is. */
|
|
4
|
+
interface Batch {
|
|
5
|
+
folder: string;
|
|
6
|
+
validity: string;
|
|
7
|
+
uids: number[];
|
|
8
|
+
size?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const doneKey: (folder: string, validity: string, uid: number) => string;
|
|
11
|
+
export interface ExportJournal {
|
|
12
|
+
done: Set<string>;
|
|
13
|
+
/** mbox: the length each folder's file had after its last finished batch. */
|
|
14
|
+
sizes: Map<string, number>;
|
|
15
|
+
record(batch: Batch): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
export interface Destination {
|
|
18
|
+
path: string;
|
|
19
|
+
format: ExportFormat;
|
|
20
|
+
account: string;
|
|
21
|
+
/** `resume` goes on in a folder that holds an export; `replace` writes into any folder, over what has the same name. */
|
|
22
|
+
mode: "new" | "resume" | "replace";
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Decides whether the folder may be written into before anything is fetched. A folder with an export in it needs
|
|
26
|
+
* `--resume`; any other folder with something in it needs `--replace`.
|
|
27
|
+
*/
|
|
28
|
+
export declare const openJournal: ({ path, format, account, mode }: Destination) => Promise<ExportJournal>;
|
|
29
|
+
/** A crash can leave bytes after the last finished batch; cutting back to it keeps every message whole. */
|
|
30
|
+
export declare const cutTo: (file: string, size: number) => Promise<void>;
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=journal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal.d.ts","sourceRoot":"","sources":["../../src/export/journal.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE/C,eAAO,MAAM,OAAO,uBAAuB,CAAA;AAQ3C,kHAAkH;AAClH,UAAU,KAAK;IACb,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,eAAO,MAAM,OAAO,WAAY,MAAM,YAAY,MAAM,OAAO,MAAM,KAAG,MAA0C,CAAA;AAkBlH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACjB,6EAA6E;IAC7E,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC1B,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACpC;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,YAAY,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,wHAAwH;IACxH,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAA;CACnC;AAQD;;;GAGG;AACH,eAAO,MAAM,WAAW,oCAA2C,WAAW,KAAG,OAAO,CAAC,aAAa,CAkDrG,CAAA;AAED,2GAA2G;AAC3G,eAAO,MAAM,KAAK,SAAU,MAAM,QAAQ,MAAM,KAAG,OAAO,CAAC,IAAI,CAAyB,CAAA"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { appendFile, mkdir, open, readdir, readFile, rm, truncate } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { CliError } from "@wirecat/cli-base";
|
|
4
|
+
export const JOURNAL = ".mail-export.jsonl";
|
|
5
|
+
export const doneKey = (folder, validity, uid) => `${folder}\0${validity}\0${uid}`;
|
|
6
|
+
const parse = (text) => {
|
|
7
|
+
const lines = text.split("\n").filter(Boolean);
|
|
8
|
+
if (lines.length === 0)
|
|
9
|
+
return undefined;
|
|
10
|
+
const header = JSON.parse(lines[0]);
|
|
11
|
+
const batches = [];
|
|
12
|
+
for (const line of lines.slice(1)) {
|
|
13
|
+
try {
|
|
14
|
+
batches.push(JSON.parse(line));
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// A line cut short by a crash is a batch that never finished; its messages are written again.
|
|
18
|
+
break;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return { header, batches };
|
|
22
|
+
};
|
|
23
|
+
const exists = async (path) => readdir(path).catch((error) => {
|
|
24
|
+
if (error.code === "ENOENT")
|
|
25
|
+
return undefined;
|
|
26
|
+
throw error;
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* Decides whether the folder may be written into before anything is fetched. A folder with an export in it needs
|
|
30
|
+
* `--resume`; any other folder with something in it needs `--replace`.
|
|
31
|
+
*/
|
|
32
|
+
export const openJournal = async ({ path, format, account, mode }) => {
|
|
33
|
+
const entries = await exists(path);
|
|
34
|
+
const journalPath = join(path, JOURNAL);
|
|
35
|
+
const text = entries?.includes(JOURNAL) ? await readFile(journalPath, "utf8") : undefined;
|
|
36
|
+
const found = text === undefined ? undefined : parse(text);
|
|
37
|
+
if (mode === "resume") {
|
|
38
|
+
if (!found)
|
|
39
|
+
throw new CliError("not_found", `${path} holds no export to resume`, { param: "resume" });
|
|
40
|
+
if (found.header.format !== format || found.header.account !== account)
|
|
41
|
+
throw new CliError("validation_error", `${path} holds ${found.header.format} of ${found.header.account}; resume it with the same --format and profile`, { param: "resume" });
|
|
42
|
+
}
|
|
43
|
+
else if (mode === "new" && entries && entries.length > 0) {
|
|
44
|
+
throw new CliError("validation_error", found
|
|
45
|
+
? `${path} already holds an export; --resume goes on with it, --replace starts over in it`
|
|
46
|
+
: `${path} is not empty; --replace writes into it anyway, over files of the same name`, { param: "output", reason: "mail.export-destination-exists" });
|
|
47
|
+
}
|
|
48
|
+
await mkdir(path, { recursive: true, mode: 0o700 });
|
|
49
|
+
const start = mode === "resume" && found ? found : undefined;
|
|
50
|
+
if (!start) {
|
|
51
|
+
const head = { v: 1, format, account };
|
|
52
|
+
await rm(journalPath, { force: true });
|
|
53
|
+
await appendFile(journalPath, `${JSON.stringify(head)}\n`, { mode: 0o600 });
|
|
54
|
+
}
|
|
55
|
+
const done = new Set();
|
|
56
|
+
const sizes = new Map();
|
|
57
|
+
for (const batch of start?.batches ?? []) {
|
|
58
|
+
for (const uid of batch.uids)
|
|
59
|
+
done.add(doneKey(batch.folder, batch.validity, uid));
|
|
60
|
+
if (batch.size !== undefined)
|
|
61
|
+
sizes.set(batch.folder, batch.size);
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
done,
|
|
65
|
+
sizes,
|
|
66
|
+
record: async (batch) => {
|
|
67
|
+
const handle = await open(journalPath, "a", 0o600);
|
|
68
|
+
try {
|
|
69
|
+
await handle.appendFile(`${JSON.stringify(batch)}\n`);
|
|
70
|
+
await handle.sync();
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
await handle.close();
|
|
74
|
+
}
|
|
75
|
+
for (const uid of batch.uids)
|
|
76
|
+
done.add(doneKey(batch.folder, batch.validity, uid));
|
|
77
|
+
if (batch.size !== undefined)
|
|
78
|
+
sizes.set(batch.folder, batch.size);
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
/** A crash can leave bytes after the last finished batch; cutting back to it keeps every message whole. */
|
|
83
|
+
export const cutTo = (file, size) => truncate(file, size);
|
|
84
|
+
//# sourceMappingURL=journal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal.js","sourceRoot":"","sources":["../../src/export/journal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ExportFormat } from "./format.js";
|
|
2
|
+
import { type ExportJournal } from "./journal.js";
|
|
3
|
+
export interface Written {
|
|
4
|
+
folder: string;
|
|
5
|
+
validity: string;
|
|
6
|
+
uid: number;
|
|
7
|
+
receivedAt: number | null;
|
|
8
|
+
read: boolean | null;
|
|
9
|
+
flagged: boolean | null;
|
|
10
|
+
raw: Uint8Array;
|
|
11
|
+
}
|
|
12
|
+
/** Writes one folder's finished messages and only then notes them in the journal, so a crash repeats at most a batch. */
|
|
13
|
+
export declare const writeBatch: (format: ExportFormat, root: string, journal: ExportJournal, folder: string, validity: string, batch: Written[], replace: boolean) => Promise<void>;
|
|
14
|
+
//# sourceMappingURL=write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/export/write.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAgD,MAAM,aAAa,CAAA;AAC7F,OAAO,EAAS,KAAK,aAAa,EAAE,MAAM,cAAc,CAAA;AAExD,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACpB,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IACvB,GAAG,EAAE,UAAU,CAAA;CAChB;AA6CD,yHAAyH;AACzH,eAAO,MAAM,UAAU,WACb,YAAY,QACd,MAAM,WACH,aAAa,UACd,MAAM,YACJ,MAAM,SACT,OAAO,EAAE,WACP,OAAO,KACf,OAAO,CAAC,IAAI,CAGoD,CAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { chmod, mkdir, open, rename, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { maildirDir, maildirName, mboxEntry, mboxFile } from "./format.js";
|
|
4
|
+
import { cutTo } from "./journal.js";
|
|
5
|
+
const exists = (path) => stat(path).then(() => true, () => false);
|
|
6
|
+
const writeMbox = async (root, journal, folder, validity, batch) => {
|
|
7
|
+
const file = join(root, mboxFile(folder));
|
|
8
|
+
const size = journal.sizes.get(folder);
|
|
9
|
+
if (size !== undefined)
|
|
10
|
+
await cutTo(file, size);
|
|
11
|
+
const handle = await open(file, size === undefined ? "w" : "a", 0o600);
|
|
12
|
+
try {
|
|
13
|
+
await handle.appendFile(Buffer.concat(batch.map((one) => mboxEntry(one.raw, one.receivedAt))));
|
|
14
|
+
await handle.sync();
|
|
15
|
+
}
|
|
16
|
+
finally {
|
|
17
|
+
await handle.close();
|
|
18
|
+
}
|
|
19
|
+
await chmod(file, 0o600);
|
|
20
|
+
await journal.record({ folder, validity, uids: batch.map((one) => one.uid), size: (await stat(file)).size });
|
|
21
|
+
};
|
|
22
|
+
const writeMaildir = async (root, journal, folder, validity, batch, replace) => {
|
|
23
|
+
const base = join(root, maildirDir(folder));
|
|
24
|
+
for (const part of ["", "cur", "new", "tmp"])
|
|
25
|
+
await mkdir(join(base, part), { recursive: true, mode: 0o700 });
|
|
26
|
+
for (const one of batch) {
|
|
27
|
+
const name = maildirName(one.receivedAt, validity, one.uid, one.read, one.flagged);
|
|
28
|
+
const target = join(base, "cur", name);
|
|
29
|
+
// The name holds the folder's UIDVALIDITY and the UID, so a file already there is this message.
|
|
30
|
+
if (!replace && (await exists(target)))
|
|
31
|
+
continue;
|
|
32
|
+
const scratch = join(base, "tmp", name);
|
|
33
|
+
await writeFile(scratch, one.raw, { mode: 0o600 });
|
|
34
|
+
await rename(scratch, target);
|
|
35
|
+
}
|
|
36
|
+
await journal.record({ folder, validity, uids: batch.map((one) => one.uid) });
|
|
37
|
+
};
|
|
38
|
+
/** Writes one folder's finished messages and only then notes them in the journal, so a crash repeats at most a batch. */
|
|
39
|
+
export const writeBatch = (format, root, journal, folder, validity, batch, replace) => format === "mbox"
|
|
40
|
+
? writeMbox(root, journal, folder, validity, batch)
|
|
41
|
+
: writeMaildir(root, journal, folder, validity, batch, replace);
|
|
42
|
+
//# sourceMappingURL=write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/export/write.ts"],"names":[],"mappings":"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"}
|
package/dist/identity.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAIxD,eAAO,MAAM,OAAO,sBAAsB,CAAA;AAE1C,eAAO,MAAM,QAAQ,EAAE,WAatB,CAAA;AAED,eAAO,MAAM,KAAK,mBAA0D,CAAA"}
|
package/dist/identity.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { REASONS } from "./reasons.js";
|
|
1
2
|
import { VERSION } from "./version.js";
|
|
2
3
|
export const PACKAGE = "@wirecat/mail-cli";
|
|
3
4
|
export const IDENTITY = {
|
|
@@ -8,9 +9,11 @@ export const IDENTITY = {
|
|
|
8
9
|
version: VERSION,
|
|
9
10
|
issues: "https://github.com/WireCatLabs/mail-cli/issues/new",
|
|
10
11
|
messenger: false,
|
|
12
|
+
sends: true,
|
|
11
13
|
// One call to the source reads 60 messages on 4 connections: 5 to 12 s on Yandex 360 (cli-testing, performance/mail).
|
|
12
14
|
requestMs: 9_000,
|
|
13
15
|
contentLanguages: ["ru", "en"],
|
|
16
|
+
errors: { reasons: REASONS },
|
|
14
17
|
};
|
|
15
18
|
export const SKILL = new URL("../skills/mail-cli/SKILL.md", import.meta.url);
|
|
16
19
|
//# sourceMappingURL=identity.js.map
|
package/dist/identity.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,CAAC,MAAM,OAAO,GAAG,mBAAmB,CAAA;AAE1C,MAAM,CAAC,MAAM,QAAQ,GAAgB;IACnC,OAAO,EAAE,MAAM;IACf,OAAO,EAAE,UAAU;IACnB,SAAS,EAAE,MAAM;IACjB,WAAW,EAAE,oGAAoG;IACjH,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE,oDAAoD;IAC5D,SAAS,EAAE,KAAK;IAChB,sHAAsH;IACtH,SAAS,EAAE,KAAK;IAChB,gBAAgB,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,CAAC,MAAM,OAAO,GAAG,mBAAmB,CAAA;AAE1C,MAAM,CAAC,MAAM,QAAQ,GAAgB;IACnC,OAAO,EAAE,MAAM;IACf,OAAO,EAAE,UAAU;IACnB,SAAS,EAAE,MAAM;IACjB,WAAW,EAAE,oGAAoG;IACjH,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE,oDAAoD;IAC5D,SAAS,EAAE,KAAK;IAChB,KAAK,EAAE,IAAI;IACX,sHAAsH;IACtH,SAAS,EAAE,KAAK;IAChB,gBAAgB,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC;IAC9B,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE;CAC7B,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,6BAA6B,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAA"}
|