@hiveai/cli 0.9.22 → 0.9.24

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
@@ -715,6 +715,7 @@ function registerIndexCode(program2) {
715
715
  const extraExcludes = (opts.exclude ?? "").split(",").map((s) => s.trim()).filter(Boolean);
716
716
  ui.info(`Indexing source files in ${root}\u2026`);
717
717
  const map = await buildCodeMap(root, {
718
+ includeUntracked: true,
718
719
  excludeDirs: [
719
720
  "node_modules",
720
721
  "dist",
@@ -1625,11 +1626,10 @@ async function projectContextVersionStatus(root, paths) {
1625
1626
  };
1626
1627
  }
1627
1628
  async function refreshCodeMap(root, paths, force) {
1628
- if (!force) {
1629
- const existing = await loadCodeMap3(paths);
1630
- if (existing) return false;
1631
- }
1629
+ const existing = await loadCodeMap3(paths);
1630
+ if (existing && !force) return false;
1632
1631
  const map = await buildCodeMap2(root, {
1632
+ includeUntracked: true,
1633
1633
  excludeDirs: [
1634
1634
  "node_modules",
1635
1635
  "dist",
@@ -1642,6 +1642,9 @@ async function refreshCodeMap(root, paths, force) {
1642
1642
  "coverage"
1643
1643
  ]
1644
1644
  });
1645
+ if (existing && existing.root === map.root && JSON.stringify(existing.files) === JSON.stringify(map.files)) {
1646
+ return false;
1647
+ }
1645
1648
  await saveCodeMap2(paths, map);
1646
1649
  return true;
1647
1650
  }
@@ -2934,7 +2937,7 @@ function registerInit(program2) {
2934
2937
  }
2935
2938
  try {
2936
2939
  ui.info("Building code-map\u2026");
2937
- const map = await buildCodeMap3(root);
2940
+ const map = await buildCodeMap3(root, { includeUntracked: true });
2938
2941
  await saveCodeMap3(paths, map);
2939
2942
  ui.success(`Code-map built (${Object.keys(map.files).length} files)`);
2940
2943
  } catch {
@@ -4385,6 +4388,7 @@ function toMatch(loaded, reason, usage) {
4385
4388
  confidence: deriveConfidence2(fm, u),
4386
4389
  read_count: u.read_count,
4387
4390
  reason,
4391
+ anchor_paths: fm.anchor.paths,
4388
4392
  file_path: loaded.filePath,
4389
4393
  body: loaded.memory.body
4390
4394
  };
@@ -6436,12 +6440,17 @@ async function preCommitCheck(input, ctx) {
6436
6440
  },
6437
6441
  warnings: classifiedWarnings,
6438
6442
  relevant_memories,
6439
- stale_anchors: staleHits.map((r) => ({
6440
- id: r.id,
6441
- // The matching `relevantMatches` entry tells us which paths overlap.
6442
- paths: relevantMatches.find((m) => m.id === r.id) ? input.paths.filter((p) => relevantMatches.some((m) => m.id === r.id)) : [],
6443
- body_preview: r.reason ?? "anchored code drifted; verify before relying on this memory"
6444
- }))
6443
+ stale_anchors: staleHits.map((r) => {
6444
+ const match = relevantMatches.find((m) => m.id === r.id);
6445
+ const overlapping = match ? input.paths.filter(
6446
+ (p) => match.anchor_paths.some((ap) => ap === p || p.startsWith(ap + "/") || ap.startsWith(p + "/"))
6447
+ ) : [];
6448
+ return {
6449
+ id: r.id,
6450
+ paths: overlapping.length > 0 ? overlapping : match ? input.paths : [],
6451
+ body_preview: r.reason ?? "anchored code drifted; verify before relying on this memory"
6452
+ };
6453
+ })
6445
6454
  };
6446
6455
  }
6447
6456
  function classifyWarning(warning, paths) {
@@ -6461,7 +6470,7 @@ function classifyWarning(warning, paths) {
6461
6470
  return {
6462
6471
  ...warning,
6463
6472
  level: "blocking",
6464
- rationale: "authoritative/trusted memory plus strong semantic match to the diff (score >= 0.65)",
6473
+ rationale: "authoritative/trusted memory plus very strong semantic match to the diff (score >= 0.75)",
6465
6474
  affected_files: affectedFiles,
6466
6475
  repair_command: repairCommand
6467
6476
  };
@@ -6489,7 +6498,8 @@ function classifyWarning(warning, paths) {
6489
6498
  function isBlockingWarning(warning) {
6490
6499
  const highConfidence = warning.confidence === "authoritative" || warning.confidence === "trusted";
6491
6500
  if (!highConfidence) return false;
6492
- return warning.reasons.includes("semantic") && (warning.semantic_score ?? 0) >= 0.65;
6501
+ if (!warning.reasons.includes("semantic")) return false;
6502
+ return (warning.semantic_score ?? 0) >= 0.75;
6493
6503
  }
6494
6504
  function fileTypeDowngradeReason(warning, paths) {
6495
6505
  if (paths.length === 0) return null;
@@ -6501,8 +6511,8 @@ function fileTypeDowngradeReason(warning, paths) {
6501
6511
  return "docs/changelog-only change; anti-pattern is downgraded unless semantic evidence is strong.";
6502
6512
  }
6503
6513
  const configOnly = paths.every(isPackageOrConfigPath);
6504
- if (configOnly && looksRuntimeSpecific(warning) && !warning.reasons.includes("anchor") && !hasStrongSemantic(warning)) {
6505
- return "package/config-only change; runtime-specific gotcha is not anchored or semantically strong.";
6514
+ if (configOnly && !warning.reasons.includes("anchor") && !hasStrongSemantic(warning)) {
6515
+ return "package/config-only change; warning has no anchor on these files and no strong semantic match \u2014 downgraded to info.";
6506
6516
  }
6507
6517
  return null;
6508
6518
  }
@@ -6517,10 +6527,6 @@ function isPackageOrConfigPath(file) {
6517
6527
  const lower = file.toLowerCase();
6518
6528
  return lower.endsWith("package.json") || lower.endsWith("package-lock.json") || lower.endsWith("pnpm-lock.yaml") || lower.endsWith("yarn.lock") || lower.endsWith("bun.lockb") || lower.endsWith(".config.ts") || lower.endsWith(".config.js") || lower.endsWith(".json") || lower.endsWith(".yml") || lower.endsWith(".yaml") || lower.startsWith(".github/workflows/");
6519
6529
  }
6520
- function looksRuntimeSpecific(warning) {
6521
- const text = `${warning.body_preview} ${warning.id}`.toLowerCase();
6522
- return /\b(runtime|controller|request|response|database|transaction|auth|cache|production|service|api|endpoint)\b/.test(text);
6523
- }
6524
6530
  function repairCommandForWarning(warning, paths) {
6525
6531
  const firstPath = paths[0];
6526
6532
  return firstPath ? `haive briefing --files "${firstPath}" --task "review ${warning.id}"` : `haive memory show ${warning.id}`;
@@ -7056,7 +7062,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
7056
7062
  };
7057
7063
  }
7058
7064
  var SERVER_NAME = "haive";
7059
- var SERVER_VERSION = "0.9.22";
7065
+ var SERVER_VERSION = "0.9.24";
7060
7066
  function jsonResult(data) {
7061
7067
  return {
7062
7068
  content: [
@@ -8654,6 +8660,7 @@ TODO \u2014 write the memory body.
8654
8660
  await writeFile14(topicMatch.filePath, serializeMemory12({ frontmatter: newFrontmatter, body }), "utf8");
8655
8661
  ui.success(`Updated (topic upsert) ${path16.relative(root, topicMatch.filePath)}`);
8656
8662
  ui.info(`id=${fm.id} revision=${revisionCount}`);
8663
+ await runPostMemoryAutopilot(root, paths, config);
8657
8664
  return;
8658
8665
  }
8659
8666
  }
@@ -8693,6 +8700,7 @@ TODO \u2014 write the memory body.
8693
8700
  await writeFile14(file, serializeMemory12({ frontmatter, body }), "utf8");
8694
8701
  ui.success(`Created ${path16.relative(root, file)}`);
8695
8702
  ui.info(`id=${frontmatter.id} scope=${frontmatter.scope} status=${frontmatter.status}`);
8703
+ await runPostMemoryAutopilot(root, paths, config);
8696
8704
  if (inferredTags.length > 0) {
8697
8705
  ui.info(`auto-tagged: ${inferredTags.join(", ")} (use --no-auto-tag to disable)`);
8698
8706
  }
@@ -8718,6 +8726,19 @@ TODO \u2014 write the memory body.
8718
8726
  }
8719
8727
  });
8720
8728
  }
8729
+ async function runPostMemoryAutopilot(root, paths, config) {
8730
+ if (!config.autopilot && config.autoRepair?.corpus !== true) return;
8731
+ const repairs = await applyAutopilotRepairs(root, paths, {
8732
+ applyConfig: false,
8733
+ applyContext: false,
8734
+ applyCorpus: true,
8735
+ applyCodeMap: false,
8736
+ applyCodeSearch: false
8737
+ });
8738
+ for (const repair of repairs) {
8739
+ ui.info(repair.message);
8740
+ }
8741
+ }
8721
8742
  function parseCsv2(value) {
8722
8743
  if (!value) return [];
8723
8744
  return value.split(",").map((s) => s.trim()).filter(Boolean);
@@ -11624,7 +11645,8 @@ function registerDoctor(program2) {
11624
11645
  applyContext: true,
11625
11646
  applyCorpus: true,
11626
11647
  applyCodeMap: true,
11627
- applyCodeSearch: true
11648
+ applyCodeSearch: true,
11649
+ forceCodeMap: true
11628
11650
  })
11629
11651
  );
11630
11652
  }
@@ -11810,14 +11832,14 @@ function registerDoctor(program2) {
11810
11832
  fix: "Edit .ai/haive.config.json: set autoSessionEnd: true (or re-run `haive init` without --manual)."
11811
11833
  });
11812
11834
  }
11813
- findings.push(...await collectInstallFindings(root, "0.9.22"));
11835
+ findings.push(...await collectInstallFindings(root, "0.9.24"));
11814
11836
  try {
11815
11837
  const legacyRaw = execSync3("haive-mcp --version", {
11816
11838
  encoding: "utf8",
11817
11839
  timeout: 3e3,
11818
11840
  stdio: ["ignore", "pipe", "ignore"]
11819
11841
  }).trim();
11820
- const cliVersion = "0.9.22";
11842
+ const cliVersion = "0.9.24";
11821
11843
  if (legacyRaw && legacyRaw !== cliVersion) {
11822
11844
  findings.push({
11823
11845
  severity: "warn",
@@ -12358,6 +12380,24 @@ function registerPrecommit(program2) {
12358
12380
  try {
12359
12381
  diff = await runCommand3("git", ["diff", "--cached"], root);
12360
12382
  if (!diff.trim()) {
12383
+ if (opts.json) {
12384
+ console.log(JSON.stringify({
12385
+ should_block: false,
12386
+ summary: {
12387
+ anti_patterns: 0,
12388
+ blocking_warnings: 0,
12389
+ review_warnings: 0,
12390
+ info_warnings: 0,
12391
+ relevant_memories: 0,
12392
+ stale_anchors: 0
12393
+ },
12394
+ warnings: [],
12395
+ relevant_memories: [],
12396
+ stale_anchors: [],
12397
+ notice: "No staged changes \u2014 nothing to check."
12398
+ }, null, 2));
12399
+ return;
12400
+ }
12361
12401
  ui.warn("No staged changes \u2014 nothing to check. Stage with `git add` first.");
12362
12402
  return;
12363
12403
  }
@@ -12768,16 +12808,12 @@ function registerEnforce(program2) {
12768
12808
  enforce.command("cleanup").description("Remove generated hAIve runtime/cache artifacts that should not appear in commits.").option("-d, --dir <dir>", "project root").option("--dry-run", "print what would be removed without deleting", false).action(async (opts) => {
12769
12809
  const root = findProjectRoot48(opts.dir);
12770
12810
  const paths = resolveHaivePaths44(root);
12771
- const targets = [
12772
- path49.join(paths.haiveDir, ".cache")
12773
- ];
12774
- for (const target of targets) {
12775
- if (!existsSync67(target)) continue;
12776
- const rel = path49.relative(root, target);
12777
- if (opts.dryRun) ui.info(`would remove ${rel}`);
12811
+ const cacheDir = path49.join(paths.haiveDir, ".cache");
12812
+ if (existsSync67(cacheDir)) {
12813
+ if (opts.dryRun) ui.info(`would clean ${path49.relative(root, cacheDir)} (preserving .gitignore)`);
12778
12814
  else {
12779
- await rm3(target, { recursive: true, force: true });
12780
- ui.success(`removed ${rel}`);
12815
+ const removed = await cleanupCacheDir(cacheDir);
12816
+ ui.success(`cleaned ${path49.relative(root, cacheDir)}${removed > 0 ? ` (${removed} item${removed === 1 ? "" : "s"} removed)` : ""}`);
12781
12817
  }
12782
12818
  }
12783
12819
  if (existsSync67(paths.runtimeDir)) {
@@ -13008,7 +13044,7 @@ async function buildEnforcementReport(dir, stage, sessionId) {
13008
13044
  findings: [{ severity: "info", code: "enforcement-off", message: "hAIve enforcement is disabled." }]
13009
13045
  });
13010
13046
  }
13011
- findings.push(...await inspectIntegrationVersions(root, "0.9.22"));
13047
+ findings.push(...await inspectIntegrationVersions(root, "0.9.24"));
13012
13048
  if (config.enforcement?.requireBriefingFirst !== false && stage !== "ci") {
13013
13049
  const hasBriefing = await hasRecentBriefingMarker(paths, sessionId);
13014
13050
  findings.push(hasBriefing ? { severity: "ok", code: "briefing-loaded", message: "A recent hAIve briefing marker exists." } : {
@@ -13237,6 +13273,18 @@ async function cleanupRuntimeDir(runtimeDir) {
13237
13273
  }
13238
13274
  return removed;
13239
13275
  }
13276
+ async function cleanupCacheDir(cacheDir) {
13277
+ let removed = 0;
13278
+ await mkdir19(cacheDir, { recursive: true });
13279
+ const entries = await readdir6(cacheDir, { withFileTypes: true }).catch(() => []);
13280
+ for (const entry of entries) {
13281
+ if (entry.name === ".gitignore") continue;
13282
+ await rm3(path49.join(cacheDir, entry.name), { recursive: true, force: true });
13283
+ removed++;
13284
+ }
13285
+ await writeFile31(path49.join(cacheDir, ".gitignore"), "*\n!.gitignore\n", "utf8");
13286
+ return removed;
13287
+ }
13240
13288
  async function cleanupEnforcementDir(enforcementDir) {
13241
13289
  let removed = 0;
13242
13290
  const entries = await readdir6(enforcementDir, { withFileTypes: true }).catch(() => []);
@@ -13536,7 +13584,7 @@ function registerRun(program2) {
13536
13584
 
13537
13585
  // src/index.ts
13538
13586
  var program = new Command51();
13539
- program.name("haive").description("hAIve \u2014 the memory and enforcement layer of your agent harness").version("0.9.22").option("--advanced", "show maintenance and experimental commands in help");
13587
+ program.name("haive").description("hAIve \u2014 the memory and enforcement layer of your agent harness").version("0.9.24").option("--advanced", "show maintenance and experimental commands in help");
13540
13588
  registerInit(program);
13541
13589
  registerWelcome(program);
13542
13590
  registerResolveProject(program);