@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.
- package/README.md +7 -3
- package/dist/src/capture/auto-capture.d.ts +105 -4
- package/dist/src/capture/auto-capture.d.ts.map +1 -1
- package/dist/src/capture/auto-capture.js +313 -34
- package/dist/src/capture/auto-capture.js.map +1 -1
- package/dist/src/capture/claude-cli-triage-provider.d.ts +28 -0
- package/dist/src/capture/claude-cli-triage-provider.d.ts.map +1 -0
- package/dist/src/capture/claude-cli-triage-provider.js +88 -0
- package/dist/src/capture/claude-cli-triage-provider.js.map +1 -0
- package/dist/src/capture/codex-cli-triage-provider.d.ts.map +1 -1
- package/dist/src/capture/codex-cli-triage-provider.js +1 -33
- package/dist/src/capture/codex-cli-triage-provider.js.map +1 -1
- package/dist/src/capture/cursor-capture.d.ts +89 -0
- package/dist/src/capture/cursor-capture.d.ts.map +1 -0
- package/dist/src/capture/cursor-capture.js +121 -0
- package/dist/src/capture/cursor-capture.js.map +1 -0
- package/dist/src/capture/observability.d.ts +30 -0
- package/dist/src/capture/observability.d.ts.map +1 -1
- package/dist/src/capture/observability.js +29 -0
- package/dist/src/capture/observability.js.map +1 -1
- package/dist/src/capture/sources.d.ts +41 -3
- package/dist/src/capture/sources.d.ts.map +1 -1
- package/dist/src/capture/sources.js +43 -1
- package/dist/src/capture/sources.js.map +1 -1
- package/dist/src/capture/triage-classification.d.ts +69 -0
- package/dist/src/capture/triage-classification.d.ts.map +1 -0
- package/dist/src/capture/triage-classification.js +62 -0
- package/dist/src/capture/triage-classification.js.map +1 -0
- package/dist/src/capture/triage-provider-factory.d.ts +36 -0
- package/dist/src/capture/triage-provider-factory.d.ts.map +1 -0
- package/dist/src/capture/triage-provider-factory.js +55 -0
- package/dist/src/capture/triage-provider-factory.js.map +1 -0
- package/dist/src/capture/triage.d.ts +1 -1
- package/dist/src/capture/triage.d.ts.map +1 -1
- package/dist/src/capture/triage.js +8 -6
- package/dist/src/capture/triage.js.map +1 -1
- package/dist/src/cli/commands/capture.d.ts.map +1 -1
- package/dist/src/cli/commands/capture.js +72 -17
- package/dist/src/cli/commands/capture.js.map +1 -1
- package/dist/src/cli/commands/chunk-backfill.d.ts +13 -0
- package/dist/src/cli/commands/chunk-backfill.d.ts.map +1 -0
- package/dist/src/cli/commands/chunk-backfill.js +157 -0
- package/dist/src/cli/commands/chunk-backfill.js.map +1 -0
- package/dist/src/cli/commands/cursor-probe.d.ts +20 -0
- package/dist/src/cli/commands/cursor-probe.d.ts.map +1 -0
- package/dist/src/cli/commands/cursor-probe.js +162 -0
- package/dist/src/cli/commands/cursor-probe.js.map +1 -0
- package/dist/src/cli/commands/menubar.d.ts +50 -0
- package/dist/src/cli/commands/menubar.d.ts.map +1 -1
- package/dist/src/cli/commands/menubar.js +224 -16
- package/dist/src/cli/commands/menubar.js.map +1 -1
- package/dist/src/cli/commands/onboard.d.ts +36 -7
- package/dist/src/cli/commands/onboard.d.ts.map +1 -1
- package/dist/src/cli/commands/onboard.js +256 -53
- package/dist/src/cli/commands/onboard.js.map +1 -1
- package/dist/src/cli/commands/status.d.ts.map +1 -1
- package/dist/src/cli/commands/status.js +16 -0
- package/dist/src/cli/commands/status.js.map +1 -1
- package/dist/src/cli/commands/update.d.ts +34 -1
- package/dist/src/cli/commands/update.d.ts.map +1 -1
- package/dist/src/cli/commands/update.js +179 -2
- package/dist/src/cli/commands/update.js.map +1 -1
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +4 -0
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/postinstall-menubar.d.ts.map +1 -1
- package/dist/src/cli/postinstall-menubar.js +14 -0
- package/dist/src/cli/postinstall-menubar.js.map +1 -1
- package/dist/src/cli/status/friend-header.d.ts +18 -0
- package/dist/src/cli/status/friend-header.d.ts.map +1 -1
- package/dist/src/cli/status/friend-header.js +137 -0
- package/dist/src/cli/status/friend-header.js.map +1 -1
- package/dist/src/cli/status/local-signals.d.ts +41 -0
- package/dist/src/cli/status/local-signals.d.ts.map +1 -1
- package/dist/src/cli/status/local-signals.js +48 -0
- package/dist/src/cli/status/local-signals.js.map +1 -1
- package/dist/src/config/schema.d.ts +220 -14
- package/dist/src/config/schema.d.ts.map +1 -1
- package/dist/src/config/schema.js +82 -7
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/diagnostics/claude-preflight.d.ts +34 -0
- package/dist/src/diagnostics/claude-preflight.d.ts.map +1 -0
- package/dist/src/diagnostics/claude-preflight.js +89 -0
- package/dist/src/diagnostics/claude-preflight.js.map +1 -0
- package/dist/src/diagnostics/codex-preflight.d.ts +1 -1
- package/dist/src/diagnostics/codex-preflight.d.ts.map +1 -1
- package/dist/src/diagnostics/codex-preflight.js +14 -0
- package/dist/src/diagnostics/codex-preflight.js.map +1 -1
- package/dist/src/diagnostics/doctor.d.ts +9 -1
- package/dist/src/diagnostics/doctor.d.ts.map +1 -1
- package/dist/src/diagnostics/doctor.js +57 -2
- package/dist/src/diagnostics/doctor.js.map +1 -1
- package/dist/src/ingestion/chunk-meta.d.ts +85 -0
- package/dist/src/ingestion/chunk-meta.d.ts.map +1 -0
- package/dist/src/ingestion/chunk-meta.js +167 -0
- package/dist/src/ingestion/chunk-meta.js.map +1 -0
- package/dist/src/ingestion/chunk-text.d.ts +39 -0
- package/dist/src/ingestion/chunk-text.d.ts.map +1 -0
- package/dist/src/ingestion/chunk-text.js +114 -0
- package/dist/src/ingestion/chunk-text.js.map +1 -0
- package/dist/src/ingestion/cursor/cursor-store.d.ts +177 -0
- package/dist/src/ingestion/cursor/cursor-store.d.ts.map +1 -0
- package/dist/src/ingestion/cursor/cursor-store.js +243 -0
- package/dist/src/ingestion/cursor/cursor-store.js.map +1 -0
- package/dist/src/ingestion/cursor/enrich-roots.d.ts +16 -0
- package/dist/src/ingestion/cursor/enrich-roots.d.ts.map +1 -0
- package/dist/src/ingestion/cursor/enrich-roots.js +22 -0
- package/dist/src/ingestion/cursor/enrich-roots.js.map +1 -0
- package/dist/src/ingestion/cursor/vscdb-reader.d.ts +32 -0
- package/dist/src/ingestion/cursor/vscdb-reader.d.ts.map +1 -0
- package/dist/src/ingestion/cursor/vscdb-reader.js +113 -0
- package/dist/src/ingestion/cursor/vscdb-reader.js.map +1 -0
- package/dist/src/ingestion/cursor/workspace-root.d.ts +96 -0
- package/dist/src/ingestion/cursor/workspace-root.d.ts.map +1 -0
- package/dist/src/ingestion/cursor/workspace-root.js +187 -0
- package/dist/src/ingestion/cursor/workspace-root.js.map +1 -0
- package/dist/src/ingestion/indexer.d.ts.map +1 -1
- package/dist/src/ingestion/indexer.js +41 -32
- package/dist/src/ingestion/indexer.js.map +1 -1
- package/dist/src/jobs/handlers/compact.d.ts.map +1 -1
- package/dist/src/jobs/handlers/compact.js +9 -4
- package/dist/src/jobs/handlers/compact.js.map +1 -1
- package/dist/src/jobs/handlers/ingest.d.ts.map +1 -1
- package/dist/src/jobs/handlers/ingest.js +60 -30
- package/dist/src/jobs/handlers/ingest.js.map +1 -1
- package/dist/src/jobs/handlers/reconcile.d.ts.map +1 -1
- package/dist/src/jobs/handlers/reconcile.js +128 -45
- package/dist/src/jobs/handlers/reconcile.js.map +1 -1
- package/dist/src/jobs/handlers/save.d.ts.map +1 -1
- package/dist/src/jobs/handlers/save.js +122 -72
- package/dist/src/jobs/handlers/save.js.map +1 -1
- package/dist/src/jobs/types.d.ts +1 -1
- package/dist/src/main.js +26 -15
- package/dist/src/main.js.map +1 -1
- package/dist/src/mcp/server.d.ts.map +1 -1
- package/dist/src/mcp/server.js +10 -3
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/mcp/tools/context-pack.d.ts.map +1 -1
- package/dist/src/mcp/tools/context-pack.js +7 -1
- package/dist/src/mcp/tools/context-pack.js.map +1 -1
- package/dist/src/mcp/tools/conversations-search.d.ts +1 -1
- package/dist/src/mcp/tools/conversations-search.d.ts.map +1 -1
- package/dist/src/mcp/tools/conversations-search.js +7 -1
- package/dist/src/mcp/tools/conversations-search.js.map +1 -1
- package/dist/src/mcp/tools/evidence-feedback.d.ts +60 -0
- package/dist/src/mcp/tools/evidence-feedback.d.ts.map +1 -0
- package/dist/src/mcp/tools/evidence-feedback.js +62 -0
- package/dist/src/mcp/tools/evidence-feedback.js.map +1 -0
- package/dist/src/mcp/tools/log-outcome.d.ts +72 -0
- package/dist/src/mcp/tools/log-outcome.d.ts.map +1 -0
- package/dist/src/mcp/tools/log-outcome.js +59 -0
- package/dist/src/mcp/tools/log-outcome.js.map +1 -0
- package/dist/src/mcp/tools/open-evidence.d.ts +37 -0
- package/dist/src/mcp/tools/open-evidence.d.ts.map +1 -0
- package/dist/src/mcp/tools/open-evidence.js +72 -0
- package/dist/src/mcp/tools/open-evidence.js.map +1 -0
- package/dist/src/mcp/tools/save.d.ts +7 -2
- package/dist/src/mcp/tools/save.d.ts.map +1 -1
- package/dist/src/mcp/tools/save.js +7 -2
- package/dist/src/mcp/tools/save.js.map +1 -1
- package/dist/src/mcp/tools/search.d.ts.map +1 -1
- package/dist/src/mcp/tools/search.js +7 -1
- package/dist/src/mcp/tools/search.js.map +1 -1
- package/dist/src/observability/retrieval-feedback.d.ts +82 -0
- package/dist/src/observability/retrieval-feedback.d.ts.map +1 -0
- package/dist/src/observability/retrieval-feedback.js +231 -0
- package/dist/src/observability/retrieval-feedback.js.map +1 -0
- package/dist/src/observability/rift-context.d.ts.map +1 -1
- package/dist/src/observability/rift-context.js +3 -0
- package/dist/src/observability/rift-context.js.map +1 -1
- package/dist/src/observability/tool-usage-stats.d.ts +13 -0
- package/dist/src/observability/tool-usage-stats.d.ts.map +1 -1
- package/dist/src/observability/tool-usage-stats.js +15 -0
- package/dist/src/observability/tool-usage-stats.js.map +1 -1
- package/dist/src/observability/tool-usage.d.ts +56 -0
- package/dist/src/observability/tool-usage.d.ts.map +1 -1
- package/dist/src/observability/tool-usage.js +86 -0
- package/dist/src/observability/tool-usage.js.map +1 -1
- package/dist/src/providers/claude-cli-metadata-extraction.d.ts +47 -0
- package/dist/src/providers/claude-cli-metadata-extraction.d.ts.map +1 -0
- package/dist/src/providers/claude-cli-metadata-extraction.js +120 -0
- package/dist/src/providers/claude-cli-metadata-extraction.js.map +1 -0
- package/dist/src/providers/claude-cli-runner.d.ts +92 -0
- package/dist/src/providers/claude-cli-runner.d.ts.map +1 -0
- package/dist/src/providers/claude-cli-runner.js +598 -0
- package/dist/src/providers/claude-cli-runner.js.map +1 -0
- package/dist/src/providers/codex-cli-metadata-extraction.d.ts.map +1 -1
- package/dist/src/providers/codex-cli-metadata-extraction.js +1 -40
- package/dist/src/providers/codex-cli-metadata-extraction.js.map +1 -1
- package/dist/src/providers/codex-cli-runner.d.ts +7 -0
- package/dist/src/providers/codex-cli-runner.d.ts.map +1 -1
- package/dist/src/providers/codex-cli-runner.js +131 -5
- package/dist/src/providers/codex-cli-runner.js.map +1 -1
- package/dist/src/providers/conversation-generation.d.ts +10 -0
- package/dist/src/providers/conversation-generation.d.ts.map +1 -1
- package/dist/src/providers/conversation-generation.js +54 -13
- package/dist/src/providers/conversation-generation.js.map +1 -1
- package/dist/src/providers/openai-metadata-extraction.d.ts +48 -1
- package/dist/src/providers/openai-metadata-extraction.d.ts.map +1 -1
- package/dist/src/providers/openai-metadata-extraction.js +51 -2
- package/dist/src/providers/openai-metadata-extraction.js.map +1 -1
- package/dist/src/providers/types.d.ts +1 -1
- package/dist/src/providers/types.d.ts.map +1 -1
- package/dist/src/providers/types.js +4 -0
- package/dist/src/providers/types.js.map +1 -1
- package/dist/src/retrieval/compact.d.ts +81 -0
- package/dist/src/retrieval/compact.d.ts.map +1 -1
- package/dist/src/retrieval/compact.js +248 -8
- package/dist/src/retrieval/compact.js.map +1 -1
- package/dist/src/retrieval/context-pack.d.ts.map +1 -1
- package/dist/src/retrieval/context-pack.js +28 -14
- package/dist/src/retrieval/context-pack.js.map +1 -1
- package/dist/src/retrieval/evidence-key.d.ts +48 -0
- package/dist/src/retrieval/evidence-key.d.ts.map +1 -0
- package/dist/src/retrieval/evidence-key.js +131 -0
- package/dist/src/retrieval/evidence-key.js.map +1 -0
- package/dist/src/retrieval/group-by-parent.d.ts +38 -0
- package/dist/src/retrieval/group-by-parent.d.ts.map +1 -0
- package/dist/src/retrieval/group-by-parent.js +40 -0
- package/dist/src/retrieval/group-by-parent.js.map +1 -0
- package/dist/src/retrieval/lexical.d.ts.map +1 -1
- package/dist/src/retrieval/lexical.js +1 -3
- package/dist/src/retrieval/lexical.js.map +1 -1
- package/dist/src/retrieval/receipt.d.ts +57 -0
- package/dist/src/retrieval/receipt.d.ts.map +1 -0
- package/dist/src/retrieval/receipt.js +119 -0
- package/dist/src/retrieval/receipt.js.map +1 -0
- package/dist/src/retrieval/reranker.d.ts +12 -2
- package/dist/src/retrieval/reranker.d.ts.map +1 -1
- package/dist/src/retrieval/reranker.js +11 -4
- package/dist/src/retrieval/reranker.js.map +1 -1
- package/dist/src/retrieval/stitch-chunks.d.ts +73 -0
- package/dist/src/retrieval/stitch-chunks.d.ts.map +1 -0
- package/dist/src/retrieval/stitch-chunks.js +106 -0
- package/dist/src/retrieval/stitch-chunks.js.map +1 -0
- package/dist/src/server/app.d.ts.map +1 -1
- package/dist/src/server/app.js +17 -1
- package/dist/src/server/app.js.map +1 -1
- package/dist/src/server/routes/conversations-search.d.ts.map +1 -1
- package/dist/src/server/routes/conversations-search.js +12 -3
- package/dist/src/server/routes/conversations-search.js.map +1 -1
- package/dist/src/server/routes/friend-status.d.ts +44 -5
- package/dist/src/server/routes/friend-status.d.ts.map +1 -1
- package/dist/src/server/routes/friend-status.js +74 -6
- package/dist/src/server/routes/friend-status.js.map +1 -1
- package/dist/src/server/routes/mcp-usage.d.ts +9 -6
- package/dist/src/server/routes/mcp-usage.d.ts.map +1 -1
- package/dist/src/server/routes/mcp-usage.js.map +1 -1
- package/dist/src/server/routes/retrieval-feedback.d.ts +3 -0
- package/dist/src/server/routes/retrieval-feedback.d.ts.map +1 -0
- package/dist/src/server/routes/retrieval-feedback.js +290 -0
- package/dist/src/server/routes/retrieval-feedback.js.map +1 -0
- package/dist/src/server/routes/save.d.ts +3 -3
- package/dist/src/server/routes/save.d.ts.map +1 -1
- package/dist/src/server/routes/save.js +6 -2
- package/dist/src/server/routes/save.js.map +1 -1
- package/dist/src/server/routes/search.d.ts.map +1 -1
- package/dist/src/server/routes/search.js +19 -7
- package/dist/src/server/routes/search.js.map +1 -1
- package/dist/src/server/serving-marker.d.ts +85 -0
- package/dist/src/server/serving-marker.d.ts.map +1 -0
- package/dist/src/server/serving-marker.js +226 -0
- package/dist/src/server/serving-marker.js.map +1 -0
- package/dist/src/storage/chunk-backfill.d.ts +39 -0
- package/dist/src/storage/chunk-backfill.d.ts.map +1 -0
- package/dist/src/storage/chunk-backfill.js +295 -0
- package/dist/src/storage/chunk-backfill.js.map +1 -0
- package/dist/src/storage/filter.d.ts +42 -0
- package/dist/src/storage/filter.d.ts.map +1 -0
- package/dist/src/storage/filter.js +70 -0
- package/dist/src/storage/filter.js.map +1 -0
- package/dist/src/storage/rebuild.d.ts.map +1 -1
- package/dist/src/storage/rebuild.js +44 -27
- package/dist/src/storage/rebuild.js.map +1 -1
- package/dist/src/storage/tables.d.ts +41 -0
- package/dist/src/storage/tables.d.ts.map +1 -1
- package/dist/src/storage/tables.js +64 -1
- package/dist/src/storage/tables.js.map +1 -1
- package/operator/swiftbar/render-menu.py +57 -15
- 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":"AA+BA,OAAO,EACL,kBAAkB,GAGnB,MAAM,qBAAqB,CAAC;AAwJ7B,MAAM,yBAAyB,GAAG,0BAA0B,CAAC;AAC7D,MAAM,uBAAuB,GAAG,eAAe,CAAC;AAChD,MAAM,gBAAgB,GAAG,WAAW,CAAC;AAErC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAC3B,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAEhC,SAAS,aAAa,CAAI,KAAa;IACrC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAM,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,IAAmB;IACrC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,KAAK,MAAM,GAAG,IAAI,IAAI;QAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IACpD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,YAAY,CAAC,EAAsB;IAC1C,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3E,OAAO,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AACpC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,SAAoC;IAClE,IAAI,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IACjC,MAAM,CAAC,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;IAClC,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,MAAM;QAAE,OAAO,SAAS,CAAC;IACtD,IAAI,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,eAAe,CAAC;IAC/E,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9F,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,IAAI,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3F,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC1C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAkB;IACjD,OAAO,mBAAmB,UAAU,EAAE,CAAC;AACzC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,8BAA8B,CAC5C,GAAkB;IAElB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,UAAU;QACtB,CAAC,CAAC,aAAa,CAAuB,UAAU,CAAC;QACjD,CAAC,CAAC,IAAI,CAAC;IAET,8EAA8E;IAC9E,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA8B,CAAC;IACvD,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,YAAY,EAAE,CAAC;QACnC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,uBAAuB,CAAC;YAAE,SAAS;QAC3D,MAAM,IAAI,GAAG,aAAa,CAAqB,GAAG,CAAC,KAAK,CAAC,CAAC;QAC1D,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC;QAC5E,IAAI,EAAE;YAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;IAED,wEAAwE;IACxE,kEAAkE;IAClE,MAAM,OAAO,GAAG,KAAK,EAAE,YAAY,IAAI,EAAE,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,UAAU,GAA6B,EAAE,CAAC;IAEhD,MAAM,aAAa,GAAG,CACpB,UAAkB,EAClB,MAAkC,EAClC,IAAoC,EAC9B,EAAE;QACR,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC;YAAE,OAAO;QAChD,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAErB,MAAM,SAAS,GAAG,IAAI,EAAE,WAAW,EAAE,SAAS,IAAI,IAAI,CAAC;QACvD,MAAM,OAAO,GAAG,MAAM,EAAE,SAAS,IAAI,IAAI,EAAE,SAAS,CAAC;QACrD,MAAM,OAAO,GAAG,MAAM,EAAE,aAAa,IAAI,IAAI,EAAE,aAAa,CAAC;QAE7D,0EAA0E;QAC1E,0EAA0E;QAC1E,MAAM,UAAU,GAAG,kBAAkB,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;QAEnE,UAAU,CAAC,IAAI,CAAC;YACd,UAAU;YACV,IAAI,EAAE,MAAM,EAAE,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,IAAI;YACxC,IAAI,EAAE,MAAM,EAAE,WAAW,IAAI,IAAI,EAAE,WAAW,IAAI,IAAI;YACtD,SAAS;YACT,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC;YACnC,WAAW,EAAE,MAAM,EAAE,mBAAmB,EAAE,EAAE,IAAI,IAAI;YACpD,WAAW,EAAE,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;YACtE,iBAAiB,EACf,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;YAC7D,iBAAiB,EAAE,UAAU,CAAC,MAAM;YACpC,SAAS,EAAE,YAAY,CAAC,OAAO,CAAC;YAChC,SAAS,EAAE,YAAY,CAAC,OAAO,CAAC;YAChC,SAAS,EAAE,IAAI,EAAE,2BAA2B,EAAE,MAAM,IAAI,CAAC;YACzD,OAAO,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI;YACjC,OAAO,EAAE,IAAI,KAAK,SAAS;SAC5B,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,MAAM,EAAE,UAAU;YAAE,SAAS;QAClC,aAAa,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IAC5E,CAAC;IACD,yEAAyE;IACzE,KAAK,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;QAC1C,aAAa,CAAC,UAAU,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;IAED,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC9B,MAAM,EAAE,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC;QAC5C,MAAM,EAAE,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC;QAC5C,OAAO,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,uBAAuB,CACrC,SAAiC;IAEjC,OAAO;QACL,MAAM,EAAE,iBAAiB;QACzB,UAAU,EAAE,QAAQ;QACpB,iBAAiB,EAAE,SAAS,CAAC,UAAU;QACvC,eAAe,EAAE,gBAAgB,CAAC,SAAS,CAAC,UAAU,CAAC;QACvD,YAAY,EAAE,SAAS,CAAC,WAAW;QACnC,YAAY,EAAE,SAAS,CAAC,WAAW;QACnC,mBAAmB,EAAE,SAAS,CAAC,iBAAiB;QAChD,UAAU,EAAE,SAAS,CAAC,SAAS;QAC/B,OAAO,EAAE,SAAS,CAAC,OAAO;QAC1B,IAAI,EAAE,SAAS,CAAC,IAAI;QACpB,UAAU,EAAE,SAAS,CAAC,SAAS;QAC/B,UAAU,EAAE,SAAS,CAAC,SAAS;KAChC,CAAC;AACJ,CAAC;AAWD;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACnC,GAAkB,EAClB,UAAkB;IAElB,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,uBAAuB,GAAG,UAAU,EAAE,CAAC,CAAC;IAClE,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,aAAa,CAAqB,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEzE,IAAI,KAAe,CAAC;IACpB,IAAI,IAAI,EAAE,2BAA2B,EAAE,MAAM,EAAE,CAAC;QAC9C,KAAK,GAAG,IAAI,CAAC,2BAA2B;aACrC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;aACtB,MAAM,CAAC,CAAC,EAAE,EAAgB,EAAE,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC;IAC1D,CAAC;SAAM,CAAC;QACN,MAAM,MAAM,GAAG,GAAG,gBAAgB,GAAG,UAAU,GAAG,CAAC;QACnD,KAAK,GAAG,GAAG,CAAC,YAAY;aACrB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;aACvC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;aACtC,IAAI,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,OAAO,GAA0B,EAAE,CAAC;IAC1C,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,gBAAgB,GAAG,UAAU,IAAI,QAAQ,EAAE,CAAC,CAAC;QACzE,IAAI,CAAC,SAAS;YAAE,SAAS;QACzB,MAAM,MAAM,GAAG,aAAa,CAAe,SAAS,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM;YAAE,SAAS;QACtB,OAAO,CAAC,IAAI,CAAC;YACX,QAAQ;YACR,IAAI,EAAE,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACvD,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE;SACxB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kCAAkC,CAChD,GAAkB,EAClB,UAAkB;IAElB,OAAO,qBAAqB,CAAC,GAAG,EAAE,UAAU,CAAC;SAC1C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;SACjD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,0BAA0B,CACxC,GAAkB,EAClB,UAAkB;IAElB,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,uBAAuB,GAAG,UAAU,EAAE,CAAC,CAAC;IAClE,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,aAAa,CAAqB,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEzE,MAAM,KAAK,GAAwD,EAAE,CAAC;IACtE,KAAK,MAAM,MAAM,IAAI,qBAAqB,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI;YAAE,SAAS,CAAC,qDAAqD;QAC1E,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;YACrC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACrC,CAAC;aAAM,IAAI,MAAM,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;YACjD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpC,MAAM,OAAO,GAAG,KAAK;SAClB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;SACpE,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,MAAM,IAAI,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAChC,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,IAAI,IAAI,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,gBAAgB,CAAC;IAC3E,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC5E,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAE7E,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AACvD,CAAC"}
|
|
@@ -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"}
|