@getrift/rift 0.1.0-beta.20 → 0.1.0-beta.22

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 (280) hide show
  1. package/README.md +7 -3
  2. package/dist/src/capture/auto-capture.d.ts +105 -4
  3. package/dist/src/capture/auto-capture.d.ts.map +1 -1
  4. package/dist/src/capture/auto-capture.js +313 -34
  5. package/dist/src/capture/auto-capture.js.map +1 -1
  6. package/dist/src/capture/claude-cli-triage-provider.d.ts +28 -0
  7. package/dist/src/capture/claude-cli-triage-provider.d.ts.map +1 -0
  8. package/dist/src/capture/claude-cli-triage-provider.js +88 -0
  9. package/dist/src/capture/claude-cli-triage-provider.js.map +1 -0
  10. package/dist/src/capture/codex-cli-triage-provider.d.ts.map +1 -1
  11. package/dist/src/capture/codex-cli-triage-provider.js +1 -33
  12. package/dist/src/capture/codex-cli-triage-provider.js.map +1 -1
  13. package/dist/src/capture/cursor-capture.d.ts +89 -0
  14. package/dist/src/capture/cursor-capture.d.ts.map +1 -0
  15. package/dist/src/capture/cursor-capture.js +121 -0
  16. package/dist/src/capture/cursor-capture.js.map +1 -0
  17. package/dist/src/capture/observability.d.ts +30 -0
  18. package/dist/src/capture/observability.d.ts.map +1 -1
  19. package/dist/src/capture/observability.js +29 -0
  20. package/dist/src/capture/observability.js.map +1 -1
  21. package/dist/src/capture/sources.d.ts +41 -3
  22. package/dist/src/capture/sources.d.ts.map +1 -1
  23. package/dist/src/capture/sources.js +43 -1
  24. package/dist/src/capture/sources.js.map +1 -1
  25. package/dist/src/capture/triage-classification.d.ts +69 -0
  26. package/dist/src/capture/triage-classification.d.ts.map +1 -0
  27. package/dist/src/capture/triage-classification.js +62 -0
  28. package/dist/src/capture/triage-classification.js.map +1 -0
  29. package/dist/src/capture/triage-provider-factory.d.ts +36 -0
  30. package/dist/src/capture/triage-provider-factory.d.ts.map +1 -0
  31. package/dist/src/capture/triage-provider-factory.js +55 -0
  32. package/dist/src/capture/triage-provider-factory.js.map +1 -0
  33. package/dist/src/capture/triage.d.ts +1 -1
  34. package/dist/src/capture/triage.d.ts.map +1 -1
  35. package/dist/src/capture/triage.js +8 -6
  36. package/dist/src/capture/triage.js.map +1 -1
  37. package/dist/src/cli/commands/capture.d.ts.map +1 -1
  38. package/dist/src/cli/commands/capture.js +72 -17
  39. package/dist/src/cli/commands/capture.js.map +1 -1
  40. package/dist/src/cli/commands/chunk-backfill.d.ts +13 -0
  41. package/dist/src/cli/commands/chunk-backfill.d.ts.map +1 -0
  42. package/dist/src/cli/commands/chunk-backfill.js +157 -0
  43. package/dist/src/cli/commands/chunk-backfill.js.map +1 -0
  44. package/dist/src/cli/commands/cursor-probe.d.ts +20 -0
  45. package/dist/src/cli/commands/cursor-probe.d.ts.map +1 -0
  46. package/dist/src/cli/commands/cursor-probe.js +162 -0
  47. package/dist/src/cli/commands/cursor-probe.js.map +1 -0
  48. package/dist/src/cli/commands/menubar.d.ts +50 -0
  49. package/dist/src/cli/commands/menubar.d.ts.map +1 -1
  50. package/dist/src/cli/commands/menubar.js +224 -16
  51. package/dist/src/cli/commands/menubar.js.map +1 -1
  52. package/dist/src/cli/commands/onboard.d.ts +36 -7
  53. package/dist/src/cli/commands/onboard.d.ts.map +1 -1
  54. package/dist/src/cli/commands/onboard.js +256 -53
  55. package/dist/src/cli/commands/onboard.js.map +1 -1
  56. package/dist/src/cli/commands/status.d.ts.map +1 -1
  57. package/dist/src/cli/commands/status.js +16 -0
  58. package/dist/src/cli/commands/status.js.map +1 -1
  59. package/dist/src/cli/commands/update.d.ts +34 -1
  60. package/dist/src/cli/commands/update.d.ts.map +1 -1
  61. package/dist/src/cli/commands/update.js +179 -2
  62. package/dist/src/cli/commands/update.js.map +1 -1
  63. package/dist/src/cli/index.d.ts.map +1 -1
  64. package/dist/src/cli/index.js +4 -0
  65. package/dist/src/cli/index.js.map +1 -1
  66. package/dist/src/cli/postinstall-menubar.d.ts.map +1 -1
  67. package/dist/src/cli/postinstall-menubar.js +14 -0
  68. package/dist/src/cli/postinstall-menubar.js.map +1 -1
  69. package/dist/src/cli/status/friend-header.d.ts +18 -0
  70. package/dist/src/cli/status/friend-header.d.ts.map +1 -1
  71. package/dist/src/cli/status/friend-header.js +137 -0
  72. package/dist/src/cli/status/friend-header.js.map +1 -1
  73. package/dist/src/cli/status/local-signals.d.ts +41 -0
  74. package/dist/src/cli/status/local-signals.d.ts.map +1 -1
  75. package/dist/src/cli/status/local-signals.js +48 -0
  76. package/dist/src/cli/status/local-signals.js.map +1 -1
  77. package/dist/src/config/schema.d.ts +220 -14
  78. package/dist/src/config/schema.d.ts.map +1 -1
  79. package/dist/src/config/schema.js +82 -7
  80. package/dist/src/config/schema.js.map +1 -1
  81. package/dist/src/diagnostics/claude-preflight.d.ts +34 -0
  82. package/dist/src/diagnostics/claude-preflight.d.ts.map +1 -0
  83. package/dist/src/diagnostics/claude-preflight.js +89 -0
  84. package/dist/src/diagnostics/claude-preflight.js.map +1 -0
  85. package/dist/src/diagnostics/codex-preflight.d.ts +1 -1
  86. package/dist/src/diagnostics/codex-preflight.d.ts.map +1 -1
  87. package/dist/src/diagnostics/codex-preflight.js +14 -0
  88. package/dist/src/diagnostics/codex-preflight.js.map +1 -1
  89. package/dist/src/diagnostics/doctor.d.ts +9 -1
  90. package/dist/src/diagnostics/doctor.d.ts.map +1 -1
  91. package/dist/src/diagnostics/doctor.js +57 -2
  92. package/dist/src/diagnostics/doctor.js.map +1 -1
  93. package/dist/src/ingestion/chunk-meta.d.ts +85 -0
  94. package/dist/src/ingestion/chunk-meta.d.ts.map +1 -0
  95. package/dist/src/ingestion/chunk-meta.js +167 -0
  96. package/dist/src/ingestion/chunk-meta.js.map +1 -0
  97. package/dist/src/ingestion/chunk-text.d.ts +39 -0
  98. package/dist/src/ingestion/chunk-text.d.ts.map +1 -0
  99. package/dist/src/ingestion/chunk-text.js +114 -0
  100. package/dist/src/ingestion/chunk-text.js.map +1 -0
  101. package/dist/src/ingestion/cursor/cursor-store.d.ts +177 -0
  102. package/dist/src/ingestion/cursor/cursor-store.d.ts.map +1 -0
  103. package/dist/src/ingestion/cursor/cursor-store.js +243 -0
  104. package/dist/src/ingestion/cursor/cursor-store.js.map +1 -0
  105. package/dist/src/ingestion/cursor/enrich-roots.d.ts +16 -0
  106. package/dist/src/ingestion/cursor/enrich-roots.d.ts.map +1 -0
  107. package/dist/src/ingestion/cursor/enrich-roots.js +22 -0
  108. package/dist/src/ingestion/cursor/enrich-roots.js.map +1 -0
  109. package/dist/src/ingestion/cursor/vscdb-reader.d.ts +32 -0
  110. package/dist/src/ingestion/cursor/vscdb-reader.d.ts.map +1 -0
  111. package/dist/src/ingestion/cursor/vscdb-reader.js +113 -0
  112. package/dist/src/ingestion/cursor/vscdb-reader.js.map +1 -0
  113. package/dist/src/ingestion/cursor/workspace-root.d.ts +96 -0
  114. package/dist/src/ingestion/cursor/workspace-root.d.ts.map +1 -0
  115. package/dist/src/ingestion/cursor/workspace-root.js +187 -0
  116. package/dist/src/ingestion/cursor/workspace-root.js.map +1 -0
  117. package/dist/src/ingestion/indexer.d.ts.map +1 -1
  118. package/dist/src/ingestion/indexer.js +41 -32
  119. package/dist/src/ingestion/indexer.js.map +1 -1
  120. package/dist/src/jobs/handlers/compact.d.ts.map +1 -1
  121. package/dist/src/jobs/handlers/compact.js +9 -4
  122. package/dist/src/jobs/handlers/compact.js.map +1 -1
  123. package/dist/src/jobs/handlers/ingest.d.ts.map +1 -1
  124. package/dist/src/jobs/handlers/ingest.js +60 -30
  125. package/dist/src/jobs/handlers/ingest.js.map +1 -1
  126. package/dist/src/jobs/handlers/reconcile.d.ts.map +1 -1
  127. package/dist/src/jobs/handlers/reconcile.js +128 -45
  128. package/dist/src/jobs/handlers/reconcile.js.map +1 -1
  129. package/dist/src/jobs/handlers/save.d.ts.map +1 -1
  130. package/dist/src/jobs/handlers/save.js +122 -72
  131. package/dist/src/jobs/handlers/save.js.map +1 -1
  132. package/dist/src/jobs/types.d.ts +1 -1
  133. package/dist/src/main.js +26 -15
  134. package/dist/src/main.js.map +1 -1
  135. package/dist/src/mcp/server.d.ts.map +1 -1
  136. package/dist/src/mcp/server.js +10 -3
  137. package/dist/src/mcp/server.js.map +1 -1
  138. package/dist/src/mcp/tools/context-pack.d.ts.map +1 -1
  139. package/dist/src/mcp/tools/context-pack.js +7 -1
  140. package/dist/src/mcp/tools/context-pack.js.map +1 -1
  141. package/dist/src/mcp/tools/conversations-search.d.ts +1 -1
  142. package/dist/src/mcp/tools/conversations-search.d.ts.map +1 -1
  143. package/dist/src/mcp/tools/conversations-search.js +7 -1
  144. package/dist/src/mcp/tools/conversations-search.js.map +1 -1
  145. package/dist/src/mcp/tools/evidence-feedback.d.ts +60 -0
  146. package/dist/src/mcp/tools/evidence-feedback.d.ts.map +1 -0
  147. package/dist/src/mcp/tools/evidence-feedback.js +62 -0
  148. package/dist/src/mcp/tools/evidence-feedback.js.map +1 -0
  149. package/dist/src/mcp/tools/log-outcome.d.ts +72 -0
  150. package/dist/src/mcp/tools/log-outcome.d.ts.map +1 -0
  151. package/dist/src/mcp/tools/log-outcome.js +59 -0
  152. package/dist/src/mcp/tools/log-outcome.js.map +1 -0
  153. package/dist/src/mcp/tools/open-evidence.d.ts +37 -0
  154. package/dist/src/mcp/tools/open-evidence.d.ts.map +1 -0
  155. package/dist/src/mcp/tools/open-evidence.js +72 -0
  156. package/dist/src/mcp/tools/open-evidence.js.map +1 -0
  157. package/dist/src/mcp/tools/save.d.ts +7 -2
  158. package/dist/src/mcp/tools/save.d.ts.map +1 -1
  159. package/dist/src/mcp/tools/save.js +7 -2
  160. package/dist/src/mcp/tools/save.js.map +1 -1
  161. package/dist/src/mcp/tools/search.d.ts.map +1 -1
  162. package/dist/src/mcp/tools/search.js +7 -1
  163. package/dist/src/mcp/tools/search.js.map +1 -1
  164. package/dist/src/observability/retrieval-feedback.d.ts +82 -0
  165. package/dist/src/observability/retrieval-feedback.d.ts.map +1 -0
  166. package/dist/src/observability/retrieval-feedback.js +231 -0
  167. package/dist/src/observability/retrieval-feedback.js.map +1 -0
  168. package/dist/src/observability/rift-context.d.ts.map +1 -1
  169. package/dist/src/observability/rift-context.js +3 -0
  170. package/dist/src/observability/rift-context.js.map +1 -1
  171. package/dist/src/observability/tool-usage-stats.d.ts +13 -0
  172. package/dist/src/observability/tool-usage-stats.d.ts.map +1 -1
  173. package/dist/src/observability/tool-usage-stats.js +15 -0
  174. package/dist/src/observability/tool-usage-stats.js.map +1 -1
  175. package/dist/src/observability/tool-usage.d.ts +56 -0
  176. package/dist/src/observability/tool-usage.d.ts.map +1 -1
  177. package/dist/src/observability/tool-usage.js +86 -0
  178. package/dist/src/observability/tool-usage.js.map +1 -1
  179. package/dist/src/providers/claude-cli-metadata-extraction.d.ts +47 -0
  180. package/dist/src/providers/claude-cli-metadata-extraction.d.ts.map +1 -0
  181. package/dist/src/providers/claude-cli-metadata-extraction.js +120 -0
  182. package/dist/src/providers/claude-cli-metadata-extraction.js.map +1 -0
  183. package/dist/src/providers/claude-cli-runner.d.ts +92 -0
  184. package/dist/src/providers/claude-cli-runner.d.ts.map +1 -0
  185. package/dist/src/providers/claude-cli-runner.js +598 -0
  186. package/dist/src/providers/claude-cli-runner.js.map +1 -0
  187. package/dist/src/providers/codex-cli-metadata-extraction.d.ts.map +1 -1
  188. package/dist/src/providers/codex-cli-metadata-extraction.js +1 -40
  189. package/dist/src/providers/codex-cli-metadata-extraction.js.map +1 -1
  190. package/dist/src/providers/codex-cli-runner.d.ts +7 -0
  191. package/dist/src/providers/codex-cli-runner.d.ts.map +1 -1
  192. package/dist/src/providers/codex-cli-runner.js +131 -5
  193. package/dist/src/providers/codex-cli-runner.js.map +1 -1
  194. package/dist/src/providers/conversation-generation.d.ts +10 -0
  195. package/dist/src/providers/conversation-generation.d.ts.map +1 -1
  196. package/dist/src/providers/conversation-generation.js +54 -13
  197. package/dist/src/providers/conversation-generation.js.map +1 -1
  198. package/dist/src/providers/openai-metadata-extraction.d.ts +48 -1
  199. package/dist/src/providers/openai-metadata-extraction.d.ts.map +1 -1
  200. package/dist/src/providers/openai-metadata-extraction.js +51 -2
  201. package/dist/src/providers/openai-metadata-extraction.js.map +1 -1
  202. package/dist/src/providers/types.d.ts +1 -1
  203. package/dist/src/providers/types.d.ts.map +1 -1
  204. package/dist/src/providers/types.js +4 -0
  205. package/dist/src/providers/types.js.map +1 -1
  206. package/dist/src/retrieval/compact.d.ts +81 -0
  207. package/dist/src/retrieval/compact.d.ts.map +1 -1
  208. package/dist/src/retrieval/compact.js +248 -8
  209. package/dist/src/retrieval/compact.js.map +1 -1
  210. package/dist/src/retrieval/context-pack.d.ts.map +1 -1
  211. package/dist/src/retrieval/context-pack.js +28 -14
  212. package/dist/src/retrieval/context-pack.js.map +1 -1
  213. package/dist/src/retrieval/evidence-key.d.ts +48 -0
  214. package/dist/src/retrieval/evidence-key.d.ts.map +1 -0
  215. package/dist/src/retrieval/evidence-key.js +131 -0
  216. package/dist/src/retrieval/evidence-key.js.map +1 -0
  217. package/dist/src/retrieval/group-by-parent.d.ts +38 -0
  218. package/dist/src/retrieval/group-by-parent.d.ts.map +1 -0
  219. package/dist/src/retrieval/group-by-parent.js +40 -0
  220. package/dist/src/retrieval/group-by-parent.js.map +1 -0
  221. package/dist/src/retrieval/lexical.d.ts.map +1 -1
  222. package/dist/src/retrieval/lexical.js +1 -3
  223. package/dist/src/retrieval/lexical.js.map +1 -1
  224. package/dist/src/retrieval/receipt.d.ts +57 -0
  225. package/dist/src/retrieval/receipt.d.ts.map +1 -0
  226. package/dist/src/retrieval/receipt.js +119 -0
  227. package/dist/src/retrieval/receipt.js.map +1 -0
  228. package/dist/src/retrieval/reranker.d.ts +12 -2
  229. package/dist/src/retrieval/reranker.d.ts.map +1 -1
  230. package/dist/src/retrieval/reranker.js +11 -4
  231. package/dist/src/retrieval/reranker.js.map +1 -1
  232. package/dist/src/retrieval/stitch-chunks.d.ts +73 -0
  233. package/dist/src/retrieval/stitch-chunks.d.ts.map +1 -0
  234. package/dist/src/retrieval/stitch-chunks.js +106 -0
  235. package/dist/src/retrieval/stitch-chunks.js.map +1 -0
  236. package/dist/src/server/app.d.ts.map +1 -1
  237. package/dist/src/server/app.js +17 -1
  238. package/dist/src/server/app.js.map +1 -1
  239. package/dist/src/server/routes/conversations-search.d.ts.map +1 -1
  240. package/dist/src/server/routes/conversations-search.js +12 -3
  241. package/dist/src/server/routes/conversations-search.js.map +1 -1
  242. package/dist/src/server/routes/friend-status.d.ts +44 -5
  243. package/dist/src/server/routes/friend-status.d.ts.map +1 -1
  244. package/dist/src/server/routes/friend-status.js +74 -6
  245. package/dist/src/server/routes/friend-status.js.map +1 -1
  246. package/dist/src/server/routes/mcp-usage.d.ts +9 -6
  247. package/dist/src/server/routes/mcp-usage.d.ts.map +1 -1
  248. package/dist/src/server/routes/mcp-usage.js.map +1 -1
  249. package/dist/src/server/routes/retrieval-feedback.d.ts +3 -0
  250. package/dist/src/server/routes/retrieval-feedback.d.ts.map +1 -0
  251. package/dist/src/server/routes/retrieval-feedback.js +290 -0
  252. package/dist/src/server/routes/retrieval-feedback.js.map +1 -0
  253. package/dist/src/server/routes/save.d.ts +3 -3
  254. package/dist/src/server/routes/save.d.ts.map +1 -1
  255. package/dist/src/server/routes/save.js +6 -2
  256. package/dist/src/server/routes/save.js.map +1 -1
  257. package/dist/src/server/routes/search.d.ts.map +1 -1
  258. package/dist/src/server/routes/search.js +19 -7
  259. package/dist/src/server/routes/search.js.map +1 -1
  260. package/dist/src/server/serving-marker.d.ts +85 -0
  261. package/dist/src/server/serving-marker.d.ts.map +1 -0
  262. package/dist/src/server/serving-marker.js +226 -0
  263. package/dist/src/server/serving-marker.js.map +1 -0
  264. package/dist/src/storage/chunk-backfill.d.ts +39 -0
  265. package/dist/src/storage/chunk-backfill.d.ts.map +1 -0
  266. package/dist/src/storage/chunk-backfill.js +295 -0
  267. package/dist/src/storage/chunk-backfill.js.map +1 -0
  268. package/dist/src/storage/filter.d.ts +42 -0
  269. package/dist/src/storage/filter.d.ts.map +1 -0
  270. package/dist/src/storage/filter.js +70 -0
  271. package/dist/src/storage/filter.js.map +1 -0
  272. package/dist/src/storage/rebuild.d.ts.map +1 -1
  273. package/dist/src/storage/rebuild.js +44 -27
  274. package/dist/src/storage/rebuild.js.map +1 -1
  275. package/dist/src/storage/tables.d.ts +41 -0
  276. package/dist/src/storage/tables.d.ts.map +1 -1
  277. package/dist/src/storage/tables.js +64 -1
  278. package/dist/src/storage/tables.js.map +1 -1
  279. package/operator/swiftbar/render-menu.py +57 -15
  280. package/package.json +5 -3
@@ -0,0 +1,114 @@
1
+ export const CHUNK_THRESHOLD_CHARS = 2400;
2
+ /**
3
+ * Whether index-time chunking is enabled. Single env flag `RIFT_CHUNKING`
4
+ * (default OFF), read at call time so tests can toggle it. With it OFF, every
5
+ * write path emits a single row with no chunk markers — byte-for-byte the
6
+ * pre-chunking behavior.
7
+ */
8
+ export function chunkingEnabled(env = process.env) {
9
+ return env["RIFT_CHUNKING"] === "1";
10
+ }
11
+ export const DEFAULT_CHUNK_OPTIONS = {
12
+ targetChars: 1800,
13
+ overlapChars: 216,
14
+ minChars: 400,
15
+ maxChars: 3600,
16
+ thresholdChars: CHUNK_THRESHOLD_CHARS,
17
+ };
18
+ const PARAGRAPH_SEP = "\n\n";
19
+ /** Split a document into overlapping chunks at paragraph boundaries. */
20
+ export function chunkText(content, options = {}) {
21
+ const opts = { ...DEFAULT_CHUNK_OPTIONS, ...options };
22
+ if (content.trim().length === 0)
23
+ return [];
24
+ if (content.length <= opts.thresholdChars)
25
+ return [content];
26
+ const units = splitParagraphs(content, opts.maxChars);
27
+ return packUnits(units, opts);
28
+ }
29
+ /** Split a conversation into overlapping chunks, preferring turn boundaries. */
30
+ export function chunkConversation(content, options = {}) {
31
+ const opts = { ...DEFAULT_CHUNK_OPTIONS, ...options };
32
+ if (content.trim().length === 0)
33
+ return [];
34
+ if (content.length <= opts.thresholdChars)
35
+ return [content];
36
+ const turns = content
37
+ .split(/\n\n(?=(?:User|Assistant): )/)
38
+ .filter((s) => s.trim().length > 0);
39
+ if (turns.length <= 1)
40
+ return chunkText(content, options);
41
+ const units = turns.flatMap((t) => t.length <= opts.maxChars ? [t] : hardWindow(t, opts.maxChars));
42
+ return packUnits(units, opts);
43
+ }
44
+ /**
45
+ * Greedily pack pre-split units into chunks near `targetChars`, seeding each new
46
+ * chunk with an overlap tail of the previous one. A too-small trailing chunk is
47
+ * merged back so we never emit a sliver.
48
+ */
49
+ function packUnits(units, opts) {
50
+ const chunks = [];
51
+ let cur = "";
52
+ for (const unit of units) {
53
+ if (cur === "") {
54
+ cur = unit;
55
+ continue;
56
+ }
57
+ if (cur.length + PARAGRAPH_SEP.length + unit.length <= opts.targetChars) {
58
+ cur = `${cur}${PARAGRAPH_SEP}${unit}`;
59
+ }
60
+ else {
61
+ chunks.push(cur);
62
+ const tail = overlapTail(cur, opts.overlapChars);
63
+ cur = tail ? `${tail}${PARAGRAPH_SEP}${unit}` : unit;
64
+ }
65
+ }
66
+ if (cur)
67
+ chunks.push(cur);
68
+ // Merge a tiny trailing chunk into its predecessor.
69
+ if (chunks.length >= 2 &&
70
+ chunks[chunks.length - 1].length < opts.minChars) {
71
+ const last = chunks.pop();
72
+ chunks[chunks.length - 1] = `${chunks[chunks.length - 1]}${PARAGRAPH_SEP}${last}`;
73
+ }
74
+ return chunks;
75
+ }
76
+ /** Split into paragraphs; hard-window any paragraph larger than `maxChars`. */
77
+ function splitParagraphs(text, maxChars) {
78
+ const out = [];
79
+ for (const para of text.split(/\n{2,}/)) {
80
+ if (para.trim().length === 0)
81
+ continue;
82
+ if (para.length <= maxChars)
83
+ out.push(para);
84
+ else
85
+ out.push(...hardWindow(para, maxChars));
86
+ }
87
+ return out;
88
+ }
89
+ /** Hard-split an oversized string into <= maxChars pieces at word boundaries. */
90
+ function hardWindow(text, maxChars) {
91
+ const out = [];
92
+ let rest = text;
93
+ while (rest.length > maxChars) {
94
+ let cut = rest.lastIndexOf(" ", maxChars);
95
+ if (cut <= 0)
96
+ cut = maxChars; // no space — hard cut
97
+ out.push(rest.slice(0, cut));
98
+ rest = rest.slice(cut).replace(/^\s+/, "");
99
+ }
100
+ if (rest.length > 0)
101
+ out.push(rest);
102
+ return out;
103
+ }
104
+ /** Last ~overlap chars of `text`, snapped forward to a word boundary. */
105
+ function overlapTail(text, overlap) {
106
+ if (overlap <= 0 || text.length <= overlap)
107
+ return text.length <= overlap ? text : "";
108
+ let slice = text.slice(text.length - overlap);
109
+ const sp = slice.indexOf(" ");
110
+ if (sp > 0 && sp < slice.length - 1)
111
+ slice = slice.slice(sp + 1);
112
+ return slice;
113
+ }
114
+ //# sourceMappingURL=chunk-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-text.js","sourceRoot":"","sources":["../../../src/ingestion/chunk-text.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Cursor native composer/chat store — read-only discovery layer.
3
+ *
4
+ * DISCOVERY SLICE ONLY. This module interprets the raw key/value rows that
5
+ * Cursor (an Electron/VS Code fork by Anysphere) persists in its SQLite
6
+ * `state.vscdb` files. It does NOT read those files itself — see
7
+ * `vscdb-reader.ts` for the I/O adapter — and it does NOT write anything to
8
+ * LanceDB, the daemon, or capture state. Keeping the interpretation pure makes
9
+ * it exhaustively unit-testable from synthetic fixtures with no DB or binary.
10
+ *
11
+ * What lives in Cursor's vscdb (empirically verified on macOS, Cursor "glass"
12
+ * build, 2026-06):
13
+ * - ItemTable['composer.composerHeaders'] -> { allComposers: ComposerHeader[] }
14
+ * The session index: one entry per composer/chat session.
15
+ * - cursorDiskKV['composerData:{composerId}'] -> CursorComposerData
16
+ * Per-session metadata incl. modelConfig + ordered bubble header list.
17
+ * - cursorDiskKV['bubbleId:{composerId}:{bubbleId}'] -> CursorBubble
18
+ * One conversation turn. type 1 = user, type 2 = assistant.
19
+ *
20
+ * CRITICAL SCOPE NOTE — the three requested "modes":
21
+ * 1. Claude Code used *through* Cursor -> NOT here. The `claude` CLI writes
22
+ * to ~/.claude/projects/**.jsonl regardless of which terminal launched it.
23
+ * Already covered by claude-code-jsonl.ts.
24
+ * 2. Codex used *through* Cursor -> NOT here. Same story: ~/.codex.
25
+ * Already covered by codex-jsonl.ts.
26
+ * 3. Cursor *native* composer/agent/chat -> THIS module. The only AI sessions
27
+ * that actually live in Cursor's vscdb.
28
+ * So this store owns exactly mode 3. Modes 1/2 are a provenance-tagging concern
29
+ * on the existing CLI parsers, not a new store. See docs/cursor-capture-discovery.md.
30
+ */
31
+ import type { ParsedConversation } from "../parsers/types.js";
32
+ import { type ProjectRootResolution } from "./workspace-root.js";
33
+ /** A single key/value row, value still a raw JSON string (BLOB/TEXT). */
34
+ export interface CursorKvRow {
35
+ key: string;
36
+ value: string;
37
+ }
38
+ /**
39
+ * The minimal raw input the discovery layer needs. The reader pulls only these
40
+ * two namespaces and deliberately never selects `cursorAuth/*` (tokens) or
41
+ * `secret://*` (MCP OAuth secrets).
42
+ */
43
+ export interface CursorRawRows {
44
+ /** Rows from the `ItemTable` table. */
45
+ itemTable: CursorKvRow[];
46
+ /** Rows from the `cursorDiskKV` table. */
47
+ cursorDiskKV: CursorKvRow[];
48
+ }
49
+ /** Coarse classification of a native Cursor session by selected model. */
50
+ export type CursorBackend = "cursor_native" | "anthropic" | "openai" | "google" | "default" | "unknown";
51
+ /**
52
+ * A discovered native Cursor session. Metadata only — by design this carries NO
53
+ * message text so discovery can run without ever touching private content.
54
+ */
55
+ export interface CursorSessionCandidate {
56
+ /** Stable session id = Cursor's composerId (a UUID). */
57
+ composerId: string;
58
+ /** User-given session name, if any (semantically a title; may be private). */
59
+ name: string | null;
60
+ /** "agent" | "chat" | other; null if absent. */
61
+ mode: string | null;
62
+ /** Cursor's own model label, e.g. "composer-2.5" or "default". */
63
+ modelName: string | null;
64
+ /** Coarse backend inferred from {@link modelName}. */
65
+ backend: CursorBackend;
66
+ /** Workspace identifier from the header (folder window id or "empty-window"). */
67
+ workspaceId: string | null;
68
+ /**
69
+ * Resolved filesystem project root, or null when not attributable (empty
70
+ * window, multi-root, remote, or unresolved). Resolved here from the inline
71
+ * header uri only (no fs); the probe upgrades legacy `unresolved` rows via the
72
+ * on-disk workspace.json join. See {@link projectRootStatus}.
73
+ */
74
+ projectRoot: string | null;
75
+ /** Which link produced {@link projectRoot}, or null when unresolved. */
76
+ projectRootSource: "header_uri" | "workspace_json" | null;
77
+ /** First-class resolution outcome — capture scopes to a root ONLY on "resolved". */
78
+ projectRootStatus: ProjectRootResolution["status"];
79
+ /** ISO 8601 creation time (from epoch ms), or null if unknown. */
80
+ createdAt: string | null;
81
+ /** ISO 8601 last-update time (from epoch ms), or null if unknown. */
82
+ updatedAt: string | null;
83
+ /** Number of conversation turns (bubbles) referenced by the session. */
84
+ turnCount: number;
85
+ /** True if Cursor flagged this as an unsent draft (skip on capture). */
86
+ isDraft: boolean;
87
+ /** True when a composerData body row exists for this id (parseable later). */
88
+ hasBody: boolean;
89
+ }
90
+ /** Proposed provenance row for the future capture slice (NOT persisted here). */
91
+ export interface ProposedCursorProvenance {
92
+ /** New ConversationSource variant proposed for native Cursor sessions. */
93
+ source: "cursor_composer";
94
+ /** Originating application, distinguishes from web/CLI captures. */
95
+ source_app: "cursor";
96
+ /** Stable upstream id. */
97
+ source_session_id: string;
98
+ /** Stable idempotency key — see {@link cursorSessionKey}. */
99
+ idempotency_key: string;
100
+ /** Cursor workspace id (workspaceStorage hash or "empty-window"). */
101
+ workspace_id: string | null;
102
+ /** Resolved filesystem project root, or null when not attributable. */
103
+ project_root: string | null;
104
+ /** Provenance of {@link project_root}: which link resolved it (or null). */
105
+ project_root_source: "header_uri" | "workspace_json" | null;
106
+ /** Model label as recorded by Cursor. */
107
+ model_name: string | null;
108
+ backend: CursorBackend;
109
+ mode: string | null;
110
+ created_at: string | null;
111
+ updated_at: string | null;
112
+ }
113
+ /**
114
+ * Map a Cursor model label to a coarse backend. Cursor records its OWN labels
115
+ * (e.g. "composer-2.5"), not raw provider ids, and very often "default" (the
116
+ * account-level pick), which is NOT resolvable from local artifacts. This is a
117
+ * best-effort heuristic — see "Unknowns" in the discovery doc.
118
+ */
119
+ export declare function classifyBackend(modelName: string | null | undefined): CursorBackend;
120
+ /**
121
+ * Stable, deterministic session key for idempotent capture. composerId is a
122
+ * UUID minted once per session by Cursor and never reused, so it is the natural
123
+ * idempotency anchor. Prefixed by source so it can't collide with CLI keys.
124
+ *
125
+ * Change detection across re-captures is a SEPARATE concern: pair this key with
126
+ * a content fingerprint (see {@link cursorConversationFingerprintInput}) and the
127
+ * session's lastUpdatedAt, exactly as the CLI lanes do. Designing this now
128
+ * satisfies the "stable key before any scheduled capture" requirement.
129
+ */
130
+ export declare function cursorSessionKey(composerId: string): string;
131
+ /**
132
+ * Discover native Cursor composer/chat sessions from raw vscdb rows.
133
+ *
134
+ * Pure and side-effect free. Uses ONLY the session index + per-session metadata
135
+ * rows — never bubble bodies — so discovery reveals no private message text.
136
+ * Sessions are returned newest-updated first.
137
+ */
138
+ export declare function discoverCursorComposerSessions(raw: CursorRawRows): CursorSessionCandidate[];
139
+ /** Build the proposed provenance row for a candidate (design artifact only). */
140
+ export declare function proposeCursorProvenance(candidate: CursorSessionCandidate): ProposedCursorProvenance;
141
+ /** One ordered conversation turn as stored, before any role/prose filtering. */
142
+ export interface CursorOrderedBubble {
143
+ bubbleId: string;
144
+ /** Raw bubble type (1 = user, 2 = assistant, other = tool/system). */
145
+ type: number;
146
+ /** Raw bubble text (may be empty for tool-only/assistant bubbles). */
147
+ text: string;
148
+ }
149
+ /**
150
+ * Collect a session's bubbles in conversation order. Order comes from the
151
+ * session body's `fullConversationHeadersOnly` when present; otherwise we fall
152
+ * back to whatever bubble rows exist for this composer, in key order. Returns
153
+ * EVERY referenced bubble (including empty/tool-only ones) so callers — notably
154
+ * the fingerprint — can see structural changes that carry no prose.
155
+ */
156
+ export declare function collectOrderedBubbles(raw: CursorRawRows, composerId: string): CursorOrderedBubble[];
157
+ /**
158
+ * Deterministic fingerprint input for a session, over the ordered
159
+ * `(bubbleId, type, text)` of every turn. This is the change-detection contract
160
+ * the capture slice will hash (NOT hashed here — the hashing util stays in one
161
+ * place): re-running on an unchanged session yields an identical string, while
162
+ * an edited/added/removed turn — including a tool-only turn that carries no
163
+ * prose — changes it. Requires bubble bodies to be present in `raw`.
164
+ */
165
+ export declare function cursorConversationFingerprintInput(raw: CursorRawRows, composerId: string): string;
166
+ /**
167
+ * Full parse of a single native Cursor session into the shared
168
+ * {@link ParsedConversation} contract. Requires the session's bubble bodies to
169
+ * be present in `raw.cursorDiskKV` (the reader only fetches these on explicit,
170
+ * privacy-acknowledged opt-in). Returns null when no user/assistant turns with
171
+ * text exist.
172
+ *
173
+ * Provided for the FUTURE capture slice and for round-trip tests; the discovery
174
+ * probe does not call it by default.
175
+ */
176
+ export declare function parseCursorComposerSession(raw: CursorRawRows, composerId: string): ParsedConversation | null;
177
+ //# sourceMappingURL=cursor-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-store.d.ts","sourceRoot":"","sources":["../../../../src/ingestion/cursor/cursor-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,243 @@
1
+ import { resolveProjectRoot, } from "./workspace-root.js";
2
+ const ITEM_KEY_COMPOSER_HEADERS = "composer.composerHeaders";
3
+ const KV_PREFIX_COMPOSER_DATA = "composerData:";
4
+ const KV_PREFIX_BUBBLE = "bubbleId:";
5
+ const BUBBLE_TYPE_USER = 1;
6
+ const BUBBLE_TYPE_ASSISTANT = 2;
7
+ function safeJsonParse(value) {
8
+ try {
9
+ return JSON.parse(value);
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ }
15
+ function indexByKey(rows) {
16
+ const map = new Map();
17
+ for (const row of rows)
18
+ map.set(row.key, row.value);
19
+ return map;
20
+ }
21
+ function epochMsToIso(ms) {
22
+ if (typeof ms !== "number" || !Number.isFinite(ms) || ms <= 0)
23
+ return null;
24
+ return new Date(ms).toISOString();
25
+ }
26
+ /**
27
+ * Map a Cursor model label to a coarse backend. Cursor records its OWN labels
28
+ * (e.g. "composer-2.5"), not raw provider ids, and very often "default" (the
29
+ * account-level pick), which is NOT resolvable from local artifacts. This is a
30
+ * best-effort heuristic — see "Unknowns" in the discovery doc.
31
+ */
32
+ export function classifyBackend(modelName) {
33
+ if (!modelName)
34
+ return "unknown";
35
+ const m = modelName.toLowerCase();
36
+ if (m === "default" || m === "auto")
37
+ return "default";
38
+ if (m.startsWith("composer") || m.startsWith("cursor"))
39
+ return "cursor_native";
40
+ if (m.includes("claude") || m.includes("sonnet") || m.includes("opus") || m.includes("haiku")) {
41
+ return "anthropic";
42
+ }
43
+ if (m.startsWith("gpt") || /^o\d/.test(m) || m.includes("openai") || m.includes("chatgpt")) {
44
+ return "openai";
45
+ }
46
+ if (m.includes("gemini"))
47
+ return "google";
48
+ return "unknown";
49
+ }
50
+ /**
51
+ * Stable, deterministic session key for idempotent capture. composerId is a
52
+ * UUID minted once per session by Cursor and never reused, so it is the natural
53
+ * idempotency anchor. Prefixed by source so it can't collide with CLI keys.
54
+ *
55
+ * Change detection across re-captures is a SEPARATE concern: pair this key with
56
+ * a content fingerprint (see {@link cursorConversationFingerprintInput}) and the
57
+ * session's lastUpdatedAt, exactly as the CLI lanes do. Designing this now
58
+ * satisfies the "stable key before any scheduled capture" requirement.
59
+ */
60
+ export function cursorSessionKey(composerId) {
61
+ return `cursor_composer:${composerId}`;
62
+ }
63
+ /**
64
+ * Discover native Cursor composer/chat sessions from raw vscdb rows.
65
+ *
66
+ * Pure and side-effect free. Uses ONLY the session index + per-session metadata
67
+ * rows — never bubble bodies — so discovery reveals no private message text.
68
+ * Sessions are returned newest-updated first.
69
+ */
70
+ export function discoverCursorComposerSessions(raw) {
71
+ const items = indexByKey(raw.itemTable);
72
+ const headersRaw = items.get(ITEM_KEY_COMPOSER_HEADERS);
73
+ const index = headersRaw
74
+ ? safeJsonParse(headersRaw)
75
+ : null;
76
+ // Body rows, indexed by composerId, give us authoritative model + turn count.
77
+ const bodyById = new Map();
78
+ for (const row of raw.cursorDiskKV) {
79
+ if (!row.key.startsWith(KV_PREFIX_COMPOSER_DATA))
80
+ continue;
81
+ const body = safeJsonParse(row.value);
82
+ if (!body)
83
+ continue;
84
+ const id = body.composerId ?? row.key.slice(KV_PREFIX_COMPOSER_DATA.length);
85
+ if (id)
86
+ bodyById.set(id, body);
87
+ }
88
+ // Prefer the header index as the session roster (it is the UI source of
89
+ // truth); fall back to body rows if the index is missing/corrupt.
90
+ const headers = index?.allComposers ?? [];
91
+ const seen = new Set();
92
+ const candidates = [];
93
+ const pushCandidate = (composerId, header, body) => {
94
+ if (!composerId || seen.has(composerId))
95
+ return;
96
+ seen.add(composerId);
97
+ const modelName = body?.modelConfig?.modelName ?? null;
98
+ const created = header?.createdAt ?? body?.createdAt;
99
+ const updated = header?.lastUpdatedAt ?? body?.lastUpdatedAt;
100
+ // Pure (inline-uri-only) resolution — discovery never touches the fs. The
101
+ // probe upgrades any legacy `unresolved` row via the workspace.json join.
102
+ const resolution = resolveProjectRoot(header?.workspaceIdentifier);
103
+ candidates.push({
104
+ composerId,
105
+ name: header?.name ?? body?.name ?? null,
106
+ mode: header?.unifiedMode ?? body?.unifiedMode ?? null,
107
+ modelName,
108
+ backend: classifyBackend(modelName),
109
+ workspaceId: header?.workspaceIdentifier?.id ?? null,
110
+ projectRoot: resolution.status === "resolved" ? resolution.root : null,
111
+ projectRootSource: resolution.status === "resolved" ? resolution.source : null,
112
+ projectRootStatus: resolution.status,
113
+ createdAt: epochMsToIso(created),
114
+ updatedAt: epochMsToIso(updated),
115
+ turnCount: body?.fullConversationHeadersOnly?.length ?? 0,
116
+ isDraft: header?.isDraft === true,
117
+ hasBody: body !== undefined,
118
+ });
119
+ };
120
+ for (const header of headers) {
121
+ if (!header?.composerId)
122
+ continue;
123
+ pushCandidate(header.composerId, header, bodyById.get(header.composerId));
124
+ }
125
+ // Bodies present but absent from the index (orphans) still get surfaced.
126
+ for (const [composerId, body] of bodyById) {
127
+ pushCandidate(composerId, undefined, body);
128
+ }
129
+ return candidates.sort((a, b) => {
130
+ const at = a.updatedAt ?? a.createdAt ?? "";
131
+ const bt = b.updatedAt ?? b.createdAt ?? "";
132
+ return bt.localeCompare(at);
133
+ });
134
+ }
135
+ /** Build the proposed provenance row for a candidate (design artifact only). */
136
+ export function proposeCursorProvenance(candidate) {
137
+ return {
138
+ source: "cursor_composer",
139
+ source_app: "cursor",
140
+ source_session_id: candidate.composerId,
141
+ idempotency_key: cursorSessionKey(candidate.composerId),
142
+ workspace_id: candidate.workspaceId,
143
+ project_root: candidate.projectRoot,
144
+ project_root_source: candidate.projectRootSource,
145
+ model_name: candidate.modelName,
146
+ backend: candidate.backend,
147
+ mode: candidate.mode,
148
+ created_at: candidate.createdAt,
149
+ updated_at: candidate.updatedAt,
150
+ };
151
+ }
152
+ /**
153
+ * Collect a session's bubbles in conversation order. Order comes from the
154
+ * session body's `fullConversationHeadersOnly` when present; otherwise we fall
155
+ * back to whatever bubble rows exist for this composer, in key order. Returns
156
+ * EVERY referenced bubble (including empty/tool-only ones) so callers — notably
157
+ * the fingerprint — can see structural changes that carry no prose.
158
+ */
159
+ export function collectOrderedBubbles(raw, composerId) {
160
+ const kv = indexByKey(raw.cursorDiskKV);
161
+ const bodyRaw = kv.get(`${KV_PREFIX_COMPOSER_DATA}${composerId}`);
162
+ const body = bodyRaw ? safeJsonParse(bodyRaw) : null;
163
+ let order;
164
+ if (body?.fullConversationHeadersOnly?.length) {
165
+ order = body.fullConversationHeadersOnly
166
+ .map((h) => h.bubbleId)
167
+ .filter((id) => typeof id === "string");
168
+ }
169
+ else {
170
+ const prefix = `${KV_PREFIX_BUBBLE}${composerId}:`;
171
+ order = raw.cursorDiskKV
172
+ .filter((r) => r.key.startsWith(prefix))
173
+ .map((r) => r.key.slice(prefix.length))
174
+ .sort();
175
+ }
176
+ const bubbles = [];
177
+ for (const bubbleId of order) {
178
+ const bubbleRaw = kv.get(`${KV_PREFIX_BUBBLE}${composerId}:${bubbleId}`);
179
+ if (!bubbleRaw)
180
+ continue;
181
+ const bubble = safeJsonParse(bubbleRaw);
182
+ if (!bubble)
183
+ continue;
184
+ bubbles.push({
185
+ bubbleId,
186
+ type: typeof bubble.type === "number" ? bubble.type : 0,
187
+ text: bubble.text ?? "",
188
+ });
189
+ }
190
+ return bubbles;
191
+ }
192
+ /**
193
+ * Deterministic fingerprint input for a session, over the ordered
194
+ * `(bubbleId, type, text)` of every turn. This is the change-detection contract
195
+ * the capture slice will hash (NOT hashed here — the hashing util stays in one
196
+ * place): re-running on an unchanged session yields an identical string, while
197
+ * an edited/added/removed turn — including a tool-only turn that carries no
198
+ * prose — changes it. Requires bubble bodies to be present in `raw`.
199
+ */
200
+ export function cursorConversationFingerprintInput(raw, composerId) {
201
+ return collectOrderedBubbles(raw, composerId)
202
+ .map((b) => `${b.bubbleId}\t${b.type}\t${b.text}`)
203
+ .join("\n");
204
+ }
205
+ /**
206
+ * Full parse of a single native Cursor session into the shared
207
+ * {@link ParsedConversation} contract. Requires the session's bubble bodies to
208
+ * be present in `raw.cursorDiskKV` (the reader only fetches these on explicit,
209
+ * privacy-acknowledged opt-in). Returns null when no user/assistant turns with
210
+ * text exist.
211
+ *
212
+ * Provided for the FUTURE capture slice and for round-trip tests; the discovery
213
+ * probe does not call it by default.
214
+ */
215
+ export function parseCursorComposerSession(raw, composerId) {
216
+ const kv = indexByKey(raw.cursorDiskKV);
217
+ const bodyRaw = kv.get(`${KV_PREFIX_COMPOSER_DATA}${composerId}`);
218
+ const body = bodyRaw ? safeJsonParse(bodyRaw) : null;
219
+ const turns = [];
220
+ for (const bubble of collectOrderedBubbles(raw, composerId)) {
221
+ const text = bubble.text.trim();
222
+ if (!text)
223
+ continue; // tool-only / empty assistant bubbles carry no prose
224
+ if (bubble.type === BUBBLE_TYPE_USER) {
225
+ turns.push({ role: "user", text });
226
+ }
227
+ else if (bubble.type === BUBBLE_TYPE_ASSISTANT) {
228
+ turns.push({ role: "assistant", text });
229
+ }
230
+ }
231
+ if (turns.length === 0)
232
+ return null;
233
+ const content = turns
234
+ .map((t) => `${t.role === "user" ? "User" : "Assistant"}: ${t.text}`)
235
+ .join("\n\n");
236
+ const name = body?.name?.trim();
237
+ const firstUser = turns.find((t) => t.role === "user");
238
+ const rawTitle = name || firstUser?.text.slice(0, 120) || "Cursor session";
239
+ const title = rawTitle.includes("\n") ? rawTitle.split("\n")[0] : rawTitle;
240
+ const createdAt = epochMsToIso(body?.createdAt) ?? new Date(0).toISOString();
241
+ return { id: composerId, title, createdAt, content };
242
+ }
243
+ //# sourceMappingURL=cursor-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-store.js","sourceRoot":"","sources":["../../../../src/ingestion/cursor/cursor-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Shared project-root enrichment for native Cursor sessions.
3
+ *
4
+ * Pure discovery (`discoverCursorComposerSessions`) resolves a project root only
5
+ * from the inline header `uri` (current Cursor builds) and never touches the
6
+ * filesystem. Legacy builds omit that inline uri, leaving the candidate
7
+ * `unresolved`. This helper upgrades those by joining the workspace id to the
8
+ * on-disk `workspace.json` — READ-ONLY, and only for `unresolved` candidates, so
9
+ * inline-resolved rows are left untouched.
10
+ *
11
+ * Used by both `rift cursor-probe` (inspection) and the auto-capture bridge so
12
+ * the two agree on exactly which sessions are project-attributable.
13
+ */
14
+ import type { CursorSessionCandidate } from "./cursor-store.js";
15
+ export declare function enrichCursorProjectRoots(candidates: CursorSessionCandidate[], cursorDir: string): CursorSessionCandidate[];
16
+ //# sourceMappingURL=enrich-roots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrich-roots.d.ts","sourceRoot":"","sources":["../../../../src/ingestion/cursor/enrich-roots.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAGhE,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,sBAAsB,EAAE,EACpC,SAAS,EAAE,MAAM,GAChB,sBAAsB,EAAE,CAiB1B"}
@@ -0,0 +1,22 @@
1
+ import { resolveProjectRootByWorkspaceId } from "./workspace-root.js";
2
+ export function enrichCursorProjectRoots(candidates, cursorDir) {
3
+ return candidates.map((c) => {
4
+ if (c.projectRootStatus !== "unresolved" || !c.workspaceId)
5
+ return c;
6
+ const r = resolveProjectRootByWorkspaceId(cursorDir, c.workspaceId);
7
+ if (r.status === "resolved") {
8
+ return {
9
+ ...c,
10
+ projectRoot: r.root,
11
+ projectRootSource: r.source,
12
+ projectRootStatus: r.status,
13
+ };
14
+ }
15
+ // A non-`resolved`, non-`unresolved` on-disk outcome (empty_window /
16
+ // multi_root / remote) is still more informative than bare `unresolved`.
17
+ if (r.status !== "unresolved")
18
+ return { ...c, projectRootStatus: r.status };
19
+ return c;
20
+ });
21
+ }
22
+ //# sourceMappingURL=enrich-roots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrich-roots.js","sourceRoot":"","sources":["../../../../src/ingestion/cursor/enrich-roots.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,+BAA+B,EAAE,MAAM,qBAAqB,CAAC;AAEtE,MAAM,UAAU,wBAAwB,CACtC,UAAoC,EACpC,SAAiB;IAEjB,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC1B,IAAI,CAAC,CAAC,iBAAiB,KAAK,YAAY,IAAI,CAAC,CAAC,CAAC,WAAW;YAAE,OAAO,CAAC,CAAC;QACrE,MAAM,CAAC,GAAG,+BAA+B,CAAC,SAAS,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;QACpE,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC5B,OAAO;gBACL,GAAG,CAAC;gBACJ,WAAW,EAAE,CAAC,CAAC,IAAI;gBACnB,iBAAiB,EAAE,CAAC,CAAC,MAAM;gBAC3B,iBAAiB,EAAE,CAAC,CAAC,MAAM;aAC5B,CAAC;QACJ,CAAC;QACD,qEAAqE;QACrE,yEAAyE;QACzE,IAAI,CAAC,CAAC,MAAM,KAAK,YAAY;YAAE,OAAO,EAAE,GAAG,CAAC,EAAE,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;QAC5E,OAAO,CAAC,CAAC;IACX,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { CursorRawRows } from "./cursor-store.js";
2
+ /** Default macOS location of Cursor's per-user application support dir. */
3
+ export declare function defaultCursorDir(): string;
4
+ /** Global KV store path under a Cursor application-support dir. */
5
+ export declare function globalStatePath(cursorDir: string): string;
6
+ export interface CursorReadResult {
7
+ /** Absolute path of the db that was read. */
8
+ dbPath: string;
9
+ /** Raw rows for the pure discovery layer. */
10
+ rows: CursorRawRows;
11
+ }
12
+ export declare class CursorReaderError extends Error {
13
+ readonly code: "sqlite_missing" | "db_missing" | "query_failed";
14
+ constructor(message: string, code: "sqlite_missing" | "db_missing" | "query_failed");
15
+ }
16
+ export interface ReadOptions {
17
+ /** Cursor application-support dir; defaults to the standard macOS path. */
18
+ cursorDir?: string;
19
+ /**
20
+ * When true, ALSO fetch bubble bodies (`bubbleId:*`) — the actual message
21
+ * text. Off by default: discovery never needs private content. Only enable
22
+ * when the caller has acknowledged it will read prose (e.g. parse round-trip).
23
+ */
24
+ includeBubbles?: boolean;
25
+ }
26
+ /**
27
+ * Read the global Cursor state.vscdb read-only and return raw rows for the pure
28
+ * discovery layer. Throws {@link CursorReaderError} with a stable `code` for the
29
+ * three expected failure modes so callers can render friendly guidance.
30
+ */
31
+ export declare function readCursorGlobalState(options?: ReadOptions): CursorReadResult;
32
+ //# sourceMappingURL=vscdb-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vscdb-reader.d.ts","sourceRoot":"","sources":["../../../../src/ingestion/cursor/vscdb-reader.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAe,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEpE,2EAA2E;AAC3E,wBAAgB,gBAAgB,IAAI,MAAM,CAOzC;AAED,mEAAmE;AACnE,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,IAAI,EAAE,aAAa,CAAC;CACrB;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IAGxC,QAAQ,CAAC,IAAI,EACT,gBAAgB,GAChB,YAAY,GACZ,cAAc;gBAJlB,OAAO,EAAE,MAAM,EACN,IAAI,EACT,gBAAgB,GAChB,YAAY,GACZ,cAAc;CAKrB;AAmDD,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,WAAgB,GAAG,gBAAgB,CA+CjF"}