@hivelore/cli 0.36.0 → 0.38.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
@@ -3,6 +3,7 @@ import {
3
3
  antiPatternsCheck,
4
4
  codeMapTool,
5
5
  codeSearch,
6
+ detectTestFrameworkForPaths,
6
7
  getBriefing,
7
8
  getRecap,
8
9
  memRelevantTo,
@@ -10,7 +11,7 @@ import {
10
11
  preCommitCheck,
11
12
  readPresumedCorrectTargets,
12
13
  runHaiveMcpStdio
13
- } from "./chunk-EWJQ3YE7.js";
14
+ } from "./chunk-UOMGIXZN.js";
14
15
  import {
15
16
  registerMemoryPending
16
17
  } from "./chunk-OYJKHD22.js";
@@ -3755,7 +3756,7 @@ ${SEED_FOOTER(stack)}` });
3755
3756
 
3756
3757
  // src/commands/init.ts
3757
3758
  var execFileAsync = promisify2(execFile2);
3758
- var HAIVE_GITHUB_ACTION_REF = `v${"0.36.0"}`;
3759
+ var HAIVE_GITHUB_ACTION_REF = `v${"0.38.0"}`;
3759
3760
  var PROJECT_CONTEXT_TEMPLATE = `# Project context
3760
3761
 
3761
3762
  > Generated by \`hivelore init\`. Run \`hivelore init --bootstrap\` to auto-fill from your codebase,
@@ -6090,6 +6091,7 @@ function registerMemoryTried(memory2) {
6090
6091
  } else if (result.hint) {
6091
6092
  ui.warn(result.hint);
6092
6093
  }
6094
+ ui.info(` Prefer a real test? \`hivelore sensors scaffold ${result.id}\` generates a pending test + the wiring command.`);
6093
6095
  });
6094
6096
  }
6095
6097
 
@@ -8959,7 +8961,7 @@ function registerDoctor(program2) {
8959
8961
  fix: "Edit .ai/haive.config.json: set autoSessionEnd: true (or re-run `hivelore init` without --manual)."
8960
8962
  });
8961
8963
  }
8962
- findings.push(...await collectInstallFindings(root, "0.36.0"));
8964
+ findings.push(...await collectInstallFindings(root, "0.38.0"));
8963
8965
  findings.push(...await collectToolchainFindings(root));
8964
8966
  try {
8965
8967
  const legacyRaw = execSync("haive-mcp --version", {
@@ -8967,7 +8969,7 @@ function registerDoctor(program2) {
8967
8969
  timeout: 3e3,
8968
8970
  stdio: ["ignore", "pipe", "ignore"]
8969
8971
  }).trim();
8970
- const cliVersion = "0.36.0";
8972
+ const cliVersion = "0.38.0";
8971
8973
  if (legacyRaw && legacyRaw !== cliVersion) {
8972
8974
  findings.push({
8973
8975
  severity: "warn",
@@ -10670,7 +10672,7 @@ async function buildEnforcementReport(dir, stage, sessionId) {
10670
10672
  findings: [{ severity: "info", code: "enforcement-off", message: "Hivelore enforcement is disabled." }]
10671
10673
  });
10672
10674
  }
10673
- findings.push(...await inspectIntegrationVersions(root, "0.36.0"));
10675
+ findings.push(...await inspectIntegrationVersions(root, "0.38.0"));
10674
10676
  if (config.enforcement?.requireBriefingFirst !== false && stage !== "ci") {
10675
10677
  const hasBriefing = await hasRecentBriefingMarker(paths, sessionId);
10676
10678
  findings.push(hasBriefing ? { severity: "ok", code: "briefing-loaded", message: "A recent Hivelore briefing marker exists." } : {
@@ -12159,10 +12161,14 @@ import {
12159
12161
  loadConfig as loadConfig13,
12160
12162
  loadSensorLedger as loadSensorLedger4,
12161
12163
  loadMemoriesFromDir as loadMemoriesFromDir15,
12164
+ normalizeFramework,
12165
+ parseLessonFields,
12162
12166
  recordPreventionHits as recordPreventionHits2,
12163
12167
  resolveHaivePaths as resolveHaivePaths36,
12164
12168
  runSensors as runSensors2,
12169
+ scaffoldPostIncidentTest,
12165
12170
  selectCommandSensors as selectCommandSensors2,
12171
+ TEST_FRAMEWORKS,
12166
12172
  sensorPatternBrittleness as sensorPatternBrittleness2,
12167
12173
  sensorSelfCheck as sensorSelfCheck2,
12168
12174
  sensorAppliesToPath as sensorAppliesToPath3,
@@ -12405,7 +12411,7 @@ function registerSensors(program2) {
12405
12411
  return;
12406
12412
  }
12407
12413
  const root2 = findProjectRoot39(opts.dir);
12408
- const { proposeSensor } = await import("./server-JFLUYWUB.js");
12414
+ const { proposeSensor } = await import("./server-HG2K3WOQ.js");
12409
12415
  const out = await proposeSensor(
12410
12416
  {
12411
12417
  memory_id: id,
@@ -12494,6 +12500,57 @@ function registerSensors(program2) {
12494
12500
  `self-check: silent on current=${verdict.self_check.silent_on_current}` + (verdict.self_check.fires_on_bad === null ? "; no bad example tested" : `; fires on bad=${verdict.self_check.fires_on_bad}`)
12495
12501
  );
12496
12502
  });
12503
+ sensors.command("scaffold").description(
12504
+ "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"
12505
+ ).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) => {
12506
+ const root = findProjectRoot39(opts.dir);
12507
+ const paths = resolveHaivePaths36(root);
12508
+ const loaded = existsSync43(paths.memoriesDir) ? await loadMemoriesFromDir15(paths.memoriesDir) : [];
12509
+ const found = loaded.find(({ memory: memory2 }) => memory2.frontmatter.id === id);
12510
+ if (!found) {
12511
+ ui.error(`No memory found with id ${id}`);
12512
+ process.exitCode = 1;
12513
+ return;
12514
+ }
12515
+ const fm = found.memory.frontmatter;
12516
+ const detected = await detectTestFrameworkForPaths(root, fm.anchor.paths ?? []);
12517
+ const framework = opts.framework ? normalizeFramework(opts.framework) : detected.framework;
12518
+ if (!framework) {
12519
+ ui.error(`Unknown --framework "${opts.framework}". Use one of: ${TEST_FRAMEWORKS.join(", ")}.`);
12520
+ process.exitCode = 1;
12521
+ return;
12522
+ }
12523
+ const fields = parseLessonFields(found.memory.body);
12524
+ const scaffold = scaffoldPostIncidentTest(
12525
+ {
12526
+ memoryId: id,
12527
+ title: fields.title || id,
12528
+ whyFailed: fields.whyFailed,
12529
+ instead: fields.instead,
12530
+ incident: fm.sensor?.incident,
12531
+ paths: fm.anchor.paths
12532
+ },
12533
+ { framework, outPath: opts.out, baseDir: detected.baseDir }
12534
+ );
12535
+ if (opts.stdout) {
12536
+ console.log(scaffold.content);
12537
+ ui.info(`Arm it once written: ${scaffold.proposeCommand}`);
12538
+ return;
12539
+ }
12540
+ const abs = path41.isAbsolute(scaffold.relPath) ? scaffold.relPath : path41.resolve(root, scaffold.relPath);
12541
+ if (existsSync43(abs) && !opts.force) {
12542
+ ui.error(`${scaffold.relPath} already exists \u2014 pass --force to overwrite, or --out <path> for a different file.`);
12543
+ process.exitCode = 1;
12544
+ return;
12545
+ }
12546
+ await mkdir17(path41.dirname(abs), { recursive: true });
12547
+ await writeFile27(abs, scaffold.content, "utf8");
12548
+ ui.success(`Wrote ${framework} post-incident test \u2192 ${scaffold.relPath}`);
12549
+ ui.info(" 1. Fill in the assertion (RED on the incident, GREEN once fixed).");
12550
+ ui.info(` 2. Run it: ${scaffold.runCommand}`);
12551
+ ui.info(" 3. Arm it as a deterministic gate:");
12552
+ console.log(` ${scaffold.proposeCommand}`);
12553
+ });
12497
12554
  sensors.command("export").description("Export regex sensors into .ai/generated for external toolchains").option("--format <format>", "grep | eslint", "grep").option("--out-dir <dir>", "output directory", ".ai/generated").option("-d, --dir <dir>", "project root").action(async (opts) => {
12498
12555
  const format = opts.format ?? "grep";
12499
12556
  if (format !== "grep" && format !== "eslint") {
@@ -13244,7 +13301,7 @@ function registerBridges(program2) {
13244
13301
 
13245
13302
  // src/index.ts
13246
13303
  var program = new Command48();
13247
- program.name("hivelore").description("Hivelore - the deterministic policy gate for agent-written code (rules live as repo-native team memory)").version("0.36.0").option("--advanced", "show maintenance and experimental commands in help").showSuggestionAfterError(true);
13304
+ program.name("hivelore").description("Hivelore - the deterministic policy gate for agent-written code (rules live as repo-native team memory)").version("0.38.0").option("--advanced", "show maintenance and experimental commands in help").showSuggestionAfterError(true);
13248
13305
  registerInit(program);
13249
13306
  registerResolveProject(program);
13250
13307
  registerEnforce(program);