@voidwire/lore 0.1.12 → 0.1.14
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/cli.ts +66 -3
- package/index.ts +3 -0
- package/lib/info.ts +2 -1
- package/lib/list.ts +30 -6
- package/lib/projects.ts +60 -0
- package/package.json +1 -1
package/cli.ts
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
listDomains,
|
|
29
29
|
info,
|
|
30
30
|
formatInfoHuman,
|
|
31
|
+
projects,
|
|
31
32
|
captureTask,
|
|
32
33
|
captureKnowledge,
|
|
33
34
|
captureNote,
|
|
@@ -317,9 +318,10 @@ function handleList(args: string[]): void {
|
|
|
317
318
|
? parseInt(parsed.get("limit")!, 10)
|
|
318
319
|
: undefined;
|
|
319
320
|
const format = parsed.get("format") || "json";
|
|
321
|
+
const project = parsed.get("project");
|
|
320
322
|
|
|
321
323
|
try {
|
|
322
|
-
const result = list(domain, { limit });
|
|
324
|
+
const result = list(domain, { limit, project });
|
|
323
325
|
|
|
324
326
|
if (format === "human") {
|
|
325
327
|
console.log(formatHumanOutput(result));
|
|
@@ -377,6 +379,31 @@ function handleInfo(args: string[]): void {
|
|
|
377
379
|
}
|
|
378
380
|
}
|
|
379
381
|
|
|
382
|
+
// ============================================================================
|
|
383
|
+
// Projects Command
|
|
384
|
+
// ============================================================================
|
|
385
|
+
|
|
386
|
+
function handleProjects(args: string[]): void {
|
|
387
|
+
if (hasFlag(args, "help")) {
|
|
388
|
+
showProjectsHelp();
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
try {
|
|
392
|
+
const result = projects();
|
|
393
|
+
|
|
394
|
+
output({
|
|
395
|
+
success: true,
|
|
396
|
+
projects: result,
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
console.error(`✅ ${result.length} projects found`);
|
|
400
|
+
process.exit(0);
|
|
401
|
+
} catch (error) {
|
|
402
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
403
|
+
fail(message, 2);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
380
407
|
// ============================================================================
|
|
381
408
|
// Capture Command
|
|
382
409
|
// ============================================================================
|
|
@@ -656,6 +683,7 @@ Usage:
|
|
|
656
683
|
Options:
|
|
657
684
|
--limit <n> Maximum entries (default: all)
|
|
658
685
|
--format <fmt> Output format: json (default), jsonl, human
|
|
686
|
+
--project <name> Filter by project name
|
|
659
687
|
--domains List available domains
|
|
660
688
|
--help Show this help
|
|
661
689
|
|
|
@@ -681,6 +709,7 @@ Available Domains:
|
|
|
681
709
|
Examples:
|
|
682
710
|
lore list development
|
|
683
711
|
lore list commits --limit 10 --format human
|
|
712
|
+
lore list commits --project=momentum --limit 5
|
|
684
713
|
lore list books --format jsonl
|
|
685
714
|
`);
|
|
686
715
|
process.exit(0);
|
|
@@ -700,7 +729,7 @@ Options:
|
|
|
700
729
|
|
|
701
730
|
Output Fields:
|
|
702
731
|
sources Array of {name, count} for each indexed source
|
|
703
|
-
projects Known projects
|
|
732
|
+
projects Known projects across all sources
|
|
704
733
|
last_indexed Most recent timestamp from indexed data
|
|
705
734
|
total_entries Total number of indexed entries
|
|
706
735
|
|
|
@@ -712,6 +741,35 @@ Examples:
|
|
|
712
741
|
process.exit(0);
|
|
713
742
|
}
|
|
714
743
|
|
|
744
|
+
function showProjectsHelp(): void {
|
|
745
|
+
console.log(`
|
|
746
|
+
lore projects - List all known projects
|
|
747
|
+
|
|
748
|
+
Usage:
|
|
749
|
+
lore projects List all unique project names
|
|
750
|
+
|
|
751
|
+
Options:
|
|
752
|
+
--help Show this help
|
|
753
|
+
|
|
754
|
+
Output:
|
|
755
|
+
JSON array of project names, sorted alphabetically.
|
|
756
|
+
Projects are extracted from metadata fields across all sources.
|
|
757
|
+
|
|
758
|
+
Sources checked:
|
|
759
|
+
commits project field
|
|
760
|
+
sessions project field
|
|
761
|
+
tasks project field
|
|
762
|
+
captures context field
|
|
763
|
+
teachings source field
|
|
764
|
+
|
|
765
|
+
Examples:
|
|
766
|
+
lore projects
|
|
767
|
+
lore projects | jq -r '.projects[]'
|
|
768
|
+
lore projects | jq '.projects | length'
|
|
769
|
+
`);
|
|
770
|
+
process.exit(0);
|
|
771
|
+
}
|
|
772
|
+
|
|
715
773
|
function showCaptureHelp(): void {
|
|
716
774
|
console.log(`
|
|
717
775
|
lore capture - Capture knowledge
|
|
@@ -790,11 +848,16 @@ function main(): void {
|
|
|
790
848
|
case "info":
|
|
791
849
|
handleInfo(commandArgs);
|
|
792
850
|
break;
|
|
851
|
+
case "projects":
|
|
852
|
+
handleProjects(commandArgs);
|
|
853
|
+
break;
|
|
793
854
|
case "capture":
|
|
794
855
|
handleCapture(commandArgs);
|
|
795
856
|
break;
|
|
796
857
|
default:
|
|
797
|
-
fail(
|
|
858
|
+
fail(
|
|
859
|
+
`Unknown command: ${command}. Use: search, list, info, projects, or capture`,
|
|
860
|
+
);
|
|
798
861
|
}
|
|
799
862
|
}
|
|
800
863
|
|
package/index.ts
CHANGED
package/lib/info.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { Database } from "bun:sqlite";
|
|
9
9
|
import { homedir } from "os";
|
|
10
10
|
import { existsSync } from "fs";
|
|
11
|
+
import { projects as getProjects } from "./projects.js";
|
|
11
12
|
|
|
12
13
|
export interface SourceInfo {
|
|
13
14
|
name: string;
|
|
@@ -72,7 +73,7 @@ export function info(): InfoOutput {
|
|
|
72
73
|
|
|
73
74
|
return {
|
|
74
75
|
sources,
|
|
75
|
-
projects:
|
|
76
|
+
projects: getProjects(),
|
|
76
77
|
last_indexed,
|
|
77
78
|
total_entries,
|
|
78
79
|
};
|
package/lib/list.ts
CHANGED
|
@@ -59,8 +59,18 @@ const PERSONAL_SUBTYPES: Partial<Record<Domain, string>> = {
|
|
|
59
59
|
habits: "habit",
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
+
// Maps source to metadata field containing project name
|
|
63
|
+
const PROJECT_FIELD: Record<string, string> = {
|
|
64
|
+
commits: "project",
|
|
65
|
+
sessions: "project",
|
|
66
|
+
tasks: "project",
|
|
67
|
+
captures: "context",
|
|
68
|
+
teachings: "source",
|
|
69
|
+
};
|
|
70
|
+
|
|
62
71
|
export interface ListOptions {
|
|
63
72
|
limit?: number;
|
|
73
|
+
project?: string;
|
|
64
74
|
}
|
|
65
75
|
|
|
66
76
|
export interface ListEntry {
|
|
@@ -93,13 +103,27 @@ function queryBySource(
|
|
|
93
103
|
db: Database,
|
|
94
104
|
source: string,
|
|
95
105
|
limit?: number,
|
|
106
|
+
project?: string,
|
|
96
107
|
): ListEntry[] {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
108
|
+
let sql = "SELECT title, content, metadata FROM search WHERE source = ?";
|
|
109
|
+
const params: (string | number)[] = [source];
|
|
110
|
+
|
|
111
|
+
// Add project filter if provided and source has a project field
|
|
112
|
+
if (project) {
|
|
113
|
+
const field = PROJECT_FIELD[source];
|
|
114
|
+
if (field) {
|
|
115
|
+
sql += ` AND json_extract(metadata, '$.${field}') = ?`;
|
|
116
|
+
params.push(project);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (limit) {
|
|
121
|
+
sql += " LIMIT ?";
|
|
122
|
+
params.push(limit);
|
|
123
|
+
}
|
|
100
124
|
|
|
101
|
-
const stmt =
|
|
102
|
-
const rows =
|
|
125
|
+
const stmt = db.prepare(sql);
|
|
126
|
+
const rows = stmt.all(...params) as RawRow[];
|
|
103
127
|
|
|
104
128
|
return rows.map((row) => ({
|
|
105
129
|
title: row.title,
|
|
@@ -166,7 +190,7 @@ export function list(domain: Domain, options: ListOptions = {}): ListResult {
|
|
|
166
190
|
if (personalType) {
|
|
167
191
|
entries = queryPersonalType(db, personalType, options.limit);
|
|
168
192
|
} else {
|
|
169
|
-
entries = queryBySource(db, domain, options.limit);
|
|
193
|
+
entries = queryBySource(db, domain, options.limit, options.project);
|
|
170
194
|
}
|
|
171
195
|
|
|
172
196
|
return {
|
package/lib/projects.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/projects.ts - List all known projects across sources
|
|
3
|
+
*
|
|
4
|
+
* Queries distinct project values from metadata fields, handling
|
|
5
|
+
* different field names per source type.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Database } from "bun:sqlite";
|
|
9
|
+
import { homedir } from "os";
|
|
10
|
+
import { existsSync } from "fs";
|
|
11
|
+
|
|
12
|
+
const PROJECT_FIELD: Record<string, string> = {
|
|
13
|
+
commits: "project",
|
|
14
|
+
sessions: "project",
|
|
15
|
+
tasks: "project",
|
|
16
|
+
captures: "context",
|
|
17
|
+
teachings: "source",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function getDatabasePath(): string {
|
|
21
|
+
return `${homedir()}/.local/share/lore/lore.db`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get all unique project names across sources
|
|
26
|
+
*
|
|
27
|
+
* @returns Sorted array of unique project names
|
|
28
|
+
*/
|
|
29
|
+
export function projects(): string[] {
|
|
30
|
+
const dbPath = getDatabasePath();
|
|
31
|
+
|
|
32
|
+
if (!existsSync(dbPath)) {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const db = new Database(dbPath, { readonly: true });
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const allProjects = new Set<string>();
|
|
40
|
+
|
|
41
|
+
for (const [source, field] of Object.entries(PROJECT_FIELD)) {
|
|
42
|
+
const stmt = db.prepare(`
|
|
43
|
+
SELECT DISTINCT json_extract(metadata, '$.${field}') as proj
|
|
44
|
+
FROM search
|
|
45
|
+
WHERE source = ? AND json_extract(metadata, '$.${field}') IS NOT NULL
|
|
46
|
+
`);
|
|
47
|
+
const results = stmt.all(source) as { proj: string | null }[];
|
|
48
|
+
|
|
49
|
+
for (const r of results) {
|
|
50
|
+
if (r.proj) {
|
|
51
|
+
allProjects.add(r.proj);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return Array.from(allProjects).sort();
|
|
57
|
+
} finally {
|
|
58
|
+
db.close();
|
|
59
|
+
}
|
|
60
|
+
}
|