@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 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, { source, limit, project });
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.tasks.count +
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
- tasks Development tasks for project
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
- "tasks": [...],
1087
+ "flux": [...],
1061
1088
  "teachings": [...],
1062
1089
  "sessions": [...]
1063
1090
  }
package/index.ts CHANGED
@@ -97,5 +97,8 @@ export {
97
97
  type HybridSearchOptions,
98
98
  } from "./lib/semantic";
99
99
 
100
+ // Types
101
+ export { LoreType, LORE_TYPES, isValidLoreType } from "./lib/types";
102
+
100
103
  // Real-time indexing
101
104
  export { indexAndEmbed } from "./lib/realtime";
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
- tasks: ListResult;
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
- "tasks",
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
- tasks: results[2],
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.tasks.count > 0) {
89
- sections.push(formatBriefList(result.tasks));
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
- | "tasks"
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
- "tasks",
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
- tasks: "project",
73
+ flux: "project",
74
74
  insights: "topic",
75
75
  captures: "topic",
76
76
  teachings: "topic",
package/lib/realtime.ts CHANGED
@@ -113,7 +113,7 @@ function getSourceForEvent(event: CaptureEvent): string {
113
113
  case "learning":
114
114
  return "learnings";
115
115
  case "task":
116
- return "tasks";
116
+ return "flux";
117
117
  case "note":
118
118
  return "captures";
119
119
  default:
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.7.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
  }