@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
package/dist/main.js
ADDED
|
@@ -0,0 +1,715 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { aliases } from "./commands/aliases.js";
|
|
5
|
+
import { baseCreate, baseQuery, bases, baseViews } from "./commands/bases.js";
|
|
6
|
+
import { bookmark, bookmarks } from "./commands/bookmarks.js";
|
|
7
|
+
import { canvasAddEdge, canvasAddNode, canvasCreate, canvases, canvasNodes, canvasRead, canvasRemoveNode, } from "./commands/canvas.js";
|
|
8
|
+
import { configGet, configSet, configShow } from "./commands/config.js";
|
|
9
|
+
import { append, create, del, move, prepend, read, rename, } from "./commands/crud.js";
|
|
10
|
+
import { daily, dailyAppend, dailyPath, dailyPrepend, dailyRead, } from "./commands/daily.js";
|
|
11
|
+
import { file, files, folder, folders } from "./commands/files.js";
|
|
12
|
+
import { graph } from "./commands/graph.js";
|
|
13
|
+
import { init, initTemplates } from "./commands/init.js";
|
|
14
|
+
import { backlinks, deadends, links, orphans, unresolvedLinks, } from "./commands/links.js";
|
|
15
|
+
import { outline } from "./commands/outline.js";
|
|
16
|
+
import { overview } from "./commands/overview.js";
|
|
17
|
+
import { properties, propertyRead, propertyRemove, propertySet, } from "./commands/properties.js";
|
|
18
|
+
import { search } from "./commands/search.js";
|
|
19
|
+
import { tag, tags } from "./commands/tags.js";
|
|
20
|
+
import { task, tasks } from "./commands/tasks.js";
|
|
21
|
+
import { templateInsert, templateRead, templates, } from "./commands/templates.js";
|
|
22
|
+
import { vault } from "./commands/vault.js";
|
|
23
|
+
import { wordcount } from "./commands/wordcount.js";
|
|
24
|
+
const require = createRequire(import.meta.url);
|
|
25
|
+
const { version } = require("../package.json");
|
|
26
|
+
const program = new Command();
|
|
27
|
+
program
|
|
28
|
+
.name("napkin")
|
|
29
|
+
.description("🧻 Knowledge system for AI agents. Local-first, file-based, progressively disclosed.")
|
|
30
|
+
.version(`napkin ${version}`, "-v, --version")
|
|
31
|
+
.option("--json", "Output as JSON")
|
|
32
|
+
.option("-q, --quiet", "Suppress output")
|
|
33
|
+
.option("--vault <path>", "Vault path (default: auto-detect from cwd)")
|
|
34
|
+
.option("--copy", "Copy output to clipboard")
|
|
35
|
+
.showSuggestionAfterError(true)
|
|
36
|
+
.helpCommand(false)
|
|
37
|
+
.addHelpText("before", () => {
|
|
38
|
+
showHelp();
|
|
39
|
+
process.exit(0);
|
|
40
|
+
});
|
|
41
|
+
function showHelp() {
|
|
42
|
+
console.log(`Usage: napkin [options] [command]
|
|
43
|
+
|
|
44
|
+
🧻 Knowledge system for AI agents. Local-first, file-based, progressively disclosed.
|
|
45
|
+
|
|
46
|
+
Examples:
|
|
47
|
+
$ napkin init --template coding Create a vault with coding structure
|
|
48
|
+
$ napkin overview See what's in the vault
|
|
49
|
+
$ napkin search "auth" Find content about auth
|
|
50
|
+
$ napkin read "Architecture" Read a specific file
|
|
51
|
+
|
|
52
|
+
Workflow: init → overview → search → read
|
|
53
|
+
|
|
54
|
+
Getting started:
|
|
55
|
+
init Initialize a new vault (--template, --list)
|
|
56
|
+
overview Vault map with TF-IDF keywords per folder
|
|
57
|
+
vault Show vault info (path, file count, size)
|
|
58
|
+
config Vault configuration (show, get, set)
|
|
59
|
+
graph Interactive vault graph visualization
|
|
60
|
+
|
|
61
|
+
Reading:
|
|
62
|
+
read <file> Read a file
|
|
63
|
+
search <query> Search vault (BM25 + backlinks + recency)
|
|
64
|
+
|
|
65
|
+
Writing:
|
|
66
|
+
create <name> Create a new file (--template, --content)
|
|
67
|
+
append <file> Append content to a file
|
|
68
|
+
prepend <file> Prepend content after frontmatter
|
|
69
|
+
move <file> <to> Move a file
|
|
70
|
+
rename <file> <name> Rename a file
|
|
71
|
+
delete <file> Delete a file
|
|
72
|
+
|
|
73
|
+
Subcommands:
|
|
74
|
+
file Files, folders, outline, wordcount
|
|
75
|
+
daily Daily notes (today, read, append, prepend)
|
|
76
|
+
tag Tags and aliases
|
|
77
|
+
property Frontmatter properties (list, set, remove, read)
|
|
78
|
+
task Tasks and checklists (list, show, toggle)
|
|
79
|
+
link Links and graph (out, back, orphans, deadends)
|
|
80
|
+
template Note templates (list, read, insert)
|
|
81
|
+
base Database views over vault files
|
|
82
|
+
canvas JSON Canvas operations
|
|
83
|
+
bookmark Bookmarks
|
|
84
|
+
|
|
85
|
+
Options:
|
|
86
|
+
--json Output as JSON
|
|
87
|
+
-q, --quiet Suppress output
|
|
88
|
+
--vault <path> Vault path (default: auto-detect from cwd)
|
|
89
|
+
--copy Copy output to clipboard
|
|
90
|
+
-v, --version Show version
|
|
91
|
+
-h, --help Show this help
|
|
92
|
+
|
|
93
|
+
All commands support --json for structured output.
|
|
94
|
+
More help: napkin <command> --help
|
|
95
|
+
Docs: https://github.com/Michaelliv/napkin`);
|
|
96
|
+
}
|
|
97
|
+
// ── Getting started ─────────────────────────────────────────────────
|
|
98
|
+
program
|
|
99
|
+
.command("init")
|
|
100
|
+
.description("Initialize a new vault")
|
|
101
|
+
.option("--path <path>", "Directory to initialize (default: cwd)")
|
|
102
|
+
.option("--template <name>", "Scaffold with template (see init --list)")
|
|
103
|
+
.option("--list", "List available vault templates")
|
|
104
|
+
.action(async (opts, cmd) => {
|
|
105
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
106
|
+
if (root.list) {
|
|
107
|
+
await initTemplates(root);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
await init(root);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
program
|
|
114
|
+
.command("overview")
|
|
115
|
+
.description("Vault map with keywords (Level 1 progressive disclosure)")
|
|
116
|
+
.option("--depth <n>", "Max folder depth")
|
|
117
|
+
.option("--keywords <n>", "Max keywords per folder")
|
|
118
|
+
.action(async (opts, cmd) => {
|
|
119
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
120
|
+
await overview(root);
|
|
121
|
+
});
|
|
122
|
+
program
|
|
123
|
+
.command("graph")
|
|
124
|
+
.description("Interactive vault graph visualization")
|
|
125
|
+
.action(async (_opts, cmd) => {
|
|
126
|
+
const root = cmd.optsWithGlobals();
|
|
127
|
+
await graph({}, root);
|
|
128
|
+
});
|
|
129
|
+
program
|
|
130
|
+
.command("vault")
|
|
131
|
+
.description("Show vault info (path, file count, size)")
|
|
132
|
+
.action(async (_opts, cmd) => {
|
|
133
|
+
const root = cmd.optsWithGlobals();
|
|
134
|
+
await vault(root);
|
|
135
|
+
});
|
|
136
|
+
// ── Reading ─────────────────────────────────────────────────────────
|
|
137
|
+
program
|
|
138
|
+
.command("read <file>")
|
|
139
|
+
.description("Read a file")
|
|
140
|
+
.action(async (fileRef, _opts, cmd) => {
|
|
141
|
+
const root = cmd.optsWithGlobals();
|
|
142
|
+
await read(fileRef, root);
|
|
143
|
+
});
|
|
144
|
+
program
|
|
145
|
+
.command("search [query...]")
|
|
146
|
+
.description("Search vault (ranked by BM25 + backlinks + recency)")
|
|
147
|
+
.option("--query <text>", "Search query")
|
|
148
|
+
.option("--path <folder>", "Limit to folder")
|
|
149
|
+
.option("--limit <n>", "Max results (default: 30)")
|
|
150
|
+
.option("--total", "Return match count")
|
|
151
|
+
.option("--snippet-lines <n>", "Context lines around matches (default: 0)")
|
|
152
|
+
.option("--no-snippets", "Return files only, no snippets")
|
|
153
|
+
.option("--score", "Include relevance score in output")
|
|
154
|
+
.action(async (queryWords, opts, cmd) => {
|
|
155
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
156
|
+
if (queryWords.length && !root.query) {
|
|
157
|
+
root.query = queryWords.join(" ");
|
|
158
|
+
}
|
|
159
|
+
await search(root);
|
|
160
|
+
});
|
|
161
|
+
// ── Writing ─────────────────────────────────────────────────────────
|
|
162
|
+
program
|
|
163
|
+
.command("create [name] [content]")
|
|
164
|
+
.description("Create a new file")
|
|
165
|
+
.option("--name <name>", "File name (alternative to positional)")
|
|
166
|
+
.option("--path <path>", "File path from vault root")
|
|
167
|
+
.option("--content <text>", "Initial content (alternative to positional)")
|
|
168
|
+
.option("--template <name>", "Template to use")
|
|
169
|
+
.option("--overwrite", "Overwrite if file exists")
|
|
170
|
+
.action(async (name, content, opts, cmd) => {
|
|
171
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
172
|
+
root.name = root.name || name;
|
|
173
|
+
root.content = root.content || content;
|
|
174
|
+
await create(root);
|
|
175
|
+
});
|
|
176
|
+
program
|
|
177
|
+
.command("append [file] [content]")
|
|
178
|
+
.description("Append content to a file")
|
|
179
|
+
.option("--file <name>", "Target file (alternative to positional)")
|
|
180
|
+
.option("--content <text>", "Content to append (alternative to positional)")
|
|
181
|
+
.option("--inline", "Append without newline")
|
|
182
|
+
.action(async (file, content, opts, cmd) => {
|
|
183
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
184
|
+
root.file = root.file || file;
|
|
185
|
+
root.content = root.content || content;
|
|
186
|
+
await append(root);
|
|
187
|
+
});
|
|
188
|
+
program
|
|
189
|
+
.command("prepend [file] [content]")
|
|
190
|
+
.description("Prepend content after frontmatter")
|
|
191
|
+
.option("--file <name>", "Target file (alternative to positional)")
|
|
192
|
+
.option("--content <text>", "Content to prepend (alternative to positional)")
|
|
193
|
+
.option("--inline", "Prepend without newline")
|
|
194
|
+
.action(async (file, content, opts, cmd) => {
|
|
195
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
196
|
+
root.file = root.file || file;
|
|
197
|
+
root.content = root.content || content;
|
|
198
|
+
await prepend(root);
|
|
199
|
+
});
|
|
200
|
+
program
|
|
201
|
+
.command("move [file] [to]")
|
|
202
|
+
.description("Move a file")
|
|
203
|
+
.option("--file <name>", "File to move (alternative to positional)")
|
|
204
|
+
.option("--to <path>", "Destination folder or path (alternative to positional)")
|
|
205
|
+
.action(async (file, to, opts, cmd) => {
|
|
206
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
207
|
+
root.file = root.file || file;
|
|
208
|
+
root.to = root.to || to;
|
|
209
|
+
await move(root);
|
|
210
|
+
});
|
|
211
|
+
program
|
|
212
|
+
.command("rename [file] [name]")
|
|
213
|
+
.description("Rename a file")
|
|
214
|
+
.option("--file <name>", "File to rename (alternative to positional)")
|
|
215
|
+
.option("--name <name>", "New file name (alternative to positional)")
|
|
216
|
+
.action(async (file, name, opts, cmd) => {
|
|
217
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
218
|
+
root.file = root.file || file;
|
|
219
|
+
root.name = root.name || name;
|
|
220
|
+
await rename(root);
|
|
221
|
+
});
|
|
222
|
+
program
|
|
223
|
+
.command("delete [file]")
|
|
224
|
+
.description("Delete a file")
|
|
225
|
+
.option("--file <name>", "File to delete (alternative to positional)")
|
|
226
|
+
.option("--permanent", "Skip trash, delete permanently")
|
|
227
|
+
.action(async (file, opts, cmd) => {
|
|
228
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
229
|
+
root.file = root.file || file;
|
|
230
|
+
await del(root);
|
|
231
|
+
});
|
|
232
|
+
// ── file ────────────────────────────────────────────────────────────
|
|
233
|
+
const fileCmd = program
|
|
234
|
+
.command("file")
|
|
235
|
+
.description("Files, folders, and metadata");
|
|
236
|
+
fileCmd
|
|
237
|
+
.command("info [name]")
|
|
238
|
+
.description("Show file info")
|
|
239
|
+
.action(async (name, _opts, cmd) => {
|
|
240
|
+
const root = cmd.optsWithGlobals();
|
|
241
|
+
await file(name, root);
|
|
242
|
+
});
|
|
243
|
+
fileCmd
|
|
244
|
+
.command("list")
|
|
245
|
+
.description("List files in vault")
|
|
246
|
+
.option("--folder <path>", "Filter by folder")
|
|
247
|
+
.option("--ext <extension>", "Filter by extension")
|
|
248
|
+
.option("--total", "Return file count")
|
|
249
|
+
.action(async (opts, cmd) => {
|
|
250
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
251
|
+
await files(root);
|
|
252
|
+
});
|
|
253
|
+
fileCmd
|
|
254
|
+
.command("folder <path>")
|
|
255
|
+
.description("Show folder info")
|
|
256
|
+
.option("--info <type>", "Return specific info: files, folders, or size")
|
|
257
|
+
.action(async (folderPath, opts, cmd) => {
|
|
258
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
259
|
+
await folder(folderPath, root);
|
|
260
|
+
});
|
|
261
|
+
fileCmd
|
|
262
|
+
.command("folders")
|
|
263
|
+
.description("List folders")
|
|
264
|
+
.option("--folder <path>", "Filter by parent folder")
|
|
265
|
+
.option("--total", "Return folder count")
|
|
266
|
+
.action(async (opts, cmd) => {
|
|
267
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
268
|
+
await folders(root);
|
|
269
|
+
});
|
|
270
|
+
fileCmd
|
|
271
|
+
.command("outline [file]")
|
|
272
|
+
.description("Show headings for a file")
|
|
273
|
+
.option("--file <name>", "File name (alternative to positional)")
|
|
274
|
+
.option("--format <type>", "Output format: tree, md, json")
|
|
275
|
+
.option("--total", "Return heading count")
|
|
276
|
+
.action(async (file, opts, cmd) => {
|
|
277
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
278
|
+
root.file = root.file || file;
|
|
279
|
+
await outline(root);
|
|
280
|
+
});
|
|
281
|
+
fileCmd
|
|
282
|
+
.command("wordcount [file]")
|
|
283
|
+
.description("Count words and characters")
|
|
284
|
+
.option("--file <name>", "File name (alternative to positional)")
|
|
285
|
+
.option("--words", "Return word count only")
|
|
286
|
+
.option("--characters", "Return character count only")
|
|
287
|
+
.action(async (file, opts, cmd) => {
|
|
288
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
289
|
+
root.file = root.file || file;
|
|
290
|
+
await wordcount(root);
|
|
291
|
+
});
|
|
292
|
+
// ── daily ───────────────────────────────────────────────────────────
|
|
293
|
+
const dailyCmd = program.command("daily").description("Daily notes");
|
|
294
|
+
dailyCmd
|
|
295
|
+
.command("today")
|
|
296
|
+
.description("Create today's daily note")
|
|
297
|
+
.action(async (_opts, cmd) => {
|
|
298
|
+
const root = cmd.optsWithGlobals();
|
|
299
|
+
await daily(root);
|
|
300
|
+
});
|
|
301
|
+
dailyCmd
|
|
302
|
+
.command("path")
|
|
303
|
+
.description("Get daily note path")
|
|
304
|
+
.action(async (_opts, cmd) => {
|
|
305
|
+
const root = cmd.optsWithGlobals();
|
|
306
|
+
await dailyPath(root);
|
|
307
|
+
});
|
|
308
|
+
dailyCmd
|
|
309
|
+
.command("read")
|
|
310
|
+
.description("Read daily note contents")
|
|
311
|
+
.action(async (_opts, cmd) => {
|
|
312
|
+
const root = cmd.optsWithGlobals();
|
|
313
|
+
await dailyRead(root);
|
|
314
|
+
});
|
|
315
|
+
dailyCmd
|
|
316
|
+
.command("append [content]")
|
|
317
|
+
.description("Append to daily note")
|
|
318
|
+
.option("--content <text>", "Content to append (alternative to positional)")
|
|
319
|
+
.option("--inline", "Append without newline")
|
|
320
|
+
.action(async (content, opts, cmd) => {
|
|
321
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
322
|
+
root.content = root.content || content;
|
|
323
|
+
await dailyAppend(root);
|
|
324
|
+
});
|
|
325
|
+
dailyCmd
|
|
326
|
+
.command("prepend [content]")
|
|
327
|
+
.description("Prepend to daily note")
|
|
328
|
+
.option("--content <text>", "Content to prepend (alternative to positional)")
|
|
329
|
+
.option("--inline", "Prepend without newline")
|
|
330
|
+
.action(async (content, opts, cmd) => {
|
|
331
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
332
|
+
root.content = root.content || content;
|
|
333
|
+
await dailyPrepend(root);
|
|
334
|
+
});
|
|
335
|
+
// ── tag ─────────────────────────────────────────────────────────────
|
|
336
|
+
const tagCmd = program.command("tag").description("Tags and aliases");
|
|
337
|
+
tagCmd
|
|
338
|
+
.command("list")
|
|
339
|
+
.description("List tags in vault")
|
|
340
|
+
.option("--file <name>", "Filter by file")
|
|
341
|
+
.option("--counts", "Include tag counts")
|
|
342
|
+
.option("--total", "Return tag count")
|
|
343
|
+
.option("--sort <by>", "Sort by: name (default) or count")
|
|
344
|
+
.action(async (opts, cmd) => {
|
|
345
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
346
|
+
await tags(root);
|
|
347
|
+
});
|
|
348
|
+
tagCmd
|
|
349
|
+
.command("info")
|
|
350
|
+
.description("Get tag info")
|
|
351
|
+
.option("--name <tag>", "Tag name")
|
|
352
|
+
.option("--verbose", "Include file list")
|
|
353
|
+
.action(async (opts, cmd) => {
|
|
354
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
355
|
+
await tag(root);
|
|
356
|
+
});
|
|
357
|
+
tagCmd
|
|
358
|
+
.command("aliases")
|
|
359
|
+
.description("List aliases in vault")
|
|
360
|
+
.option("--file <name>", "Filter by file")
|
|
361
|
+
.option("--total", "Return alias count")
|
|
362
|
+
.option("--verbose", "Include file paths")
|
|
363
|
+
.action(async (opts, cmd) => {
|
|
364
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
365
|
+
await aliases(root);
|
|
366
|
+
});
|
|
367
|
+
// ── property ────────────────────────────────────────────────────────
|
|
368
|
+
const propCmd = program
|
|
369
|
+
.command("property")
|
|
370
|
+
.description("Frontmatter properties");
|
|
371
|
+
propCmd
|
|
372
|
+
.command("list")
|
|
373
|
+
.description("List properties in vault")
|
|
374
|
+
.option("--file <name>", "Filter by file")
|
|
375
|
+
.option("--counts", "Include counts")
|
|
376
|
+
.option("--total", "Return property count")
|
|
377
|
+
.option("--sort <by>", "Sort by: name (default) or count")
|
|
378
|
+
.action(async (opts, cmd) => {
|
|
379
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
380
|
+
await properties(root);
|
|
381
|
+
});
|
|
382
|
+
propCmd
|
|
383
|
+
.command("set")
|
|
384
|
+
.description("Set a property on a file")
|
|
385
|
+
.option("--name <name>", "Property name")
|
|
386
|
+
.option("--value <value>", "Property value")
|
|
387
|
+
.option("--file <name>", "Target file")
|
|
388
|
+
.action(async (opts, cmd) => {
|
|
389
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
390
|
+
await propertySet(root);
|
|
391
|
+
});
|
|
392
|
+
propCmd
|
|
393
|
+
.command("remove")
|
|
394
|
+
.description("Remove a property from a file")
|
|
395
|
+
.option("--name <name>", "Property name")
|
|
396
|
+
.option("--file <name>", "Target file")
|
|
397
|
+
.action(async (opts, cmd) => {
|
|
398
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
399
|
+
await propertyRemove(root);
|
|
400
|
+
});
|
|
401
|
+
propCmd
|
|
402
|
+
.command("read")
|
|
403
|
+
.description("Read a property value")
|
|
404
|
+
.option("--name <name>", "Property name")
|
|
405
|
+
.option("--file <name>", "Target file")
|
|
406
|
+
.action(async (opts, cmd) => {
|
|
407
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
408
|
+
await propertyRead(root);
|
|
409
|
+
});
|
|
410
|
+
// ── task ────────────────────────────────────────────────────────────
|
|
411
|
+
const taskCmd = program.command("task").description("Tasks and checklists");
|
|
412
|
+
taskCmd
|
|
413
|
+
.command("list")
|
|
414
|
+
.description("List tasks in vault")
|
|
415
|
+
.option("--file <name>", "Filter by file")
|
|
416
|
+
.option("--done", "Show completed tasks")
|
|
417
|
+
.option("--todo", "Show incomplete tasks")
|
|
418
|
+
.option("--total", "Return task count")
|
|
419
|
+
.option("--verbose", "Group by file with line numbers")
|
|
420
|
+
.option("--daily", "Show tasks from daily note")
|
|
421
|
+
.option("--status <char>", "Filter by status character")
|
|
422
|
+
.action(async (opts, cmd) => {
|
|
423
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
424
|
+
await tasks(root);
|
|
425
|
+
});
|
|
426
|
+
taskCmd
|
|
427
|
+
.command("show")
|
|
428
|
+
.description("Show or update a task")
|
|
429
|
+
.option("--file <name>", "File name")
|
|
430
|
+
.option("--line <n>", "Line number")
|
|
431
|
+
.option("--ref <path:line>", "Task reference")
|
|
432
|
+
.option("--toggle", "Toggle task status")
|
|
433
|
+
.option("--done", "Mark as done")
|
|
434
|
+
.option("--todo", "Mark as todo")
|
|
435
|
+
.option("--status <char>", "Set status character")
|
|
436
|
+
.option("--daily", "Daily note")
|
|
437
|
+
.action(async (opts, cmd) => {
|
|
438
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
439
|
+
await task(root);
|
|
440
|
+
});
|
|
441
|
+
// ── link ────────────────────────────────────────────────────────────
|
|
442
|
+
const linkCmd = program.command("link").description("Links and graph analysis");
|
|
443
|
+
linkCmd
|
|
444
|
+
.command("out")
|
|
445
|
+
.description("List outgoing links from a file")
|
|
446
|
+
.option("--file <name>", "Source file")
|
|
447
|
+
.option("--total", "Return link count")
|
|
448
|
+
.action(async (opts, cmd) => {
|
|
449
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
450
|
+
await links(root);
|
|
451
|
+
});
|
|
452
|
+
linkCmd
|
|
453
|
+
.command("back")
|
|
454
|
+
.description("List backlinks to a file")
|
|
455
|
+
.option("--file <name>", "Target file")
|
|
456
|
+
.option("--counts", "Include link counts")
|
|
457
|
+
.option("--total", "Return backlink count")
|
|
458
|
+
.action(async (opts, cmd) => {
|
|
459
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
460
|
+
await backlinks(root);
|
|
461
|
+
});
|
|
462
|
+
linkCmd
|
|
463
|
+
.command("unresolved")
|
|
464
|
+
.description("List unresolved links in vault")
|
|
465
|
+
.option("--total", "Return count")
|
|
466
|
+
.option("--counts", "Include link counts")
|
|
467
|
+
.option("--verbose", "Include source files")
|
|
468
|
+
.action(async (opts, cmd) => {
|
|
469
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
470
|
+
await unresolvedLinks(root);
|
|
471
|
+
});
|
|
472
|
+
linkCmd
|
|
473
|
+
.command("orphans")
|
|
474
|
+
.description("Files with no incoming links")
|
|
475
|
+
.option("--total", "Return count")
|
|
476
|
+
.action(async (opts, cmd) => {
|
|
477
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
478
|
+
await orphans(root);
|
|
479
|
+
});
|
|
480
|
+
linkCmd
|
|
481
|
+
.command("deadends")
|
|
482
|
+
.description("Files with no outgoing links")
|
|
483
|
+
.option("--total", "Return count")
|
|
484
|
+
.action(async (opts, cmd) => {
|
|
485
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
486
|
+
await deadends(root);
|
|
487
|
+
});
|
|
488
|
+
// ── base ────────────────────────────────────────────────────────────
|
|
489
|
+
const baseCmd = program
|
|
490
|
+
.command("base")
|
|
491
|
+
.description("Bases (database views over vault files)");
|
|
492
|
+
baseCmd
|
|
493
|
+
.command("list")
|
|
494
|
+
.description("List base files in vault")
|
|
495
|
+
.action(async (_opts, cmd) => {
|
|
496
|
+
const root = cmd.optsWithGlobals();
|
|
497
|
+
await bases(root);
|
|
498
|
+
});
|
|
499
|
+
baseCmd
|
|
500
|
+
.command("views")
|
|
501
|
+
.description("List views in a base")
|
|
502
|
+
.option("--file <name>", "Base file name")
|
|
503
|
+
.option("--path <path>", "Base file path")
|
|
504
|
+
.action(async (opts, cmd) => {
|
|
505
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
506
|
+
await baseViews(root);
|
|
507
|
+
});
|
|
508
|
+
baseCmd
|
|
509
|
+
.command("query")
|
|
510
|
+
.description("Query a base and return results")
|
|
511
|
+
.option("--file <name>", "Base file name")
|
|
512
|
+
.option("--path <path>", "Base file path")
|
|
513
|
+
.option("--view <name>", "View name to query")
|
|
514
|
+
.option("--format <type>", "Output format: json, csv, tsv, md, paths")
|
|
515
|
+
.action(async (opts, cmd) => {
|
|
516
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
517
|
+
await baseQuery(root);
|
|
518
|
+
});
|
|
519
|
+
baseCmd
|
|
520
|
+
.command("create")
|
|
521
|
+
.description("Create a new item in a base")
|
|
522
|
+
.option("--file <name>", "Base file name")
|
|
523
|
+
.option("--path <path>", "Base file path")
|
|
524
|
+
.option("--name <name>", "New file name")
|
|
525
|
+
.option("--content <text>", "Initial content")
|
|
526
|
+
.action(async (opts, cmd) => {
|
|
527
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
528
|
+
await baseCreate(root);
|
|
529
|
+
});
|
|
530
|
+
// ── canvas ──────────────────────────────────────────────────────────
|
|
531
|
+
const canvasCmd = program
|
|
532
|
+
.command("canvas")
|
|
533
|
+
.description("JSON Canvas operations");
|
|
534
|
+
canvasCmd
|
|
535
|
+
.command("list")
|
|
536
|
+
.description("List canvas files in vault")
|
|
537
|
+
.option("--total", "Return count")
|
|
538
|
+
.action(async (opts, cmd) => {
|
|
539
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
540
|
+
await canvases(root);
|
|
541
|
+
});
|
|
542
|
+
canvasCmd
|
|
543
|
+
.command("read")
|
|
544
|
+
.description("Read a canvas file")
|
|
545
|
+
.option("--file <name>", "Canvas file name")
|
|
546
|
+
.action(async (opts, cmd) => {
|
|
547
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
548
|
+
await canvasRead(root);
|
|
549
|
+
});
|
|
550
|
+
canvasCmd
|
|
551
|
+
.command("nodes")
|
|
552
|
+
.description("List nodes in a canvas")
|
|
553
|
+
.option("--file <name>", "Canvas file name")
|
|
554
|
+
.option("--type <type>", "Filter by type: text, file, link, group")
|
|
555
|
+
.action(async (opts, cmd) => {
|
|
556
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
557
|
+
await canvasNodes(root);
|
|
558
|
+
});
|
|
559
|
+
canvasCmd
|
|
560
|
+
.command("create")
|
|
561
|
+
.description("Create an empty canvas")
|
|
562
|
+
.option("--file <name>", "Canvas file name")
|
|
563
|
+
.option("--path <path>", "Folder path")
|
|
564
|
+
.action(async (opts, cmd) => {
|
|
565
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
566
|
+
await canvasCreate(root);
|
|
567
|
+
});
|
|
568
|
+
canvasCmd
|
|
569
|
+
.command("add-node")
|
|
570
|
+
.description("Add a node to a canvas")
|
|
571
|
+
.option("--file <name>", "Canvas file name")
|
|
572
|
+
.option("--type <type>", "Node type: text, file, link, group")
|
|
573
|
+
.option("--text <text>", "Text content (for text nodes)")
|
|
574
|
+
.option("--note-file <path>", "File path (for file nodes)")
|
|
575
|
+
.option("--subpath <subpath>", "Subpath (for file nodes)")
|
|
576
|
+
.option("--url <url>", "URL (for link nodes)")
|
|
577
|
+
.option("--label <label>", "Label (for group nodes)")
|
|
578
|
+
.option("--x <n>", "X position")
|
|
579
|
+
.option("--y <n>", "Y position")
|
|
580
|
+
.option("--width <n>", "Width")
|
|
581
|
+
.option("--height <n>", "Height")
|
|
582
|
+
.option("--color <color>", "Node color (1-6 or hex)")
|
|
583
|
+
.action(async (opts, cmd) => {
|
|
584
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
585
|
+
await canvasAddNode(root);
|
|
586
|
+
});
|
|
587
|
+
canvasCmd
|
|
588
|
+
.command("add-edge")
|
|
589
|
+
.description("Add an edge between nodes")
|
|
590
|
+
.option("--file <name>", "Canvas file name")
|
|
591
|
+
.option("--from <id>", "Source node ID (or prefix)")
|
|
592
|
+
.option("--to <id>", "Target node ID (or prefix)")
|
|
593
|
+
.option("--from-side <side>", "Source side: top, right, bottom, left")
|
|
594
|
+
.option("--to-side <side>", "Target side: top, right, bottom, left")
|
|
595
|
+
.option("--label <text>", "Edge label")
|
|
596
|
+
.option("--color <color>", "Edge color")
|
|
597
|
+
.action(async (opts, cmd) => {
|
|
598
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
599
|
+
await canvasAddEdge(root);
|
|
600
|
+
});
|
|
601
|
+
canvasCmd
|
|
602
|
+
.command("remove-node")
|
|
603
|
+
.description("Remove a node and its edges")
|
|
604
|
+
.option("--file <name>", "Canvas file name")
|
|
605
|
+
.option("--id <id>", "Node ID (or prefix)")
|
|
606
|
+
.action(async (opts, cmd) => {
|
|
607
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
608
|
+
await canvasRemoveNode(root);
|
|
609
|
+
});
|
|
610
|
+
// ── template ────────────────────────────────────────────────────────
|
|
611
|
+
const tmplCmd = program.command("template").description("Note templates");
|
|
612
|
+
tmplCmd
|
|
613
|
+
.command("list")
|
|
614
|
+
.description("List note templates")
|
|
615
|
+
.option("--total", "Return template count")
|
|
616
|
+
.action(async (opts, cmd) => {
|
|
617
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
618
|
+
await templates(root);
|
|
619
|
+
});
|
|
620
|
+
tmplCmd
|
|
621
|
+
.command("read")
|
|
622
|
+
.description("Read template content")
|
|
623
|
+
.option("--name <name>", "Template name")
|
|
624
|
+
.option("--resolve", "Resolve template variables")
|
|
625
|
+
.option("--title <title>", "Title for variable resolution")
|
|
626
|
+
.action(async (opts, cmd) => {
|
|
627
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
628
|
+
await templateRead(root);
|
|
629
|
+
});
|
|
630
|
+
tmplCmd
|
|
631
|
+
.command("insert")
|
|
632
|
+
.description("Insert template into a file")
|
|
633
|
+
.option("--name <name>", "Template name")
|
|
634
|
+
.option("--file <name>", "Target file")
|
|
635
|
+
.action(async (opts, cmd) => {
|
|
636
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
637
|
+
await templateInsert(root);
|
|
638
|
+
});
|
|
639
|
+
// ── bookmark ────────────────────────────────────────────────────────
|
|
640
|
+
const bookmarkCmd = program.command("bookmark").description("Bookmarks");
|
|
641
|
+
bookmarkCmd
|
|
642
|
+
.command("list")
|
|
643
|
+
.description("List bookmarks")
|
|
644
|
+
.option("--total", "Return bookmark count")
|
|
645
|
+
.option("--verbose", "Include bookmark types")
|
|
646
|
+
.action(async (opts, cmd) => {
|
|
647
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
648
|
+
await bookmarks(root);
|
|
649
|
+
});
|
|
650
|
+
bookmarkCmd
|
|
651
|
+
.command("add")
|
|
652
|
+
.description("Add a bookmark")
|
|
653
|
+
.option("--file <path>", "File to bookmark")
|
|
654
|
+
.option("--subpath <subpath>", "Subpath within file")
|
|
655
|
+
.option("--folder <path>", "Folder to bookmark")
|
|
656
|
+
.option("--search <query>", "Search query to bookmark")
|
|
657
|
+
.option("--url <url>", "URL to bookmark")
|
|
658
|
+
.option("--title <title>", "Bookmark title")
|
|
659
|
+
.action(async (opts, cmd) => {
|
|
660
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
661
|
+
await bookmark(root);
|
|
662
|
+
});
|
|
663
|
+
// ── config ──────────────────────────────────────────────────────────
|
|
664
|
+
const configCmd = program.command("config").description("Vault configuration");
|
|
665
|
+
configCmd
|
|
666
|
+
.command("show")
|
|
667
|
+
.description("Show current config")
|
|
668
|
+
.action(async (_opts, cmd) => {
|
|
669
|
+
const root = cmd.optsWithGlobals();
|
|
670
|
+
await configShow(root);
|
|
671
|
+
});
|
|
672
|
+
configCmd
|
|
673
|
+
.command("get")
|
|
674
|
+
.description("Get a config value")
|
|
675
|
+
.option("--key <path>", "Config key (dot notation, e.g. search.limit)")
|
|
676
|
+
.action(async (opts, cmd) => {
|
|
677
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
678
|
+
await configGet(root);
|
|
679
|
+
});
|
|
680
|
+
configCmd
|
|
681
|
+
.command("set")
|
|
682
|
+
.description("Set a config value")
|
|
683
|
+
.option("--key <path>", "Config key (dot notation, e.g. search.limit)")
|
|
684
|
+
.option("--value <value>", "Value to set (JSON or string)")
|
|
685
|
+
.action(async (opts, cmd) => {
|
|
686
|
+
const root = { ...cmd.optsWithGlobals(), ...opts };
|
|
687
|
+
await configSet(root);
|
|
688
|
+
});
|
|
689
|
+
// ── copy support ────────────────────────────────────────────────────
|
|
690
|
+
const origWrite = process.stdout.write.bind(process.stdout);
|
|
691
|
+
let capturedOutput = "";
|
|
692
|
+
program.hook("preAction", () => {
|
|
693
|
+
const opts = program.opts();
|
|
694
|
+
if (opts.copy) {
|
|
695
|
+
process.stdout.write = (chunk, ...args) => {
|
|
696
|
+
capturedOutput += chunk.toString();
|
|
697
|
+
return origWrite(chunk, ...args);
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
});
|
|
701
|
+
program
|
|
702
|
+
.parseAsync(process.argv)
|
|
703
|
+
.then(async () => {
|
|
704
|
+
const opts = program.opts();
|
|
705
|
+
if (opts.copy && capturedOutput.trim()) {
|
|
706
|
+
const { exec } = await import("node:child_process");
|
|
707
|
+
const proc = exec("pbcopy");
|
|
708
|
+
proc.stdin?.write(capturedOutput);
|
|
709
|
+
proc.stdin?.end();
|
|
710
|
+
}
|
|
711
|
+
})
|
|
712
|
+
.catch((err) => {
|
|
713
|
+
console.error("Fatal error:", err.message);
|
|
714
|
+
process.exit(1);
|
|
715
|
+
});
|