cogpit-memory 0.1.3 → 0.1.5
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 +13 -7
- package/dist/cli.js +71 -14
- package/dist/index.js +43 -9
- package/package.json +1 -1
- package/skill/SKILL.md +4 -1
package/README.md
CHANGED
|
@@ -40,14 +40,14 @@ cogpit-memory search "authentication"
|
|
|
40
40
|
cogpit-memory sessions # Recent sessions (last 7 days)
|
|
41
41
|
cogpit-memory sessions --cwd /path/to/project # Filter by project
|
|
42
42
|
cogpit-memory sessions --current --cwd /path/to/project # Most recent for a project
|
|
43
|
-
cogpit-memory sessions --max-age
|
|
43
|
+
cogpit-memory sessions --max-age 90d --limit 50 # Custom window
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
| Flag | Default | Description |
|
|
47
47
|
|------|---------|-------------|
|
|
48
48
|
| `--cwd` | all | Filter by working directory |
|
|
49
49
|
| `--limit` | `20` | Max results |
|
|
50
|
-
| `--max-age` | `7d` | Time window (`7d`, `12h`, `
|
|
50
|
+
| `--max-age` | `7d` | Time window — any duration (`7d`, `12h`, `90d`, `365d`) |
|
|
51
51
|
| `--current` | — | Most recent session for `--cwd` |
|
|
52
52
|
|
|
53
53
|
### `context` — Layered session drill-down
|
|
@@ -72,16 +72,20 @@ cogpit-memory search "authentication" # Cross-session sea
|
|
|
72
72
|
cogpit-memory search "auth" --session <sessionId> # Single session
|
|
73
73
|
cogpit-memory search "bug" --max-age 30d --limit 50 # Custom window
|
|
74
74
|
cogpit-memory search "AuthProvider" --case-sensitive # Case-sensitive
|
|
75
|
+
cogpit-memory search "auth" --limit 200 --session-limit 50 # 50 unique sessions
|
|
76
|
+
cogpit-memory search "bug" --session-limit 20 --hits-per-session 2 # Compact results
|
|
75
77
|
```
|
|
76
78
|
|
|
77
79
|
| Flag | Default | Description |
|
|
78
80
|
|------|---------|-------------|
|
|
79
81
|
| `--session` | all | Scope to single session |
|
|
80
|
-
| `--max-age` | `5d` | Time window |
|
|
81
|
-
| `--limit` | `20` | Max
|
|
82
|
+
| `--max-age` | `5d` | Time window — any duration (`5d`, `30d`, `365d`) |
|
|
83
|
+
| `--limit` | `20` | Max total hits returned |
|
|
84
|
+
| `--session-limit` | all | Cap unique sessions in results |
|
|
85
|
+
| `--hits-per-session` | all | Max hits kept per session |
|
|
82
86
|
| `--case-sensitive` | `false` | Case sensitivity |
|
|
83
87
|
|
|
84
|
-
Each hit includes a `location` string (e.g. `turn/3/assistantMessage`, `agent/a7f3bc2/toolCall/tc1/result`) that maps directly to L2/L3 drill-down commands.
|
|
88
|
+
Each result includes the `cwd` (working directory where the session ran) and an array of hits. Each hit includes a `location` string (e.g. `turn/3/assistantMessage`, `agent/a7f3bc2/toolCall/tc1/result`) that maps directly to L2/L3 drill-down commands.
|
|
85
89
|
|
|
86
90
|
### `index` — Manage the FTS5 search index
|
|
87
91
|
|
|
@@ -151,9 +155,11 @@ Browse at [skills.sh](https://skills.sh).
|
|
|
151
155
|
|
|
152
156
|
### Install via cogpit-memory CLI
|
|
153
157
|
|
|
154
|
-
Installs into a single project's `.claude/skills/`:
|
|
155
|
-
|
|
156
158
|
```bash
|
|
159
|
+
# Install globally (all projects)
|
|
160
|
+
npx cogpit-memory install-skill -g
|
|
161
|
+
|
|
162
|
+
# Install into a single project's .claude/skills/
|
|
157
163
|
npx cogpit-memory install-skill
|
|
158
164
|
|
|
159
165
|
# Or specify a project directory
|
package/dist/cli.js
CHANGED
|
@@ -812,7 +812,7 @@ var SearchIndex = class {
|
|
|
812
812
|
const caseSensitive = opts?.caseSensitive ?? false;
|
|
813
813
|
const ftsQuery = `"${query.replace(/"/g, '""')}"`;
|
|
814
814
|
let sql = `
|
|
815
|
-
SELECT sc.session_id, sc.location,
|
|
815
|
+
SELECT sc.session_id, sc.source_file, sc.location,
|
|
816
816
|
snippet(search_content, 3, '', '', '...', 120) as snippet
|
|
817
817
|
FROM search_content sc
|
|
818
818
|
`;
|
|
@@ -835,6 +835,7 @@ var SearchIndex = class {
|
|
|
835
835
|
const rows = this.db.prepare(sql).all(...params);
|
|
836
836
|
let hits = rows.map((row) => ({
|
|
837
837
|
sessionId: row.session_id,
|
|
838
|
+
filePath: row.source_file,
|
|
838
839
|
location: row.location,
|
|
839
840
|
snippet: row.snippet,
|
|
840
841
|
matchCount: 1
|
|
@@ -1213,20 +1214,21 @@ async function searchSessions(query, opts, searchIndex) {
|
|
|
1213
1214
|
});
|
|
1214
1215
|
const grouped = /* @__PURE__ */ new Map();
|
|
1215
1216
|
for (const hit of hits) {
|
|
1216
|
-
let
|
|
1217
|
-
if (!
|
|
1218
|
-
|
|
1219
|
-
grouped.set(hit.sessionId,
|
|
1217
|
+
let entry = grouped.get(hit.sessionId);
|
|
1218
|
+
if (!entry) {
|
|
1219
|
+
entry = { filePath: hit.filePath, hits: [] };
|
|
1220
|
+
grouped.set(hit.sessionId, entry);
|
|
1220
1221
|
}
|
|
1221
|
-
|
|
1222
|
+
entry.hits.push({
|
|
1222
1223
|
location: hit.location,
|
|
1223
1224
|
snippet: hit.snippet,
|
|
1224
1225
|
matchCount: hit.matchCount
|
|
1225
1226
|
});
|
|
1226
1227
|
}
|
|
1227
1228
|
const results = [];
|
|
1228
|
-
for (const [sid,
|
|
1229
|
-
|
|
1229
|
+
for (const [sid, entry] of grouped) {
|
|
1230
|
+
const cwd = await cwdFromFilePath(entry.filePath);
|
|
1231
|
+
results.push({ sessionId: sid, cwd, hits: entry.hits });
|
|
1230
1232
|
}
|
|
1231
1233
|
let totalHits = hits.length;
|
|
1232
1234
|
let sessionsSearched = grouped.size;
|
|
@@ -1252,6 +1254,37 @@ async function searchSessions(query, opts, searchIndex) {
|
|
|
1252
1254
|
}
|
|
1253
1255
|
return rawScanSearch(query, opts.sessionId ?? null, maxAgeMs, limit, caseSensitive, depth);
|
|
1254
1256
|
}
|
|
1257
|
+
var CWD_READ_BYTES = 4096;
|
|
1258
|
+
var cwdCache = /* @__PURE__ */ new Map();
|
|
1259
|
+
async function cwdFromFilePath(filePath) {
|
|
1260
|
+
const cached = cwdCache.get(filePath);
|
|
1261
|
+
if (cached !== void 0) return cached;
|
|
1262
|
+
try {
|
|
1263
|
+
const fh = await (0, import_promises2.open)(filePath, "r");
|
|
1264
|
+
try {
|
|
1265
|
+
const buf = Buffer.alloc(CWD_READ_BYTES);
|
|
1266
|
+
const { bytesRead } = await fh.read(buf, 0, CWD_READ_BYTES, 0);
|
|
1267
|
+
const head = buf.subarray(0, bytesRead).toString("utf-8");
|
|
1268
|
+
const lines = head.split("\n", 10);
|
|
1269
|
+
for (const line of lines) {
|
|
1270
|
+
if (!line) continue;
|
|
1271
|
+
try {
|
|
1272
|
+
const obj = JSON.parse(line);
|
|
1273
|
+
if (obj.cwd) {
|
|
1274
|
+
cwdCache.set(filePath, obj.cwd);
|
|
1275
|
+
return obj.cwd;
|
|
1276
|
+
}
|
|
1277
|
+
} catch {
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
} finally {
|
|
1281
|
+
await fh.close();
|
|
1282
|
+
}
|
|
1283
|
+
} catch {
|
|
1284
|
+
}
|
|
1285
|
+
cwdCache.set(filePath, "");
|
|
1286
|
+
return "";
|
|
1287
|
+
}
|
|
1255
1288
|
var SNIPPET_WINDOW = 150;
|
|
1256
1289
|
function generateSnippet(text, matchIdx, queryLen) {
|
|
1257
1290
|
if (matchIdx === -1) return text.slice(0, SNIPPET_WINDOW);
|
|
@@ -1450,6 +1483,7 @@ async function rawScanSearch(query, sessionId, maxAgeMs, limit, caseSensitive, d
|
|
|
1450
1483
|
totalHits += allHits.length;
|
|
1451
1484
|
const sessionResult = {
|
|
1452
1485
|
sessionId: session.sessionId || (0, import_node_path4.basename)(file.path, ".jsonl"),
|
|
1486
|
+
cwd: session.cwd || "",
|
|
1453
1487
|
hits: []
|
|
1454
1488
|
};
|
|
1455
1489
|
for (const hit of allHits) {
|
|
@@ -1469,7 +1503,7 @@ async function rawScanSearch(query, sessionId, maxAgeMs, limit, caseSensitive, d
|
|
|
1469
1503
|
sessionsSearched,
|
|
1470
1504
|
results
|
|
1471
1505
|
};
|
|
1472
|
-
} catch
|
|
1506
|
+
} catch {
|
|
1473
1507
|
return {
|
|
1474
1508
|
query,
|
|
1475
1509
|
totalHits: 0,
|
|
@@ -2093,9 +2127,9 @@ function findSkillContent() {
|
|
|
2093
2127
|
}
|
|
2094
2128
|
throw new Error("Could not find SKILL.md \u2014 try reinstalling cogpit-memory");
|
|
2095
2129
|
}
|
|
2096
|
-
function installSkill(cwd) {
|
|
2097
|
-
const root = cwd ?? process.cwd();
|
|
2098
|
-
const skillDir = (0, import_node_path8.join)(root, "
|
|
2130
|
+
function installSkill(cwd, global) {
|
|
2131
|
+
const root = global ? (0, import_node_path8.join)(process.env.HOME ?? process.env.USERPROFILE ?? "~", ".claude") : (0, import_node_path8.join)(cwd ?? process.cwd(), ".claude");
|
|
2132
|
+
const skillDir = (0, import_node_path8.join)(root, "skills", "cogpit-memory");
|
|
2099
2133
|
(0, import_node_fs4.mkdirSync)(skillDir, { recursive: true });
|
|
2100
2134
|
const content = findSkillContent();
|
|
2101
2135
|
const dest = (0, import_node_path8.join)(skillDir, "SKILL.md");
|
|
@@ -2121,6 +2155,12 @@ function parseArgs(argv) {
|
|
|
2121
2155
|
case "--limit":
|
|
2122
2156
|
args.limit = parseInt(argv[++i], 10);
|
|
2123
2157
|
break;
|
|
2158
|
+
case "--session-limit":
|
|
2159
|
+
args.sessionLimit = parseInt(argv[++i], 10);
|
|
2160
|
+
break;
|
|
2161
|
+
case "--hits-per-session":
|
|
2162
|
+
args.hitsPerSession = parseInt(argv[++i], 10);
|
|
2163
|
+
break;
|
|
2124
2164
|
case "--case-sensitive":
|
|
2125
2165
|
args.caseSensitive = true;
|
|
2126
2166
|
break;
|
|
@@ -2171,6 +2211,10 @@ function parseArgs(argv) {
|
|
|
2171
2211
|
case "--cwd":
|
|
2172
2212
|
args.cwd = argv[++i];
|
|
2173
2213
|
break;
|
|
2214
|
+
case "-g":
|
|
2215
|
+
case "--global":
|
|
2216
|
+
args.global = true;
|
|
2217
|
+
break;
|
|
2174
2218
|
}
|
|
2175
2219
|
}
|
|
2176
2220
|
break;
|
|
@@ -2198,6 +2242,15 @@ async function main() {
|
|
|
2198
2242
|
limit: cmd.args.limit,
|
|
2199
2243
|
caseSensitive: cmd.args.caseSensitive
|
|
2200
2244
|
});
|
|
2245
|
+
if (result && !("error" in result) && (cmd.args.sessionLimit || cmd.args.hitsPerSession)) {
|
|
2246
|
+
const sl = cmd.args.sessionLimit ?? result.results.length;
|
|
2247
|
+
const hpp = cmd.args.hitsPerSession ?? Infinity;
|
|
2248
|
+
result.results = result.results.slice(0, sl).map((sr) => ({
|
|
2249
|
+
...sr,
|
|
2250
|
+
hits: sr.hits.slice(0, hpp)
|
|
2251
|
+
}));
|
|
2252
|
+
result.returnedHits = result.results.reduce((n, sr) => n + sr.hits.length, 0);
|
|
2253
|
+
}
|
|
2201
2254
|
break;
|
|
2202
2255
|
case "context":
|
|
2203
2256
|
if (!cmd.args.sessionId) {
|
|
@@ -2233,7 +2286,7 @@ async function main() {
|
|
|
2233
2286
|
}
|
|
2234
2287
|
break;
|
|
2235
2288
|
case "install-skill":
|
|
2236
|
-
result = installSkill(cmd.args.cwd);
|
|
2289
|
+
result = installSkill(cmd.args.cwd, cmd.args.global);
|
|
2237
2290
|
break;
|
|
2238
2291
|
default:
|
|
2239
2292
|
console.error(JSON.stringify({ error: `Unknown command: ${cmd.command}` }));
|
|
@@ -2250,6 +2303,8 @@ Commands:
|
|
|
2250
2303
|
--session <id> Scope to single session
|
|
2251
2304
|
--max-age <5d> Time window (default: 5d)
|
|
2252
2305
|
--limit <20> Max hits (default: 20)
|
|
2306
|
+
--session-limit <N> Cap unique sessions returned
|
|
2307
|
+
--hits-per-session <N> Max hits kept per session
|
|
2253
2308
|
--case-sensitive Case sensitive matching
|
|
2254
2309
|
|
|
2255
2310
|
context <sessionId> Session overview (L1)
|
|
@@ -2265,7 +2320,9 @@ Commands:
|
|
|
2265
2320
|
index stats Show index stats
|
|
2266
2321
|
index rebuild Rebuild full index
|
|
2267
2322
|
|
|
2268
|
-
install-skill [
|
|
2323
|
+
install-skill [options] Install Claude Code skill
|
|
2324
|
+
--cwd <path> Target project directory
|
|
2325
|
+
-g, --global Install to ~/.claude/skills/ (all projects)
|
|
2269
2326
|
`);
|
|
2270
2327
|
}
|
|
2271
2328
|
var isBunCompiled = false;
|
package/dist/index.js
CHANGED
|
@@ -898,7 +898,7 @@ var SearchIndex = class {
|
|
|
898
898
|
const caseSensitive = opts?.caseSensitive ?? false;
|
|
899
899
|
const ftsQuery = `"${query.replace(/"/g, '""')}"`;
|
|
900
900
|
let sql = `
|
|
901
|
-
SELECT sc.session_id, sc.location,
|
|
901
|
+
SELECT sc.session_id, sc.source_file, sc.location,
|
|
902
902
|
snippet(search_content, 3, '', '', '...', 120) as snippet
|
|
903
903
|
FROM search_content sc
|
|
904
904
|
`;
|
|
@@ -921,6 +921,7 @@ var SearchIndex = class {
|
|
|
921
921
|
const rows = this.db.prepare(sql).all(...params);
|
|
922
922
|
let hits = rows.map((row) => ({
|
|
923
923
|
sessionId: row.session_id,
|
|
924
|
+
filePath: row.source_file,
|
|
924
925
|
location: row.location,
|
|
925
926
|
snippet: row.snippet,
|
|
926
927
|
matchCount: 1
|
|
@@ -1304,20 +1305,21 @@ async function searchSessions(query, opts, searchIndex) {
|
|
|
1304
1305
|
});
|
|
1305
1306
|
const grouped = /* @__PURE__ */ new Map();
|
|
1306
1307
|
for (const hit of hits) {
|
|
1307
|
-
let
|
|
1308
|
-
if (!
|
|
1309
|
-
|
|
1310
|
-
grouped.set(hit.sessionId,
|
|
1308
|
+
let entry = grouped.get(hit.sessionId);
|
|
1309
|
+
if (!entry) {
|
|
1310
|
+
entry = { filePath: hit.filePath, hits: [] };
|
|
1311
|
+
grouped.set(hit.sessionId, entry);
|
|
1311
1312
|
}
|
|
1312
|
-
|
|
1313
|
+
entry.hits.push({
|
|
1313
1314
|
location: hit.location,
|
|
1314
1315
|
snippet: hit.snippet,
|
|
1315
1316
|
matchCount: hit.matchCount
|
|
1316
1317
|
});
|
|
1317
1318
|
}
|
|
1318
1319
|
const results = [];
|
|
1319
|
-
for (const [sid,
|
|
1320
|
-
|
|
1320
|
+
for (const [sid, entry] of grouped) {
|
|
1321
|
+
const cwd = await cwdFromFilePath(entry.filePath);
|
|
1322
|
+
results.push({ sessionId: sid, cwd, hits: entry.hits });
|
|
1321
1323
|
}
|
|
1322
1324
|
let totalHits = hits.length;
|
|
1323
1325
|
let sessionsSearched = grouped.size;
|
|
@@ -1343,6 +1345,37 @@ async function searchSessions(query, opts, searchIndex) {
|
|
|
1343
1345
|
}
|
|
1344
1346
|
return rawScanSearch(query, opts.sessionId ?? null, maxAgeMs, limit, caseSensitive, depth);
|
|
1345
1347
|
}
|
|
1348
|
+
var CWD_READ_BYTES = 4096;
|
|
1349
|
+
var cwdCache = /* @__PURE__ */ new Map();
|
|
1350
|
+
async function cwdFromFilePath(filePath) {
|
|
1351
|
+
const cached = cwdCache.get(filePath);
|
|
1352
|
+
if (cached !== void 0) return cached;
|
|
1353
|
+
try {
|
|
1354
|
+
const fh = await (0, import_promises2.open)(filePath, "r");
|
|
1355
|
+
try {
|
|
1356
|
+
const buf = Buffer.alloc(CWD_READ_BYTES);
|
|
1357
|
+
const { bytesRead } = await fh.read(buf, 0, CWD_READ_BYTES, 0);
|
|
1358
|
+
const head = buf.subarray(0, bytesRead).toString("utf-8");
|
|
1359
|
+
const lines = head.split("\n", 10);
|
|
1360
|
+
for (const line of lines) {
|
|
1361
|
+
if (!line) continue;
|
|
1362
|
+
try {
|
|
1363
|
+
const obj = JSON.parse(line);
|
|
1364
|
+
if (obj.cwd) {
|
|
1365
|
+
cwdCache.set(filePath, obj.cwd);
|
|
1366
|
+
return obj.cwd;
|
|
1367
|
+
}
|
|
1368
|
+
} catch {
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
} finally {
|
|
1372
|
+
await fh.close();
|
|
1373
|
+
}
|
|
1374
|
+
} catch {
|
|
1375
|
+
}
|
|
1376
|
+
cwdCache.set(filePath, "");
|
|
1377
|
+
return "";
|
|
1378
|
+
}
|
|
1346
1379
|
var SNIPPET_WINDOW = 150;
|
|
1347
1380
|
function generateSnippet(text, matchIdx, queryLen) {
|
|
1348
1381
|
if (matchIdx === -1) return text.slice(0, SNIPPET_WINDOW);
|
|
@@ -1541,6 +1574,7 @@ async function rawScanSearch(query, sessionId, maxAgeMs, limit, caseSensitive, d
|
|
|
1541
1574
|
totalHits += allHits.length;
|
|
1542
1575
|
const sessionResult = {
|
|
1543
1576
|
sessionId: session.sessionId || (0, import_node_path4.basename)(file.path, ".jsonl"),
|
|
1577
|
+
cwd: session.cwd || "",
|
|
1544
1578
|
hits: []
|
|
1545
1579
|
};
|
|
1546
1580
|
for (const hit of allHits) {
|
|
@@ -1560,7 +1594,7 @@ async function rawScanSearch(query, sessionId, maxAgeMs, limit, caseSensitive, d
|
|
|
1560
1594
|
sessionsSearched,
|
|
1561
1595
|
results
|
|
1562
1596
|
};
|
|
1563
|
-
} catch
|
|
1597
|
+
} catch {
|
|
1564
1598
|
return {
|
|
1565
1599
|
query,
|
|
1566
1600
|
totalHits: 0,
|
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -248,7 +248,9 @@ bunx cogpit-memory search "AuthProvider" --case-sensitive
|
|
|
248
248
|
|------|---------|-------------|
|
|
249
249
|
| `--session` | all sessions | Scope to single session |
|
|
250
250
|
| `--max-age` | `5d` | Time window: `5d`, `12h`, `30d` |
|
|
251
|
-
| `--limit` | `20` | Max
|
|
251
|
+
| `--limit` | `20` | Max total hits returned |
|
|
252
|
+
| `--session-limit` | all | Cap unique sessions in results |
|
|
253
|
+
| `--hits-per-session` | all | Max hits kept per session |
|
|
252
254
|
| `--case-sensitive` | `false` | Case sensitivity |
|
|
253
255
|
|
|
254
256
|
### Response shape
|
|
@@ -262,6 +264,7 @@ bunx cogpit-memory search "AuthProvider" --case-sensitive
|
|
|
262
264
|
"results": [
|
|
263
265
|
{
|
|
264
266
|
"sessionId": "abc-123",
|
|
267
|
+
"cwd": "/path/to/project",
|
|
265
268
|
"hits": [
|
|
266
269
|
{
|
|
267
270
|
"location": "turn/3/userMessage",
|