@hiveai/mcp 0.2.15 → 0.3.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 CHANGED
@@ -163,6 +163,9 @@ async function memSave(input, ctx) {
163
163
  );
164
164
  }
165
165
  const existing = existsSync4(ctx.paths.memoriesDir) ? await loadMemoriesFromDir2(ctx.paths.memoriesDir) : [];
166
+ const invalidPaths = input.paths.filter(
167
+ (p) => !existsSync4(path3.resolve(ctx.paths.root, p))
168
+ );
166
169
  const incomingHash = bodyHash(input.body);
167
170
  const hashDuplicate = existing.find(
168
171
  ({ memory }) => bodyHash(memory.body) === incomingHash && memory.frontmatter.scope === input.scope
@@ -199,7 +202,8 @@ async function memSave(input, ctx) {
199
202
  scope: fm.scope,
200
203
  file_path: topicMatch.filePath,
201
204
  action: "updated",
202
- revision_count: newFrontmatter.revision_count
205
+ revision_count: newFrontmatter.revision_count,
206
+ ...invalidPaths.length > 0 ? { invalid_paths: invalidPaths, warning: `Anchor path(s) not found in project: ${invalidPaths.join(", ")}. They will be marked stale by haive sync.` } : {}
203
207
  };
204
208
  }
205
209
  }
@@ -240,13 +244,18 @@ async function memSave(input, ctx) {
240
244
  }
241
245
  }
242
246
  await writeFile2(file, serializeMemory({ frontmatter, body: input.body }), "utf8");
247
+ const finalWarning = [
248
+ invalidPaths.length > 0 ? `Anchor path(s) not found in project: ${invalidPaths.join(", ")}. They will be marked stale by \`haive sync\`.` : null,
249
+ warning ?? null
250
+ ].filter(Boolean).join(" \u2014 ") || void 0;
243
251
  return {
244
252
  id: frontmatter.id,
245
253
  scope: frontmatter.scope,
246
254
  file_path: file,
247
255
  action: "created",
248
- ...warning ? { warning } : {},
249
- ...similar_found ? { similar_found } : {}
256
+ ...finalWarning ? { warning: finalWarning } : {},
257
+ ...similar_found ? { similar_found } : {},
258
+ ...invalidPaths.length > 0 ? { invalid_paths: invalidPaths } : {}
250
259
  };
251
260
  }
252
261
 
@@ -1081,6 +1090,12 @@ async function memSessionEnd(input, ctx) {
1081
1090
  }
1082
1091
  const body = buildBody(input);
1083
1092
  const topic = recapTopic(input.scope, input.module);
1093
+ const invalidPaths = input.files_touched.filter(
1094
+ (p) => !existsSync16(path7.resolve(ctx.paths.root, p))
1095
+ );
1096
+ if (invalidPaths.length > 0) {
1097
+ console.warn(`[haive] session end: anchor path(s) not found: ${invalidPaths.join(", ")}`);
1098
+ }
1084
1099
  const existing = existsSync16(ctx.paths.memoriesDir) ? await loadMemoriesFromDir12(ctx.paths.memoriesDir) : [];
1085
1100
  const topicMatch = existing.find(
1086
1101
  ({ memory }) => memory.frontmatter.topic === topic && memory.frontmatter.scope === input.scope && (!input.module || memory.frontmatter.module === input.module)
@@ -1149,9 +1164,11 @@ import {
1149
1164
  isDecaying,
1150
1165
  literalMatchesAllTokens as literalMatchesAllTokens2,
1151
1166
  literalMatchesAnyToken as literalMatchesAnyToken2,
1167
+ loadCodeMap,
1152
1168
  loadMemoriesFromDir as loadMemoriesFromDir13,
1153
1169
  loadUsageIndex as loadUsageIndex7,
1154
1170
  memoryMatchesAnchorPaths as memoryMatchesAnchorPaths2,
1171
+ queryCodeMap,
1155
1172
  tokenizeQuery as tokenizeQuery2,
1156
1173
  trackReads as trackReads3,
1157
1174
  truncateToTokens
@@ -1175,6 +1192,9 @@ var GetBriefingInputSchema = {
1175
1192
  track: z17.boolean().default(true).describe("Increment read_count on returned memories"),
1176
1193
  format: z17.enum(["full", "compact"]).default("full").describe(
1177
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."
1178
1198
  )
1179
1199
  };
1180
1200
  async function getBriefing(input, ctx) {
@@ -1236,6 +1256,7 @@ async function getBriefing(input, ctx) {
1236
1256
  tags: fm.tags,
1237
1257
  status: fm.status,
1238
1258
  confidence: deriveConfidence4(fm, u),
1259
+ ...fm.status === "draft" || fm.status === "proposed" ? { unverified: true } : {},
1239
1260
  read_count: u.read_count,
1240
1261
  reasons: [reason],
1241
1262
  match_quality: matchQuality ?? "partial",
@@ -1299,7 +1320,20 @@ async function getBriefing(input, ctx) {
1299
1320
  await trackReads3(ctx.paths, memories.map((m) => m.id));
1300
1321
  }
1301
1322
  }
1302
- const projectContext = input.include_project_context && existsSync17(ctx.paths.projectContext) ? await readFile3(ctx.paths.projectContext, "utf8") : "";
1323
+ const projectContextRaw = input.include_project_context && existsSync17(ctx.paths.projectContext) ? await readFile3(ctx.paths.projectContext, "utf8") : "";
1324
+ const isTemplateContext = projectContextRaw.includes("TODO \u2014 high-level overview") || projectContextRaw.includes("Generated by `haive init`");
1325
+ const projectContext = isTemplateContext ? "" : projectContextRaw;
1326
+ const setupWarnings = [];
1327
+ if (isTemplateContext) {
1328
+ setupWarnings.push(
1329
+ "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."
1330
+ );
1331
+ }
1332
+ if (!existsSync17(ctx.paths.projectContext)) {
1333
+ setupWarnings.push(
1334
+ "No project-context.md found. Run `haive init` then invoke the bootstrap_project MCP prompt."
1335
+ );
1336
+ }
1303
1337
  const moduleContents = input.include_module_contexts ? await loadModuleContexts2(ctx, inferred) : [];
1304
1338
  const memoriesText = memories.map((m) => {
1305
1339
  const unverified = m.status === "proposed" ? " [UNVERIFIED \u2014 not yet validated]" : "";
@@ -1361,15 +1395,52 @@ ${m.content}`).join("\n\n---\n\n"),
1361
1395
  if (isDecaying(u, createdAt)) decayWarnings.push(m.id);
1362
1396
  }
1363
1397
  const outputMemories = input.format === "compact" ? trimmedMemories.map((m) => ({ ...m, body: compactSummary(m.body) })) : trimmedMemories;
1398
+ let symbolLocations;
1399
+ const symbolsToLookup = new Set(input.symbols);
1400
+ for (const m of outputMemories) {
1401
+ const loaded = byId.get(m.id);
1402
+ for (const sym of loaded?.memory.frontmatter.anchor.symbols ?? []) {
1403
+ symbolsToLookup.add(sym);
1404
+ }
1405
+ }
1406
+ if (symbolsToLookup.size > 0) {
1407
+ const codeMap = await loadCodeMap(ctx.paths);
1408
+ if (codeMap) {
1409
+ symbolLocations = [];
1410
+ for (const sym of symbolsToLookup) {
1411
+ const { files } = queryCodeMap(codeMap, { symbol: sym });
1412
+ if (files.length > 0) {
1413
+ symbolLocations.push({
1414
+ symbol: sym,
1415
+ locations: files.flatMap(
1416
+ (f) => f.entry.exports.filter((e) => e.name.toLowerCase().includes(sym.toLowerCase())).map((e) => ({
1417
+ file: f.path,
1418
+ kind: e.kind,
1419
+ line: e.line,
1420
+ ...e.description ? { description: e.description } : {}
1421
+ }))
1422
+ )
1423
+ });
1424
+ }
1425
+ }
1426
+ if (symbolLocations.length === 0) symbolLocations = void 0;
1427
+ }
1428
+ }
1364
1429
  return {
1365
1430
  ...input.task ? { task: input.task } : {},
1366
1431
  search_mode: searchMode,
1367
1432
  inferred_modules: inferred,
1368
1433
  ...lastSession ? { last_session: lastSession } : {},
1369
- project_context: projectContext ? { content: projectSlice.text, truncated: projectSlice.truncated } : null,
1434
+ project_context: projectContextRaw ? {
1435
+ content: projectSlice.text,
1436
+ truncated: projectSlice.truncated,
1437
+ ...isTemplateContext ? { is_template: true } : {}
1438
+ } : null,
1370
1439
  module_contexts: trimmedModules,
1371
1440
  memories: outputMemories,
1441
+ ...symbolLocations ? { symbol_locations: symbolLocations } : {},
1372
1442
  decay_warnings: decayWarnings,
1443
+ setup_warnings: setupWarnings,
1373
1444
  estimated_tokens: totalTokens,
1374
1445
  budget: {
1375
1446
  max_tokens: input.max_tokens,
@@ -1417,7 +1488,7 @@ async function loadModuleContexts2(ctx, modules) {
1417
1488
  }
1418
1489
 
1419
1490
  // src/tools/code-map.ts
1420
- import { loadCodeMap, queryCodeMap } from "@hiveai/core";
1491
+ import { loadCodeMap as loadCodeMap2, queryCodeMap as queryCodeMap2 } from "@hiveai/core";
1421
1492
  import { z as z18 } from "zod";
1422
1493
  var CodeMapInputSchema = {
1423
1494
  file: z18.string().optional().describe("Filter to files whose path contains this substring"),
@@ -1425,7 +1496,7 @@ var CodeMapInputSchema = {
1425
1496
  max_files: z18.number().int().positive().default(40).describe("Cap on returned files")
1426
1497
  };
1427
1498
  async function codeMapTool(input, ctx) {
1428
- const map = await loadCodeMap(ctx.paths);
1499
+ const map = await loadCodeMap2(ctx.paths);
1429
1500
  if (!map) {
1430
1501
  return {
1431
1502
  available: false,
@@ -1433,7 +1504,7 @@ async function codeMapTool(input, ctx) {
1433
1504
  notice: "No code map found. Run `haive index code` to generate `.ai/code-map.json`."
1434
1505
  };
1435
1506
  }
1436
- const { files } = queryCodeMap(map, { file: input.file, symbol: input.symbol });
1507
+ const { files } = queryCodeMap2(map, { file: input.file, symbol: input.symbol });
1437
1508
  return {
1438
1509
  available: true,
1439
1510
  generated_at: map.generated_at,
@@ -1735,7 +1806,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
1735
1806
 
1736
1807
  // src/server.ts
1737
1808
  var SERVER_NAME = "haive";
1738
- var SERVER_VERSION = "0.2.15";
1809
+ var SERVER_VERSION = "0.3.0";
1739
1810
  function jsonResult(data) {
1740
1811
  return {
1741
1812
  content: [