@hiveai/cli 0.19.0 → 0.20.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
@@ -262,6 +262,7 @@ import {
262
262
  loadCodeMap,
263
263
  loadMemoriesFromDir,
264
264
  loadUsageIndex,
265
+ looksLikeGenericAdvice,
265
266
  resolveHaivePaths,
266
267
  serializeMemory,
267
268
  specificityScore
@@ -310,7 +311,9 @@ async function lintMemoriesAsync(root, options = {}) {
310
311
  message: "Record does not contain obvious action/rationale words. Add the concrete rule, why it exists, and what to do instead."
311
312
  });
312
313
  }
313
- if (["decision", "gotcha", "convention", "architecture"].includes(fm.type) && fm.status !== "rejected" && naked.length >= 40 && specificityScore(naked) < 0.2) {
314
+ if (["decision", "gotcha", "convention", "architecture"].includes(fm.type) && fm.status !== "rejected" && naked.length >= 40 && specificityScore(naked) < 0.2 && // High-precision gate: only flag when there is positive evidence of generic advice.
315
+ // A low-density but arbitrary team policy (unguessable prose) must not be flagged.
316
+ looksLikeGenericAdvice(naked)) {
314
317
  out.push({
315
318
  file: filePath,
316
319
  id: fm.id,
@@ -3309,9 +3312,10 @@ async function seedStackPack(haivePaths, stack) {
3309
3312
  autogen: false,
3310
3313
  last_fired: null
3311
3314
  } : void 0;
3315
+ const combinedSlug = mem.slug === stack || mem.slug.startsWith(`${stack}-`) ? mem.slug : `${stack}-${mem.slug}`;
3312
3316
  const fm = buildFrontmatter({
3313
3317
  type: mem.type,
3314
- slug: `${stack}-${mem.slug}`,
3318
+ slug: combinedSlug,
3315
3319
  scope: "team",
3316
3320
  status: "validated",
3317
3321
  // STACK_PACK_TAG marks this as generic seed knowledge so briefing ranking
@@ -3334,7 +3338,7 @@ ${SEED_FOOTER(stack)}` });
3334
3338
 
3335
3339
  // src/commands/init.ts
3336
3340
  var execFileAsync = promisify2(execFile2);
3337
- var HAIVE_GITHUB_ACTION_REF = `v${"0.19.0"}`;
3341
+ var HAIVE_GITHUB_ACTION_REF = `v${"0.20.0"}`;
3338
3342
  var PROJECT_CONTEXT_TEMPLATE = `# Project context
3339
3343
 
3340
3344
  > Generated by \`haive init\`. Run \`haive init --bootstrap\` to auto-fill from your codebase,
@@ -7894,8 +7898,17 @@ function classifyWarning(warning, paths, anchoredBlocks = false) {
7894
7898
  repair_command: repairCommand
7895
7899
  };
7896
7900
  }
7901
+ if (warning.has_sensor && !warning.reasons.includes("sensor") && !warning.reasons.includes("anchor")) {
7902
+ return {
7903
+ ...warning,
7904
+ level: "info",
7905
+ rationale: "memory has a deterministic sensor that did not fire and is not anchored to a touched file \u2014 treated as non-violation noise",
7906
+ affected_files: affectedFiles,
7907
+ repair_command: repairCommand
7908
+ };
7909
+ }
7897
7910
  const corroborated = warning.reasons.includes("anchor") || warning.distinctive_literal === true;
7898
- const semanticReviewFloor = corroborated ? 0.45 : 0.6;
7911
+ const semanticReviewFloor = corroborated ? 0.45 : 0.65;
7899
7912
  if (hasSemantic && semanticScore >= semanticReviewFloor || highConfidence && warning.reasons.includes("anchor") && warning.reasons.includes("literal")) {
7900
7913
  return {
7901
7914
  ...warning,
@@ -8571,7 +8584,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
8571
8584
  };
8572
8585
  }
8573
8586
  var SERVER_NAME = "haive";
8574
- var SERVER_VERSION = "0.19.0";
8587
+ var SERVER_VERSION = "0.20.0";
8575
8588
  function jsonResult(data) {
8576
8589
  return {
8577
8590
  content: [
@@ -14323,7 +14336,7 @@ function registerDoctor(program2) {
14323
14336
  fix: "Edit .ai/haive.config.json: set autoSessionEnd: true (or re-run `haive init` without --manual)."
14324
14337
  });
14325
14338
  }
14326
- findings.push(...await collectInstallFindings(root, "0.19.0"));
14339
+ findings.push(...await collectInstallFindings(root, "0.20.0"));
14327
14340
  findings.push(...await collectToolchainFindings(root));
14328
14341
  try {
14329
14342
  const legacyRaw = execSync3("haive-mcp --version", {
@@ -14331,7 +14344,7 @@ function registerDoctor(program2) {
14331
14344
  timeout: 3e3,
14332
14345
  stdio: ["ignore", "pipe", "ignore"]
14333
14346
  }).trim();
14334
- const cliVersion = "0.19.0";
14347
+ const cliVersion = "0.20.0";
14335
14348
  if (legacyRaw && legacyRaw !== cliVersion) {
14336
14349
  findings.push({
14337
14350
  severity: "warn",
@@ -15411,17 +15424,21 @@ import path53 from "path";
15411
15424
  import "commander";
15412
15425
  import {
15413
15426
  antiPatternGateParams as antiPatternGateParams2,
15427
+ BRIDGE_TARGET_PATH as BRIDGE_TARGET_PATH2,
15414
15428
  findProjectRoot as findProjectRoot52,
15415
15429
  findUncapturedFailures,
15416
15430
  hasRecentBriefingMarker as hasRecentBriefingMarker2,
15417
15431
  isFreshIsoDate,
15432
+ isRetiredMemory as isRetiredMemory3,
15418
15433
  loadConfig as loadConfig14,
15419
15434
  loadMemoriesFromDir as loadMemoriesFromDir38,
15420
15435
  memoryMatchesAnchorPaths as memoryMatchesAnchorPaths6,
15421
15436
  readRecentBriefingMarker,
15422
15437
  resolveBriefingBudget as resolveBriefingBudget3,
15423
15438
  resolveHaivePaths as resolveHaivePaths48,
15439
+ runSensors as runSensors2,
15424
15440
  saveConfig as saveConfig4,
15441
+ sensorTargetsFromDiff as sensorTargetsFromDiff2,
15425
15442
  SESSION_RECAP_TTL_MS,
15426
15443
  verifyAnchor as verifyAnchor4,
15427
15444
  writeBriefingMarker as writeBriefingMarker3
@@ -16027,7 +16044,7 @@ async function buildEnforcementReport(dir, stage, sessionId) {
16027
16044
  findings: [{ severity: "info", code: "enforcement-off", message: "hAIve enforcement is disabled." }]
16028
16045
  });
16029
16046
  }
16030
- findings.push(...await inspectIntegrationVersions(root, "0.19.0"));
16047
+ findings.push(...await inspectIntegrationVersions(root, "0.20.0"));
16031
16048
  if (config.enforcement?.requireBriefingFirst !== false && stage !== "ci") {
16032
16049
  const hasBriefing = await hasRecentBriefingMarker2(paths, sessionId);
16033
16050
  findings.push(hasBriefing ? { severity: "ok", code: "briefing-loaded", message: "A recent hAIve briefing marker exists." } : {
@@ -16213,20 +16230,83 @@ async function runPrecommitPolicy(paths, gate, stage) {
16213
16230
  anchored_blocks,
16214
16231
  semantic: true
16215
16232
  }, { paths });
16233
+ const sensorFindings = await runSensorGate(paths, snapshot.diff);
16216
16234
  if (!result.should_block) {
16217
- return [{
16218
- severity: "ok",
16219
- code: "precommit-policy-pass",
16220
- message: `${stage === "ci" ? "CI" : "Pre-commit"} policy passed for ${touchedPaths.length} changed file(s).`
16221
- }];
16235
+ return [
16236
+ {
16237
+ severity: "ok",
16238
+ code: "precommit-policy-pass",
16239
+ message: `${stage === "ci" ? "CI" : "Pre-commit"} policy passed for ${touchedPaths.length} changed file(s).`
16240
+ },
16241
+ ...sensorFindings
16242
+ ];
16243
+ }
16244
+ return [
16245
+ {
16246
+ severity: "error",
16247
+ code: "precommit-policy-block",
16248
+ message: `Pre-commit policy matched ${result.summary.blocking_warnings ?? result.summary.anti_patterns} blocking anti-pattern(s), ${result.summary.stale_anchors} stale anchor(s).`,
16249
+ fix: "Review the hAIve warnings, then update the code or the relevant memories.",
16250
+ impact: 45
16251
+ },
16252
+ ...sensorFindings
16253
+ ];
16254
+ }
16255
+ var SENSOR_OWNED_FILES = /* @__PURE__ */ new Set([
16256
+ ...Object.values(BRIDGE_TARGET_PATH2),
16257
+ "CLAUDE.md",
16258
+ ".cursorrules",
16259
+ ".gitignore",
16260
+ ".mcp.json",
16261
+ ".cursor/mcp.json",
16262
+ ".vscode/mcp.json",
16263
+ ".cursor/rules/haive-mcp-required.mdc"
16264
+ ]);
16265
+ function isSensorScannablePath(p) {
16266
+ if (!p) return false;
16267
+ if (p.startsWith(".ai/")) return false;
16268
+ return !SENSOR_OWNED_FILES.has(p);
16269
+ }
16270
+ async function runSensorGate(paths, diff) {
16271
+ if (!diff || !existsSync75(paths.memoriesDir)) return [];
16272
+ try {
16273
+ const loaded = await loadMemoriesFromDir38(paths.memoriesDir);
16274
+ const sensorMemories = loaded.map((l) => l.memory).filter((m) => {
16275
+ const s = m.frontmatter.sensor;
16276
+ return Boolean(s) && s.kind === "regex" && !isRetiredMemory3(m.frontmatter, m.body);
16277
+ });
16278
+ if (sensorMemories.length === 0) return [];
16279
+ const targets = sensorTargetsFromDiff2(diff).filter((t) => isSensorScannablePath(t.path));
16280
+ if (targets.length === 0) return [];
16281
+ const hits = runSensors2(sensorMemories, targets);
16282
+ const findings = [];
16283
+ const seen = /* @__PURE__ */ new Set();
16284
+ for (const hit of hits) {
16285
+ if (seen.has(hit.memory_id)) continue;
16286
+ seen.add(hit.memory_id);
16287
+ const where = hit.file ? ` (${hit.file})` : "";
16288
+ if (hit.severity === "block") {
16289
+ findings.push({
16290
+ severity: "error",
16291
+ code: "sensor-block",
16292
+ message: `Block sensor fired \u2014 ${hit.memory_id}: ${hit.message}${where}`,
16293
+ fix: "Remove the flagged pattern, or run `haive sensors check` to inspect the match.",
16294
+ impact: 45
16295
+ });
16296
+ } else {
16297
+ findings.push({
16298
+ severity: "warn",
16299
+ code: "sensor-warn",
16300
+ message: `Sensor flagged ${hit.memory_id}: ${hit.message}${where}`,
16301
+ fix: "Review the flagged line; `haive sensors check` shows the matched code.",
16302
+ impact: 5
16303
+ });
16304
+ }
16305
+ }
16306
+ return findings;
16307
+ } catch {
16308
+ return [];
16222
16309
  }
16223
- return [{
16224
- severity: "error",
16225
- code: "precommit-policy-block",
16226
- message: `Pre-commit policy matched ${result.summary.blocking_warnings ?? result.summary.anti_patterns} blocking anti-pattern(s), ${result.summary.stale_anchors} stale anchor(s).`,
16227
- fix: "Review the hAIve warnings, then update the code or the relevant memories.",
16228
- impact: 45
16229
- }];
16230
16310
  }
16231
16311
  async function findGeneratedArtifacts(paths) {
16232
16312
  const dirty = await runCommand4("git", ["status", "--short", "--untracked-files=all"], paths.root).catch(() => "");
@@ -17022,16 +17102,16 @@ import "commander";
17022
17102
  import {
17023
17103
  appendPreventionEvent as appendPreventionEvent2,
17024
17104
  findProjectRoot as findProjectRoot53,
17025
- isRetiredMemory as isRetiredMemory3,
17105
+ isRetiredMemory as isRetiredMemory4,
17026
17106
  loadConfig as loadConfig15,
17027
17107
  loadMemoriesFromDir as loadMemoriesFromDir39,
17028
17108
  loadUsageIndex as loadUsageIndex31,
17029
17109
  recordPrevention as recordPrevention2,
17030
17110
  resolveHaivePaths as resolveHaivePaths49,
17031
- runSensors as runSensors2,
17111
+ runSensors as runSensors3,
17032
17112
  saveUsageIndex as saveUsageIndex8,
17033
17113
  selectCommandSensors,
17034
- sensorTargetsFromDiff as sensorTargetsFromDiff2,
17114
+ sensorTargetsFromDiff as sensorTargetsFromDiff3,
17035
17115
  serializeMemory as serializeMemory29
17036
17116
  } from "@hiveai/core";
17037
17117
  var exec2 = promisify3(execFile3);
@@ -17065,8 +17145,8 @@ function registerSensors(program2) {
17065
17145
  const paths = resolveHaivePaths49(root);
17066
17146
  const memories = await runnableSensorMemories(paths);
17067
17147
  const diff = opts.diffFile ? await readFile25(path54.resolve(root, opts.diffFile), "utf8") : await stagedDiff(root);
17068
- const targets = sensorTargetsFromDiff2(diff);
17069
- const hits = runSensors2(memories, targets.length > 0 ? targets : [{ path: "", content: diff }]);
17148
+ const targets = sensorTargetsFromDiff3(diff);
17149
+ const hits = runSensors3(memories, targets.length > 0 ? targets : [{ path: "", content: diff }]);
17070
17150
  const config = await loadConfig15(paths);
17071
17151
  const runCommands = opts.commands || config.enforcement?.runCommandSensors === true;
17072
17152
  const changedPaths = targets.map((t) => t.path).filter(Boolean);
@@ -17222,7 +17302,7 @@ async function runnableSensorMemories(paths, regexOnly = true) {
17222
17302
  const sensor = memory2.frontmatter.sensor;
17223
17303
  if (!sensor) return false;
17224
17304
  if (regexOnly && sensor.kind !== "regex") return false;
17225
- return !isRetiredMemory3(memory2.frontmatter, memory2.body);
17305
+ return !isRetiredMemory4(memory2.frontmatter, memory2.body);
17226
17306
  });
17227
17307
  }
17228
17308
  async function runCommandSensor(spec, root) {
@@ -17924,7 +18004,7 @@ import "commander";
17924
18004
  import {
17925
18005
  findProjectRoot as findProjectRoot61,
17926
18006
  resolveHaivePaths as resolveHaivePaths55,
17927
- BRIDGE_TARGET_PATH as BRIDGE_TARGET_PATH2,
18007
+ BRIDGE_TARGET_PATH as BRIDGE_TARGET_PATH3,
17928
18008
  BRIDGE_TARGETS as BRIDGE_TARGETS3
17929
18009
  } from "@hiveai/core";
17930
18010
  function registerBridges(program2) {
@@ -17959,7 +18039,7 @@ function registerBridges(program2) {
17959
18039
  targets = BRIDGE_TARGETS3;
17960
18040
  } else {
17961
18041
  targets = BRIDGE_TARGETS3.filter(
17962
- (t) => existsSync84(path59.join(root, BRIDGE_TARGET_PATH2[t]))
18042
+ (t) => existsSync84(path59.join(root, BRIDGE_TARGET_PATH3[t]))
17963
18043
  );
17964
18044
  if (targets.length === 0) {
17965
18045
  ui.info(
@@ -17987,7 +18067,7 @@ function registerBridges(program2) {
17987
18067
  const root = findProjectRoot61(opts.dir);
17988
18068
  console.log(ui.bold("hAIve bridge targets:"));
17989
18069
  for (const target of BRIDGE_TARGETS3) {
17990
- const relPath = BRIDGE_TARGET_PATH2[target];
18070
+ const relPath = BRIDGE_TARGET_PATH3[target];
17991
18071
  const exists = existsSync84(path59.join(root, relPath));
17992
18072
  const marker = exists ? ui.dim("\u2713") : ui.dim("\xB7");
17993
18073
  console.log(` ${marker} ${target.padEnd(10)} ${relPath}${exists ? "" : " (not present)"}`);
@@ -17999,7 +18079,7 @@ function registerBridges(program2) {
17999
18079
 
18000
18080
  // src/index.ts
18001
18081
  var program = new Command64();
18002
- program.name("haive").description("hAIve - repo-native memory and context policy for coding-agent harnesses").version("0.19.0").option("--advanced", "show maintenance and experimental commands in help");
18082
+ program.name("haive").description("hAIve - repo-native memory and context policy for coding-agent harnesses").version("0.20.0").option("--advanced", "show maintenance and experimental commands in help");
18003
18083
  registerInit(program);
18004
18084
  registerWelcome(program);
18005
18085
  registerResolveProject(program);