@hiveai/mcp 0.2.16 → 0.3.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/README.md +44 -4
- package/dist/index.js +192 -24
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +13 -0
- package/dist/server.js +192 -24
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
package/dist/server.d.ts
CHANGED
|
@@ -10,11 +10,24 @@ interface CreateContextOptions {
|
|
|
10
10
|
cwd?: string;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
declare class SessionTracker {
|
|
14
|
+
private events;
|
|
15
|
+
private startedAt;
|
|
16
|
+
private config;
|
|
17
|
+
private ctx;
|
|
18
|
+
private shutdownRegistered;
|
|
19
|
+
constructor(ctx: HaiveContext);
|
|
20
|
+
init(): Promise<void>;
|
|
21
|
+
record(tool: string, summary?: string): void;
|
|
22
|
+
private registerShutdownHandler;
|
|
23
|
+
}
|
|
24
|
+
|
|
13
25
|
declare const SERVER_NAME = "haive";
|
|
14
26
|
declare const SERVER_VERSION: string;
|
|
15
27
|
declare function createHaiveServer(options?: CreateContextOptions): {
|
|
16
28
|
server: McpServer;
|
|
17
29
|
context: HaiveContext;
|
|
30
|
+
tracker: SessionTracker;
|
|
18
31
|
};
|
|
19
32
|
|
|
20
33
|
export { SERVER_NAME, SERVER_VERSION, createHaiveServer };
|
package/dist/server.js
CHANGED
|
@@ -125,6 +125,7 @@ import { existsSync as existsSync4 } from "fs";
|
|
|
125
125
|
import path3 from "path";
|
|
126
126
|
import {
|
|
127
127
|
buildFrontmatter,
|
|
128
|
+
loadConfig,
|
|
128
129
|
loadMemoriesFromDir as loadMemoriesFromDir2,
|
|
129
130
|
memoryFilePath,
|
|
130
131
|
serializeMemory
|
|
@@ -202,10 +203,12 @@ async function memSave(input, ctx) {
|
|
|
202
203
|
};
|
|
203
204
|
}
|
|
204
205
|
}
|
|
206
|
+
const haiveConfig = await loadConfig(ctx.paths);
|
|
207
|
+
const resolvedScope = input.scope !== "personal" ? input.scope : haiveConfig.defaultScope ?? "personal";
|
|
205
208
|
const frontmatter = buildFrontmatter({
|
|
206
209
|
type: input.type,
|
|
207
210
|
slug: input.slug,
|
|
208
|
-
scope:
|
|
211
|
+
scope: resolvedScope,
|
|
209
212
|
module: input.module,
|
|
210
213
|
tags: input.tags,
|
|
211
214
|
domain: input.domain,
|
|
@@ -213,7 +216,8 @@ async function memSave(input, ctx) {
|
|
|
213
216
|
paths: input.paths,
|
|
214
217
|
symbols: input.symbols,
|
|
215
218
|
commit: input.commit,
|
|
216
|
-
topic: input.topic
|
|
219
|
+
topic: input.topic,
|
|
220
|
+
status: haiveConfig.defaultStatus === "validated" ? "validated" : void 0
|
|
217
221
|
});
|
|
218
222
|
const file = memoryFilePath(
|
|
219
223
|
ctx.paths,
|
|
@@ -1159,9 +1163,12 @@ import {
|
|
|
1159
1163
|
isDecaying,
|
|
1160
1164
|
literalMatchesAllTokens as literalMatchesAllTokens2,
|
|
1161
1165
|
literalMatchesAnyToken as literalMatchesAnyToken2,
|
|
1166
|
+
loadCodeMap,
|
|
1167
|
+
loadConfig as loadConfig2,
|
|
1162
1168
|
loadMemoriesFromDir as loadMemoriesFromDir13,
|
|
1163
1169
|
loadUsageIndex as loadUsageIndex7,
|
|
1164
1170
|
memoryMatchesAnchorPaths as memoryMatchesAnchorPaths2,
|
|
1171
|
+
queryCodeMap,
|
|
1165
1172
|
tokenizeQuery as tokenizeQuery2,
|
|
1166
1173
|
trackReads as trackReads3,
|
|
1167
1174
|
truncateToTokens
|
|
@@ -1185,6 +1192,9 @@ var GetBriefingInputSchema = {
|
|
|
1185
1192
|
track: z17.boolean().default(true).describe("Increment read_count on returned memories"),
|
|
1186
1193
|
format: z17.enum(["full", "compact"]).default("full").describe(
|
|
1187
1194
|
"Output format: 'full' returns complete memory bodies; 'compact' returns id + 1-line summary only (call mem_get for details)."
|
|
1195
|
+
),
|
|
1196
|
+
symbols: z17.array(z17.string()).default([]).describe(
|
|
1197
|
+
"Symbol names to look up in the code-map (e.g. ['PaymentService', 'TenantFilter']). Returns the file(s) exporting each symbol so agents don't need to grep. Requires `haive index code` to have been run."
|
|
1188
1198
|
)
|
|
1189
1199
|
};
|
|
1190
1200
|
async function getBriefing(input, ctx) {
|
|
@@ -1246,6 +1256,7 @@ async function getBriefing(input, ctx) {
|
|
|
1246
1256
|
tags: fm.tags,
|
|
1247
1257
|
status: fm.status,
|
|
1248
1258
|
confidence: deriveConfidence4(fm, u),
|
|
1259
|
+
...fm.status === "draft" || fm.status === "proposed" ? { unverified: true } : {},
|
|
1249
1260
|
read_count: u.read_count,
|
|
1250
1261
|
reasons: [reason],
|
|
1251
1262
|
match_quality: matchQuality ?? "partial",
|
|
@@ -1311,17 +1322,55 @@ async function getBriefing(input, ctx) {
|
|
|
1311
1322
|
}
|
|
1312
1323
|
const projectContextRaw = input.include_project_context && existsSync17(ctx.paths.projectContext) ? await readFile3(ctx.paths.projectContext, "utf8") : "";
|
|
1313
1324
|
const isTemplateContext = projectContextRaw.includes("TODO \u2014 high-level overview") || projectContextRaw.includes("Generated by `haive init`");
|
|
1314
|
-
const projectContext = isTemplateContext ? "" : projectContextRaw;
|
|
1315
1325
|
const setupWarnings = [];
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
);
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1326
|
+
let autoContextGenerated = false;
|
|
1327
|
+
let projectContext = isTemplateContext ? "" : projectContextRaw;
|
|
1328
|
+
if ((isTemplateContext || !existsSync17(ctx.paths.projectContext)) && input.include_project_context) {
|
|
1329
|
+
const haiveConfig = await loadConfig2(ctx.paths);
|
|
1330
|
+
if (haiveConfig.autoContext) {
|
|
1331
|
+
const codeMap = await loadCodeMap(ctx.paths);
|
|
1332
|
+
if (codeMap) {
|
|
1333
|
+
const totalFiles = Object.keys(codeMap.files).length;
|
|
1334
|
+
const extensions = /* @__PURE__ */ new Map();
|
|
1335
|
+
for (const filePath of Object.keys(codeMap.files)) {
|
|
1336
|
+
const ext = filePath.slice(filePath.lastIndexOf(".") + 1).toLowerCase();
|
|
1337
|
+
extensions.set(ext, (extensions.get(ext) ?? 0) + 1);
|
|
1338
|
+
}
|
|
1339
|
+
const topExts = [...extensions.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([e, n]) => `${e} (${n})`).join(", ");
|
|
1340
|
+
const topSymbols = Object.entries(codeMap.files).flatMap(
|
|
1341
|
+
([fp, entry]) => entry.exports.slice(0, 3).map((e) => `${e.name} (${fp.split("/").slice(-2).join("/")})`)
|
|
1342
|
+
).slice(0, 15).join(", ");
|
|
1343
|
+
projectContext = `# Project context (auto-generated by hAIve)
|
|
1344
|
+
|
|
1345
|
+
> \u26A0 This is a minimal auto-generated context based on the code-map. Invoke the \`bootstrap_project\` MCP prompt to replace it with a full analysis.
|
|
1346
|
+
|
|
1347
|
+
## Codebase overview
|
|
1348
|
+
- **${totalFiles} files** indexed in code-map
|
|
1349
|
+
- **Main file types:** ${topExts}
|
|
1350
|
+
- **Generated at:** ${codeMap.generated_at}
|
|
1351
|
+
|
|
1352
|
+
## Key exports (sample)
|
|
1353
|
+
` + topSymbols + "\n";
|
|
1354
|
+
autoContextGenerated = true;
|
|
1355
|
+
setupWarnings.push(
|
|
1356
|
+
"project-context.md is still the default template. A minimal auto-generated context has been injected from the code-map. Invoke bootstrap_project to replace it with a full AI-analyzed context."
|
|
1357
|
+
);
|
|
1358
|
+
} else {
|
|
1359
|
+
setupWarnings.push(
|
|
1360
|
+
"project-context.md is still the default template and no code-map found. Run `haive index code` then invoke bootstrap_project for a full context."
|
|
1361
|
+
);
|
|
1362
|
+
}
|
|
1363
|
+
} else {
|
|
1364
|
+
if (isTemplateContext) {
|
|
1365
|
+
setupWarnings.push(
|
|
1366
|
+
"project-context.md still contains the default template. Invoke the bootstrap_project MCP prompt to auto-fill it from your codebase. Until then, get_briefing returns no project context."
|
|
1367
|
+
);
|
|
1368
|
+
} else {
|
|
1369
|
+
setupWarnings.push(
|
|
1370
|
+
"No project-context.md found. Run `haive init` then invoke the bootstrap_project MCP prompt."
|
|
1371
|
+
);
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1325
1374
|
}
|
|
1326
1375
|
const moduleContents = input.include_module_contexts ? await loadModuleContexts2(ctx, inferred) : [];
|
|
1327
1376
|
const memoriesText = memories.map((m) => {
|
|
@@ -1384,18 +1433,51 @@ ${m.content}`).join("\n\n---\n\n"),
|
|
|
1384
1433
|
if (isDecaying(u, createdAt)) decayWarnings.push(m.id);
|
|
1385
1434
|
}
|
|
1386
1435
|
const outputMemories = input.format === "compact" ? trimmedMemories.map((m) => ({ ...m, body: compactSummary(m.body) })) : trimmedMemories;
|
|
1436
|
+
let symbolLocations;
|
|
1437
|
+
const symbolsToLookup = new Set(input.symbols);
|
|
1438
|
+
for (const m of outputMemories) {
|
|
1439
|
+
const loaded = byId.get(m.id);
|
|
1440
|
+
for (const sym of loaded?.memory.frontmatter.anchor.symbols ?? []) {
|
|
1441
|
+
symbolsToLookup.add(sym);
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
if (symbolsToLookup.size > 0) {
|
|
1445
|
+
const codeMap = await loadCodeMap(ctx.paths);
|
|
1446
|
+
if (codeMap) {
|
|
1447
|
+
symbolLocations = [];
|
|
1448
|
+
for (const sym of symbolsToLookup) {
|
|
1449
|
+
const { files } = queryCodeMap(codeMap, { symbol: sym });
|
|
1450
|
+
if (files.length > 0) {
|
|
1451
|
+
symbolLocations.push({
|
|
1452
|
+
symbol: sym,
|
|
1453
|
+
locations: files.flatMap(
|
|
1454
|
+
(f) => f.entry.exports.filter((e) => e.name.toLowerCase().includes(sym.toLowerCase())).map((e) => ({
|
|
1455
|
+
file: f.path,
|
|
1456
|
+
kind: e.kind,
|
|
1457
|
+
line: e.line,
|
|
1458
|
+
...e.description ? { description: e.description } : {}
|
|
1459
|
+
}))
|
|
1460
|
+
)
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
if (symbolLocations.length === 0) symbolLocations = void 0;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1387
1467
|
return {
|
|
1388
1468
|
...input.task ? { task: input.task } : {},
|
|
1389
1469
|
search_mode: searchMode,
|
|
1390
1470
|
inferred_modules: inferred,
|
|
1391
1471
|
...lastSession ? { last_session: lastSession } : {},
|
|
1392
|
-
project_context: projectContextRaw ? {
|
|
1472
|
+
project_context: projectContextRaw || autoContextGenerated ? {
|
|
1393
1473
|
content: projectSlice.text,
|
|
1394
1474
|
truncated: projectSlice.truncated,
|
|
1395
|
-
...isTemplateContext ? { is_template: true } : {}
|
|
1475
|
+
...isTemplateContext && !autoContextGenerated ? { is_template: true } : {},
|
|
1476
|
+
...autoContextGenerated ? { auto_generated: true } : {}
|
|
1396
1477
|
} : null,
|
|
1397
1478
|
module_contexts: trimmedModules,
|
|
1398
1479
|
memories: outputMemories,
|
|
1480
|
+
...symbolLocations ? { symbol_locations: symbolLocations } : {},
|
|
1399
1481
|
decay_warnings: decayWarnings,
|
|
1400
1482
|
setup_warnings: setupWarnings,
|
|
1401
1483
|
estimated_tokens: totalTokens,
|
|
@@ -1445,7 +1527,7 @@ async function loadModuleContexts2(ctx, modules) {
|
|
|
1445
1527
|
}
|
|
1446
1528
|
|
|
1447
1529
|
// src/tools/code-map.ts
|
|
1448
|
-
import { loadCodeMap, queryCodeMap } from "@hiveai/core";
|
|
1530
|
+
import { loadCodeMap as loadCodeMap2, queryCodeMap as queryCodeMap2 } from "@hiveai/core";
|
|
1449
1531
|
import { z as z18 } from "zod";
|
|
1450
1532
|
var CodeMapInputSchema = {
|
|
1451
1533
|
file: z18.string().optional().describe("Filter to files whose path contains this substring"),
|
|
@@ -1453,7 +1535,7 @@ var CodeMapInputSchema = {
|
|
|
1453
1535
|
max_files: z18.number().int().positive().default(40).describe("Cap on returned files")
|
|
1454
1536
|
};
|
|
1455
1537
|
async function codeMapTool(input, ctx) {
|
|
1456
|
-
const map = await
|
|
1538
|
+
const map = await loadCodeMap2(ctx.paths);
|
|
1457
1539
|
if (!map) {
|
|
1458
1540
|
return {
|
|
1459
1541
|
available: false,
|
|
@@ -1461,7 +1543,7 @@ async function codeMapTool(input, ctx) {
|
|
|
1461
1543
|
notice: "No code map found. Run `haive index code` to generate `.ai/code-map.json`."
|
|
1462
1544
|
};
|
|
1463
1545
|
}
|
|
1464
|
-
const { files } =
|
|
1546
|
+
const { files } = queryCodeMap2(map, { file: input.file, symbol: input.symbol });
|
|
1465
1547
|
return {
|
|
1466
1548
|
available: true,
|
|
1467
1549
|
generated_at: map.generated_at,
|
|
@@ -1761,9 +1843,78 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
|
|
|
1761
1843
|
};
|
|
1762
1844
|
}
|
|
1763
1845
|
|
|
1846
|
+
// src/session-tracker.ts
|
|
1847
|
+
import { loadConfig as loadConfig3 } from "@hiveai/core";
|
|
1848
|
+
var SessionTracker = class {
|
|
1849
|
+
events = [];
|
|
1850
|
+
startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1851
|
+
config = null;
|
|
1852
|
+
ctx;
|
|
1853
|
+
shutdownRegistered = false;
|
|
1854
|
+
constructor(ctx) {
|
|
1855
|
+
this.ctx = ctx;
|
|
1856
|
+
}
|
|
1857
|
+
async init() {
|
|
1858
|
+
this.config = await loadConfig3(this.ctx.paths);
|
|
1859
|
+
if (this.config.autoSessionEnd) {
|
|
1860
|
+
this.registerShutdownHandler();
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
record(tool, summary) {
|
|
1864
|
+
this.events.push({ tool, at: (/* @__PURE__ */ new Date()).toISOString(), summary });
|
|
1865
|
+
}
|
|
1866
|
+
registerShutdownHandler() {
|
|
1867
|
+
if (this.shutdownRegistered) return;
|
|
1868
|
+
this.shutdownRegistered = true;
|
|
1869
|
+
const save = async () => {
|
|
1870
|
+
const writingTools = this.events.filter(
|
|
1871
|
+
(e) => ["mem_save", "mem_tried", "mem_observe", "mem_update", "bootstrap_project_save"].includes(e.tool)
|
|
1872
|
+
);
|
|
1873
|
+
const totalCalls = this.events.length;
|
|
1874
|
+
if (totalCalls === 0) return;
|
|
1875
|
+
const toolSummary = summarizeTools(this.events);
|
|
1876
|
+
const filesSet = /* @__PURE__ */ new Set();
|
|
1877
|
+
for (const e of this.events) {
|
|
1878
|
+
if (e.summary) {
|
|
1879
|
+
const matches = e.summary.match(/[^\s"',]+\.[a-zA-Z]{1,6}/g) ?? [];
|
|
1880
|
+
for (const m of matches) filesSet.add(m);
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
try {
|
|
1884
|
+
await memSessionEnd(
|
|
1885
|
+
{
|
|
1886
|
+
goal: `Auto-captured session (${totalCalls} tool call${totalCalls === 1 ? "" : "s"})`,
|
|
1887
|
+
accomplished: toolSummary,
|
|
1888
|
+
discoveries: writingTools.length > 0 ? `${writingTools.length} memor${writingTools.length === 1 ? "y" : "ies"} saved during this session.` : "No new memories saved this session.",
|
|
1889
|
+
files_touched: [...filesSet].slice(0, 10),
|
|
1890
|
+
next_steps: "",
|
|
1891
|
+
scope: this.config?.defaultScope ?? "personal",
|
|
1892
|
+
module: void 0
|
|
1893
|
+
},
|
|
1894
|
+
this.ctx
|
|
1895
|
+
);
|
|
1896
|
+
} catch {
|
|
1897
|
+
}
|
|
1898
|
+
};
|
|
1899
|
+
process.once("SIGTERM", () => {
|
|
1900
|
+
void save().finally(() => process.exit(0));
|
|
1901
|
+
});
|
|
1902
|
+
process.once("SIGINT", () => {
|
|
1903
|
+
void save().finally(() => process.exit(0));
|
|
1904
|
+
});
|
|
1905
|
+
}
|
|
1906
|
+
};
|
|
1907
|
+
function summarizeTools(events) {
|
|
1908
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1909
|
+
for (const e of events) {
|
|
1910
|
+
counts.set(e.tool, (counts.get(e.tool) ?? 0) + 1);
|
|
1911
|
+
}
|
|
1912
|
+
return [...counts.entries()].sort((a, b) => b[1] - a[1]).map(([t, n]) => `${t} \xD7${n}`).join(", ");
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1764
1915
|
// src/server.ts
|
|
1765
1916
|
var SERVER_NAME = "haive";
|
|
1766
|
-
var SERVER_VERSION = "0.2
|
|
1917
|
+
var SERVER_VERSION = "0.3.2";
|
|
1767
1918
|
function jsonResult(data) {
|
|
1768
1919
|
return {
|
|
1769
1920
|
content: [
|
|
@@ -1776,6 +1927,8 @@ function jsonResult(data) {
|
|
|
1776
1927
|
}
|
|
1777
1928
|
function createHaiveServer(options = {}) {
|
|
1778
1929
|
const context = createContext(options);
|
|
1930
|
+
const tracker = new SessionTracker(context);
|
|
1931
|
+
void tracker.init();
|
|
1779
1932
|
const server = new McpServer(
|
|
1780
1933
|
{ name: SERVER_NAME, version: SERVER_VERSION },
|
|
1781
1934
|
{ capabilities: { tools: {}, prompts: {} } }
|
|
@@ -1784,7 +1937,10 @@ function createHaiveServer(options = {}) {
|
|
|
1784
1937
|
"mem_save",
|
|
1785
1938
|
"Save a new memory (convention, decision, gotcha, architecture, glossary). For failed approaches use mem_tried instead \u2014 it enforces a structured format that is more useful to future agents. Use scope=team to share with the whole team.",
|
|
1786
1939
|
MemSaveInputSchema,
|
|
1787
|
-
async (input) =>
|
|
1940
|
+
async (input) => {
|
|
1941
|
+
tracker.record("mem_save", input.slug);
|
|
1942
|
+
return jsonResult(await memSave(input, context));
|
|
1943
|
+
}
|
|
1788
1944
|
);
|
|
1789
1945
|
server.tool(
|
|
1790
1946
|
"mem_search",
|
|
@@ -1808,7 +1964,10 @@ function createHaiveServer(options = {}) {
|
|
|
1808
1964
|
"get_briefing",
|
|
1809
1965
|
"One-shot onboarding: returns project context + module contexts + ranked relevant memories under a token budget. Replaces 4\u20135 separate calls when an agent starts a task.",
|
|
1810
1966
|
GetBriefingInputSchema,
|
|
1811
|
-
async (input) =>
|
|
1967
|
+
async (input) => {
|
|
1968
|
+
tracker.record("get_briefing", input.task ?? "");
|
|
1969
|
+
return jsonResult(await getBriefing(input, context));
|
|
1970
|
+
}
|
|
1812
1971
|
);
|
|
1813
1972
|
server.tool(
|
|
1814
1973
|
"code_map",
|
|
@@ -1874,7 +2033,10 @@ function createHaiveServer(options = {}) {
|
|
|
1874
2033
|
"mem_tried",
|
|
1875
2034
|
"Preferred way to record a failed approach. Enforces a structured what/why_failed/instead format that is immediately actionable for future agents. Auto-validated (no approval cycle). Use whenever you tried an approach and it failed \u2014 prevents the same mistake from happening in the next session.",
|
|
1876
2035
|
MemTriedInputSchema,
|
|
1877
|
-
async (input) =>
|
|
2036
|
+
async (input) => {
|
|
2037
|
+
tracker.record("mem_tried", input.what.slice(0, 80));
|
|
2038
|
+
return jsonResult(await memTried(input, context));
|
|
2039
|
+
}
|
|
1878
2040
|
);
|
|
1879
2041
|
server.tool(
|
|
1880
2042
|
"mem_diff",
|
|
@@ -1886,13 +2048,19 @@ function createHaiveServer(options = {}) {
|
|
|
1886
2048
|
"mem_observe",
|
|
1887
2049
|
"Capture a code-level discovery made during exploration: a bug, inconsistency, missing config, or security gap found by reading existing code that was NOT in the briefing. Use this whenever you read code and spot something that could silently break in production. Auto-validated, anchored to file paths for staleness detection. Prefer this over mem_save for reactive discoveries during code reading.",
|
|
1888
2050
|
MemObserveInputSchema,
|
|
1889
|
-
async (input) =>
|
|
2051
|
+
async (input) => {
|
|
2052
|
+
tracker.record("mem_observe", input.where);
|
|
2053
|
+
return jsonResult(await memObserve(input, context));
|
|
2054
|
+
}
|
|
1890
2055
|
);
|
|
1891
2056
|
server.tool(
|
|
1892
2057
|
"mem_session_end",
|
|
1893
2058
|
"Save a structured end-of-session recap (goal / accomplished / discoveries / next steps). Uses topic-upsert: one recap per scope is kept and updated in-place so the next session always has fresh context. Call this before closing every significant session. get_briefing automatically surfaces the latest recap at the top of the next session's briefing.",
|
|
1894
2059
|
MemSessionEndInputSchema,
|
|
1895
|
-
async (input) =>
|
|
2060
|
+
async (input) => {
|
|
2061
|
+
tracker.record("mem_session_end", input.goal.slice(0, 80));
|
|
2062
|
+
return jsonResult(await memSessionEnd(input, context));
|
|
2063
|
+
}
|
|
1896
2064
|
);
|
|
1897
2065
|
server.prompt(
|
|
1898
2066
|
"bootstrap_project",
|
|
@@ -1912,7 +2080,7 @@ function createHaiveServer(options = {}) {
|
|
|
1912
2080
|
ImportDocsArgsSchema,
|
|
1913
2081
|
(args) => importDocsPrompt(args, context)
|
|
1914
2082
|
);
|
|
1915
|
-
return { server, context };
|
|
2083
|
+
return { server, context, tracker };
|
|
1916
2084
|
}
|
|
1917
2085
|
export {
|
|
1918
2086
|
SERVER_NAME,
|