@wirecat/cli-memo 0.0.0-stage → 0.5.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 (191) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +314 -2
  3. package/dist/answers/command.d.ts +35 -0
  4. package/dist/answers/command.d.ts.map +1 -0
  5. package/dist/answers/command.js +117 -0
  6. package/dist/answers/command.js.map +1 -0
  7. package/dist/app.d.ts +9 -0
  8. package/dist/app.d.ts.map +1 -0
  9. package/dist/app.js +10 -0
  10. package/dist/app.js.map +1 -0
  11. package/dist/bin/memo.d.ts +3 -0
  12. package/dist/bin/memo.d.ts.map +1 -0
  13. package/dist/bin/memo.js +14 -0
  14. package/dist/bin/memo.js.map +1 -0
  15. package/dist/config.d.ts +39 -0
  16. package/dist/config.d.ts.map +1 -0
  17. package/dist/config.js +40 -0
  18. package/dist/config.js.map +1 -0
  19. package/dist/context/command.d.ts +6 -0
  20. package/dist/context/command.d.ts.map +1 -0
  21. package/dist/context/command.js +73 -0
  22. package/dist/context/command.js.map +1 -0
  23. package/dist/context/context.d.ts +28 -0
  24. package/dist/context/context.d.ts.map +1 -0
  25. package/dist/context/context.js +49 -0
  26. package/dist/context/context.js.map +1 -0
  27. package/dist/knowledge/command.d.ts +4 -0
  28. package/dist/knowledge/command.d.ts.map +1 -0
  29. package/dist/knowledge/command.js +158 -0
  30. package/dist/knowledge/command.js.map +1 -0
  31. package/dist/mail/command.d.ts +4 -0
  32. package/dist/mail/command.d.ts.map +1 -0
  33. package/dist/mail/command.js +61 -0
  34. package/dist/mail/command.js.map +1 -0
  35. package/dist/mail/gmail.d.ts +18 -0
  36. package/dist/mail/gmail.d.ts.map +1 -0
  37. package/dist/mail/gmail.js +103 -0
  38. package/dist/mail/gmail.js.map +1 -0
  39. package/dist/mail/himalaya.d.ts +4 -0
  40. package/dist/mail/himalaya.d.ts.map +1 -0
  41. package/dist/mail/himalaya.js +13 -0
  42. package/dist/mail/himalaya.js.map +1 -0
  43. package/dist/mail/import.d.ts +53 -0
  44. package/dist/mail/import.d.ts.map +1 -0
  45. package/dist/mail/import.js +170 -0
  46. package/dist/mail/import.js.map +1 -0
  47. package/dist/mail/parse.d.ts +21 -0
  48. package/dist/mail/parse.d.ts.map +1 -0
  49. package/dist/mail/parse.js +86 -0
  50. package/dist/mail/parse.js.map +1 -0
  51. package/dist/notes/about.d.ts +31 -0
  52. package/dist/notes/about.d.ts.map +1 -0
  53. package/dist/notes/about.js +69 -0
  54. package/dist/notes/about.js.map +1 -0
  55. package/dist/notes/bound.d.ts +24 -0
  56. package/dist/notes/bound.d.ts.map +1 -0
  57. package/dist/notes/bound.js +57 -0
  58. package/dist/notes/bound.js.map +1 -0
  59. package/dist/notes/command.d.ts +4 -0
  60. package/dist/notes/command.d.ts.map +1 -0
  61. package/dist/notes/command.js +222 -0
  62. package/dist/notes/command.js.map +1 -0
  63. package/dist/notes/dialects/common.d.ts +18 -0
  64. package/dist/notes/dialects/common.d.ts.map +1 -0
  65. package/dist/notes/dialects/common.js +79 -0
  66. package/dist/notes/dialects/common.js.map +1 -0
  67. package/dist/notes/dialects/index.d.ts +5 -0
  68. package/dist/notes/dialects/index.d.ts.map +1 -0
  69. package/dist/notes/dialects/index.js +6 -0
  70. package/dist/notes/dialects/index.js.map +1 -0
  71. package/dist/notes/dialects/markdown.d.ts +7 -0
  72. package/dist/notes/dialects/markdown.d.ts.map +1 -0
  73. package/dist/notes/dialects/markdown.js +51 -0
  74. package/dist/notes/dialects/markdown.js.map +1 -0
  75. package/dist/notes/dialects/obsidian.d.ts +6 -0
  76. package/dist/notes/dialects/obsidian.d.ts.map +1 -0
  77. package/dist/notes/dialects/obsidian.js +33 -0
  78. package/dist/notes/dialects/obsidian.js.map +1 -0
  79. package/dist/notes/dialects/types.d.ts +39 -0
  80. package/dist/notes/dialects/types.d.ts.map +1 -0
  81. package/dist/notes/dialects/types.js +2 -0
  82. package/dist/notes/dialects/types.js.map +1 -0
  83. package/dist/notes/embed.d.ts +51 -0
  84. package/dist/notes/embed.d.ts.map +1 -0
  85. package/dist/notes/embed.js +109 -0
  86. package/dist/notes/embed.js.map +1 -0
  87. package/dist/notes/export.d.ts +27 -0
  88. package/dist/notes/export.d.ts.map +1 -0
  89. package/dist/notes/export.js +76 -0
  90. package/dist/notes/export.js.map +1 -0
  91. package/dist/notes/files.d.ts +14 -0
  92. package/dist/notes/files.d.ts.map +1 -0
  93. package/dist/notes/files.js +77 -0
  94. package/dist/notes/files.js.map +1 -0
  95. package/dist/notes/folders-command.d.ts +4 -0
  96. package/dist/notes/folders-command.d.ts.map +1 -0
  97. package/dist/notes/folders-command.js +113 -0
  98. package/dist/notes/folders-command.js.map +1 -0
  99. package/dist/notes/folders.d.ts +27 -0
  100. package/dist/notes/folders.d.ts.map +1 -0
  101. package/dist/notes/folders.js +46 -0
  102. package/dist/notes/folders.js.map +1 -0
  103. package/dist/notes/import.d.ts +33 -0
  104. package/dist/notes/import.d.ts.map +1 -0
  105. package/dist/notes/import.js +183 -0
  106. package/dist/notes/import.js.map +1 -0
  107. package/dist/notes/internal.d.ts +17 -0
  108. package/dist/notes/internal.d.ts.map +1 -0
  109. package/dist/notes/internal.js +47 -0
  110. package/dist/notes/internal.js.map +1 -0
  111. package/dist/notes/links.d.ts +18 -0
  112. package/dist/notes/links.d.ts.map +1 -0
  113. package/dist/notes/links.js +44 -0
  114. package/dist/notes/links.js.map +1 -0
  115. package/dist/notes/renames.d.ts +11 -0
  116. package/dist/notes/renames.d.ts.map +1 -0
  117. package/dist/notes/renames.js +24 -0
  118. package/dist/notes/renames.js.map +1 -0
  119. package/dist/notes/search.d.ts +5 -0
  120. package/dist/notes/search.d.ts.map +1 -0
  121. package/dist/notes/search.js +20 -0
  122. package/dist/notes/search.js.map +1 -0
  123. package/dist/notes/state.d.ts +14 -0
  124. package/dist/notes/state.d.ts.map +1 -0
  125. package/dist/notes/state.js +21 -0
  126. package/dist/notes/state.js.map +1 -0
  127. package/dist/options.d.ts +4 -0
  128. package/dist/options.d.ts.map +1 -0
  129. package/dist/options.js +12 -0
  130. package/dist/options.js.map +1 -0
  131. package/dist/people/command.d.ts +5 -0
  132. package/dist/people/command.d.ts.map +1 -0
  133. package/dist/people/command.js +57 -0
  134. package/dist/people/command.js.map +1 -0
  135. package/dist/people/identity.d.ts +4 -0
  136. package/dist/people/identity.d.ts.map +1 -0
  137. package/dist/people/identity.js +13 -0
  138. package/dist/people/identity.js.map +1 -0
  139. package/dist/people/notes-map.d.ts +13 -0
  140. package/dist/people/notes-map.d.ts.map +1 -0
  141. package/dist/people/notes-map.js +49 -0
  142. package/dist/people/notes-map.js.map +1 -0
  143. package/dist/people/subject.d.ts +8 -0
  144. package/dist/people/subject.d.ts.map +1 -0
  145. package/dist/people/subject.js +19 -0
  146. package/dist/people/subject.js.map +1 -0
  147. package/dist/program.d.ts +7 -0
  148. package/dist/program.d.ts.map +1 -0
  149. package/dist/program.js +34 -0
  150. package/dist/program.js.map +1 -0
  151. package/dist/run/auto.d.ts +20 -0
  152. package/dist/run/auto.d.ts.map +1 -0
  153. package/dist/run/auto.js +139 -0
  154. package/dist/run/auto.js.map +1 -0
  155. package/dist/run/import.d.ts +18 -0
  156. package/dist/run/import.d.ts.map +1 -0
  157. package/dist/run/import.js +114 -0
  158. package/dist/run/import.js.map +1 -0
  159. package/dist/search/command.d.ts +38 -0
  160. package/dist/search/command.d.ts.map +1 -0
  161. package/dist/search/command.js +269 -0
  162. package/dist/search/command.js.map +1 -0
  163. package/dist/store/gone.d.ts +17 -0
  164. package/dist/store/gone.d.ts.map +1 -0
  165. package/dist/store/gone.js +52 -0
  166. package/dist/store/gone.js.map +1 -0
  167. package/dist/store/scope.d.ts +19 -0
  168. package/dist/store/scope.d.ts.map +1 -0
  169. package/dist/store/scope.js +34 -0
  170. package/dist/store/scope.js.map +1 -0
  171. package/dist/store/source-target.d.ts +18 -0
  172. package/dist/store/source-target.d.ts.map +1 -0
  173. package/dist/store/source-target.js +28 -0
  174. package/dist/store/source-target.js.map +1 -0
  175. package/dist/tags/command.d.ts +4 -0
  176. package/dist/tags/command.d.ts.map +1 -0
  177. package/dist/tags/command.js +166 -0
  178. package/dist/tags/command.js.map +1 -0
  179. package/dist/tasks/command.d.ts +4 -0
  180. package/dist/tasks/command.d.ts.map +1 -0
  181. package/dist/tasks/command.js +83 -0
  182. package/dist/tasks/command.js.map +1 -0
  183. package/dist/tasks/context.d.ts +16 -0
  184. package/dist/tasks/context.d.ts.map +1 -0
  185. package/dist/tasks/context.js +68 -0
  186. package/dist/tasks/context.js.map +1 -0
  187. package/dist/version.d.ts +2 -0
  188. package/dist/version.d.ts.map +1 -0
  189. package/dist/version.js +2 -0
  190. package/dist/version.js.map +1 -0
  191. package/package.json +53 -4
@@ -0,0 +1,57 @@
1
+ import { join } from "node:path";
2
+ import { CliError } from "@wirecat/cli-core";
3
+ import { openStore } from "@wirecat/cli-messaging/store";
4
+ import { boundFolders, folderOfFile } from "../notes/bound.js";
5
+ import { folderNotes } from "../notes/import.js";
6
+ import { identityOf } from "./identity.js";
7
+ import { importNotesMap } from "./notes-map.js";
8
+ /** Who is who is linked in messaging (`tg contacts link`); the note about a person is an `about` link. */
9
+ export const noteCommand = (program, streams, env) => {
10
+ program
11
+ .command("note")
12
+ .description("Name the note that is about a person, or show it")
13
+ .argument("<identity>", "<messenger>:<name or id> of any identity of the person")
14
+ .argument("[path]", "the note about them, a file in a configured folder")
15
+ .option("--clear", "forget which file note is about them")
16
+ .action(async (identity, path, options) => {
17
+ const store = await openStore({ env });
18
+ try {
19
+ const folders = await boundFolders(store, env, { strict: false });
20
+ await importNotesMap(store, env, folders);
21
+ const person = await store.personOf(await identityOf(store, identity));
22
+ if (person === undefined)
23
+ throw new CliError("not_found", `the store has no person for "${identity}"`);
24
+ const to = `person:${person.uid}`;
25
+ const files = async () => {
26
+ const found = [];
27
+ for (const link of await store.notes.links({ to })) {
28
+ if (link.kind !== "about" || link.origin !== "owner")
29
+ continue;
30
+ const note = await store.notes.note(link.from.replace(/^note:/, "")).catch(() => undefined);
31
+ if (note?.source === "file" && note.deletedAt === null)
32
+ found.push({ link, note });
33
+ }
34
+ return found;
35
+ };
36
+ if (options.clear)
37
+ for (const { link } of await files())
38
+ await store.notes.removeLink(link.id);
39
+ else if (path !== undefined) {
40
+ const { folder, path: inside } = folderOfFile(folders, path);
41
+ const note = (await folderNotes(store, folder.id)).find((candidate) => candidate.path === inside);
42
+ if (!note)
43
+ throw new CliError("not_found", `${path} is not imported yet — memo notes import`);
44
+ await store.notes.addLink({ from: `note:${note.id}`, to, kind: "about", origin: "owner" });
45
+ }
46
+ const shown = (await files()).map(({ note }) => {
47
+ const folder = folders.find((candidate) => candidate.id === note.folderId);
48
+ return folder ? join(folder.path, note.path) : `note:${note.id}`;
49
+ });
50
+ streams.data(`${person.name ?? person.uid}: ${shown.join(", ") || "no note"}\n`);
51
+ }
52
+ finally {
53
+ await store.close();
54
+ }
55
+ });
56
+ };
57
+ //# sourceMappingURL=command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/people/command.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { IdentityRef, MessageStore } from "@wirecat/cli-messaging/store";
2
+ /** `telegram:Ana`, `max:12345`, `email:ana@example.com` — the messenger is always named. */
3
+ export declare const identityOf: (store: MessageStore, reference: string) => Promise<IdentityRef>;
4
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/people/identity.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAE7E,4FAA4F;AAC5F,eAAO,MAAM,UAAU,UAAiB,YAAY,aAAa,MAAM,KAAG,OAAO,CAAC,WAAW,CAQ5F,CAAA"}
@@ -0,0 +1,13 @@
1
+ import { CliError } from "@wirecat/cli-core";
2
+ import { pickPerson } from "@wirecat/cli-messaging";
3
+ /** `telegram:Ana`, `max:12345`, `email:ana@example.com` — the messenger is always named. */
4
+ export const identityOf = async (store, reference) => {
5
+ const match = /^([a-z][a-z0-9-]*):(.+)$/.exec(reference.trim());
6
+ if (match === null)
7
+ throw new CliError("validation_error", `"${reference}" names no messenger — write it as <messenger>:<name or id>`);
8
+ const [, provider = "", who = ""] = match;
9
+ const people = await store.people(provider);
10
+ const exact = people.get(provider === "email" ? who.toLowerCase() : who);
11
+ return { provider, id: exact?.id ?? pickPerson(who, people).id };
12
+ };
13
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/people/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAGnD,4FAA4F;AAC5F,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,KAAmB,EAAE,SAAiB,EAAwB,EAAE;IAC/F,MAAM,KAAK,GAAG,0BAA0B,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAA;IAC/D,IAAI,KAAK,KAAK,IAAI;QAChB,MAAM,IAAI,QAAQ,CAAC,kBAAkB,EAAE,IAAI,SAAS,6DAA6D,CAAC,CAAA;IACpH,MAAM,CAAC,EAAE,QAAQ,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,CAAC,GAAG,KAAK,CAAA;IACzC,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IACxE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,CAAA;AAClE,CAAC,CAAA"}
@@ -0,0 +1,13 @@
1
+ import type { MessageStore } from "@wirecat/cli-messaging/store";
2
+ import * as v from "valibot";
3
+ import { type BoundFolder } from "../notes/bound.js";
4
+ declare const NotesMapSchema: v.RecordSchema<v.StringSchema<undefined>, v.StringSchema<undefined>, undefined>;
5
+ /** Person uid → the note about them, as `memo note` kept it before the store could hold the link. */
6
+ export type NotesMap = v.InferOutput<typeof NotesMapSchema>;
7
+ /**
8
+ * Moves each entry of the old `people-notes.json` into the store as an `about` link, once. An entry whose
9
+ * note is not imported yet waits for a later run; the file itself is left as the owner wrote it.
10
+ */
11
+ export declare const importNotesMap: (store: MessageStore, env: NodeJS.ProcessEnv, folders: BoundFolder[]) => Promise<number>;
12
+ export {};
13
+ //# sourceMappingURL=notes-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notes-map.d.ts","sourceRoot":"","sources":["../../src/people/notes-map.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAChE,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAC5B,OAAO,EAAE,KAAK,WAAW,EAAgB,MAAM,mBAAmB,CAAA;AAGlE,QAAA,MAAM,cAAc,iFAAmC,CAAA;AAEvD,qGAAqG;AACrG,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,cAAc,CAAC,CAAA;AAQ3D;;;GAGG;AACH,eAAO,MAAM,cAAc,UAClB,YAAY,OACd,MAAM,CAAC,UAAU,WACb,WAAW,EAAE,KACrB,OAAO,CAAC,MAAM,CAgChB,CAAA"}
@@ -0,0 +1,49 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { loadConfigFile, resolvePaths } from "@wirecat/cli-core";
4
+ import * as v from "valibot";
5
+ import { folderOfFile } from "../notes/bound.js";
6
+ import { folderNotes } from "../notes/import.js";
7
+ const NotesMapSchema = v.record(v.string(), v.string());
8
+ const mapPath = (env) => join(resolvePaths({ appName: "cli-memo", prefix: "MEMO", env }).config, "people-notes.json");
9
+ const donePath = (env) => join(resolvePaths({ appName: "cli-memo", prefix: "MEMO", env }).state, "people-notes-imported.json");
10
+ /**
11
+ * Moves each entry of the old `people-notes.json` into the store as an `about` link, once. An entry whose
12
+ * note is not imported yet waits for a later run; the file itself is left as the owner wrote it.
13
+ */
14
+ export const importNotesMap = async (store, env, folders) => {
15
+ if (!existsSync(mapPath(env)))
16
+ return 0;
17
+ const map = loadConfigFile(mapPath(env), NotesMapSchema, () => ({}));
18
+ let done = [];
19
+ try {
20
+ done = JSON.parse(readFileSync(donePath(env), "utf8"));
21
+ }
22
+ catch { }
23
+ const pending = Object.entries(map).filter(([uid]) => !done.includes(uid));
24
+ if (pending.length === 0)
25
+ return 0;
26
+ const byFolder = new Map();
27
+ let linked = 0;
28
+ for (const [uid, file] of pending) {
29
+ let place;
30
+ try {
31
+ place = folderOfFile(folders, file);
32
+ }
33
+ catch {
34
+ continue;
35
+ }
36
+ if (!byFolder.has(place.folder.id))
37
+ byFolder.set(place.folder.id, new Map((await folderNotes(store, place.folder.id)).map((note) => [note.path, note.id])));
38
+ const id = byFolder.get(place.folder.id)?.get(place.path);
39
+ if (id === undefined)
40
+ continue;
41
+ await store.notes.addLink({ from: `note:${id}`, to: `person:${uid}`, kind: "about", origin: "owner" });
42
+ done.push(uid);
43
+ linked++;
44
+ }
45
+ mkdirSync(join(donePath(env), ".."), { recursive: true });
46
+ writeFileSync(donePath(env), JSON.stringify(done));
47
+ return linked;
48
+ };
49
+ //# sourceMappingURL=notes-map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notes-map.js","sourceRoot":"","sources":["../../src/people/notes-map.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { MessageStore, PersonRecord } from "@wirecat/cli-messaging/store";
2
+ export interface Subject {
3
+ ref: string;
4
+ person?: PersonRecord;
5
+ }
6
+ /** A typed reference as written, or `<messenger>:<name or id>` turned into the person behind it. */
7
+ export declare const subjectOf: (store: MessageStore, text: string) => Promise<Subject>;
8
+ //# sourceMappingURL=subject.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subject.d.ts","sourceRoot":"","sources":["../../src/people/subject.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAK9E,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,YAAY,CAAA;CACtB;AAED,oGAAoG;AACpG,eAAO,MAAM,SAAS,UAAiB,YAAY,QAAQ,MAAM,KAAG,OAAO,CAAC,OAAO,CAYlF,CAAA"}
@@ -0,0 +1,19 @@
1
+ import { formatReference } from "@wirecat/cli-messaging";
2
+ import { identityOf } from "./identity.js";
3
+ const TYPED = /^(person|entity|note|task|msg|chat|contact|folder):\S+$/;
4
+ /** A typed reference as written, or `<messenger>:<name or id>` turned into the person behind it. */
5
+ export const subjectOf = async (store, text) => {
6
+ const typed = text.trim();
7
+ if (typed.startsWith("person:")) {
8
+ const person = await store.personByUid(typed.slice("person:".length));
9
+ return person === undefined ? { ref: typed } : { ref: typed, person };
10
+ }
11
+ if (TYPED.test(typed))
12
+ return { ref: typed };
13
+ const identity = await identityOf(store, text);
14
+ const person = await store.personOf(identity);
15
+ return person === undefined
16
+ ? { ref: formatReference({ type: "contact", provider: identity.provider, id: identity.id }) }
17
+ : { ref: `person:${person.uid}`, person };
18
+ };
19
+ //# sourceMappingURL=subject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subject.js","sourceRoot":"","sources":["../../src/people/subject.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAExD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE1C,MAAM,KAAK,GAAG,yDAAyD,CAAA;AAOvE,oGAAoG;AACpG,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,EAAE,KAAmB,EAAE,IAAY,EAAoB,EAAE;IACrF,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;IACzB,IAAI,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAA;QACrE,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;IACvE,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAA;IAC5C,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;IAC9C,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;IAC7C,OAAO,MAAM,KAAK,SAAS;QACzB,CAAC,CAAC,EAAE,GAAG,EAAE,eAAe,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,EAAE;QAC7F,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,MAAM,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,CAAA;AAC7C,CAAC,CAAA"}
@@ -0,0 +1,7 @@
1
+ import { type Streams } from "@wirecat/cli-core";
2
+ import { Command } from "commander";
3
+ export declare const createProgram: ({ streams, env, }?: {
4
+ streams?: Streams;
5
+ env?: NodeJS.ProcessEnv;
6
+ }) => Command;
7
+ //# sourceMappingURL=program.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAenC,eAAO,MAAM,aAAa,uBAGvB;IACD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CACxB,KAAQ,OAmBR,CAAA"}
@@ -0,0 +1,34 @@
1
+ import { processStreams } from "@wirecat/cli-core";
2
+ import { Command } from "commander";
3
+ import { askCommand } from "./answers/command.js";
4
+ import { contextCommand } from "./context/command.js";
5
+ import { knowledgeCommands } from "./knowledge/command.js";
6
+ import { mailCommand } from "./mail/command.js";
7
+ import { notesCommand } from "./notes/command.js";
8
+ import { foldersCommand } from "./notes/folders-command.js";
9
+ import { noteCommand } from "./people/command.js";
10
+ import { autoCommand } from "./run/auto.js";
11
+ import { importCommand } from "./run/import.js";
12
+ import { searchCommand } from "./search/command.js";
13
+ import { tagsCommand } from "./tags/command.js";
14
+ import { tasksCommand } from "./tasks/command.js";
15
+ import { VERSION } from "./version.js";
16
+ export const createProgram = ({ streams = processStreams, env = process.env, } = {}) => {
17
+ const program = new Command("memo")
18
+ .description("Context about people across messengers, notes and mail")
19
+ .version(VERSION);
20
+ contextCommand(program, streams, env);
21
+ notesCommand(program, streams, env);
22
+ foldersCommand(program, streams, env);
23
+ mailCommand(program, streams, env);
24
+ noteCommand(program, streams, env);
25
+ tagsCommand(program, streams, env);
26
+ tasksCommand(program, streams, env);
27
+ knowledgeCommands(program, streams, env);
28
+ searchCommand(program, streams, env);
29
+ askCommand(program, streams, env);
30
+ importCommand(program, streams, env);
31
+ autoCommand(program, streams, env);
32
+ return program;
33
+ };
34
+ //# sourceMappingURL=program.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"program.js","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAgB,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,EAC5B,OAAO,GAAG,cAAc,EACxB,GAAG,GAAG,OAAO,CAAC,GAAG,GAClB,GAGG,EAAE,EAAW,EAAE;IACjB,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;SAChC,WAAW,CAAC,wDAAwD,CAAC;SACrE,OAAO,CAAC,OAAO,CAAC,CAAA;IAEnB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IACrC,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IACnC,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IACrC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IAClC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IAClC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IAClC,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IACnC,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IACxC,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IACpC,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IACjC,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IACpC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IAElC,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA"}
@@ -0,0 +1,20 @@
1
+ import { type Streams } from "@wirecat/cli-core";
2
+ import { type Command } from "commander";
3
+ import { type Config } from "../config.js";
4
+ export declare const DEFAULT_EVERY = "5m";
5
+ /** `5m`, `90s`, `1h` → systemd's `5min`, `90s`, `1h`; under a minute is refused. */
6
+ export declare const interval: (value: string) => string;
7
+ export declare const serviceUnit: (env: NodeJS.ProcessEnv) => string;
8
+ export declare const timerUnit: (every: string) => string;
9
+ export interface AutoState {
10
+ enabled: boolean;
11
+ every: string;
12
+ }
13
+ export declare const autoState: (config: Config) => AutoState;
14
+ /**
15
+ * Makes the timer match the config: on with its interval, or gone. The config is the one source, so a
16
+ * hand edit of `auto` takes effect at the next timer run, which calls this first.
17
+ */
18
+ export declare const applyAuto: (env: NodeJS.ProcessEnv, state: AutoState) => Promise<void>;
19
+ export declare const autoCommand: (program: Command, streams: Streams, env: NodeJS.ProcessEnv) => void;
20
+ //# sourceMappingURL=auto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto.d.ts","sourceRoot":"","sources":["../../src/run/auto.ts"],"names":[],"mappings":"AAKA,OAAO,EAA4B,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAC1E,OAAO,EAAE,KAAK,OAAO,EAAwB,MAAM,WAAW,CAAA;AAC9D,OAAO,EAAE,KAAK,MAAM,EAA4B,MAAM,cAAc,CAAA;AAEpE,eAAO,MAAM,aAAa,OAAO,CAAA;AAGjC,oFAAoF;AACpF,eAAO,MAAM,QAAQ,UAAW,MAAM,KAAG,MAKxC,CAAA;AAWD,eAAO,MAAM,WAAW,QAAS,MAAM,CAAC,UAAU,KAAG,MAYvC,CAAA;AAEd,eAAO,MAAM,SAAS,UAAW,MAAM,KAAG,MAa5B,CAAA;AAad,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,eAAO,MAAM,SAAS,WAAY,MAAM,KAAG,SAGzC,CAAA;AAEF;;;GAGG;AACH,eAAO,MAAM,SAAS,QAAe,MAAM,CAAC,UAAU,SAAS,SAAS,KAAG,OAAO,CAAC,IAAI,CAwBtF,CAAA;AAED,eAAO,MAAM,WAAW,YAAa,OAAO,WAAW,OAAO,OAAO,MAAM,CAAC,UAAU,KAAG,IAiExF,CAAA"}
@@ -0,0 +1,139 @@
1
+ import { execFile } from "node:child_process";
2
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { CliError, createRenderer } from "@wirecat/cli-core";
7
+ import { InvalidArgumentError } from "commander";
8
+ import { loadConfig, updateConfig } from "../config.js";
9
+ export const DEFAULT_EVERY = "5m";
10
+ const UNIT = "memo-import";
11
+ /** `5m`, `90s`, `1h` → systemd's `5min`, `90s`, `1h`; under a minute is refused. */
12
+ export const interval = (value) => {
13
+ const match = /^(\d+)(s|m|h)$/.exec(value.trim());
14
+ const seconds = match === null ? 0 : Number(match[1]) * { s: 1, m: 60, h: 3600 }[match[2]];
15
+ if (seconds < 60)
16
+ throw new InvalidArgumentError("an interval of a minute or more, like 5m, 90s or 1h");
17
+ return value.trim();
18
+ };
19
+ const systemdSpan = (every) => every.replace(/m$/, "min");
20
+ const unitDir = (env) => join(env.XDG_CONFIG_HOME ?? join(env.HOME ?? homedir(), ".config"), "systemd", "user");
21
+ const quote = (arg) => `"${arg.replace(/(["\\])/g, "\\$1")}"`;
22
+ const memoBin = () => resolve(dirname(fileURLToPath(import.meta.url)), "../bin/memo.js");
23
+ export const serviceUnit = (env) => [
24
+ "[Unit]",
25
+ "Description=memo: import notes and mail into the shared store",
26
+ "",
27
+ "[Service]",
28
+ "Type=oneshot",
29
+ `ExecStart=${[process.execPath, memoBin(), "import"].map(quote).join(" ")}`,
30
+ // Himalaya and the keyring helper it calls are found on the PATH memo was set up with.
31
+ `Environment=${quote(`PATH=${env.PATH ?? ""}`)} MEMO_AUTO=1`,
32
+ "Nice=10",
33
+ "",
34
+ ].join("\n");
35
+ export const timerUnit = (every) => [
36
+ "[Unit]",
37
+ `Description=memo: import notes and mail every ${every}`,
38
+ "",
39
+ "[Timer]",
40
+ "OnActiveSec=1min",
41
+ `OnUnitActiveSec=${systemdSpan(every)}`,
42
+ "AccuracySec=30s",
43
+ "",
44
+ "[Install]",
45
+ "WantedBy=timers.target",
46
+ "",
47
+ ].join("\n");
48
+ const systemctl = (env) => (...args) => new Promise((done, fail) => execFile(env.MEMO_SYSTEMCTL ?? "systemctl", ["--user", ...args], { env }, (error, stdout, stderr) => error === null
49
+ ? done(stdout)
50
+ : fail(new CliError("provider_error", `systemctl ${args.join(" ")}: ${stderr.trim() || error.message}`))));
51
+ export const autoState = (config) => ({
52
+ enabled: config.auto?.enabled ?? false,
53
+ every: config.auto?.every ?? DEFAULT_EVERY,
54
+ });
55
+ /**
56
+ * Makes the timer match the config: on with its interval, or gone. The config is the one source, so a
57
+ * hand edit of `auto` takes effect at the next timer run, which calls this first.
58
+ */
59
+ export const applyAuto = async (env, state) => {
60
+ const run = systemctl(env);
61
+ const dir = unitDir(env);
62
+ const timerPath = join(dir, `${UNIT}.timer`);
63
+ const servicePath = join(dir, `${UNIT}.service`);
64
+ if (!state.enabled) {
65
+ if (!existsSync(timerPath) && !existsSync(servicePath))
66
+ return;
67
+ await run("disable", "--now", `${UNIT}.timer`).catch(() => "");
68
+ rmSync(timerPath, { force: true });
69
+ rmSync(servicePath, { force: true });
70
+ await run("daemon-reload");
71
+ return;
72
+ }
73
+ const wanted = { [servicePath]: serviceUnit(env), [timerPath]: timerUnit(state.every) };
74
+ const stale = Object.entries(wanted).filter(([path, text]) => !existsSync(path) || readFileSync(path, "utf8") !== text);
75
+ if (stale.length === 0)
76
+ return;
77
+ mkdirSync(dir, { recursive: true });
78
+ for (const [path, text] of stale)
79
+ writeFileSync(path, text);
80
+ await run("daemon-reload");
81
+ await run("enable", "--now", `${UNIT}.timer`);
82
+ // A timer already running keeps its old interval until restarted.
83
+ if (stale.some(([path]) => path === timerPath))
84
+ await run("restart", `${UNIT}.timer`);
85
+ };
86
+ export const autoCommand = (program, streams, env) => {
87
+ const run = systemctl(env);
88
+ const auto = program
89
+ .command("auto")
90
+ .description("Run memo import on a timer (systemd user timer); on/off and the interval live in the config");
91
+ auto
92
+ .command("on")
93
+ .description("Import every --every (default: auto.every in the config, else 5m), starting a minute from now")
94
+ .option("--every <interval>", "how often: 5m, 90s, 1h — a minute or more", interval)
95
+ .action(async (options) => {
96
+ const config = updateConfig((current) => ({ ...current, auto: { enabled: true, every: options.every ?? autoState(current).every } }), env);
97
+ await applyAuto(env, autoState(config));
98
+ streams.data(`memo import runs every ${autoState(config).every}.\n`);
99
+ });
100
+ auto
101
+ .command("off")
102
+ .description("Stop importing on a timer and remove the timer")
103
+ .action(async () => {
104
+ const config = updateConfig((current) => ({ ...current, auto: { ...current.auto, enabled: false } }), env);
105
+ await applyAuto(env, autoState(config));
106
+ streams.data("memo import no longer runs on a timer.\n");
107
+ });
108
+ auto
109
+ .command("status")
110
+ .description("Whether the timer is on, its interval, when it runs next and how the last run ended")
111
+ .option("--json", "print JSON")
112
+ .action(async (options) => {
113
+ const state = autoState(loadConfig(env));
114
+ const show = async (unit, properties) => Object.fromEntries((await run("show", unit, "--property", properties).catch(() => ""))
115
+ .split("\n")
116
+ .filter(Boolean)
117
+ .map((line) => [line.slice(0, line.indexOf("=")), line.slice(line.indexOf("=") + 1)]));
118
+ const timer = await show(`${UNIT}.timer`, "ActiveState");
119
+ const service = await show(`${UNIT}.service`, "Result");
120
+ // list-timers gives wall-clock times for every kind of timer; `show` leaves them empty for these.
121
+ const listed = JSON.parse((await run("list-timers", `${UNIT}.timer`, "--output=json").catch(() => "[]")) || "[]")[0];
122
+ const when = (micros) => typeof micros === "number" && micros > 0 ? new Date(micros / 1000).toISOString() : null;
123
+ const status = {
124
+ ...state,
125
+ timer: timer.ActiveState ?? "unknown",
126
+ next: when(listed?.next),
127
+ last: when(listed?.last),
128
+ lastResult: service.Result || null,
129
+ };
130
+ if (options.json)
131
+ createRenderer({ format: "json", color: false, streams }).result(status);
132
+ else
133
+ streams.data(`${status.enabled ? `on, every ${status.every}` : "off"} — timer ${status.timer}` +
134
+ (status.next ? `, next ${status.next}` : "") +
135
+ (status.last ? `, last ${status.last} (${status.lastResult ?? "?"})` : "") +
136
+ "\n");
137
+ });
138
+ };
139
+ //# sourceMappingURL=auto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto.js","sourceRoot":"","sources":["../../src/run/auto.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { type Streams } from "@wirecat/cli-core";
2
+ import type { Command } from "commander";
3
+ import { type ImportResult } from "../mail/import.js";
4
+ import { type NoteChunksEmbedded } from "../notes/embed.js";
5
+ import { type NotesImport } from "../notes/import.js";
6
+ export interface ImportRun {
7
+ notes: NotesImport[];
8
+ /** The notes' chunks embedded for search by meaning this run. */
9
+ notesEmbedded?: NoteChunksEmbedded;
10
+ mail: ImportResult[];
11
+ /** A source that failed; the others still ran. */
12
+ failed: {
13
+ source: string;
14
+ reason: string;
15
+ }[];
16
+ }
17
+ export declare const importCommand: (program: Command, streams: Streams, env: NodeJS.ProcessEnv) => void;
18
+ //# sourceMappingURL=import.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../src/run/import.ts"],"names":[],"mappings":"AACA,OAAO,EAA0C,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAGxF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGxC,OAAO,EAAE,KAAK,YAAY,EAAc,MAAM,mBAAmB,CAAA;AAEjE,OAAO,EAAmB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAE5E,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAOlE,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,WAAW,EAAE,CAAA;IACpB,iEAAiE;IACjE,aAAa,CAAC,EAAE,kBAAkB,CAAA;IAClC,IAAI,EAAE,YAAY,EAAE,CAAA;IACpB,kDAAkD;IAClD,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAC7C;AA4BD,eAAO,MAAM,aAAa,YAAa,OAAO,WAAW,OAAO,OAAO,MAAM,CAAC,UAAU,KAAG,IA8E1F,CAAA"}
@@ -0,0 +1,114 @@
1
+ import { join } from "node:path";
2
+ import { CliError, createRenderer, resolvePaths } from "@wirecat/cli-core";
3
+ import { releaseLock, takeLock } from "@wirecat/cli-messaging/background";
4
+ import { openStore } from "@wirecat/cli-messaging/store";
5
+ import { loadConfig } from "../config.js";
6
+ import { himalaya } from "../mail/himalaya.js";
7
+ import { importMail } from "../mail/import.js";
8
+ import { boundFolders } from "../notes/bound.js";
9
+ import { embedNoteChunks } from "../notes/embed.js";
10
+ import { noteFolders } from "../notes/folders.js";
11
+ import { importNotes } from "../notes/import.js";
12
+ import { importNotesMap } from "../people/notes-map.js";
13
+ import { applyAuto, autoState } from "./auto.js";
14
+ const DAY = 86_400_000;
15
+ const MAIL_WINDOW_DAYS = 30;
16
+ const text = (run) => [
17
+ ...run.notes.map((n) => `notes ${n.folder}: ${n.notes} notes, ${n.changed} changed, ${n.renamed} moved, ${n.deleted} gone` +
18
+ (n.deletionsSkipped === undefined ? "" : ` — deletions skipped: ${n.deletionsSkipped}`)),
19
+ ...(run.notesEmbedded === undefined
20
+ ? []
21
+ : [
22
+ `notes by meaning: ${run.notesEmbedded.chunks} chunks embedded` +
23
+ (run.notesEmbedded.notEmbedded !== undefined
24
+ ? ` — ${run.notesEmbedded.notEmbedded}`
25
+ : run.notesEmbedded.left
26
+ ? " — more next run"
27
+ : ""),
28
+ ]),
29
+ ...run.mail.map((m) => `mail ${m.account}: ${m.listed} listed, ${m.saved} new, ${m.deleted} gone` +
30
+ (m.complete ? "" : " — more to read next run") +
31
+ (m.deletionsSkipped === undefined ? "" : ` — deletions skipped: ${m.deletionsSkipped}`)),
32
+ ...run.failed.map(({ source, reason }) => `failed ${source}: ${reason}`),
33
+ ].join("\n") || "Nothing to import: set notes.folders or mail.accounts in the config.";
34
+ export const importCommand = (program, streams, env) => {
35
+ program
36
+ .command("import")
37
+ .description("Bring notes and mail up to date in the shared store — only what changed; the timer runs this")
38
+ .option("--notes", "notes only")
39
+ .option("--mail", "mail only")
40
+ .option("--no-embed", "skip embedding notes and mail for search by meaning this run")
41
+ .option("--json", "print JSON")
42
+ .action(async (options) => {
43
+ const both = !options.notes && !options.mail;
44
+ const config = loadConfig(env);
45
+ if (env.MEMO_AUTO === "1") {
46
+ await applyAuto(env, autoState(config));
47
+ if (!autoState(config).enabled)
48
+ return;
49
+ }
50
+ const lock = join(resolvePaths({ appName: "cli-memo", prefix: "MEMO", env }).state, "import.lock");
51
+ const holder = takeLock(lock, { pid: process.pid, startedAt: new Date().toISOString() });
52
+ if (holder !== undefined)
53
+ throw new CliError("rate_limited", `an import is already running (process ${holder.pid}); try again when it ends`);
54
+ const store = await openStore({ env });
55
+ const run = { notes: [], mail: [], failed: [] };
56
+ const attempt = async (source, work) => {
57
+ try {
58
+ await work();
59
+ }
60
+ catch (error) {
61
+ run.failed.push({ source, reason: error instanceof Error ? error.message : String(error) });
62
+ }
63
+ };
64
+ try {
65
+ if (both || options.notes) {
66
+ const folders = await boundFolders(store, env, { strict: false });
67
+ for (const folder of noteFolders(config.notes))
68
+ if (!folders.some(({ path }) => path === folder.path))
69
+ run.failed.push({
70
+ source: `notes ${folder.path}`,
71
+ reason: `no folder id — memo folders add ${folder.path}`,
72
+ });
73
+ for (const folder of folders)
74
+ await attempt(`notes ${folder.path}`, async () => {
75
+ run.notes.push(await importNotes(store, folder, { ignore: config.notes?.ignore ?? [], env }));
76
+ });
77
+ if (folders.length > 0)
78
+ await attempt("notes by meaning", async () => {
79
+ run.notesEmbedded = await embedNoteChunks(store, {
80
+ embed: options.embed && config.notes?.embed !== false,
81
+ env,
82
+ });
83
+ });
84
+ await attempt("people-notes.json", async () => {
85
+ await importNotesMap(store, env, folders);
86
+ });
87
+ }
88
+ if (both || options.mail) {
89
+ for (const account of config.mail?.accounts ?? [])
90
+ await attempt(`mail ${account.name}`, async () => {
91
+ run.mail.push(await importMail({
92
+ store,
93
+ run: himalaya(env),
94
+ account,
95
+ since: new Date(Date.now() - MAIL_WINDOW_DAYS * DAY),
96
+ env,
97
+ embed: options.embed,
98
+ }));
99
+ });
100
+ }
101
+ }
102
+ finally {
103
+ await store.close();
104
+ releaseLock(lock, process.pid);
105
+ }
106
+ if (options.json)
107
+ createRenderer({ format: "json", color: false, streams }).result(run);
108
+ else
109
+ streams.data(`${text(run)}\n`);
110
+ if (run.failed.length > 0)
111
+ process.exitCode = 1;
112
+ });
113
+ };
114
+ //# sourceMappingURL=import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import.js","sourceRoot":"","sources":["../../src/run/import.ts"],"names":[],"mappings":"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"}