@hivelore/cli 0.44.0 → 0.46.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-W7EPRKOZ.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.46.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-V3ZGBTAG.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.46.0"));
9317
+ findings.push(...await collectMcpRuntimeFindings(paths, "0.46.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.46.0";
9307
9326
  if (legacyRaw && legacyRaw !== cliVersion) {
9308
9327
  findings.push({
9309
9328
  severity: "warn",
@@ -9560,6 +9579,33 @@ 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
+ const more = cov.uncoveredAreas.length > 4 ? `
9595
+ # +${cov.uncoveredAreas.length - 4} more area(s)` : "";
9596
+ fix = "Scaffold a behavioural oracle for each uncovered area:\n " + lines.join("\n ") + more;
9597
+ } else if (cov.armedOracles < cov.totalOracles || cov.redProvenOracles < cov.armedOracles) {
9598
+ fix = "Arm warn-only oracles to `block` and re-propose with `--red-ref` so each substantiates its incident.";
9599
+ }
9600
+ return [{
9601
+ severity: "info",
9602
+ code: "behaviour-coverage",
9603
+ section: "Protection",
9604
+ coverage_percent: Math.round(cov.areasWithOracle.length / cov.mainAreas.length * 100),
9605
+ message: `Behaviour harness: ${renderBehaviourCoverageLine2(cov)}.` + uncoveredHint,
9606
+ fix
9607
+ }];
9608
+ }
9563
9609
  async function collectSemanticIndexFindings(paths, config, memoryCount, codeMap) {
9564
9610
  const findings = [];
9565
9611
  const autoWantsCodeSearch = Boolean(config.autopilot || config.autoRepair?.codeSearch);
@@ -10085,7 +10131,7 @@ import {
10085
10131
  detectSensorWeakening,
10086
10132
  isSensorScannablePath,
10087
10133
  findProjectRoot as findProjectRoot37,
10088
- loadCodeMap as loadCodeMap7,
10134
+ loadCodeMap as loadCodeMap8,
10089
10135
  renderBootstrapChecklist,
10090
10136
  findUncapturedFailures,
10091
10137
  handoffAgeMs,
@@ -11018,7 +11064,7 @@ async function checkBootstrapComplete(paths, config, productionCodeChanged) {
11018
11064
  } catch {
11019
11065
  }
11020
11066
  const memories = existsSync42(paths.memoriesDir) ? await loadMemoriesFromDir15(paths.memoriesDir) : [];
11021
- const codeMap = await loadCodeMap7(paths);
11067
+ const codeMap = await loadCodeMap8(paths);
11022
11068
  const codeFiles = codeMap ? Object.keys(codeMap.files).filter((file) => existsSync42(path40.join(paths.root, file))) : [];
11023
11069
  let existingModules = [];
11024
11070
  try {
@@ -11083,7 +11129,7 @@ async function buildEnforcementReport(dir, stage, sessionId) {
11083
11129
  findings: [{ severity: "info", code: "enforcement-off", message: "Hivelore enforcement is disabled." }]
11084
11130
  });
11085
11131
  }
11086
- findings.push(...await inspectIntegrationVersions(root, "0.44.0"));
11132
+ findings.push(...await inspectIntegrationVersions(root, "0.46.0"));
11087
11133
  if (config.enforcement?.requireBriefingFirst !== false && stage !== "ci") {
11088
11134
  const hasBriefing = await hasRecentBriefingMarker(paths, sessionId);
11089
11135
  findings.push(hasBriefing ? { severity: "ok", code: "briefing-loaded", message: "A recent Hivelore briefing marker exists." } : {
@@ -11403,6 +11449,7 @@ async function runPrecommitPolicy(paths, gate, stage, config) {
11403
11449
  } catch {
11404
11450
  }
11405
11451
  }
11452
+ const noticeFinding = result.notice ? [{ severity: "info", code: "precommit-policy-notice", message: result.notice }] : [];
11406
11453
  if (!result.should_block) {
11407
11454
  return [
11408
11455
  {
@@ -11410,6 +11457,7 @@ async function runPrecommitPolicy(paths, gate, stage, config) {
11410
11457
  code: "precommit-policy-pass",
11411
11458
  message: `${stage === "ci" ? "CI" : "Pre-commit"} policy passed for ${touchedPaths.length} changed file(s).`
11412
11459
  },
11460
+ ...noticeFinding,
11413
11461
  ...reviewFinding,
11414
11462
  ...sensorFindings,
11415
11463
  ...weakeningFindings
@@ -11426,6 +11474,7 @@ async function runPrecommitPolicy(paths, gate, stage, config) {
11426
11474
  memory_ids: blockingWarnings.slice(0, 10).map((w) => w.id),
11427
11475
  impact: 45
11428
11476
  },
11477
+ ...noticeFinding,
11429
11478
  ...reviewFinding,
11430
11479
  ...sensorFindings,
11431
11480
  ...weakeningFindings
@@ -12720,6 +12769,7 @@ import {
12720
12769
  addedLineNumbersFromDiff as addedLineNumbersFromDiff2,
12721
12770
  buildProposeCommand,
12722
12771
  scaffoldPostIncidentTest,
12772
+ incidentHintsFromDiff,
12723
12773
  selectCommandSensors as selectCommandSensors2,
12724
12774
  TEST_FRAMEWORKS,
12725
12775
  sensorPatternBrittleness as sensorPatternBrittleness2,
@@ -13051,7 +13101,7 @@ function registerSensors(program2) {
13051
13101
  }
13052
13102
  }
13053
13103
  const root2 = findProjectRoot39(opts.dir);
13054
- const { proposeSensor } = await import("./server-MCNCAFJN.js");
13104
+ const { proposeSensor } = await import("./server-V3ZGBTAG.js");
13055
13105
  const out = await proposeSensor(
13056
13106
  {
13057
13107
  memory_id: id,
@@ -13175,7 +13225,10 @@ function registerSensors(program2) {
13175
13225
  });
13176
13226
  sensors.command("scaffold").description(
13177
13227
  "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) => {
13228
+ ).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(
13229
+ "--red-ref <ref>",
13230
+ "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"
13231
+ ).option("-d, --dir <dir>", "project root").action(async (id, opts) => {
13179
13232
  const root = findProjectRoot39(opts.dir);
13180
13233
  const paths = resolveHaivePaths36(root);
13181
13234
  const loaded = existsSync44(paths.memoriesDir) ? await loadMemoriesFromDir16(paths.memoriesDir) : [];
@@ -13195,13 +13248,28 @@ function registerSensors(program2) {
13195
13248
  const allGroups = await detectTestFrameworksForAnchors(root, fm.anchor.paths ?? []);
13196
13249
  const groups = opts.out ? allGroups.slice(0, 1) : allGroups;
13197
13250
  const fields = parseLessonFields(found.memory.body);
13251
+ let incidentHints;
13252
+ if (opts.redRef) {
13253
+ try {
13254
+ const args = ["diff", `${opts.redRef}`, "HEAD", "--", ...fm.anchor.paths ?? []];
13255
+ const { stdout } = await exec5("git", args, { cwd: root, maxBuffer: 64 * 1024 * 1024 });
13256
+ incidentHints = incidentHintsFromDiff(stdout, { redRef: opts.redRef });
13257
+ if (incidentHints.changedSymbols.length === 0 && incidentHints.changedFiles.length === 0) {
13258
+ ui.warn(`--red-ref ${opts.redRef}: no changed symbols found in the anchor scope \u2014 using the generic template.`);
13259
+ incidentHints = void 0;
13260
+ }
13261
+ } catch (err) {
13262
+ ui.warn(`--red-ref ${opts.redRef}: could not read the fix diff (${err instanceof Error ? err.message : String(err)}) \u2014 using the generic template.`);
13263
+ }
13264
+ }
13198
13265
  const lesson = {
13199
13266
  memoryId: id,
13200
13267
  title: fields.title || id,
13201
13268
  whyFailed: fields.whyFailed,
13202
13269
  instead: fields.instead,
13203
13270
  incident: fm.sensor?.incident,
13204
- paths: fm.anchor.paths
13271
+ paths: fm.anchor.paths,
13272
+ incidentHints
13205
13273
  };
13206
13274
  let scaffolds = groups.map(
13207
13275
  (g) => scaffoldPostIncidentTest(lesson, { framework: forced ?? g.framework, outPath: opts.out, baseDir: g.baseDir })
@@ -13304,7 +13372,7 @@ async function runnableSensorMemories(paths, regexOnly = true) {
13304
13372
  }
13305
13373
  async function stagedDiff(root) {
13306
13374
  try {
13307
- const { stdout } = await exec5("git", ["diff", "--cached"], { cwd: root });
13375
+ const { stdout } = await exec5("git", ["diff", "--cached"], { cwd: root, maxBuffer: 256 * 1024 * 1024 });
13308
13376
  return stdout;
13309
13377
  } catch (err) {
13310
13378
  throw new Error(`git diff --cached failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -14082,7 +14150,7 @@ function registerBridges(program2) {
14082
14150
 
14083
14151
  // src/index.ts
14084
14152
  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);
14153
+ program.name("hivelore").description("Hivelore - the deterministic policy gate for agent-written code (rules live as repo-native team memory)").version("0.46.0").option("--advanced", "show maintenance and experimental commands in help").showSuggestionAfterError(true);
14086
14154
  registerInit(program);
14087
14155
  registerResolveProject(program);
14088
14156
  registerEnforce(program);
@@ -14172,7 +14240,7 @@ program.parseAsync(process.argv).catch((err) => {
14172
14240
  console.error(`\x1B[31m\u2717\x1B[0m ${field}${issue.message}`);
14173
14241
  }
14174
14242
  } else {
14175
- console.error(err instanceof Error ? err.message : err);
14243
+ console.error(err instanceof Error ? process.env.HIVELORE_DEBUG ? err.stack ?? err.message : err.message : err);
14176
14244
  }
14177
14245
  process.exit(1);
14178
14246
  });