@voidwire/lore 0.7.0 → 0.8.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 +32 -5
- package/index.ts +3 -0
- package/lib/about.ts +5 -5
- package/lib/list.ts +3 -3
- package/lib/realtime.ts +1 -1
- package/lib/search.ts +13 -0
- package/lib/semantic.ts +11 -0
- package/lib/types.ts +33 -0
- package/package.json +3 -1
package/cli.ts
CHANGED
|
@@ -56,6 +56,7 @@ import {
|
|
|
56
56
|
type ObservationSubtype,
|
|
57
57
|
type ObservationConfidence,
|
|
58
58
|
} from "./index";
|
|
59
|
+
import { isValidLoreType, LORE_TYPES } from "./lib/types";
|
|
59
60
|
|
|
60
61
|
// ============================================================================
|
|
61
62
|
// Argument Parsing
|
|
@@ -204,6 +205,17 @@ async function handleSearch(args: string[]): Promise<void> {
|
|
|
204
205
|
const limit = parsed.has("limit") ? parseInt(parsed.get("limit")!, 10) : 20;
|
|
205
206
|
const since = parsed.get("since");
|
|
206
207
|
const project = parsed.get("project");
|
|
208
|
+
const type = parseList(parsed.get("type"));
|
|
209
|
+
|
|
210
|
+
// Validate type values against LoreType enum
|
|
211
|
+
if (type) {
|
|
212
|
+
const invalid = type.filter((t) => !isValidLoreType(t));
|
|
213
|
+
if (invalid.length > 0) {
|
|
214
|
+
fail(
|
|
215
|
+
`Invalid type: ${invalid.join(", ")}. Valid types: ${LORE_TYPES.join(", ")}`,
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
207
219
|
|
|
208
220
|
// Handle prismis passthrough
|
|
209
221
|
if (source === "prismis") {
|
|
@@ -250,7 +262,7 @@ async function handleSearch(args: string[]): Promise<void> {
|
|
|
250
262
|
// FTS5 path (explicit --exact only)
|
|
251
263
|
if (exact) {
|
|
252
264
|
try {
|
|
253
|
-
const results = search(query, { source, limit, since });
|
|
265
|
+
const results = search(query, { source, limit, since, type });
|
|
254
266
|
output({
|
|
255
267
|
success: true,
|
|
256
268
|
results,
|
|
@@ -278,7 +290,12 @@ async function handleSearch(args: string[]): Promise<void> {
|
|
|
278
290
|
// Semantic-only path (explicit --semantic)
|
|
279
291
|
if (semanticOnly) {
|
|
280
292
|
try {
|
|
281
|
-
const results = await semanticSearch(query, {
|
|
293
|
+
const results = await semanticSearch(query, {
|
|
294
|
+
source,
|
|
295
|
+
limit,
|
|
296
|
+
project,
|
|
297
|
+
type,
|
|
298
|
+
});
|
|
282
299
|
|
|
283
300
|
if (brief) {
|
|
284
301
|
console.log(formatBriefSearch(results));
|
|
@@ -308,6 +325,7 @@ async function handleSearch(args: string[]): Promise<void> {
|
|
|
308
325
|
limit,
|
|
309
326
|
project,
|
|
310
327
|
since,
|
|
328
|
+
type,
|
|
311
329
|
});
|
|
312
330
|
|
|
313
331
|
if (brief) {
|
|
@@ -510,7 +528,7 @@ function handleAbout(args: string[]): void {
|
|
|
510
528
|
const totalCount =
|
|
511
529
|
result.commits.count +
|
|
512
530
|
result.captures.count +
|
|
513
|
-
result.
|
|
531
|
+
result.flux.count +
|
|
514
532
|
result.teachings.count +
|
|
515
533
|
result.sessions.count;
|
|
516
534
|
|
|
@@ -817,6 +835,7 @@ Usage:
|
|
|
817
835
|
|
|
818
836
|
Search Options:
|
|
819
837
|
--exact Use FTS5 text search (bypasses semantic search)
|
|
838
|
+
--type <types> Filter by knowledge type (gotcha, decision, learning, etc.)
|
|
820
839
|
--limit <n> Maximum results (default: 20)
|
|
821
840
|
--project <name> Filter results by project
|
|
822
841
|
--brief Compact output (titles only)
|
|
@@ -864,6 +883,8 @@ Capture Types:
|
|
|
864
883
|
|
|
865
884
|
Examples:
|
|
866
885
|
lore search "authentication"
|
|
886
|
+
lore search --type=gotcha "sable"
|
|
887
|
+
lore search --type=gotcha,decision "lore"
|
|
867
888
|
lore search blogs "typescript patterns"
|
|
868
889
|
lore sources
|
|
869
890
|
lore list development
|
|
@@ -888,6 +909,10 @@ Search Modes:
|
|
|
888
909
|
--semantic Vector search only
|
|
889
910
|
|
|
890
911
|
Options:
|
|
912
|
+
--type <types> Filter by knowledge type (pre-filters before search)
|
|
913
|
+
Comma-separated: --type=gotcha,decision
|
|
914
|
+
Valid: gotcha, decision, pattern, learning, preference,
|
|
915
|
+
term, style, teaching, task, todo, idea
|
|
891
916
|
--limit <n> Maximum results (default: 20)
|
|
892
917
|
--project <name> Filter results by project/topic
|
|
893
918
|
--brief Compact output (titles only)
|
|
@@ -919,6 +944,8 @@ See also:
|
|
|
919
944
|
|
|
920
945
|
Examples:
|
|
921
946
|
lore search "authentication" # hybrid (default)
|
|
947
|
+
lore search --type=gotcha "sable" # filter by type
|
|
948
|
+
lore search --type=gotcha,decision "lore" # multiple types
|
|
922
949
|
lore search --exact "def process_data" # keyword only
|
|
923
950
|
lore search --semantic "login flow concepts" # vector only
|
|
924
951
|
lore search blogs "typescript patterns"
|
|
@@ -1048,7 +1075,7 @@ Options:
|
|
|
1048
1075
|
Sources queried:
|
|
1049
1076
|
commits Git commits for project
|
|
1050
1077
|
captures Quick captures in project context
|
|
1051
|
-
|
|
1078
|
+
flux Flux items for project
|
|
1052
1079
|
teachings Teachings from project
|
|
1053
1080
|
sessions Claude Code sessions for project
|
|
1054
1081
|
|
|
@@ -1057,7 +1084,7 @@ Output (JSON):
|
|
|
1057
1084
|
"project": "name",
|
|
1058
1085
|
"commits": [...],
|
|
1059
1086
|
"captures": [...],
|
|
1060
|
-
"
|
|
1087
|
+
"flux": [...],
|
|
1061
1088
|
"teachings": [...],
|
|
1062
1089
|
"sessions": [...]
|
|
1063
1090
|
}
|
package/index.ts
CHANGED
package/lib/about.ts
CHANGED
|
@@ -16,7 +16,7 @@ export interface AboutResult {
|
|
|
16
16
|
project: string;
|
|
17
17
|
commits: ListResult;
|
|
18
18
|
captures: ListResult;
|
|
19
|
-
|
|
19
|
+
flux: ListResult;
|
|
20
20
|
teachings: ListResult;
|
|
21
21
|
sessions: ListResult;
|
|
22
22
|
}
|
|
@@ -29,7 +29,7 @@ export interface AboutResult {
|
|
|
29
29
|
const ABOUT_SOURCES: Source[] = [
|
|
30
30
|
"commits",
|
|
31
31
|
"captures",
|
|
32
|
-
"
|
|
32
|
+
"flux",
|
|
33
33
|
"teachings",
|
|
34
34
|
"sessions",
|
|
35
35
|
];
|
|
@@ -65,7 +65,7 @@ export function about(
|
|
|
65
65
|
project,
|
|
66
66
|
commits: results[0],
|
|
67
67
|
captures: results[1],
|
|
68
|
-
|
|
68
|
+
flux: results[2],
|
|
69
69
|
teachings: results[3],
|
|
70
70
|
sessions: results[4],
|
|
71
71
|
};
|
|
@@ -85,8 +85,8 @@ export function formatBriefAbout(result: AboutResult): string {
|
|
|
85
85
|
if (result.captures.count > 0) {
|
|
86
86
|
sections.push(formatBriefList(result.captures));
|
|
87
87
|
}
|
|
88
|
-
if (result.
|
|
89
|
-
sections.push(formatBriefList(result.
|
|
88
|
+
if (result.flux.count > 0) {
|
|
89
|
+
sections.push(formatBriefList(result.flux));
|
|
90
90
|
}
|
|
91
91
|
if (result.teachings.count > 0) {
|
|
92
92
|
sections.push(formatBriefList(result.teachings));
|
package/lib/list.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { existsSync } from "fs";
|
|
|
12
12
|
// Source types - data sources that can be listed
|
|
13
13
|
export type Source =
|
|
14
14
|
| "development"
|
|
15
|
-
| "
|
|
15
|
+
| "flux"
|
|
16
16
|
| "events"
|
|
17
17
|
| "blogs"
|
|
18
18
|
| "commits"
|
|
@@ -34,7 +34,7 @@ export type Source =
|
|
|
34
34
|
|
|
35
35
|
export const SOURCES: Source[] = [
|
|
36
36
|
"development",
|
|
37
|
-
"
|
|
37
|
+
"flux",
|
|
38
38
|
"events",
|
|
39
39
|
"blogs",
|
|
40
40
|
"commits",
|
|
@@ -70,7 +70,7 @@ const PERSONAL_SUBTYPES: Partial<Record<Source, string>> = {
|
|
|
70
70
|
const PROJECT_FIELD: Record<string, string> = {
|
|
71
71
|
commits: "project",
|
|
72
72
|
sessions: "project",
|
|
73
|
-
|
|
73
|
+
flux: "project",
|
|
74
74
|
insights: "topic",
|
|
75
75
|
captures: "topic",
|
|
76
76
|
teachings: "topic",
|
package/lib/realtime.ts
CHANGED
package/lib/search.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface SearchOptions {
|
|
|
22
22
|
source?: string;
|
|
23
23
|
limit?: number;
|
|
24
24
|
since?: string;
|
|
25
|
+
type?: string | string[];
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
function getDatabasePath(): string {
|
|
@@ -73,6 +74,18 @@ export function search(
|
|
|
73
74
|
params.push(options.source);
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
if (options.type) {
|
|
78
|
+
const types = Array.isArray(options.type) ? options.type : [options.type];
|
|
79
|
+
const typeClauses = types.map(
|
|
80
|
+
() =>
|
|
81
|
+
"(json_extract(metadata, '$.type') = ? OR json_extract(metadata, '$.subtype') = ?)",
|
|
82
|
+
);
|
|
83
|
+
conditions.push(`(${typeClauses.join(" OR ")})`);
|
|
84
|
+
types.forEach((t) => {
|
|
85
|
+
params.push(t, t);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
76
89
|
if (options.since) {
|
|
77
90
|
conditions.push(
|
|
78
91
|
"json_extract(metadata, '$.date') IS NOT NULL AND json_extract(metadata, '$.date') != 'unknown' AND json_extract(metadata, '$.date') >= ?",
|
package/lib/semantic.ts
CHANGED
|
@@ -25,6 +25,7 @@ export interface SemanticSearchOptions {
|
|
|
25
25
|
source?: string;
|
|
26
26
|
limit?: number;
|
|
27
27
|
project?: string;
|
|
28
|
+
type?: string | string[];
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
/**
|
|
@@ -230,6 +231,13 @@ export async function semanticSearch(
|
|
|
230
231
|
params.push(options.project);
|
|
231
232
|
}
|
|
232
233
|
|
|
234
|
+
if (options.type) {
|
|
235
|
+
const types = Array.isArray(options.type) ? options.type : [options.type];
|
|
236
|
+
const placeholders = types.map(() => "?").join(", ");
|
|
237
|
+
conditions.push(`e.type IN (${placeholders})`);
|
|
238
|
+
params.push(...types);
|
|
239
|
+
}
|
|
240
|
+
|
|
233
241
|
sql = `
|
|
234
242
|
SELECT
|
|
235
243
|
s.rowid,
|
|
@@ -274,6 +282,7 @@ export interface HybridSearchOptions {
|
|
|
274
282
|
limit?: number;
|
|
275
283
|
project?: string;
|
|
276
284
|
since?: string;
|
|
285
|
+
type?: string | string[];
|
|
277
286
|
vectorWeight?: number;
|
|
278
287
|
textWeight?: number;
|
|
279
288
|
}
|
|
@@ -325,12 +334,14 @@ export async function hybridSearch(
|
|
|
325
334
|
source: options.source,
|
|
326
335
|
limit: fetchLimit,
|
|
327
336
|
project: options.project,
|
|
337
|
+
type: options.type,
|
|
328
338
|
}),
|
|
329
339
|
Promise.resolve(
|
|
330
340
|
keywordSearch(query, {
|
|
331
341
|
source: options.source,
|
|
332
342
|
limit: fetchLimit,
|
|
333
343
|
since: options.since,
|
|
344
|
+
type: options.type,
|
|
334
345
|
}),
|
|
335
346
|
),
|
|
336
347
|
]);
|
package/lib/types.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/types.ts - Core type definitions for lore
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Capture type vocabulary
|
|
7
|
+
* Single source of truth for --type filter validation
|
|
8
|
+
*/
|
|
9
|
+
export enum LoreType {
|
|
10
|
+
Gotcha = "gotcha",
|
|
11
|
+
Decision = "decision",
|
|
12
|
+
Pattern = "pattern",
|
|
13
|
+
Learning = "learning",
|
|
14
|
+
Preference = "preference",
|
|
15
|
+
Term = "term",
|
|
16
|
+
Style = "style",
|
|
17
|
+
Teaching = "teaching",
|
|
18
|
+
Task = "task",
|
|
19
|
+
Todo = "todo",
|
|
20
|
+
Idea = "idea",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Valid type values for runtime checking
|
|
25
|
+
*/
|
|
26
|
+
export const LORE_TYPES = Object.values(LoreType);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Check if a string is a valid LoreType
|
|
30
|
+
*/
|
|
31
|
+
export function isValidLoreType(value: string): value is LoreType {
|
|
32
|
+
return LORE_TYPES.includes(value as LoreType);
|
|
33
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voidwire/lore",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Unified knowledge CLI - Search, list, and capture your indexed knowledge",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.ts",
|
|
@@ -49,6 +49,8 @@
|
|
|
49
49
|
"bun-types": "1.3.5"
|
|
50
50
|
},
|
|
51
51
|
"scripts": {
|
|
52
|
+
"build": "tsc --noEmit false --outDir dist --declaration",
|
|
53
|
+
"typecheck": "tsc --noEmit",
|
|
52
54
|
"test": "bun test"
|
|
53
55
|
}
|
|
54
56
|
}
|