rubric-chat 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ rubric-chat rate <id> --quiet # exit code + URL only
|
|
|
37
37
|
| --- | --- | --- |
|
|
38
38
|
| **Claude Code** | `~/.claude/projects/**/*.jsonl` | ✅ |
|
|
39
39
|
| **Codex CLI** | `~/.codex/sessions/**/*.jsonl` | ✅ |
|
|
40
|
-
| **Cursor** | local SQLite (`composerData`
|
|
40
|
+
| **Cursor** | local SQLite at `~/Library/Application Support/Cursor/User/globalStorage/state.vscdb` (macOS) — verified against `composerData` / `bubbleId` schema `_v: 16` | ✅ |
|
|
41
41
|
| **Cline / Roo / Aider / Continue** | per-tool storage | ⏳ planned |
|
|
42
42
|
| **ChatGPT export** | upload `conversations.json` via `--file` | ✅ |
|
|
43
43
|
| **Claude.ai export** | upload Anthropic data export JSON via `--file` | ✅ |
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { stat } from "node:fs/promises";
|
|
2
|
+
import { homedir, platform } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { CLI_VERSION } from "../lib/config.js";
|
|
5
|
+
/**
|
|
6
|
+
* Cursor stores chat conversations in a SQLite database at the OS-specific
|
|
7
|
+
* `state.vscdb` path. The relevant table is `cursorDiskKV`, with rows shaped:
|
|
8
|
+
*
|
|
9
|
+
* key = "composerData:<composerId>"
|
|
10
|
+
* value = JSON {
|
|
11
|
+
* composerId, name, createdAt,
|
|
12
|
+
* fullConversationHeadersOnly: [{ bubbleId, type, grouping }],
|
|
13
|
+
* ...
|
|
14
|
+
* }
|
|
15
|
+
*
|
|
16
|
+
* key = "bubbleId:<composerId>:<bubbleId>"
|
|
17
|
+
* value = JSON {
|
|
18
|
+
* bubbleId, type, // type 1 = user, type 2 = assistant
|
|
19
|
+
* text, // primary content (plain)
|
|
20
|
+
* richText, // serialized rich text fallback
|
|
21
|
+
* ...
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* Verified against Cursor schema version `_v: 16` (May 2026). Defensive
|
|
25
|
+
* parsing keeps us safe across minor schema drift — unknown fields are ignored.
|
|
26
|
+
*/
|
|
27
|
+
const SKIP_COMPOSER_IDS = new Set(["empty-state-draft"]);
|
|
28
|
+
function getCursorDbPath() {
|
|
29
|
+
const plat = platform();
|
|
30
|
+
if (plat === "darwin") {
|
|
31
|
+
return join(homedir(), "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb");
|
|
32
|
+
}
|
|
33
|
+
if (plat === "linux") {
|
|
34
|
+
return join(homedir(), ".config", "Cursor", "User", "globalStorage", "state.vscdb");
|
|
35
|
+
}
|
|
36
|
+
if (plat === "win32") {
|
|
37
|
+
const appData = process.env.APPDATA ?? join(homedir(), "AppData", "Roaming");
|
|
38
|
+
return join(appData, "Cursor", "User", "globalStorage", "state.vscdb");
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
async function dbExists(path) {
|
|
43
|
+
try {
|
|
44
|
+
const s = await stat(path);
|
|
45
|
+
return s.isFile();
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function openDatabase(path) {
|
|
52
|
+
let DatabaseCtor;
|
|
53
|
+
try {
|
|
54
|
+
const mod = await import("better-sqlite3");
|
|
55
|
+
DatabaseCtor = mod.default;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
return new DatabaseCtor(path, { readonly: true, fileMustExist: true });
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function parseComposer(raw) {
|
|
68
|
+
let json;
|
|
69
|
+
try {
|
|
70
|
+
json = JSON.parse(raw);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
if (!json || typeof json !== "object")
|
|
76
|
+
return null;
|
|
77
|
+
const obj = json;
|
|
78
|
+
const composerId = typeof obj.composerId === "string" ? obj.composerId : null;
|
|
79
|
+
if (!composerId)
|
|
80
|
+
return null;
|
|
81
|
+
if (SKIP_COMPOSER_IDS.has(composerId))
|
|
82
|
+
return null;
|
|
83
|
+
const name = typeof obj.name === "string" && obj.name.trim() ? obj.name.trim() : "";
|
|
84
|
+
const createdAt = typeof obj.createdAt === "number" ? obj.createdAt : 0;
|
|
85
|
+
const rawHeaders = Array.isArray(obj.fullConversationHeadersOnly)
|
|
86
|
+
? obj.fullConversationHeadersOnly
|
|
87
|
+
: [];
|
|
88
|
+
const headers = [];
|
|
89
|
+
for (const h of rawHeaders) {
|
|
90
|
+
if (!h || typeof h !== "object")
|
|
91
|
+
continue;
|
|
92
|
+
const rec = h;
|
|
93
|
+
const bubbleId = typeof rec.bubbleId === "string" ? rec.bubbleId : "";
|
|
94
|
+
const type = typeof rec.type === "number" ? rec.type : 0;
|
|
95
|
+
if (bubbleId)
|
|
96
|
+
headers.push({ bubbleId, type });
|
|
97
|
+
}
|
|
98
|
+
return { composerId, name, createdAt, headers };
|
|
99
|
+
}
|
|
100
|
+
function parseBubble(raw) {
|
|
101
|
+
let json;
|
|
102
|
+
try {
|
|
103
|
+
json = JSON.parse(raw);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
if (!json || typeof json !== "object")
|
|
109
|
+
return null;
|
|
110
|
+
const obj = json;
|
|
111
|
+
const type = typeof obj.type === "number" ? obj.type : 0;
|
|
112
|
+
// Prefer plain text. Some bubbles store everything in richText (lexical state JSON).
|
|
113
|
+
const text = typeof obj.text === "string" && obj.text.length > 0
|
|
114
|
+
? obj.text
|
|
115
|
+
: extractRichText(obj.richText);
|
|
116
|
+
return { type, text };
|
|
117
|
+
}
|
|
118
|
+
/** Cursor's `richText` is a serialized lexical-style JSON tree. Walk it and
|
|
119
|
+
* concatenate text nodes. If parsing fails or the field isn't a string, return ""
|
|
120
|
+
* — losing rich text on a single bubble is preferable to bailing on the whole
|
|
121
|
+
* session. */
|
|
122
|
+
function extractRichText(value) {
|
|
123
|
+
if (typeof value !== "string" || !value)
|
|
124
|
+
return "";
|
|
125
|
+
let parsed;
|
|
126
|
+
try {
|
|
127
|
+
parsed = JSON.parse(value);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return "";
|
|
131
|
+
}
|
|
132
|
+
const out = [];
|
|
133
|
+
walk(parsed, out);
|
|
134
|
+
return out.join(" ").replace(/\s+/g, " ").trim();
|
|
135
|
+
function walk(node, into) {
|
|
136
|
+
if (!node)
|
|
137
|
+
return;
|
|
138
|
+
if (Array.isArray(node)) {
|
|
139
|
+
for (const child of node)
|
|
140
|
+
walk(child, into);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (typeof node !== "object")
|
|
144
|
+
return;
|
|
145
|
+
const rec = node;
|
|
146
|
+
if (typeof rec.text === "string")
|
|
147
|
+
into.push(rec.text);
|
|
148
|
+
if (Array.isArray(rec.children))
|
|
149
|
+
walk(rec.children, into);
|
|
150
|
+
if (typeof rec.root === "object")
|
|
151
|
+
walk(rec.root, into);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function summarizeAssistant(text) {
|
|
155
|
+
return {
|
|
156
|
+
response_length_chars: text.length,
|
|
157
|
+
contained_code_block: text.includes("```"),
|
|
158
|
+
contained_error: /\berror\b|\bexception\b|\bfailed\b/i.test(text),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function buildSession(composer, bubbles) {
|
|
162
|
+
const turns = [];
|
|
163
|
+
let pendingAssistantText = "";
|
|
164
|
+
for (const header of composer.headers) {
|
|
165
|
+
const bubble = bubbles.get(header.bubbleId);
|
|
166
|
+
if (!bubble)
|
|
167
|
+
continue;
|
|
168
|
+
if (bubble.type === 1) {
|
|
169
|
+
// user
|
|
170
|
+
const text = bubble.text.trim();
|
|
171
|
+
if (!text)
|
|
172
|
+
continue;
|
|
173
|
+
const turn = { index: turns.length, text };
|
|
174
|
+
if (pendingAssistantText) {
|
|
175
|
+
turn.preceded_by_assistant = summarizeAssistant(pendingAssistantText);
|
|
176
|
+
}
|
|
177
|
+
turns.push(turn);
|
|
178
|
+
pendingAssistantText = "";
|
|
179
|
+
}
|
|
180
|
+
else if (bubble.type === 2) {
|
|
181
|
+
// assistant
|
|
182
|
+
pendingAssistantText += (pendingAssistantText ? "\n" : "") + bubble.text;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
schema_version: "1.0",
|
|
187
|
+
target_tool: "cursor",
|
|
188
|
+
source_client: "cli",
|
|
189
|
+
source_client_version: CLI_VERSION,
|
|
190
|
+
ingested_at: new Date().toISOString(),
|
|
191
|
+
turns,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function readComposers(db, limit) {
|
|
195
|
+
const composerRows = db
|
|
196
|
+
.prepare("SELECT key, CAST(value AS TEXT) AS value FROM cursorDiskKV WHERE key LIKE 'composerData:%'")
|
|
197
|
+
.all();
|
|
198
|
+
const composers = [];
|
|
199
|
+
for (const row of composerRows) {
|
|
200
|
+
const meta = parseComposer(row.value);
|
|
201
|
+
if (!meta)
|
|
202
|
+
continue;
|
|
203
|
+
if (meta.headers.length === 0)
|
|
204
|
+
continue;
|
|
205
|
+
composers.push(meta);
|
|
206
|
+
}
|
|
207
|
+
composers.sort((a, b) => b.createdAt - a.createdAt);
|
|
208
|
+
const sliced = composers.slice(0, limit);
|
|
209
|
+
// Batch-fetch all bubble keys we'll need.
|
|
210
|
+
const bubbleKeys = sliced.flatMap((c) => c.headers.map((h) => `bubbleId:${c.composerId}:${h.bubbleId}`));
|
|
211
|
+
const bubbles = fetchBubbles(db, bubbleKeys);
|
|
212
|
+
const result = [];
|
|
213
|
+
for (const meta of sliced) {
|
|
214
|
+
let userCount = 0;
|
|
215
|
+
let preview = "";
|
|
216
|
+
for (const header of meta.headers) {
|
|
217
|
+
if (header.type !== 1)
|
|
218
|
+
continue;
|
|
219
|
+
const b = bubbles.get(`bubbleId:${meta.composerId}:${header.bubbleId}`);
|
|
220
|
+
if (!b)
|
|
221
|
+
continue;
|
|
222
|
+
const text = b.text.trim();
|
|
223
|
+
if (!text)
|
|
224
|
+
continue;
|
|
225
|
+
userCount += 1;
|
|
226
|
+
if (!preview)
|
|
227
|
+
preview = text.replace(/\s+/g, " ").slice(0, 80);
|
|
228
|
+
}
|
|
229
|
+
if (userCount === 0)
|
|
230
|
+
continue;
|
|
231
|
+
result.push({ meta, userTurnCount: userCount, preview });
|
|
232
|
+
}
|
|
233
|
+
return result;
|
|
234
|
+
}
|
|
235
|
+
function fetchBubbles(db, keys) {
|
|
236
|
+
const out = new Map();
|
|
237
|
+
if (keys.length === 0)
|
|
238
|
+
return out;
|
|
239
|
+
// SQLite has a parameter limit (~999 by default). Chunk just in case.
|
|
240
|
+
const CHUNK = 500;
|
|
241
|
+
const stmtTpl = (n) => `SELECT key, CAST(value AS TEXT) AS value FROM cursorDiskKV WHERE key IN (${"?,"
|
|
242
|
+
.repeat(n)
|
|
243
|
+
.slice(0, -1)})`;
|
|
244
|
+
for (let i = 0; i < keys.length; i += CHUNK) {
|
|
245
|
+
const chunk = keys.slice(i, i + CHUNK);
|
|
246
|
+
const rows = db
|
|
247
|
+
.prepare(stmtTpl(chunk.length))
|
|
248
|
+
.all(...chunk);
|
|
249
|
+
for (const row of rows) {
|
|
250
|
+
const bubble = parseBubble(row.value);
|
|
251
|
+
if (bubble)
|
|
252
|
+
out.set(row.key, bubble);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return out;
|
|
256
|
+
}
|
|
257
|
+
export const cursorSource = {
|
|
258
|
+
id: "cursor",
|
|
259
|
+
label: "Cursor",
|
|
260
|
+
async discover(limit = 50) {
|
|
261
|
+
const dbPath = getCursorDbPath();
|
|
262
|
+
if (!dbPath)
|
|
263
|
+
return [];
|
|
264
|
+
if (!(await dbExists(dbPath)))
|
|
265
|
+
return [];
|
|
266
|
+
const db = await openDatabase(dbPath);
|
|
267
|
+
if (!db)
|
|
268
|
+
return [];
|
|
269
|
+
try {
|
|
270
|
+
const listed = readComposers(db, limit);
|
|
271
|
+
return listed.map((entry) => ({
|
|
272
|
+
// The "id" is the composerId itself — there's no file path for Cursor.
|
|
273
|
+
id: entry.meta.composerId,
|
|
274
|
+
// Store the composerId in `path` too so the wizard's display layer can
|
|
275
|
+
// round-trip without a special case.
|
|
276
|
+
path: entry.meta.composerId,
|
|
277
|
+
last_modified: new Date(entry.meta.createdAt || Date.now()).toISOString(),
|
|
278
|
+
turn_count: entry.userTurnCount,
|
|
279
|
+
preview: entry.meta.name || entry.preview,
|
|
280
|
+
source: "cursor",
|
|
281
|
+
}));
|
|
282
|
+
}
|
|
283
|
+
finally {
|
|
284
|
+
db.close();
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
async load(stub) {
|
|
288
|
+
return loadCursorSession(stub.id);
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
export async function loadCursorSession(composerId) {
|
|
292
|
+
const dbPath = getCursorDbPath();
|
|
293
|
+
if (!dbPath) {
|
|
294
|
+
throw new Error("Cursor is not supported on this OS");
|
|
295
|
+
}
|
|
296
|
+
if (!(await dbExists(dbPath))) {
|
|
297
|
+
throw new Error(`Cursor database not found at ${dbPath}`);
|
|
298
|
+
}
|
|
299
|
+
const db = await openDatabase(dbPath);
|
|
300
|
+
if (!db) {
|
|
301
|
+
throw new Error("better-sqlite3 failed to load. Reinstall rubric-chat with build tools available.");
|
|
302
|
+
}
|
|
303
|
+
try {
|
|
304
|
+
return loadCursorSessionFromDb(db, composerId);
|
|
305
|
+
}
|
|
306
|
+
finally {
|
|
307
|
+
db.close();
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
export function loadCursorSessionFromDb(db, composerId) {
|
|
311
|
+
const row = db
|
|
312
|
+
.prepare("SELECT CAST(value AS TEXT) AS value FROM cursorDiskKV WHERE key = ?")
|
|
313
|
+
.get(`composerData:${composerId}`);
|
|
314
|
+
if (!row)
|
|
315
|
+
throw new Error(`Cursor composer ${composerId} not found`);
|
|
316
|
+
const composer = parseComposer(row.value);
|
|
317
|
+
if (!composer)
|
|
318
|
+
throw new Error(`Cursor composer ${composerId} could not be parsed`);
|
|
319
|
+
const bubbleKeys = composer.headers.map((h) => `bubbleId:${composerId}:${h.bubbleId}`);
|
|
320
|
+
const bubbles = fetchBubbles(db, bubbleKeys);
|
|
321
|
+
// Re-key bubbles by bubbleId so buildSession can look them up directly.
|
|
322
|
+
const byBubbleId = new Map();
|
|
323
|
+
for (const [key, value] of bubbles) {
|
|
324
|
+
const bubbleId = key.split(":").pop();
|
|
325
|
+
if (bubbleId)
|
|
326
|
+
byBubbleId.set(bubbleId, value);
|
|
327
|
+
}
|
|
328
|
+
return buildSession(composer, byBubbleId);
|
|
329
|
+
}
|
|
330
|
+
//# sourceMappingURL=cursor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/sources/cursor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import Database from "better-sqlite3";
|
|
3
|
+
import { loadCursorSessionFromDb } from "./cursor.js";
|
|
4
|
+
function makeDb() {
|
|
5
|
+
const db = new Database(":memory:");
|
|
6
|
+
db.exec("CREATE TABLE cursorDiskKV (key TEXT UNIQUE, value BLOB);");
|
|
7
|
+
return db;
|
|
8
|
+
}
|
|
9
|
+
function put(db, key, value) {
|
|
10
|
+
db.prepare("INSERT INTO cursorDiskKV (key, value) VALUES (?, ?)").run(key, JSON.stringify(value));
|
|
11
|
+
}
|
|
12
|
+
describe("loadCursorSessionFromDb", () => {
|
|
13
|
+
it("walks the composer header order and keeps only user turns", () => {
|
|
14
|
+
const db = makeDb();
|
|
15
|
+
const composerId = "comp-A";
|
|
16
|
+
put(db, `composerData:${composerId}`, {
|
|
17
|
+
_v: 16,
|
|
18
|
+
composerId,
|
|
19
|
+
name: "General chat",
|
|
20
|
+
createdAt: 1779450000000,
|
|
21
|
+
fullConversationHeadersOnly: [
|
|
22
|
+
{ bubbleId: "b-user-1", type: 1 },
|
|
23
|
+
{ bubbleId: "b-asst-1", type: 2 },
|
|
24
|
+
{ bubbleId: "b-user-2", type: 1 },
|
|
25
|
+
],
|
|
26
|
+
});
|
|
27
|
+
put(db, `bubbleId:${composerId}:b-user-1`, { type: 1, text: "Help me refactor" });
|
|
28
|
+
put(db, `bubbleId:${composerId}:b-asst-1`, {
|
|
29
|
+
type: 2,
|
|
30
|
+
text: "Sure — here is some code\n```js\nconsole.log(1)\n```",
|
|
31
|
+
});
|
|
32
|
+
put(db, `bubbleId:${composerId}:b-user-2`, { type: 1, text: "Now add tests" });
|
|
33
|
+
const session = loadCursorSessionFromDb(db, composerId);
|
|
34
|
+
expect(session.target_tool).toBe("cursor");
|
|
35
|
+
expect(session.source_client).toBe("cli");
|
|
36
|
+
expect(session.turns.map((t) => t.text)).toEqual([
|
|
37
|
+
"Help me refactor",
|
|
38
|
+
"Now add tests",
|
|
39
|
+
]);
|
|
40
|
+
expect(session.turns[1].preceded_by_assistant?.contained_code_block).toBe(true);
|
|
41
|
+
// Assistant text is never serialized into the payload.
|
|
42
|
+
expect(JSON.stringify(session)).not.toContain("console.log");
|
|
43
|
+
expect(JSON.stringify(session)).not.toContain("Sure — here is some code");
|
|
44
|
+
db.close();
|
|
45
|
+
});
|
|
46
|
+
it("falls back to richText when text is empty", () => {
|
|
47
|
+
const db = makeDb();
|
|
48
|
+
const composerId = "comp-B";
|
|
49
|
+
put(db, `composerData:${composerId}`, {
|
|
50
|
+
composerId,
|
|
51
|
+
name: "",
|
|
52
|
+
createdAt: 1779450000000,
|
|
53
|
+
fullConversationHeadersOnly: [{ bubbleId: "b-rich", type: 1 }],
|
|
54
|
+
});
|
|
55
|
+
const lexical = JSON.stringify({
|
|
56
|
+
root: {
|
|
57
|
+
children: [
|
|
58
|
+
{ children: [{ text: "part one" }, { text: "part two" }] },
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
put(db, `bubbleId:${composerId}:b-rich`, {
|
|
63
|
+
type: 1,
|
|
64
|
+
text: "",
|
|
65
|
+
richText: lexical,
|
|
66
|
+
});
|
|
67
|
+
const session = loadCursorSessionFromDb(db, composerId);
|
|
68
|
+
expect(session.turns).toHaveLength(1);
|
|
69
|
+
expect(session.turns[0].text).toContain("part one");
|
|
70
|
+
expect(session.turns[0].text).toContain("part two");
|
|
71
|
+
db.close();
|
|
72
|
+
});
|
|
73
|
+
it("skips header entries that have no matching bubble row", () => {
|
|
74
|
+
const db = makeDb();
|
|
75
|
+
const composerId = "comp-C";
|
|
76
|
+
put(db, `composerData:${composerId}`, {
|
|
77
|
+
composerId,
|
|
78
|
+
name: "Orphan refs",
|
|
79
|
+
createdAt: 1,
|
|
80
|
+
fullConversationHeadersOnly: [
|
|
81
|
+
{ bubbleId: "missing-1", type: 1 },
|
|
82
|
+
{ bubbleId: "real", type: 1 },
|
|
83
|
+
],
|
|
84
|
+
});
|
|
85
|
+
put(db, `bubbleId:${composerId}:real`, { type: 1, text: "real turn" });
|
|
86
|
+
const session = loadCursorSessionFromDb(db, composerId);
|
|
87
|
+
expect(session.turns.map((t) => t.text)).toEqual(["real turn"]);
|
|
88
|
+
db.close();
|
|
89
|
+
});
|
|
90
|
+
it("throws when the composerId doesn't exist", () => {
|
|
91
|
+
const db = makeDb();
|
|
92
|
+
expect(() => loadCursorSessionFromDb(db, "nope")).toThrow(/not found/);
|
|
93
|
+
db.close();
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
//# sourceMappingURL=cursor.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.test.js","sourceRoot":"","sources":["../../src/sources/cursor.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAEtD,SAAS,MAAM;IACb,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC;IACpC,EAAE,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;IACpE,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,GAAG,CAAC,EAAqB,EAAE,GAAW,EAAE,KAAa;IAC5D,EAAE,CAAC,OAAO,CAAC,qDAAqD,CAAC,CAAC,GAAG,CACnE,GAAG,EACH,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CACtB,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;QACpB,MAAM,UAAU,GAAG,QAAQ,CAAC;QAC5B,GAAG,CAAC,EAAE,EAAE,gBAAgB,UAAU,EAAE,EAAE;YACpC,EAAE,EAAE,EAAE;YACN,UAAU;YACV,IAAI,EAAE,cAAc;YACpB,SAAS,EAAE,aAAa;YACxB,2BAA2B,EAAE;gBAC3B,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,EAAE;gBACjC,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,EAAE;gBACjC,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,EAAE;aAClC;SACF,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,EAAE,YAAY,UAAU,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAClF,GAAG,CAAC,EAAE,EAAE,YAAY,UAAU,WAAW,EAAE;YACzC,IAAI,EAAE,CAAC;YACP,IAAI,EAAE,sDAAsD;SAC7D,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,EAAE,YAAY,UAAU,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC;QAE/E,MAAM,OAAO,GAAG,uBAAuB,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QAExD,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3C,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;YAC/C,kBAAkB;YAClB,eAAe;SAChB,CAAC,CAAC;QACH,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,qBAAqB,EAAE,oBAAoB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChF,uDAAuD;QACvD,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QAC7D,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAC;QAC1E,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;QACpB,MAAM,UAAU,GAAG,QAAQ,CAAC;QAC5B,GAAG,CAAC,EAAE,EAAE,gBAAgB,UAAU,EAAE,EAAE;YACpC,UAAU;YACV,IAAI,EAAE,EAAE;YACR,SAAS,EAAE,aAAa;YACxB,2BAA2B,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;SAC/D,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;YAC7B,IAAI,EAAE;gBACJ,QAAQ,EAAE;oBACR,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE;iBAC3D;aACF;SACF,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,EAAE,YAAY,UAAU,SAAS,EAAE;YACvC,IAAI,EAAE,CAAC;YACP,IAAI,EAAE,EAAE;YACR,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,uBAAuB,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QACxD,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACpD,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACpD,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;QACpB,MAAM,UAAU,GAAG,QAAQ,CAAC;QAC5B,GAAG,CAAC,EAAE,EAAE,gBAAgB,UAAU,EAAE,EAAE;YACpC,UAAU;YACV,IAAI,EAAE,aAAa;YACnB,SAAS,EAAE,CAAC;YACZ,2BAA2B,EAAE;gBAC3B,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE;gBAClC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE;aAC9B;SACF,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,EAAE,YAAY,UAAU,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QAEvE,MAAM,OAAO,GAAG,uBAAuB,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QACxD,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;QAChE,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;QACpB,MAAM,CAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QACvE,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/sources/index.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { claudeCodeSource } from "./claudeCode.js";
|
|
2
2
|
import { codexSource } from "./codex.js";
|
|
3
|
+
import { cursorSource } from "./cursor.js";
|
|
3
4
|
export const SOURCES = {
|
|
4
5
|
"claude-code": claudeCodeSource,
|
|
5
|
-
codex: codexSource
|
|
6
|
+
codex: codexSource,
|
|
7
|
+
cursor: cursorSource
|
|
6
8
|
};
|
|
7
9
|
export function getSource(name) {
|
|
8
10
|
return SOURCES[name];
|
|
9
11
|
}
|
|
10
|
-
export { claudeCodeSource, codexSource };
|
|
12
|
+
export { claudeCodeSource, codexSource, cursorSource };
|
|
11
13
|
export { loadGenericSession } from "./generic.js";
|
|
12
14
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sources/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sources/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,CAAC,MAAM,OAAO,GAAkC;IACpD,aAAa,EAAE,gBAAgB;IAC/B,KAAK,EAAE,WAAW;IAClB,MAAM,EAAE,YAAY;CACrB,CAAC;AAEF,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;AACvB,CAAC;AAED,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rubric-chat",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "A strict 0–100 score for AI conversations. Auto-discovers Claude Code
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "A strict 0–100 score for AI conversations. Auto-discovers Claude Code, Codex CLI, and Cursor sessions; also accepts ChatGPT and Claude.ai exports. Six dimensions, eight archetypes, shareable score card.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"homepage": "https://rubric.chat",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"prepublishOnly": "npm run test && npm run build"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
+
"better-sqlite3": "^12.10.0",
|
|
50
51
|
"commander": "^12.1.0",
|
|
51
52
|
"kleur": "^4.1.5",
|
|
52
53
|
"open": "^10.1.0",
|
|
@@ -56,6 +57,7 @@
|
|
|
56
57
|
"keytar": "^7.9.0"
|
|
57
58
|
},
|
|
58
59
|
"devDependencies": {
|
|
60
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
59
61
|
"@types/node": "^20.11.0",
|
|
60
62
|
"@types/prompts": "^2.4.9",
|
|
61
63
|
"typescript": "^5.4.0",
|