@hivelore/cli 0.44.0 → 0.47.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
@@ -13,7 +13,7 @@ import {
13
13
  readPresumedCorrectTargets,
14
14
  runAstSensorOnContent,
15
15
  runHaiveMcpStdio
16
- } from "./chunk-6KRXMDLC.js";
16
+ } from "./chunk-HBS7PNNY.js";
17
17
  import {
18
18
  registerMemoryPending
19
19
  } from "./chunk-OYJKHD22.js";
@@ -3758,7 +3758,7 @@ ${SEED_FOOTER(stack)}` });
3758
3758
 
3759
3759
  // src/commands/init.ts
3760
3760
  var execFileAsync = promisify2(execFile2);
3761
- var HAIVE_GITHUB_ACTION_REF = `v${"0.44.0"}`;
3761
+ var HAIVE_GITHUB_ACTION_REF = `v${"0.47.0"}`;
3762
3762
  var PROJECT_CONTEXT_TEMPLATE = `# Project context
3763
3763
 
3764
3764
  > Generated by \`hivelore init\`. Run \`hivelore init --bootstrap\` to auto-fill from your codebase,
@@ -7418,7 +7418,10 @@ import { mkdir as mkdir12, writeFile as writeFile18 } from "fs/promises";
7418
7418
  import path30 from "path";
7419
7419
  import {
7420
7420
  aggregateUsage,
7421
+ assessBehaviourCoverage,
7421
7422
  buildPreventionReceipt,
7423
+ loadCodeMap as loadCodeMap6,
7424
+ renderBehaviourCoverageLine,
7422
7425
  renderPreventionReceipt,
7423
7426
  findProjectRoot as findProjectRoot28,
7424
7427
  loadMemoriesFromDir as loadMemoriesFromDir11,
@@ -7447,6 +7450,19 @@ function registerStats(program2) {
7447
7450
  const receipt = buildPreventionReceipt(events, memories, usage, { since });
7448
7451
  const output = sub.share ? renderPreventionReceiptShare(receipt) : opts.json ? JSON.stringify(receipt, null, 2) : renderPreventionReceipt(receipt);
7449
7452
  console.log(output);
7453
+ if (!opts.json && !sub.share) {
7454
+ try {
7455
+ const codeMap = await loadCodeMap6(paths);
7456
+ if (codeMap) {
7457
+ const cov = assessBehaviourCoverage({ memories, codeFiles: Object.keys(codeMap.files) });
7458
+ if (cov.mainAreas.length > 0) {
7459
+ console.log(`
7460
+ Behaviour harness: ${renderBehaviourCoverageLine(cov)}.`);
7461
+ }
7462
+ }
7463
+ } catch {
7464
+ }
7465
+ }
7450
7466
  });
7451
7467
  stats.option("--since <window>", "ISO date or relative (e.g. '7d', '24h', '30m')", "30d").option("--json", "emit JSON instead of human-readable output", false).option("--memory-hits", "show top-read memories (which mems are actually being used)", false).option(
7452
7468
  "--export-report <path>",
@@ -8785,6 +8801,8 @@ import "commander";
8785
8801
  import {
8786
8802
  codeMapPath as codeMapPath2,
8787
8803
  assessSensorHealth as assessSensorHealth2,
8804
+ assessBehaviourCoverage as assessBehaviourCoverage2,
8805
+ renderBehaviourCoverageLine as renderBehaviourCoverageLine2,
8788
8806
  sensorPromotedAtMap as sensorPromotedAtMap2,
8789
8807
  countSourceFilesOnDisk,
8790
8808
  extractReferencedPaths,
@@ -8793,7 +8811,7 @@ import {
8793
8811
  findProjectRoot as findProjectRoot35,
8794
8812
  getUsage as getUsage9,
8795
8813
  isStackPackSeed as isStackPackSeed2,
8796
- loadCodeMap as loadCodeMap6,
8814
+ loadCodeMap as loadCodeMap7,
8797
8815
  loadConfig as loadConfig10,
8798
8816
  loadMemoriesFromDirDetailed,
8799
8817
  loadSensorLedger as loadSensorLedger2,
@@ -9124,7 +9142,7 @@ function registerDoctor(program2) {
9124
9142
  }
9125
9143
  const astSensorCount = sensorMemories.filter((m) => m.memory.frontmatter.sensor?.kind === "ast").length;
9126
9144
  if (astSensorCount > 0) {
9127
- const { astEngineAvailable: astEngineAvailable2 } = await import("./server-MCNCAFJN.js");
9145
+ const { astEngineAvailable: astEngineAvailable2 } = await import("./server-LNSXYVVW.js");
9128
9146
  if (!await astEngineAvailable2()) {
9129
9147
  findings.push({
9130
9148
  severity: "warn",
@@ -9185,7 +9203,7 @@ function registerDoctor(program2) {
9185
9203
  fix: "Review the sensor manually; no automatic delete/retire command is provided."
9186
9204
  });
9187
9205
  }
9188
- const codeMap = await loadCodeMap6(paths);
9206
+ const codeMap = await loadCodeMap7(paths);
9189
9207
  if (!codeMap) {
9190
9208
  findings.push({
9191
9209
  severity: "warn",
@@ -9217,6 +9235,7 @@ function registerDoctor(program2) {
9217
9235
  }
9218
9236
  }
9219
9237
  findings.push(...await collectHarnessCoverageFindings(codeMap, memories));
9238
+ findings.push(...collectBehaviourCoverageFindings(codeMap, memories));
9220
9239
  findings.push(...await collectSemanticIndexFindings(paths, config, memories.length, codeMap));
9221
9240
  try {
9222
9241
  const scaffoldGaps = await collectScaffoldLoopGaps(paths);
@@ -9294,8 +9313,8 @@ function registerDoctor(program2) {
9294
9313
  fix: "Edit .ai/haive.config.json: set autoSessionEnd: true (or re-run `hivelore init` without --manual)."
9295
9314
  });
9296
9315
  }
9297
- findings.push(...await collectInstallFindings(root, "0.44.0"));
9298
- findings.push(...await collectMcpRuntimeFindings(paths, "0.44.0"));
9316
+ findings.push(...await collectInstallFindings(root, "0.47.0"));
9317
+ findings.push(...await collectMcpRuntimeFindings(paths, "0.47.0"));
9299
9318
  findings.push(...await collectToolchainFindings(root));
9300
9319
  try {
9301
9320
  const legacyRaw = execSync("haive-mcp --version", {
@@ -9303,7 +9322,7 @@ function registerDoctor(program2) {
9303
9322
  timeout: 3e3,
9304
9323
  stdio: ["ignore", "pipe", "ignore"]
9305
9324
  }).trim();
9306
- const cliVersion = "0.44.0";
9325
+ const cliVersion = "0.47.0";
9307
9326
  if (legacyRaw && legacyRaw !== cliVersion) {
9308
9327
  findings.push({
9309
9328
  severity: "warn",
@@ -9560,6 +9579,32 @@ async function collectHarnessCoverageFindings(codeMap, memories) {
9560
9579
  });
9561
9580
  return findings;
9562
9581
  }
9582
+ function collectBehaviourCoverageFindings(codeMap, memories) {
9583
+ if (!codeMap) return [];
9584
+ const codeFiles = Object.keys(codeMap.files);
9585
+ const cov = assessBehaviourCoverage2({ memories, codeFiles });
9586
+ if (cov.mainAreas.length === 0) return [];
9587
+ const uncoveredHint = cov.uncoveredAreas.length > 0 && cov.totalOracles > 0 ? `
9588
+ No behavioural oracle: ${cov.uncoveredAreas.slice(0, 5).map((a) => `\`${a}\``).join(", ")}` + (cov.uncoveredAreas.length > 5 ? `, +${cov.uncoveredAreas.length - 5} more` : "") : "";
9589
+ let fix;
9590
+ if (cov.uncoveredAreas.length > 0) {
9591
+ const lines = cov.uncoveredAreaSuggestions.slice(0, 4).map(
9592
+ (s) => s.candidateLessonId ? `hivelore sensors scaffold ${s.candidateLessonId} --red-ref <pre-fix-commit> # guard ${s.area}` : `hivelore memory tried --paths ${s.area}/ --what "<incident>" --why-failed "<why>" # then scaffold --red-ref for ${s.area}`
9593
+ );
9594
+ if (cov.uncoveredAreas.length > 4) lines.push(`# +${cov.uncoveredAreas.length - 4} more uncovered area(s) \u2014 run doctor after guarding these`);
9595
+ fix = lines.join("\n");
9596
+ } else if (cov.armedOracles < cov.totalOracles || cov.redProvenOracles < cov.armedOracles) {
9597
+ fix = "Arm warn-only oracles to `block` and re-propose with `--red-ref` so each substantiates its incident.";
9598
+ }
9599
+ return [{
9600
+ severity: "info",
9601
+ code: "behaviour-coverage",
9602
+ section: "Protection",
9603
+ coverage_percent: Math.round(cov.areasWithOracle.length / cov.mainAreas.length * 100),
9604
+ message: `Behaviour harness: ${renderBehaviourCoverageLine2(cov)}.` + uncoveredHint,
9605
+ fix
9606
+ }];
9607
+ }
9563
9608
  async function collectSemanticIndexFindings(paths, config, memoryCount, codeMap) {
9564
9609
  const findings = [];
9565
9610
  const autoWantsCodeSearch = Boolean(config.autopilot || config.autoRepair?.codeSearch);
@@ -10085,7 +10130,7 @@ import {
10085
10130
  detectSensorWeakening,
10086
10131
  isSensorScannablePath,
10087
10132
  findProjectRoot as findProjectRoot37,
10088
- loadCodeMap as loadCodeMap7,
10133
+ loadCodeMap as loadCodeMap8,
10089
10134
  renderBootstrapChecklist,
10090
10135
  findUncapturedFailures,
10091
10136
  handoffAgeMs,
@@ -11018,7 +11063,7 @@ async function checkBootstrapComplete(paths, config, productionCodeChanged) {
11018
11063
  } catch {
11019
11064
  }
11020
11065
  const memories = existsSync42(paths.memoriesDir) ? await loadMemoriesFromDir15(paths.memoriesDir) : [];
11021
- const codeMap = await loadCodeMap7(paths);
11066
+ const codeMap = await loadCodeMap8(paths);
11022
11067
  const codeFiles = codeMap ? Object.keys(codeMap.files).filter((file) => existsSync42(path40.join(paths.root, file))) : [];
11023
11068
  let existingModules = [];
11024
11069
  try {
@@ -11083,7 +11128,7 @@ async function buildEnforcementReport(dir, stage, sessionId) {
11083
11128
  findings: [{ severity: "info", code: "enforcement-off", message: "Hivelore enforcement is disabled." }]
11084
11129
  });
11085
11130
  }
11086
- findings.push(...await inspectIntegrationVersions(root, "0.44.0"));
11131
+ findings.push(...await inspectIntegrationVersions(root, "0.47.0"));
11087
11132
  if (config.enforcement?.requireBriefingFirst !== false && stage !== "ci") {
11088
11133
  const hasBriefing = await hasRecentBriefingMarker(paths, sessionId);
11089
11134
  findings.push(hasBriefing ? { severity: "ok", code: "briefing-loaded", message: "A recent Hivelore briefing marker exists." } : {
@@ -11403,6 +11448,7 @@ async function runPrecommitPolicy(paths, gate, stage, config) {
11403
11448
  } catch {
11404
11449
  }
11405
11450
  }
11451
+ const noticeFinding = result.notice ? [{ severity: "info", code: "precommit-policy-notice", message: result.notice }] : [];
11406
11452
  if (!result.should_block) {
11407
11453
  return [
11408
11454
  {
@@ -11410,6 +11456,7 @@ async function runPrecommitPolicy(paths, gate, stage, config) {
11410
11456
  code: "precommit-policy-pass",
11411
11457
  message: `${stage === "ci" ? "CI" : "Pre-commit"} policy passed for ${touchedPaths.length} changed file(s).`
11412
11458
  },
11459
+ ...noticeFinding,
11413
11460
  ...reviewFinding,
11414
11461
  ...sensorFindings,
11415
11462
  ...weakeningFindings
@@ -11426,6 +11473,7 @@ async function runPrecommitPolicy(paths, gate, stage, config) {
11426
11473
  memory_ids: blockingWarnings.slice(0, 10).map((w) => w.id),
11427
11474
  impact: 45
11428
11475
  },
11476
+ ...noticeFinding,
11429
11477
  ...reviewFinding,
11430
11478
  ...sensorFindings,
11431
11479
  ...weakeningFindings
@@ -12720,6 +12768,7 @@ import {
12720
12768
  addedLineNumbersFromDiff as addedLineNumbersFromDiff2,
12721
12769
  buildProposeCommand,
12722
12770
  scaffoldPostIncidentTest,
12771
+ incidentHintsFromDiff,
12723
12772
  selectCommandSensors as selectCommandSensors2,
12724
12773
  TEST_FRAMEWORKS,
12725
12774
  sensorPatternBrittleness as sensorPatternBrittleness2,
@@ -13051,7 +13100,7 @@ function registerSensors(program2) {
13051
13100
  }
13052
13101
  }
13053
13102
  const root2 = findProjectRoot39(opts.dir);
13054
- const { proposeSensor } = await import("./server-MCNCAFJN.js");
13103
+ const { proposeSensor } = await import("./server-LNSXYVVW.js");
13055
13104
  const out = await proposeSensor(
13056
13105
  {
13057
13106
  memory_id: id,
@@ -13175,7 +13224,10 @@ function registerSensors(program2) {
13175
13224
  });
13176
13225
  sensors.command("scaffold").description(
13177
13226
  "Generate a PENDING post-incident test from a lesson (mem_tried/attempt/gotcha) \u2014 the on-ramp to\n a command sensor. Writes a test stub carrying the incident's provenance, then prints the exact\n `sensors propose --kind test` line to arm it once you've written the assertion. It never arms a\n sensor itself \u2014 propose_sensor stays the sole validated writer.\n\n Example:\n hivelore sensors scaffold 2026-07-03-attempt-refund-exceeds-capture --framework vitest"
13178
- ).argument("<memory-id>", "lesson id to scaffold a test from").option("--framework <fw>", `test framework: ${TEST_FRAMEWORKS.join(" | ")} (auto-detected when omitted)`).option("--out <path>", "override the generated test file path (project-relative)").option("--stdout", "print the test to stdout instead of writing a file", false).option("--force", "overwrite an existing file at the target path", false).option("-d, --dir <dir>", "project root").action(async (id, opts) => {
13227
+ ).argument("<memory-id>", "lesson id to scaffold a test from").option("--framework <fw>", `test framework: ${TEST_FRAMEWORKS.join(" | ")} (auto-detected when omitted)`).option("--out <path>", "override the generated test file path (project-relative)").option("--stdout", "print the test to stdout instead of writing a file", false).option("--force", "overwrite an existing file at the target path", false).option(
13228
+ "--red-ref <ref>",
13229
+ "pre-fix incident commit/ref: the scaffold names the symbols the fix (<ref>..HEAD) touched and pre-fills the example around them, so the assertion is a targeted edit, not a blank page"
13230
+ ).option("-d, --dir <dir>", "project root").action(async (id, opts) => {
13179
13231
  const root = findProjectRoot39(opts.dir);
13180
13232
  const paths = resolveHaivePaths36(root);
13181
13233
  const loaded = existsSync44(paths.memoriesDir) ? await loadMemoriesFromDir16(paths.memoriesDir) : [];
@@ -13195,13 +13247,28 @@ function registerSensors(program2) {
13195
13247
  const allGroups = await detectTestFrameworksForAnchors(root, fm.anchor.paths ?? []);
13196
13248
  const groups = opts.out ? allGroups.slice(0, 1) : allGroups;
13197
13249
  const fields = parseLessonFields(found.memory.body);
13250
+ let incidentHints;
13251
+ if (opts.redRef) {
13252
+ try {
13253
+ const args = ["diff", `${opts.redRef}`, "HEAD", "--", ...fm.anchor.paths ?? []];
13254
+ const { stdout } = await exec5("git", args, { cwd: root, maxBuffer: 64 * 1024 * 1024 });
13255
+ incidentHints = incidentHintsFromDiff(stdout, { redRef: opts.redRef });
13256
+ if (incidentHints.changedSymbols.length === 0 && incidentHints.changedFiles.length === 0) {
13257
+ ui.warn(`--red-ref ${opts.redRef}: no changed symbols found in the anchor scope \u2014 using the generic template.`);
13258
+ incidentHints = void 0;
13259
+ }
13260
+ } catch (err) {
13261
+ ui.warn(`--red-ref ${opts.redRef}: could not read the fix diff (${err instanceof Error ? err.message : String(err)}) \u2014 using the generic template.`);
13262
+ }
13263
+ }
13198
13264
  const lesson = {
13199
13265
  memoryId: id,
13200
13266
  title: fields.title || id,
13201
13267
  whyFailed: fields.whyFailed,
13202
13268
  instead: fields.instead,
13203
13269
  incident: fm.sensor?.incident,
13204
- paths: fm.anchor.paths
13270
+ paths: fm.anchor.paths,
13271
+ incidentHints
13205
13272
  };
13206
13273
  let scaffolds = groups.map(
13207
13274
  (g) => scaffoldPostIncidentTest(lesson, { framework: forced ?? g.framework, outPath: opts.out, baseDir: g.baseDir })
@@ -13304,7 +13371,7 @@ async function runnableSensorMemories(paths, regexOnly = true) {
13304
13371
  }
13305
13372
  async function stagedDiff(root) {
13306
13373
  try {
13307
- const { stdout } = await exec5("git", ["diff", "--cached"], { cwd: root });
13374
+ const { stdout } = await exec5("git", ["diff", "--cached"], { cwd: root, maxBuffer: 256 * 1024 * 1024 });
13308
13375
  return stdout;
13309
13376
  } catch (err) {
13310
13377
  throw new Error(`git diff --cached failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -14082,7 +14149,7 @@ function registerBridges(program2) {
14082
14149
 
14083
14150
  // src/index.ts
14084
14151
  var program = new Command48();
14085
- program.name("hivelore").description("Hivelore - the deterministic policy gate for agent-written code (rules live as repo-native team memory)").version("0.44.0").option("--advanced", "show maintenance and experimental commands in help").showSuggestionAfterError(true);
14152
+ program.name("hivelore").description("Hivelore - the deterministic policy gate for agent-written code (rules live as repo-native team memory)").version("0.47.0").option("--advanced", "show maintenance and experimental commands in help").showSuggestionAfterError(true);
14086
14153
  registerInit(program);
14087
14154
  registerResolveProject(program);
14088
14155
  registerEnforce(program);
@@ -14172,7 +14239,7 @@ program.parseAsync(process.argv).catch((err) => {
14172
14239
  console.error(`\x1B[31m\u2717\x1B[0m ${field}${issue.message}`);
14173
14240
  }
14174
14241
  } else {
14175
- console.error(err instanceof Error ? err.message : err);
14242
+ console.error(err instanceof Error ? process.env.HIVELORE_DEBUG ? err.stack ?? err.message : err.message : err);
14176
14243
  }
14177
14244
  process.exit(1);
14178
14245
  });