ricord 1.0.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.
Files changed (134) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +213 -0
  3. package/commands/ricord-flush.md +29 -0
  4. package/commands/ricord-init.md +129 -0
  5. package/commands/ricord-lint.md +64 -0
  6. package/commands/ricord-query.md +71 -0
  7. package/dist/cli/auth.d.ts +16 -0
  8. package/dist/cli/auth.js +42 -0
  9. package/dist/cli/auth.js.map +1 -0
  10. package/dist/cli/bundle.d.ts +25 -0
  11. package/dist/cli/bundle.js +179 -0
  12. package/dist/cli/bundle.js.map +1 -0
  13. package/dist/cli/cache.d.ts +18 -0
  14. package/dist/cli/cache.js +39 -0
  15. package/dist/cli/cache.js.map +1 -0
  16. package/dist/cli/cli.d.ts +21 -0
  17. package/dist/cli/cli.js +355 -0
  18. package/dist/cli/cli.js.map +1 -0
  19. package/dist/cli/client.d.ts +12 -0
  20. package/dist/cli/client.js +35 -0
  21. package/dist/cli/client.js.map +1 -0
  22. package/dist/cli/commands/build.d.ts +44 -0
  23. package/dist/cli/commands/build.js +437 -0
  24. package/dist/cli/commands/build.js.map +1 -0
  25. package/dist/cli/commands/curate.d.ts +32 -0
  26. package/dist/cli/commands/curate.js +154 -0
  27. package/dist/cli/commands/curate.js.map +1 -0
  28. package/dist/cli/commands/doctor.d.ts +16 -0
  29. package/dist/cli/commands/doctor.js +92 -0
  30. package/dist/cli/commands/doctor.js.map +1 -0
  31. package/dist/cli/commands/ingest.d.ts +25 -0
  32. package/dist/cli/commands/ingest.js +121 -0
  33. package/dist/cli/commands/ingest.js.map +1 -0
  34. package/dist/cli/commands/install.d.ts +16 -0
  35. package/dist/cli/commands/install.js +82 -0
  36. package/dist/cli/commands/install.js.map +1 -0
  37. package/dist/cli/commands/pull.d.ts +24 -0
  38. package/dist/cli/commands/pull.js +104 -0
  39. package/dist/cli/commands/pull.js.map +1 -0
  40. package/dist/cli/commands/push.d.ts +28 -0
  41. package/dist/cli/commands/push.js +164 -0
  42. package/dist/cli/commands/push.js.map +1 -0
  43. package/dist/cli/commands/rollup.d.ts +21 -0
  44. package/dist/cli/commands/rollup.js +118 -0
  45. package/dist/cli/commands/rollup.js.map +1 -0
  46. package/dist/cli/commands/setup.d.ts +7 -0
  47. package/dist/cli/commands/setup.js +43 -0
  48. package/dist/cli/commands/setup.js.map +1 -0
  49. package/dist/cli/commands/sync.d.ts +15 -0
  50. package/dist/cli/commands/sync.js +63 -0
  51. package/dist/cli/commands/sync.js.map +1 -0
  52. package/dist/cli/commands/watch.d.ts +17 -0
  53. package/dist/cli/commands/watch.js +87 -0
  54. package/dist/cli/commands/watch.js.map +1 -0
  55. package/dist/cli/config.d.ts +29 -0
  56. package/dist/cli/config.js +52 -0
  57. package/dist/cli/config.js.map +1 -0
  58. package/dist/cli/extract.d.ts +101 -0
  59. package/dist/cli/extract.js +216 -0
  60. package/dist/cli/extract.js.map +1 -0
  61. package/dist/cli/ingest.d.ts +48 -0
  62. package/dist/cli/ingest.js +74 -0
  63. package/dist/cli/ingest.js.map +1 -0
  64. package/dist/cli/ledger.d.ts +44 -0
  65. package/dist/cli/ledger.js +67 -0
  66. package/dist/cli/ledger.js.map +1 -0
  67. package/dist/cli/llm.d.ts +21 -0
  68. package/dist/cli/llm.js +138 -0
  69. package/dist/cli/llm.js.map +1 -0
  70. package/dist/cli/parse.d.ts +13 -0
  71. package/dist/cli/parse.js +188 -0
  72. package/dist/cli/parse.js.map +1 -0
  73. package/dist/cli/run-explore.d.ts +56 -0
  74. package/dist/cli/run-explore.js +229 -0
  75. package/dist/cli/run-explore.js.map +1 -0
  76. package/dist/cli/summarize.d.ts +15 -0
  77. package/dist/cli/summarize.js +49 -0
  78. package/dist/cli/summarize.js.map +1 -0
  79. package/dist/cli/uninstall.d.ts +6 -0
  80. package/dist/cli/uninstall.js +277 -0
  81. package/dist/cli/uninstall.js.map +1 -0
  82. package/dist/cli/walk.d.ts +13 -0
  83. package/dist/cli/walk.js +62 -0
  84. package/dist/cli/walk.js.map +1 -0
  85. package/dist/cli/walker.d.ts +14 -0
  86. package/dist/cli/walker.js +120 -0
  87. package/dist/cli/walker.js.map +1 -0
  88. package/dist/hooks/pre-compact.d.ts +15 -0
  89. package/dist/hooks/pre-compact.js +127 -0
  90. package/dist/hooks/pre-compact.js.map +1 -0
  91. package/dist/hooks/pre-tool-use.d.ts +15 -0
  92. package/dist/hooks/pre-tool-use.js +25 -0
  93. package/dist/hooks/pre-tool-use.js.map +1 -0
  94. package/dist/hooks/session-end.d.ts +21 -0
  95. package/dist/hooks/session-end.js +186 -0
  96. package/dist/hooks/session-end.js.map +1 -0
  97. package/dist/hooks/session-start.d.ts +15 -0
  98. package/dist/hooks/session-start.js +233 -0
  99. package/dist/hooks/session-start.js.map +1 -0
  100. package/dist/hooks/turn-end-post.d.ts +17 -0
  101. package/dist/hooks/turn-end-post.js +66 -0
  102. package/dist/hooks/turn-end-post.js.map +1 -0
  103. package/dist/hooks/turn-end.d.ts +29 -0
  104. package/dist/hooks/turn-end.js +295 -0
  105. package/dist/hooks/turn-end.js.map +1 -0
  106. package/dist/index.d.ts +24 -0
  107. package/dist/index.js +1547 -0
  108. package/dist/index.js.map +1 -0
  109. package/dist/init.d.ts +45 -0
  110. package/dist/init.js +839 -0
  111. package/dist/init.js.map +1 -0
  112. package/dist/lib/active-project.d.ts +14 -0
  113. package/dist/lib/active-project.js +65 -0
  114. package/dist/lib/active-project.js.map +1 -0
  115. package/dist/lib/buffer.d.ts +34 -0
  116. package/dist/lib/buffer.js +79 -0
  117. package/dist/lib/buffer.js.map +1 -0
  118. package/dist/scripts/compile.d.ts +25 -0
  119. package/dist/scripts/compile.js +185 -0
  120. package/dist/scripts/compile.js.map +1 -0
  121. package/dist/scripts/config.d.ts +30 -0
  122. package/dist/scripts/config.js +68 -0
  123. package/dist/scripts/config.js.map +1 -0
  124. package/dist/scripts/flush.d.ts +23 -0
  125. package/dist/scripts/flush.js +230 -0
  126. package/dist/scripts/flush.js.map +1 -0
  127. package/dist/scripts/lint.d.ts +21 -0
  128. package/dist/scripts/lint.js +242 -0
  129. package/dist/scripts/lint.js.map +1 -0
  130. package/dist/scripts/utils.d.ts +43 -0
  131. package/dist/scripts/utils.js +165 -0
  132. package/dist/scripts/utils.js.map +1 -0
  133. package/package.json +74 -0
  134. package/scripts/postinstall.mjs +56 -0
@@ -0,0 +1,230 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Memory flush — saves the residual session conversation to Ricord.
4
+ *
5
+ * Spawned by session-end.ts or pre-compact.ts as a background process.
6
+ * Reads the conversation context from a temp .md file (markdown turns),
7
+ * parses it into a messages[] array, and POSTs to /v1/ingest/extracted
8
+ * with empty anchors (embed-only mode):
9
+ * - 1 row written to `memories` (full session, embedded)
10
+ * - N rows written to `episodes` (per-turn embedding)
11
+ * - Zero server-side LLM calls (post 2026-04-30 client-extraction migration)
12
+ * Also appends a human-readable summary to today's daily log.
13
+ *
14
+ * For full graph extraction (anchors / connections / tasks), the host LLM
15
+ * runs ricord_extract action="fetch_prompt" + "submit". This script does
16
+ * NOT do that — keeps the cost predictable (zero server LLM).
17
+ *
18
+ * After flushing, if it's past 6 PM local time, auto-triggers compilation.
19
+ *
20
+ * Usage:
21
+ * node dist/scripts/flush.js <context_file.md> <session_id>
22
+ */
23
+ import { readFileSync, existsSync, unlinkSync } from "node:fs";
24
+ import { spawn } from "node:child_process";
25
+ import { join } from "node:path";
26
+ // Recursion guard: if spawned by another flush/compile, exit
27
+ if (process.env.CLAUDE_INVOKED_BY) {
28
+ process.exit(0);
29
+ }
30
+ process.env.CLAUDE_INVOKED_BY = "ricord_flush";
31
+ import { loadCredentials, api, COMPILE_AFTER_HOUR, ROOT_DIR, } from "./config.js";
32
+ import { loadFlushState, saveFlushState, loadState, fileHash, appendToDailyLog, todayLogPath, scrubCredentials, detectProject, detectGitRepo, detectGitBranch, logToFile, } from "./utils.js";
33
+ const DEDUP_COOLDOWN_MS = 60_000; // 60s — same session can't flush twice within this window
34
+ // Convert markdown context (`**User:** ... \n\n**Assistant:** ... \n\n...`)
35
+ // back to a messages[] array for /v1/ingest/extracted. Lines that don't
36
+ // start with a known role marker are appended to the previous message.
37
+ function parseContextToMessages(context) {
38
+ const messages = [];
39
+ const blocks = context.split(/\n\n+/);
40
+ for (const raw of blocks) {
41
+ const block = raw.trim();
42
+ if (!block)
43
+ continue;
44
+ if (block.startsWith("**User:**")) {
45
+ messages.push({ role: "user", content: block.replace(/^\*\*User:\*\*\s*/, "").trim() });
46
+ }
47
+ else if (block.startsWith("**Assistant:**")) {
48
+ messages.push({ role: "assistant", content: block.replace(/^\*\*Assistant:\*\*\s*/, "").trim() });
49
+ }
50
+ else if (messages.length > 0) {
51
+ // Continuation of the previous message
52
+ messages[messages.length - 1].content += "\n\n" + block;
53
+ }
54
+ }
55
+ return messages.filter(m => m.content.length > 0);
56
+ }
57
+ async function extractAndSave(context, apiKey, apiBase, project, sessionId) {
58
+ const gitRepo = detectGitRepo();
59
+ const gitBranch = detectGitBranch();
60
+ const messages = parseContextToMessages(context);
61
+ let ingested = null;
62
+ if (messages.length > 0) {
63
+ const tags = ["auto-flush", "session-log"];
64
+ if (gitRepo)
65
+ tags.push(`repo:${gitRepo}`);
66
+ if (gitBranch)
67
+ tags.push(`branch:${gitBranch}`);
68
+ const body = {
69
+ session_id: sessionId,
70
+ messages,
71
+ extracted: { anchors: [] },
72
+ extraction_meta: {
73
+ model: "embed-only",
74
+ client: "ricord-mcp/flush",
75
+ schema_version: 1,
76
+ },
77
+ tags,
78
+ };
79
+ if (project)
80
+ body.project_id = project;
81
+ try {
82
+ const result = await api("POST", "/v1/ingest/extracted", body, apiKey, apiBase);
83
+ ingested = {
84
+ memory_id: result.memory_id,
85
+ messages: messages.length,
86
+ };
87
+ }
88
+ catch (e) {
89
+ logToFile(`ERROR ingest failed for session ${sessionId}: ${e.message}`);
90
+ }
91
+ }
92
+ // Build daily log entry
93
+ const lines = [];
94
+ lines.push(`**Context:** Auto-flushed from conversation`);
95
+ if (project)
96
+ lines.push(`**Project:** ${project}`);
97
+ if (ingested) {
98
+ lines.push("");
99
+ lines.push(`**Ingested:** 1 memory + ${ingested.messages} episode(s) (embed-only, no graph extraction)${ingested.memory_id ? ` — memory_id ${ingested.memory_id}` : ""}`);
100
+ }
101
+ else if (messages.length === 0) {
102
+ lines.push("", "**Ingested:** (none — context had no parseable turns)");
103
+ }
104
+ else {
105
+ lines.push("", "**Ingested:** (failed — see hook log)");
106
+ }
107
+ // Include abbreviated user topics for human-readable daily log
108
+ const userLines = messages
109
+ .filter(m => m.role === "user")
110
+ .map(m => m.content.split("\n")[0].slice(0, 120))
111
+ .slice(-5);
112
+ if (userLines.length > 0) {
113
+ lines.push("");
114
+ lines.push("**Session Topics:**");
115
+ for (const topic of userLines) {
116
+ lines.push(`- ${topic}`);
117
+ }
118
+ }
119
+ return { ingested, dailyEntry: lines.join("\n") };
120
+ }
121
+ function maybeTriggerCompilation() {
122
+ const now = new Date();
123
+ const localHour = now.getHours();
124
+ if (localHour < COMPILE_AFTER_HOUR)
125
+ return;
126
+ // Check if today's log has changed since last compile
127
+ const logPath = todayLogPath();
128
+ if (!existsSync(logPath))
129
+ return;
130
+ const state = loadState();
131
+ const today = now.toLocaleDateString("en-CA") + ".md";
132
+ const prev = state.ingested[today];
133
+ if (prev && prev.hash === fileHash(logPath)) {
134
+ logToFile("INFO skip compilation — daily log unchanged since last compile");
135
+ return;
136
+ }
137
+ // Spawn compile.ts as background process
138
+ const compileScript = join(ROOT_DIR, "dist", "scripts", "compile.js");
139
+ if (!existsSync(compileScript)) {
140
+ logToFile("WARN compile.js not found, skipping auto-compilation");
141
+ return;
142
+ }
143
+ logToFile(`INFO triggering end-of-day compilation (after ${COMPILE_AFTER_HOUR}:00)`);
144
+ try {
145
+ // REL-02: Use "ignore" for child stdio — piping stdout/stderr without reading
146
+ // can cause the child to block when the pipe buffer fills.
147
+ const child = spawn("node", [compileScript], {
148
+ cwd: ROOT_DIR,
149
+ detached: true,
150
+ stdio: "ignore",
151
+ env: { ...process.env, CLAUDE_INVOKED_BY: "ricord_compile" },
152
+ });
153
+ child.unref();
154
+ }
155
+ catch (e) {
156
+ logToFile(`ERROR failed to spawn compile: ${e.message}`);
157
+ }
158
+ }
159
+ async function main() {
160
+ if (process.argv.length < 4) {
161
+ logToFile("ERROR usage: flush.js <context_file.md> <session_id>");
162
+ process.exit(1);
163
+ }
164
+ const contextFile = process.argv[2];
165
+ const sessionId = process.argv[3];
166
+ logToFile(`INFO flush started: session=${sessionId}`);
167
+ // SEC-08: Validate contextFile is within the expected temp directory to prevent
168
+ // path traversal if flush.js is invoked with a crafted argument.
169
+ const { resolve: resolvePath } = await import("node:path");
170
+ const { tmpdir: _tmpdir } = await import("node:os");
171
+ const EXPECTED_CONTEXT_DIR = resolvePath(_tmpdir(), "ricord-contexts");
172
+ const resolvedContextFile = resolvePath(contextFile);
173
+ if (!resolvedContextFile.startsWith(EXPECTED_CONTEXT_DIR + "/")) {
174
+ logToFile(`ERROR context file is outside expected directory: ${resolvedContextFile}`);
175
+ return;
176
+ }
177
+ // Deduplication: same session can't flush twice within cooldown
178
+ const lastFlush = loadFlushState();
179
+ if (lastFlush && lastFlush.session_id === sessionId) {
180
+ const elapsed = Date.now() - lastFlush.timestamp;
181
+ if (elapsed < DEDUP_COOLDOWN_MS) {
182
+ logToFile(`INFO skip — session ${sessionId} flushed ${Math.round(elapsed / 1000)}s ago`);
183
+ return;
184
+ }
185
+ }
186
+ // Read context from temp file
187
+ if (!existsSync(contextFile)) {
188
+ logToFile(`ERROR context file not found: ${contextFile}`);
189
+ return;
190
+ }
191
+ let context = readFileSync(contextFile, "utf8");
192
+ if (!context.trim()) {
193
+ logToFile("INFO skip — empty context");
194
+ return;
195
+ }
196
+ // Scrub credentials before sending to API
197
+ context = scrubCredentials(context);
198
+ // Load credentials
199
+ const creds = loadCredentials();
200
+ if (!creds) {
201
+ logToFile("ERROR no Ricord credentials found");
202
+ return;
203
+ }
204
+ const apiBase = creds.api_base || "https://api.ricord.ai";
205
+ const project = detectProject();
206
+ // Extract and save
207
+ try {
208
+ const { ingested, dailyEntry } = await extractAndSave(context, creds.api_key, apiBase, project, sessionId);
209
+ logToFile(`INFO flushed session ${sessionId} — ${ingested ? `1 memory + ${ingested.messages} episodes` : "no rows ingested"}`);
210
+ // Append to daily log
211
+ appendToDailyLog(dailyEntry, `Flush (session ${sessionId.slice(0, 8)})`);
212
+ // Update flush state for dedup
213
+ saveFlushState({ session_id: sessionId, timestamp: Date.now() });
214
+ // Maybe trigger compilation
215
+ maybeTriggerCompilation();
216
+ }
217
+ catch (e) {
218
+ logToFile(`ERROR flush failed: ${e.message}`);
219
+ }
220
+ // Clean up temp context file
221
+ try {
222
+ unlinkSync(contextFile);
223
+ }
224
+ catch { }
225
+ }
226
+ main().catch(e => {
227
+ logToFile(`FATAL ${e.message}`);
228
+ process.exit(1);
229
+ });
230
+ //# sourceMappingURL=flush.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flush.js","sourceRoot":"","sources":["../../src/scripts/flush.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Lint the Ricord knowledge base for health issues.
4
+ *
5
+ * Runs health checks against both the local daily logs and the remote
6
+ * Ricord KB layer. Generates a markdown report in reports/.
7
+ *
8
+ * Checks:
9
+ * 1. Orphan sources — daily logs that haven't been compiled
10
+ * 2. Stale articles — daily logs changed since last compilation
11
+ * 3. KB lint — server-side orphans, stale pages, oversize bodies
12
+ * 4. Sparse items — knowledge items with very short content
13
+ * 5. Duplicate titles — items with identical or near-identical titles
14
+ * 6. Untagged items — items with no tags (harder to find later)
15
+ * 7. Empty daily logs — log files with no actual content
16
+ *
17
+ * Usage:
18
+ * node dist/scripts/lint.js # all checks
19
+ * node dist/scripts/lint.js --structural-only # skip API checks (offline)
20
+ */
21
+ export {};
@@ -0,0 +1,242 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Lint the Ricord knowledge base for health issues.
4
+ *
5
+ * Runs health checks against both the local daily logs and the remote
6
+ * Ricord KB layer. Generates a markdown report in reports/.
7
+ *
8
+ * Checks:
9
+ * 1. Orphan sources — daily logs that haven't been compiled
10
+ * 2. Stale articles — daily logs changed since last compilation
11
+ * 3. KB lint — server-side orphans, stale pages, oversize bodies
12
+ * 4. Sparse items — knowledge items with very short content
13
+ * 5. Duplicate titles — items with identical or near-identical titles
14
+ * 6. Untagged items — items with no tags (harder to find later)
15
+ * 7. Empty daily logs — log files with no actual content
16
+ *
17
+ * Usage:
18
+ * node dist/scripts/lint.js # all checks
19
+ * node dist/scripts/lint.js --structural-only # skip API checks (offline)
20
+ */
21
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
22
+ import { join } from "node:path";
23
+ import { loadCredentials, api, DAILY_DIR, REPORTS_DIR, todayISO, nowISO, } from "./config.js";
24
+ import { loadState, saveState, fileHash, listDailyLogs, detectProject, logToFile, } from "./utils.js";
25
+ // ── Check 1: Orphan sources (daily logs not compiled) ────────────────
26
+ function checkOrphanSources() {
27
+ const state = loadState();
28
+ const issues = [];
29
+ for (const logName of listDailyLogs()) {
30
+ if (!state.ingested[logName]) {
31
+ issues.push({
32
+ severity: "warning",
33
+ check: "orphan_source",
34
+ file: `daily/${logName}`,
35
+ detail: `Uncompiled daily log: ${logName} has not been ingested`,
36
+ });
37
+ }
38
+ }
39
+ return issues;
40
+ }
41
+ // ── Check 2: Stale articles (source changed since compilation) ───────
42
+ function checkStaleArticles() {
43
+ const state = loadState();
44
+ const issues = [];
45
+ for (const logName of listDailyLogs()) {
46
+ const prev = state.ingested[logName];
47
+ if (prev) {
48
+ const logPath = join(DAILY_DIR, logName);
49
+ const currentHash = fileHash(logPath);
50
+ if (prev.hash !== currentHash) {
51
+ issues.push({
52
+ severity: "warning",
53
+ check: "stale_article",
54
+ file: `daily/${logName}`,
55
+ detail: `Stale: ${logName} has changed since last compilation at ${prev.compiled_at}`,
56
+ });
57
+ }
58
+ }
59
+ }
60
+ return issues;
61
+ }
62
+ // ── Check 3: KB lint (server-side) ───────────────────────────────────
63
+ async function checkKBLint(apiKey, apiBase, project) {
64
+ const issues = [];
65
+ try {
66
+ const body = {};
67
+ if (project)
68
+ body.project_id = project;
69
+ const result = await api("POST", "/v1/kb/lint", body, apiKey, apiBase);
70
+ for (const issue of result.issues || []) {
71
+ issues.push({
72
+ severity: issue.severity === "error" ? "error" : "warning",
73
+ check: `kb_${issue.type}`,
74
+ file: issue.page_id || "(kb)",
75
+ detail: issue.message,
76
+ });
77
+ }
78
+ }
79
+ catch (e) {
80
+ issues.push({
81
+ severity: "error",
82
+ check: "kb_lint",
83
+ file: "(system)",
84
+ detail: `KB lint API call failed: ${e.message}`,
85
+ });
86
+ }
87
+ return issues;
88
+ }
89
+ // ── Check 4: Sparse items ────────────────────────────────────────────
90
+ async function checkSparseItems(apiKey, apiBase, project) {
91
+ const issues = [];
92
+ try {
93
+ const params = project ? `?project_id=${project}&limit=100` : "?limit=100";
94
+ const result = await api("GET", `/v1/memories${params}`, undefined, apiKey, apiBase);
95
+ for (const item of result.memories || []) {
96
+ const wordCount = (item.content || "").split(/\s+/).filter(Boolean).length;
97
+ if (wordCount < 10) {
98
+ issues.push({
99
+ severity: "suggestion",
100
+ check: "sparse_item",
101
+ file: item.id,
102
+ detail: `Sparse: "${item.title}" has only ${wordCount} words`,
103
+ });
104
+ }
105
+ }
106
+ }
107
+ catch (e) {
108
+ logToFile(`WARN sparse check failed: ${e.message}`);
109
+ }
110
+ return issues;
111
+ }
112
+ // ── Check 5: Duplicate titles ────────────────────────────────────────
113
+ async function checkDuplicateTitles(apiKey, apiBase, project) {
114
+ const issues = [];
115
+ try {
116
+ const params = project ? `?project_id=${project}&limit=200` : "?limit=200";
117
+ const result = await api("GET", `/v1/memories${params}`, undefined, apiKey, apiBase);
118
+ const titleMap = new Map();
119
+ for (const item of result.memories || []) {
120
+ const normalized = item.title.toLowerCase().trim();
121
+ const ids = titleMap.get(normalized) || [];
122
+ ids.push(item.id);
123
+ titleMap.set(normalized, ids);
124
+ }
125
+ for (const [title, ids] of titleMap) {
126
+ if (ids.length > 1) {
127
+ issues.push({
128
+ severity: "warning",
129
+ check: "duplicate_title",
130
+ file: ids.join(", "),
131
+ detail: `Duplicate title: "${title}" appears ${ids.length} times`,
132
+ });
133
+ }
134
+ }
135
+ }
136
+ catch (e) {
137
+ logToFile(`WARN duplicate check failed: ${e.message}`);
138
+ }
139
+ return issues;
140
+ }
141
+ // ── Check 6: Empty daily logs ────────────────────────────────────────
142
+ function checkEmptyDailyLogs() {
143
+ const issues = [];
144
+ for (const logName of listDailyLogs()) {
145
+ const logPath = join(DAILY_DIR, logName);
146
+ const content = readFileSync(logPath, "utf8");
147
+ // A "template only" log has the header but no session content
148
+ const stripped = content
149
+ .replace(/^#.*$/gm, "")
150
+ .replace(/^##.*$/gm, "")
151
+ .trim();
152
+ if (stripped.length < 50) {
153
+ issues.push({
154
+ severity: "suggestion",
155
+ check: "empty_log",
156
+ file: `daily/${logName}`,
157
+ detail: `Empty or near-empty daily log: ${logName}`,
158
+ });
159
+ }
160
+ }
161
+ return issues;
162
+ }
163
+ // ── Report generation ────────────────────────────────────────────────
164
+ function generateReport(issues) {
165
+ const errors = issues.filter(i => i.severity === "error");
166
+ const warnings = issues.filter(i => i.severity === "warning");
167
+ const suggestions = issues.filter(i => i.severity === "suggestion");
168
+ const lines = [
169
+ `# Ricord Lint Report — ${todayISO()}`,
170
+ "",
171
+ `**Total issues:** ${issues.length}`,
172
+ `- Errors: ${errors.length}`,
173
+ `- Warnings: ${warnings.length}`,
174
+ `- Suggestions: ${suggestions.length}`,
175
+ "",
176
+ ];
177
+ const sections = [
178
+ ["Errors", errors, "x"],
179
+ ["Warnings", warnings, "!"],
180
+ ["Suggestions", suggestions, "?"],
181
+ ];
182
+ for (const [label, items, marker] of sections) {
183
+ if (items.length > 0) {
184
+ lines.push(`## ${label}`);
185
+ lines.push("");
186
+ for (const issue of items) {
187
+ lines.push(`- **[${marker}]** \`${issue.file}\` — ${issue.detail}`);
188
+ }
189
+ lines.push("");
190
+ }
191
+ }
192
+ if (issues.length === 0) {
193
+ lines.push("All checks passed. Knowledge base is healthy.");
194
+ lines.push("");
195
+ }
196
+ return lines.join("\n");
197
+ }
198
+ async function main() {
199
+ const args = process.argv.slice(2);
200
+ const structuralOnly = args.includes("--structural-only");
201
+ console.log(`Ricord KB Lint — ${todayISO()}`);
202
+ console.log("=".repeat(40));
203
+ const allIssues = [];
204
+ // Structural checks (no API needed)
205
+ console.log("\nRunning structural checks...");
206
+ allIssues.push(...checkOrphanSources());
207
+ allIssues.push(...checkStaleArticles());
208
+ allIssues.push(...checkEmptyDailyLogs());
209
+ // API-backed checks
210
+ if (!structuralOnly) {
211
+ const creds = loadCredentials();
212
+ if (!creds) {
213
+ console.error("No Ricord credentials — skipping API checks. Use --structural-only for offline mode.");
214
+ }
215
+ else {
216
+ const apiBase = creds.api_base || "https://api.ricord.ai";
217
+ const project = detectProject();
218
+ console.log("Running API-backed checks...");
219
+ allIssues.push(...await checkKBLint(creds.api_key, apiBase, project));
220
+ allIssues.push(...await checkSparseItems(creds.api_key, apiBase, project));
221
+ allIssues.push(...await checkDuplicateTitles(creds.api_key, apiBase, project));
222
+ }
223
+ }
224
+ // Generate report
225
+ const report = generateReport(allIssues);
226
+ console.log("\n" + report);
227
+ // Save report to file
228
+ if (!existsSync(REPORTS_DIR))
229
+ mkdirSync(REPORTS_DIR, { recursive: true });
230
+ const reportPath = join(REPORTS_DIR, `lint-${todayISO()}.md`);
231
+ writeFileSync(reportPath, report, "utf8");
232
+ console.log(`Report saved to: ${reportPath}`);
233
+ // Update state
234
+ const state = loadState();
235
+ state.last_lint = nowISO();
236
+ saveState(state);
237
+ }
238
+ main().catch(e => {
239
+ console.error(`Fatal: ${e.message}`);
240
+ process.exit(1);
241
+ });
242
+ //# sourceMappingURL=lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.js","sourceRoot":"","sources":["../../src/scripts/lint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Shared utilities for Ricord scripts.
3
+ *
4
+ * Helpers for state tracking, file hashing, daily log manipulation,
5
+ * credential scrubbing, and JSONL transcript parsing.
6
+ */
7
+ export interface CompileState {
8
+ ingested: Record<string, {
9
+ hash: string;
10
+ compiled_at: string;
11
+ cost_usd?: number;
12
+ }>;
13
+ total_cost: number;
14
+ query_count: number;
15
+ last_lint: string;
16
+ }
17
+ export declare function loadState(): CompileState;
18
+ export declare function saveState(state: CompileState): void;
19
+ export interface FlushState {
20
+ session_id: string;
21
+ timestamp: number;
22
+ }
23
+ export declare function loadFlushState(): FlushState | null;
24
+ export declare function saveFlushState(state: FlushState): void;
25
+ export declare function fileHash(path: string): string;
26
+ export declare function ensureDailyDir(): void;
27
+ export declare function todayLogPath(): string;
28
+ export declare function appendToDailyLog(content: string, section?: string): void;
29
+ export declare function listDailyLogs(): string[];
30
+ export interface ConversationTurn {
31
+ role: "user" | "assistant";
32
+ text: string;
33
+ }
34
+ export declare function extractConversation(transcriptPath: string, maxTurns?: number, maxChars?: number): {
35
+ turns: ConversationTurn[];
36
+ context: string;
37
+ turnCount: number;
38
+ };
39
+ export declare function scrubCredentials(text: string): string;
40
+ export declare function detectProject(): string;
41
+ export declare function detectGitRepo(): string;
42
+ export declare function detectGitBranch(): string;
43
+ export declare function logToFile(message: string, file?: string): void;