resurf 1.0.0

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/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # Resurf CLI
2
+
3
+ Access Resurf vault data from the terminal.
4
+
5
+ ## Install from npm
6
+
7
+ ```bash
8
+ npm install -g resurf
9
+ ```
10
+
11
+ Or with Bun:
12
+
13
+ ```bash
14
+ bun install -g resurf
15
+ ```
16
+
17
+ Then run:
18
+
19
+ ```bash
20
+ resurf vaults
21
+ resurf list --limit 10
22
+ resurf --help
23
+ ```
24
+
25
+ ## Run from repo
26
+
27
+ From the monorepo root (after building the CLI once):
28
+
29
+ ```bash
30
+ bun run resurf:build # build the CLI
31
+ bun run resurf -- vaults
32
+ bun run resurf -- list --limit 5
33
+ bun run resurf -- --help
34
+ ```
35
+
36
+ ## Install globally (use `resurf` anywhere)
37
+
38
+ From this package directory:
39
+
40
+ ```bash
41
+ cd packages/resurf-cli
42
+ bun run build
43
+ bun link
44
+ ```
45
+
46
+ Then you can run `resurf` from any terminal:
47
+
48
+ ```bash
49
+ resurf vaults
50
+ resurf list --json
51
+ resurf --help
52
+ ```
53
+
54
+ To remove the global link: `bun unlink` (from `packages/resurf-cli`).
package/dist/index.js ADDED
@@ -0,0 +1,1063 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/reader.ts
4
+ import * as fs2 from "fs/promises";
5
+ import * as path2 from "path";
6
+
7
+ // src/vault.ts
8
+ import * as fs from "fs/promises";
9
+ import * as os from "os";
10
+ import * as path from "path";
11
+ var VAULT_NAMES = ["Resurf Vault", "Resurf Vault Dev"];
12
+ var APP_NAMES = ["Resurf", "Resurf Dev"];
13
+ var CONFIG_FILES = ["app.json", "app.dev.json"];
14
+ function getVaultStructure(vaultPath) {
15
+ const root = path.resolve(vaultPath);
16
+ return {
17
+ root,
18
+ captures: path.join(root, "captures"),
19
+ attachments: path.join(root, "attachments"),
20
+ index: path.join(root, ".index"),
21
+ config: path.join(root, ".config"),
22
+ trash: path.join(root, ".trash")
23
+ };
24
+ }
25
+ async function hasVaultConfig(dir) {
26
+ try {
27
+ const configPath = path.join(dir, ".config", "vault.json");
28
+ await fs.access(configPath);
29
+ return true;
30
+ } catch {
31
+ return false;
32
+ }
33
+ }
34
+ async function getVaultNameFromConfig(dir) {
35
+ try {
36
+ const configPath = path.join(dir, ".config", "vault.json");
37
+ const data = await fs.readFile(configPath, "utf-8");
38
+ const config = JSON.parse(data);
39
+ return config.name ?? path.basename(dir);
40
+ } catch {
41
+ return path.basename(dir);
42
+ }
43
+ }
44
+ async function getCurrentVaultFromAppConfig() {
45
+ const home = os.homedir();
46
+ const base = path.join(home, "Library", "Application Support");
47
+ for (const appName of APP_NAMES) {
48
+ for (const configFile of CONFIG_FILES) {
49
+ const configPath = path.join(base, appName, configFile);
50
+ try {
51
+ const data = await fs.readFile(configPath, "utf-8");
52
+ const config = JSON.parse(data);
53
+ const vaultPath = config.vaultPath?.trim();
54
+ if (vaultPath) {
55
+ const valid = await hasVaultConfig(vaultPath);
56
+ return { path: vaultPath, valid };
57
+ }
58
+ } catch {
59
+ }
60
+ }
61
+ }
62
+ return null;
63
+ }
64
+ function getDefaultSearchDirs() {
65
+ const home = os.homedir();
66
+ const dirs = [];
67
+ const documents = path.join(home, "Documents");
68
+ dirs.push(documents);
69
+ for (const name of VAULT_NAMES) {
70
+ dirs.push(path.join(documents, name));
71
+ }
72
+ const iCloud = path.join(home, "Library", "Mobile Documents", "com~apple~CloudDocs");
73
+ dirs.push(iCloud);
74
+ for (const name of VAULT_NAMES) {
75
+ dirs.push(path.join(iCloud, name));
76
+ }
77
+ return dirs;
78
+ }
79
+ async function findVaults(options) {
80
+ const vaults = [];
81
+ const seen = /* @__PURE__ */ new Set();
82
+ const current = await getCurrentVaultFromAppConfig();
83
+ if (current?.path && current.valid) {
84
+ const name = await getVaultNameFromConfig(current.path);
85
+ vaults.push({ path: path.resolve(current.path), name, current: true });
86
+ seen.add(path.resolve(current.path));
87
+ }
88
+ const searchDirs = options?.scanDir ? [options.scanDir] : getDefaultSearchDirs();
89
+ for (const dir of searchDirs) {
90
+ try {
91
+ await fs.access(dir);
92
+ } catch {
93
+ if (options?.verbose) console.error("Skipping (inaccessible):", dir);
94
+ continue;
95
+ }
96
+ if (await hasVaultConfig(dir)) {
97
+ const resolved = path.resolve(dir);
98
+ if (!seen.has(resolved)) {
99
+ const name = await getVaultNameFromConfig(dir);
100
+ vaults.push({
101
+ path: resolved,
102
+ name,
103
+ current: !!current?.path && path.resolve(current.path) === resolved
104
+ });
105
+ seen.add(resolved);
106
+ }
107
+ } else if (options?.scanDir) {
108
+ await findVaultsRecursive(dir, vaults, seen, current?.path ? path.resolve(current.path) : null);
109
+ } else {
110
+ const base = path.basename(dir);
111
+ if (base === "Documents" || base === "com~apple~CloudDocs") {
112
+ for (const vname of VAULT_NAMES) {
113
+ const sub = path.join(dir, vname);
114
+ try {
115
+ await fs.access(sub);
116
+ if (await hasVaultConfig(sub)) {
117
+ const resolved = path.resolve(sub);
118
+ if (!seen.has(resolved)) {
119
+ const name = await getVaultNameFromConfig(sub);
120
+ vaults.push({
121
+ path: resolved,
122
+ name,
123
+ current: !!current?.path && path.resolve(current.path) === resolved
124
+ });
125
+ seen.add(resolved);
126
+ }
127
+ }
128
+ } catch {
129
+ }
130
+ }
131
+ }
132
+ }
133
+ }
134
+ const currentResolved = current?.path ? path.resolve(current.path) : null;
135
+ const normalized = vaults.map((v) => ({
136
+ ...v,
137
+ path: path.resolve(v.path),
138
+ current: currentResolved === path.resolve(v.path)
139
+ }));
140
+ return Array.from(new Map(normalized.map((v) => [v.path, v])).values());
141
+ }
142
+ async function findVaultsRecursive(dir, results, seen, currentResolved) {
143
+ try {
144
+ const stat3 = await fs.stat(dir);
145
+ if (!stat3.isDirectory()) return;
146
+ if (seen.has(dir)) return;
147
+ seen.add(dir);
148
+ if (await hasVaultConfig(dir)) {
149
+ const name = await getVaultNameFromConfig(dir);
150
+ results.push({
151
+ path: path.resolve(dir),
152
+ name,
153
+ current: currentResolved === path.resolve(dir)
154
+ });
155
+ return;
156
+ }
157
+ const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => []);
158
+ for (const ent of entries) {
159
+ if (ent.isDirectory() && !ent.name.startsWith(".")) {
160
+ const child = path.join(dir, ent.name);
161
+ await findVaultsRecursive(child, results, seen, currentResolved);
162
+ }
163
+ }
164
+ } catch {
165
+ }
166
+ }
167
+ async function discoverVaultPath(override) {
168
+ if (override?.trim()) {
169
+ const resolved = path.resolve(override);
170
+ const valid = await hasVaultConfig(resolved);
171
+ if (!valid) {
172
+ throw new Error(`Not a valid Resurf vault: ${resolved}`);
173
+ }
174
+ return resolved;
175
+ }
176
+ const current = await getCurrentVaultFromAppConfig();
177
+ if (current?.path && current.valid) {
178
+ return path.resolve(current.path);
179
+ }
180
+ const home = os.homedir();
181
+ const documents = path.join(home, "Documents");
182
+ const iCloud = path.join(home, "Library", "Mobile Documents", "com~apple~CloudDocs");
183
+ for (const name of VAULT_NAMES) {
184
+ for (const parent of [documents, iCloud]) {
185
+ const candidate = path.join(parent, name);
186
+ try {
187
+ await fs.access(candidate);
188
+ if (await hasVaultConfig(candidate)) {
189
+ return path.resolve(candidate);
190
+ }
191
+ } catch {
192
+ }
193
+ }
194
+ }
195
+ const fallback = path.join(documents, VAULT_NAMES[0]);
196
+ throw new Error(
197
+ `No Resurf vault found. Set one with --vault <path>, or create a vault at ${fallback}`
198
+ );
199
+ }
200
+
201
+ // src/reader.ts
202
+ async function readJson(filePath) {
203
+ try {
204
+ const data = await fs2.readFile(filePath, "utf-8");
205
+ return JSON.parse(data);
206
+ } catch {
207
+ return null;
208
+ }
209
+ }
210
+ var VaultReader = class {
211
+ structure;
212
+ constructor(vaultPath) {
213
+ this.structure = getVaultStructure(vaultPath);
214
+ }
215
+ get vaultPath() {
216
+ return this.structure.root;
217
+ }
218
+ async getCaptureIndex() {
219
+ const indexPath = path2.join(this.structure.index, "index.captures.json");
220
+ const data = await readJson(indexPath);
221
+ if (!data) return [];
222
+ return Object.values(data);
223
+ }
224
+ async getSpaces() {
225
+ const indexPath = path2.join(this.structure.index, "index.spaces.json");
226
+ const data = await readJson(indexPath);
227
+ if (!data) return [];
228
+ return Object.values(data);
229
+ }
230
+ async getAreas() {
231
+ const indexPath = path2.join(this.structure.index, "index.areas.json");
232
+ const data = await readJson(indexPath);
233
+ if (!data) return [];
234
+ return Object.values(data);
235
+ }
236
+ async getCanvases() {
237
+ const indexPath = path2.join(this.structure.index, "index.canvases.json");
238
+ const data = await readJson(indexPath);
239
+ if (!data) return [];
240
+ return Object.values(data);
241
+ }
242
+ async getTags() {
243
+ const indexPath = path2.join(this.structure.index, "index.tags.json");
244
+ const data = await readJson(indexPath);
245
+ return data ?? [];
246
+ }
247
+ async getCaptureById(id) {
248
+ const capturePath = path2.join(this.structure.captures, `${id}.json`);
249
+ return readJson(capturePath);
250
+ }
251
+ async listCaptures(options = {}) {
252
+ let captures = await this.getCaptureIndex();
253
+ captures = captures.filter((c) => !c.isHidden);
254
+ if (options.spaceKey) {
255
+ captures = captures.filter((c) => c.spaceKeys?.includes(options.spaceKey));
256
+ }
257
+ if (options.tag) {
258
+ captures = captures.filter((c) => c.tags?.includes(options.tag));
259
+ }
260
+ if (options.contentType) {
261
+ captures = captures.filter((c) => {
262
+ const ct = c.contentType;
263
+ if (Array.isArray(ct)) return ct.includes(options.contentType);
264
+ return ct === options.contentType;
265
+ });
266
+ }
267
+ if (options.pinned !== void 0) {
268
+ captures = captures.filter((c) => c.isPinned === options.pinned);
269
+ }
270
+ if (options.search) {
271
+ const q = options.search.toLowerCase();
272
+ captures = captures.filter((c) => {
273
+ const fields = [c.title, c.note, c.tldr, c.source, ...c.tags ?? []].filter(Boolean);
274
+ return fields.some((f) => f.toLowerCase().includes(q));
275
+ });
276
+ }
277
+ const sortField = options.sortBy === "updated" ? "updatedAt" : "createdAt";
278
+ const sortDir = options.sortOrder === "asc" ? 1 : -1;
279
+ captures.sort((a, b) => (b[sortField] - a[sortField]) * sortDir);
280
+ const total = captures.length;
281
+ const offset = options.offset ?? 0;
282
+ const limit = options.limit ?? 20;
283
+ return {
284
+ captures: captures.slice(offset, offset + limit),
285
+ total
286
+ };
287
+ }
288
+ async getStats() {
289
+ const [captures, spaces, areas, canvases, tags] = await Promise.all([
290
+ this.getCaptureIndex(),
291
+ this.getSpaces(),
292
+ this.getAreas(),
293
+ this.getCanvases(),
294
+ this.getTags()
295
+ ]);
296
+ const byContentType = {};
297
+ const byTriageStatus = {};
298
+ for (const c of captures) {
299
+ const types = Array.isArray(c.contentType) ? c.contentType : c.contentType ? [c.contentType] : ["unknown"];
300
+ for (const t of types) {
301
+ byContentType[t] = (byContentType[t] ?? 0) + 1;
302
+ }
303
+ const status = c.triageStatus ?? "none";
304
+ byTriageStatus[status] = (byTriageStatus[status] ?? 0) + 1;
305
+ }
306
+ return {
307
+ totalCaptures: captures.length,
308
+ totalSpaces: spaces.length,
309
+ totalAreas: areas.length,
310
+ totalCanvases: canvases.length,
311
+ totalTags: tags.length,
312
+ byContentType,
313
+ byTriageStatus
314
+ };
315
+ }
316
+ async getVaultSize() {
317
+ let files = 0;
318
+ let bytes = 0;
319
+ const walk = async (dir) => {
320
+ try {
321
+ const entries = await fs2.readdir(dir, { withFileTypes: true });
322
+ for (const entry of entries) {
323
+ const full = path2.join(dir, entry.name);
324
+ if (entry.isDirectory()) {
325
+ await walk(full);
326
+ } else {
327
+ files++;
328
+ try {
329
+ const stat3 = await fs2.stat(full);
330
+ bytes += stat3.size;
331
+ } catch {
332
+ }
333
+ }
334
+ }
335
+ } catch {
336
+ }
337
+ };
338
+ await walk(this.structure.root);
339
+ return { files, bytes };
340
+ }
341
+ };
342
+
343
+ // src/format.ts
344
+ import * as path3 from "path";
345
+ function formatVaults(vaults, format) {
346
+ if (format === "json") return JSON.stringify(vaults, null, 2);
347
+ if (vaults.length === 0) return "No vaults found.";
348
+ if (format === "md") {
349
+ const lines = [];
350
+ lines.push(`| Path | Name | Current |`);
351
+ lines.push(`| --- | --- | --- |`);
352
+ for (const v of vaults) {
353
+ lines.push(`| \`${v.path}\` | ${v.name} | ${v.current ? "yes" : ""} |`);
354
+ }
355
+ return lines.join("\n");
356
+ }
357
+ if (format === "table") {
358
+ const pathW = 60;
359
+ const nameW = 24;
360
+ const header = `${padRight("PATH", pathW)} ${padRight("NAME", nameW)} CURRENT`;
361
+ const sep = "\u2500".repeat(header.length);
362
+ const rows = vaults.map((v) => {
363
+ const p = truncate(v.path, pathW);
364
+ const n = truncate(v.name, nameW);
365
+ return `${padRight(p, pathW)} ${padRight(n, nameW)} ${v.current ? "yes" : ""}`;
366
+ });
367
+ return [sep, header, sep, ...rows, sep].join("\n");
368
+ }
369
+ return vaults.map((v) => `${v.path}${v.current ? " (current)" : ""}`).join("\n");
370
+ }
371
+ function truncate(str, max) {
372
+ if (str.length <= max) return str;
373
+ return str.slice(0, max - 1) + "\u2026";
374
+ }
375
+ function formatDate(ts) {
376
+ return new Date(ts).toLocaleString();
377
+ }
378
+ function relativeTime(ts) {
379
+ const diff = Date.now() - ts;
380
+ const seconds = Math.floor(diff / 1e3);
381
+ if (seconds < 60) return `${seconds}s ago`;
382
+ const minutes = Math.floor(seconds / 60);
383
+ if (minutes < 60) return `${minutes}m ago`;
384
+ const hours = Math.floor(minutes / 60);
385
+ if (hours < 24) return `${hours}h ago`;
386
+ const days = Math.floor(hours / 24);
387
+ if (days < 30) return `${days}d ago`;
388
+ const months = Math.floor(days / 30);
389
+ if (months < 12) return `${months}mo ago`;
390
+ return `${Math.floor(months / 12)}y ago`;
391
+ }
392
+ function padRight(str, len) {
393
+ return str + " ".repeat(Math.max(0, len - str.length));
394
+ }
395
+ function padLeft(str, len) {
396
+ return " ".repeat(Math.max(0, len - str.length)) + str;
397
+ }
398
+ function formatContentType(ct) {
399
+ if (!ct) return "\u2014";
400
+ if (Array.isArray(ct)) return ct.join(", ");
401
+ return ct;
402
+ }
403
+ function isEmbeddableImage(mime) {
404
+ return /^image\/(png|jpe?g|gif|webp|svg\+xml|bmp|avif)$/i.test(mime);
405
+ }
406
+ function isEmbeddableVideo(mime) {
407
+ return /^video\/(mp4|webm|mov|quicktime)$/i.test(mime);
408
+ }
409
+ function resolveAttachmentPath(vaultPath, relativePath) {
410
+ return path3.resolve(vaultPath, relativePath);
411
+ }
412
+ function formatSize(bytes) {
413
+ if (bytes < 1024) return `${bytes} B`;
414
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
415
+ if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
416
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
417
+ }
418
+ function formatCaptureList(captures, total, format) {
419
+ if (format === "json") return JSON.stringify({ captures, total }, null, 2);
420
+ if (captures.length === 0) return "No captures found.";
421
+ if (format === "md") {
422
+ const lines2 = [];
423
+ lines2.push(`| ID | Type | Title | Tags | Created |`);
424
+ lines2.push(`| --- | --- | --- | --- | --- |`);
425
+ for (const c of captures) {
426
+ const id = `\`${c.id.slice(0, 8)}\``;
427
+ const ct = formatContentType(c.contentType);
428
+ const title = c.title ? c.title.replace(/\|/g, "\\|") : "_(untitled)_";
429
+ const tags = c.tags?.length ? c.tags.map((t) => `\`${t}\``).join(", ") : "";
430
+ const date = relativeTime(c.createdAt);
431
+ lines2.push(`| ${id} | ${ct} | ${title} | ${tags} | ${date} |`);
432
+ }
433
+ lines2.push("");
434
+ lines2.push(`_Showing ${captures.length} of ${total} captures_`);
435
+ return lines2.join("\n");
436
+ }
437
+ if (format === "table") {
438
+ const idW = 10;
439
+ const typeW = 12;
440
+ const titleW = 40;
441
+ const tagsW = 20;
442
+ const dateW = 12;
443
+ const header = `${padRight("ID", idW)} ${padRight("TYPE", typeW)} ${padRight("TITLE", titleW)} ${padRight("TAGS", tagsW)} ${padRight("CREATED", dateW)}`;
444
+ const sep = "\u2500".repeat(header.length);
445
+ const rows = captures.map((c) => {
446
+ const id = truncate(c.id, idW);
447
+ const ct = truncate(formatContentType(c.contentType), typeW);
448
+ const title = truncate(c.title ?? "(untitled)", titleW);
449
+ const tags = truncate(c.tags?.join(", ") ?? "", tagsW);
450
+ const date = relativeTime(c.createdAt);
451
+ return `${padRight(id, idW)} ${padRight(ct, typeW)} ${padRight(title, titleW)} ${padRight(tags, tagsW)} ${padRight(date, dateW)}`;
452
+ });
453
+ return [`${sep}`, header, sep, ...rows, sep, `Showing ${captures.length} of ${total}`].join(
454
+ "\n"
455
+ );
456
+ }
457
+ const lines = [];
458
+ for (const c of captures) {
459
+ const pin = c.isPinned ? " \u{1F4CC}" : "";
460
+ const title = c.title ?? "(untitled)";
461
+ const ct = formatContentType(c.contentType);
462
+ lines.push(` ${c.id.slice(0, 8)} ${ct.padEnd(10)} ${title}${pin}`);
463
+ if (c.tldr) lines.push(` ${truncate(c.tldr, 70)}`);
464
+ if (c.tags?.length) lines.push(` tags: ${c.tags.join(", ")}`);
465
+ lines.push("");
466
+ }
467
+ lines.push(`${captures.length} of ${total} captures`);
468
+ return lines.join("\n");
469
+ }
470
+ function formatCapture(capture, format, vaultPath) {
471
+ if (format === "json") return JSON.stringify(capture, null, 2);
472
+ if (format === "md") {
473
+ const lines2 = [];
474
+ const title = capture.title || "Untitled Capture";
475
+ lines2.push(`# ${title}`);
476
+ lines2.push("");
477
+ const content2 = capture.content;
478
+ if (content2?.type === "attachment" && content2.path) {
479
+ const fullPath = vaultPath ? resolveAttachmentPath(vaultPath, String(content2.path)) : String(content2.path);
480
+ const mime = String(content2.mimeType ?? "");
481
+ if (isEmbeddableImage(mime)) {
482
+ lines2.push(`![${title}](${fullPath})`);
483
+ lines2.push("");
484
+ } else if (isEmbeddableVideo(mime)) {
485
+ lines2.push(`[Video: ${title}](${fullPath})`);
486
+ lines2.push("");
487
+ }
488
+ }
489
+ lines2.push(`- **ID:** \`${capture.id}\``);
490
+ lines2.push(`- **Type:** ${capture.type} (${formatContentType(capture.contentType)})`);
491
+ if (capture.source) lines2.push(`- **Source:** ${capture.source}`);
492
+ lines2.push(`- **Created:** ${formatDate(capture.createdAt)}`);
493
+ lines2.push(`- **Updated:** ${formatDate(capture.updatedAt)}`);
494
+ if (capture.isPinned) lines2.push(`- **Pinned:** yes`);
495
+ if (capture.tags?.length)
496
+ lines2.push(`- **Tags:** ${capture.tags.map((t) => `\`${t}\``).join(", ")}`);
497
+ if (capture.spaceKeys?.length)
498
+ lines2.push(`- **Spaces:** ${capture.spaceKeys.map((k) => `\`${k}\``).join(", ")}`);
499
+ if (capture.triageStatus) lines2.push(`- **Triage:** ${capture.triageStatus}`);
500
+ if (capture.tldr) {
501
+ lines2.push("");
502
+ lines2.push(`## TLDR`);
503
+ lines2.push(capture.tldr);
504
+ }
505
+ if (capture.note) {
506
+ lines2.push("");
507
+ lines2.push(`## Note`);
508
+ lines2.push(capture.note);
509
+ }
510
+ if (content2) {
511
+ if (content2.type === "note" && content2.textContent) {
512
+ lines2.push("");
513
+ lines2.push(`## Content`);
514
+ lines2.push(String(content2.textContent));
515
+ } else if (content2.type === "link") {
516
+ lines2.push("");
517
+ lines2.push(`## Content`);
518
+ if (content2.url) lines2.push(`**URL:** ${content2.url}`);
519
+ if (content2.ogTitle) lines2.push(`**OG Title:** ${content2.ogTitle}`);
520
+ if (content2.ogDescription)
521
+ lines2.push(`**OG Description:** ${truncate(String(content2.ogDescription), 200)}`);
522
+ } else if (content2.type === "attachment") {
523
+ const fullPath = vaultPath ? resolveAttachmentPath(vaultPath, String(content2.path)) : String(content2.path ?? "");
524
+ lines2.push("");
525
+ lines2.push(`## Attachment`);
526
+ if (content2.mimeType) lines2.push(`- **MIME:** ${content2.mimeType}`);
527
+ if (content2.size) lines2.push(`- **Size:** ${formatSize(Number(content2.size))}`);
528
+ lines2.push(`- **Path:** \`${fullPath}\``);
529
+ }
530
+ }
531
+ return lines2.join("\n");
532
+ }
533
+ const lines = [];
534
+ const sep = "\u2500".repeat(60);
535
+ lines.push(sep);
536
+ lines.push(` ID: ${capture.id}`);
537
+ lines.push(` Type: ${capture.type} (${formatContentType(capture.contentType)})`);
538
+ if (capture.title) lines.push(` Title: ${capture.title}`);
539
+ if (capture.source) lines.push(` Source: ${capture.source}`);
540
+ lines.push(` Created: ${formatDate(capture.createdAt)}`);
541
+ lines.push(` Updated: ${formatDate(capture.updatedAt)}`);
542
+ if (capture.isPinned) lines.push(` Pinned: yes`);
543
+ if (capture.tags?.length) lines.push(` Tags: ${capture.tags.join(", ")}`);
544
+ if (capture.spaceKeys?.length) lines.push(` Spaces: ${capture.spaceKeys.join(", ")}`);
545
+ if (capture.triageStatus) lines.push(` Triage: ${capture.triageStatus}`);
546
+ if (capture.processingStatus) lines.push(` Status: ${capture.processingStatus}`);
547
+ if (capture.tldr) {
548
+ lines.push(sep);
549
+ lines.push(" TLDR:");
550
+ lines.push(` ${capture.tldr}`);
551
+ }
552
+ if (capture.note) {
553
+ lines.push(sep);
554
+ lines.push(" Note:");
555
+ lines.push(` ${capture.note}`);
556
+ }
557
+ const content = capture.content;
558
+ if (content) {
559
+ lines.push(sep);
560
+ lines.push(" Content:");
561
+ if (content.type === "note" && content.textContent) {
562
+ const text = String(content.textContent);
563
+ lines.push(` ${truncate(text, 500)}`);
564
+ } else if (content.type === "link") {
565
+ if (content.url) lines.push(` URL: ${content.url}`);
566
+ if (content.ogTitle) lines.push(` OG Title: ${content.ogTitle}`);
567
+ if (content.ogDescription)
568
+ lines.push(` OG Desc: ${truncate(String(content.ogDescription), 200)}`);
569
+ } else if (content.type === "attachment") {
570
+ if (content.mimeType) lines.push(` MIME: ${content.mimeType}`);
571
+ if (content.size) lines.push(` Size: ${formatSize(Number(content.size))}`);
572
+ if (content.path) {
573
+ const fullPath = vaultPath ? resolveAttachmentPath(vaultPath, String(content.path)) : String(content.path);
574
+ lines.push(` Path: ${fullPath}`);
575
+ }
576
+ }
577
+ }
578
+ lines.push(sep);
579
+ return lines.join("\n");
580
+ }
581
+ function formatSpaces(spaces, format) {
582
+ if (format === "json") return JSON.stringify(spaces, null, 2);
583
+ if (spaces.length === 0) return "No spaces found.";
584
+ if (format === "md") {
585
+ const lines = [];
586
+ lines.push(`| Key | Name | Captures | Pinned |`);
587
+ lines.push(`| --- | --- | ---: | --- |`);
588
+ for (const s of spaces) {
589
+ const pin = s.isPinned ? "yes" : "";
590
+ lines.push(`| \`${s.key}\` | ${s.name} | ${s.noteCount ?? 0} | ${pin} |`);
591
+ }
592
+ return lines.join("\n");
593
+ }
594
+ if (format === "table") {
595
+ const keyW = 20;
596
+ const nameW = 30;
597
+ const countW = 8;
598
+ const header = `${padRight("KEY", keyW)} ${padRight("NAME", nameW)} ${padLeft("COUNT", countW)}`;
599
+ const sep = "\u2500".repeat(header.length);
600
+ const rows = spaces.map((s) => {
601
+ return `${padRight(truncate(s.key, keyW), keyW)} ${padRight(truncate(s.name, nameW), nameW)} ${padLeft(String(s.noteCount ?? 0), countW)}`;
602
+ });
603
+ return [sep, header, sep, ...rows, sep].join("\n");
604
+ }
605
+ return spaces.map((s) => {
606
+ const pin = s.isPinned ? " \u{1F4CC}" : "";
607
+ return ` ${s.key.padEnd(20)} ${s.name}${pin} (${s.noteCount ?? 0} captures)`;
608
+ }).join("\n");
609
+ }
610
+ function formatAreas(areas, format) {
611
+ if (format === "json") return JSON.stringify(areas, null, 2);
612
+ if (areas.length === 0) return "No areas found.";
613
+ if (format === "md") {
614
+ const lines = [];
615
+ lines.push(`| Key | Name |`);
616
+ lines.push(`| --- | --- |`);
617
+ for (const a of areas) {
618
+ lines.push(`| \`${a.key}\` | ${a.name} |`);
619
+ }
620
+ return lines.join("\n");
621
+ }
622
+ return areas.map((a) => ` ${a.key.padEnd(20)} ${a.name}`).join("\n");
623
+ }
624
+ function formatTags(tags, format) {
625
+ if (format === "json") return JSON.stringify(tags, null, 2);
626
+ if (tags.length === 0) return "No tags found.";
627
+ if (format === "md") {
628
+ return tags.map((t) => `- \`${t}\``).join("\n");
629
+ }
630
+ return tags.map((t) => ` ${t}`).join("\n");
631
+ }
632
+ function formatCanvases(canvases, format) {
633
+ if (format === "json") return JSON.stringify(canvases, null, 2);
634
+ if (canvases.length === 0) return "No canvases found.";
635
+ if (format === "md") {
636
+ const lines = [];
637
+ lines.push(`| ID | Name | Nodes | Connections |`);
638
+ lines.push(`| --- | --- | ---: | ---: |`);
639
+ for (const c of canvases) {
640
+ lines.push(
641
+ `| \`${c.id.slice(0, 8)}\` | ${c.name} | ${c.nodes.length} | ${c.connections.length} |`
642
+ );
643
+ }
644
+ return lines.join("\n");
645
+ }
646
+ return canvases.map(
647
+ (c) => ` ${c.id.slice(0, 8)} ${c.name} (${c.nodes.length} nodes, ${c.connections.length} connections)`
648
+ ).join("\n");
649
+ }
650
+ function formatStats(stats, vaultPath, format) {
651
+ if (format === "json") return JSON.stringify({ vaultPath, ...stats }, null, 2);
652
+ if (format === "md") {
653
+ const lines2 = [];
654
+ lines2.push(`# Vault Stats`);
655
+ lines2.push("");
656
+ lines2.push(`**Path:** \`${vaultPath}\``);
657
+ lines2.push("");
658
+ lines2.push(`| Metric | Count |`);
659
+ lines2.push(`| --- | ---: |`);
660
+ lines2.push(`| Captures | ${stats.totalCaptures} |`);
661
+ lines2.push(`| Spaces | ${stats.totalSpaces} |`);
662
+ lines2.push(`| Areas | ${stats.totalAreas} |`);
663
+ lines2.push(`| Canvases | ${stats.totalCanvases} |`);
664
+ lines2.push(`| Tags | ${stats.totalTags} |`);
665
+ lines2.push("");
666
+ lines2.push(`### By Content Type`);
667
+ lines2.push("");
668
+ lines2.push(`| Type | Count |`);
669
+ lines2.push(`| --- | ---: |`);
670
+ const sortedTypes2 = Object.entries(stats.byContentType).sort((a, b) => b[1] - a[1]);
671
+ for (const [type, count] of sortedTypes2) {
672
+ lines2.push(`| ${type} | ${count} |`);
673
+ }
674
+ lines2.push("");
675
+ lines2.push(`### By Triage Status`);
676
+ lines2.push("");
677
+ lines2.push(`| Status | Count |`);
678
+ lines2.push(`| --- | ---: |`);
679
+ const sortedStatus2 = Object.entries(stats.byTriageStatus).sort((a, b) => b[1] - a[1]);
680
+ for (const [status, count] of sortedStatus2) {
681
+ lines2.push(`| ${status} | ${count} |`);
682
+ }
683
+ return lines2.join("\n");
684
+ }
685
+ const sep = "\u2500".repeat(40);
686
+ const lines = [];
687
+ lines.push(sep);
688
+ lines.push(` Vault: ${vaultPath}`);
689
+ lines.push(sep);
690
+ lines.push(` Captures: ${stats.totalCaptures}`);
691
+ lines.push(` Spaces: ${stats.totalSpaces}`);
692
+ lines.push(` Areas: ${stats.totalAreas}`);
693
+ lines.push(` Canvases: ${stats.totalCanvases}`);
694
+ lines.push(` Tags: ${stats.totalTags}`);
695
+ lines.push(sep);
696
+ lines.push(" By Content Type:");
697
+ const sortedTypes = Object.entries(stats.byContentType).sort((a, b) => b[1] - a[1]);
698
+ for (const [type, count] of sortedTypes) {
699
+ lines.push(` ${type.padEnd(14)} ${count}`);
700
+ }
701
+ lines.push(sep);
702
+ lines.push(" By Triage Status:");
703
+ const sortedStatus = Object.entries(stats.byTriageStatus).sort((a, b) => b[1] - a[1]);
704
+ for (const [status, count] of sortedStatus) {
705
+ lines.push(` ${status.padEnd(14)} ${count}`);
706
+ }
707
+ lines.push(sep);
708
+ return lines.join("\n");
709
+ }
710
+
711
+ // src/index.ts
712
+ var VERSION = "1.0.0";
713
+ function parseGlobalFlags(args) {
714
+ const flags = { format: "pretty" };
715
+ const rest = [];
716
+ let i = 0;
717
+ while (i < args.length) {
718
+ const arg = args[i];
719
+ if (arg === "--vault" && i + 1 < args.length) {
720
+ flags.vault = args[i + 1];
721
+ i += 2;
722
+ } else if (arg === "--json") {
723
+ flags.format = "json";
724
+ i++;
725
+ } else if (arg === "--md" || arg === "--markdown") {
726
+ flags.format = "md";
727
+ i++;
728
+ } else if (arg === "--table") {
729
+ flags.format = "table";
730
+ i++;
731
+ } else if (arg === "--format" && i + 1 < args.length) {
732
+ flags.format = args[i + 1];
733
+ i += 2;
734
+ } else if (arg === "--verbose") {
735
+ flags.verbose = true;
736
+ i++;
737
+ } else {
738
+ rest.push(arg);
739
+ i++;
740
+ }
741
+ }
742
+ return { flags, rest };
743
+ }
744
+ function extractFlag(args, flag) {
745
+ const idx = args.indexOf(flag);
746
+ if (idx === -1 || idx + 1 >= args.length) return void 0;
747
+ return args[idx + 1];
748
+ }
749
+ function hasFlag(args, flag) {
750
+ return args.includes(flag);
751
+ }
752
+ function extractNumber(args, flag, defaultVal) {
753
+ const val = extractFlag(args, flag);
754
+ if (!val) return defaultVal;
755
+ const n = parseInt(val, 10);
756
+ return isNaN(n) ? defaultVal : n;
757
+ }
758
+ async function cmdList(reader, args, format) {
759
+ const limit = extractNumber(args, "--limit", 20);
760
+ const offset = extractNumber(args, "--offset", 0);
761
+ const spaceKey = extractFlag(args, "--space");
762
+ const tag = extractFlag(args, "--tag");
763
+ const contentType = extractFlag(args, "--type");
764
+ const search = extractFlag(args, "--search") ?? extractFlag(args, "-s");
765
+ const pinned = hasFlag(args, "--pinned") ? true : void 0;
766
+ const sortBy = extractFlag(args, "--sort") ?? "created";
767
+ const sortOrder = hasFlag(args, "--asc") ? "asc" : "desc";
768
+ const result = await reader.listCaptures({
769
+ limit,
770
+ offset,
771
+ spaceKey,
772
+ tag,
773
+ contentType,
774
+ search,
775
+ pinned,
776
+ sortBy,
777
+ sortOrder
778
+ });
779
+ console.log(formatCaptureList(result.captures, result.total, format));
780
+ }
781
+ async function cmdGet(reader, args, format) {
782
+ const id = args[0];
783
+ if (!id) {
784
+ console.error("Usage: resurf get <capture-id>");
785
+ process.exit(1);
786
+ }
787
+ let capture = await reader.getCaptureById(id);
788
+ if (!capture) {
789
+ const index = await reader.getCaptureIndex();
790
+ const match = index.find((c) => c.id.startsWith(id));
791
+ if (match) {
792
+ capture = await reader.getCaptureById(match.id);
793
+ }
794
+ }
795
+ if (!capture) {
796
+ console.error(`Capture not found: ${id}`);
797
+ process.exit(1);
798
+ }
799
+ console.log(formatCapture(capture, format, reader.vaultPath));
800
+ }
801
+ async function cmdSearch(reader, args, format) {
802
+ const positional = [];
803
+ let i = 0;
804
+ while (i < args.length) {
805
+ if (args[i].startsWith("--") && i + 1 < args.length) {
806
+ i += 2;
807
+ } else if (args[i].startsWith("--")) {
808
+ i++;
809
+ } else {
810
+ positional.push(args[i]);
811
+ i++;
812
+ }
813
+ }
814
+ const query = positional.join(" ");
815
+ if (!query) {
816
+ console.error("Usage: resurf search <query>");
817
+ process.exit(1);
818
+ }
819
+ const limit = extractNumber(args, "--limit", 20);
820
+ const result = await reader.listCaptures({ search: query, limit });
821
+ console.log(formatCaptureList(result.captures, result.total, format));
822
+ }
823
+ async function cmdSpaces(reader, _args, format) {
824
+ const spaces = await reader.getSpaces();
825
+ console.log(formatSpaces(spaces, format));
826
+ }
827
+ async function cmdAreas(reader, _args, format) {
828
+ const areas = await reader.getAreas();
829
+ console.log(formatAreas(areas, format));
830
+ }
831
+ async function cmdTags(reader, _args, format) {
832
+ const tags = await reader.getTags();
833
+ console.log(formatTags(tags, format));
834
+ }
835
+ async function cmdCanvases(reader, _args, format) {
836
+ const canvases = await reader.getCanvases();
837
+ console.log(formatCanvases(canvases, format));
838
+ }
839
+ async function cmdStats(reader, _args, format) {
840
+ const stats = await reader.getStats();
841
+ console.log(formatStats(stats, reader.vaultPath, format));
842
+ }
843
+ async function cmdOpen(reader, args) {
844
+ const id = args[0];
845
+ if (!id) {
846
+ console.error("Usage: resurf open <capture-id>");
847
+ process.exit(1);
848
+ }
849
+ let captureId = id;
850
+ const capture = await reader.getCaptureById(id);
851
+ if (!capture) {
852
+ const index = await reader.getCaptureIndex();
853
+ const match = index.find((c) => c.id.startsWith(id));
854
+ if (match) captureId = match.id;
855
+ }
856
+ const { exec } = await import("child_process");
857
+ const url = `resurf://capture/${captureId}`;
858
+ exec(`open "${url}"`);
859
+ console.log(`Opening capture in Resurf: ${captureId}`);
860
+ }
861
+ async function cmdCreate(args) {
862
+ const content = extractFlag(args, "--content") ?? extractFlag(args, "--text");
863
+ const url = extractFlag(args, "--url");
864
+ const title = extractFlag(args, "--title");
865
+ const tags = extractFlag(args, "--tags");
866
+ const source = extractFlag(args, "--source");
867
+ const space = extractFlag(args, "--space");
868
+ if (!content && !url) {
869
+ console.error(
870
+ "Usage: resurf create --content <text> [--url <url>] [--title <title>] [--tags <tags>]"
871
+ );
872
+ process.exit(1);
873
+ }
874
+ const params = new URLSearchParams();
875
+ if (content) params.set("content", content);
876
+ if (url) params.set("url", url);
877
+ if (title) params.set("title", title);
878
+ if (tags) params.set("tags", tags);
879
+ if (source) params.set("source", source);
880
+ if (space) params.set("space", space);
881
+ const protocolUrl = `resurf://new?${params.toString()}`;
882
+ const { exec } = await import("child_process");
883
+ exec(`open "${protocolUrl}"`);
884
+ console.log("Creating capture via Resurf protocol...");
885
+ }
886
+ async function cmdExport(reader, args, format) {
887
+ const spaceKey = extractFlag(args, "--space");
888
+ const tag = extractFlag(args, "--tag");
889
+ const contentType = extractFlag(args, "--type");
890
+ const result = await reader.listCaptures({
891
+ limit: 999999,
892
+ spaceKey,
893
+ tag,
894
+ contentType
895
+ });
896
+ const captures = [];
897
+ for (const item of result.captures) {
898
+ const full = await reader.getCaptureById(item.id);
899
+ if (full) captures.push(full);
900
+ }
901
+ if (format === "json") {
902
+ console.log(JSON.stringify(captures, null, 2));
903
+ } else if (format === "md") {
904
+ const lines = [];
905
+ for (const c of captures) {
906
+ const cap = c;
907
+ const title = cap.title || "Untitled";
908
+ const id = cap.id;
909
+ lines.push(`## ${title}`);
910
+ lines.push(`- **ID:** \`${id}\``);
911
+ if (cap.contentType) lines.push(`- **Type:** ${cap.contentType}`);
912
+ if (cap.tldr) lines.push(`- **TLDR:** ${cap.tldr}`);
913
+ if (cap.note) lines.push(`- **Note:** ${cap.note}`);
914
+ lines.push("");
915
+ }
916
+ lines.push(`_Exported ${captures.length} captures_`);
917
+ console.log(lines.join("\n"));
918
+ } else {
919
+ console.log(JSON.stringify(captures, null, 2));
920
+ console.error(`
921
+ Exported ${captures.length} captures (use --json or --md for piping)`);
922
+ }
923
+ }
924
+ function printHelp() {
925
+ const help = `
926
+ resurf - Access Resurf vault data from the command line
927
+
928
+ USAGE
929
+ resurf <command> [options]
930
+
931
+ COMMANDS
932
+ list List captures (default)
933
+ get <id> Get a capture by ID (supports partial IDs)
934
+ search <query> Search captures by title, note, or TLDR
935
+ spaces List all spaces
936
+ areas List all areas
937
+ tags List all tags
938
+ canvases List all canvases
939
+ stats Show vault statistics
940
+ vaults List available Resurf vaults on this computer
941
+ open <id> Open a capture in Resurf app
942
+ create Create a capture via Resurf protocol
943
+ export Export captures as JSON
944
+
945
+ GLOBAL OPTIONS
946
+ --vault <path> Path to Resurf vault (auto-detected if omitted)
947
+ --json Output as JSON
948
+ --md, --markdown Output as Markdown
949
+ --table Output as table
950
+ --format <fmt> Output format: json, md, table, pretty (default: pretty)
951
+
952
+ LIST OPTIONS
953
+ --limit <n> Max results (default: 20)
954
+ --offset <n> Skip first N results
955
+ --space <key> Filter by space key
956
+ --tag <tag> Filter by tag
957
+ --type <type> Filter by content type (note, link, image, video, etc.)
958
+ --search <query> Filter by text search
959
+ --pinned Show only pinned captures
960
+ --sort <field> Sort by: created, updated (default: created)
961
+ --asc Sort ascending (default: descending)
962
+
963
+ SEARCH OPTIONS
964
+ --limit <n> Max results (default: 20)
965
+
966
+ CREATE OPTIONS
967
+ --content <text> Text content for the capture
968
+ --url <url> URL to capture
969
+ --title <title> Title for the capture
970
+ --tags <tags> Comma-separated tags
971
+ --source <source> Source identifier
972
+ --space <key> Space key to assign
973
+
974
+ EXPORT OPTIONS
975
+ --space <key> Filter by space key
976
+ --tag <tag> Filter by tag
977
+ --type <type> Filter by content type
978
+
979
+ VAULTS OPTIONS
980
+ [directory] Scan this directory recursively for vaults
981
+ --verbose Log skipped inaccessible paths
982
+
983
+ EXAMPLES
984
+ resurf list --limit 10 --json
985
+ resurf list --space work --type note
986
+ resurf get abc123
987
+ resurf search "meeting notes"
988
+ resurf search "react hooks" --json | jq '.[].title'
989
+ resurf spaces --json
990
+ resurf tags
991
+ resurf stats
992
+ resurf vaults
993
+ resurf vaults --json
994
+ resurf vaults /path/to/folder
995
+ resurf open abc123
996
+ resurf create --content "Quick note" --tags "idea,work"
997
+ resurf create --url "https://example.com" --title "Example"
998
+ resurf export --space work --json > work-captures.json
999
+ resurf list --json | jq '.captures[].id'
1000
+
1001
+ VERSION
1002
+ ${VERSION}
1003
+ `;
1004
+ console.log(help.trim());
1005
+ }
1006
+ async function main() {
1007
+ const rawArgs = process.argv.slice(2);
1008
+ if (rawArgs.length === 0 || rawArgs[0] === "--help" || rawArgs[0] === "-h") {
1009
+ printHelp();
1010
+ return;
1011
+ }
1012
+ if (rawArgs[0] === "--version" || rawArgs[0] === "-v") {
1013
+ console.log(VERSION);
1014
+ return;
1015
+ }
1016
+ const { flags, rest } = parseGlobalFlags(rawArgs);
1017
+ const command = rest[0] ?? "list";
1018
+ const commandArgs = rest.slice(1);
1019
+ if (command === "create") {
1020
+ await cmdCreate(commandArgs);
1021
+ return;
1022
+ }
1023
+ if (command === "vaults" || command === "find-vaults") {
1024
+ const scanDir = commandArgs.find((a) => !a.startsWith("-"));
1025
+ const vaults = await findVaults({ scanDir, verbose: flags.verbose });
1026
+ console.log(formatVaults(vaults, flags.format));
1027
+ return;
1028
+ }
1029
+ const vaultPath = await discoverVaultPath(flags.vault);
1030
+ const reader = new VaultReader(vaultPath);
1031
+ const commands = {
1032
+ list: cmdList,
1033
+ ls: cmdList,
1034
+ get: cmdGet,
1035
+ show: cmdGet,
1036
+ search: cmdSearch,
1037
+ find: cmdSearch,
1038
+ spaces: cmdSpaces,
1039
+ areas: cmdAreas,
1040
+ tags: cmdTags,
1041
+ canvases: cmdCanvases,
1042
+ stats: cmdStats,
1043
+ info: cmdStats,
1044
+ export: cmdExport
1045
+ };
1046
+ if (command === "open") {
1047
+ await cmdOpen(reader, commandArgs);
1048
+ return;
1049
+ }
1050
+ const handler = commands[command];
1051
+ if (!handler) {
1052
+ console.error(`Unknown command: ${command}`);
1053
+ console.error(`Run 'resurf --help' for usage.`);
1054
+ process.exit(1);
1055
+ }
1056
+ await handler(reader, commandArgs, flags.format);
1057
+ }
1058
+ main().catch((err) => {
1059
+ const message = err instanceof Error ? err.message : String(err);
1060
+ console.error(`Error: ${message}`);
1061
+ process.exit(1);
1062
+ });
1063
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/reader.ts","../src/vault.ts","../src/format.ts","../src/index.ts"],"sourcesContent":["import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { type VaultStructure, getVaultStructure } from \"./vault.js\";\n\nexport type CaptureIndex = {\n id: string;\n type: string;\n filePath?: string;\n createdAt: number;\n updatedAt: number;\n contentType?: string | string[];\n title?: string;\n tags?: string[];\n spaceKeys?: string[];\n mimeTypes?: string[];\n note?: string;\n tldr?: string;\n source?: string;\n isPinned?: boolean;\n isHidden?: boolean;\n triageStatus?: string;\n processingStatus?: string;\n};\n\nexport type Space = {\n id: string;\n name: string;\n key: string;\n areaKey?: string;\n icon?: string;\n color?: string;\n createdAt: number;\n updatedAt: number;\n noteCount?: number;\n isPinned?: boolean;\n};\n\nexport type Area = {\n id: string;\n name: string;\n key: string;\n createdAt: number;\n updatedAt: number;\n};\n\nexport type Canvas = {\n id: string;\n name: string;\n createdAt: number;\n updatedAt: number;\n nodes: unknown[];\n connections: unknown[];\n annotations: unknown[];\n};\n\nexport type Capture = CaptureIndex & {\n content: Record<string, unknown>;\n author?: Record<string, unknown>;\n colorPalette?: unknown[];\n embedding?: number[];\n};\n\ntype IndexMap<T> = Record<string, T>;\n\nasync function readJson<T>(filePath: string): Promise<T | null> {\n try {\n const data = await fs.readFile(filePath, \"utf-8\");\n return JSON.parse(data) as T;\n } catch {\n return null;\n }\n}\n\nexport class VaultReader {\n private structure: VaultStructure;\n\n constructor(vaultPath: string) {\n this.structure = getVaultStructure(vaultPath);\n }\n\n get vaultPath(): string {\n return this.structure.root;\n }\n\n async getCaptureIndex(): Promise<CaptureIndex[]> {\n const indexPath = path.join(this.structure.index, \"index.captures.json\");\n const data = await readJson<IndexMap<CaptureIndex>>(indexPath);\n if (!data) return [];\n return Object.values(data);\n }\n\n async getSpaces(): Promise<Space[]> {\n const indexPath = path.join(this.structure.index, \"index.spaces.json\");\n const data = await readJson<IndexMap<Space>>(indexPath);\n if (!data) return [];\n return Object.values(data);\n }\n\n async getAreas(): Promise<Area[]> {\n const indexPath = path.join(this.structure.index, \"index.areas.json\");\n const data = await readJson<IndexMap<Area>>(indexPath);\n if (!data) return [];\n return Object.values(data);\n }\n\n async getCanvases(): Promise<Canvas[]> {\n const indexPath = path.join(this.structure.index, \"index.canvases.json\");\n const data = await readJson<IndexMap<Canvas>>(indexPath);\n if (!data) return [];\n return Object.values(data);\n }\n\n async getTags(): Promise<string[]> {\n const indexPath = path.join(this.structure.index, \"index.tags.json\");\n const data = await readJson<string[]>(indexPath);\n return data ?? [];\n }\n\n async getCaptureById(id: string): Promise<Capture | null> {\n const capturePath = path.join(this.structure.captures, `${id}.json`);\n return readJson<Capture>(capturePath);\n }\n\n async listCaptures(\n options: {\n limit?: number;\n offset?: number;\n spaceKey?: string;\n tag?: string;\n contentType?: string;\n search?: string;\n pinned?: boolean;\n sortBy?: \"created\" | \"updated\";\n sortOrder?: \"asc\" | \"desc\";\n } = {}\n ): Promise<{ captures: CaptureIndex[]; total: number }> {\n let captures = await this.getCaptureIndex();\n\n captures = captures.filter((c) => !c.isHidden);\n\n if (options.spaceKey) {\n captures = captures.filter((c) => c.spaceKeys?.includes(options.spaceKey!));\n }\n\n if (options.tag) {\n captures = captures.filter((c) => c.tags?.includes(options.tag!));\n }\n\n if (options.contentType) {\n captures = captures.filter((c) => {\n const ct = c.contentType;\n if (Array.isArray(ct)) return ct.includes(options.contentType!);\n return ct === options.contentType;\n });\n }\n\n if (options.pinned !== undefined) {\n captures = captures.filter((c) => c.isPinned === options.pinned);\n }\n\n if (options.search) {\n const q = options.search.toLowerCase();\n captures = captures.filter((c) => {\n const fields = [c.title, c.note, c.tldr, c.source, ...(c.tags ?? [])].filter(Boolean);\n return fields.some((f) => f!.toLowerCase().includes(q));\n });\n }\n\n const sortField = options.sortBy === \"updated\" ? \"updatedAt\" : \"createdAt\";\n const sortDir = options.sortOrder === \"asc\" ? 1 : -1;\n captures.sort((a, b) => (b[sortField] - a[sortField]) * sortDir);\n\n const total = captures.length;\n const offset = options.offset ?? 0;\n const limit = options.limit ?? 20;\n\n return {\n captures: captures.slice(offset, offset + limit),\n total,\n };\n }\n\n async getStats(): Promise<{\n totalCaptures: number;\n totalSpaces: number;\n totalAreas: number;\n totalCanvases: number;\n totalTags: number;\n byContentType: Record<string, number>;\n byTriageStatus: Record<string, number>;\n }> {\n const [captures, spaces, areas, canvases, tags] = await Promise.all([\n this.getCaptureIndex(),\n this.getSpaces(),\n this.getAreas(),\n this.getCanvases(),\n this.getTags(),\n ]);\n\n const byContentType: Record<string, number> = {};\n const byTriageStatus: Record<string, number> = {};\n\n for (const c of captures) {\n const types = Array.isArray(c.contentType)\n ? c.contentType\n : c.contentType\n ? [c.contentType]\n : [\"unknown\"];\n for (const t of types) {\n byContentType[t] = (byContentType[t] ?? 0) + 1;\n }\n const status = c.triageStatus ?? \"none\";\n byTriageStatus[status] = (byTriageStatus[status] ?? 0) + 1;\n }\n\n return {\n totalCaptures: captures.length,\n totalSpaces: spaces.length,\n totalAreas: areas.length,\n totalCanvases: canvases.length,\n totalTags: tags.length,\n byContentType,\n byTriageStatus,\n };\n }\n\n async getVaultSize(): Promise<{ files: number; bytes: number }> {\n let files = 0;\n let bytes = 0;\n\n const walk = async (dir: string): Promise<void> => {\n try {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n await walk(full);\n } else {\n files++;\n try {\n const stat = await fs.stat(full);\n bytes += stat.size;\n } catch {}\n }\n }\n } catch {}\n };\n\n await walk(this.structure.root);\n return { files, bytes };\n }\n}\n","import * as fs from \"fs/promises\";\nimport * as os from \"os\";\nimport * as path from \"path\";\n\nconst VAULT_NAMES = [\"Resurf Vault\", \"Resurf Vault Dev\"];\nconst APP_NAMES = [\"Resurf\", \"Resurf Dev\"];\nconst CONFIG_FILES = [\"app.json\", \"app.dev.json\"];\n\nexport type VaultStructure = {\n root: string;\n captures: string;\n attachments: string;\n index: string;\n config: string;\n trash: string;\n};\n\nexport function getVaultStructure(vaultPath: string): VaultStructure {\n const root = path.resolve(vaultPath);\n return {\n root,\n captures: path.join(root, \"captures\"),\n attachments: path.join(root, \"attachments\"),\n index: path.join(root, \".index\"),\n config: path.join(root, \".config\"),\n trash: path.join(root, \".trash\"),\n };\n}\n\nexport async function hasVaultConfig(dir: string): Promise<boolean> {\n try {\n const configPath = path.join(dir, \".config\", \"vault.json\");\n await fs.access(configPath);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function getVaultNameFromConfig(dir: string): Promise<string> {\n try {\n const configPath = path.join(dir, \".config\", \"vault.json\");\n const data = await fs.readFile(configPath, \"utf-8\");\n const config = JSON.parse(data) as { name?: string };\n return config.name ?? path.basename(dir);\n } catch {\n return path.basename(dir);\n }\n}\n\nasync function getCurrentVaultFromAppConfig(): Promise<{\n path: string;\n valid: boolean;\n} | null> {\n const home = os.homedir();\n const base = path.join(home, \"Library\", \"Application Support\");\n for (const appName of APP_NAMES) {\n for (const configFile of CONFIG_FILES) {\n const configPath = path.join(base, appName, configFile);\n try {\n const data = await fs.readFile(configPath, \"utf-8\");\n const config = JSON.parse(data) as { vaultPath?: string };\n const vaultPath = config.vaultPath?.trim();\n if (vaultPath) {\n const valid = await hasVaultConfig(vaultPath);\n return { path: vaultPath, valid };\n }\n } catch {\n // ignore\n }\n }\n }\n return null;\n}\n\nfunction getDefaultSearchDirs(): string[] {\n const home = os.homedir();\n const dirs: string[] = [];\n const documents = path.join(home, \"Documents\");\n dirs.push(documents);\n for (const name of VAULT_NAMES) {\n dirs.push(path.join(documents, name));\n }\n const iCloud = path.join(home, \"Library\", \"Mobile Documents\", \"com~apple~CloudDocs\");\n dirs.push(iCloud);\n for (const name of VAULT_NAMES) {\n dirs.push(path.join(iCloud, name));\n }\n return dirs;\n}\n\nexport type VaultInfo = {\n path: string;\n name: string;\n current: boolean;\n};\n\nexport async function findVaults(options?: {\n scanDir?: string;\n verbose?: boolean;\n}): Promise<VaultInfo[]> {\n const vaults: VaultInfo[] = [];\n const seen = new Set<string>();\n\n const current = await getCurrentVaultFromAppConfig();\n if (current?.path && current.valid) {\n const name = await getVaultNameFromConfig(current.path);\n vaults.push({ path: path.resolve(current.path), name, current: true });\n seen.add(path.resolve(current.path));\n }\n\n const searchDirs = options?.scanDir ? [options.scanDir] : getDefaultSearchDirs();\n for (const dir of searchDirs) {\n try {\n await fs.access(dir);\n } catch {\n if (options?.verbose) console.error(\"Skipping (inaccessible):\", dir);\n continue;\n }\n if (await hasVaultConfig(dir)) {\n const resolved = path.resolve(dir);\n if (!seen.has(resolved)) {\n const name = await getVaultNameFromConfig(dir);\n vaults.push({\n path: resolved,\n name,\n current: !!current?.path && path.resolve(current.path) === resolved,\n });\n seen.add(resolved);\n }\n } else if (options?.scanDir) {\n await findVaultsRecursive(dir, vaults, seen, current?.path ? path.resolve(current.path) : null);\n } else {\n const base = path.basename(dir);\n if (base === \"Documents\" || base === \"com~apple~CloudDocs\") {\n for (const vname of VAULT_NAMES) {\n const sub = path.join(dir, vname);\n try {\n await fs.access(sub);\n if (await hasVaultConfig(sub)) {\n const resolved = path.resolve(sub);\n if (!seen.has(resolved)) {\n const name = await getVaultNameFromConfig(sub);\n vaults.push({\n path: resolved,\n name,\n current: !!current?.path && path.resolve(current.path) === resolved,\n });\n seen.add(resolved);\n }\n }\n } catch {\n // skip\n }\n }\n }\n }\n }\n\n const currentResolved = current?.path ? path.resolve(current.path) : null;\n const normalized = vaults.map((v) => ({\n ...v,\n path: path.resolve(v.path),\n current: currentResolved === path.resolve(v.path),\n }));\n return Array.from(new Map(normalized.map((v) => [v.path, v])).values());\n}\n\nasync function findVaultsRecursive(\n dir: string,\n results: VaultInfo[],\n seen: Set<string>,\n currentResolved: string | null\n): Promise<void> {\n try {\n const stat = await fs.stat(dir);\n if (!stat.isDirectory()) return;\n if (seen.has(dir)) return;\n seen.add(dir);\n\n if (await hasVaultConfig(dir)) {\n const name = await getVaultNameFromConfig(dir);\n results.push({\n path: path.resolve(dir),\n name,\n current: currentResolved === path.resolve(dir),\n });\n return;\n }\n\n const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => []);\n for (const ent of entries) {\n if (ent.isDirectory() && !ent.name.startsWith(\".\")) {\n const child = path.join(dir, ent.name);\n await findVaultsRecursive(child, results, seen, currentResolved);\n }\n }\n } catch {\n // skip inaccessible dirs\n }\n}\n\nexport async function discoverVaultPath(override?: string): Promise<string> {\n if (override?.trim()) {\n const resolved = path.resolve(override);\n const valid = await hasVaultConfig(resolved);\n if (!valid) {\n throw new Error(`Not a valid Resurf vault: ${resolved}`);\n }\n return resolved;\n }\n\n const current = await getCurrentVaultFromAppConfig();\n if (current?.path && current.valid) {\n return path.resolve(current.path);\n }\n\n const home = os.homedir();\n const documents = path.join(home, \"Documents\");\n const iCloud = path.join(home, \"Library\", \"Mobile Documents\", \"com~apple~CloudDocs\");\n\n for (const name of VAULT_NAMES) {\n for (const parent of [documents, iCloud]) {\n const candidate = path.join(parent, name);\n try {\n await fs.access(candidate);\n if (await hasVaultConfig(candidate)) {\n return path.resolve(candidate);\n }\n } catch {\n // skip\n }\n }\n }\n\n const fallback = path.join(documents, VAULT_NAMES[0]);\n throw new Error(\n `No Resurf vault found. Set one with --vault <path>, or create a vault at ${fallback}`\n );\n}\n","import * as path from \"path\";\nimport type { CaptureIndex, Capture, Space, Area, Canvas } from \"./reader.js\";\nimport type { VaultInfo } from \"./vault.js\";\n\nexport type OutputFormat = \"json\" | \"md\" | \"table\" | \"pretty\";\n\nexport function formatVaults(vaults: VaultInfo[], format: OutputFormat): string {\n if (format === \"json\") return JSON.stringify(vaults, null, 2);\n\n if (vaults.length === 0) return \"No vaults found.\";\n\n if (format === \"md\") {\n const lines: string[] = [];\n lines.push(`| Path | Name | Current |`);\n lines.push(`| --- | --- | --- |`);\n for (const v of vaults) {\n lines.push(`| \\`${v.path}\\` | ${v.name} | ${v.current ? \"yes\" : \"\"} |`);\n }\n return lines.join(\"\\n\");\n }\n\n if (format === \"table\") {\n const pathW = 60;\n const nameW = 24;\n const header = `${padRight(\"PATH\", pathW)} ${padRight(\"NAME\", nameW)} CURRENT`;\n const sep = \"─\".repeat(header.length);\n const rows = vaults.map((v) => {\n const p = truncate(v.path, pathW);\n const n = truncate(v.name, nameW);\n return `${padRight(p, pathW)} ${padRight(n, nameW)} ${v.current ? \"yes\" : \"\"}`;\n });\n return [sep, header, sep, ...rows, sep].join(\"\\n\");\n }\n\n return vaults\n .map((v) => `${v.path}${v.current ? \" (current)\" : \"\"}`)\n .join(\"\\n\");\n}\n\nfunction truncate(str: string, max: number): string {\n if (str.length <= max) return str;\n return str.slice(0, max - 1) + \"…\";\n}\n\nfunction formatDate(ts: number): string {\n return new Date(ts).toLocaleString();\n}\n\nfunction relativeTime(ts: number): string {\n const diff = Date.now() - ts;\n const seconds = Math.floor(diff / 1000);\n if (seconds < 60) return `${seconds}s ago`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m ago`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${hours}h ago`;\n const days = Math.floor(hours / 24);\n if (days < 30) return `${days}d ago`;\n const months = Math.floor(days / 30);\n if (months < 12) return `${months}mo ago`;\n return `${Math.floor(months / 12)}y ago`;\n}\n\nfunction padRight(str: string, len: number): string {\n return str + \" \".repeat(Math.max(0, len - str.length));\n}\n\nfunction padLeft(str: string, len: number): string {\n return \" \".repeat(Math.max(0, len - str.length)) + str;\n}\n\nfunction formatContentType(ct: string | string[] | undefined): string {\n if (!ct) return \"—\";\n if (Array.isArray(ct)) return ct.join(\", \");\n return ct;\n}\n\nfunction isEmbeddableImage(mime: string): boolean {\n return /^image\\/(png|jpe?g|gif|webp|svg\\+xml|bmp|avif)$/i.test(mime);\n}\n\nfunction isEmbeddableVideo(mime: string): boolean {\n return /^video\\/(mp4|webm|mov|quicktime)$/i.test(mime);\n}\n\nfunction resolveAttachmentPath(vaultPath: string, relativePath: string): string {\n return path.resolve(vaultPath, relativePath);\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;\n}\n\nexport function formatCaptureList(\n captures: CaptureIndex[],\n total: number,\n format: OutputFormat\n): string {\n if (format === \"json\") return JSON.stringify({ captures, total }, null, 2);\n\n if (captures.length === 0) return \"No captures found.\";\n\n if (format === \"md\") {\n const lines: string[] = [];\n lines.push(`| ID | Type | Title | Tags | Created |`);\n lines.push(`| --- | --- | --- | --- | --- |`);\n for (const c of captures) {\n const id = `\\`${c.id.slice(0, 8)}\\``;\n const ct = formatContentType(c.contentType);\n const title = c.title ? c.title.replace(/\\|/g, \"\\\\|\") : \"_(untitled)_\";\n const tags = c.tags?.length ? c.tags.map((t) => `\\`${t}\\``).join(\", \") : \"\";\n const date = relativeTime(c.createdAt);\n lines.push(`| ${id} | ${ct} | ${title} | ${tags} | ${date} |`);\n }\n lines.push(\"\");\n lines.push(`_Showing ${captures.length} of ${total} captures_`);\n return lines.join(\"\\n\");\n }\n\n if (format === \"table\") {\n const idW = 10;\n const typeW = 12;\n const titleW = 40;\n const tagsW = 20;\n const dateW = 12;\n\n const header = `${padRight(\"ID\", idW)} ${padRight(\"TYPE\", typeW)} ${padRight(\"TITLE\", titleW)} ${padRight(\"TAGS\", tagsW)} ${padRight(\"CREATED\", dateW)}`;\n const sep = \"─\".repeat(header.length);\n\n const rows = captures.map((c) => {\n const id = truncate(c.id, idW);\n const ct = truncate(formatContentType(c.contentType), typeW);\n const title = truncate(c.title ?? \"(untitled)\", titleW);\n const tags = truncate(c.tags?.join(\", \") ?? \"\", tagsW);\n const date = relativeTime(c.createdAt);\n return `${padRight(id, idW)} ${padRight(ct, typeW)} ${padRight(title, titleW)} ${padRight(tags, tagsW)} ${padRight(date, dateW)}`;\n });\n\n return [`${sep}`, header, sep, ...rows, sep, `Showing ${captures.length} of ${total}`].join(\n \"\\n\"\n );\n }\n\n const lines: string[] = [];\n for (const c of captures) {\n const pin = c.isPinned ? \" 📌\" : \"\";\n const title = c.title ?? \"(untitled)\";\n const ct = formatContentType(c.contentType);\n lines.push(` ${c.id.slice(0, 8)} ${ct.padEnd(10)} ${title}${pin}`);\n if (c.tldr) lines.push(` ${truncate(c.tldr, 70)}`);\n if (c.tags?.length) lines.push(` tags: ${c.tags.join(\", \")}`);\n lines.push(\"\");\n }\n lines.push(`${captures.length} of ${total} captures`);\n return lines.join(\"\\n\");\n}\n\nexport function formatCapture(capture: Capture, format: OutputFormat, vaultPath?: string): string {\n if (format === \"json\") return JSON.stringify(capture, null, 2);\n\n if (format === \"md\") {\n const lines: string[] = [];\n const title = capture.title || \"Untitled Capture\";\n lines.push(`# ${title}`);\n lines.push(\"\");\n\n const content = capture.content;\n if (content?.type === \"attachment\" && content.path) {\n const fullPath = vaultPath\n ? resolveAttachmentPath(vaultPath, String(content.path))\n : String(content.path);\n const mime = String(content.mimeType ?? \"\");\n\n if (isEmbeddableImage(mime)) {\n lines.push(`![${title}](${fullPath})`);\n lines.push(\"\");\n } else if (isEmbeddableVideo(mime)) {\n lines.push(`[Video: ${title}](${fullPath})`);\n lines.push(\"\");\n }\n }\n\n lines.push(`- **ID:** \\`${capture.id}\\``);\n lines.push(`- **Type:** ${capture.type} (${formatContentType(capture.contentType)})`);\n if (capture.source) lines.push(`- **Source:** ${capture.source}`);\n lines.push(`- **Created:** ${formatDate(capture.createdAt)}`);\n lines.push(`- **Updated:** ${formatDate(capture.updatedAt)}`);\n if (capture.isPinned) lines.push(`- **Pinned:** yes`);\n if (capture.tags?.length)\n lines.push(`- **Tags:** ${capture.tags.map((t) => `\\`${t}\\``).join(\", \")}`);\n if (capture.spaceKeys?.length)\n lines.push(`- **Spaces:** ${capture.spaceKeys.map((k) => `\\`${k}\\``).join(\", \")}`);\n if (capture.triageStatus) lines.push(`- **Triage:** ${capture.triageStatus}`);\n\n if (capture.tldr) {\n lines.push(\"\");\n lines.push(`## TLDR`);\n lines.push(capture.tldr);\n }\n\n if (capture.note) {\n lines.push(\"\");\n lines.push(`## Note`);\n lines.push(capture.note);\n }\n\n if (content) {\n if (content.type === \"note\" && content.textContent) {\n lines.push(\"\");\n lines.push(`## Content`);\n lines.push(String(content.textContent));\n } else if (content.type === \"link\") {\n lines.push(\"\");\n lines.push(`## Content`);\n if (content.url) lines.push(`**URL:** ${content.url}`);\n if (content.ogTitle) lines.push(`**OG Title:** ${content.ogTitle}`);\n if (content.ogDescription)\n lines.push(`**OG Description:** ${truncate(String(content.ogDescription), 200)}`);\n } else if (content.type === \"attachment\") {\n const fullPath = vaultPath\n ? resolveAttachmentPath(vaultPath, String(content.path))\n : String(content.path ?? \"\");\n lines.push(\"\");\n lines.push(`## Attachment`);\n if (content.mimeType) lines.push(`- **MIME:** ${content.mimeType}`);\n if (content.size) lines.push(`- **Size:** ${formatSize(Number(content.size))}`);\n lines.push(`- **Path:** \\`${fullPath}\\``);\n }\n }\n\n return lines.join(\"\\n\");\n }\n\n const lines: string[] = [];\n const sep = \"─\".repeat(60);\n\n lines.push(sep);\n lines.push(` ID: ${capture.id}`);\n lines.push(` Type: ${capture.type} (${formatContentType(capture.contentType)})`);\n if (capture.title) lines.push(` Title: ${capture.title}`);\n if (capture.source) lines.push(` Source: ${capture.source}`);\n lines.push(` Created: ${formatDate(capture.createdAt)}`);\n lines.push(` Updated: ${formatDate(capture.updatedAt)}`);\n if (capture.isPinned) lines.push(` Pinned: yes`);\n if (capture.tags?.length) lines.push(` Tags: ${capture.tags.join(\", \")}`);\n if (capture.spaceKeys?.length) lines.push(` Spaces: ${capture.spaceKeys.join(\", \")}`);\n if (capture.triageStatus) lines.push(` Triage: ${capture.triageStatus}`);\n if (capture.processingStatus) lines.push(` Status: ${capture.processingStatus}`);\n\n if (capture.tldr) {\n lines.push(sep);\n lines.push(\" TLDR:\");\n lines.push(` ${capture.tldr}`);\n }\n\n if (capture.note) {\n lines.push(sep);\n lines.push(\" Note:\");\n lines.push(` ${capture.note}`);\n }\n\n const content = capture.content;\n if (content) {\n lines.push(sep);\n lines.push(\" Content:\");\n if (content.type === \"note\" && content.textContent) {\n const text = String(content.textContent);\n lines.push(` ${truncate(text, 500)}`);\n } else if (content.type === \"link\") {\n if (content.url) lines.push(` URL: ${content.url}`);\n if (content.ogTitle) lines.push(` OG Title: ${content.ogTitle}`);\n if (content.ogDescription)\n lines.push(` OG Desc: ${truncate(String(content.ogDescription), 200)}`);\n } else if (content.type === \"attachment\") {\n if (content.mimeType) lines.push(` MIME: ${content.mimeType}`);\n if (content.size) lines.push(` Size: ${formatSize(Number(content.size))}`);\n if (content.path) {\n const fullPath = vaultPath\n ? resolveAttachmentPath(vaultPath, String(content.path))\n : String(content.path);\n lines.push(` Path: ${fullPath}`);\n }\n }\n }\n\n lines.push(sep);\n return lines.join(\"\\n\");\n}\n\nexport function formatSpaces(spaces: Space[], format: OutputFormat): string {\n if (format === \"json\") return JSON.stringify(spaces, null, 2);\n\n if (spaces.length === 0) return \"No spaces found.\";\n\n if (format === \"md\") {\n const lines: string[] = [];\n lines.push(`| Key | Name | Captures | Pinned |`);\n lines.push(`| --- | --- | ---: | --- |`);\n for (const s of spaces) {\n const pin = s.isPinned ? \"yes\" : \"\";\n lines.push(`| \\`${s.key}\\` | ${s.name} | ${s.noteCount ?? 0} | ${pin} |`);\n }\n return lines.join(\"\\n\");\n }\n\n if (format === \"table\") {\n const keyW = 20;\n const nameW = 30;\n const countW = 8;\n const header = `${padRight(\"KEY\", keyW)} ${padRight(\"NAME\", nameW)} ${padLeft(\"COUNT\", countW)}`;\n const sep = \"─\".repeat(header.length);\n\n const rows = spaces.map((s) => {\n return `${padRight(truncate(s.key, keyW), keyW)} ${padRight(truncate(s.name, nameW), nameW)} ${padLeft(String(s.noteCount ?? 0), countW)}`;\n });\n\n return [sep, header, sep, ...rows, sep].join(\"\\n\");\n }\n\n return spaces\n .map((s) => {\n const pin = s.isPinned ? \" 📌\" : \"\";\n return ` ${s.key.padEnd(20)} ${s.name}${pin} (${s.noteCount ?? 0} captures)`;\n })\n .join(\"\\n\");\n}\n\nexport function formatAreas(areas: Area[], format: OutputFormat): string {\n if (format === \"json\") return JSON.stringify(areas, null, 2);\n if (areas.length === 0) return \"No areas found.\";\n\n if (format === \"md\") {\n const lines: string[] = [];\n lines.push(`| Key | Name |`);\n lines.push(`| --- | --- |`);\n for (const a of areas) {\n lines.push(`| \\`${a.key}\\` | ${a.name} |`);\n }\n return lines.join(\"\\n\");\n }\n\n return areas.map((a) => ` ${a.key.padEnd(20)} ${a.name}`).join(\"\\n\");\n}\n\nexport function formatTags(tags: string[], format: OutputFormat): string {\n if (format === \"json\") return JSON.stringify(tags, null, 2);\n if (tags.length === 0) return \"No tags found.\";\n\n if (format === \"md\") {\n return tags.map((t) => `- \\`${t}\\``).join(\"\\n\");\n }\n\n return tags.map((t) => ` ${t}`).join(\"\\n\");\n}\n\nexport function formatCanvases(canvases: Canvas[], format: OutputFormat): string {\n if (format === \"json\") return JSON.stringify(canvases, null, 2);\n if (canvases.length === 0) return \"No canvases found.\";\n\n if (format === \"md\") {\n const lines: string[] = [];\n lines.push(`| ID | Name | Nodes | Connections |`);\n lines.push(`| --- | --- | ---: | ---: |`);\n for (const c of canvases) {\n lines.push(\n `| \\`${c.id.slice(0, 8)}\\` | ${c.name} | ${c.nodes.length} | ${c.connections.length} |`\n );\n }\n return lines.join(\"\\n\");\n }\n\n return canvases\n .map(\n (c) =>\n ` ${c.id.slice(0, 8)} ${c.name} (${c.nodes.length} nodes, ${c.connections.length} connections)`\n )\n .join(\"\\n\");\n}\n\nexport function formatStats(\n stats: {\n totalCaptures: number;\n totalSpaces: number;\n totalAreas: number;\n totalCanvases: number;\n totalTags: number;\n byContentType: Record<string, number>;\n byTriageStatus: Record<string, number>;\n },\n vaultPath: string,\n format: OutputFormat\n): string {\n if (format === \"json\") return JSON.stringify({ vaultPath, ...stats }, null, 2);\n\n if (format === \"md\") {\n const lines: string[] = [];\n lines.push(`# Vault Stats`);\n lines.push(\"\");\n lines.push(`**Path:** \\`${vaultPath}\\``);\n lines.push(\"\");\n lines.push(`| Metric | Count |`);\n lines.push(`| --- | ---: |`);\n lines.push(`| Captures | ${stats.totalCaptures} |`);\n lines.push(`| Spaces | ${stats.totalSpaces} |`);\n lines.push(`| Areas | ${stats.totalAreas} |`);\n lines.push(`| Canvases | ${stats.totalCanvases} |`);\n lines.push(`| Tags | ${stats.totalTags} |`);\n lines.push(\"\");\n lines.push(`### By Content Type`);\n lines.push(\"\");\n lines.push(`| Type | Count |`);\n lines.push(`| --- | ---: |`);\n const sortedTypes = Object.entries(stats.byContentType).sort((a, b) => b[1] - a[1]);\n for (const [type, count] of sortedTypes) {\n lines.push(`| ${type} | ${count} |`);\n }\n lines.push(\"\");\n lines.push(`### By Triage Status`);\n lines.push(\"\");\n lines.push(`| Status | Count |`);\n lines.push(`| --- | ---: |`);\n const sortedStatus = Object.entries(stats.byTriageStatus).sort((a, b) => b[1] - a[1]);\n for (const [status, count] of sortedStatus) {\n lines.push(`| ${status} | ${count} |`);\n }\n return lines.join(\"\\n\");\n }\n\n const sep = \"─\".repeat(40);\n const lines: string[] = [];\n\n lines.push(sep);\n lines.push(` Vault: ${vaultPath}`);\n lines.push(sep);\n lines.push(` Captures: ${stats.totalCaptures}`);\n lines.push(` Spaces: ${stats.totalSpaces}`);\n lines.push(` Areas: ${stats.totalAreas}`);\n lines.push(` Canvases: ${stats.totalCanvases}`);\n lines.push(` Tags: ${stats.totalTags}`);\n lines.push(sep);\n\n lines.push(\" By Content Type:\");\n const sortedTypes = Object.entries(stats.byContentType).sort((a, b) => b[1] - a[1]);\n for (const [type, count] of sortedTypes) {\n lines.push(` ${type.padEnd(14)} ${count}`);\n }\n\n lines.push(sep);\n lines.push(\" By Triage Status:\");\n const sortedStatus = Object.entries(stats.byTriageStatus).sort((a, b) => b[1] - a[1]);\n for (const [status, count] of sortedStatus) {\n lines.push(` ${status.padEnd(14)} ${count}`);\n }\n\n lines.push(sep);\n return lines.join(\"\\n\");\n}\n","import { VaultReader } from \"./reader.js\";\nimport { discoverVaultPath, findVaults } from \"./vault.js\";\nimport {\n type OutputFormat,\n formatAreas,\n formatCanvases,\n formatCapture,\n formatCaptureList,\n formatSpaces,\n formatStats,\n formatTags,\n formatVaults,\n} from \"./format.js\";\n\nconst VERSION = \"1.0.0\";\n\ntype GlobalFlags = {\n vault?: string;\n format: OutputFormat;\n verbose?: boolean;\n};\n\nfunction parseGlobalFlags(args: string[]): { flags: GlobalFlags; rest: string[] } {\n const flags: GlobalFlags = { format: \"pretty\" };\n const rest: string[] = [];\n let i = 0;\n\n while (i < args.length) {\n const arg = args[i];\n if (arg === \"--vault\" && i + 1 < args.length) {\n flags.vault = args[i + 1];\n i += 2;\n } else if (arg === \"--json\") {\n flags.format = \"json\";\n i++;\n } else if (arg === \"--md\" || arg === \"--markdown\") {\n flags.format = \"md\";\n i++;\n } else if (arg === \"--table\") {\n flags.format = \"table\";\n i++;\n } else if (arg === \"--format\" && i + 1 < args.length) {\n flags.format = args[i + 1] as OutputFormat;\n i += 2;\n } else if (arg === \"--verbose\") {\n flags.verbose = true;\n i++;\n } else {\n rest.push(arg);\n i++;\n }\n }\n\n return { flags, rest };\n}\n\nfunction extractFlag(args: string[], flag: string): string | undefined {\n const idx = args.indexOf(flag);\n if (idx === -1 || idx + 1 >= args.length) return undefined;\n return args[idx + 1];\n}\n\nfunction hasFlag(args: string[], flag: string): boolean {\n return args.includes(flag);\n}\n\nfunction extractNumber(args: string[], flag: string, defaultVal: number): number {\n const val = extractFlag(args, flag);\n if (!val) return defaultVal;\n const n = parseInt(val, 10);\n return isNaN(n) ? defaultVal : n;\n}\n\nasync function cmdList(reader: VaultReader, args: string[], format: OutputFormat): Promise<void> {\n const limit = extractNumber(args, \"--limit\", 20);\n const offset = extractNumber(args, \"--offset\", 0);\n const spaceKey = extractFlag(args, \"--space\");\n const tag = extractFlag(args, \"--tag\");\n const contentType = extractFlag(args, \"--type\");\n const search = extractFlag(args, \"--search\") ?? extractFlag(args, \"-s\");\n const pinned = hasFlag(args, \"--pinned\") ? true : undefined;\n const sortBy = (extractFlag(args, \"--sort\") as \"created\" | \"updated\") ?? \"created\";\n const sortOrder = hasFlag(args, \"--asc\") ? (\"asc\" as const) : (\"desc\" as const);\n\n const result = await reader.listCaptures({\n limit,\n offset,\n spaceKey,\n tag,\n contentType,\n search,\n pinned,\n sortBy,\n sortOrder,\n });\n\n console.log(formatCaptureList(result.captures, result.total, format));\n}\n\nasync function cmdGet(reader: VaultReader, args: string[], format: OutputFormat): Promise<void> {\n const id = args[0];\n if (!id) {\n console.error(\"Usage: resurf get <capture-id>\");\n process.exit(1);\n }\n\n let capture = await reader.getCaptureById(id);\n\n if (!capture) {\n const index = await reader.getCaptureIndex();\n const match = index.find((c) => c.id.startsWith(id));\n if (match) {\n capture = await reader.getCaptureById(match.id);\n }\n }\n\n if (!capture) {\n console.error(`Capture not found: ${id}`);\n process.exit(1);\n }\n\n console.log(formatCapture(capture, format, reader.vaultPath));\n}\n\nasync function cmdSearch(reader: VaultReader, args: string[], format: OutputFormat): Promise<void> {\n const positional: string[] = [];\n let i = 0;\n while (i < args.length) {\n if (args[i].startsWith(\"--\") && i + 1 < args.length) {\n i += 2;\n } else if (args[i].startsWith(\"--\")) {\n i++;\n } else {\n positional.push(args[i]);\n i++;\n }\n }\n\n const query = positional.join(\" \");\n if (!query) {\n console.error(\"Usage: resurf search <query>\");\n process.exit(1);\n }\n\n const limit = extractNumber(args, \"--limit\", 20);\n\n const result = await reader.listCaptures({ search: query, limit });\n console.log(formatCaptureList(result.captures, result.total, format));\n}\n\nasync function cmdSpaces(\n reader: VaultReader,\n _args: string[],\n format: OutputFormat\n): Promise<void> {\n const spaces = await reader.getSpaces();\n console.log(formatSpaces(spaces, format));\n}\n\nasync function cmdAreas(reader: VaultReader, _args: string[], format: OutputFormat): Promise<void> {\n const areas = await reader.getAreas();\n console.log(formatAreas(areas, format));\n}\n\nasync function cmdTags(reader: VaultReader, _args: string[], format: OutputFormat): Promise<void> {\n const tags = await reader.getTags();\n console.log(formatTags(tags, format));\n}\n\nasync function cmdCanvases(\n reader: VaultReader,\n _args: string[],\n format: OutputFormat\n): Promise<void> {\n const canvases = await reader.getCanvases();\n console.log(formatCanvases(canvases, format));\n}\n\nasync function cmdStats(reader: VaultReader, _args: string[], format: OutputFormat): Promise<void> {\n const stats = await reader.getStats();\n console.log(formatStats(stats, reader.vaultPath, format));\n}\n\nasync function cmdOpen(reader: VaultReader, args: string[]): Promise<void> {\n const id = args[0];\n if (!id) {\n console.error(\"Usage: resurf open <capture-id>\");\n process.exit(1);\n }\n\n let captureId = id;\n const capture = await reader.getCaptureById(id);\n if (!capture) {\n const index = await reader.getCaptureIndex();\n const match = index.find((c) => c.id.startsWith(id));\n if (match) captureId = match.id;\n }\n\n const { exec } = await import(\"child_process\");\n const url = `resurf://capture/${captureId}`;\n exec(`open \"${url}\"`);\n console.log(`Opening capture in Resurf: ${captureId}`);\n}\n\nasync function cmdCreate(args: string[]): Promise<void> {\n const content = extractFlag(args, \"--content\") ?? extractFlag(args, \"--text\");\n const url = extractFlag(args, \"--url\");\n const title = extractFlag(args, \"--title\");\n const tags = extractFlag(args, \"--tags\");\n const source = extractFlag(args, \"--source\");\n const space = extractFlag(args, \"--space\");\n\n if (!content && !url) {\n console.error(\n \"Usage: resurf create --content <text> [--url <url>] [--title <title>] [--tags <tags>]\"\n );\n process.exit(1);\n }\n\n const params = new URLSearchParams();\n if (content) params.set(\"content\", content);\n if (url) params.set(\"url\", url);\n if (title) params.set(\"title\", title);\n if (tags) params.set(\"tags\", tags);\n if (source) params.set(\"source\", source);\n if (space) params.set(\"space\", space);\n\n const protocolUrl = `resurf://new?${params.toString()}`;\n const { exec } = await import(\"child_process\");\n exec(`open \"${protocolUrl}\"`);\n console.log(\"Creating capture via Resurf protocol...\");\n}\n\nasync function cmdExport(reader: VaultReader, args: string[], format: OutputFormat): Promise<void> {\n const spaceKey = extractFlag(args, \"--space\");\n const tag = extractFlag(args, \"--tag\");\n const contentType = extractFlag(args, \"--type\");\n\n const result = await reader.listCaptures({\n limit: 999999,\n spaceKey,\n tag,\n contentType,\n });\n\n const captures: Record<string, unknown>[] = [];\n for (const item of result.captures) {\n const full = await reader.getCaptureById(item.id);\n if (full) captures.push(full);\n }\n\n if (format === \"json\") {\n console.log(JSON.stringify(captures, null, 2));\n } else if (format === \"md\") {\n const lines: string[] = [];\n for (const c of captures) {\n const cap = c as Record<string, unknown>;\n const title = (cap.title as string) || \"Untitled\";\n const id = cap.id as string;\n lines.push(`## ${title}`);\n lines.push(`- **ID:** \\`${id}\\``);\n if (cap.contentType) lines.push(`- **Type:** ${cap.contentType}`);\n if (cap.tldr) lines.push(`- **TLDR:** ${cap.tldr}`);\n if (cap.note) lines.push(`- **Note:** ${cap.note}`);\n lines.push(\"\");\n }\n lines.push(`_Exported ${captures.length} captures_`);\n console.log(lines.join(\"\\n\"));\n } else {\n console.log(JSON.stringify(captures, null, 2));\n console.error(`\\nExported ${captures.length} captures (use --json or --md for piping)`);\n }\n}\n\nfunction printHelp(): void {\n const help = `\nresurf - Access Resurf vault data from the command line\n\nUSAGE\n resurf <command> [options]\n\nCOMMANDS\n list List captures (default)\n get <id> Get a capture by ID (supports partial IDs)\n search <query> Search captures by title, note, or TLDR\n spaces List all spaces\n areas List all areas\n tags List all tags\n canvases List all canvases\n stats Show vault statistics\n vaults List available Resurf vaults on this computer\n open <id> Open a capture in Resurf app\n create Create a capture via Resurf protocol\n export Export captures as JSON\n\nGLOBAL OPTIONS\n --vault <path> Path to Resurf vault (auto-detected if omitted)\n --json Output as JSON\n --md, --markdown Output as Markdown\n --table Output as table\n --format <fmt> Output format: json, md, table, pretty (default: pretty)\n\nLIST OPTIONS\n --limit <n> Max results (default: 20)\n --offset <n> Skip first N results\n --space <key> Filter by space key\n --tag <tag> Filter by tag\n --type <type> Filter by content type (note, link, image, video, etc.)\n --search <query> Filter by text search\n --pinned Show only pinned captures\n --sort <field> Sort by: created, updated (default: created)\n --asc Sort ascending (default: descending)\n\nSEARCH OPTIONS\n --limit <n> Max results (default: 20)\n\nCREATE OPTIONS\n --content <text> Text content for the capture\n --url <url> URL to capture\n --title <title> Title for the capture\n --tags <tags> Comma-separated tags\n --source <source> Source identifier\n --space <key> Space key to assign\n\nEXPORT OPTIONS\n --space <key> Filter by space key\n --tag <tag> Filter by tag\n --type <type> Filter by content type\n\nVAULTS OPTIONS\n [directory] Scan this directory recursively for vaults\n --verbose Log skipped inaccessible paths\n\nEXAMPLES\n resurf list --limit 10 --json\n resurf list --space work --type note\n resurf get abc123\n resurf search \"meeting notes\"\n resurf search \"react hooks\" --json | jq '.[].title'\n resurf spaces --json\n resurf tags\n resurf stats\n resurf vaults\n resurf vaults --json\n resurf vaults /path/to/folder\n resurf open abc123\n resurf create --content \"Quick note\" --tags \"idea,work\"\n resurf create --url \"https://example.com\" --title \"Example\"\n resurf export --space work --json > work-captures.json\n resurf list --json | jq '.captures[].id'\n\nVERSION\n ${VERSION}\n`;\n console.log(help.trim());\n}\n\nasync function main(): Promise<void> {\n const rawArgs = process.argv.slice(2);\n\n if (rawArgs.length === 0 || rawArgs[0] === \"--help\" || rawArgs[0] === \"-h\") {\n printHelp();\n return;\n }\n\n if (rawArgs[0] === \"--version\" || rawArgs[0] === \"-v\") {\n console.log(VERSION);\n return;\n }\n\n const { flags, rest } = parseGlobalFlags(rawArgs);\n const command = rest[0] ?? \"list\";\n const commandArgs = rest.slice(1);\n\n if (command === \"create\") {\n await cmdCreate(commandArgs);\n return;\n }\n\n if (command === \"vaults\" || command === \"find-vaults\") {\n const scanDir = commandArgs.find((a) => !a.startsWith(\"-\"));\n const vaults = await findVaults({ scanDir, verbose: flags.verbose });\n console.log(formatVaults(vaults, flags.format));\n return;\n }\n\n const vaultPath = await discoverVaultPath(flags.vault);\n const reader = new VaultReader(vaultPath);\n\n const commands: Record<string, (r: VaultReader, a: string[], f: OutputFormat) => Promise<void>> =\n {\n list: cmdList,\n ls: cmdList,\n get: cmdGet,\n show: cmdGet,\n search: cmdSearch,\n find: cmdSearch,\n spaces: cmdSpaces,\n areas: cmdAreas,\n tags: cmdTags,\n canvases: cmdCanvases,\n stats: cmdStats,\n info: cmdStats,\n export: cmdExport,\n };\n\n if (command === \"open\") {\n await cmdOpen(reader, commandArgs);\n return;\n }\n\n const handler = commands[command];\n if (!handler) {\n console.error(`Unknown command: ${command}`);\n console.error(`Run 'resurf --help' for usage.`);\n process.exit(1);\n }\n\n await handler(reader, commandArgs, flags.format);\n}\n\nmain().catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`Error: ${message}`);\n process.exit(1);\n});\n"],"mappings":"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","names":["fs","path","stat","stat","path","lines","content","sortedTypes","sortedStatus"]}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "resurf",
3
+ "version": "1.0.0",
4
+ "description": "CLI to access Resurf vault data from any app or terminal",
5
+ "private": false,
6
+ "type": "module",
7
+ "bin": {
8
+ "resurf": "./dist/index.js"
9
+ },
10
+ "files": ["dist"],
11
+ "scripts": {
12
+ "build": "tsup",
13
+ "dev": "tsup --watch",
14
+ "prepublishOnly": "npm run build"
15
+ },
16
+ "keywords": ["resurf", "cli", "captures", "knowledge-base", "notes", "vault"],
17
+ "author": "",
18
+ "license": "MIT",
19
+ "engines": {
20
+ "node": ">=18.0.0"
21
+ },
22
+ "devDependencies": {
23
+ "tsup": "^8.0.0",
24
+ "typescript": "^5.8.0"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/captureai/captureai.git",
29
+ "directory": "packages/resurf-cli"
30
+ },
31
+ "homepage": "https://github.com/captureai/captureai#readme",
32
+ "bugs": {
33
+ "url": "https://github.com/captureai/captureai/issues"
34
+ }
35
+ }