@cad0p/napkin 0.8.1

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 (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +342 -0
  3. package/dist/commands/aliases.d.ts +7 -0
  4. package/dist/commands/aliases.js +25 -0
  5. package/dist/commands/bases.d.ts +23 -0
  6. package/dist/commands/bases.js +139 -0
  7. package/dist/commands/bookmarks.d.ts +15 -0
  8. package/dist/commands/bookmarks.js +51 -0
  9. package/dist/commands/canvas.d.ts +49 -0
  10. package/dist/commands/canvas.js +186 -0
  11. package/dist/commands/config.d.ts +13 -0
  12. package/dist/commands/config.js +48 -0
  13. package/dist/commands/crud.d.ts +40 -0
  14. package/dist/commands/crud.js +195 -0
  15. package/dist/commands/daily.d.ts +20 -0
  16. package/dist/commands/daily.js +58 -0
  17. package/dist/commands/files.d.ts +23 -0
  18. package/dist/commands/files.js +132 -0
  19. package/dist/commands/graph.d.ts +4 -0
  20. package/dist/commands/graph.js +461 -0
  21. package/dist/commands/init.d.ts +7 -0
  22. package/dist/commands/init.js +52 -0
  23. package/dist/commands/links.d.ts +26 -0
  24. package/dist/commands/links.js +119 -0
  25. package/dist/commands/outline.d.ts +7 -0
  26. package/dist/commands/outline.js +48 -0
  27. package/dist/commands/overview.d.ts +6 -0
  28. package/dist/commands/overview.js +40 -0
  29. package/dist/commands/properties.d.ts +24 -0
  30. package/dist/commands/properties.js +115 -0
  31. package/dist/commands/search.d.ts +13 -0
  32. package/dist/commands/search.js +48 -0
  33. package/dist/commands/tags.d.ts +13 -0
  34. package/dist/commands/tags.js +51 -0
  35. package/dist/commands/tasks.d.ts +22 -0
  36. package/dist/commands/tasks.js +106 -0
  37. package/dist/commands/templates.d.ts +16 -0
  38. package/dist/commands/templates.js +70 -0
  39. package/dist/commands/vault.d.ts +4 -0
  40. package/dist/commands/vault.js +17 -0
  41. package/dist/commands/wordcount.d.ts +7 -0
  42. package/dist/commands/wordcount.js +43 -0
  43. package/dist/core/aliases.d.ts +5 -0
  44. package/dist/core/aliases.js +26 -0
  45. package/dist/core/bases.d.ts +29 -0
  46. package/dist/core/bases.js +67 -0
  47. package/dist/core/bookmarks.d.ts +14 -0
  48. package/dist/core/bookmarks.js +34 -0
  49. package/dist/core/canvas.d.ts +74 -0
  50. package/dist/core/canvas.js +125 -0
  51. package/dist/core/config.d.ts +7 -0
  52. package/dist/core/config.js +35 -0
  53. package/dist/core/crud.d.ts +32 -0
  54. package/dist/core/crud.js +119 -0
  55. package/dist/core/daily.d.ts +12 -0
  56. package/dist/core/daily.js +102 -0
  57. package/dist/core/files.d.ts +15 -0
  58. package/dist/core/files.js +30 -0
  59. package/dist/core/init.d.ts +31 -0
  60. package/dist/core/init.js +119 -0
  61. package/dist/core/links.d.ts +11 -0
  62. package/dist/core/links.js +66 -0
  63. package/dist/core/outline.d.ts +3 -0
  64. package/dist/core/outline.js +12 -0
  65. package/dist/core/overview.d.ts +15 -0
  66. package/dist/core/overview.js +384 -0
  67. package/dist/core/properties.d.ts +14 -0
  68. package/dist/core/properties.js +60 -0
  69. package/dist/core/search.d.ts +17 -0
  70. package/dist/core/search.js +153 -0
  71. package/dist/core/tags.d.ts +11 -0
  72. package/dist/core/tags.js +40 -0
  73. package/dist/core/tasks.d.ts +35 -0
  74. package/dist/core/tasks.js +97 -0
  75. package/dist/core/templates.d.ts +14 -0
  76. package/dist/core/templates.js +55 -0
  77. package/dist/core/vault.d.ts +10 -0
  78. package/dist/core/vault.js +37 -0
  79. package/dist/core/wordcount.d.ts +5 -0
  80. package/dist/core/wordcount.js +16 -0
  81. package/dist/index.d.ts +17 -0
  82. package/dist/index.js +1 -0
  83. package/dist/main.d.ts +2 -0
  84. package/dist/main.js +715 -0
  85. package/dist/sdk.d.ts +179 -0
  86. package/dist/sdk.js +232 -0
  87. package/dist/templates/coding.d.ts +2 -0
  88. package/dist/templates/coding.js +104 -0
  89. package/dist/templates/company.d.ts +2 -0
  90. package/dist/templates/company.js +121 -0
  91. package/dist/templates/index.d.ts +4 -0
  92. package/dist/templates/index.js +15 -0
  93. package/dist/templates/personal.d.ts +2 -0
  94. package/dist/templates/personal.js +91 -0
  95. package/dist/templates/product.d.ts +2 -0
  96. package/dist/templates/product.js +123 -0
  97. package/dist/templates/research.d.ts +2 -0
  98. package/dist/templates/research.js +114 -0
  99. package/dist/templates/types.d.ts +7 -0
  100. package/dist/templates/types.js +1 -0
  101. package/dist/utils/bases.d.ts +61 -0
  102. package/dist/utils/bases.js +661 -0
  103. package/dist/utils/config.d.ts +42 -0
  104. package/dist/utils/config.js +112 -0
  105. package/dist/utils/exit-codes.d.ts +5 -0
  106. package/dist/utils/exit-codes.js +5 -0
  107. package/dist/utils/files.d.ts +135 -0
  108. package/dist/utils/files.js +299 -0
  109. package/dist/utils/formula.d.ts +28 -0
  110. package/dist/utils/formula.js +462 -0
  111. package/dist/utils/frontmatter.d.ts +17 -0
  112. package/dist/utils/frontmatter.js +34 -0
  113. package/dist/utils/markdown.d.ts +31 -0
  114. package/dist/utils/markdown.js +80 -0
  115. package/dist/utils/output.d.ts +28 -0
  116. package/dist/utils/output.js +48 -0
  117. package/dist/utils/search-cache.d.ts +29 -0
  118. package/dist/utils/search-cache.js +41 -0
  119. package/dist/utils/test-helpers.d.ts +13 -0
  120. package/dist/utils/test-helpers.js +40 -0
  121. package/dist/utils/vault.d.ts +21 -0
  122. package/dist/utils/vault.js +144 -0
  123. package/package.json +76 -0
@@ -0,0 +1,119 @@
1
+ import { Napkin } from "../sdk.js";
2
+ import { EXIT_NOT_FOUND, EXIT_USER_ERROR } from "../utils/exit-codes.js";
3
+ import { suggestFile } from "../utils/files.js";
4
+ import { dim, error, fileNotFound, output, } from "../utils/output.js";
5
+ export async function backlinks(opts) {
6
+ const n = new Napkin(opts.vault || process.cwd());
7
+ if (!opts.file) {
8
+ error("No file specified. Use --file <name>");
9
+ process.exit(EXIT_USER_ERROR);
10
+ }
11
+ let links;
12
+ try {
13
+ links = n.linksBack(opts.file);
14
+ }
15
+ catch (e) {
16
+ const msg = e.message;
17
+ if (msg.startsWith("File not found:")) {
18
+ fileNotFound(opts.file, suggestFile(n.vault.contentPath, opts.file));
19
+ process.exit(EXIT_NOT_FOUND);
20
+ }
21
+ throw e;
22
+ }
23
+ output(opts, {
24
+ json: () => (opts.total ? { total: links.length } : { backlinks: links }),
25
+ human: () => {
26
+ if (opts.total)
27
+ console.log(links.length);
28
+ else
29
+ for (const l of links)
30
+ console.log(l);
31
+ },
32
+ });
33
+ }
34
+ export async function links(opts) {
35
+ const n = new Napkin(opts.vault || process.cwd());
36
+ if (!opts.file) {
37
+ error("No file specified. Use --file <name>");
38
+ process.exit(EXIT_USER_ERROR);
39
+ }
40
+ let outgoing;
41
+ try {
42
+ outgoing = n.linksOut(opts.file);
43
+ }
44
+ catch (e) {
45
+ const msg = e.message;
46
+ if (msg.startsWith("File not found:")) {
47
+ fileNotFound(opts.file, suggestFile(n.vault.contentPath, opts.file));
48
+ process.exit(EXIT_NOT_FOUND);
49
+ }
50
+ throw e;
51
+ }
52
+ output(opts, {
53
+ json: () => (opts.total ? { total: outgoing.length } : { links: outgoing }),
54
+ human: () => {
55
+ if (opts.total)
56
+ console.log(outgoing.length);
57
+ else
58
+ for (const l of outgoing)
59
+ console.log(l);
60
+ },
61
+ });
62
+ }
63
+ export async function unresolvedLinks(opts) {
64
+ const n = new Napkin(opts.vault || process.cwd());
65
+ const entries = n.linksUnresolved();
66
+ output(opts, {
67
+ json: () => {
68
+ if (opts.total)
69
+ return { total: entries.length };
70
+ if (opts.counts || opts.verbose)
71
+ return {
72
+ unresolved: Object.fromEntries(entries.map(([k, v]) => [k, opts.verbose ? v : v.length])),
73
+ };
74
+ return { unresolved: entries.map(([k]) => k) };
75
+ },
76
+ human: () => {
77
+ if (opts.total) {
78
+ console.log(entries.length);
79
+ }
80
+ else {
81
+ for (const [target, sources] of entries) {
82
+ console.log(opts.counts ? `${target}\t${sources.length}` : target);
83
+ if (opts.verbose) {
84
+ for (const s of sources)
85
+ console.log(` ${dim(s)}`);
86
+ }
87
+ }
88
+ }
89
+ },
90
+ });
91
+ }
92
+ export async function orphans(opts) {
93
+ const n = new Napkin(opts.vault || process.cwd());
94
+ const result = n.orphans();
95
+ output(opts, {
96
+ json: () => (opts.total ? { total: result.length } : { orphans: result }),
97
+ human: () => {
98
+ if (opts.total)
99
+ console.log(result.length);
100
+ else
101
+ for (const f of result)
102
+ console.log(f);
103
+ },
104
+ });
105
+ }
106
+ export async function deadends(opts) {
107
+ const n = new Napkin(opts.vault || process.cwd());
108
+ const result = n.deadends();
109
+ output(opts, {
110
+ json: () => (opts.total ? { total: result.length } : { deadends: result }),
111
+ human: () => {
112
+ if (opts.total)
113
+ console.log(result.length);
114
+ else
115
+ for (const f of result)
116
+ console.log(f);
117
+ },
118
+ });
119
+ }
@@ -0,0 +1,7 @@
1
+ import { type OutputOptions } from "../utils/output.js";
2
+ export declare function outline(opts: OutputOptions & {
3
+ vault?: string;
4
+ file?: string;
5
+ format?: string;
6
+ total?: boolean;
7
+ }): Promise<void>;
@@ -0,0 +1,48 @@
1
+ import { Napkin } from "../sdk.js";
2
+ import { EXIT_NOT_FOUND, EXIT_USER_ERROR } from "../utils/exit-codes.js";
3
+ import { suggestFile } from "../utils/files.js";
4
+ import { error, fileNotFound, output, } from "../utils/output.js";
5
+ export async function outline(opts) {
6
+ const n = new Napkin(opts.vault || process.cwd());
7
+ if (!opts.file) {
8
+ error("No file specified. Use --file <name>");
9
+ process.exit(EXIT_USER_ERROR);
10
+ }
11
+ let headings;
12
+ try {
13
+ headings = n.outline(opts.file);
14
+ }
15
+ catch (e) {
16
+ const msg = e.message;
17
+ if (msg.startsWith("File not found:")) {
18
+ fileNotFound(opts.file, suggestFile(n.vault.contentPath, opts.file));
19
+ process.exit(EXIT_NOT_FOUND);
20
+ }
21
+ throw e;
22
+ }
23
+ output(opts, {
24
+ json: () => (opts.total ? { total: headings.length } : { headings }),
25
+ human: () => {
26
+ if (opts.total) {
27
+ console.log(headings.length);
28
+ return;
29
+ }
30
+ const fmt = opts.format || "tree";
31
+ if (fmt === "json") {
32
+ console.log(JSON.stringify(headings, null, 2));
33
+ }
34
+ else if (fmt === "md") {
35
+ for (const h of headings) {
36
+ console.log(`${"#".repeat(h.level)} ${h.text}`);
37
+ }
38
+ }
39
+ else {
40
+ // tree format
41
+ for (const h of headings) {
42
+ const indent = " ".repeat(h.level - 1);
43
+ console.log(`${indent}${h.text}`);
44
+ }
45
+ }
46
+ },
47
+ });
48
+ }
@@ -0,0 +1,6 @@
1
+ import { type OutputOptions } from "../utils/output.js";
2
+ export declare function overview(opts: OutputOptions & {
3
+ vault?: string;
4
+ depth?: string;
5
+ keywords?: string;
6
+ }): Promise<void>;
@@ -0,0 +1,40 @@
1
+ import { Napkin } from "../sdk.js";
2
+ import { bold, dim, output, warn, } from "../utils/output.js";
3
+ export async function overview(opts) {
4
+ const n = new Napkin(opts.vault || process.cwd());
5
+ const result = n.overview({
6
+ depth: opts.depth ? Number.parseInt(opts.depth, 10) : undefined,
7
+ keywords: opts.keywords ? Number.parseInt(opts.keywords, 10) : undefined,
8
+ });
9
+ for (const w of result.warnings ?? []) {
10
+ warn(w);
11
+ }
12
+ output(opts, {
13
+ json: () => result,
14
+ human: () => {
15
+ console.log(dim("WORKFLOW: overview (you are here) → search <query> → read <file>"));
16
+ console.log("");
17
+ if (result.context) {
18
+ console.log(bold("CONTEXT"));
19
+ console.log(result.context);
20
+ console.log("");
21
+ }
22
+ if (result.overview.length === 0) {
23
+ console.log("Empty vault");
24
+ return;
25
+ }
26
+ for (const f of result.overview) {
27
+ console.log(bold(f.path === "/" ? "./" : `${f.path}/`));
28
+ if (f.keywords.length > 0) {
29
+ console.log(` ${dim("keywords:")} ${f.keywords.join(", ")}`);
30
+ }
31
+ if (f.tags.length > 0) {
32
+ console.log(` ${dim("tags:")} ${f.tags.map((t) => `#${t}`).join(", ")}`);
33
+ }
34
+ console.log(` ${dim("notes:")} ${f.notes}`);
35
+ }
36
+ console.log("");
37
+ console.log(dim("HINT: Use napkin search <query> to find specific content. Use napkin read <file> to open a file."));
38
+ },
39
+ });
40
+ }
@@ -0,0 +1,24 @@
1
+ import { type OutputOptions } from "../utils/output.js";
2
+ export declare function properties(opts: OutputOptions & {
3
+ vault?: string;
4
+ file?: string;
5
+ counts?: boolean;
6
+ total?: boolean;
7
+ sort?: string;
8
+ }): Promise<void>;
9
+ export declare function propertySet(opts: OutputOptions & {
10
+ vault?: string;
11
+ file?: string;
12
+ name?: string;
13
+ value?: string;
14
+ }): Promise<void>;
15
+ export declare function propertyRemove(opts: OutputOptions & {
16
+ vault?: string;
17
+ file?: string;
18
+ name?: string;
19
+ }): Promise<void>;
20
+ export declare function propertyRead(opts: OutputOptions & {
21
+ vault?: string;
22
+ file?: string;
23
+ name?: string;
24
+ }): Promise<void>;
@@ -0,0 +1,115 @@
1
+ import { Napkin } from "../sdk.js";
2
+ import { EXIT_NOT_FOUND, EXIT_USER_ERROR } from "../utils/exit-codes.js";
3
+ import { suggestFile } from "../utils/files.js";
4
+ import { error, fileNotFound, output, success, } from "../utils/output.js";
5
+ export async function properties(opts) {
6
+ const n = new Napkin(opts.vault || process.cwd());
7
+ const propCounts = n.properties(opts.file);
8
+ const entries = [...propCounts.entries()];
9
+ if (opts.sort === "count") {
10
+ entries.sort((a, b) => b[1] - a[1]);
11
+ }
12
+ else {
13
+ entries.sort((a, b) => a[0].localeCompare(b[0]));
14
+ }
15
+ output(opts, {
16
+ json: () => {
17
+ if (opts.total)
18
+ return { total: entries.length };
19
+ if (opts.counts)
20
+ return { properties: Object.fromEntries(entries) };
21
+ return { properties: entries.map(([p]) => p) };
22
+ },
23
+ human: () => {
24
+ if (opts.total) {
25
+ console.log(entries.length);
26
+ }
27
+ else {
28
+ for (const [prop, count] of entries) {
29
+ console.log(opts.counts ? `${prop}\t${count}` : prop);
30
+ }
31
+ }
32
+ },
33
+ });
34
+ }
35
+ export async function propertySet(opts) {
36
+ const n = new Napkin(opts.vault || process.cwd());
37
+ if (!opts.name || opts.value === undefined) {
38
+ error("Usage: property:set --name <name> --value <value> --file <file>");
39
+ process.exit(EXIT_USER_ERROR);
40
+ }
41
+ if (!opts.file) {
42
+ error("No file specified. Use --file <name>");
43
+ process.exit(EXIT_USER_ERROR);
44
+ }
45
+ let result;
46
+ try {
47
+ result = n.propertySet(opts.file, opts.name, opts.value);
48
+ }
49
+ catch (e) {
50
+ const msg = e.message;
51
+ if (msg.startsWith("File not found:")) {
52
+ fileNotFound(opts.file, suggestFile(n.vault.contentPath, opts.file));
53
+ process.exit(EXIT_NOT_FOUND);
54
+ }
55
+ throw e;
56
+ }
57
+ output(opts, {
58
+ json: () => result,
59
+ human: () => success(`Set ${result.property} = ${opts.value} on ${result.path}`),
60
+ });
61
+ }
62
+ export async function propertyRemove(opts) {
63
+ const n = new Napkin(opts.vault || process.cwd());
64
+ if (!opts.name) {
65
+ error("No property name specified. Use --name <name>");
66
+ process.exit(EXIT_USER_ERROR);
67
+ }
68
+ if (!opts.file) {
69
+ error("No file specified. Use --file <name>");
70
+ process.exit(EXIT_USER_ERROR);
71
+ }
72
+ let result;
73
+ try {
74
+ result = n.propertyRemove(opts.file, opts.name);
75
+ }
76
+ catch (e) {
77
+ const msg = e.message;
78
+ if (msg.startsWith("File not found:")) {
79
+ fileNotFound(opts.file, suggestFile(n.vault.contentPath, opts.file));
80
+ process.exit(EXIT_NOT_FOUND);
81
+ }
82
+ throw e;
83
+ }
84
+ output(opts, {
85
+ json: () => result,
86
+ human: () => success(`Removed ${result.removed} from ${result.path}`),
87
+ });
88
+ }
89
+ export async function propertyRead(opts) {
90
+ const n = new Napkin(opts.vault || process.cwd());
91
+ if (!opts.name) {
92
+ error("No property name specified. Use --name <name>");
93
+ process.exit(EXIT_USER_ERROR);
94
+ }
95
+ if (!opts.file) {
96
+ error("No file specified. Use --file <name>");
97
+ process.exit(EXIT_USER_ERROR);
98
+ }
99
+ let result;
100
+ try {
101
+ result = n.propertyGet(opts.file, opts.name);
102
+ }
103
+ catch (e) {
104
+ const msg = e.message;
105
+ if (msg.startsWith("File not found:")) {
106
+ fileNotFound(opts.file, suggestFile(n.vault.contentPath, opts.file));
107
+ process.exit(EXIT_NOT_FOUND);
108
+ }
109
+ throw e;
110
+ }
111
+ output(opts, {
112
+ json: () => result,
113
+ human: () => console.log(result.value !== null ? String(result.value) : ""),
114
+ });
115
+ }
@@ -0,0 +1,13 @@
1
+ import { type OutputOptions } from "../utils/output.js";
2
+ interface SearchOpts extends OutputOptions {
3
+ vault?: string;
4
+ query?: string;
5
+ path?: string;
6
+ limit?: string;
7
+ total?: boolean;
8
+ snippetLines?: string;
9
+ snippets?: boolean;
10
+ score?: boolean;
11
+ }
12
+ export declare function search(opts: SearchOpts): Promise<void>;
13
+ export {};
@@ -0,0 +1,48 @@
1
+ import { Napkin } from "../sdk.js";
2
+ import { EXIT_USER_ERROR } from "../utils/exit-codes.js";
3
+ import { bold, dim, error, output, } from "../utils/output.js";
4
+ export async function search(opts) {
5
+ const n = new Napkin(opts.vault || process.cwd());
6
+ if (!opts.query) {
7
+ error("No query specified. Use --query <text>");
8
+ process.exit(EXIT_USER_ERROR);
9
+ }
10
+ const top = n.search(opts.query, {
11
+ path: opts.path,
12
+ limit: opts.limit ? Number.parseInt(opts.limit, 10) : undefined,
13
+ snippetLines: opts.snippetLines
14
+ ? Number.parseInt(opts.snippetLines, 10)
15
+ : undefined,
16
+ snippets: opts.snippets,
17
+ });
18
+ output(opts, {
19
+ json: () => {
20
+ if (opts.total)
21
+ return { total: top.length };
22
+ const mapResult = (r) => {
23
+ const { score: _score, snippets, ...rest } = r;
24
+ const out = { ...rest };
25
+ if (opts.score)
26
+ out.score = r.score;
27
+ if (opts.snippets !== false)
28
+ out.snippets = snippets;
29
+ return out;
30
+ };
31
+ return { results: top.map(mapResult) };
32
+ },
33
+ human: () => {
34
+ if (opts.total) {
35
+ console.log(top.length);
36
+ return;
37
+ }
38
+ for (const r of top) {
39
+ console.log(`${bold(r.file)} ${dim(`(${opts.score ? `score: ${r.score}, ` : ""}links: ${r.links}, modified: ${r.modified})`)}`);
40
+ for (const s of r.snippets) {
41
+ console.log(` ${dim(`${s.line}:`)} ${s.text}`);
42
+ }
43
+ }
44
+ console.log("");
45
+ console.log(dim("HINT: Use napkin read <file> to open a full file. Use napkin outline --file <file> to see its structure."));
46
+ },
47
+ });
48
+ }
@@ -0,0 +1,13 @@
1
+ import { type OutputOptions } from "../utils/output.js";
2
+ export declare function tags(opts: OutputOptions & {
3
+ vault?: string;
4
+ file?: string;
5
+ counts?: boolean;
6
+ total?: boolean;
7
+ sort?: string;
8
+ }): Promise<void>;
9
+ export declare function tag(opts: OutputOptions & {
10
+ vault?: string;
11
+ name?: string;
12
+ verbose?: boolean;
13
+ }): Promise<void>;
@@ -0,0 +1,51 @@
1
+ import { Napkin } from "../sdk.js";
2
+ import { EXIT_USER_ERROR } from "../utils/exit-codes.js";
3
+ import { bold, dim, error, output, } from "../utils/output.js";
4
+ export async function tags(opts) {
5
+ const n = new Napkin(opts.vault || process.cwd());
6
+ const { tagCounts } = n.tags(opts.file);
7
+ const entries = [...tagCounts.entries()];
8
+ if (opts.sort === "count") {
9
+ entries.sort((a, b) => b[1] - a[1]);
10
+ }
11
+ else {
12
+ entries.sort((a, b) => a[0].localeCompare(b[0]));
13
+ }
14
+ output(opts, {
15
+ json: () => {
16
+ if (opts.total)
17
+ return { total: entries.length };
18
+ if (opts.counts)
19
+ return { tags: Object.fromEntries(entries) };
20
+ return { tags: entries.map(([t]) => t) };
21
+ },
22
+ human: () => {
23
+ if (opts.total) {
24
+ console.log(entries.length);
25
+ }
26
+ else {
27
+ for (const [tag, count] of entries) {
28
+ console.log(opts.counts ? `${tag}\t${count}` : tag);
29
+ }
30
+ }
31
+ },
32
+ });
33
+ }
34
+ export async function tag(opts) {
35
+ const n = new Napkin(opts.vault || process.cwd());
36
+ if (!opts.name) {
37
+ error("No tag name specified. Use --name <tag>");
38
+ process.exit(EXIT_USER_ERROR);
39
+ }
40
+ const { tag: _tag, count, files } = n.tagInfo(opts.name);
41
+ output(opts, {
42
+ json: () => ({ tag: opts.name, count, ...(opts.verbose ? { files } : {}) }),
43
+ human: () => {
44
+ console.log(`${bold(opts.name)} ${count} occurrence${count !== 1 ? "s" : ""}`);
45
+ if (opts.verbose) {
46
+ for (const f of files)
47
+ console.log(` ${dim(f)}`);
48
+ }
49
+ },
50
+ });
51
+ }
@@ -0,0 +1,22 @@
1
+ import { type OutputOptions } from "../utils/output.js";
2
+ export declare function tasks(opts: OutputOptions & {
3
+ vault?: string;
4
+ file?: string;
5
+ done?: boolean;
6
+ todo?: boolean;
7
+ total?: boolean;
8
+ verbose?: boolean;
9
+ daily?: boolean;
10
+ status?: string;
11
+ }): Promise<void>;
12
+ export declare function task(opts: OutputOptions & {
13
+ vault?: string;
14
+ file?: string;
15
+ line?: string;
16
+ ref?: string;
17
+ toggle?: boolean;
18
+ done?: boolean;
19
+ todo?: boolean;
20
+ status?: string;
21
+ daily?: boolean;
22
+ }): Promise<void>;
@@ -0,0 +1,106 @@
1
+ import { resolveTaskLocation } from "../core/tasks.js";
2
+ import { Napkin } from "../sdk.js";
3
+ import { EXIT_NOT_FOUND, EXIT_USER_ERROR } from "../utils/exit-codes.js";
4
+ import { suggestFile } from "../utils/files.js";
5
+ import { bold, dim, error, fileNotFound, output, } from "../utils/output.js";
6
+ export async function tasks(opts) {
7
+ const n = new Napkin(opts.vault || process.cwd());
8
+ const result = n.tasks({
9
+ file: opts.file,
10
+ daily: opts.daily,
11
+ done: opts.done,
12
+ todo: opts.todo,
13
+ status: opts.status,
14
+ });
15
+ output(opts, {
16
+ json: () => (opts.total ? { total: result.length } : { tasks: result }),
17
+ human: () => {
18
+ if (opts.total) {
19
+ console.log(result.length);
20
+ }
21
+ else if (opts.verbose) {
22
+ const byFile = new Map();
23
+ for (const t of result) {
24
+ if (!byFile.has(t.file))
25
+ byFile.set(t.file, []);
26
+ byFile.get(t.file)?.push(t);
27
+ }
28
+ for (const [file, tasks] of byFile) {
29
+ console.log(bold(file));
30
+ for (const t of tasks) {
31
+ console.log(` ${dim(`${t.line}:`)} [${t.status}] ${t.text}`);
32
+ }
33
+ }
34
+ }
35
+ else {
36
+ for (const t of result) {
37
+ console.log(`[${t.status}] ${t.text}`);
38
+ }
39
+ }
40
+ },
41
+ });
42
+ }
43
+ export async function task(opts) {
44
+ const n = new Napkin(opts.vault || process.cwd());
45
+ let filePath;
46
+ let lineNum;
47
+ try {
48
+ ({ filePath, lineNum } = resolveTaskLocation(n.vault, opts));
49
+ }
50
+ catch (e) {
51
+ const msg = e.message;
52
+ if (msg.includes("File not found")) {
53
+ const ref = opts.ref?.split(":")[0] || opts.file || "";
54
+ fileNotFound(ref, suggestFile(n.vault.contentPath, ref));
55
+ process.exit(EXIT_NOT_FOUND);
56
+ }
57
+ error(msg);
58
+ process.exit(EXIT_USER_ERROR);
59
+ }
60
+ let taskInfo;
61
+ try {
62
+ taskInfo = n.taskShow(filePath, lineNum);
63
+ }
64
+ catch (e) {
65
+ const msg = e.message;
66
+ error(msg);
67
+ process.exit(msg.includes("is not a task") ? EXIT_USER_ERROR : EXIT_NOT_FOUND);
68
+ }
69
+ const { currentStatus } = taskInfo;
70
+ const isMutating = opts.toggle || opts.done || opts.todo || opts.status;
71
+ if (isMutating) {
72
+ let newStatus;
73
+ if (opts.status)
74
+ newStatus = opts.status;
75
+ else if (opts.done)
76
+ newStatus = "x";
77
+ else if (opts.todo)
78
+ newStatus = " ";
79
+ else if (opts.toggle)
80
+ newStatus = currentStatus === " " ? "x" : " ";
81
+ else
82
+ newStatus = currentStatus;
83
+ const result = n.taskUpdate(filePath, lineNum, newStatus);
84
+ output(opts, {
85
+ json: () => result,
86
+ human: () => console.log(`[${result.status}] ${result.text}`),
87
+ });
88
+ }
89
+ else {
90
+ output(opts, {
91
+ json: () => ({
92
+ file: filePath,
93
+ line: lineNum,
94
+ status: currentStatus,
95
+ text: taskInfo.text,
96
+ done: currentStatus === "x" || currentStatus === "X",
97
+ }),
98
+ human: () => {
99
+ console.log(`${dim("file")} ${filePath}`);
100
+ console.log(`${dim("line")} ${lineNum}`);
101
+ console.log(`${dim("status")} [${currentStatus}]`);
102
+ console.log(`${dim("text")} ${taskInfo.text}`);
103
+ },
104
+ });
105
+ }
106
+ }
@@ -0,0 +1,16 @@
1
+ import { type OutputOptions } from "../utils/output.js";
2
+ export declare function templates(opts: OutputOptions & {
3
+ vault?: string;
4
+ total?: boolean;
5
+ }): Promise<void>;
6
+ export declare function templateRead(opts: OutputOptions & {
7
+ vault?: string;
8
+ name?: string;
9
+ resolve?: boolean;
10
+ title?: string;
11
+ }): Promise<void>;
12
+ export declare function templateInsert(opts: OutputOptions & {
13
+ vault?: string;
14
+ name?: string;
15
+ file?: string;
16
+ }): Promise<void>;