rubric-chat 0.1.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/dist/commands/list.js +34 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/login.js +110 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.js +7 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/rate.js +116 -0
- package/dist/commands/rate.js.map +1 -0
- package/dist/commands/status.js +47 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/whoami.js +20 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/commands/wizard.js +107 -0
- package/dist/commands/wizard.js.map +1 -0
- package/dist/index.js +70 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api.js +53 -0
- package/dist/lib/api.js.map +1 -0
- package/dist/lib/config.js +80 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/local-server.js +126 -0
- package/dist/lib/local-server.js.map +1 -0
- package/dist/lib/render.js +38 -0
- package/dist/lib/render.js.map +1 -0
- package/dist/sources/claudeCode.js +200 -0
- package/dist/sources/claudeCode.js.map +1 -0
- package/dist/sources/claudeCode.test.js +55 -0
- package/dist/sources/claudeCode.test.js.map +1 -0
- package/dist/sources/codex.js +200 -0
- package/dist/sources/codex.js.map +1 -0
- package/dist/sources/codex.test.js +64 -0
- package/dist/sources/codex.test.js.map +1 -0
- package/dist/sources/generic.js +169 -0
- package/dist/sources/generic.js.map +1 -0
- package/dist/sources/index.js +12 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/sources/types.js +2 -0
- package/dist/sources/types.js.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile, chmod } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
export const RUBRIC_HOME = join(homedir(), ".rubric");
|
|
5
|
+
const CREDENTIALS_FILE = join(RUBRIC_HOME, "credentials");
|
|
6
|
+
const KEYTAR_SERVICE = "rubric-chat";
|
|
7
|
+
const KEYTAR_ACCOUNT = "default";
|
|
8
|
+
export const CLI_VERSION = "0.0.1";
|
|
9
|
+
export function getApiBaseUrl() {
|
|
10
|
+
return process.env.RUBRIC_API_BASE_URL ?? "https://api.rubric.chat";
|
|
11
|
+
}
|
|
12
|
+
export function getWebBaseUrl() {
|
|
13
|
+
return process.env.RUBRIC_WEB_BASE_URL ?? "https://rubric.chat";
|
|
14
|
+
}
|
|
15
|
+
async function ensureHome() {
|
|
16
|
+
await mkdir(RUBRIC_HOME, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
async function loadKeytar() {
|
|
19
|
+
try {
|
|
20
|
+
const mod = await import("keytar");
|
|
21
|
+
return mod.default ?? mod;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export async function storeToken(jwt) {
|
|
28
|
+
const keytar = await loadKeytar();
|
|
29
|
+
if (keytar) {
|
|
30
|
+
try {
|
|
31
|
+
await keytar.setPassword(KEYTAR_SERVICE, KEYTAR_ACCOUNT, jwt);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Fall through to filesystem.
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
await ensureHome();
|
|
39
|
+
await writeFile(CREDENTIALS_FILE, jwt, { encoding: "utf8", mode: 0o600 });
|
|
40
|
+
await chmod(CREDENTIALS_FILE, 0o600).catch(() => undefined);
|
|
41
|
+
}
|
|
42
|
+
export async function readToken() {
|
|
43
|
+
if (process.env.RUBRIC_JWT)
|
|
44
|
+
return process.env.RUBRIC_JWT;
|
|
45
|
+
const keytar = await loadKeytar();
|
|
46
|
+
if (keytar) {
|
|
47
|
+
try {
|
|
48
|
+
const stored = await keytar.getPassword(KEYTAR_SERVICE, KEYTAR_ACCOUNT);
|
|
49
|
+
if (stored)
|
|
50
|
+
return stored;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Fall through.
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
return (await readFile(CREDENTIALS_FILE, "utf8")).trim() || null;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export async function clearToken() {
|
|
64
|
+
const keytar = await loadKeytar();
|
|
65
|
+
if (keytar) {
|
|
66
|
+
try {
|
|
67
|
+
await keytar.deletePassword(KEYTAR_SERVICE, KEYTAR_ACCOUNT);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// Ignore.
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
await writeFile(CREDENTIALS_FILE, "", { encoding: "utf8", mode: 0o600 });
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Ignore.
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
3
|
+
const SUCCESS_HTML = `<!doctype html><html><head><meta charset="utf-8"><title>Rubric — Signed in</title>
|
|
4
|
+
<style>
|
|
5
|
+
:root { color-scheme: dark; }
|
|
6
|
+
html, body { margin: 0; height: 100%; font-family: ui-sans-serif, system-ui, -apple-system, sans-serif; background: #0C0B0A; color: #F2EEE3; }
|
|
7
|
+
main { min-height: 100%; display: grid; place-items: center; padding: 24px; }
|
|
8
|
+
.card { max-width: 420px; padding: 28px 30px; border: 1px solid #2A271F; border-radius: 16px; background: #17150F; box-shadow: 0 12px 28px -16px rgba(0,0,0,.65); }
|
|
9
|
+
.eyebrow { font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: #857E73; margin: 0 0 8px; }
|
|
10
|
+
h1 { font-family: ui-serif, Georgia, serif; font-weight: 500; font-size: 26px; margin: 0 0 14px; }
|
|
11
|
+
p { color: #B7B1A1; line-height: 1.55; margin: 0 0 12px; font-size: 15px; }
|
|
12
|
+
code { background: #1F1C16; border: 1px solid #2A271F; border-radius: 6px; padding: 2px 6px; font-size: 12px; color: #F2EEE3; }
|
|
13
|
+
</style></head><body><main><div class="card">
|
|
14
|
+
<p class="eyebrow">Rubric CLI</p>
|
|
15
|
+
<h1>You can close this tab.</h1>
|
|
16
|
+
<p>Your terminal session has picked up the credentials. Head back to <code>rubric-chat</code>.</p>
|
|
17
|
+
</div></main></body></html>`;
|
|
18
|
+
const FAILURE_HTML = `<!doctype html><html><head><meta charset="utf-8"><title>Rubric — Bad request</title></head>
|
|
19
|
+
<body style="margin:0;font-family:system-ui;background:#0C0B0A;color:#F2EEE3;display:grid;place-items:center;height:100vh">
|
|
20
|
+
<div style="max-width:420px;padding:24px;border:1px solid #9B2C2C;border-radius:12px;background:#17150F">
|
|
21
|
+
<h1 style="font-size:18px;margin:0 0 10px">Something looked off.</h1>
|
|
22
|
+
<p style="color:#B7B1A1;font-size:14px;line-height:1.55;margin:0">The CLI couldn't verify this response. Try running <code>rubric-chat login</code> again.</p>
|
|
23
|
+
</div></body></html>`;
|
|
24
|
+
function setCors(res) {
|
|
25
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
26
|
+
res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
|
|
27
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
28
|
+
}
|
|
29
|
+
async function readJson(req) {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const chunks = [];
|
|
32
|
+
req.on("data", (chunk) => chunks.push(chunk));
|
|
33
|
+
req.on("end", () => {
|
|
34
|
+
const raw = Buffer.concat(chunks).toString("utf8") || "{}";
|
|
35
|
+
try {
|
|
36
|
+
resolve(JSON.parse(raw));
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
reject(err);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
req.on("error", reject);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Spawn a one-shot HTTP server on a random localhost port. The CLI passes its
|
|
47
|
+
* URL + state to the backend with the magic-link request; the verify page in
|
|
48
|
+
* the browser POSTs `{jwt, state, user}` here after a successful sign-in.
|
|
49
|
+
*/
|
|
50
|
+
export function startLocalCallback(timeoutMs = 5 * 60 * 1000) {
|
|
51
|
+
const state = randomBytes(16).toString("hex");
|
|
52
|
+
let resolveResult = null;
|
|
53
|
+
let rejectResult = null;
|
|
54
|
+
const resultPromise = new Promise((resolve, reject) => {
|
|
55
|
+
resolveResult = resolve;
|
|
56
|
+
rejectResult = reject;
|
|
57
|
+
});
|
|
58
|
+
const server = createServer((req, res) => {
|
|
59
|
+
if (req.method === "OPTIONS") {
|
|
60
|
+
setCors(res);
|
|
61
|
+
res.writeHead(204);
|
|
62
|
+
res.end();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (req.method !== "POST" || !req.url?.startsWith("/auth")) {
|
|
66
|
+
res.writeHead(404, { "content-type": "text/plain" });
|
|
67
|
+
res.end("not found");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
setCors(res);
|
|
71
|
+
readJson(req)
|
|
72
|
+
.then((payload) => {
|
|
73
|
+
if (!payload || typeof payload !== "object") {
|
|
74
|
+
res.writeHead(400, { "content-type": "text/html" });
|
|
75
|
+
res.end(FAILURE_HTML);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const body = payload;
|
|
79
|
+
if (body.state !== state) {
|
|
80
|
+
res.writeHead(400, { "content-type": "text/html" });
|
|
81
|
+
res.end(FAILURE_HTML);
|
|
82
|
+
rejectResult?.(new Error("CSRF state mismatch"));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (typeof body.jwt !== "string" || !body.jwt) {
|
|
86
|
+
res.writeHead(400, { "content-type": "text/html" });
|
|
87
|
+
res.end(FAILURE_HTML);
|
|
88
|
+
rejectResult?.(new Error("Missing jwt in callback"));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
res.writeHead(200, { "content-type": "text/html" });
|
|
92
|
+
res.end(SUCCESS_HTML);
|
|
93
|
+
resolveResult?.({
|
|
94
|
+
jwt: body.jwt,
|
|
95
|
+
user: body.user
|
|
96
|
+
});
|
|
97
|
+
})
|
|
98
|
+
.catch((err) => {
|
|
99
|
+
res.writeHead(400, { "content-type": "text/html" });
|
|
100
|
+
res.end(FAILURE_HTML);
|
|
101
|
+
rejectResult?.(err instanceof Error ? err : new Error(String(err)));
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
server.listen(0, "127.0.0.1");
|
|
105
|
+
const port = server.address().port;
|
|
106
|
+
const callbackUrl = `http://127.0.0.1:${port}/auth`;
|
|
107
|
+
const timer = setTimeout(() => {
|
|
108
|
+
rejectResult?.(new Error("Timed out waiting for browser callback"));
|
|
109
|
+
server.close();
|
|
110
|
+
}, timeoutMs);
|
|
111
|
+
const close = () => {
|
|
112
|
+
clearTimeout(timer);
|
|
113
|
+
server.close();
|
|
114
|
+
};
|
|
115
|
+
const wait = async () => {
|
|
116
|
+
try {
|
|
117
|
+
const result = await resultPromise;
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
close();
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
return { port, callbackUrl, state, wait, close };
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=local-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-server.js","sourceRoot":"","sources":["../../src/lib/local-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA6C,MAAM,WAAW,CAAC;AAEpF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAiB1C,MAAM,YAAY,GAAG;;;;;;;;;;;;;;4BAcO,CAAC;AAE7B,MAAM,YAAY,GAAG;;;;;qBAKA,CAAC;AAEtB,SAAS,OAAO,CAAC,GAAmB;IAClC,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;IAClD,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,eAAe,CAAC,CAAC;IAC/D,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAC;AAChE,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,GAAoB;IAC1C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9C,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACjB,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC;YAC3D,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAAS,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI;IAC1D,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE9C,IAAI,aAAa,GAA8C,IAAI,CAAC;IACpE,IAAI,YAAY,GAAkC,IAAI,CAAC;IACvD,MAAM,aAAa,GAAG,IAAI,OAAO,CAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACpE,aAAa,GAAG,OAAO,CAAC;QACxB,YAAY,GAAG,MAAM,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACvC,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,CAAC;YACb,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3D,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;YACrD,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,CAAC;QAEb,QAAQ,CAAC,GAAG,CAAC;aACV,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;YAChB,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAC5C,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;gBACpD,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;gBACtB,OAAO;YACT,CAAC;YACD,MAAM,IAAI,GAAG,OAAkC,CAAC;YAChD,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;gBACzB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;gBACpD,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;gBACtB,YAAY,EAAE,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC;gBACjD,OAAO;YACT,CAAC;YACD,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;gBAC9C,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;gBACpD,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;gBACtB,YAAY,EAAE,CAAC,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAC;gBACrD,OAAO;YACT,CAAC;YAED,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;YACpD,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;YAEtB,aAAa,EAAE,CAAC;gBACd,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,IAAI,EAAE,IAAI,CAAC,IAA8B;aAC1C,CAAC,CAAC;QACL,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YACtB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;YACpD,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;YACtB,YAAY,EAAE,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACtE,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IAE9B,MAAM,IAAI,GAAI,MAAM,CAAC,OAAO,EAAkB,CAAC,IAAI,CAAC;IACpD,MAAM,WAAW,GAAG,oBAAoB,IAAI,OAAO,CAAC;IAEpD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;QAC5B,YAAY,EAAE,CAAC,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC,CAAC;QACpE,MAAM,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC,EAAE,SAAS,CAAC,CAAC;IAEd,MAAM,KAAK,GAAG,GAAS,EAAE;QACvB,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,MAAM,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,KAAK,IAA6B,EAAE;QAC/C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC;YACnC,OAAO,MAAM,CAAC;QAChB,CAAC;gBAAS,CAAC;YACT,KAAK,EAAE,CAAC;QACV,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACnD,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import kleur from "kleur";
|
|
2
|
+
export function renderTeaser(teaser, webBase) {
|
|
3
|
+
return [
|
|
4
|
+
"",
|
|
5
|
+
` ${kleur.bold(`Score`)} ${kleur.yellow(String(teaser.score))}${kleur.dim("/100")} ${kleur.dim("(strict median ~50)")}`,
|
|
6
|
+
` ${kleur.bold("Archetype")} ${teaser.archetype_name}`,
|
|
7
|
+
` ${kleur.dim(teaser.archetype_tagline)}`,
|
|
8
|
+
"",
|
|
9
|
+
kleur.dim(" Sign in to unlock the full report:"),
|
|
10
|
+
` ${kleur.cyan(`${webBase}/auth/login`)}`,
|
|
11
|
+
""
|
|
12
|
+
].join("\n");
|
|
13
|
+
}
|
|
14
|
+
export function renderReport(report, webBase) {
|
|
15
|
+
const lines = [];
|
|
16
|
+
lines.push("");
|
|
17
|
+
lines.push(` ${kleur.bold("Score")} ${kleur.yellow(String(report.score))}${kleur.dim("/100")} ${kleur.dim(`(raw ${report.raw_score})`)}`);
|
|
18
|
+
lines.push(` ${kleur.bold(report.archetype.name)} — ${kleur.dim(report.archetype.tagline)}`);
|
|
19
|
+
lines.push("");
|
|
20
|
+
lines.push(` ${kleur.dim(report.summary)}`);
|
|
21
|
+
lines.push("");
|
|
22
|
+
for (const dimension of report.dimensions) {
|
|
23
|
+
const bar = renderBar(dimension.score);
|
|
24
|
+
lines.push(` ${dimension.dimension.padEnd(20)} ${bar} ${String(dimension.score).padStart(3)} ${kleur.dim(dimension.feedback)}`);
|
|
25
|
+
}
|
|
26
|
+
lines.push("");
|
|
27
|
+
lines.push(` ${kleur.dim("Open in browser:")} ${kleur.cyan(`${webBase}/result/${report.id}`)}`);
|
|
28
|
+
if (report.share?.url) {
|
|
29
|
+
lines.push(` ${kleur.dim("Public share:")} ${kleur.cyan(report.share.url)}`);
|
|
30
|
+
}
|
|
31
|
+
lines.push("");
|
|
32
|
+
return lines.join("\n");
|
|
33
|
+
}
|
|
34
|
+
function renderBar(score, width = 24) {
|
|
35
|
+
const filled = Math.max(0, Math.min(width, Math.round((score / 100) * width)));
|
|
36
|
+
return kleur.green("█".repeat(filled)) + kleur.dim("░".repeat(width - filled));
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/lib/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { basename, join } from "node:path";
|
|
4
|
+
import { CLI_VERSION } from "../lib/config.js";
|
|
5
|
+
const CLAUDE_CODE_ROOT = join(homedir(), ".claude", "projects");
|
|
6
|
+
export const claudeCodeSource = {
|
|
7
|
+
id: "claude-code",
|
|
8
|
+
label: "Claude Code",
|
|
9
|
+
async discover(limit = 50) {
|
|
10
|
+
const files = await collectJsonl(CLAUDE_CODE_ROOT);
|
|
11
|
+
files.sort((a, b) => b.last_modified.localeCompare(a.last_modified));
|
|
12
|
+
const stubs = [];
|
|
13
|
+
for (const file of files.slice(0, limit)) {
|
|
14
|
+
try {
|
|
15
|
+
const { turnCount, preview } = await peekSession(file.path);
|
|
16
|
+
if (turnCount === 0)
|
|
17
|
+
continue;
|
|
18
|
+
stubs.push({
|
|
19
|
+
id: basename(file.path).replace(/\.jsonl$/, ""),
|
|
20
|
+
path: file.path,
|
|
21
|
+
last_modified: file.last_modified,
|
|
22
|
+
turn_count: turnCount,
|
|
23
|
+
preview,
|
|
24
|
+
source: "claude-code"
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// Skip files we can't read.
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return stubs;
|
|
32
|
+
},
|
|
33
|
+
async load(stub) {
|
|
34
|
+
return loadClaudeCodeSession(stub.path);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
export async function loadClaudeCodeSession(path) {
|
|
38
|
+
const content = await readFile(path, "utf8");
|
|
39
|
+
const lines = content.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
40
|
+
const turns = [];
|
|
41
|
+
let lastAssistantSummary;
|
|
42
|
+
let lastAssistantText = "";
|
|
43
|
+
for (const line of lines) {
|
|
44
|
+
let event;
|
|
45
|
+
try {
|
|
46
|
+
event = JSON.parse(line);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (!event || typeof event !== "object")
|
|
52
|
+
continue;
|
|
53
|
+
const record = event;
|
|
54
|
+
const type = typeof record.type === "string" ? record.type : "";
|
|
55
|
+
const role = inferRole(record);
|
|
56
|
+
if (role === "assistant" || type === "assistant") {
|
|
57
|
+
const text = extractText(record.message ?? record);
|
|
58
|
+
if (text) {
|
|
59
|
+
lastAssistantText += (lastAssistantText ? "\n" : "") + text;
|
|
60
|
+
lastAssistantSummary = {
|
|
61
|
+
response_length_chars: lastAssistantText.length,
|
|
62
|
+
contained_code_block: lastAssistantText.includes("```"),
|
|
63
|
+
contained_error: /\berror\b|\bexception\b|\bfailed\b/i.test(lastAssistantText)
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (role === "user" || type === "user") {
|
|
69
|
+
const text = extractUserText(record);
|
|
70
|
+
if (!text.trim())
|
|
71
|
+
continue;
|
|
72
|
+
turns.push({
|
|
73
|
+
index: turns.length,
|
|
74
|
+
text,
|
|
75
|
+
preceded_by_assistant: lastAssistantSummary
|
|
76
|
+
});
|
|
77
|
+
lastAssistantSummary = undefined;
|
|
78
|
+
lastAssistantText = "";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
schema_version: "1.0",
|
|
83
|
+
target_tool: "claude_code",
|
|
84
|
+
source_client: "cli",
|
|
85
|
+
source_client_version: CLI_VERSION,
|
|
86
|
+
ingested_at: new Date().toISOString(),
|
|
87
|
+
turns
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function inferRole(record) {
|
|
91
|
+
if (typeof record.role === "string")
|
|
92
|
+
return record.role;
|
|
93
|
+
const message = record.message;
|
|
94
|
+
if (message && typeof message === "object") {
|
|
95
|
+
const role = message.role;
|
|
96
|
+
if (typeof role === "string")
|
|
97
|
+
return role;
|
|
98
|
+
}
|
|
99
|
+
return "";
|
|
100
|
+
}
|
|
101
|
+
function extractUserText(record) {
|
|
102
|
+
const message = record.message ?? record;
|
|
103
|
+
return extractText(message);
|
|
104
|
+
}
|
|
105
|
+
function extractText(value) {
|
|
106
|
+
if (typeof value === "string")
|
|
107
|
+
return value;
|
|
108
|
+
if (!value || typeof value !== "object")
|
|
109
|
+
return "";
|
|
110
|
+
const record = value;
|
|
111
|
+
const content = record.content;
|
|
112
|
+
if (typeof content === "string")
|
|
113
|
+
return content;
|
|
114
|
+
if (Array.isArray(content)) {
|
|
115
|
+
return content
|
|
116
|
+
.map((part) => {
|
|
117
|
+
if (typeof part === "string")
|
|
118
|
+
return part;
|
|
119
|
+
if (part && typeof part === "object") {
|
|
120
|
+
const obj = part;
|
|
121
|
+
if (obj.type === "text" && typeof obj.text === "string")
|
|
122
|
+
return obj.text;
|
|
123
|
+
if (typeof obj.text === "string")
|
|
124
|
+
return obj.text;
|
|
125
|
+
}
|
|
126
|
+
return "";
|
|
127
|
+
})
|
|
128
|
+
.filter(Boolean)
|
|
129
|
+
.join("\n");
|
|
130
|
+
}
|
|
131
|
+
if (typeof record.text === "string")
|
|
132
|
+
return record.text;
|
|
133
|
+
return "";
|
|
134
|
+
}
|
|
135
|
+
async function peekSession(path) {
|
|
136
|
+
const content = await readFile(path, "utf8");
|
|
137
|
+
const lines = content.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
138
|
+
let turnCount = 0;
|
|
139
|
+
let preview = "";
|
|
140
|
+
for (const line of lines) {
|
|
141
|
+
let event;
|
|
142
|
+
try {
|
|
143
|
+
event = JSON.parse(line);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (!event || typeof event !== "object")
|
|
149
|
+
continue;
|
|
150
|
+
const record = event;
|
|
151
|
+
const role = inferRole(record);
|
|
152
|
+
if (role === "user" || record.type === "user") {
|
|
153
|
+
const text = extractUserText(record);
|
|
154
|
+
if (!text.trim())
|
|
155
|
+
continue;
|
|
156
|
+
if (!preview)
|
|
157
|
+
preview = text.replace(/\s+/g, " ").slice(0, 80);
|
|
158
|
+
turnCount += 1;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return { turnCount, preview };
|
|
162
|
+
}
|
|
163
|
+
async function collectJsonl(root) {
|
|
164
|
+
const out = [];
|
|
165
|
+
let stack = [];
|
|
166
|
+
try {
|
|
167
|
+
stack.push(root);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
return out;
|
|
171
|
+
}
|
|
172
|
+
while (stack.length > 0) {
|
|
173
|
+
const current = stack.pop();
|
|
174
|
+
let entries;
|
|
175
|
+
try {
|
|
176
|
+
entries = (await readdir(current, { withFileTypes: true }));
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
for (const entry of entries) {
|
|
182
|
+
const name = entry.name;
|
|
183
|
+
const full = join(current, name);
|
|
184
|
+
if (entry.isDirectory()) {
|
|
185
|
+
stack.push(full);
|
|
186
|
+
}
|
|
187
|
+
else if (entry.isFile() && name.endsWith(".jsonl")) {
|
|
188
|
+
try {
|
|
189
|
+
const s = await stat(full);
|
|
190
|
+
out.push({ path: full, last_modified: s.mtime.toISOString() });
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// ignore
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return out;
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=claudeCode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeCode.js","sourceRoot":"","sources":["../../src/sources/claudeCode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { mkdtemp, writeFile, rm } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { describe, expect, it, afterEach } from "vitest";
|
|
5
|
+
import { loadClaudeCodeSession } from "./claudeCode.js";
|
|
6
|
+
const dirs = [];
|
|
7
|
+
afterEach(async () => {
|
|
8
|
+
while (dirs.length > 0) {
|
|
9
|
+
const dir = dirs.pop();
|
|
10
|
+
await rm(dir, { recursive: true, force: true });
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
async function tempJsonl(lines) {
|
|
14
|
+
const dir = await mkdtemp(join(tmpdir(), "rubric-cli-"));
|
|
15
|
+
dirs.push(dir);
|
|
16
|
+
const path = join(dir, "session.jsonl");
|
|
17
|
+
await writeFile(path, lines.map((line) => JSON.stringify(line)).join("\n"));
|
|
18
|
+
return path;
|
|
19
|
+
}
|
|
20
|
+
describe("loadClaudeCodeSession", () => {
|
|
21
|
+
it("collects user turns and drops assistant content", async () => {
|
|
22
|
+
const path = await tempJsonl([
|
|
23
|
+
{ type: "user", message: { role: "user", content: "Help me refactor this" } },
|
|
24
|
+
{ type: "assistant", message: { role: "assistant", content: "Sure, here is some code\n```js\n1\n```" } },
|
|
25
|
+
{ type: "user", message: { role: "user", content: "Now add tests" } }
|
|
26
|
+
]);
|
|
27
|
+
const session = await loadClaudeCodeSession(path);
|
|
28
|
+
expect(session.target_tool).toBe("claude_code");
|
|
29
|
+
expect(session.turns.map((turn) => turn.text)).toEqual([
|
|
30
|
+
"Help me refactor this",
|
|
31
|
+
"Now add tests"
|
|
32
|
+
]);
|
|
33
|
+
expect(session.turns[1].preceded_by_assistant?.contained_code_block).toBe(true);
|
|
34
|
+
expect(JSON.stringify(session)).not.toContain("Sure, here is some code");
|
|
35
|
+
});
|
|
36
|
+
it("handles array content from typed events", async () => {
|
|
37
|
+
const path = await tempJsonl([
|
|
38
|
+
{
|
|
39
|
+
type: "user",
|
|
40
|
+
message: {
|
|
41
|
+
role: "user",
|
|
42
|
+
content: [
|
|
43
|
+
{ type: "text", text: "part one" },
|
|
44
|
+
{ type: "text", text: "part two" }
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
]);
|
|
49
|
+
const session = await loadClaudeCodeSession(path);
|
|
50
|
+
expect(session.turns).toHaveLength(1);
|
|
51
|
+
expect(session.turns[0].text).toContain("part one");
|
|
52
|
+
expect(session.turns[0].text).toContain("part two");
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
//# sourceMappingURL=claudeCode.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeCode.test.js","sourceRoot":"","sources":["../../src/sources/claudeCode.test.ts"],"names":[],"mappings":"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"}
|