@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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Michael Liv
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,342 @@
1
+ # napkin
2
+
3
+ 🧻 Knowledge system for agents. Local-first, file-based, progressively disclosed.
4
+
5
+ Every great idea started on a napkin.
6
+
7
+ ```bash
8
+ npm install -g napkin-ai
9
+ ```
10
+
11
+ ---
12
+
13
+ ## Quick Start
14
+
15
+ ```bash
16
+ # Initialize a vault
17
+ napkin init --template coding
18
+
19
+ # See what's in it
20
+ napkin overview
21
+
22
+ # Search for something
23
+ napkin search "authentication"
24
+
25
+ # Read a file
26
+ napkin read "Architecture"
27
+
28
+ # Write
29
+ napkin create "Decision" --template Decision
30
+ napkin append "Decision" "We chose Postgres."
31
+ napkin daily append "- [ ] Review PR"
32
+ ```
33
+
34
+ ---
35
+
36
+ ## SDK
37
+
38
+ napkin is also a library. No CLI, no stdout - just data:
39
+
40
+ ```typescript
41
+ import { Napkin } from "napkin-ai";
42
+
43
+ // Always works - creates bare vault if needed
44
+ const n = new Napkin("/path/to/project");
45
+
46
+ // Progressive disclosure
47
+ const overview = n.overview();
48
+ const results = n.search("authentication");
49
+ const file = n.read("Architecture");
50
+
51
+ // Write
52
+ n.create({ name: "New Note", content: "# Hello" });
53
+ n.append("New Note", "\nMore content");
54
+
55
+ // Daily notes
56
+ n.dailyEnsure();
57
+ n.dailyAppend("- Met with team");
58
+
59
+ // Everything else
60
+ n.tags();
61
+ n.tasks({ todo: true });
62
+ n.linksBack("Architecture");
63
+ n.outline("Architecture");
64
+ n.properties();
65
+ n.bookmarks();
66
+ n.config();
67
+ ```
68
+
69
+ Scaffold with a template:
70
+
71
+ ```typescript
72
+ Napkin.scaffold("/path/to/project", { template: "coding" });
73
+ Napkin.vaultTemplates(); // list available templates
74
+ ```
75
+
76
+ All SDK methods return typed data and throw errors on failure. No `console.log`, no `process.exit`.
77
+
78
+ ---
79
+
80
+ ## Progressive Disclosure
81
+
82
+ napkin is designed as a memory system for agents. Instead of dumping the full vault into context, it reveals information gradually:
83
+
84
+ | Level | Command | Tokens | What it does |
85
+ |-------|---------|--------|-------------|
86
+ | 0 | `NAPKIN.md` | ~200 | Project context note |
87
+ | 1 | `napkin overview` | ~1-2k | L0 + vault map with TF-IDF keywords |
88
+ | 2 | `napkin search <query>` | ~2-5k | Ranked results with snippets |
89
+ | 3 | `napkin read <file>` | ~5-20k | Full file content |
90
+
91
+ ## Benchmarks
92
+
93
+ napkin includes agentic retrieval benchmarks in `bench/`. The headline result is [LongMemEval](https://arxiv.org/abs/2410.10813) (ICLR 2025), which tests long-term conversational memory across 500 questions.
94
+
95
+ | Dataset | Sessions | pi + napkin | Best prior system | GPT-4o full context |
96
+ |---------|----------|-------------|-------------------|---------------------|
97
+ | Oracle | 1-6 | **92.0%** | 92.4% | 92.4% |
98
+ | S | ~40 | **91.0%** | 86% | 64% |
99
+ | M | ~500 | **83.0%** | 72% | n/a |
100
+
101
+ Zero preprocessing. No embeddings, no graphs, no summaries. Just BM25 search on markdown files.
102
+
103
+ See [`bench/README.md`](bench/README.md) for details and usage.
104
+
105
+ ---
106
+
107
+ ## Vault Structure
108
+
109
+ `.napkin/` holds config. Content lives in the project directory alongside `.obsidian/`:
110
+
111
+ ```
112
+ my-project/
113
+ .napkin/ # napkin config
114
+ config.json # Unified config (syncs to .obsidian/)
115
+ .obsidian/ # Obsidian config (auto-generated)
116
+ NAPKIN.md # Context note (Level 0)
117
+ decisions/ # Template-defined directories
118
+ architecture/
119
+ Templates/ # Note templates
120
+ src/ # Your project (not in vault)
121
+ ```
122
+
123
+ ## Templates
124
+
125
+ Scaffold a vault with a domain-specific structure:
126
+
127
+ ```bash
128
+ napkin init --template coding # decisions/, architecture/, guides/, changelog/
129
+ napkin init --template company # people/, projects/, runbooks/, infrastructure/
130
+ napkin init --template product # features/, roadmap/, research/, specs/, releases/
131
+ napkin init --template personal # people/, projects/, areas/, references/
132
+ napkin init --template research # papers/, concepts/, questions/, experiments/
133
+ ```
134
+
135
+ Each template includes directory structure, `_about.md` files, Obsidian note templates, and a `NAPKIN.md` skeleton.
136
+
137
+ ---
138
+
139
+ ## For Agents
140
+
141
+ Every command supports `--json` for structured output and `-q` for raw output:
142
+
143
+ ```bash
144
+ napkin overview --json # Structured vault map
145
+ napkin search "auth" --json # Ranked results as JSON
146
+ napkin read "Note" -q # Raw markdown, nothing else
147
+ ```
148
+
149
+ ---
150
+
151
+ ## CLI Reference
152
+
153
+ ### Global Flags
154
+
155
+ | Flag | Description |
156
+ |---|---|
157
+ | `--json` | Output as JSON |
158
+ | `-q, --quiet` | Suppress output |
159
+ | `--vault <path>` | Vault path (default: auto-detect from cwd) |
160
+ | `--copy` | Copy output to clipboard |
161
+
162
+ ### Core
163
+
164
+ ```bash
165
+ napkin vault # Vault info
166
+ napkin overview # Vault map with keywords
167
+ napkin read <file> # Read file contents
168
+ napkin create "Note" $'# Hello\nFirst note.' # Create with content
169
+ napkin append "Note" $'\n## Update\nNew info.' # Append to file
170
+ napkin prepend "Note" $'---\ntags: [new]\n---' # Prepend frontmatter
171
+ napkin move "Note" Archive # Move to folder
172
+ napkin rename "Note" "Renamed" # Rename file
173
+ napkin delete "Note" # Move to .trash
174
+ napkin search "meeting" # Ranked search with snippets
175
+ napkin search "TODO" --no-snippets # Files only
176
+ echo "piped content" | napkin append "Note" # Stdin support
177
+ ```
178
+
179
+ ### Files & Folders - `napkin file`
180
+
181
+ ```bash
182
+ napkin file info <name> # File info (path, size, dates)
183
+ napkin file list # List all files
184
+ napkin file list --ext md # Filter by extension
185
+ napkin file list --folder Projects # Filter by folder
186
+ napkin file folder <path> # Folder info
187
+ napkin file folders # List all folders
188
+ napkin file outline "note" # Heading tree
189
+ napkin file wordcount "note" # Word + character count
190
+ ```
191
+
192
+ ### Daily Notes - `napkin daily`
193
+
194
+ ```bash
195
+ napkin daily today # Create today's daily note
196
+ napkin daily path # Print daily note path
197
+ napkin daily read # Print daily note contents
198
+ napkin daily append "- [ ] Buy groceries"
199
+ napkin daily prepend "## Morning"
200
+ ```
201
+
202
+ ### Tags - `napkin tag`
203
+
204
+ ```bash
205
+ napkin tag list # List all tags
206
+ napkin tag list --counts # With occurrence counts
207
+ napkin tag list --sort count # Sort by frequency
208
+ napkin tag info --name "project" # Tag info
209
+ napkin tag aliases # List all aliases
210
+ ```
211
+
212
+ ### Properties - `napkin property`
213
+
214
+ ```bash
215
+ napkin property list # List all properties
216
+ napkin property list --file "note" # Properties for a file
217
+ napkin property read --file "note" --name title
218
+ napkin property set --file "note" --name status --value done
219
+ napkin property remove --file "note" --name status
220
+ ```
221
+
222
+ ### Tasks - `napkin task`
223
+
224
+ ```bash
225
+ napkin task list # List all tasks
226
+ napkin task list --todo # Incomplete only
227
+ napkin task list --done # Completed only
228
+ napkin task list --daily # Today's daily note tasks
229
+ napkin task show --file "note" --line 3 --toggle
230
+ ```
231
+
232
+ ### Links - `napkin link`
233
+
234
+ ```bash
235
+ napkin link out --file "note" # Outgoing links
236
+ napkin link back --file "note" # Backlinks
237
+ napkin link unresolved # Broken links
238
+ napkin link orphans # No incoming links
239
+ napkin link deadends # No outgoing links
240
+ ```
241
+
242
+ ### Bases - `napkin base`
243
+
244
+ ```bash
245
+ napkin base list # List .base files
246
+ napkin base views --file "projects" # List views
247
+ napkin base query --file "projects" # Query default view
248
+ napkin base query --file "projects" --view "Active" --format csv
249
+ napkin base create --file "projects" --name "New Item"
250
+ ```
251
+
252
+ ### Canvas - `napkin canvas`
253
+
254
+ ```bash
255
+ napkin canvas list # List .canvas files
256
+ napkin canvas read --file "Board" # Dump canvas
257
+ napkin canvas nodes --file "Board" # List nodes
258
+ napkin canvas create --file "Board" # Create empty canvas
259
+ napkin canvas add-node --file "Board" --type text --text "# Hello"
260
+ napkin canvas add-edge --file "Board" --from abc1 --to def2
261
+ napkin canvas remove-node --file "Board" --id abc1
262
+ ```
263
+
264
+ ### Templates - `napkin template`
265
+
266
+ ```bash
267
+ napkin template list # List note templates
268
+ napkin template read --name "Daily Note"
269
+ napkin template insert --file "note" --name "Template"
270
+ ```
271
+
272
+ ### Bookmarks - `napkin bookmark`
273
+
274
+ ```bash
275
+ napkin bookmark list # List bookmarks
276
+ napkin bookmark add --file "note" # Bookmark a file
277
+ ```
278
+
279
+ ### Config - `napkin config`
280
+
281
+ ```bash
282
+ napkin config show # Show full config
283
+ napkin config get --key search.limit # Get a value
284
+ napkin config set --key search.limit --value 50
285
+ ```
286
+
287
+ ### Graph - `napkin graph`
288
+
289
+ ```bash
290
+ napkin graph # Interactive vault graph
291
+ ```
292
+
293
+ Force-directed graph of vault notes and wikilinks. Click nodes to read content in a sidebar.
294
+
295
+ ---
296
+
297
+ ## File Resolution
298
+
299
+ Files can be referenced two ways:
300
+ - **By name** (wikilink-style): `"Active Projects"` - searches all `.md` files by basename
301
+ - **By path**: `"Projects/Active Projects.md"` - exact path from vault root
302
+
303
+ ---
304
+
305
+ ## Architecture
306
+
307
+ ```
308
+ src/
309
+ index.ts # SDK exports: Napkin class + all types
310
+ sdk.ts # Napkin class wrapping core modules
311
+ main.ts # CLI entry (Commander) - thin wrapper
312
+ core/ # Pure logic, returns data, no stdout
313
+ commands/ # CLI wrappers: parse args → sdk → format + print
314
+ utils/ # Shared utilities (files, frontmatter, markdown, etc.)
315
+ ```
316
+
317
+ Core modules never call `console.log`, `process.exit`, or import output utilities. They return typed data and throw errors. The CLI commands are thin wrappers that instantiate the SDK, call methods, and format the output.
318
+
319
+ ---
320
+
321
+ ## Pi Integration
322
+
323
+ For [pi](https://github.com/badlogic/pi) users, install [pi-napkin](https://github.com/Michaelliv/pi-napkin) — vault context injection, `kb_search`/`kb_read` tools, and automatic distillation.
324
+
325
+ ```bash
326
+ pi install git:github.com/Michaelliv/pi-napkin
327
+ ```
328
+
329
+ ---
330
+
331
+ ## Development
332
+
333
+ ```bash
334
+ bun install
335
+ bun run dev -- vault --json
336
+ bun test
337
+ bun run check
338
+ ```
339
+
340
+ ## License
341
+
342
+ MIT
@@ -0,0 +1,7 @@
1
+ import { type OutputOptions } from "../utils/output.js";
2
+ export declare function aliases(opts: OutputOptions & {
3
+ vault?: string;
4
+ file?: string;
5
+ total?: boolean;
6
+ verbose?: boolean;
7
+ }): Promise<void>;
@@ -0,0 +1,25 @@
1
+ import { Napkin } from "../sdk.js";
2
+ import { dim, output } from "../utils/output.js";
3
+ export async function aliases(opts) {
4
+ const n = new Napkin(opts.vault || process.cwd());
5
+ const result = n.aliases(opts.file);
6
+ output(opts, {
7
+ json: () => {
8
+ if (opts.total)
9
+ return { total: result.length };
10
+ if (opts.verbose)
11
+ return { aliases: result };
12
+ return { aliases: result.map((r) => r.alias) };
13
+ },
14
+ human: () => {
15
+ if (opts.total) {
16
+ console.log(result.length);
17
+ }
18
+ else {
19
+ for (const r of result) {
20
+ console.log(opts.verbose ? `${r.alias}\t${dim(r.file)}` : r.alias);
21
+ }
22
+ }
23
+ },
24
+ });
25
+ }
@@ -0,0 +1,23 @@
1
+ import { type OutputOptions } from "../utils/output.js";
2
+ export declare function bases(opts: OutputOptions & {
3
+ vault?: string;
4
+ }): Promise<void>;
5
+ export declare function baseViews(opts: OutputOptions & {
6
+ vault?: string;
7
+ file?: string;
8
+ path?: string;
9
+ }): Promise<void>;
10
+ export declare function baseQuery(opts: OutputOptions & {
11
+ vault?: string;
12
+ file?: string;
13
+ path?: string;
14
+ view?: string;
15
+ format?: string;
16
+ }): Promise<void>;
17
+ export declare function baseCreate(opts: OutputOptions & {
18
+ vault?: string;
19
+ file?: string;
20
+ path?: string;
21
+ name?: string;
22
+ content?: string;
23
+ }): Promise<void>;
@@ -0,0 +1,139 @@
1
+ import { Napkin } from "../sdk.js";
2
+ import { EXIT_USER_ERROR } from "../utils/exit-codes.js";
3
+ import { bold, dim, error, output, success, } from "../utils/output.js";
4
+ export async function bases(opts) {
5
+ const n = new Napkin(opts.vault || process.cwd());
6
+ const files = n.bases();
7
+ output(opts, {
8
+ json: () => ({ bases: files }),
9
+ human: () => {
10
+ if (files.length === 0) {
11
+ console.log("No .base files found");
12
+ }
13
+ else {
14
+ for (const f of files)
15
+ console.log(f);
16
+ }
17
+ },
18
+ });
19
+ }
20
+ export async function baseViews(opts) {
21
+ const n = new Napkin(opts.vault || process.cwd());
22
+ let views;
23
+ try {
24
+ views = n.baseViews(opts);
25
+ }
26
+ catch (e) {
27
+ error(e.message);
28
+ process.exit(EXIT_USER_ERROR);
29
+ }
30
+ output(opts, {
31
+ json: () => ({ views }),
32
+ human: () => {
33
+ for (const view of views) {
34
+ console.log(`${bold(view.name)} ${dim(view.type)}`);
35
+ }
36
+ },
37
+ });
38
+ }
39
+ export async function baseQuery(opts) {
40
+ const n = new Napkin(opts.vault || process.cwd());
41
+ let result;
42
+ try {
43
+ result = await n.baseQuery(opts, opts.view);
44
+ }
45
+ catch (e) {
46
+ error(e.message);
47
+ process.exit(EXIT_USER_ERROR);
48
+ }
49
+ const fmt = opts.format || "json";
50
+ const displayCols = result.columns.map((c) => result.displayNames?.[c] || c);
51
+ output(opts, {
52
+ json: () => {
53
+ if (fmt === "paths") {
54
+ const pathIdx = result.columns.indexOf("path");
55
+ return { paths: result.rows.map((r) => r[pathIdx]) };
56
+ }
57
+ // Convert to array of objects
58
+ const rows = result.rows.map((row) => {
59
+ const obj = {};
60
+ for (let i = 0; i < result.columns.length; i++) {
61
+ obj[result.columns[i]] = row[i];
62
+ }
63
+ return obj;
64
+ });
65
+ const out = { columns: result.columns, rows };
66
+ if (result.displayNames && Object.keys(result.displayNames).length > 0) {
67
+ out.displayNames = result.displayNames;
68
+ }
69
+ if (result.groups) {
70
+ out.groups = result.groups.map((g) => ({
71
+ key: g.key,
72
+ rows: g.rows.map((row) => {
73
+ const obj = {};
74
+ for (let i = 0; i < result.columns.length; i++) {
75
+ obj[result.columns[i]] = row[i];
76
+ }
77
+ return obj;
78
+ }),
79
+ }));
80
+ }
81
+ if (result.summaries)
82
+ out.summaries = result.summaries;
83
+ return out;
84
+ },
85
+ human: () => {
86
+ if (result.rows.length === 0) {
87
+ console.log("No results");
88
+ return;
89
+ }
90
+ if (fmt === "paths") {
91
+ const pathIdx = result.columns.indexOf("path");
92
+ for (const row of result.rows)
93
+ console.log(row[pathIdx]);
94
+ return;
95
+ }
96
+ if (fmt === "csv" || fmt === "tsv") {
97
+ const sep = fmt === "csv" ? "," : "\t";
98
+ console.log(displayCols.join(sep));
99
+ for (const row of result.rows) {
100
+ console.log(row.map((v) => (v === null ? "" : String(v))).join(sep));
101
+ }
102
+ return;
103
+ }
104
+ if (fmt === "md") {
105
+ console.log(`| ${displayCols.join(" | ")} |`);
106
+ console.log(`| ${displayCols.map(() => "---").join(" | ")} |`);
107
+ for (const row of result.rows) {
108
+ console.log(`| ${row.map((v) => (v === null ? "" : String(v))).join(" | ")} |`);
109
+ }
110
+ return;
111
+ }
112
+ // Default: table-like
113
+ for (const row of result.rows) {
114
+ const obj = {};
115
+ for (let i = 0; i < result.columns.length; i++) {
116
+ if (row[i] !== null)
117
+ obj[result.columns[i]] = row[i];
118
+ }
119
+ console.log(JSON.stringify(obj));
120
+ }
121
+ },
122
+ });
123
+ }
124
+ export async function baseCreate(opts) {
125
+ const n = new Napkin(opts.vault || process.cwd());
126
+ if (!opts.name) {
127
+ error("No name specified. Use --name <name>");
128
+ process.exit(EXIT_USER_ERROR);
129
+ }
130
+ const result = n.baseCreate({
131
+ name: opts.name,
132
+ path: opts.path,
133
+ content: opts.content,
134
+ });
135
+ output(opts, {
136
+ json: () => result,
137
+ human: () => success(`Created ${result.path}`),
138
+ });
139
+ }
@@ -0,0 +1,15 @@
1
+ import { type OutputOptions } from "../utils/output.js";
2
+ export declare function bookmarks(opts: OutputOptions & {
3
+ vault?: string;
4
+ total?: boolean;
5
+ verbose?: boolean;
6
+ }): Promise<void>;
7
+ export declare function bookmark(opts: OutputOptions & {
8
+ vault?: string;
9
+ file?: string;
10
+ subpath?: string;
11
+ folder?: string;
12
+ search?: string;
13
+ url?: string;
14
+ title?: string;
15
+ }): Promise<void>;
@@ -0,0 +1,51 @@
1
+ import { Napkin } from "../sdk.js";
2
+ import { EXIT_USER_ERROR } from "../utils/exit-codes.js";
3
+ import { dim, error, output, success, } from "../utils/output.js";
4
+ export async function bookmarks(opts) {
5
+ const n = new Napkin(opts.vault || process.cwd());
6
+ const flat = n.bookmarks();
7
+ output(opts, {
8
+ json: () => (opts.total ? { total: flat.length } : { bookmarks: flat }),
9
+ human: () => {
10
+ if (opts.total) {
11
+ console.log(flat.length);
12
+ }
13
+ else {
14
+ for (const b of flat) {
15
+ const label = b.title || b.path || b.query || b.url || "(untitled)";
16
+ console.log(opts.verbose ? `${label}\t${dim(b.type)}` : label);
17
+ }
18
+ }
19
+ },
20
+ });
21
+ }
22
+ export async function bookmark(opts) {
23
+ const n = new Napkin(opts.vault || process.cwd());
24
+ let entry;
25
+ if (opts.file) {
26
+ entry = {
27
+ type: "file",
28
+ path: opts.file,
29
+ title: opts.title,
30
+ subpath: opts.subpath,
31
+ };
32
+ }
33
+ else if (opts.folder) {
34
+ entry = { type: "folder", path: opts.folder, title: opts.title };
35
+ }
36
+ else if (opts.search) {
37
+ entry = { type: "search", query: opts.search, title: opts.title };
38
+ }
39
+ else if (opts.url) {
40
+ entry = { type: "url", url: opts.url, title: opts.title };
41
+ }
42
+ else {
43
+ error("Specify --file, --folder, --search, or --url to bookmark");
44
+ process.exit(EXIT_USER_ERROR);
45
+ }
46
+ const result = n.bookmarkAdd(entry);
47
+ output(opts, {
48
+ json: () => result,
49
+ human: () => success(`Bookmarked ${result.added.path || result.added.query || result.added.url}`),
50
+ });
51
+ }
@@ -0,0 +1,49 @@
1
+ import { type OutputOptions } from "../utils/output.js";
2
+ export declare function canvases(opts: OutputOptions & {
3
+ vault?: string;
4
+ total?: boolean;
5
+ }): Promise<void>;
6
+ export declare function canvasRead(opts: OutputOptions & {
7
+ vault?: string;
8
+ file?: string;
9
+ }): Promise<void>;
10
+ export declare function canvasNodes(opts: OutputOptions & {
11
+ vault?: string;
12
+ file?: string;
13
+ type?: string;
14
+ }): Promise<void>;
15
+ export declare function canvasCreate(opts: OutputOptions & {
16
+ vault?: string;
17
+ file?: string;
18
+ path?: string;
19
+ }): Promise<void>;
20
+ export declare function canvasAddNode(opts: OutputOptions & {
21
+ vault?: string;
22
+ file?: string;
23
+ type?: string;
24
+ text?: string;
25
+ noteFile?: string;
26
+ subpath?: string;
27
+ url?: string;
28
+ label?: string;
29
+ x?: string;
30
+ y?: string;
31
+ width?: string;
32
+ height?: string;
33
+ color?: string;
34
+ }): Promise<void>;
35
+ export declare function canvasAddEdge(opts: OutputOptions & {
36
+ vault?: string;
37
+ file?: string;
38
+ from?: string;
39
+ to?: string;
40
+ fromSide?: string;
41
+ toSide?: string;
42
+ label?: string;
43
+ color?: string;
44
+ }): Promise<void>;
45
+ export declare function canvasRemoveNode(opts: OutputOptions & {
46
+ vault?: string;
47
+ file?: string;
48
+ id?: string;
49
+ }): Promise<void>;