@hivelore/cli 0.36.0 → 0.37.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.
@@ -2730,7 +2730,7 @@ function oneLine(value) {
2730
2730
  return value.replace(/\s+/g, " ").replace(/"/g, '\\"').trim().slice(0, 120);
2731
2731
  }
2732
2732
  function serverVersion() {
2733
- return true ? "0.36.0" : "dev";
2733
+ return true ? "0.37.0" : "dev";
2734
2734
  }
2735
2735
  var CodeMapInputSchema = {
2736
2736
  file: z20.string().optional().describe("Filter to files whose path contains this substring"),
@@ -4057,7 +4057,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
4057
4057
  };
4058
4058
  }
4059
4059
  var SERVER_NAME = "hivelore";
4060
- var SERVER_VERSION = "0.36.0";
4060
+ var SERVER_VERSION = "0.37.0";
4061
4061
  function jsonResult(data) {
4062
4062
  return {
4063
4063
  content: [
@@ -5000,4 +5000,4 @@ export {
5000
5000
  printHaiveMcpVersion,
5001
5001
  runHaiveMcpStdio
5002
5002
  };
5003
- //# sourceMappingURL=chunk-EWJQ3YE7.js.map
5003
+ //# sourceMappingURL=chunk-VLRQ4MRO.js.map
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  preCommitCheck,
11
11
  readPresumedCorrectTargets,
12
12
  runHaiveMcpStdio
13
- } from "./chunk-EWJQ3YE7.js";
13
+ } from "./chunk-VLRQ4MRO.js";
14
14
  import {
15
15
  registerMemoryPending
16
16
  } from "./chunk-OYJKHD22.js";
@@ -3755,7 +3755,7 @@ ${SEED_FOOTER(stack)}` });
3755
3755
 
3756
3756
  // src/commands/init.ts
3757
3757
  var execFileAsync = promisify2(execFile2);
3758
- var HAIVE_GITHUB_ACTION_REF = `v${"0.36.0"}`;
3758
+ var HAIVE_GITHUB_ACTION_REF = `v${"0.37.0"}`;
3759
3759
  var PROJECT_CONTEXT_TEMPLATE = `# Project context
3760
3760
 
3761
3761
  > Generated by \`hivelore init\`. Run \`hivelore init --bootstrap\` to auto-fill from your codebase,
@@ -6090,6 +6090,7 @@ function registerMemoryTried(memory2) {
6090
6090
  } else if (result.hint) {
6091
6091
  ui.warn(result.hint);
6092
6092
  }
6093
+ ui.info(` Prefer a real test? \`hivelore sensors scaffold ${result.id}\` generates a pending test + the wiring command.`);
6093
6094
  });
6094
6095
  }
6095
6096
 
@@ -8959,7 +8960,7 @@ function registerDoctor(program2) {
8959
8960
  fix: "Edit .ai/haive.config.json: set autoSessionEnd: true (or re-run `hivelore init` without --manual)."
8960
8961
  });
8961
8962
  }
8962
- findings.push(...await collectInstallFindings(root, "0.36.0"));
8963
+ findings.push(...await collectInstallFindings(root, "0.37.0"));
8963
8964
  findings.push(...await collectToolchainFindings(root));
8964
8965
  try {
8965
8966
  const legacyRaw = execSync("haive-mcp --version", {
@@ -8967,7 +8968,7 @@ function registerDoctor(program2) {
8967
8968
  timeout: 3e3,
8968
8969
  stdio: ["ignore", "pipe", "ignore"]
8969
8970
  }).trim();
8970
- const cliVersion = "0.36.0";
8971
+ const cliVersion = "0.37.0";
8971
8972
  if (legacyRaw && legacyRaw !== cliVersion) {
8972
8973
  findings.push({
8973
8974
  severity: "warn",
@@ -10670,7 +10671,7 @@ async function buildEnforcementReport(dir, stage, sessionId) {
10670
10671
  findings: [{ severity: "info", code: "enforcement-off", message: "Hivelore enforcement is disabled." }]
10671
10672
  });
10672
10673
  }
10673
- findings.push(...await inspectIntegrationVersions(root, "0.36.0"));
10674
+ findings.push(...await inspectIntegrationVersions(root, "0.37.0"));
10674
10675
  if (config.enforcement?.requireBriefingFirst !== false && stage !== "ci") {
10675
10676
  const hasBriefing = await hasRecentBriefingMarker(paths, sessionId);
10676
10677
  findings.push(hasBriefing ? { severity: "ok", code: "briefing-loaded", message: "A recent Hivelore briefing marker exists." } : {
@@ -12159,10 +12160,13 @@ import {
12159
12160
  loadConfig as loadConfig13,
12160
12161
  loadSensorLedger as loadSensorLedger4,
12161
12162
  loadMemoriesFromDir as loadMemoriesFromDir15,
12163
+ parseLessonFields,
12162
12164
  recordPreventionHits as recordPreventionHits2,
12163
12165
  resolveHaivePaths as resolveHaivePaths36,
12164
12166
  runSensors as runSensors2,
12167
+ scaffoldPostIncidentTest,
12165
12168
  selectCommandSensors as selectCommandSensors2,
12169
+ TEST_FRAMEWORKS,
12166
12170
  sensorPatternBrittleness as sensorPatternBrittleness2,
12167
12171
  sensorSelfCheck as sensorSelfCheck2,
12168
12172
  sensorAppliesToPath as sensorAppliesToPath3,
@@ -12405,7 +12409,7 @@ function registerSensors(program2) {
12405
12409
  return;
12406
12410
  }
12407
12411
  const root2 = findProjectRoot39(opts.dir);
12408
- const { proposeSensor } = await import("./server-JFLUYWUB.js");
12412
+ const { proposeSensor } = await import("./server-J6TDFG2C.js");
12409
12413
  const out = await proposeSensor(
12410
12414
  {
12411
12415
  memory_id: id,
@@ -12494,6 +12498,56 @@ function registerSensors(program2) {
12494
12498
  `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
12499
  );
12496
12500
  });
12501
+ sensors.command("scaffold").description(
12502
+ "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"
12503
+ ).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) => {
12504
+ const root = findProjectRoot39(opts.dir);
12505
+ const paths = resolveHaivePaths36(root);
12506
+ const loaded = existsSync43(paths.memoriesDir) ? await loadMemoriesFromDir15(paths.memoriesDir) : [];
12507
+ const found = loaded.find(({ memory: memory2 }) => memory2.frontmatter.id === id);
12508
+ if (!found) {
12509
+ ui.error(`No memory found with id ${id}`);
12510
+ process.exitCode = 1;
12511
+ return;
12512
+ }
12513
+ const framework = opts.framework ? normalizeFramework(opts.framework) : await detectTestFramework(root);
12514
+ if (!framework) {
12515
+ ui.error(`Unknown --framework "${opts.framework}". Use one of: ${TEST_FRAMEWORKS.join(", ")}.`);
12516
+ process.exitCode = 1;
12517
+ return;
12518
+ }
12519
+ const fields = parseLessonFields(found.memory.body);
12520
+ const fm = found.memory.frontmatter;
12521
+ const scaffold = scaffoldPostIncidentTest(
12522
+ {
12523
+ memoryId: id,
12524
+ title: fields.title || id,
12525
+ whyFailed: fields.whyFailed,
12526
+ instead: fields.instead,
12527
+ incident: fm.sensor?.incident,
12528
+ paths: fm.anchor.paths
12529
+ },
12530
+ { framework, outPath: opts.out }
12531
+ );
12532
+ if (opts.stdout) {
12533
+ console.log(scaffold.content);
12534
+ ui.info(`Arm it once written: ${scaffold.proposeCommand}`);
12535
+ return;
12536
+ }
12537
+ const abs = path41.isAbsolute(scaffold.relPath) ? scaffold.relPath : path41.resolve(root, scaffold.relPath);
12538
+ if (existsSync43(abs) && !opts.force) {
12539
+ ui.error(`${scaffold.relPath} already exists \u2014 pass --force to overwrite, or --out <path> for a different file.`);
12540
+ process.exitCode = 1;
12541
+ return;
12542
+ }
12543
+ await mkdir17(path41.dirname(abs), { recursive: true });
12544
+ await writeFile27(abs, scaffold.content, "utf8");
12545
+ ui.success(`Wrote ${framework} post-incident test \u2192 ${scaffold.relPath}`);
12546
+ ui.info(" 1. Fill in the assertion (RED on the incident, GREEN once fixed).");
12547
+ ui.info(` 2. Run it: ${scaffold.runCommand}`);
12548
+ ui.info(" 3. Arm it as a deterministic gate:");
12549
+ console.log(` ${scaffold.proposeCommand}`);
12550
+ });
12497
12551
  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
12552
  const format = opts.format ?? "grep";
12499
12553
  if (format !== "grep" && format !== "eslint") {
@@ -12583,6 +12637,31 @@ function renderGrepScript(rows) {
12583
12637
  function shellQuote(value) {
12584
12638
  return `'${value.replace(/'/g, "'\\''")}'`;
12585
12639
  }
12640
+ function normalizeFramework(input) {
12641
+ const v = input.trim().toLowerCase();
12642
+ if (v === "vitest") return "vitest";
12643
+ if (v === "jest") return "jest";
12644
+ if (v === "pytest" || v === "py" || v === "python") return "pytest";
12645
+ if (v === "go" || v === "gotest" || v === "go-test") return "gotest";
12646
+ return null;
12647
+ }
12648
+ async function detectTestFramework(root) {
12649
+ try {
12650
+ const pkgPath = path41.join(root, "package.json");
12651
+ if (existsSync43(pkgPath)) {
12652
+ const pkg = JSON.parse(await readFile20(pkgPath, "utf8"));
12653
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
12654
+ if (deps.vitest) return "vitest";
12655
+ if (deps.jest || deps["ts-jest"]) return "jest";
12656
+ }
12657
+ } catch {
12658
+ }
12659
+ if (existsSync43(path41.join(root, "go.mod"))) return "gotest";
12660
+ for (const signal of ["pyproject.toml", "setup.py", "pytest.ini", "requirements.txt", "tox.ini"]) {
12661
+ if (existsSync43(path41.join(root, signal))) return "pytest";
12662
+ }
12663
+ return "vitest";
12664
+ }
12586
12665
 
12587
12666
  // src/commands/ingest.ts
12588
12667
  import { existsSync as existsSync44 } from "fs";
@@ -13244,7 +13323,7 @@ function registerBridges(program2) {
13244
13323
 
13245
13324
  // src/index.ts
13246
13325
  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);
13326
+ program.name("hivelore").description("Hivelore - the deterministic policy gate for agent-written code (rules live as repo-native team memory)").version("0.37.0").option("--advanced", "show maintenance and experimental commands in help").showSuggestionAfterError(true);
13248
13327
  registerInit(program);
13249
13328
  registerResolveProject(program);
13250
13329
  registerEnforce(program);