@cognistore/mcp-server 1.3.0 → 1.4.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/index.js +200 -18
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -537,11 +537,28 @@ var KnowledgeRepository = class {
|
|
|
537
537
|
conditions.push(sql`${knowledgeEntries.scope} = ${filters.scope}`);
|
|
538
538
|
return this.db.select().from(knowledgeEntries).where(and(...conditions)).orderBy(sql`${knowledgeEntries.createdAt} DESC`).limit(limit);
|
|
539
539
|
}
|
|
540
|
-
async listTags() {
|
|
540
|
+
async listTags(opts = {}) {
|
|
541
|
+
const { from, to } = opts;
|
|
542
|
+
if (from && to) {
|
|
543
|
+
const result2 = await this.db.all(sql`SELECT DISTINCT value FROM knowledge_entries, json_each(knowledge_entries.tags)
|
|
544
|
+
WHERE knowledge_entries.type != 'system'
|
|
545
|
+
AND knowledge_entries.created_at >= ${from}
|
|
546
|
+
AND knowledge_entries.created_at < ${to}`);
|
|
547
|
+
return result2.map((r) => r.value);
|
|
548
|
+
}
|
|
541
549
|
const result = await this.db.all(sql`SELECT DISTINCT value FROM knowledge_entries, json_each(knowledge_entries.tags) WHERE knowledge_entries.type != 'system'`);
|
|
542
550
|
return result.map((r) => r.value);
|
|
543
551
|
}
|
|
544
|
-
async topTags(limit = 10) {
|
|
552
|
+
async topTags(limit = 10, opts = {}) {
|
|
553
|
+
const { from, to } = opts;
|
|
554
|
+
if (from && to) {
|
|
555
|
+
const result2 = await this.db.all(sql`SELECT value as tag, COUNT(*) as count FROM knowledge_entries, json_each(knowledge_entries.tags)
|
|
556
|
+
WHERE knowledge_entries.type != 'system'
|
|
557
|
+
AND knowledge_entries.created_at >= ${from}
|
|
558
|
+
AND knowledge_entries.created_at < ${to}
|
|
559
|
+
GROUP BY value ORDER BY count DESC LIMIT ${limit}`);
|
|
560
|
+
return result2;
|
|
561
|
+
}
|
|
545
562
|
const result = await this.db.all(sql`SELECT value as tag, COUNT(*) as count FROM knowledge_entries, json_each(knowledge_entries.tags) WHERE knowledge_entries.type != 'system' GROUP BY value ORDER BY count DESC LIMIT ${limit}`);
|
|
546
563
|
return result;
|
|
547
564
|
}
|
|
@@ -553,18 +570,30 @@ var KnowledgeRepository = class {
|
|
|
553
570
|
const result = await this.db.all(sql`SELECT MAX(updated_at) as latest FROM knowledge_entries`);
|
|
554
571
|
return result[0]?.latest ?? null;
|
|
555
572
|
}
|
|
556
|
-
async countByType() {
|
|
573
|
+
async countByType(opts = {}) {
|
|
574
|
+
const { from, to } = opts;
|
|
575
|
+
const conditions = [ne(knowledgeEntries.type, "system")];
|
|
576
|
+
if (from && to) {
|
|
577
|
+
conditions.push(sql`${knowledgeEntries.createdAt} >= ${from}`);
|
|
578
|
+
conditions.push(sql`${knowledgeEntries.createdAt} < ${to}`);
|
|
579
|
+
}
|
|
557
580
|
const results = await this.db.select({
|
|
558
581
|
type: knowledgeEntries.type,
|
|
559
582
|
count: sql`count(*)`
|
|
560
|
-
}).from(knowledgeEntries).where(
|
|
583
|
+
}).from(knowledgeEntries).where(and(...conditions)).groupBy(knowledgeEntries.type);
|
|
561
584
|
return results.map((r) => ({ type: r.type, count: Number(r.count) }));
|
|
562
585
|
}
|
|
563
|
-
async countByScope() {
|
|
586
|
+
async countByScope(opts = {}) {
|
|
587
|
+
const { from, to } = opts;
|
|
588
|
+
const conditions = [ne(knowledgeEntries.type, "system")];
|
|
589
|
+
if (from && to) {
|
|
590
|
+
conditions.push(sql`${knowledgeEntries.createdAt} >= ${from}`);
|
|
591
|
+
conditions.push(sql`${knowledgeEntries.createdAt} < ${to}`);
|
|
592
|
+
}
|
|
564
593
|
const results = await this.db.select({
|
|
565
594
|
scope: knowledgeEntries.scope,
|
|
566
595
|
count: sql`count(*)`
|
|
567
|
-
}).from(knowledgeEntries).where(
|
|
596
|
+
}).from(knowledgeEntries).where(and(...conditions)).groupBy(knowledgeEntries.scope);
|
|
568
597
|
return results.map((r) => ({ scope: r.scope, count: Number(r.count) }));
|
|
569
598
|
}
|
|
570
599
|
async listAll() {
|
|
@@ -1043,11 +1072,11 @@ var KnowledgeService = class {
|
|
|
1043
1072
|
const entries = await this.repository.listRecent(limit, filters);
|
|
1044
1073
|
return entries.map((e) => this.toKnowledgeEntry(e));
|
|
1045
1074
|
}
|
|
1046
|
-
async topTags(limit = 10) {
|
|
1047
|
-
return this.repository.topTags(limit);
|
|
1075
|
+
async topTags(limit = 10, opts = {}) {
|
|
1076
|
+
return this.repository.topTags(limit, opts);
|
|
1048
1077
|
}
|
|
1049
|
-
async listTags() {
|
|
1050
|
-
return this.repository.listTags();
|
|
1078
|
+
async listTags(opts = {}) {
|
|
1079
|
+
return this.repository.listTags(opts);
|
|
1051
1080
|
}
|
|
1052
1081
|
async getStats() {
|
|
1053
1082
|
const [count, byType, byScope, lastUpdatedAt] = await Promise.all([
|
|
@@ -1058,6 +1087,12 @@ var KnowledgeService = class {
|
|
|
1058
1087
|
]);
|
|
1059
1088
|
return { total: count, byType, byScope, lastUpdatedAt };
|
|
1060
1089
|
}
|
|
1090
|
+
async countByType(opts = {}) {
|
|
1091
|
+
return this.repository.countByType(opts);
|
|
1092
|
+
}
|
|
1093
|
+
async countByScope(opts = {}) {
|
|
1094
|
+
return this.repository.countByScope(opts);
|
|
1095
|
+
}
|
|
1061
1096
|
// ─── Plans (separate entity) ────────────────────────────────
|
|
1062
1097
|
async createPlan(input) {
|
|
1063
1098
|
const { tasks, skipDedup, ...planInput } = input;
|
|
@@ -1498,11 +1533,13 @@ var TokenUsageScanner = class {
|
|
|
1498
1533
|
batch = [];
|
|
1499
1534
|
};
|
|
1500
1535
|
for await (const { record, filePath, byteOffset, mtime } of adapter.scan((fp) => this.repo.getScanState(adapter.name, fp))) {
|
|
1501
|
-
|
|
1536
|
+
if (record) {
|
|
1537
|
+
batch.push(record);
|
|
1538
|
+
if (batch.length >= BATCH_SIZE)
|
|
1539
|
+
flush();
|
|
1540
|
+
}
|
|
1502
1541
|
offsets.set(filePath, { offset: byteOffset, mtime });
|
|
1503
1542
|
stats.scanned++;
|
|
1504
|
-
if (batch.length >= BATCH_SIZE)
|
|
1505
|
-
flush();
|
|
1506
1543
|
}
|
|
1507
1544
|
flush();
|
|
1508
1545
|
for (const [filePath, { offset, mtime }] of offsets) {
|
|
@@ -1656,6 +1693,135 @@ var ClaudeCodeAdapter = class {
|
|
|
1656
1693
|
}
|
|
1657
1694
|
};
|
|
1658
1695
|
|
|
1696
|
+
// ../../packages/core/dist/services/token-usage/adapters/copilot-cli.js
|
|
1697
|
+
import { createHash as createHash2 } from "crypto";
|
|
1698
|
+
import { existsSync as existsSync3, readdirSync as readdirSync3, statSync as statSync2, readFileSync as readFileSync2 } from "fs";
|
|
1699
|
+
import { homedir as homedir3 } from "os";
|
|
1700
|
+
import { resolve as resolve4, basename as basename2 } from "path";
|
|
1701
|
+
var SOURCE2 = "copilot-cli";
|
|
1702
|
+
function recordId2(sessionId, model, occurredAt) {
|
|
1703
|
+
const key = `${SOURCE2}|${sessionId ?? ""}|${model}|${occurredAt}`;
|
|
1704
|
+
return createHash2("sha256").update(key).digest("hex").slice(0, 32);
|
|
1705
|
+
}
|
|
1706
|
+
function parseEventsFile(filePath) {
|
|
1707
|
+
let raw;
|
|
1708
|
+
try {
|
|
1709
|
+
raw = readFileSync2(filePath, "utf8");
|
|
1710
|
+
} catch {
|
|
1711
|
+
return null;
|
|
1712
|
+
}
|
|
1713
|
+
let cwd = null;
|
|
1714
|
+
let sessionId = null;
|
|
1715
|
+
let shutdown = null;
|
|
1716
|
+
for (const line of raw.split("\n")) {
|
|
1717
|
+
if (!line)
|
|
1718
|
+
continue;
|
|
1719
|
+
let evt;
|
|
1720
|
+
try {
|
|
1721
|
+
evt = JSON.parse(line);
|
|
1722
|
+
} catch {
|
|
1723
|
+
continue;
|
|
1724
|
+
}
|
|
1725
|
+
if (!evt || typeof evt !== "object")
|
|
1726
|
+
continue;
|
|
1727
|
+
if (evt.type === "session.start") {
|
|
1728
|
+
const data = evt.data ?? {};
|
|
1729
|
+
sessionId = data.sessionId ?? sessionId;
|
|
1730
|
+
const ctx = data.context ?? {};
|
|
1731
|
+
cwd = ctx.cwd ?? cwd;
|
|
1732
|
+
} else if (evt.type === "session.shutdown") {
|
|
1733
|
+
const data = evt.data ?? {};
|
|
1734
|
+
const modelMetrics = data.modelMetrics;
|
|
1735
|
+
if (!modelMetrics || typeof modelMetrics !== "object")
|
|
1736
|
+
continue;
|
|
1737
|
+
const perModel = [];
|
|
1738
|
+
for (const [model, payload] of Object.entries(modelMetrics)) {
|
|
1739
|
+
const usage = payload?.usage;
|
|
1740
|
+
if (!usage || typeof usage !== "object")
|
|
1741
|
+
continue;
|
|
1742
|
+
perModel.push({
|
|
1743
|
+
model,
|
|
1744
|
+
inputTokens: Number(usage.inputTokens ?? 0) || 0,
|
|
1745
|
+
outputTokens: Number(usage.outputTokens ?? 0) || 0,
|
|
1746
|
+
cacheReadTokens: Number(usage.cacheReadTokens ?? 0) || 0,
|
|
1747
|
+
cacheCreationTokens: Number(usage.cacheWriteTokens ?? 0) || 0
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1750
|
+
if (perModel.length === 0)
|
|
1751
|
+
continue;
|
|
1752
|
+
shutdown = {
|
|
1753
|
+
occurredAt: evt.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1754
|
+
sessionId,
|
|
1755
|
+
cwd,
|
|
1756
|
+
perModel
|
|
1757
|
+
};
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
return shutdown;
|
|
1761
|
+
}
|
|
1762
|
+
var CopilotCliAdapter = class {
|
|
1763
|
+
name = SOURCE2;
|
|
1764
|
+
sessionStateDir;
|
|
1765
|
+
constructor(options = {}) {
|
|
1766
|
+
this.sessionStateDir = options.sessionStateDir ?? resolve4(homedir3(), ".copilot", "session-state");
|
|
1767
|
+
}
|
|
1768
|
+
async *scan(getState) {
|
|
1769
|
+
if (!existsSync3(this.sessionStateDir))
|
|
1770
|
+
return;
|
|
1771
|
+
let entries;
|
|
1772
|
+
try {
|
|
1773
|
+
entries = readdirSync3(this.sessionStateDir);
|
|
1774
|
+
} catch {
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1777
|
+
for (const entry of entries) {
|
|
1778
|
+
const sessionDir = resolve4(this.sessionStateDir, entry);
|
|
1779
|
+
let stat;
|
|
1780
|
+
try {
|
|
1781
|
+
stat = statSync2(sessionDir);
|
|
1782
|
+
} catch {
|
|
1783
|
+
continue;
|
|
1784
|
+
}
|
|
1785
|
+
if (!stat.isDirectory())
|
|
1786
|
+
continue;
|
|
1787
|
+
const filePath = resolve4(sessionDir, "events.jsonl");
|
|
1788
|
+
let fstat;
|
|
1789
|
+
try {
|
|
1790
|
+
fstat = statSync2(filePath);
|
|
1791
|
+
} catch {
|
|
1792
|
+
continue;
|
|
1793
|
+
}
|
|
1794
|
+
const fileSize = fstat.size;
|
|
1795
|
+
const mtime = fstat.mtime.toISOString();
|
|
1796
|
+
const state = getState(filePath);
|
|
1797
|
+
if (state && state.lastOffset >= fileSize)
|
|
1798
|
+
continue;
|
|
1799
|
+
const parsed = parseEventsFile(filePath);
|
|
1800
|
+
if (!parsed) {
|
|
1801
|
+
yield { record: null, filePath, byteOffset: fileSize, mtime };
|
|
1802
|
+
continue;
|
|
1803
|
+
}
|
|
1804
|
+
const project = parsed.cwd ? basename2(parsed.cwd) : null;
|
|
1805
|
+
for (const m of parsed.perModel) {
|
|
1806
|
+
const record = {
|
|
1807
|
+
id: recordId2(parsed.sessionId, m.model, parsed.occurredAt),
|
|
1808
|
+
source: SOURCE2,
|
|
1809
|
+
model: m.model,
|
|
1810
|
+
project,
|
|
1811
|
+
sessionId: parsed.sessionId,
|
|
1812
|
+
messageId: null,
|
|
1813
|
+
occurredAt: parsed.occurredAt,
|
|
1814
|
+
inputTokens: m.inputTokens,
|
|
1815
|
+
outputTokens: m.outputTokens,
|
|
1816
|
+
cacheReadTokens: m.cacheReadTokens,
|
|
1817
|
+
cacheCreationTokens: m.cacheCreationTokens
|
|
1818
|
+
};
|
|
1819
|
+
yield { record, filePath, byteOffset: fileSize, mtime };
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
};
|
|
1824
|
+
|
|
1659
1825
|
// ../../packages/core/dist/services/token-usage/service.js
|
|
1660
1826
|
var DEFAULT_TOP_SESSIONS = 20;
|
|
1661
1827
|
var TokenUsageService = class {
|
|
@@ -1663,7 +1829,7 @@ var TokenUsageService = class {
|
|
|
1663
1829
|
scanner;
|
|
1664
1830
|
constructor(repo, adapters) {
|
|
1665
1831
|
this.repo = repo;
|
|
1666
|
-
this.scanner = new TokenUsageScanner(repo, adapters ?? [new ClaudeCodeAdapter()]);
|
|
1832
|
+
this.scanner = new TokenUsageScanner(repo, adapters ?? [new ClaudeCodeAdapter(), new CopilotCliAdapter()]);
|
|
1667
1833
|
}
|
|
1668
1834
|
scan() {
|
|
1669
1835
|
return this.scanner.scanAll();
|
|
@@ -2001,22 +2167,38 @@ var KnowledgeSDK = class {
|
|
|
2001
2167
|
throw this.wrapError(error, "Failed to list recent knowledge");
|
|
2002
2168
|
}
|
|
2003
2169
|
}
|
|
2004
|
-
async getTopTags(limit = 10) {
|
|
2170
|
+
async getTopTags(limit = 10, opts = {}) {
|
|
2005
2171
|
this.ensureInitialized();
|
|
2006
2172
|
try {
|
|
2007
|
-
return await this.service.topTags(limit);
|
|
2173
|
+
return await this.service.topTags(limit, opts);
|
|
2008
2174
|
} catch (error) {
|
|
2009
2175
|
throw this.wrapError(error, "Failed to get top tags");
|
|
2010
2176
|
}
|
|
2011
2177
|
}
|
|
2012
|
-
async listTags() {
|
|
2178
|
+
async listTags(opts = {}) {
|
|
2013
2179
|
this.ensureInitialized();
|
|
2014
2180
|
try {
|
|
2015
|
-
return await this.service.listTags();
|
|
2181
|
+
return await this.service.listTags(opts);
|
|
2016
2182
|
} catch (error) {
|
|
2017
2183
|
throw this.wrapError(error, "Failed to list tags");
|
|
2018
2184
|
}
|
|
2019
2185
|
}
|
|
2186
|
+
async countByType(opts = {}) {
|
|
2187
|
+
this.ensureInitialized();
|
|
2188
|
+
try {
|
|
2189
|
+
return await this.service.countByType(opts);
|
|
2190
|
+
} catch (error) {
|
|
2191
|
+
throw this.wrapError(error, "Failed to count by type");
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
async countByScope(opts = {}) {
|
|
2195
|
+
this.ensureInitialized();
|
|
2196
|
+
try {
|
|
2197
|
+
return await this.service.countByScope(opts);
|
|
2198
|
+
} catch (error) {
|
|
2199
|
+
throw this.wrapError(error, "Failed to count by scope");
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2020
2202
|
async getStats() {
|
|
2021
2203
|
this.ensureInitialized();
|
|
2022
2204
|
try {
|