@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.
- package/LICENSE +21 -0
- package/README.md +342 -0
- package/dist/commands/aliases.d.ts +7 -0
- package/dist/commands/aliases.js +25 -0
- package/dist/commands/bases.d.ts +23 -0
- package/dist/commands/bases.js +139 -0
- package/dist/commands/bookmarks.d.ts +15 -0
- package/dist/commands/bookmarks.js +51 -0
- package/dist/commands/canvas.d.ts +49 -0
- package/dist/commands/canvas.js +186 -0
- package/dist/commands/config.d.ts +13 -0
- package/dist/commands/config.js +48 -0
- package/dist/commands/crud.d.ts +40 -0
- package/dist/commands/crud.js +195 -0
- package/dist/commands/daily.d.ts +20 -0
- package/dist/commands/daily.js +58 -0
- package/dist/commands/files.d.ts +23 -0
- package/dist/commands/files.js +132 -0
- package/dist/commands/graph.d.ts +4 -0
- package/dist/commands/graph.js +461 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.js +52 -0
- package/dist/commands/links.d.ts +26 -0
- package/dist/commands/links.js +119 -0
- package/dist/commands/outline.d.ts +7 -0
- package/dist/commands/outline.js +48 -0
- package/dist/commands/overview.d.ts +6 -0
- package/dist/commands/overview.js +40 -0
- package/dist/commands/properties.d.ts +24 -0
- package/dist/commands/properties.js +115 -0
- package/dist/commands/search.d.ts +13 -0
- package/dist/commands/search.js +48 -0
- package/dist/commands/tags.d.ts +13 -0
- package/dist/commands/tags.js +51 -0
- package/dist/commands/tasks.d.ts +22 -0
- package/dist/commands/tasks.js +106 -0
- package/dist/commands/templates.d.ts +16 -0
- package/dist/commands/templates.js +70 -0
- package/dist/commands/vault.d.ts +4 -0
- package/dist/commands/vault.js +17 -0
- package/dist/commands/wordcount.d.ts +7 -0
- package/dist/commands/wordcount.js +43 -0
- package/dist/core/aliases.d.ts +5 -0
- package/dist/core/aliases.js +26 -0
- package/dist/core/bases.d.ts +29 -0
- package/dist/core/bases.js +67 -0
- package/dist/core/bookmarks.d.ts +14 -0
- package/dist/core/bookmarks.js +34 -0
- package/dist/core/canvas.d.ts +74 -0
- package/dist/core/canvas.js +125 -0
- package/dist/core/config.d.ts +7 -0
- package/dist/core/config.js +35 -0
- package/dist/core/crud.d.ts +32 -0
- package/dist/core/crud.js +119 -0
- package/dist/core/daily.d.ts +12 -0
- package/dist/core/daily.js +102 -0
- package/dist/core/files.d.ts +15 -0
- package/dist/core/files.js +30 -0
- package/dist/core/init.d.ts +31 -0
- package/dist/core/init.js +119 -0
- package/dist/core/links.d.ts +11 -0
- package/dist/core/links.js +66 -0
- package/dist/core/outline.d.ts +3 -0
- package/dist/core/outline.js +12 -0
- package/dist/core/overview.d.ts +15 -0
- package/dist/core/overview.js +384 -0
- package/dist/core/properties.d.ts +14 -0
- package/dist/core/properties.js +60 -0
- package/dist/core/search.d.ts +17 -0
- package/dist/core/search.js +153 -0
- package/dist/core/tags.d.ts +11 -0
- package/dist/core/tags.js +40 -0
- package/dist/core/tasks.d.ts +35 -0
- package/dist/core/tasks.js +97 -0
- package/dist/core/templates.d.ts +14 -0
- package/dist/core/templates.js +55 -0
- package/dist/core/vault.d.ts +10 -0
- package/dist/core/vault.js +37 -0
- package/dist/core/wordcount.d.ts +5 -0
- package/dist/core/wordcount.js +16 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +715 -0
- package/dist/sdk.d.ts +179 -0
- package/dist/sdk.js +232 -0
- package/dist/templates/coding.d.ts +2 -0
- package/dist/templates/coding.js +104 -0
- package/dist/templates/company.d.ts +2 -0
- package/dist/templates/company.js +121 -0
- package/dist/templates/index.d.ts +4 -0
- package/dist/templates/index.js +15 -0
- package/dist/templates/personal.d.ts +2 -0
- package/dist/templates/personal.js +91 -0
- package/dist/templates/product.d.ts +2 -0
- package/dist/templates/product.js +123 -0
- package/dist/templates/research.d.ts +2 -0
- package/dist/templates/research.js +114 -0
- package/dist/templates/types.d.ts +7 -0
- package/dist/templates/types.js +1 -0
- package/dist/utils/bases.d.ts +61 -0
- package/dist/utils/bases.js +661 -0
- package/dist/utils/config.d.ts +42 -0
- package/dist/utils/config.js +112 -0
- package/dist/utils/exit-codes.d.ts +5 -0
- package/dist/utils/exit-codes.js +5 -0
- package/dist/utils/files.d.ts +135 -0
- package/dist/utils/files.js +299 -0
- package/dist/utils/formula.d.ts +28 -0
- package/dist/utils/formula.js +462 -0
- package/dist/utils/frontmatter.d.ts +17 -0
- package/dist/utils/frontmatter.js +34 -0
- package/dist/utils/markdown.d.ts +31 -0
- package/dist/utils/markdown.js +80 -0
- package/dist/utils/output.d.ts +28 -0
- package/dist/utils/output.js +48 -0
- package/dist/utils/search-cache.d.ts +29 -0
- package/dist/utils/search-cache.js +41 -0
- package/dist/utils/test-helpers.d.ts +13 -0
- package/dist/utils/test-helpers.js +40 -0
- package/dist/utils/vault.d.ts +21 -0
- package/dist/utils/vault.js +144 -0
- package/package.json +76 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type Task } from "../utils/markdown.js";
|
|
2
|
+
import type { VaultInfo } from "../utils/vault.js";
|
|
3
|
+
export interface TaskWithFile extends Task {
|
|
4
|
+
file: string;
|
|
5
|
+
}
|
|
6
|
+
export interface TaskShowResult {
|
|
7
|
+
file: string;
|
|
8
|
+
line: number;
|
|
9
|
+
status: string;
|
|
10
|
+
text: string;
|
|
11
|
+
done?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function collectTasks(vault: VaultInfo, opts: {
|
|
14
|
+
file?: string;
|
|
15
|
+
daily?: boolean;
|
|
16
|
+
}): TaskWithFile[];
|
|
17
|
+
export declare function filterTasks(tasks: TaskWithFile[], opts: {
|
|
18
|
+
done?: boolean;
|
|
19
|
+
todo?: boolean;
|
|
20
|
+
status?: string;
|
|
21
|
+
}): TaskWithFile[];
|
|
22
|
+
export declare function resolveTaskLocation(vault: VaultInfo, opts: {
|
|
23
|
+
file?: string;
|
|
24
|
+
line?: string;
|
|
25
|
+
ref?: string;
|
|
26
|
+
daily?: boolean;
|
|
27
|
+
}): {
|
|
28
|
+
filePath: string;
|
|
29
|
+
lineNum: number;
|
|
30
|
+
};
|
|
31
|
+
export declare function showTask(vaultPath: string, filePath: string, lineNum: number): {
|
|
32
|
+
currentStatus: string;
|
|
33
|
+
text: string;
|
|
34
|
+
};
|
|
35
|
+
export declare function updateTask(vaultPath: string, filePath: string, lineNum: number, newStatus: string): TaskShowResult;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { listFiles, resolveFile } from "../utils/files.js";
|
|
4
|
+
import { extractTasks } from "../utils/markdown.js";
|
|
5
|
+
import { getDailyPath } from "./daily.js";
|
|
6
|
+
export function collectTasks(vault, opts) {
|
|
7
|
+
let files;
|
|
8
|
+
if (opts.daily) {
|
|
9
|
+
const dp = getDailyPath(vault.configPath);
|
|
10
|
+
files = fs.existsSync(path.join(vault.contentPath, dp)) ? [dp] : [];
|
|
11
|
+
}
|
|
12
|
+
else if (opts.file) {
|
|
13
|
+
const r = resolveFile(vault.contentPath, opts.file);
|
|
14
|
+
files = r ? [r] : [];
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
files = listFiles(vault.contentPath, { ext: "md" });
|
|
18
|
+
}
|
|
19
|
+
const results = [];
|
|
20
|
+
for (const file of files) {
|
|
21
|
+
const content = fs.readFileSync(path.join(vault.contentPath, file), "utf-8");
|
|
22
|
+
const tasks = extractTasks(content);
|
|
23
|
+
for (const t of tasks) {
|
|
24
|
+
results.push({ ...t, file });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return results;
|
|
28
|
+
}
|
|
29
|
+
export function filterTasks(tasks, opts) {
|
|
30
|
+
let result = tasks;
|
|
31
|
+
if (opts.done)
|
|
32
|
+
result = result.filter((t) => t.done);
|
|
33
|
+
if (opts.todo)
|
|
34
|
+
result = result.filter((t) => !t.done);
|
|
35
|
+
if (opts.status)
|
|
36
|
+
result = result.filter((t) => t.status === opts.status);
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
export function resolveTaskLocation(vault, opts) {
|
|
40
|
+
if (opts.ref) {
|
|
41
|
+
const parts = opts.ref.split(":");
|
|
42
|
+
if (parts.length !== 2) {
|
|
43
|
+
throw new Error("Invalid ref format. Use --ref <path:line>");
|
|
44
|
+
}
|
|
45
|
+
const resolved = resolveFile(vault.contentPath, parts[0]);
|
|
46
|
+
if (!resolved) {
|
|
47
|
+
throw new Error(`File not found: ${parts[0]}`);
|
|
48
|
+
}
|
|
49
|
+
return { filePath: resolved, lineNum: Number.parseInt(parts[1], 10) };
|
|
50
|
+
}
|
|
51
|
+
if (opts.daily) {
|
|
52
|
+
return {
|
|
53
|
+
filePath: getDailyPath(vault.configPath),
|
|
54
|
+
lineNum: Number.parseInt(opts.line || "0", 10),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (!opts.file || !opts.line) {
|
|
58
|
+
throw new Error("Specify --file and --line, or --ref <path:line>");
|
|
59
|
+
}
|
|
60
|
+
const resolved = resolveFile(vault.contentPath, opts.file);
|
|
61
|
+
if (!resolved) {
|
|
62
|
+
throw new Error(`File not found: ${opts.file}`);
|
|
63
|
+
}
|
|
64
|
+
return { filePath: resolved, lineNum: Number.parseInt(opts.line, 10) };
|
|
65
|
+
}
|
|
66
|
+
function parseTask(vaultPath, filePath, lineNum) {
|
|
67
|
+
const fullPath = path.join(vaultPath, filePath);
|
|
68
|
+
if (!fs.existsSync(fullPath)) {
|
|
69
|
+
throw new Error(`File not found: ${filePath}`);
|
|
70
|
+
}
|
|
71
|
+
const content = fs.readFileSync(fullPath, "utf-8");
|
|
72
|
+
const lines = content.split("\n");
|
|
73
|
+
const targetLine = lines[lineNum - 1];
|
|
74
|
+
if (!targetLine) {
|
|
75
|
+
throw new Error(`Line ${lineNum} not found in ${filePath}`);
|
|
76
|
+
}
|
|
77
|
+
const taskMatch = targetLine.match(/^([\s]*[-*]\s+\[)(.)(].*)$/);
|
|
78
|
+
if (!taskMatch) {
|
|
79
|
+
throw new Error(`Line ${lineNum} is not a task`);
|
|
80
|
+
}
|
|
81
|
+
return { lines, taskMatch, fullPath };
|
|
82
|
+
}
|
|
83
|
+
export function showTask(vaultPath, filePath, lineNum) {
|
|
84
|
+
const { taskMatch } = parseTask(vaultPath, filePath, lineNum);
|
|
85
|
+
return { currentStatus: taskMatch[2], text: taskMatch[3].slice(2) };
|
|
86
|
+
}
|
|
87
|
+
export function updateTask(vaultPath, filePath, lineNum, newStatus) {
|
|
88
|
+
const { lines, taskMatch, fullPath } = parseTask(vaultPath, filePath, lineNum);
|
|
89
|
+
lines[lineNum - 1] = `${taskMatch[1]}${newStatus}${taskMatch[3]}`;
|
|
90
|
+
fs.writeFileSync(fullPath, lines.join("\n"));
|
|
91
|
+
return {
|
|
92
|
+
file: filePath,
|
|
93
|
+
line: lineNum,
|
|
94
|
+
status: newStatus,
|
|
95
|
+
text: taskMatch[3].slice(2),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { VaultInfo } from "../utils/vault.js";
|
|
2
|
+
export declare function listTemplates(v: VaultInfo): string[];
|
|
3
|
+
export declare function readTemplate(v: VaultInfo, name: string, opts?: {
|
|
4
|
+
resolve?: boolean;
|
|
5
|
+
title?: string;
|
|
6
|
+
}): {
|
|
7
|
+
template: string;
|
|
8
|
+
content: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function insertTemplate(v: VaultInfo, templateName: string, fileRef: string): {
|
|
11
|
+
file: string;
|
|
12
|
+
template: string;
|
|
13
|
+
inserted: boolean;
|
|
14
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { loadConfig } from "../utils/config.js";
|
|
4
|
+
import { listFiles, resolveFile } from "../utils/files.js";
|
|
5
|
+
function getTemplateFolder(configPath) {
|
|
6
|
+
const config = loadConfig(configPath);
|
|
7
|
+
return config.templates.folder;
|
|
8
|
+
}
|
|
9
|
+
export function listTemplates(v) {
|
|
10
|
+
const folder = getTemplateFolder(v.configPath);
|
|
11
|
+
return listFiles(v.contentPath, { folder, ext: "md" }).map((f) => path.basename(f, ".md"));
|
|
12
|
+
}
|
|
13
|
+
function resolveVariables(content, title) {
|
|
14
|
+
const now = new Date();
|
|
15
|
+
const dateStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
|
16
|
+
const timeStr = `${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}`;
|
|
17
|
+
return content
|
|
18
|
+
.replace(/\{\{date\}\}/g, dateStr)
|
|
19
|
+
.replace(/\{\{time\}\}/g, timeStr)
|
|
20
|
+
.replace(/\{\{title\}\}/g, title || "Untitled");
|
|
21
|
+
}
|
|
22
|
+
export function readTemplate(v, name, opts) {
|
|
23
|
+
const folder = getTemplateFolder(v.configPath);
|
|
24
|
+
const resolved = resolveFile(v.contentPath, `${folder}/${name}`) ||
|
|
25
|
+
resolveFile(v.contentPath, name);
|
|
26
|
+
if (!resolved) {
|
|
27
|
+
const templateFiles = listFiles(v.contentPath, { folder, ext: "md" }).map((f) => path.basename(f, ".md"));
|
|
28
|
+
throw new Error(`Template not found: ${name}. Available: ${templateFiles.slice(0, 3).join(", ")}`);
|
|
29
|
+
}
|
|
30
|
+
let content = fs.readFileSync(path.join(v.contentPath, resolved), "utf-8");
|
|
31
|
+
if (opts?.resolve) {
|
|
32
|
+
content = resolveVariables(content, opts.title);
|
|
33
|
+
}
|
|
34
|
+
return { template: name, content };
|
|
35
|
+
}
|
|
36
|
+
export function insertTemplate(v, templateName, fileRef) {
|
|
37
|
+
const folder = getTemplateFolder(v.configPath);
|
|
38
|
+
const templateResolved = resolveFile(v.contentPath, `${folder}/${templateName}`) ||
|
|
39
|
+
resolveFile(v.contentPath, templateName);
|
|
40
|
+
if (!templateResolved) {
|
|
41
|
+
const templateFiles = listFiles(v.contentPath, { folder, ext: "md" }).map((f) => path.basename(f, ".md"));
|
|
42
|
+
throw new Error(`Template not found: ${templateName}. Available: ${templateFiles.slice(0, 3).join(", ")}`);
|
|
43
|
+
}
|
|
44
|
+
const targetResolved = resolveFile(v.contentPath, fileRef);
|
|
45
|
+
if (!targetResolved) {
|
|
46
|
+
throw new Error(`File not found: ${fileRef}`);
|
|
47
|
+
}
|
|
48
|
+
const title = path.basename(targetResolved, ".md");
|
|
49
|
+
let templateContent = fs.readFileSync(path.join(v.contentPath, templateResolved), "utf-8");
|
|
50
|
+
templateContent = resolveVariables(templateContent, title);
|
|
51
|
+
const targetPath = path.join(v.contentPath, targetResolved);
|
|
52
|
+
const existing = fs.readFileSync(targetPath, "utf-8");
|
|
53
|
+
fs.writeFileSync(targetPath, existing + templateContent);
|
|
54
|
+
return { file: targetResolved, template: templateName, inserted: true };
|
|
55
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { VaultInfo } from "../utils/vault.js";
|
|
2
|
+
export interface VaultMetadata {
|
|
3
|
+
name: string;
|
|
4
|
+
path: string;
|
|
5
|
+
files: number;
|
|
6
|
+
folders: number;
|
|
7
|
+
size: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function formatSize(bytes: number): string;
|
|
10
|
+
export declare function getVaultMetadata(v: VaultInfo): VaultMetadata;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import { listFiles, listFolders, walkDir } from "../utils/files.js";
|
|
3
|
+
function getVaultSize(vaultPath) {
|
|
4
|
+
let total = 0;
|
|
5
|
+
walkDir(vaultPath, {
|
|
6
|
+
onEntry: (fullPath, _entry, kind) => {
|
|
7
|
+
if (kind !== "file")
|
|
8
|
+
return;
|
|
9
|
+
try {
|
|
10
|
+
total += fs.statSync(fullPath).size;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
// Entry disappeared between readdir and stat — skip.
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
return total;
|
|
18
|
+
}
|
|
19
|
+
export function formatSize(bytes) {
|
|
20
|
+
if (bytes < 1024)
|
|
21
|
+
return `${bytes} B`;
|
|
22
|
+
if (bytes < 1024 * 1024)
|
|
23
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
24
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
25
|
+
}
|
|
26
|
+
export function getVaultMetadata(v) {
|
|
27
|
+
const files = listFiles(v.contentPath);
|
|
28
|
+
const folders = listFolders(v.contentPath);
|
|
29
|
+
const size = getVaultSize(v.contentPath);
|
|
30
|
+
return {
|
|
31
|
+
name: v.name,
|
|
32
|
+
path: v.contentPath,
|
|
33
|
+
files: files.length,
|
|
34
|
+
folders: folders.length,
|
|
35
|
+
size,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { resolveFile } from "../utils/files.js";
|
|
4
|
+
import { parseFrontmatter } from "../utils/frontmatter.js";
|
|
5
|
+
export function getWordCount(vaultPath, fileRef) {
|
|
6
|
+
const resolved = resolveFile(vaultPath, fileRef);
|
|
7
|
+
if (!resolved) {
|
|
8
|
+
throw new Error(`File not found: ${fileRef}`);
|
|
9
|
+
}
|
|
10
|
+
const content = fs.readFileSync(path.join(vaultPath, resolved), "utf-8");
|
|
11
|
+
const { body } = parseFrontmatter(content);
|
|
12
|
+
const text = body.trim();
|
|
13
|
+
const words = text ? text.split(/\s+/).length : 0;
|
|
14
|
+
const characters = text.length;
|
|
15
|
+
return { words, characters };
|
|
16
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type { AliasEntry } from "./core/aliases.js";
|
|
2
|
+
export type { BaseQueryResult, BaseView } from "./core/bases.js";
|
|
3
|
+
export type { Bookmark } from "./core/bookmarks.js";
|
|
4
|
+
export type { Canvas, CanvasEdge, CanvasNode } from "./core/canvas.js";
|
|
5
|
+
export type { CreateOptions, CreateResult, DeleteResult, MoveResult, ReadResult, } from "./core/crud.js";
|
|
6
|
+
export type { FileInfo, FolderInfo } from "./core/files.js";
|
|
7
|
+
export type { AddTemplateResult, ScaffoldResult, TemplateInfo, } from "./core/init.js";
|
|
8
|
+
export type { OverviewFolder, VaultOverview } from "./core/overview.js";
|
|
9
|
+
export type { SearchOptions, SearchResult } from "./core/search.js";
|
|
10
|
+
export type { TagInfo } from "./core/tags.js";
|
|
11
|
+
export type { TaskShowResult, TaskWithFile } from "./core/tasks.js";
|
|
12
|
+
export type { VaultMetadata } from "./core/vault.js";
|
|
13
|
+
export type { WordCount } from "./core/wordcount.js";
|
|
14
|
+
export { Napkin } from "./sdk.js";
|
|
15
|
+
export type { VaultTemplate } from "./templates/types.js";
|
|
16
|
+
export type { Heading } from "./utils/markdown.js";
|
|
17
|
+
export type { VaultInfo } from "./utils/vault.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Napkin } from "./sdk.js";
|
package/dist/main.d.ts
ADDED