recallnest 2.2.1 → 2.5.4

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.
Files changed (227) hide show
  1. package/CHANGELOG.md +150 -0
  2. package/README.md +46 -35
  3. package/README_CN.md +41 -26
  4. package/assets/ui/app.js +1031 -0
  5. package/assets/ui/index.html +224 -0
  6. package/assets/ui/styles.css +781 -0
  7. package/config.json.example +4 -1
  8. package/connectors/examples/email-adapter.ts +73 -0
  9. package/connectors/examples/logs-adapter.ts +103 -0
  10. package/connectors/examples/rss-adapter.ts +95 -0
  11. package/docs/api-reference.md +1291 -0
  12. package/docs/architecture.md +168 -0
  13. package/docs/connector-spec.md +126 -0
  14. package/eval/cases-canary.json +58 -0
  15. package/eval/cases-scope-robustness.json +278 -0
  16. package/eval/cases.json +117 -20
  17. package/package.json +22 -1
  18. package/src/__tests__/access-tracker-novelty.test.ts +238 -0
  19. package/src/__tests__/activity-counter.test.ts +125 -0
  20. package/src/__tests__/adaptive-fidelity.test.ts +102 -0
  21. package/src/__tests__/admission-control.test.ts +206 -0
  22. package/src/__tests__/anchor-generator.test.ts +67 -0
  23. package/src/__tests__/auto-consolidation.test.ts +168 -0
  24. package/src/__tests__/auto-recall.test.ts +131 -0
  25. package/src/__tests__/babel-integration.test.ts +144 -0
  26. package/src/__tests__/batch-dedup.test.ts +65 -0
  27. package/src/__tests__/canary-eval.test.ts +114 -0
  28. package/src/__tests__/capture-engine.test.ts +1238 -0
  29. package/src/__tests__/capture-heuristic.test.ts +171 -0
  30. package/src/__tests__/cascade-forget.test.ts +210 -0
  31. package/src/__tests__/category-min-scores.test.ts +33 -0
  32. package/src/__tests__/cc8-cc1-essential-context.test.ts +298 -0
  33. package/src/__tests__/circuit-breaker.test.ts +99 -0
  34. package/src/__tests__/cluster-consolidation.test.ts +782 -0
  35. package/src/__tests__/confidence-metadata.test.ts +125 -0
  36. package/src/__tests__/confidence-tracker.test.ts +261 -0
  37. package/src/__tests__/conflict-advisor.test.ts +206 -0
  38. package/src/__tests__/conflict-escalation.test.ts +149 -0
  39. package/src/__tests__/conflict-lifecycle.test.ts +83 -0
  40. package/src/__tests__/conflict-output.test.ts +85 -0
  41. package/src/__tests__/conflict-store.test.ts +374 -0
  42. package/src/__tests__/connector-v1.test.ts +181 -0
  43. package/src/__tests__/consolidation-engine.test.ts +333 -0
  44. package/src/__tests__/constructive-retrieval.test.ts +509 -0
  45. package/src/__tests__/context-collapse-renderer.test.ts +214 -0
  46. package/src/__tests__/context-composer-pins.test.ts +64 -0
  47. package/src/__tests__/context-composer-task-selection.test.ts +24 -0
  48. package/src/__tests__/context-reconstructor.test.ts +65 -0
  49. package/src/__tests__/context-renderer.test.ts +91 -0
  50. package/src/__tests__/continuity-eval.test.ts +275 -0
  51. package/src/__tests__/continuity-schema.test.ts +97 -0
  52. package/src/__tests__/contracts.test.ts +216 -0
  53. package/src/__tests__/conversation-importer.test.ts +692 -0
  54. package/src/__tests__/core-recall-eval.test.ts +235 -0
  55. package/src/__tests__/core-summary.test.ts +109 -0
  56. package/src/__tests__/data-checkup.test.ts +276 -0
  57. package/src/__tests__/decay-exemption.test.ts +84 -0
  58. package/src/__tests__/dedup-actions.test.ts +58 -0
  59. package/src/__tests__/dedup-guard.test.ts +39 -0
  60. package/src/__tests__/deterministic-id.test.ts +39 -0
  61. package/src/__tests__/distill-lock.test.ts +305 -0
  62. package/src/__tests__/distill-session-argshape.test.ts +79 -0
  63. package/src/__tests__/doctor.test.ts +319 -0
  64. package/src/__tests__/dream-pipeline.test.ts +321 -0
  65. package/src/__tests__/drill-down.test.ts +108 -0
  66. package/src/__tests__/embedder.test.ts +122 -0
  67. package/src/__tests__/emotion-decay.test.ts +46 -0
  68. package/src/__tests__/emotion-detector.test.ts +56 -0
  69. package/src/__tests__/emotion-phase1-integration.test.ts +153 -0
  70. package/src/__tests__/emotion-retrieval.test.ts +56 -0
  71. package/src/__tests__/entity-resolver.test.ts +58 -0
  72. package/src/__tests__/env-config.test.ts +151 -0
  73. package/src/__tests__/error-signature-boost.test.ts +87 -0
  74. package/src/__tests__/error-signature.test.ts +95 -0
  75. package/src/__tests__/error-taxonomy.test.ts +129 -0
  76. package/src/__tests__/ethics-layer.test.ts +476 -0
  77. package/src/__tests__/event-segmenter.test.ts +153 -0
  78. package/src/__tests__/feature-flags-integration.test.ts +54 -0
  79. package/src/__tests__/frequency-tracker.test.ts +113 -0
  80. package/src/__tests__/graph-export.test.ts +489 -0
  81. package/src/__tests__/hotness-blend.test.ts +76 -0
  82. package/src/__tests__/ingest-chunking.test.ts +44 -0
  83. package/src/__tests__/ingest.test.ts +360 -0
  84. package/src/__tests__/interference-detector.test.ts +203 -0
  85. package/src/__tests__/kg-extractor.test.ts +192 -0
  86. package/src/__tests__/kg-store.test.ts +300 -0
  87. package/src/__tests__/llm-consolidation.test.ts +226 -0
  88. package/src/__tests__/maintenance-locks.test.ts +174 -0
  89. package/src/__tests__/mcp-efficiency.test.ts +288 -0
  90. package/src/__tests__/mcp-related-scopes.test.ts +151 -0
  91. package/src/__tests__/memory-boundaries.test.ts +250 -0
  92. package/src/__tests__/memory-evolution-b2-b3-e1.test.ts +345 -0
  93. package/src/__tests__/memory-evolution.test.ts +271 -0
  94. package/src/__tests__/memory-health-rebalance.test.ts +144 -0
  95. package/src/__tests__/memory-lint.test.ts +421 -0
  96. package/src/__tests__/memory-output.test.ts +215 -0
  97. package/src/__tests__/memory-promotion.test.ts +315 -0
  98. package/src/__tests__/migrate-dedup-ids.test.ts +65 -0
  99. package/src/__tests__/multi-vector.test.ts +242 -0
  100. package/src/__tests__/narrative-architecture.test.ts +456 -0
  101. package/src/__tests__/noise-filter.test.ts +205 -0
  102. package/src/__tests__/obsidian-connector.test.ts +363 -0
  103. package/src/__tests__/omitted-reporting.test.ts +98 -0
  104. package/src/__tests__/pending-review.test.ts +77 -0
  105. package/src/__tests__/pii-redact.test.ts +314 -0
  106. package/src/__tests__/post-retrieval-filter.test.ts +178 -0
  107. package/src/__tests__/ppr-traversal.test.ts +256 -0
  108. package/src/__tests__/prediction-engine.test.ts +349 -0
  109. package/src/__tests__/predictive-prospective-memory.test.ts +416 -0
  110. package/src/__tests__/preference-guard-smoke.test.ts +211 -0
  111. package/src/__tests__/preference-matcher.test.ts +230 -0
  112. package/src/__tests__/preference-slots.test.ts +205 -0
  113. package/src/__tests__/prospective-memory.test.ts +283 -0
  114. package/src/__tests__/query-entity-detector.test.ts +171 -0
  115. package/src/__tests__/query-expander-alias.test.ts +146 -0
  116. package/src/__tests__/query-expander.test.ts +34 -0
  117. package/src/__tests__/recall-governor.test.ts +227 -0
  118. package/src/__tests__/recall-mode.test.ts +64 -0
  119. package/src/__tests__/result-synthesizer.test.ts +198 -0
  120. package/src/__tests__/resume-context.test.ts +4898 -0
  121. package/src/__tests__/retrieval-trace.test.ts +213 -0
  122. package/src/__tests__/retriever-boundary-weight.test.ts +136 -0
  123. package/src/__tests__/retroactive-boost.test.ts +223 -0
  124. package/src/__tests__/salience-scoring.test.ts +106 -0
  125. package/src/__tests__/scope-inventory.test.ts +200 -0
  126. package/src/__tests__/scope-policy.test.ts +69 -0
  127. package/src/__tests__/scope-suggester.test.ts +80 -0
  128. package/src/__tests__/session-checkpoint.test.ts +291 -0
  129. package/src/__tests__/session-distiller.test.ts +640 -0
  130. package/src/__tests__/session-gc.test.ts +215 -0
  131. package/src/__tests__/skill-engine.test.ts +552 -0
  132. package/src/__tests__/skill-promotion.test.ts +601 -0
  133. package/src/__tests__/skill-verifier.test.ts +122 -0
  134. package/src/__tests__/source-heartbeat.test.ts +250 -0
  135. package/src/__tests__/store-patch-metadata.test.ts +205 -0
  136. package/src/__tests__/store-scope-audit.test.ts +81 -0
  137. package/src/__tests__/store-upsert.test.ts +184 -0
  138. package/src/__tests__/supersede-chain.test.ts +154 -0
  139. package/src/__tests__/temporal-parser.test.ts +241 -0
  140. package/src/__tests__/temporal-validity.test.ts +160 -0
  141. package/src/__tests__/term-registry.test.ts +121 -0
  142. package/src/__tests__/tool-error-surfacing.test.ts +98 -0
  143. package/src/__tests__/tool-output-compressor.test.ts +160 -0
  144. package/src/__tests__/topic-tag.test.ts +113 -0
  145. package/src/__tests__/trusted-memory.test.ts +839 -0
  146. package/src/__tests__/usage-tracker.test.ts +287 -0
  147. package/src/__tests__/version-manager.test.ts +213 -0
  148. package/src/__tests__/workflow-observation-skill-outcome.test.ts +352 -0
  149. package/src/__tests__/workflow-observation.test.ts +433 -0
  150. package/src/__tests__/write-verifier.test.ts +122 -0
  151. package/src/access-tracker.ts +38 -32
  152. package/src/activity-counter.ts +46 -18
  153. package/src/aliases.ts +133 -0
  154. package/src/api-server.ts +27 -7
  155. package/src/audit-log.ts +4 -2
  156. package/src/auto-consolidation.ts +8 -3
  157. package/src/auto-gc.ts +85 -21
  158. package/src/capture-engine.ts +54 -21
  159. package/src/cli.ts +199 -37
  160. package/src/confidence-tracker.ts +36 -18
  161. package/src/connector-types.ts +57 -0
  162. package/src/consolidation-engine.ts +109 -11
  163. package/src/context-composer.ts +8 -1
  164. package/src/conversation-importer.ts +25 -1
  165. package/src/data-checkup.ts +126 -7
  166. package/src/distill-lock.ts +194 -15
  167. package/src/doctor.ts +38 -2
  168. package/src/dream-pipeline.ts +118 -34
  169. package/src/env-config.ts +77 -0
  170. package/src/error-signature.ts +153 -0
  171. package/src/error-taxonomy.ts +115 -0
  172. package/src/eval.ts +251 -6
  173. package/src/idempotency.ts +8 -0
  174. package/src/ingest.ts +234 -10
  175. package/src/kg-extractor.ts +6 -2
  176. package/src/kg-store.ts +236 -44
  177. package/src/llm-consolidation.ts +2 -1
  178. package/src/mcp-server.ts +85 -1799
  179. package/src/mcp-tool-deps.ts +48 -0
  180. package/src/mcp-tools-advanced.ts +941 -0
  181. package/src/mcp-tools-core.ts +633 -0
  182. package/src/mcp-tools-governance.ts +475 -0
  183. package/src/memory-boundaries.ts +3 -1
  184. package/src/memory-evolution.ts +73 -1
  185. package/src/memory-lint.ts +183 -10
  186. package/src/memory-output.ts +114 -3
  187. package/src/memory-promotion.ts +246 -0
  188. package/src/memory-schema.ts +25 -2
  189. package/src/memory-store-port.ts +43 -0
  190. package/src/multi-vector.ts +2 -1
  191. package/src/narrative-schema.ts +2 -1
  192. package/src/noise-filter.ts +57 -6
  193. package/src/obsidian-connector.ts +282 -0
  194. package/src/pii-detector.ts +157 -5
  195. package/src/query-expander.ts +90 -9
  196. package/src/result-synthesizer.ts +2 -1
  197. package/src/retention-policy.ts +2 -1
  198. package/src/retriever.ts +259 -139
  199. package/src/runtime-config.ts +8 -1
  200. package/src/scope-suggester.ts +113 -0
  201. package/src/session-distiller.ts +23 -2
  202. package/src/session-engine.ts +2 -1
  203. package/src/session-schema.ts +3 -2
  204. package/src/session-store.ts +5 -0
  205. package/src/skill-engine.ts +78 -0
  206. package/src/skill-promotion.ts +247 -47
  207. package/src/skill-schema.ts +16 -3
  208. package/src/skill-verifier.ts +152 -0
  209. package/src/source-heartbeat.ts +108 -0
  210. package/src/store.ts +267 -38
  211. package/src/tool-output-compressor.ts +3 -1
  212. package/src/ui-server.ts +2 -1
  213. package/src/usage-tracker.ts +242 -0
  214. package/src/version-manager.ts +3 -2
  215. package/src/workflow-observation-engine.ts +2 -1
  216. package/src/workflow-observation-schema.ts +2 -1
  217. package/src/workflow-observation-store.ts +6 -2
  218. package/.env +0 -4
  219. package/CLAUDE.md +0 -46
  220. package/config.json +0 -55
  221. package/daily-recall.sh +0 -110
  222. package/logs/daily-recall.error.log +0 -0
  223. package/logs/daily-recall.log +0 -30
  224. package/logs/ingest-2026-04-11.log +0 -110
  225. package/logs/ingest-2026-04-12.log +0 -90
  226. package/logs/launchagent-stderr.log +0 -0
  227. package/logs/launchagent-stdout.log +0 -0
@@ -28,11 +28,14 @@
28
28
  }
29
29
  },
30
30
  "retrieval": {
31
- "mode": "hybrid",
31
+ "mode": "vector",
32
32
  "vectorWeight": 0.7,
33
33
  "bm25Weight": 0.3,
34
34
  "recencyHalfLifeDays": 30,
35
35
  "timeDecayHalfLifeDays": 120,
36
36
  "hardMinScore": 0.3
37
+ },
38
+ "scopeRelations": {
39
+ "project:example-a": ["project:example-b"]
37
40
  }
38
41
  }
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Email Connector Adapter (skeleton)
4
+ *
5
+ * Demonstrates how to produce a ConnectorOutputV1 JSON file from an email
6
+ * source (IMAP, Gmail API, local mbox, etc.) for RecallNest ingestion.
7
+ *
8
+ * Usage:
9
+ * bun run connectors/examples/email-adapter.ts > email-output.json
10
+ * lm ingest --connector email-output.json
11
+ *
12
+ * Customize:
13
+ * 1. Replace the fetchEmails() stub with your IMAP/API client
14
+ * 2. Adjust scope to match your project naming
15
+ * 3. Set categoryHint based on email type (meeting invite → "events", etc.)
16
+ */
17
+
18
+ import type { ConnectorOutputV1 } from "../../src/connector-types.js";
19
+ import { createHash } from "node:crypto";
20
+
21
+ // ---------------------------------------------------------------------------
22
+ // TODO: Replace with real email fetching logic
23
+ // ---------------------------------------------------------------------------
24
+
25
+ interface RawEmail {
26
+ messageId: string;
27
+ subject: string;
28
+ body: string;
29
+ from: string;
30
+ date: string; // ISO 8601
31
+ }
32
+
33
+ async function fetchEmails(_since: Date): Promise<RawEmail[]> {
34
+ // Example: use imapflow, googleapis, or read from .mbox
35
+ // const client = new ImapFlow({ host: 'imap.example.com', ... });
36
+ // await client.connect();
37
+ // const messages = await client.fetch(...);
38
+ return []; // Replace with real implementation
39
+ }
40
+
41
+ // ---------------------------------------------------------------------------
42
+ // Transform → ConnectorOutputV1
43
+ // ---------------------------------------------------------------------------
44
+
45
+ async function main() {
46
+ const since = new Date(Date.now() - 7 * 86_400_000); // last 7 days
47
+ const emails = await fetchEmails(since);
48
+
49
+ const output: ConnectorOutputV1 = {
50
+ version: "connector-v1",
51
+ source: "email",
52
+ scope: "inbox:personal", // Customize: "inbox:work", "project:xyz"
53
+ producedAt: new Date().toISOString(),
54
+ records: emails.map((email) => ({
55
+ id: `email:${email.messageId}`,
56
+ text: email.body,
57
+ title: email.subject,
58
+ categoryHint: "events", // Customize per email type
59
+ importanceHint: 0.6, // Customize: 0.9 for flagged/starred
60
+ tags: ["email", `from:${email.from}`],
61
+ timestamp: email.date,
62
+ contentHash: createHash("sha256").update(email.body).digest("hex"),
63
+ sourceMetadata: {
64
+ from: email.from,
65
+ messageId: email.messageId,
66
+ },
67
+ })),
68
+ };
69
+
70
+ console.log(JSON.stringify(output, null, 2));
71
+ }
72
+
73
+ main().catch(console.error);
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Log File Connector Adapter (skeleton)
4
+ *
5
+ * Demonstrates how to produce a ConnectorOutputV1 JSON file from application
6
+ * log files for RecallNest ingestion. Useful for tracking deploy events,
7
+ * error patterns, and operational decisions.
8
+ *
9
+ * Usage:
10
+ * bun run connectors/examples/logs-adapter.ts /var/log/myapp/*.log > logs-output.json
11
+ * lm ingest --connector logs-output.json
12
+ *
13
+ * Customize:
14
+ * 1. Replace parseLogLine() with your log format parser
15
+ * 2. Adjust the importance/category logic for your use case
16
+ * 3. Set scope to match your project
17
+ */
18
+
19
+ import type { ConnectorOutputV1 } from "../../src/connector-types.js";
20
+ import { readFileSync } from "node:fs";
21
+ import { createHash } from "node:crypto";
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // TODO: Replace with your log format parser
25
+ // ---------------------------------------------------------------------------
26
+
27
+ interface ParsedLogEntry {
28
+ timestamp: string; // ISO 8601
29
+ level: "info" | "warn" | "error" | "debug";
30
+ message: string;
31
+ source?: string; // e.g. module name, service
32
+ }
33
+
34
+ function parseLogLine(line: string): ParsedLogEntry | null {
35
+ // Example: "2026-04-14T10:00:00Z [ERROR] auth: login failed for user@example.com"
36
+ const match = line.match(
37
+ /^(\d{4}-\d{2}-\d{2}T[\d:.]+Z?)\s+\[(\w+)]\s+(?:(\w+):\s+)?(.+)$/,
38
+ );
39
+ if (!match) return null;
40
+ return {
41
+ timestamp: match[1],
42
+ level: match[2].toLowerCase() as ParsedLogEntry["level"],
43
+ source: match[3],
44
+ message: match[4],
45
+ };
46
+ }
47
+
48
+ function levelToImportance(level: string): number {
49
+ switch (level) {
50
+ case "error": return 0.9;
51
+ case "warn": return 0.7;
52
+ case "info": return 0.5;
53
+ default: return 0.3;
54
+ }
55
+ }
56
+
57
+ // ---------------------------------------------------------------------------
58
+ // Transform → ConnectorOutputV1
59
+ // ---------------------------------------------------------------------------
60
+
61
+ function main() {
62
+ const files = process.argv.slice(2);
63
+ if (files.length === 0) {
64
+ console.error("Usage: logs-adapter.ts <logfile> [logfile...]");
65
+ process.exit(1);
66
+ }
67
+
68
+ const records: ConnectorOutputV1["records"] = [];
69
+
70
+ for (const file of files) {
71
+ const lines = readFileSync(file, "utf-8").split("\n").filter(Boolean);
72
+ for (const line of lines) {
73
+ const entry = parseLogLine(line);
74
+ if (!entry) continue;
75
+
76
+ // Skip debug-level by default — too noisy for memory storage
77
+ if (entry.level === "debug") continue;
78
+
79
+ records.push({
80
+ id: `log:${createHash("md5").update(line).digest("hex")}`,
81
+ text: entry.message,
82
+ title: entry.source ? `[${entry.level.toUpperCase()}] ${entry.source}` : undefined,
83
+ categoryHint: entry.level === "error" ? "cases" : "events",
84
+ importanceHint: levelToImportance(entry.level),
85
+ tags: ["log", entry.level, ...(entry.source ? [`module:${entry.source}`] : [])],
86
+ timestamp: entry.timestamp,
87
+ contentHash: createHash("sha256").update(line).digest("hex"),
88
+ });
89
+ }
90
+ }
91
+
92
+ const output: ConnectorOutputV1 = {
93
+ version: "connector-v1",
94
+ source: "logs",
95
+ scope: "ops:myapp", // Customize: "project:xyz", "ops:production"
96
+ producedAt: new Date().toISOString(),
97
+ records,
98
+ };
99
+
100
+ console.log(JSON.stringify(output, null, 2));
101
+ }
102
+
103
+ main();
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * RSS Feed Connector Adapter (skeleton)
4
+ *
5
+ * Demonstrates how to produce a ConnectorOutputV1 JSON file from RSS/Atom
6
+ * feeds for RecallNest ingestion. Useful for tracking industry news,
7
+ * blog posts, and research updates.
8
+ *
9
+ * Usage:
10
+ * bun run connectors/examples/rss-adapter.ts > rss-output.json
11
+ * lm ingest --connector rss-output.json
12
+ *
13
+ * Customize:
14
+ * 1. Replace fetchFeed() with your RSS parsing library (e.g. rss-parser)
15
+ * 2. Adjust feed URLs and scope
16
+ * 3. Set categoryHint / importanceHint based on feed type
17
+ */
18
+
19
+ import type { ConnectorOutputV1 } from "../../src/connector-types.js";
20
+ import { createHash } from "node:crypto";
21
+
22
+ // ---------------------------------------------------------------------------
23
+ // TODO: Replace with real RSS/Atom parsing
24
+ // ---------------------------------------------------------------------------
25
+
26
+ interface FeedItem {
27
+ guid: string;
28
+ title: string;
29
+ content: string; // HTML stripped to plain text
30
+ link: string;
31
+ pubDate: string; // ISO 8601
32
+ categories?: string[];
33
+ }
34
+
35
+ interface FeedConfig {
36
+ url: string;
37
+ scope: string; // e.g. "feeds:ai-news"
38
+ categoryHint?: string;
39
+ importanceHint?: number;
40
+ }
41
+
42
+ const FEEDS: FeedConfig[] = [
43
+ // Add your feeds here:
44
+ // { url: "https://example.com/feed.xml", scope: "feeds:example" },
45
+ ];
46
+
47
+ async function fetchFeed(_url: string): Promise<FeedItem[]> {
48
+ // Example with rss-parser:
49
+ // import Parser from "rss-parser";
50
+ // const parser = new Parser();
51
+ // const feed = await parser.parseURL(url);
52
+ // return feed.items.map(item => ({ ... }));
53
+ return []; // Replace with real implementation
54
+ }
55
+
56
+ // ---------------------------------------------------------------------------
57
+ // Transform → ConnectorOutputV1
58
+ // ---------------------------------------------------------------------------
59
+
60
+ async function main() {
61
+ for (const feed of FEEDS) {
62
+ const items = await fetchFeed(feed.url);
63
+
64
+ const output: ConnectorOutputV1 = {
65
+ version: "connector-v1",
66
+ source: "rss",
67
+ scope: feed.scope,
68
+ producedAt: new Date().toISOString(),
69
+ records: items.map((item) => ({
70
+ id: `rss:${createHash("md5").update(item.guid || item.link).digest("hex")}`,
71
+ text: item.content,
72
+ title: item.title,
73
+ categoryHint: feed.categoryHint ?? "knowledge",
74
+ importanceHint: feed.importanceHint ?? 0.6,
75
+ tags: [
76
+ "rss",
77
+ ...(item.categories ?? []),
78
+ `link:${item.link}`,
79
+ ],
80
+ timestamp: item.pubDate,
81
+ contentHash: createHash("sha256").update(item.content).digest("hex"),
82
+ sourceMetadata: {
83
+ feedUrl: feed.url,
84
+ link: item.link,
85
+ guid: item.guid,
86
+ },
87
+ })),
88
+ };
89
+
90
+ // Each feed outputs one JSON — pipe to separate files if needed
91
+ console.log(JSON.stringify(output, null, 2));
92
+ }
93
+ }
94
+
95
+ main().catch(console.error);