context-vault 3.0.1 → 3.0.2
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/bin/cli.js +151 -6
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -3308,7 +3308,7 @@ async function runRecall() {
|
|
|
3308
3308
|
const { initDatabase, prepareStatements } =
|
|
3309
3309
|
await import("@context-vault/core/db");
|
|
3310
3310
|
const { embed } = await import("@context-vault/core/embed");
|
|
3311
|
-
const { hybridSearch } = await import("@context-vault/core/
|
|
3311
|
+
const { hybridSearch } = await import("@context-vault/core/search");
|
|
3312
3312
|
|
|
3313
3313
|
db = await initDatabase(config.dbPath);
|
|
3314
3314
|
const stmts = prepareStatements(db);
|
|
@@ -3436,13 +3436,158 @@ async function runSessionCapture() {
|
|
|
3436
3436
|
}
|
|
3437
3437
|
|
|
3438
3438
|
async function runSessionEnd() {
|
|
3439
|
-
|
|
3440
|
-
|
|
3439
|
+
let db;
|
|
3440
|
+
try {
|
|
3441
|
+
const raw = await new Promise((resolve) => {
|
|
3442
|
+
let data = "";
|
|
3443
|
+
process.stdin.on("data", (chunk) => (data += chunk));
|
|
3444
|
+
process.stdin.on("end", () => resolve(data));
|
|
3445
|
+
});
|
|
3446
|
+
if (!raw.trim()) return;
|
|
3447
|
+
let input;
|
|
3448
|
+
try {
|
|
3449
|
+
input = JSON.parse(raw);
|
|
3450
|
+
} catch {
|
|
3451
|
+
return;
|
|
3452
|
+
}
|
|
3453
|
+
const { session_id, transcript_path, cwd } = input ?? {};
|
|
3454
|
+
if (!transcript_path || !cwd) return;
|
|
3455
|
+
|
|
3456
|
+
// Read transcript (JSONL)
|
|
3457
|
+
let turns = [];
|
|
3458
|
+
try {
|
|
3459
|
+
const transcriptRaw = readFileSync(transcript_path, "utf-8");
|
|
3460
|
+
for (const line of transcriptRaw.split("\n")) {
|
|
3461
|
+
const trimmed = line.trim();
|
|
3462
|
+
if (!trimmed) continue;
|
|
3463
|
+
try { turns.push(JSON.parse(trimmed)); } catch {}
|
|
3464
|
+
}
|
|
3465
|
+
} catch { return; }
|
|
3466
|
+
|
|
3467
|
+
const extractText = (turn) => {
|
|
3468
|
+
if (typeof turn.content === "string") return turn.content;
|
|
3469
|
+
if (Array.isArray(turn.content))
|
|
3470
|
+
return turn.content.filter((b) => b.type === "text").map((b) => b.text).join(" ");
|
|
3471
|
+
return "";
|
|
3472
|
+
};
|
|
3473
|
+
|
|
3474
|
+
const userTurns = turns.filter((t) => t.role === "user");
|
|
3475
|
+
if (userTurns.length === 0) return;
|
|
3476
|
+
|
|
3477
|
+
// Tool use blocks
|
|
3478
|
+
const allToolUse = [];
|
|
3479
|
+
for (const turn of turns) {
|
|
3480
|
+
if (!Array.isArray(turn.content)) continue;
|
|
3481
|
+
for (const block of turn.content) {
|
|
3482
|
+
if (block.type === "tool_use") allToolUse.push(block);
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
3485
|
+
|
|
3486
|
+
// Files modified
|
|
3487
|
+
const seenFiles = new Set();
|
|
3488
|
+
const filesModified = [];
|
|
3489
|
+
for (const block of allToolUse) {
|
|
3490
|
+
if (block.name === "Write" || block.name === "Edit") {
|
|
3491
|
+
const path = block.input?.file_path ?? block.input?.path ?? null;
|
|
3492
|
+
if (path && !seenFiles.has(path)) { seenFiles.add(path); filesModified.push(path); }
|
|
3493
|
+
}
|
|
3494
|
+
}
|
|
3495
|
+
|
|
3496
|
+
// Commands run
|
|
3497
|
+
const commandsRun = [];
|
|
3498
|
+
for (const block of allToolUse) {
|
|
3499
|
+
if (block.name === "Bash") {
|
|
3500
|
+
const cmd = block.input?.command ?? block.input?.cmd ?? null;
|
|
3501
|
+
if (cmd) commandsRun.push(cmd.slice(0, 100));
|
|
3502
|
+
}
|
|
3503
|
+
}
|
|
3504
|
+
|
|
3505
|
+
// Tool counts
|
|
3506
|
+
const toolCounts = {};
|
|
3507
|
+
for (const block of allToolUse) {
|
|
3508
|
+
const name = block.name ?? "unknown";
|
|
3509
|
+
toolCounts[name] = (toolCounts[name] ?? 0) + 1;
|
|
3510
|
+
}
|
|
3511
|
+
const toolSummary = Object.entries(toolCounts)
|
|
3512
|
+
.sort((a, b) => b[1] - a[1])
|
|
3513
|
+
.map(([name, count]) => `${name}: ${count}`)
|
|
3514
|
+
.join(", ");
|
|
3515
|
+
|
|
3516
|
+
// Duration
|
|
3517
|
+
let durationStr = null;
|
|
3518
|
+
const timestampedTurns = turns.filter((t) => t.timestamp != null);
|
|
3519
|
+
if (timestampedTurns.length >= 2) {
|
|
3520
|
+
const diffMs = new Date(timestampedTurns[timestampedTurns.length - 1].timestamp) - new Date(timestampedTurns[0].timestamp);
|
|
3521
|
+
if (!isNaN(diffMs) && diffMs >= 0) {
|
|
3522
|
+
const totalSec = Math.round(diffMs / 1000);
|
|
3523
|
+
const hours = Math.floor(totalSec / 3600);
|
|
3524
|
+
const minutes = Math.floor((totalSec % 3600) / 60);
|
|
3525
|
+
const seconds = totalSec % 60;
|
|
3526
|
+
durationStr = hours > 0 ? `${hours}h ${minutes}m` : minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;
|
|
3527
|
+
}
|
|
3528
|
+
}
|
|
3529
|
+
|
|
3530
|
+
const message_count = userTurns.length;
|
|
3531
|
+
const project = cwd.split("/").pop() || "unknown";
|
|
3532
|
+
const first_prompt = extractText(userTurns[0]).slice(0, 200);
|
|
3533
|
+
const last_prompt = message_count > 1 ? extractText(userTurns[message_count - 1]).slice(0, 200) : first_prompt;
|
|
3534
|
+
|
|
3535
|
+
// Build body
|
|
3536
|
+
const durationPart = durationStr ? `, ~${durationStr}` : "";
|
|
3537
|
+
const bodyLines = [
|
|
3538
|
+
`Session in ${project} (${message_count} exchange${message_count !== 1 ? "s" : ""}${durationPart}).`,
|
|
3539
|
+
"", "## What was done",
|
|
3540
|
+
`Opened with: ${first_prompt}`, "",
|
|
3541
|
+
`Closed with: ${last_prompt}`,
|
|
3542
|
+
];
|
|
3543
|
+
const limitedFiles = filesModified.slice(0, 20);
|
|
3544
|
+
if (limitedFiles.length > 0) {
|
|
3545
|
+
bodyLines.push("", "## Files modified");
|
|
3546
|
+
for (const f of limitedFiles) bodyLines.push(`- ${f}`);
|
|
3547
|
+
if (filesModified.length > 20) bodyLines.push(`- ... and ${filesModified.length - 20} more`);
|
|
3548
|
+
}
|
|
3549
|
+
const limitedCmds = commandsRun.slice(0, 10);
|
|
3550
|
+
if (limitedCmds.length > 0) {
|
|
3551
|
+
bodyLines.push("", "## Key commands");
|
|
3552
|
+
for (const c of limitedCmds) bodyLines.push(`- ${c}`);
|
|
3553
|
+
if (commandsRun.length > 10) bodyLines.push(`- ... and ${commandsRun.length - 10} more`);
|
|
3554
|
+
}
|
|
3555
|
+
if (toolSummary) bodyLines.push("", "## Tools used", toolSummary);
|
|
3556
|
+
const body = bodyLines.join("\n");
|
|
3557
|
+
|
|
3558
|
+
// Save via core APIs
|
|
3559
|
+
const { resolveConfig } = await import("@context-vault/core/config");
|
|
3560
|
+
const config = resolveConfig();
|
|
3561
|
+
if (!config.vaultDirExists) return;
|
|
3562
|
+
const { initDatabase, prepareStatements, insertVec, deleteVec } =
|
|
3563
|
+
await import("@context-vault/core/db");
|
|
3564
|
+
const { captureAndIndex } = await import("@context-vault/core/capture");
|
|
3565
|
+
db = await initDatabase(config.dbPath);
|
|
3566
|
+
const stmts = prepareStatements(db);
|
|
3567
|
+
const ctx = {
|
|
3568
|
+
db, config, stmts,
|
|
3569
|
+
embed: async () => null,
|
|
3570
|
+
insertVec: (rowid, embedding) => insertVec(stmts, rowid, embedding),
|
|
3571
|
+
deleteVec: (rowid) => deleteVec(stmts, rowid),
|
|
3572
|
+
};
|
|
3573
|
+
const entry = await captureAndIndex(ctx, {
|
|
3574
|
+
kind: "session",
|
|
3575
|
+
title: `Session — ${project} ${new Date().toLocaleString("en-US", { month: "short", day: "numeric", year: "numeric", hour: "2-digit", minute: "2-digit" })}`,
|
|
3576
|
+
body,
|
|
3577
|
+
tags: ["session-end", "session-summary", project],
|
|
3578
|
+
source: "claude-code",
|
|
3579
|
+
meta: { session_id: session_id ?? null, cwd, message_count },
|
|
3580
|
+
});
|
|
3581
|
+
console.log(`context-vault session captured — id: ${entry.id}`);
|
|
3582
|
+
} catch {
|
|
3583
|
+
// fail silently — never block session end
|
|
3584
|
+
} finally {
|
|
3585
|
+
try { db?.close(); } catch {}
|
|
3586
|
+
}
|
|
3441
3587
|
}
|
|
3442
3588
|
|
|
3443
3589
|
async function runPostToolCall() {
|
|
3444
|
-
|
|
3445
|
-
await main();
|
|
3590
|
+
// Removed in v3 — post-tool-call hooks are no longer supported
|
|
3446
3591
|
}
|
|
3447
3592
|
|
|
3448
3593
|
async function runSave() {
|
|
@@ -3579,7 +3724,7 @@ async function runSearch() {
|
|
|
3579
3724
|
const { initDatabase, prepareStatements } =
|
|
3580
3725
|
await import("@context-vault/core/db");
|
|
3581
3726
|
const { embed } = await import("@context-vault/core/embed");
|
|
3582
|
-
const { hybridSearch } = await import("@context-vault/core/
|
|
3727
|
+
const { hybridSearch } = await import("@context-vault/core/search");
|
|
3583
3728
|
|
|
3584
3729
|
db = await initDatabase(config.dbPath);
|
|
3585
3730
|
const stmts = prepareStatements(db);
|