@dvquys/qrec 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 ADDED
@@ -0,0 +1,99 @@
1
+ # qrec
2
+
3
+ Purpose-built session recall engine for Claude Code. Keeps an embedding model resident in memory for fast hybrid search (BM25 + vector) over your Claude session transcripts.
4
+
5
+ - **Warm query**: ~55ms vs ~2600ms cold model load per invocation
6
+
7
+ ## Install
8
+
9
+ ### Step 1 — Install the CLI
10
+
11
+ ```bash
12
+ npm install -g qrec
13
+ qrec onboard
14
+ ```
15
+
16
+ `qrec onboard` downloads the embedding model (~313 MB, once), indexes your Claude sessions at `~/.claude/projects/`, and starts the daemon. Your browser opens automatically to show live progress.
17
+
18
+ ### Step 2 — Claude Code integration (optional)
19
+
20
+ Install the plugin so the daemon auto-starts with every Claude Code session:
21
+
22
+ ```bash
23
+ /plugin marketplace add dvquy13/qrec
24
+ /plugin install qrec@dvquy13-qrec
25
+ ```
26
+
27
+ That's it — no further configuration needed.
28
+
29
+ ### Local dev
30
+
31
+ ```bash
32
+ bun install
33
+ bun link # register qrec globally → ~/.bun/bin/qrec
34
+ qrec onboard
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ The daemon runs at **http://localhost:3030**. Open it in your browser to search sessions and monitor indexing activity.
40
+
41
+ ```bash
42
+ qrec status # check if daemon is running
43
+ qrec stop # stop the daemon
44
+ ```
45
+
46
+ ### API
47
+
48
+ ```bash
49
+ curl -s -X POST http://localhost:3030/search \
50
+ -H "Content-Type: application/json" \
51
+ -d '{"query": "sqlite vec extension", "k": 5}' | jq .
52
+ ```
53
+
54
+ ```json
55
+ {
56
+ "results": [
57
+ {
58
+ "session_id": "a1b2c3d4",
59
+ "title": "...",
60
+ "date": "2026-03-09",
61
+ "project": "qrec",
62
+ "score": 0.042,
63
+ "preview": "...best matching chunk..."
64
+ }
65
+ ],
66
+ "latencyMs": 58
67
+ }
68
+ ```
69
+
70
+ ### MCP server
71
+
72
+ ```bash
73
+ qrec mcp # stdio (Claude Code MCP config)
74
+ qrec mcp --http # HTTP on port 3031
75
+ ```
76
+
77
+ Tools: `search(query, k?)`, `get(session_id)`, `status()`
78
+
79
+ ## Commands
80
+
81
+ | Command | Description |
82
+ |---|---|
83
+ | `qrec onboard` | First-time setup: model download + index + start daemon + open browser |
84
+ | `qrec teardown` | Stop daemon and remove all qrec data (`~/.qrec/`) |
85
+ | `qrec index [path]` | Re-index sessions (default: `~/.claude/projects/`) |
86
+ | `qrec serve [--daemon]` | Start HTTP server on port 3030 |
87
+ | `qrec stop` | Stop daemon |
88
+ | `qrec mcp [--http]` | Start MCP server (stdio or HTTP) |
89
+ | `qrec status` | Status summary + log tail |
90
+
91
+ ## Stack
92
+
93
+ | Layer | Choice |
94
+ |---|---|
95
+ | Runtime | Bun |
96
+ | Language | TypeScript |
97
+ | Search DB | SQLite (FTS5 + sqlite-vec) |
98
+ | Embeddings | node-llama-cpp 3.15.1 (`embeddinggemma-300M-Q8_0`) |
99
+ | MCP | `@modelcontextprotocol/sdk` |
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@dvquys/qrec",
3
+ "version": "0.2.0",
4
+ "description": "Purpose-built session recall engine — persistent daemon with BM25 + vector hybrid search",
5
+ "bin": {
6
+ "qrec": "plugin/scripts/qrec-cli.js"
7
+ },
8
+ "files": [
9
+ "plugin/scripts/qrec.cjs",
10
+ "plugin/scripts/qrec-cli.js",
11
+ "README.md"
12
+ ],
13
+ "scripts": {
14
+ "dev": "bun run src/cli.ts",
15
+ "build": "node scripts/build.js",
16
+ "release": "bash scripts/release.sh",
17
+ "smoke-test": "bash scripts/smoke-test.sh"
18
+ },
19
+ "dependencies": {
20
+ "@modelcontextprotocol/sdk": "^1.0.0",
21
+ "node-llama-cpp": "3.15.1",
22
+ "sqlite-vec": "^0.1.0"
23
+ },
24
+ "devDependencies": {
25
+ "@types/bun": "latest",
26
+ "esbuild": "^0.27.3",
27
+ "typescript": "^5.0.0"
28
+ },
29
+ "trustedDependencies": [
30
+ "node-llama-cpp"
31
+ ]
32
+ }
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+ // qrec-cli.js — npm bin entry. Locates bun and spawns qrec.cjs with all CLI args.
3
+
4
+ "use strict";
5
+
6
+ const { spawnSync, spawn } = require("child_process");
7
+ const { existsSync } = require("fs");
8
+ const { homedir } = require("os");
9
+ const path = require("path");
10
+
11
+ const BUN_CANDIDATES = [
12
+ path.join(homedir(), ".bun", "bin", "bun"),
13
+ "/usr/local/bin/bun",
14
+ "/opt/homebrew/bin/bun",
15
+ "/home/linuxbrew/.linuxbrew/bin/bun",
16
+ ];
17
+
18
+ function findBun() {
19
+ for (const candidate of BUN_CANDIDATES) {
20
+ if (existsSync(candidate)) return candidate;
21
+ }
22
+ try {
23
+ const r = spawnSync("which", ["bun"], { encoding: "utf-8", timeout: 3000 });
24
+ if (r.status === 0 && r.stdout.trim()) return r.stdout.trim();
25
+ } catch {}
26
+ return null;
27
+ }
28
+
29
+ const bunPath = findBun();
30
+ if (!bunPath) {
31
+ process.stderr.write("[qrec] ERROR: bun not found. Install from https://bun.sh\n");
32
+ process.exit(1);
33
+ }
34
+
35
+ const qrecCjs = path.join(__dirname, "qrec.cjs");
36
+ const userArgs = process.argv.slice(2);
37
+ const bunArgs = ["run", qrecCjs, ...userArgs];
38
+
39
+ // serve --daemon: fire-and-fork so the hook returns immediately.
40
+ // Claude Code hooks never close stdin, so blocking on stdin would hang forever.
41
+ if (userArgs.includes("serve") && userArgs.includes("--daemon")) {
42
+ const child = spawn(bunPath, bunArgs, {
43
+ detached: true,
44
+ stdio: "ignore",
45
+ env: process.env,
46
+ });
47
+ child.unref();
48
+ process.exit(0);
49
+ }
50
+
51
+ // Buffer stdin before passing to bun (avoids libuv pipe crash on Linux).
52
+ const stdinChunks = [];
53
+ process.stdin.on("data", chunk => stdinChunks.push(chunk));
54
+ process.stdin.on("end", () => {
55
+ const buf = Buffer.concat(stdinChunks);
56
+ const result = spawnSync(bunPath, bunArgs, {
57
+ input: buf.length > 0 ? buf : undefined,
58
+ stdio: buf.length > 0 ? ["pipe", "inherit", "inherit"] : ["ignore", "inherit", "inherit"],
59
+ env: process.env,
60
+ });
61
+ process.exit(result.status ?? 1);
62
+ });
63
+
64
+ if (process.stdin.isTTY) {
65
+ process.stdin.destroy();
66
+ const result = spawnSync(bunPath, bunArgs, {
67
+ stdio: ["ignore", "inherit", "inherit"],
68
+ env: process.env,
69
+ });
70
+ process.exit(result.status ?? 1);
71
+ }