@voidwire/lore 0.3.0 → 0.4.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/cli.ts +79 -29
- package/index.ts +2 -3
- package/lib/about.ts +5 -5
- package/lib/list.ts +32 -32
- package/package.json +1 -1
package/cli.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* Usage:
|
|
11
11
|
* lore search <query> Search all sources
|
|
12
12
|
* lore search <source> <query> Search specific source
|
|
13
|
-
* lore list <
|
|
13
|
+
* lore list <source> List source entries
|
|
14
14
|
* lore capture task|knowledge|note|teaching Capture knowledge
|
|
15
15
|
*
|
|
16
16
|
* Exit codes:
|
|
@@ -25,7 +25,6 @@ import {
|
|
|
25
25
|
searchAtuin,
|
|
26
26
|
listSources,
|
|
27
27
|
list,
|
|
28
|
-
listDomains,
|
|
29
28
|
formatBriefList,
|
|
30
29
|
info,
|
|
31
30
|
formatInfoHuman,
|
|
@@ -39,11 +38,11 @@ import {
|
|
|
39
38
|
semanticSearch,
|
|
40
39
|
formatBriefSearch,
|
|
41
40
|
hasEmbeddings,
|
|
42
|
-
|
|
41
|
+
SOURCES,
|
|
43
42
|
type SearchResult,
|
|
44
43
|
type ListResult,
|
|
45
44
|
type ListEntry,
|
|
46
|
-
type
|
|
45
|
+
type Source,
|
|
47
46
|
type TaskInput,
|
|
48
47
|
type KnowledgeInput,
|
|
49
48
|
type NoteInput,
|
|
@@ -289,7 +288,7 @@ async function handleSearch(args: string[]): Promise<void> {
|
|
|
289
288
|
// ============================================================================
|
|
290
289
|
|
|
291
290
|
function formatHumanOutput(result: ListResult): string {
|
|
292
|
-
const lines: string[] = [`${result.
|
|
291
|
+
const lines: string[] = [`${result.source} (${result.count} entries):`, ""];
|
|
293
292
|
|
|
294
293
|
for (const entry of result.entries) {
|
|
295
294
|
lines.push(` ${entry.title}`);
|
|
@@ -309,21 +308,23 @@ function handleList(args: string[]): void {
|
|
|
309
308
|
const parsed = parseArgs(args);
|
|
310
309
|
const positional = getPositionalArgs(args);
|
|
311
310
|
|
|
312
|
-
// Handle --domains flag
|
|
311
|
+
// Handle --domains flag (deprecated)
|
|
313
312
|
if (hasFlag(args, "domains")) {
|
|
314
|
-
|
|
315
|
-
|
|
313
|
+
console.error("⚠️ --domains is deprecated. Use 'lore sources' instead.");
|
|
314
|
+
const sources = listSources();
|
|
315
|
+
output({ success: true, sources });
|
|
316
|
+
console.error(`✅ ${SOURCES.length} sources available`);
|
|
316
317
|
process.exit(0);
|
|
317
318
|
}
|
|
318
319
|
|
|
319
320
|
if (positional.length === 0) {
|
|
320
|
-
fail(`Missing
|
|
321
|
+
fail(`Missing source. Available: ${SOURCES.join(", ")}`);
|
|
321
322
|
}
|
|
322
323
|
|
|
323
|
-
const
|
|
324
|
+
const source = positional[0] as Source;
|
|
324
325
|
|
|
325
|
-
if (!
|
|
326
|
-
fail(`Invalid
|
|
326
|
+
if (!SOURCES.includes(source)) {
|
|
327
|
+
fail(`Invalid source: ${source}. Available: ${SOURCES.join(", ")}`);
|
|
327
328
|
}
|
|
328
329
|
|
|
329
330
|
const limit = parsed.has("limit")
|
|
@@ -334,7 +335,7 @@ function handleList(args: string[]): void {
|
|
|
334
335
|
const brief = hasFlag(args, "brief");
|
|
335
336
|
|
|
336
337
|
try {
|
|
337
|
-
const result = list(
|
|
338
|
+
const result = list(source, { limit, project });
|
|
338
339
|
|
|
339
340
|
if (brief) {
|
|
340
341
|
console.log(formatBriefList(result));
|
|
@@ -347,13 +348,13 @@ function handleList(args: string[]): void {
|
|
|
347
348
|
} else {
|
|
348
349
|
output({
|
|
349
350
|
success: true,
|
|
350
|
-
|
|
351
|
+
source: result.source,
|
|
351
352
|
entries: result.entries,
|
|
352
353
|
count: result.count,
|
|
353
354
|
});
|
|
354
355
|
}
|
|
355
356
|
|
|
356
|
-
console.error(`✅ ${result.count} entries in ${
|
|
357
|
+
console.error(`✅ ${result.count} entries in ${source}`);
|
|
357
358
|
process.exit(0);
|
|
358
359
|
} catch (error) {
|
|
359
360
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
@@ -468,6 +469,50 @@ function handleAbout(args: string[]): void {
|
|
|
468
469
|
}
|
|
469
470
|
}
|
|
470
471
|
|
|
472
|
+
// ============================================================================
|
|
473
|
+
// Sources Command
|
|
474
|
+
// ============================================================================
|
|
475
|
+
|
|
476
|
+
function handleSources(args: string[]): void {
|
|
477
|
+
if (hasFlag(args, "help")) {
|
|
478
|
+
showSourcesHelp();
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
try {
|
|
482
|
+
const sources = listSources();
|
|
483
|
+
output({
|
|
484
|
+
success: true,
|
|
485
|
+
sources,
|
|
486
|
+
});
|
|
487
|
+
console.error(`✅ ${sources.length} sources indexed`);
|
|
488
|
+
process.exit(0);
|
|
489
|
+
} catch (error) {
|
|
490
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
491
|
+
fail(message, 2);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function showSourcesHelp(): void {
|
|
496
|
+
console.log(`
|
|
497
|
+
lore sources - List all indexed sources with counts
|
|
498
|
+
|
|
499
|
+
Usage:
|
|
500
|
+
lore sources List all sources with entry counts
|
|
501
|
+
|
|
502
|
+
Options:
|
|
503
|
+
--help Show this help
|
|
504
|
+
|
|
505
|
+
Output:
|
|
506
|
+
JSON array of {source, count} objects, sorted by count descending.
|
|
507
|
+
|
|
508
|
+
Examples:
|
|
509
|
+
lore sources
|
|
510
|
+
lore sources | jq '.[0]'
|
|
511
|
+
lore sources | jq -r '.[] | "\\(.source): \\(.count)"'
|
|
512
|
+
`);
|
|
513
|
+
process.exit(0);
|
|
514
|
+
}
|
|
515
|
+
|
|
471
516
|
// ============================================================================
|
|
472
517
|
// Capture Command
|
|
473
518
|
// ============================================================================
|
|
@@ -635,9 +680,8 @@ Philosophy:
|
|
|
635
680
|
Usage:
|
|
636
681
|
lore search <query> Search all sources
|
|
637
682
|
lore search <source> <query> Search specific source
|
|
638
|
-
lore
|
|
639
|
-
lore list <
|
|
640
|
-
lore list --domains List available domains
|
|
683
|
+
lore sources List indexed sources with counts
|
|
684
|
+
lore list <source> List source entries
|
|
641
685
|
lore info Show indexed sources and counts
|
|
642
686
|
lore info --human Human-readable info
|
|
643
687
|
lore about <project> Aggregate view of project knowledge
|
|
@@ -650,7 +694,6 @@ Search Options:
|
|
|
650
694
|
--project <name> Filter results by project
|
|
651
695
|
--brief Compact output (titles only)
|
|
652
696
|
--since <date> Filter by date (today, yesterday, this-week, YYYY-MM-DD)
|
|
653
|
-
--sources List indexed sources with counts
|
|
654
697
|
|
|
655
698
|
Passthrough Sources:
|
|
656
699
|
prismis Semantic search via prismis daemon (requires prismis-daemon running)
|
|
@@ -660,7 +703,7 @@ List Options:
|
|
|
660
703
|
--limit <n> Maximum entries
|
|
661
704
|
--format <fmt> Output format: json (default), jsonl, human
|
|
662
705
|
--brief Compact output (titles only)
|
|
663
|
-
--
|
|
706
|
+
--project <name> Filter by project name
|
|
664
707
|
|
|
665
708
|
Capture Types:
|
|
666
709
|
task Log task completion
|
|
@@ -688,6 +731,7 @@ Capture Types:
|
|
|
688
731
|
Examples:
|
|
689
732
|
lore search "authentication"
|
|
690
733
|
lore search blogs "typescript patterns"
|
|
734
|
+
lore sources
|
|
691
735
|
lore list development
|
|
692
736
|
lore list commits --limit 10 --format human
|
|
693
737
|
lore capture knowledge --context=lore --text="Unified CLI works" --type=learning
|
|
@@ -702,7 +746,6 @@ lore search - Search indexed knowledge
|
|
|
702
746
|
Usage:
|
|
703
747
|
lore search <query> Search all sources
|
|
704
748
|
lore search <source> <query> Search specific source
|
|
705
|
-
lore search --sources List indexed sources
|
|
706
749
|
|
|
707
750
|
Options:
|
|
708
751
|
--exact Use FTS5 text search (bypasses semantic search)
|
|
@@ -710,7 +753,6 @@ Options:
|
|
|
710
753
|
--project <name> Filter results by project (post-filters KNN results)
|
|
711
754
|
--brief Compact output (titles only)
|
|
712
755
|
--since <date> Filter by date (today, yesterday, this-week, YYYY-MM-DD)
|
|
713
|
-
--sources List indexed sources with counts
|
|
714
756
|
--help Show this help
|
|
715
757
|
|
|
716
758
|
Indexed Sources:
|
|
@@ -725,6 +767,7 @@ Indexed Sources:
|
|
|
725
767
|
readmes Project README files
|
|
726
768
|
sessions Claude Code session transcripts
|
|
727
769
|
tasks Logged development tasks
|
|
770
|
+
teachings Teaching moments
|
|
728
771
|
|
|
729
772
|
Passthrough Sources:
|
|
730
773
|
prismis Semantic search via prismis daemon
|
|
@@ -732,6 +775,9 @@ Passthrough Sources:
|
|
|
732
775
|
atuin Shell history search
|
|
733
776
|
(queries ~/.local/share/atuin/history.db directly)
|
|
734
777
|
|
|
778
|
+
See also:
|
|
779
|
+
lore sources List all sources with entry counts
|
|
780
|
+
|
|
735
781
|
Examples:
|
|
736
782
|
lore search "authentication"
|
|
737
783
|
lore search blogs "typescript patterns"
|
|
@@ -746,21 +792,19 @@ Examples:
|
|
|
746
792
|
|
|
747
793
|
function showListHelp(): void {
|
|
748
794
|
console.log(`
|
|
749
|
-
lore list - List
|
|
795
|
+
lore list - List source entries
|
|
750
796
|
|
|
751
797
|
Usage:
|
|
752
|
-
lore list <
|
|
753
|
-
lore list --domains List available domains
|
|
798
|
+
lore list <source> List entries in source
|
|
754
799
|
|
|
755
800
|
Options:
|
|
756
801
|
--limit <n> Maximum entries (default: all)
|
|
757
802
|
--format <fmt> Output format: json (default), jsonl, human
|
|
758
803
|
--project <name> Filter by project name
|
|
759
804
|
--brief Compact output (titles only)
|
|
760
|
-
--domains List available domains
|
|
761
805
|
--help Show this help
|
|
762
806
|
|
|
763
|
-
Available
|
|
807
|
+
Available Sources:
|
|
764
808
|
blogs Blog posts
|
|
765
809
|
books Books read
|
|
766
810
|
captures Quick captures
|
|
@@ -773,11 +817,14 @@ Available Domains:
|
|
|
773
817
|
movies Movies watched
|
|
774
818
|
obsidian Obsidian notes
|
|
775
819
|
people People/contacts
|
|
776
|
-
personal Personal data aggregate
|
|
777
820
|
podcasts Podcasts listened
|
|
778
821
|
readmes Project READMEs
|
|
779
822
|
sessions Claude Code sessions
|
|
780
823
|
tasks Development tasks
|
|
824
|
+
teachings Teaching moments
|
|
825
|
+
|
|
826
|
+
See also:
|
|
827
|
+
lore sources List all sources with entry counts
|
|
781
828
|
|
|
782
829
|
Examples:
|
|
783
830
|
lore list development
|
|
@@ -963,6 +1010,9 @@ function main(): void {
|
|
|
963
1010
|
case "list":
|
|
964
1011
|
handleList(commandArgs);
|
|
965
1012
|
break;
|
|
1013
|
+
case "sources":
|
|
1014
|
+
handleSources(commandArgs);
|
|
1015
|
+
break;
|
|
966
1016
|
case "info":
|
|
967
1017
|
handleInfo(commandArgs);
|
|
968
1018
|
break;
|
|
@@ -977,7 +1027,7 @@ function main(): void {
|
|
|
977
1027
|
break;
|
|
978
1028
|
default:
|
|
979
1029
|
fail(
|
|
980
|
-
`Unknown command: ${command}. Use: search, list, info, projects, about, or capture`,
|
|
1030
|
+
`Unknown command: ${command}. Use: search, list, sources, info, projects, about, or capture`,
|
|
981
1031
|
);
|
|
982
1032
|
}
|
|
983
1033
|
}
|
package/index.ts
CHANGED
package/lib/about.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Uses parallel queries via Promise.all for performance.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { list, formatBriefList, type ListResult, type
|
|
8
|
+
import { list, formatBriefList, type ListResult, type Source } from "./list";
|
|
9
9
|
|
|
10
10
|
export interface AboutOptions {
|
|
11
11
|
brief?: boolean;
|
|
@@ -26,7 +26,7 @@ export interface AboutResult {
|
|
|
26
26
|
* Each source has a different field for project mapping (handled by list.ts)
|
|
27
27
|
* Note: "insights" will be added when task 2.1 is complete
|
|
28
28
|
*/
|
|
29
|
-
const ABOUT_SOURCES:
|
|
29
|
+
const ABOUT_SOURCES: Source[] = [
|
|
30
30
|
"commits",
|
|
31
31
|
"captures",
|
|
32
32
|
"tasks",
|
|
@@ -48,13 +48,13 @@ export function about(
|
|
|
48
48
|
const limit = options.limit ?? 10;
|
|
49
49
|
|
|
50
50
|
// Query all sources in parallel
|
|
51
|
-
const results = ABOUT_SOURCES.map((
|
|
51
|
+
const results = ABOUT_SOURCES.map((src) => {
|
|
52
52
|
try {
|
|
53
|
-
return list(
|
|
53
|
+
return list(src, { project, limit });
|
|
54
54
|
} catch {
|
|
55
55
|
// Source doesn't exist or has no data - return empty result
|
|
56
56
|
return {
|
|
57
|
-
|
|
57
|
+
source: src,
|
|
58
58
|
entries: [],
|
|
59
59
|
count: 0,
|
|
60
60
|
} as ListResult;
|
package/lib/list.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* lib/list.ts -
|
|
2
|
+
* lib/list.ts - Source listing functions
|
|
3
3
|
*
|
|
4
|
-
* Browse indexed
|
|
4
|
+
* Browse indexed sources without search queries.
|
|
5
5
|
* Uses Bun's built-in SQLite for zero external dependencies.
|
|
6
6
|
*/
|
|
7
7
|
|
|
@@ -9,8 +9,8 @@ import { Database } from "bun:sqlite";
|
|
|
9
9
|
import { homedir } from "os";
|
|
10
10
|
import { existsSync } from "fs";
|
|
11
11
|
|
|
12
|
-
//
|
|
13
|
-
export type
|
|
12
|
+
// Source types - data sources that can be listed
|
|
13
|
+
export type Source =
|
|
14
14
|
| "development"
|
|
15
15
|
| "tasks"
|
|
16
16
|
| "events"
|
|
@@ -29,7 +29,7 @@ export type Domain =
|
|
|
29
29
|
| "teachings"
|
|
30
30
|
| "sessions";
|
|
31
31
|
|
|
32
|
-
export const
|
|
32
|
+
export const SOURCES: Source[] = [
|
|
33
33
|
"development",
|
|
34
34
|
"tasks",
|
|
35
35
|
"events",
|
|
@@ -49,8 +49,8 @@ export const DOMAINS: Domain[] = [
|
|
|
49
49
|
"sessions",
|
|
50
50
|
];
|
|
51
51
|
|
|
52
|
-
//
|
|
53
|
-
const PERSONAL_SUBTYPES: Partial<Record<
|
|
52
|
+
// Sources that query the 'personal' source with type filter
|
|
53
|
+
const PERSONAL_SUBTYPES: Partial<Record<Source, string>> = {
|
|
54
54
|
books: "book",
|
|
55
55
|
movies: "movie",
|
|
56
56
|
podcasts: "podcast",
|
|
@@ -80,7 +80,7 @@ export interface ListEntry {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
export interface ListResult {
|
|
83
|
-
|
|
83
|
+
source: Source;
|
|
84
84
|
entries: ListEntry[];
|
|
85
85
|
count: number;
|
|
86
86
|
}
|
|
@@ -160,17 +160,17 @@ function queryPersonalType(
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
/**
|
|
163
|
-
* List all entries in a
|
|
163
|
+
* List all entries in a source
|
|
164
164
|
*
|
|
165
|
-
* @param
|
|
165
|
+
* @param source - The source to list (development, tasks, blogs, etc.)
|
|
166
166
|
* @param options - Optional limit
|
|
167
167
|
* @returns ListResult with entries and count
|
|
168
|
-
* @throws Error if database doesn't exist or
|
|
168
|
+
* @throws Error if database doesn't exist or source is invalid
|
|
169
169
|
*/
|
|
170
|
-
export function list(
|
|
171
|
-
if (!
|
|
170
|
+
export function list(source: Source, options: ListOptions = {}): ListResult {
|
|
171
|
+
if (!SOURCES.includes(source)) {
|
|
172
172
|
throw new Error(
|
|
173
|
-
`Invalid
|
|
173
|
+
`Invalid source: ${source}. Valid sources: ${SOURCES.join(", ")}`,
|
|
174
174
|
);
|
|
175
175
|
}
|
|
176
176
|
|
|
@@ -185,16 +185,16 @@ export function list(domain: Domain, options: ListOptions = {}): ListResult {
|
|
|
185
185
|
try {
|
|
186
186
|
let entries: ListEntry[];
|
|
187
187
|
|
|
188
|
-
// Check if this is a personal subtype
|
|
189
|
-
const personalType = PERSONAL_SUBTYPES[
|
|
188
|
+
// Check if this is a personal subtype source
|
|
189
|
+
const personalType = PERSONAL_SUBTYPES[source];
|
|
190
190
|
if (personalType) {
|
|
191
191
|
entries = queryPersonalType(db, personalType, options.limit);
|
|
192
192
|
} else {
|
|
193
|
-
entries = queryBySource(db,
|
|
193
|
+
entries = queryBySource(db, source, options.limit, options.project);
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
return {
|
|
197
|
-
|
|
197
|
+
source,
|
|
198
198
|
entries,
|
|
199
199
|
count: entries.length,
|
|
200
200
|
};
|
|
@@ -204,28 +204,28 @@ export function list(domain: Domain, options: ListOptions = {}): ListResult {
|
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
/**
|
|
207
|
-
* Get available
|
|
207
|
+
* Get available sources
|
|
208
208
|
*/
|
|
209
|
-
export function
|
|
210
|
-
return [...
|
|
209
|
+
export function listSources(): Source[] {
|
|
210
|
+
return [...SOURCES];
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
/**
|
|
214
214
|
* Extract project name from entry metadata
|
|
215
215
|
*/
|
|
216
|
-
function extractProjectFromEntry(entry: ListEntry,
|
|
217
|
-
const field = PROJECT_FIELD[
|
|
216
|
+
function extractProjectFromEntry(entry: ListEntry, source: string): string {
|
|
217
|
+
const field = PROJECT_FIELD[source];
|
|
218
218
|
if (!field) return "unknown";
|
|
219
219
|
return (entry.metadata[field] as string) || "unknown";
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
/**
|
|
223
|
-
* Extract identifier from entry based on
|
|
223
|
+
* Extract identifier from entry based on source type
|
|
224
224
|
*/
|
|
225
|
-
function extractIdentifier(entry: ListEntry,
|
|
225
|
+
function extractIdentifier(entry: ListEntry, source: string): string {
|
|
226
226
|
const metadata = entry.metadata;
|
|
227
227
|
|
|
228
|
-
switch (
|
|
228
|
+
switch (source) {
|
|
229
229
|
case "commits":
|
|
230
230
|
return (metadata.sha as string)?.substring(0, 7) || "";
|
|
231
231
|
case "sessions":
|
|
@@ -239,8 +239,8 @@ function extractIdentifier(entry: ListEntry, domain: string): string {
|
|
|
239
239
|
* Get the best display text for an entry
|
|
240
240
|
* Commits use content (commit message), others use title
|
|
241
241
|
*/
|
|
242
|
-
function getDisplayText(entry: ListEntry,
|
|
243
|
-
if (
|
|
242
|
+
function getDisplayText(entry: ListEntry, source: string): string {
|
|
243
|
+
if (source === "commits") {
|
|
244
244
|
return entry.content || entry.title;
|
|
245
245
|
}
|
|
246
246
|
return entry.title;
|
|
@@ -251,12 +251,12 @@ function getDisplayText(entry: ListEntry, domain: string): string {
|
|
|
251
251
|
* One line per entry: " project: identifier - title"
|
|
252
252
|
*/
|
|
253
253
|
export function formatBriefList(result: ListResult): string {
|
|
254
|
-
const lines = [`${result.
|
|
254
|
+
const lines = [`${result.source} (${result.count}):`];
|
|
255
255
|
|
|
256
256
|
result.entries.forEach((entry) => {
|
|
257
|
-
const project = extractProjectFromEntry(entry, result.
|
|
258
|
-
const identifier = extractIdentifier(entry, result.
|
|
259
|
-
const displayText = getDisplayText(entry, result.
|
|
257
|
+
const project = extractProjectFromEntry(entry, result.source);
|
|
258
|
+
const identifier = extractIdentifier(entry, result.source);
|
|
259
|
+
const displayText = getDisplayText(entry, result.source);
|
|
260
260
|
|
|
261
261
|
const line = identifier
|
|
262
262
|
? ` ${project}: ${identifier} - ${displayText}`
|