@hiveai/mcp 0.3.0 → 0.3.3
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 +67 -14
- package/dist/index.js +527 -83
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +13 -0
- package/dist/server.js +527 -83
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
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,
|
|
@@ -1160,6 +1164,7 @@ import {
|
|
|
1160
1164
|
literalMatchesAllTokens as literalMatchesAllTokens2,
|
|
1161
1165
|
literalMatchesAnyToken as literalMatchesAnyToken2,
|
|
1162
1166
|
loadCodeMap,
|
|
1167
|
+
loadConfig as loadConfig2,
|
|
1163
1168
|
loadMemoriesFromDir as loadMemoriesFromDir13,
|
|
1164
1169
|
loadUsageIndex as loadUsageIndex7,
|
|
1165
1170
|
memoryMatchesAnchorPaths as memoryMatchesAnchorPaths2,
|
|
@@ -1317,17 +1322,55 @@ async function getBriefing(input, ctx) {
|
|
|
1317
1322
|
}
|
|
1318
1323
|
const projectContextRaw = input.include_project_context && existsSync17(ctx.paths.projectContext) ? await readFile3(ctx.paths.projectContext, "utf8") : "";
|
|
1319
1324
|
const isTemplateContext = projectContextRaw.includes("TODO \u2014 high-level overview") || projectContextRaw.includes("Generated by `haive init`");
|
|
1320
|
-
const projectContext = isTemplateContext ? "" : projectContextRaw;
|
|
1321
1325
|
const setupWarnings = [];
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
);
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
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
|
+
}
|
|
1331
1374
|
}
|
|
1332
1375
|
const moduleContents = input.include_module_contexts ? await loadModuleContexts2(ctx, inferred) : [];
|
|
1333
1376
|
const memoriesText = memories.map((m) => {
|
|
@@ -1426,10 +1469,11 @@ ${m.content}`).join("\n\n---\n\n"),
|
|
|
1426
1469
|
search_mode: searchMode,
|
|
1427
1470
|
inferred_modules: inferred,
|
|
1428
1471
|
...lastSession ? { last_session: lastSession } : {},
|
|
1429
|
-
project_context: projectContextRaw ? {
|
|
1472
|
+
project_context: projectContextRaw || autoContextGenerated ? {
|
|
1430
1473
|
content: projectSlice.text,
|
|
1431
1474
|
truncated: projectSlice.truncated,
|
|
1432
|
-
...isTemplateContext ? { is_template: true } : {}
|
|
1475
|
+
...isTemplateContext && !autoContextGenerated ? { is_template: true } : {},
|
|
1476
|
+
...autoContextGenerated ? { auto_generated: true } : {}
|
|
1433
1477
|
} : null,
|
|
1434
1478
|
module_contexts: trimmedModules,
|
|
1435
1479
|
memories: outputMemories,
|
|
@@ -1799,9 +1843,78 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
|
|
|
1799
1843
|
};
|
|
1800
1844
|
}
|
|
1801
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
|
+
|
|
1802
1915
|
// src/server.ts
|
|
1803
1916
|
var SERVER_NAME = "haive";
|
|
1804
|
-
var SERVER_VERSION = "0.3.
|
|
1917
|
+
var SERVER_VERSION = "0.3.3";
|
|
1805
1918
|
function jsonResult(data) {
|
|
1806
1919
|
return {
|
|
1807
1920
|
content: [
|
|
@@ -1814,143 +1927,474 @@ function jsonResult(data) {
|
|
|
1814
1927
|
}
|
|
1815
1928
|
function createHaiveServer(options = {}) {
|
|
1816
1929
|
const context = createContext(options);
|
|
1930
|
+
const tracker = new SessionTracker(context);
|
|
1931
|
+
void tracker.init();
|
|
1817
1932
|
const server = new McpServer(
|
|
1818
1933
|
{ name: SERVER_NAME, version: SERVER_VERSION },
|
|
1819
1934
|
{ capabilities: { tools: {}, prompts: {} } }
|
|
1820
1935
|
);
|
|
1821
1936
|
server.tool(
|
|
1822
1937
|
"mem_save",
|
|
1823
|
-
|
|
1938
|
+
[
|
|
1939
|
+
"Save a piece of knowledge as a persistent memory that survives across AI sessions.",
|
|
1940
|
+
"",
|
|
1941
|
+
"USE THIS WHEN you discover something worth remembering for future sessions:",
|
|
1942
|
+
" - A project convention (how things are done here)",
|
|
1943
|
+
" - An architectural decision and its rationale",
|
|
1944
|
+
" - A gotcha or non-obvious behavior that surprised you",
|
|
1945
|
+
" - A domain term and what it means in this codebase",
|
|
1946
|
+
"",
|
|
1947
|
+
"DO NOT USE for failed approaches \u2192 use mem_tried instead (better structure).",
|
|
1948
|
+
"DO NOT USE for code discoveries during exploration \u2192 use mem_observe instead.",
|
|
1949
|
+
"",
|
|
1950
|
+
"PARAMETERS:",
|
|
1951
|
+
" type \u2014 convention | decision | gotcha | architecture | glossary | attempt",
|
|
1952
|
+
" slug \u2014 short kebab-case id (e.g. 'flyway-no-modify-existing')",
|
|
1953
|
+
" body \u2014 Markdown content with the full knowledge",
|
|
1954
|
+
" scope \u2014 team (shared with all devs) | personal (private) | module (component-scoped)",
|
|
1955
|
+
" paths \u2014 anchor to source files for staleness detection (STRONGLY recommended)",
|
|
1956
|
+
" topic \u2014 stable key for upsert: if a memory with same topic+scope exists, update it in-place",
|
|
1957
|
+
"",
|
|
1958
|
+
"RETURNS: { id, scope, file_path, action: 'created'|'updated', warning?, invalid_paths? }",
|
|
1959
|
+
"WARNING: if paths point to non-existent files, they will be immediately stale after haive sync.",
|
|
1960
|
+
"DEDUP: identical body content within the same scope is rejected \u2014 use mem_update to modify."
|
|
1961
|
+
].join("\n"),
|
|
1824
1962
|
MemSaveInputSchema,
|
|
1825
|
-
async (input) =>
|
|
1963
|
+
async (input) => {
|
|
1964
|
+
tracker.record("mem_save", input.slug);
|
|
1965
|
+
return jsonResult(await memSave(input, context));
|
|
1966
|
+
}
|
|
1967
|
+
);
|
|
1968
|
+
server.tool(
|
|
1969
|
+
"mem_tried",
|
|
1970
|
+
[
|
|
1971
|
+
"Record a FAILED approach so future agents don't repeat the same mistake.",
|
|
1972
|
+
"",
|
|
1973
|
+
"USE THIS IMMEDIATELY when you try something and it doesn't work. This is the",
|
|
1974
|
+
"most valuable type of negative knowledge \u2014 it saves hours of debugging for",
|
|
1975
|
+
"future agents working on the same codebase.",
|
|
1976
|
+
"",
|
|
1977
|
+
"Auto-validated (no approval cycle). Surfaced FIRST in future get_briefing calls",
|
|
1978
|
+
"so it's impossible to miss.",
|
|
1979
|
+
"",
|
|
1980
|
+
"PARAMETERS:",
|
|
1981
|
+
" what \u2014 short title of what you tried (e.g. 'importing X with ESM dynamic import')",
|
|
1982
|
+
" why_failed \u2014 the exact error or reason it failed",
|
|
1983
|
+
" instead \u2014 what to do instead (the correct approach)",
|
|
1984
|
+
" scope \u2014 team (default) | personal",
|
|
1985
|
+
" paths \u2014 source files where the issue lives",
|
|
1986
|
+
"",
|
|
1987
|
+
"RETURNS: { id, file_path, action: 'created' }"
|
|
1988
|
+
].join("\n"),
|
|
1989
|
+
MemTriedInputSchema,
|
|
1990
|
+
async (input) => {
|
|
1991
|
+
tracker.record("mem_tried", input.what.slice(0, 80));
|
|
1992
|
+
return jsonResult(await memTried(input, context));
|
|
1993
|
+
}
|
|
1994
|
+
);
|
|
1995
|
+
server.tool(
|
|
1996
|
+
"mem_observe",
|
|
1997
|
+
[
|
|
1998
|
+
"Capture a code-level discovery made WHILE READING existing code.",
|
|
1999
|
+
"",
|
|
2000
|
+
"USE THIS when you read a file and spot something the team may not know about:",
|
|
2001
|
+
" - A bug or race condition hiding in the code",
|
|
2002
|
+
" - A security gap or missing validation",
|
|
2003
|
+
" - An inconsistency between two files",
|
|
2004
|
+
" - A missing configuration or environment variable",
|
|
2005
|
+
" - Anything that could silently break in production",
|
|
2006
|
+
"",
|
|
2007
|
+
"DIFFERENCE from mem_save: mem_observe is for REACTIVE discoveries during code",
|
|
2008
|
+
"reading. mem_save is for deliberate knowledge capture (conventions, decisions).",
|
|
2009
|
+
"",
|
|
2010
|
+
"Auto-validated, anchored to file paths for staleness detection.",
|
|
2011
|
+
"",
|
|
2012
|
+
"PARAMETERS:",
|
|
2013
|
+
" what \u2014 one-line title (e.g. 'MobilePaymentController: duplicate @RequestBody')",
|
|
2014
|
+
" where \u2014 file path(s) where the issue lives",
|
|
2015
|
+
" impact \u2014 what breaks or could break because of this",
|
|
2016
|
+
" fix \u2014 suggested fix (optional)",
|
|
2017
|
+
" scope \u2014 team (default, since discoveries benefit everyone)",
|
|
2018
|
+
"",
|
|
2019
|
+
"RETURNS: { id, file_path }"
|
|
2020
|
+
].join("\n"),
|
|
2021
|
+
MemObserveInputSchema,
|
|
2022
|
+
async (input) => {
|
|
2023
|
+
tracker.record("mem_observe", input.where);
|
|
2024
|
+
return jsonResult(await memObserve(input, context));
|
|
2025
|
+
}
|
|
2026
|
+
);
|
|
2027
|
+
server.tool(
|
|
2028
|
+
"mem_session_end",
|
|
2029
|
+
[
|
|
2030
|
+
"Save an end-of-session recap so the NEXT session starts with fresh context.",
|
|
2031
|
+
"",
|
|
2032
|
+
"CALL THIS before closing any significant working session. In autopilot mode,",
|
|
2033
|
+
"the MCP server saves a minimal recap automatically on exit \u2014 but calling this",
|
|
2034
|
+
"manually produces a richer, more useful recap.",
|
|
2035
|
+
"",
|
|
2036
|
+
"HOW IT WORKS: uses topic-upsert \u2014 one recap per scope is kept and updated",
|
|
2037
|
+
"in-place (revision_count increments). get_briefing surfaces the latest recap",
|
|
2038
|
+
"at the very top of the next session's briefing, before project context.",
|
|
2039
|
+
"",
|
|
2040
|
+
"PARAMETERS:",
|
|
2041
|
+
" goal \u2014 what you were trying to accomplish (1\u20132 sentences)",
|
|
2042
|
+
" accomplished \u2014 what was actually done (bullet list recommended)",
|
|
2043
|
+
" discoveries \u2014 bugs, surprises, missing knowledge found during this session",
|
|
2044
|
+
" files_touched \u2014 key files read or modified (used as anchor for staleness)",
|
|
2045
|
+
" next_steps \u2014 what should happen in the next session or for a teammate",
|
|
2046
|
+
" scope \u2014 personal (default) | team",
|
|
2047
|
+
"",
|
|
2048
|
+
"RETURNS: { id, scope, action: 'created'|'updated', revision_count }"
|
|
2049
|
+
].join("\n"),
|
|
2050
|
+
MemSessionEndInputSchema,
|
|
2051
|
+
async (input) => {
|
|
2052
|
+
tracker.record("mem_session_end", input.goal.slice(0, 80));
|
|
2053
|
+
return jsonResult(await memSessionEnd(input, context));
|
|
2054
|
+
}
|
|
2055
|
+
);
|
|
2056
|
+
server.tool(
|
|
2057
|
+
"get_briefing",
|
|
2058
|
+
[
|
|
2059
|
+
"\u2B50 CALL THIS FIRST at the start of every task. One-shot onboarding that returns",
|
|
2060
|
+
"everything relevant in a single call under a token budget.",
|
|
2061
|
+
"",
|
|
2062
|
+
"RETURNS (in order of priority):",
|
|
2063
|
+
" 1. last_session \u2014 recap of the previous session (goal, what was done, next steps)",
|
|
2064
|
+
" 2. project_context \u2014 .ai/project-context.md (auto-generated from code-map if template)",
|
|
2065
|
+
" 3. module_contexts \u2014 relevant .ai/modules/<name>/context.md based on files being edited",
|
|
2066
|
+
" 4. memories \u2014 ranked team memories relevant to your task",
|
|
2067
|
+
" 5. symbol_locations \u2014 file:line:kind for any requested symbols (no grep needed)",
|
|
2068
|
+
" 6. setup_warnings \u2014 actionable warnings if setup is incomplete",
|
|
2069
|
+
" 7. decay_warnings \u2014 memories not read in >90 days (consider reviewing)",
|
|
2070
|
+
"",
|
|
2071
|
+
"KEY PARAMETERS:",
|
|
2072
|
+
" task \u2014 what you are about to do (1\u20132 sentences) \u2014 ALWAYS provide this",
|
|
2073
|
+
" files \u2014 files you are about to edit \u2014 surfaces anchored memories",
|
|
2074
|
+
" symbols \u2014 symbol names to look up in the code-map (e.g. ['PaymentService'])",
|
|
2075
|
+
" format \u2014 'full' (default) | 'compact' (1-line summaries, use when token budget is tight)",
|
|
2076
|
+
"",
|
|
2077
|
+
"EXAMPLE USAGE:",
|
|
2078
|
+
" get_briefing({ task: 'add a Stripe payment integration', files: ['src/payments/'], symbols: ['PaymentService'] })",
|
|
2079
|
+
"",
|
|
2080
|
+
"CONFIDENCE LEVELS in memories:",
|
|
2081
|
+
" authoritative \u2014 validated + read 10+ times (highest trust)",
|
|
2082
|
+
" trusted \u2014 validated or proposed + read 3+ times",
|
|
2083
|
+
" low \u2014 proposed, few reads (take with caution)",
|
|
2084
|
+
" unverified \u2014 draft (unverified: true flag set)",
|
|
2085
|
+
"",
|
|
2086
|
+
"Replaces 4\u20135 separate tool calls. Always call this before any other tool."
|
|
2087
|
+
].join("\n"),
|
|
2088
|
+
GetBriefingInputSchema,
|
|
2089
|
+
async (input) => {
|
|
2090
|
+
tracker.record("get_briefing", input.task ?? "");
|
|
2091
|
+
return jsonResult(await getBriefing(input, context));
|
|
2092
|
+
}
|
|
1826
2093
|
);
|
|
1827
2094
|
server.tool(
|
|
1828
2095
|
"mem_search",
|
|
1829
|
-
|
|
2096
|
+
[
|
|
2097
|
+
"Search memories by keyword or semantic similarity.",
|
|
2098
|
+
"",
|
|
2099
|
+
"USE WHEN you need to find a specific memory and don't know its id.",
|
|
2100
|
+
"For session onboarding, use get_briefing instead (richer, ranked, budgeted).",
|
|
2101
|
+
"",
|
|
2102
|
+
"SEARCH MODES:",
|
|
2103
|
+
" Literal (default): AND search across id, tags, and body \u2014 all tokens must match.",
|
|
2104
|
+
" Falls back to OR automatically if no AND results (partial match).",
|
|
2105
|
+
" Semantic (semantic: true): embedding-based similarity \u2014 finds related memories",
|
|
2106
|
+
" even with different wording. Requires haive embeddings index to be built.",
|
|
2107
|
+
"",
|
|
2108
|
+
"PARAMETERS:",
|
|
2109
|
+
" query \u2014 search terms or natural language question",
|
|
2110
|
+
" scope \u2014 filter by personal | team | module",
|
|
2111
|
+
" type \u2014 filter by convention | decision | gotcha | architecture | glossary",
|
|
2112
|
+
" semantic \u2014 true for embedding-based search (requires @hiveai/embeddings)",
|
|
2113
|
+
" limit \u2014 max results (default 10)",
|
|
2114
|
+
"",
|
|
2115
|
+
"RETURNS: array of { id, type, scope, status, confidence, body, match_quality }"
|
|
2116
|
+
].join("\n"),
|
|
1830
2117
|
MemSearchInputSchema,
|
|
1831
2118
|
async (input) => jsonResult(await memSearch(input, context))
|
|
1832
2119
|
);
|
|
2120
|
+
server.tool(
|
|
2121
|
+
"mem_for_files",
|
|
2122
|
+
[
|
|
2123
|
+
"Surface memories relevant to the files you are currently editing.",
|
|
2124
|
+
"",
|
|
2125
|
+
"USE WHEN starting work on specific files and you want to know:",
|
|
2126
|
+
" - What conventions apply to these files",
|
|
2127
|
+
" - What gotchas are anchored to these paths",
|
|
2128
|
+
" - What decisions were made about this module",
|
|
2129
|
+
"",
|
|
2130
|
+
"Matching strategy (in priority order):",
|
|
2131
|
+
" 1. Anchor overlap \u2014 memories whose paths overlap with your files",
|
|
2132
|
+
" 2. Module context \u2014 .ai/modules/<name>/context.md if module is inferred",
|
|
2133
|
+
" 3. Domain/tag match \u2014 memories whose tags include path segments",
|
|
2134
|
+
"",
|
|
2135
|
+
"PARAMETERS:",
|
|
2136
|
+
" files \u2014 list of project-relative file paths you are editing",
|
|
2137
|
+
" scope \u2014 filter by scope (default: all)",
|
|
2138
|
+
"",
|
|
2139
|
+
"RETURNS: { memories: [...], module_contexts: [...] }"
|
|
2140
|
+
].join("\n"),
|
|
2141
|
+
MemForFilesInputSchema,
|
|
2142
|
+
async (input) => jsonResult(await memForFiles(input, context))
|
|
2143
|
+
);
|
|
2144
|
+
server.tool(
|
|
2145
|
+
"mem_get",
|
|
2146
|
+
[
|
|
2147
|
+
"Fetch a single memory by its full id with all details.",
|
|
2148
|
+
"",
|
|
2149
|
+
"USE WHEN get_briefing returned a memory in 'compact' format and you need",
|
|
2150
|
+
"the full body, or when you know the exact id of a memory.",
|
|
2151
|
+
"",
|
|
2152
|
+
"PARAMETERS:",
|
|
2153
|
+
" id \u2014 full memory id (e.g. '2026-04-28-gotcha-flyway-strict-no-ddl')",
|
|
2154
|
+
"",
|
|
2155
|
+
"RETURNS: { id, type, scope, status, confidence, body, anchor, tags, usage }"
|
|
2156
|
+
].join("\n"),
|
|
2157
|
+
MemGetInputSchema,
|
|
2158
|
+
async (input) => jsonResult(await memGet(input, context))
|
|
2159
|
+
);
|
|
1833
2160
|
server.tool(
|
|
1834
2161
|
"mem_list",
|
|
1835
|
-
|
|
2162
|
+
[
|
|
2163
|
+
"List memories with optional filters. Use for browsing, not for task onboarding.",
|
|
2164
|
+
"",
|
|
2165
|
+
"For task onboarding use get_briefing (ranked + budgeted).",
|
|
2166
|
+
"For keyword search use mem_search.",
|
|
2167
|
+
"",
|
|
2168
|
+
"PARAMETERS:",
|
|
2169
|
+
" scope \u2014 personal | team | module",
|
|
2170
|
+
" type \u2014 convention | decision | gotcha | architecture | glossary",
|
|
2171
|
+
" status \u2014 draft | proposed | validated | stale | rejected",
|
|
2172
|
+
" tags \u2014 filter by tags (AND match)",
|
|
2173
|
+
" module \u2014 filter by module name",
|
|
2174
|
+
"",
|
|
2175
|
+
"RETURNS: array of { id, type, scope, status, confidence, tags, created_at }"
|
|
2176
|
+
].join("\n"),
|
|
1836
2177
|
MemListInputSchema,
|
|
1837
2178
|
async (input) => jsonResult(await memList(input, context))
|
|
1838
2179
|
);
|
|
1839
2180
|
server.tool(
|
|
1840
2181
|
"get_project_context",
|
|
1841
|
-
|
|
2182
|
+
[
|
|
2183
|
+
"Read .ai/project-context.md (and optionally a module context) directly.",
|
|
2184
|
+
"",
|
|
2185
|
+
"USE WHEN you need the full project context without the memory ranking and",
|
|
2186
|
+
"token budgeting of get_briefing \u2014 e.g. for a reference architecture review.",
|
|
2187
|
+
"",
|
|
2188
|
+
"For normal task onboarding, use get_briefing instead (more efficient).",
|
|
2189
|
+
"",
|
|
2190
|
+
"PARAMETERS:",
|
|
2191
|
+
" module \u2014 also load .ai/modules/<module>/context.md if provided",
|
|
2192
|
+
"",
|
|
2193
|
+
"RETURNS: { content: string, module_context?: string }"
|
|
2194
|
+
].join("\n"),
|
|
1842
2195
|
GetProjectContextInputSchema,
|
|
1843
2196
|
async (input) => jsonResult(await getProjectContext(input, context))
|
|
1844
2197
|
);
|
|
1845
2198
|
server.tool(
|
|
1846
|
-
"
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
2199
|
+
"bootstrap_project_save",
|
|
2200
|
+
[
|
|
2201
|
+
"Persist the project context document (.ai/project-context.md) or a module",
|
|
2202
|
+
"context (.ai/modules/<name>/context.md) analyzed by the AI.",
|
|
2203
|
+
"",
|
|
2204
|
+
"USE AFTER the bootstrap_project MCP prompt: the prompt tells you how to",
|
|
2205
|
+
"analyze the codebase; this tool saves the result.",
|
|
2206
|
+
"",
|
|
2207
|
+
"PARAMETERS:",
|
|
2208
|
+
" content \u2014 full Markdown content of the context document",
|
|
2209
|
+
" module \u2014 if provided, saves as a module context (not root project context)",
|
|
2210
|
+
"",
|
|
2211
|
+
"RETURNS: { file_path, module? }"
|
|
2212
|
+
].join("\n"),
|
|
2213
|
+
BootstrapProjectSaveInputSchema,
|
|
2214
|
+
async (input) => jsonResult(await bootstrapProjectSave(input, context))
|
|
1850
2215
|
);
|
|
1851
2216
|
server.tool(
|
|
1852
2217
|
"code_map",
|
|
1853
|
-
|
|
2218
|
+
[
|
|
2219
|
+
"Look up where symbols (classes, functions, interfaces) are defined in the codebase.",
|
|
2220
|
+
"",
|
|
2221
|
+
"USE INSTEAD OF grepping when you need to find where something lives.",
|
|
2222
|
+
"Requires haive index code to have been run (done automatically in autopilot mode).",
|
|
2223
|
+
"",
|
|
2224
|
+
"TIP: include symbols in get_briefing directly for auto-lookup at session start.",
|
|
2225
|
+
"",
|
|
2226
|
+
"PARAMETERS:",
|
|
2227
|
+
" symbol \u2014 name or partial name to search (e.g. 'PaymentService')",
|
|
2228
|
+
" file \u2014 filter by file path substring",
|
|
2229
|
+
" max_files \u2014 cap on results (default 40)",
|
|
2230
|
+
"",
|
|
2231
|
+
"RETURNS: { available: bool, files: [{ path, exports: [{ name, kind, line, description }] }] }",
|
|
2232
|
+
"If available: false \u2192 run haive index code first."
|
|
2233
|
+
].join("\n"),
|
|
1854
2234
|
CodeMapInputSchema,
|
|
1855
2235
|
async (input) => jsonResult(await codeMapTool(input, context))
|
|
1856
2236
|
);
|
|
1857
2237
|
server.tool(
|
|
1858
|
-
"
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
2238
|
+
"mem_update",
|
|
2239
|
+
[
|
|
2240
|
+
"Update the body, tags, or anchor of an existing memory in-place.",
|
|
2241
|
+
"",
|
|
2242
|
+
"USE WHEN a memory exists but its content has become outdated or incomplete.",
|
|
2243
|
+
"This preserves the memory's id, usage history, and read_count.",
|
|
2244
|
+
"",
|
|
2245
|
+
"For evolving memories that you will update repeatedly, use mem_save with a",
|
|
2246
|
+
"topic key instead (topic-upsert pattern).",
|
|
2247
|
+
"",
|
|
2248
|
+
"PARAMETERS:",
|
|
2249
|
+
" id \u2014 full memory id to update",
|
|
2250
|
+
" body \u2014 new Markdown content (replaces existing body)",
|
|
2251
|
+
" tags \u2014 new tag list (replaces existing tags)",
|
|
2252
|
+
" paths \u2014 new anchor paths (replaces existing paths)",
|
|
2253
|
+
" symbols \u2014 new anchor symbols (replaces existing symbols)",
|
|
2254
|
+
"",
|
|
2255
|
+
"RETURNS: { id, file_path, updated_fields: string[] }"
|
|
2256
|
+
].join("\n"),
|
|
2257
|
+
MemUpdateInputSchema,
|
|
2258
|
+
async (input) => jsonResult(await memUpdate(input, context))
|
|
1862
2259
|
);
|
|
1863
2260
|
server.tool(
|
|
1864
2261
|
"mem_verify",
|
|
1865
|
-
|
|
2262
|
+
[
|
|
2263
|
+
"Check whether memory anchor paths and symbols still exist in the current code.",
|
|
2264
|
+
"",
|
|
2265
|
+
"USE WHEN you want to know if a specific memory is still valid after a refactor,",
|
|
2266
|
+
"or to check all memories for staleness (haive sync does this automatically).",
|
|
2267
|
+
"",
|
|
2268
|
+
"PARAMETERS:",
|
|
2269
|
+
" id \u2014 check a single memory (omit to check all)",
|
|
2270
|
+
" update \u2014 write 'stale' or 'validated' status back to disk",
|
|
2271
|
+
"",
|
|
2272
|
+
"RETURNS: { results: [{ id, status: 'fresh'|'stale'|'anchorless', reason? }] }",
|
|
2273
|
+
"Stale means the anchored file/symbol no longer exists at that path.",
|
|
2274
|
+
"Anchorless means the memory has no paths/symbols \u2014 staleness is undetectable."
|
|
2275
|
+
].join("\n"),
|
|
1866
2276
|
MemVerifyInputSchema,
|
|
1867
2277
|
async (input) => jsonResult(await memVerify(input, context))
|
|
1868
2278
|
);
|
|
2279
|
+
server.tool(
|
|
2280
|
+
"mem_approve",
|
|
2281
|
+
[
|
|
2282
|
+
"Mark a memory as validated (trusted, approved by a human or the team).",
|
|
2283
|
+
"",
|
|
2284
|
+
"In autopilot mode, memories are validated automatically \u2014 you rarely need this.",
|
|
2285
|
+
"In manual mode, call this after reviewing a proposed memory to activate it.",
|
|
2286
|
+
"",
|
|
2287
|
+
"PARAMETERS:",
|
|
2288
|
+
" id \u2014 full memory id to approve",
|
|
2289
|
+
"",
|
|
2290
|
+
"RETURNS: { id, previous_status, new_status: 'validated' }"
|
|
2291
|
+
].join("\n"),
|
|
2292
|
+
MemApproveInputSchema,
|
|
2293
|
+
async (input) => jsonResult(await memApprove(input, context))
|
|
2294
|
+
);
|
|
1869
2295
|
server.tool(
|
|
1870
2296
|
"mem_reject",
|
|
1871
|
-
|
|
2297
|
+
[
|
|
2298
|
+
"Mark a memory as rejected and record a reason.",
|
|
2299
|
+
"",
|
|
2300
|
+
"USE WHEN a memory is factually wrong, outdated, or not useful.",
|
|
2301
|
+
"Rejection blocks auto-promotion and lowers the memory's trust signal.",
|
|
2302
|
+
"Rejected memories are excluded from get_briefing by default.",
|
|
2303
|
+
"",
|
|
2304
|
+
"PARAMETERS:",
|
|
2305
|
+
" id \u2014 full memory id to reject",
|
|
2306
|
+
" reason \u2014 why this memory is being rejected (stored in frontmatter)",
|
|
2307
|
+
"",
|
|
2308
|
+
"RETURNS: { id, previous_status, new_status: 'rejected' }"
|
|
2309
|
+
].join("\n"),
|
|
1872
2310
|
MemRejectInputSchema,
|
|
1873
2311
|
async (input) => jsonResult(await memReject(input, context))
|
|
1874
2312
|
);
|
|
1875
|
-
server.tool(
|
|
1876
|
-
"mem_for_files",
|
|
1877
|
-
"Given the file paths the agent is currently working on, return relevant memories grouped by reason (anchor overlap, module, domain) plus any matching .ai/modules/<name>/context.md contents.",
|
|
1878
|
-
MemForFilesInputSchema,
|
|
1879
|
-
async (input) => jsonResult(await memForFiles(input, context))
|
|
1880
|
-
);
|
|
1881
|
-
server.tool(
|
|
1882
|
-
"mem_get",
|
|
1883
|
-
"Fetch a single memory by id, including its body, anchor, usage, and confidence.",
|
|
1884
|
-
MemGetInputSchema,
|
|
1885
|
-
async (input) => jsonResult(await memGet(input, context))
|
|
1886
|
-
);
|
|
1887
|
-
server.tool(
|
|
1888
|
-
"mem_delete",
|
|
1889
|
-
"Delete a memory by id (and its usage entry by default).",
|
|
1890
|
-
MemDeleteInputSchema,
|
|
1891
|
-
async (input) => jsonResult(await memDelete(input, context))
|
|
1892
|
-
);
|
|
1893
|
-
server.tool(
|
|
1894
|
-
"mem_update",
|
|
1895
|
-
"Update the body, tags, or anchor of an existing memory without changing its id or losing usage history.",
|
|
1896
|
-
MemUpdateInputSchema,
|
|
1897
|
-
async (input) => jsonResult(await memUpdate(input, context))
|
|
1898
|
-
);
|
|
1899
2313
|
server.tool(
|
|
1900
2314
|
"mem_pending",
|
|
1901
|
-
|
|
2315
|
+
[
|
|
2316
|
+
"List memories in 'proposed' status awaiting review, sorted by read count.",
|
|
2317
|
+
"",
|
|
2318
|
+
"USE IN MANUAL MODE to see what memories are waiting for human review.",
|
|
2319
|
+
"In autopilot mode, proposed memories auto-approve after 72h.",
|
|
2320
|
+
"",
|
|
2321
|
+
"High read_count on a proposed memory = many agents found it useful without",
|
|
2322
|
+
"rejecting it = strong signal to approve.",
|
|
2323
|
+
"",
|
|
2324
|
+
"RETURNS: array of { id, type, scope, read_count, created_at, body_preview }"
|
|
2325
|
+
].join("\n"),
|
|
1902
2326
|
MemPendingInputSchema,
|
|
1903
2327
|
async (input) => jsonResult(await memPending(input, context))
|
|
1904
2328
|
);
|
|
1905
2329
|
server.tool(
|
|
1906
|
-
"
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
2330
|
+
"mem_delete",
|
|
2331
|
+
[
|
|
2332
|
+
"Permanently delete a memory by id.",
|
|
2333
|
+
"",
|
|
2334
|
+
"USE WITH CAUTION \u2014 prefer mem_reject for outdated memories (preserves history).",
|
|
2335
|
+
"Use delete only for accidentally created memories or duplicates.",
|
|
2336
|
+
"",
|
|
2337
|
+
"PARAMETERS:",
|
|
2338
|
+
" id \u2014 full memory id to delete",
|
|
2339
|
+
" delete_usage \u2014 also delete usage stats (default: true)",
|
|
2340
|
+
"",
|
|
2341
|
+
"RETURNS: { deleted: true, id }"
|
|
2342
|
+
].join("\n"),
|
|
2343
|
+
MemDeleteInputSchema,
|
|
2344
|
+
async (input) => jsonResult(await memDelete(input, context))
|
|
1916
2345
|
);
|
|
1917
2346
|
server.tool(
|
|
1918
2347
|
"mem_diff",
|
|
1919
|
-
|
|
2348
|
+
[
|
|
2349
|
+
"Compare two memories side-by-side to decide if they should be merged.",
|
|
2350
|
+
"",
|
|
2351
|
+
"USE BEFORE merging or deduplicating similar memories.",
|
|
2352
|
+
"Shows: frontmatter fields that differ + lines unique to each body.",
|
|
2353
|
+
"",
|
|
2354
|
+
"PARAMETERS:",
|
|
2355
|
+
" id_a \u2014 first memory id",
|
|
2356
|
+
" id_b \u2014 second memory id",
|
|
2357
|
+
"",
|
|
2358
|
+
"RETURNS: { frontmatter_diff: {...}, body_only_in_a: [...], body_only_in_b: [...] }"
|
|
2359
|
+
].join("\n"),
|
|
1920
2360
|
MemDiffInputSchema,
|
|
1921
2361
|
async (input) => jsonResult(await memDiff(input, context))
|
|
1922
2362
|
);
|
|
1923
|
-
server.tool(
|
|
1924
|
-
"mem_observe",
|
|
1925
|
-
"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.",
|
|
1926
|
-
MemObserveInputSchema,
|
|
1927
|
-
async (input) => jsonResult(await memObserve(input, context))
|
|
1928
|
-
);
|
|
1929
|
-
server.tool(
|
|
1930
|
-
"mem_session_end",
|
|
1931
|
-
"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.",
|
|
1932
|
-
MemSessionEndInputSchema,
|
|
1933
|
-
async (input) => jsonResult(await memSessionEnd(input, context))
|
|
1934
|
-
);
|
|
1935
2363
|
server.prompt(
|
|
1936
2364
|
"bootstrap_project",
|
|
1937
|
-
|
|
2365
|
+
[
|
|
2366
|
+
"Analyze the project codebase and write .ai/project-context.md \u2014 run once after haive init.",
|
|
2367
|
+
"The AI explores the directory structure, reads key files (package.json, README, config),",
|
|
2368
|
+
"identifies the tech stack, architectural patterns, key modules, and conventions,",
|
|
2369
|
+
"then persists everything via bootstrap_project_save.",
|
|
2370
|
+
"For multi-component projects, run with module param to create .ai/modules/<name>/context.md."
|
|
2371
|
+
].join(" "),
|
|
1938
2372
|
BootstrapProjectArgsSchema,
|
|
1939
2373
|
(args) => bootstrapProjectPrompt(args, context)
|
|
1940
2374
|
);
|
|
1941
2375
|
server.prompt(
|
|
1942
2376
|
"post_task",
|
|
1943
|
-
|
|
2377
|
+
[
|
|
2378
|
+
"\u2B50 Post-task reflection \u2014 run at the end of every session to capture what you learned:",
|
|
2379
|
+
"failed approaches (mem_tried), new conventions/decisions/gotchas (mem_save),",
|
|
2380
|
+
"code discoveries (mem_observe), and an end-of-session recap (mem_session_end).",
|
|
2381
|
+
"In autopilot mode a minimal recap saves automatically; calling this produces a richer one."
|
|
2382
|
+
].join(" "),
|
|
1944
2383
|
PostTaskArgsSchema,
|
|
1945
2384
|
(args) => postTaskPrompt(args, context)
|
|
1946
2385
|
);
|
|
1947
2386
|
server.prompt(
|
|
1948
2387
|
"import_docs",
|
|
1949
|
-
|
|
2388
|
+
[
|
|
2389
|
+
"Import knowledge from a document (README, ADR, wiki, API spec) as hAIve memories.",
|
|
2390
|
+
"Pass the full document content; the AI extracts up to 10 actionable memories",
|
|
2391
|
+
"(conventions, decisions, gotchas, architecture) and saves them via mem_save.",
|
|
2392
|
+
"Good candidates: ADRs, onboarding docs, runbooks, team wikis."
|
|
2393
|
+
].join(" "),
|
|
1950
2394
|
ImportDocsArgsSchema,
|
|
1951
2395
|
(args) => importDocsPrompt(args, context)
|
|
1952
2396
|
);
|
|
1953
|
-
return { server, context };
|
|
2397
|
+
return { server, context, tracker };
|
|
1954
2398
|
}
|
|
1955
2399
|
export {
|
|
1956
2400
|
SERVER_NAME,
|