@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/server.js CHANGED
@@ -158,6 +158,9 @@ async function memSave(input, ctx) {
158
158
  );
159
159
  }
160
160
  const existing = existsSync4(ctx.paths.memoriesDir) ? await loadMemoriesFromDir2(ctx.paths.memoriesDir) : [];
161
+ const invalidPaths = input.paths.filter(
162
+ (p) => !existsSync4(path3.resolve(ctx.paths.root, p))
163
+ );
161
164
  const incomingHash = bodyHash(input.body);
162
165
  const hashDuplicate = existing.find(
163
166
  ({ memory }) => bodyHash(memory.body) === incomingHash && memory.frontmatter.scope === input.scope
@@ -194,7 +197,8 @@ async function memSave(input, ctx) {
194
197
  scope: fm.scope,
195
198
  file_path: topicMatch.filePath,
196
199
  action: "updated",
197
- revision_count: newFrontmatter.revision_count
200
+ revision_count: newFrontmatter.revision_count,
201
+ ...invalidPaths.length > 0 ? { invalid_paths: invalidPaths, warning: `Anchor path(s) not found in project: ${invalidPaths.join(", ")}. They will be marked stale by haive sync.` } : {}
198
202
  };
199
203
  }
200
204
  }
@@ -235,13 +239,18 @@ async function memSave(input, ctx) {
235
239
  }
236
240
  }
237
241
  await writeFile2(file, serializeMemory({ frontmatter, body: input.body }), "utf8");
242
+ const finalWarning = [
243
+ invalidPaths.length > 0 ? `Anchor path(s) not found in project: ${invalidPaths.join(", ")}. They will be marked stale by \`haive sync\`.` : null,
244
+ warning ?? null
245
+ ].filter(Boolean).join(" \u2014 ") || void 0;
238
246
  return {
239
247
  id: frontmatter.id,
240
248
  scope: frontmatter.scope,
241
249
  file_path: file,
242
250
  action: "created",
243
- ...warning ? { warning } : {},
244
- ...similar_found ? { similar_found } : {}
251
+ ...finalWarning ? { warning: finalWarning } : {},
252
+ ...similar_found ? { similar_found } : {},
253
+ ...invalidPaths.length > 0 ? { invalid_paths: invalidPaths } : {}
245
254
  };
246
255
  }
247
256
 
@@ -1076,6 +1085,12 @@ async function memSessionEnd(input, ctx) {
1076
1085
  }
1077
1086
  const body = buildBody(input);
1078
1087
  const topic = recapTopic(input.scope, input.module);
1088
+ const invalidPaths = input.files_touched.filter(
1089
+ (p) => !existsSync16(path7.resolve(ctx.paths.root, p))
1090
+ );
1091
+ if (invalidPaths.length > 0) {
1092
+ console.warn(`[haive] session end: anchor path(s) not found: ${invalidPaths.join(", ")}`);
1093
+ }
1079
1094
  const existing = existsSync16(ctx.paths.memoriesDir) ? await loadMemoriesFromDir12(ctx.paths.memoriesDir) : [];
1080
1095
  const topicMatch = existing.find(
1081
1096
  ({ memory }) => memory.frontmatter.topic === topic && memory.frontmatter.scope === input.scope && (!input.module || memory.frontmatter.module === input.module)
@@ -1144,9 +1159,11 @@ import {
1144
1159
  isDecaying,
1145
1160
  literalMatchesAllTokens as literalMatchesAllTokens2,
1146
1161
  literalMatchesAnyToken as literalMatchesAnyToken2,
1162
+ loadCodeMap,
1147
1163
  loadMemoriesFromDir as loadMemoriesFromDir13,
1148
1164
  loadUsageIndex as loadUsageIndex7,
1149
1165
  memoryMatchesAnchorPaths as memoryMatchesAnchorPaths2,
1166
+ queryCodeMap,
1150
1167
  tokenizeQuery as tokenizeQuery2,
1151
1168
  trackReads as trackReads3,
1152
1169
  truncateToTokens
@@ -1170,6 +1187,9 @@ var GetBriefingInputSchema = {
1170
1187
  track: z17.boolean().default(true).describe("Increment read_count on returned memories"),
1171
1188
  format: z17.enum(["full", "compact"]).default("full").describe(
1172
1189
  "Output format: 'full' returns complete memory bodies; 'compact' returns id + 1-line summary only (call mem_get for details)."
1190
+ ),
1191
+ symbols: z17.array(z17.string()).default([]).describe(
1192
+ "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."
1173
1193
  )
1174
1194
  };
1175
1195
  async function getBriefing(input, ctx) {
@@ -1231,6 +1251,7 @@ async function getBriefing(input, ctx) {
1231
1251
  tags: fm.tags,
1232
1252
  status: fm.status,
1233
1253
  confidence: deriveConfidence4(fm, u),
1254
+ ...fm.status === "draft" || fm.status === "proposed" ? { unverified: true } : {},
1234
1255
  read_count: u.read_count,
1235
1256
  reasons: [reason],
1236
1257
  match_quality: matchQuality ?? "partial",
@@ -1294,7 +1315,20 @@ async function getBriefing(input, ctx) {
1294
1315
  await trackReads3(ctx.paths, memories.map((m) => m.id));
1295
1316
  }
1296
1317
  }
1297
- const projectContext = input.include_project_context && existsSync17(ctx.paths.projectContext) ? await readFile3(ctx.paths.projectContext, "utf8") : "";
1318
+ const projectContextRaw = input.include_project_context && existsSync17(ctx.paths.projectContext) ? await readFile3(ctx.paths.projectContext, "utf8") : "";
1319
+ const isTemplateContext = projectContextRaw.includes("TODO \u2014 high-level overview") || projectContextRaw.includes("Generated by `haive init`");
1320
+ const projectContext = isTemplateContext ? "" : projectContextRaw;
1321
+ const setupWarnings = [];
1322
+ if (isTemplateContext) {
1323
+ setupWarnings.push(
1324
+ "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."
1325
+ );
1326
+ }
1327
+ if (!existsSync17(ctx.paths.projectContext)) {
1328
+ setupWarnings.push(
1329
+ "No project-context.md found. Run `haive init` then invoke the bootstrap_project MCP prompt."
1330
+ );
1331
+ }
1298
1332
  const moduleContents = input.include_module_contexts ? await loadModuleContexts2(ctx, inferred) : [];
1299
1333
  const memoriesText = memories.map((m) => {
1300
1334
  const unverified = m.status === "proposed" ? " [UNVERIFIED \u2014 not yet validated]" : "";
@@ -1356,15 +1390,52 @@ ${m.content}`).join("\n\n---\n\n"),
1356
1390
  if (isDecaying(u, createdAt)) decayWarnings.push(m.id);
1357
1391
  }
1358
1392
  const outputMemories = input.format === "compact" ? trimmedMemories.map((m) => ({ ...m, body: compactSummary(m.body) })) : trimmedMemories;
1393
+ let symbolLocations;
1394
+ const symbolsToLookup = new Set(input.symbols);
1395
+ for (const m of outputMemories) {
1396
+ const loaded = byId.get(m.id);
1397
+ for (const sym of loaded?.memory.frontmatter.anchor.symbols ?? []) {
1398
+ symbolsToLookup.add(sym);
1399
+ }
1400
+ }
1401
+ if (symbolsToLookup.size > 0) {
1402
+ const codeMap = await loadCodeMap(ctx.paths);
1403
+ if (codeMap) {
1404
+ symbolLocations = [];
1405
+ for (const sym of symbolsToLookup) {
1406
+ const { files } = queryCodeMap(codeMap, { symbol: sym });
1407
+ if (files.length > 0) {
1408
+ symbolLocations.push({
1409
+ symbol: sym,
1410
+ locations: files.flatMap(
1411
+ (f) => f.entry.exports.filter((e) => e.name.toLowerCase().includes(sym.toLowerCase())).map((e) => ({
1412
+ file: f.path,
1413
+ kind: e.kind,
1414
+ line: e.line,
1415
+ ...e.description ? { description: e.description } : {}
1416
+ }))
1417
+ )
1418
+ });
1419
+ }
1420
+ }
1421
+ if (symbolLocations.length === 0) symbolLocations = void 0;
1422
+ }
1423
+ }
1359
1424
  return {
1360
1425
  ...input.task ? { task: input.task } : {},
1361
1426
  search_mode: searchMode,
1362
1427
  inferred_modules: inferred,
1363
1428
  ...lastSession ? { last_session: lastSession } : {},
1364
- project_context: projectContext ? { content: projectSlice.text, truncated: projectSlice.truncated } : null,
1429
+ project_context: projectContextRaw ? {
1430
+ content: projectSlice.text,
1431
+ truncated: projectSlice.truncated,
1432
+ ...isTemplateContext ? { is_template: true } : {}
1433
+ } : null,
1365
1434
  module_contexts: trimmedModules,
1366
1435
  memories: outputMemories,
1436
+ ...symbolLocations ? { symbol_locations: symbolLocations } : {},
1367
1437
  decay_warnings: decayWarnings,
1438
+ setup_warnings: setupWarnings,
1368
1439
  estimated_tokens: totalTokens,
1369
1440
  budget: {
1370
1441
  max_tokens: input.max_tokens,
@@ -1412,7 +1483,7 @@ async function loadModuleContexts2(ctx, modules) {
1412
1483
  }
1413
1484
 
1414
1485
  // src/tools/code-map.ts
1415
- import { loadCodeMap, queryCodeMap } from "@hiveai/core";
1486
+ import { loadCodeMap as loadCodeMap2, queryCodeMap as queryCodeMap2 } from "@hiveai/core";
1416
1487
  import { z as z18 } from "zod";
1417
1488
  var CodeMapInputSchema = {
1418
1489
  file: z18.string().optional().describe("Filter to files whose path contains this substring"),
@@ -1420,7 +1491,7 @@ var CodeMapInputSchema = {
1420
1491
  max_files: z18.number().int().positive().default(40).describe("Cap on returned files")
1421
1492
  };
1422
1493
  async function codeMapTool(input, ctx) {
1423
- const map = await loadCodeMap(ctx.paths);
1494
+ const map = await loadCodeMap2(ctx.paths);
1424
1495
  if (!map) {
1425
1496
  return {
1426
1497
  available: false,
@@ -1428,7 +1499,7 @@ async function codeMapTool(input, ctx) {
1428
1499
  notice: "No code map found. Run `haive index code` to generate `.ai/code-map.json`."
1429
1500
  };
1430
1501
  }
1431
- const { files } = queryCodeMap(map, { file: input.file, symbol: input.symbol });
1502
+ const { files } = queryCodeMap2(map, { file: input.file, symbol: input.symbol });
1432
1503
  return {
1433
1504
  available: true,
1434
1505
  generated_at: map.generated_at,
@@ -1730,7 +1801,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
1730
1801
 
1731
1802
  // src/server.ts
1732
1803
  var SERVER_NAME = "haive";
1733
- var SERVER_VERSION = "0.2.15";
1804
+ var SERVER_VERSION = "0.3.0";
1734
1805
  function jsonResult(data) {
1735
1806
  return {
1736
1807
  content: [