@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,70 @@
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 templates(opts) {
6
+ const n = new Napkin(opts.vault || process.cwd());
7
+ const files = n.templates();
8
+ output(opts, {
9
+ json: () => (opts.total ? { total: files.length } : { templates: files }),
10
+ human: () => {
11
+ if (opts.total)
12
+ console.log(files.length);
13
+ else
14
+ for (const f of files)
15
+ console.log(f);
16
+ },
17
+ });
18
+ }
19
+ export async function templateRead(opts) {
20
+ const n = new Napkin(opts.vault || process.cwd());
21
+ if (!opts.name) {
22
+ error("No template name specified. Use --name <template>");
23
+ process.exit(EXIT_USER_ERROR);
24
+ }
25
+ let result;
26
+ try {
27
+ result = n.templateRead(opts.name, {
28
+ resolve: opts.resolve,
29
+ title: opts.title,
30
+ });
31
+ }
32
+ catch (e) {
33
+ error(e.message);
34
+ process.exit(EXIT_NOT_FOUND);
35
+ }
36
+ output(opts, {
37
+ json: () => result,
38
+ human: () => console.log(result.content),
39
+ });
40
+ }
41
+ export async function templateInsert(opts) {
42
+ const n = new Napkin(opts.vault || process.cwd());
43
+ const templateName = opts.name;
44
+ const targetFile = opts.file;
45
+ if (!templateName) {
46
+ error("No template name specified. Use --name <template>");
47
+ process.exit(EXIT_USER_ERROR);
48
+ }
49
+ if (!targetFile) {
50
+ error("No target file specified. Use --file <name>");
51
+ process.exit(EXIT_USER_ERROR);
52
+ }
53
+ let result;
54
+ try {
55
+ result = n.templateInsert(templateName, targetFile);
56
+ }
57
+ catch (e) {
58
+ if (e.message.includes("File not found")) {
59
+ fileNotFound(targetFile, suggestFile(n.vault.contentPath, targetFile));
60
+ }
61
+ else {
62
+ error(e.message);
63
+ }
64
+ process.exit(EXIT_NOT_FOUND);
65
+ }
66
+ output(opts, {
67
+ json: () => result,
68
+ human: () => success(`Inserted template "${result.template}" into ${result.file}`),
69
+ });
70
+ }
@@ -0,0 +1,4 @@
1
+ import { type OutputOptions } from "../utils/output.js";
2
+ export declare function vault(opts: OutputOptions & {
3
+ vault?: string;
4
+ }): Promise<void>;
@@ -0,0 +1,17 @@
1
+ import { formatSize } from "../core/vault.js";
2
+ import { Napkin } from "../sdk.js";
3
+ import { bold, dim, output } from "../utils/output.js";
4
+ export async function vault(opts) {
5
+ const n = new Napkin(opts.vault || process.cwd());
6
+ const meta = n.info();
7
+ output(opts, {
8
+ json: () => meta,
9
+ human: () => {
10
+ console.log(`${dim("name")} ${bold(meta.name)}`);
11
+ console.log(`${dim("path")} ${meta.path}`);
12
+ console.log(`${dim("files")} ${meta.files}`);
13
+ console.log(`${dim("folders")} ${meta.folders}`);
14
+ console.log(`${dim("size")} ${formatSize(meta.size)}`);
15
+ },
16
+ });
17
+ }
@@ -0,0 +1,7 @@
1
+ import { type OutputOptions } from "../utils/output.js";
2
+ export declare function wordcount(opts: OutputOptions & {
3
+ vault?: string;
4
+ file?: string;
5
+ words?: boolean;
6
+ characters?: boolean;
7
+ }): Promise<void>;
@@ -0,0 +1,43 @@
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 wordcount(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 result;
12
+ try {
13
+ result = n.wordcount(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
+ const { words, characters } = result;
24
+ output(opts, {
25
+ json: () => {
26
+ if (opts.words)
27
+ return { words };
28
+ if (opts.characters)
29
+ return { characters };
30
+ return { words, characters };
31
+ },
32
+ human: () => {
33
+ if (opts.words)
34
+ console.log(words);
35
+ else if (opts.characters)
36
+ console.log(characters);
37
+ else {
38
+ console.log(`${dim("words")} ${words}`);
39
+ console.log(`${dim("characters")} ${characters}`);
40
+ }
41
+ },
42
+ });
43
+ }
@@ -0,0 +1,5 @@
1
+ export interface AliasEntry {
2
+ alias: string;
3
+ file: string;
4
+ }
5
+ export declare function collectAliases(vaultPath: string, fileFilter?: string): AliasEntry[];
@@ -0,0 +1,26 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { listFiles, resolveFile } from "../utils/files.js";
4
+ import { parseFrontmatter } from "../utils/frontmatter.js";
5
+ export function collectAliases(vaultPath, fileFilter) {
6
+ const files = fileFilter
7
+ ? (() => {
8
+ const r = resolveFile(vaultPath, fileFilter);
9
+ return r ? [r] : [];
10
+ })()
11
+ : listFiles(vaultPath, { ext: "md" });
12
+ const results = [];
13
+ for (const file of files) {
14
+ const content = fs.readFileSync(path.join(vaultPath, file), "utf-8");
15
+ const { properties } = parseFrontmatter(content);
16
+ const aliases = properties.aliases;
17
+ if (Array.isArray(aliases)) {
18
+ for (const a of aliases)
19
+ results.push({ alias: String(a), file });
20
+ }
21
+ else if (typeof aliases === "string" && aliases) {
22
+ results.push({ alias: aliases, file });
23
+ }
24
+ }
25
+ return results;
26
+ }
@@ -0,0 +1,29 @@
1
+ export interface BaseView {
2
+ name: string;
3
+ type: string;
4
+ }
5
+ export interface BaseQueryResult {
6
+ columns: string[];
7
+ rows: unknown[][];
8
+ displayNames?: Record<string, string>;
9
+ groups?: {
10
+ key: string;
11
+ rows: unknown[][];
12
+ }[];
13
+ summaries?: Record<string, unknown>;
14
+ }
15
+ export declare function listBases(vaultPath: string): string[];
16
+ export declare function resolveBaseFile(vaultPath: string, opts: {
17
+ file?: string;
18
+ path?: string;
19
+ }): string | null;
20
+ export declare function getBaseViews(vaultPath: string, baseFile: string): BaseView[];
21
+ export declare function queryBaseFile(vaultPath: string, baseFile: string, viewName?: string): Promise<BaseQueryResult>;
22
+ export declare function createBaseItem(vaultPath: string, opts: {
23
+ name: string;
24
+ path?: string;
25
+ content?: string;
26
+ }): {
27
+ path: string;
28
+ created: boolean;
29
+ };
@@ -0,0 +1,67 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { buildDatabase, parseBaseFile, queryBase } from "../utils/bases.js";
4
+ import { listFiles } from "../utils/files.js";
5
+ export function listBases(vaultPath) {
6
+ return listFiles(vaultPath).filter((f) => f.endsWith(".base"));
7
+ }
8
+ export function resolveBaseFile(vaultPath, opts) {
9
+ if (opts.path) {
10
+ const p = opts.path.endsWith(".base") ? opts.path : `${opts.path}.base`;
11
+ if (fs.existsSync(path.join(vaultPath, p)))
12
+ return p;
13
+ return null;
14
+ }
15
+ if (opts.file) {
16
+ const allFiles = listFiles(vaultPath).filter((f) => f.endsWith(".base"));
17
+ const target = opts.file.toLowerCase();
18
+ for (const f of allFiles) {
19
+ const basename = path.basename(f, ".base").toLowerCase();
20
+ if (basename === target)
21
+ return f;
22
+ }
23
+ const withExt = opts.file.endsWith(".base")
24
+ ? opts.file
25
+ : `${opts.file}.base`;
26
+ if (fs.existsSync(path.join(vaultPath, withExt)))
27
+ return withExt;
28
+ return null;
29
+ }
30
+ return null;
31
+ }
32
+ export function getBaseViews(vaultPath, baseFile) {
33
+ const content = fs.readFileSync(path.join(vaultPath, baseFile), "utf-8");
34
+ const config = parseBaseFile(content);
35
+ return (config.views || []).map((view) => ({
36
+ name: view.name || "(unnamed)",
37
+ type: view.type,
38
+ }));
39
+ }
40
+ export async function queryBaseFile(vaultPath, baseFile, viewName) {
41
+ const content = fs.readFileSync(path.join(vaultPath, baseFile), "utf-8");
42
+ const config = parseBaseFile(content);
43
+ const db = await buildDatabase(vaultPath);
44
+ try {
45
+ const thisFile = {
46
+ name: path.basename(baseFile),
47
+ path: baseFile,
48
+ folder: path.dirname(baseFile),
49
+ };
50
+ const result = await queryBase(db, config, viewName, thisFile);
51
+ return result;
52
+ }
53
+ finally {
54
+ db.close();
55
+ }
56
+ }
57
+ export function createBaseItem(vaultPath, opts) {
58
+ const targetPath = opts.path
59
+ ? opts.path.endsWith(".md")
60
+ ? opts.path
61
+ : `${opts.path}/${opts.name}.md`
62
+ : `${opts.name}.md`;
63
+ const fullPath = path.join(vaultPath, targetPath);
64
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
65
+ fs.writeFileSync(fullPath, opts.content || "");
66
+ return { path: targetPath, created: true };
67
+ }
@@ -0,0 +1,14 @@
1
+ export interface Bookmark {
2
+ type: string;
3
+ title?: string;
4
+ path?: string;
5
+ query?: string;
6
+ url?: string;
7
+ subpath?: string;
8
+ items?: Bookmark[];
9
+ }
10
+ export declare function readBookmarks(obsidianPath: string): Bookmark[];
11
+ export declare function flattenBookmarks(items: Bookmark[]): Bookmark[];
12
+ export declare function addBookmark(obsidianPath: string, entry: Bookmark): {
13
+ added: Bookmark;
14
+ };
@@ -0,0 +1,34 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ export function readBookmarks(obsidianPath) {
4
+ const configPath = path.join(obsidianPath, "bookmarks.json");
5
+ try {
6
+ const content = fs.readFileSync(configPath, "utf-8");
7
+ return JSON.parse(content);
8
+ }
9
+ catch {
10
+ return [];
11
+ }
12
+ }
13
+ function writeBookmarks(obsidianPath, bookmarks) {
14
+ const configPath = path.join(obsidianPath, "bookmarks.json");
15
+ fs.writeFileSync(configPath, JSON.stringify(bookmarks, null, 2));
16
+ }
17
+ export function flattenBookmarks(items) {
18
+ const result = [];
19
+ for (const item of items) {
20
+ if (item.type === "group" && item.items) {
21
+ result.push(...flattenBookmarks(item.items));
22
+ }
23
+ else {
24
+ result.push(item);
25
+ }
26
+ }
27
+ return result;
28
+ }
29
+ export function addBookmark(obsidianPath, entry) {
30
+ const items = readBookmarks(obsidianPath);
31
+ items.push(entry);
32
+ writeBookmarks(obsidianPath, items);
33
+ return { added: entry };
34
+ }
@@ -0,0 +1,74 @@
1
+ export interface CanvasNode {
2
+ id: string;
3
+ type: "text" | "file" | "link" | "group";
4
+ x: number;
5
+ y: number;
6
+ width: number;
7
+ height: number;
8
+ text?: string;
9
+ file?: string;
10
+ subpath?: string;
11
+ url?: string;
12
+ label?: string;
13
+ color?: string;
14
+ background?: string;
15
+ backgroundStyle?: string;
16
+ }
17
+ export interface CanvasEdge {
18
+ id: string;
19
+ fromNode: string;
20
+ fromSide?: string;
21
+ fromEnd?: string;
22
+ toNode: string;
23
+ toSide?: string;
24
+ toEnd?: string;
25
+ color?: string;
26
+ label?: string;
27
+ }
28
+ export interface Canvas {
29
+ nodes: CanvasNode[];
30
+ edges: CanvasEdge[];
31
+ }
32
+ export declare function resolveCanvas(vaultPath: string, fileRef: string): {
33
+ canvas: Canvas;
34
+ filePath: string;
35
+ };
36
+ export declare function listCanvases(vaultPath: string): string[];
37
+ export declare function createCanvas(vaultPath: string, fileName: string, folder?: string): {
38
+ path: string;
39
+ created: boolean;
40
+ };
41
+ export declare function addCanvasNode(vaultPath: string, fileRef: string, opts: {
42
+ type?: string;
43
+ text?: string;
44
+ noteFile?: string;
45
+ subpath?: string;
46
+ url?: string;
47
+ label?: string;
48
+ x?: string;
49
+ y?: string;
50
+ width?: string;
51
+ height?: string;
52
+ color?: string;
53
+ }): {
54
+ id: string;
55
+ type: string;
56
+ added: boolean;
57
+ };
58
+ export declare function addCanvasEdge(vaultPath: string, fileRef: string, opts: {
59
+ from: string;
60
+ to: string;
61
+ fromSide?: string;
62
+ toSide?: string;
63
+ label?: string;
64
+ color?: string;
65
+ }): {
66
+ id: string;
67
+ from: string;
68
+ to: string;
69
+ added: boolean;
70
+ };
71
+ export declare function removeCanvasNode(vaultPath: string, fileRef: string, nodeId: string): {
72
+ id: string;
73
+ removed: boolean;
74
+ };
@@ -0,0 +1,125 @@
1
+ import * as crypto from "node:crypto";
2
+ import * as fs from "node:fs";
3
+ import * as path from "node:path";
4
+ import { listFiles } from "../utils/files.js";
5
+ function genId() {
6
+ return crypto.randomBytes(8).toString("hex");
7
+ }
8
+ export function resolveCanvas(vaultPath, fileRef) {
9
+ let filePath = fileRef;
10
+ if (!filePath.endsWith(".canvas"))
11
+ filePath = `${filePath}.canvas`;
12
+ const fullPath = path.join(vaultPath, filePath);
13
+ if (!fs.existsSync(fullPath)) {
14
+ const all = listFiles(vaultPath).filter((f) => f.endsWith(".canvas"));
15
+ const target = fileRef.toLowerCase().replace(/\.canvas$/, "");
16
+ const found = all.find((f) => path.basename(f, ".canvas").toLowerCase() === target);
17
+ if (!found) {
18
+ throw new Error(`Canvas not found: ${fileRef}`);
19
+ }
20
+ filePath = found;
21
+ }
22
+ const content = fs.readFileSync(path.join(vaultPath, filePath), "utf-8");
23
+ const canvas = JSON.parse(content);
24
+ canvas.nodes = canvas.nodes || [];
25
+ canvas.edges = canvas.edges || [];
26
+ return { canvas, filePath };
27
+ }
28
+ function writeCanvas(vaultPath, filePath, canvas) {
29
+ fs.writeFileSync(path.join(vaultPath, filePath), JSON.stringify(canvas, null, 2));
30
+ }
31
+ export function listCanvases(vaultPath) {
32
+ return listFiles(vaultPath).filter((f) => f.endsWith(".canvas"));
33
+ }
34
+ export function createCanvas(vaultPath, fileName, folder) {
35
+ const name = fileName.endsWith(".canvas") ? fileName : `${fileName}.canvas`;
36
+ const targetPath = folder ? `${folder}/${name}` : name;
37
+ const fullPath = path.join(vaultPath, targetPath);
38
+ if (fs.existsSync(fullPath)) {
39
+ throw new Error(`Canvas already exists: ${targetPath}`);
40
+ }
41
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
42
+ const canvas = { nodes: [], edges: [] };
43
+ writeCanvas(vaultPath, targetPath, canvas);
44
+ return { path: targetPath, created: true };
45
+ }
46
+ export function addCanvasNode(vaultPath, fileRef, opts) {
47
+ const nodeType = (opts.type || "text");
48
+ if (!["text", "file", "link", "group"].includes(nodeType)) {
49
+ throw new Error("Invalid node type. Use: text, file, link, or group");
50
+ }
51
+ const { canvas, filePath } = resolveCanvas(vaultPath, fileRef);
52
+ const maxX = canvas.nodes.reduce((max, n) => Math.max(max, n.x + n.width), 0);
53
+ const node = {
54
+ id: genId(),
55
+ type: nodeType,
56
+ x: opts.x
57
+ ? Number.parseInt(opts.x, 10)
58
+ : canvas.nodes.length > 0
59
+ ? maxX + 50
60
+ : 0,
61
+ y: opts.y ? Number.parseInt(opts.y, 10) : 0,
62
+ width: opts.width
63
+ ? Number.parseInt(opts.width, 10)
64
+ : nodeType === "group"
65
+ ? 600
66
+ : 300,
67
+ height: opts.height
68
+ ? Number.parseInt(opts.height, 10)
69
+ : nodeType === "group"
70
+ ? 400
71
+ : 150,
72
+ };
73
+ if (nodeType === "text")
74
+ node.text = opts.text || "";
75
+ if (nodeType === "file") {
76
+ node.file = opts.noteFile || "";
77
+ if (opts.subpath)
78
+ node.subpath = opts.subpath;
79
+ }
80
+ if (nodeType === "link")
81
+ node.url = opts.url || "";
82
+ if (nodeType === "group")
83
+ node.label = opts.label || "";
84
+ if (opts.color)
85
+ node.color = opts.color;
86
+ canvas.nodes.push(node);
87
+ writeCanvas(vaultPath, filePath, canvas);
88
+ return { id: node.id, type: node.type, added: true };
89
+ }
90
+ export function addCanvasEdge(vaultPath, fileRef, opts) {
91
+ const { canvas, filePath } = resolveCanvas(vaultPath, fileRef);
92
+ const findNode = (ref) => canvas.nodes.find((n) => n.id === ref || n.id.startsWith(ref));
93
+ const fromNode = findNode(opts.from);
94
+ const toNode = findNode(opts.to);
95
+ if (!fromNode)
96
+ throw new Error(`Node not found: ${opts.from}`);
97
+ if (!toNode)
98
+ throw new Error(`Node not found: ${opts.to}`);
99
+ const edge = {
100
+ id: genId(),
101
+ fromNode: fromNode.id,
102
+ toNode: toNode.id,
103
+ };
104
+ if (opts.fromSide)
105
+ edge.fromSide = opts.fromSide;
106
+ if (opts.toSide)
107
+ edge.toSide = opts.toSide;
108
+ if (opts.label)
109
+ edge.label = opts.label;
110
+ if (opts.color)
111
+ edge.color = opts.color;
112
+ canvas.edges.push(edge);
113
+ writeCanvas(vaultPath, filePath, canvas);
114
+ return { id: edge.id, from: edge.fromNode, to: edge.toNode, added: true };
115
+ }
116
+ export function removeCanvasNode(vaultPath, fileRef, nodeId) {
117
+ const { canvas, filePath } = resolveCanvas(vaultPath, fileRef);
118
+ const node = canvas.nodes.find((n) => n.id === nodeId || n.id.startsWith(nodeId));
119
+ if (!node)
120
+ throw new Error(`Node not found: ${nodeId}`);
121
+ canvas.nodes = canvas.nodes.filter((n) => n.id !== node.id);
122
+ canvas.edges = canvas.edges.filter((e) => e.fromNode !== node.id && e.toNode !== node.id);
123
+ writeCanvas(vaultPath, filePath, canvas);
124
+ return { id: node.id, removed: true };
125
+ }
@@ -0,0 +1,7 @@
1
+ import { loadConfig } from "../utils/config.js";
2
+ export { loadConfig };
3
+ export declare function getConfigValue(configPath: string, key: string): unknown;
4
+ export declare function setConfigValue(configPath: string, key: string, rawValue: string): {
5
+ config: Record<string, unknown>;
6
+ parsed: unknown;
7
+ };
@@ -0,0 +1,35 @@
1
+ import { loadConfig, updateConfig } from "../utils/config.js";
2
+ export { loadConfig };
3
+ export function getConfigValue(configPath, key) {
4
+ const config = loadConfig(configPath);
5
+ const parts = key.split(".");
6
+ let value = config;
7
+ for (const part of parts) {
8
+ if (value && typeof value === "object" && part in value) {
9
+ value = value[part];
10
+ }
11
+ else {
12
+ return undefined;
13
+ }
14
+ }
15
+ return value;
16
+ }
17
+ export function setConfigValue(configPath, key, rawValue) {
18
+ const parts = key.split(".");
19
+ const obj = {};
20
+ let current = obj;
21
+ for (let i = 0; i < parts.length - 1; i++) {
22
+ current[parts[i]] = {};
23
+ current = current[parts[i]];
24
+ }
25
+ let parsed;
26
+ try {
27
+ parsed = JSON.parse(rawValue);
28
+ }
29
+ catch {
30
+ parsed = rawValue;
31
+ }
32
+ current[parts[parts.length - 1]] = parsed;
33
+ const updated = updateConfig(configPath, obj);
34
+ return { config: updated, parsed };
35
+ }
@@ -0,0 +1,32 @@
1
+ import type { VaultInfo } from "../utils/vault.js";
2
+ export interface ReadResult {
3
+ path: string;
4
+ content: string;
5
+ }
6
+ export interface CreateOptions {
7
+ name?: string;
8
+ path?: string;
9
+ content?: string;
10
+ template?: string;
11
+ overwrite?: boolean;
12
+ }
13
+ export interface CreateResult {
14
+ path: string;
15
+ created: boolean;
16
+ }
17
+ export interface MoveResult {
18
+ from: string;
19
+ to: string;
20
+ }
21
+ export interface DeleteResult {
22
+ path: string;
23
+ deleted: boolean;
24
+ permanent: boolean;
25
+ }
26
+ export declare function readFile(vaultPath: string, fileRef: string): ReadResult;
27
+ export declare function createFile(v: VaultInfo, opts: CreateOptions): CreateResult;
28
+ export declare function appendFile(vaultPath: string, fileRef: string, content: string, inline?: boolean): string;
29
+ export declare function prependFile(vaultPath: string, fileRef: string, content: string, inline?: boolean): string;
30
+ export declare function moveFile(vaultPath: string, fileRef: string, destination: string): MoveResult;
31
+ export declare function renameFile(vaultPath: string, fileRef: string, newName: string): MoveResult;
32
+ export declare function deleteFile(vaultPath: string, fileRef: string, permanent?: boolean): DeleteResult;