@hivelore/cli 0.51.0 → 0.52.1

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-UK4CWVS7.js";
16
+ } from "./chunk-WQWNIGVL.js";
17
17
  import {
18
18
  registerMemoryPending
19
19
  } from "./chunk-OYJKHD22.js";
@@ -3762,7 +3762,7 @@ ${SEED_FOOTER(stack)}` });
3762
3762
 
3763
3763
  // src/commands/init.ts
3764
3764
  var execFileAsync = promisify2(execFile2);
3765
- var HAIVE_GITHUB_ACTION_REF = `v${"0.51.0"}`;
3765
+ var HAIVE_GITHUB_ACTION_REF = `v${"0.52.1"}`;
3766
3766
  var PROJECT_CONTEXT_TEMPLATE = `# Project context
3767
3767
 
3768
3768
  > Generated by \`hivelore init\`. Run \`hivelore init --bootstrap\` to auto-fill from your codebase,
@@ -9158,7 +9158,7 @@ function registerDoctor(program2) {
9158
9158
  }
9159
9159
  const astSensorCount = sensorMemories.filter((m) => m.memory.frontmatter.sensor?.kind === "ast").length;
9160
9160
  if (astSensorCount > 0) {
9161
- const { astEngineAvailable: astEngineAvailable2 } = await import("./server-Z4M6ERWN.js");
9161
+ const { astEngineAvailable: astEngineAvailable2 } = await import("./server-AXRCHDHW.js");
9162
9162
  if (!await astEngineAvailable2()) {
9163
9163
  findings.push({
9164
9164
  severity: "warn",
@@ -9329,8 +9329,8 @@ function registerDoctor(program2) {
9329
9329
  fix: "Edit .ai/hivelore.config.json: set autoSessionEnd: true (or re-run `hivelore init` without --manual)."
9330
9330
  });
9331
9331
  }
9332
- findings.push(...await collectInstallFindings(root, "0.51.0"));
9333
- findings.push(...await collectMcpRuntimeFindings(paths, "0.51.0"));
9332
+ findings.push(...await collectInstallFindings(root, "0.52.1"));
9333
+ findings.push(...await collectMcpRuntimeFindings(paths, "0.52.1"));
9334
9334
  findings.push(...await collectToolchainFindings(root));
9335
9335
  try {
9336
9336
  const legacyRaw = execSync("haive-mcp --version", {
@@ -9338,7 +9338,7 @@ function registerDoctor(program2) {
9338
9338
  timeout: 3e3,
9339
9339
  stdio: ["ignore", "pipe", "ignore"]
9340
9340
  }).trim();
9341
- const cliVersion = "0.51.0";
9341
+ const cliVersion = "0.52.1";
9342
9342
  if (legacyRaw && legacyRaw !== cliVersion) {
9343
9343
  findings.push({
9344
9344
  severity: "warn",
@@ -9607,7 +9607,7 @@ function collectBehaviourCoverageFindings(codeMap, memories) {
9607
9607
  if (!codeMap) return [];
9608
9608
  const codeFiles = Object.keys(codeMap.files);
9609
9609
  const cov = assessBehaviourCoverage2({ memories, codeFiles });
9610
- if (cov.mainAreas.length === 0) return [];
9610
+ if (cov.mainAreas.length === 0 && cov.totalOracles === 0) return [];
9611
9611
  const uncoveredHint = cov.uncoveredAreas.length > 0 && cov.totalOracles > 0 ? `
9612
9612
  No behavioural oracle: ${cov.uncoveredAreas.slice(0, 5).map((a) => `\`${a}\``).join(", ")}` + (cov.uncoveredAreas.length > 5 ? `, +${cov.uncoveredAreas.length - 5} more` : "") : "";
9613
9613
  let fix;
@@ -9625,7 +9625,7 @@ function collectBehaviourCoverageFindings(codeMap, memories) {
9625
9625
  code: "behaviour-coverage",
9626
9626
  alwaysShow: true,
9627
9627
  section: "Protection",
9628
- coverage_percent: Math.round(cov.areasWithOracle.length / cov.mainAreas.length * 100),
9628
+ coverage_percent: cov.mainAreas.length > 0 ? Math.round(cov.areasWithOracle.length / cov.mainAreas.length * 100) : cov.totalOracles > 0 ? 100 : 0,
9629
9629
  message: `Behaviour harness: ${renderBehaviourCoverageLine2(cov)}.` + uncoveredHint,
9630
9630
  fix
9631
9631
  }];
@@ -10431,6 +10431,35 @@ function evaluation(base, command) {
10431
10431
  var execFileAsync2 = promisify5(execFile5);
10432
10432
  var MAX_STDIN_BYTES2 = 256 * 1024;
10433
10433
  var ENFORCE_HOOK_MARKER = "# Hivelore enforcement hook";
10434
+ function stripHiveloreHookBlock(content) {
10435
+ const markerRe = /^\s*#\s*(?:hivelore|h[aA]ive)\b.*\bhook\b/i;
10436
+ const invocationRe = /^\s*_?(?:hivelore|haive)\b.*\|\|/i;
10437
+ const shebangRe = /^\s*#!.*\bsh\b/;
10438
+ const out = [];
10439
+ let inBlock = false;
10440
+ for (const line of content.split("\n")) {
10441
+ if (inBlock) {
10442
+ if (invocationRe.test(line)) inBlock = false;
10443
+ continue;
10444
+ }
10445
+ if (markerRe.test(line)) {
10446
+ inBlock = true;
10447
+ continue;
10448
+ }
10449
+ if (shebangRe.test(line)) continue;
10450
+ out.push(line);
10451
+ }
10452
+ return out.join("\n").replace(/\n{3,}/g, "\n\n").trim();
10453
+ }
10454
+ function buildHookFileContent(current, ownBody) {
10455
+ const foreign = stripHiveloreHookBlock(current);
10456
+ if (!foreign) return ownBody;
10457
+ const ownWithoutShebang = ownBody.replace(/^\s*#!.*\n/, "");
10458
+ return `#!/bin/sh
10459
+ ${foreign}
10460
+
10461
+ ${ownWithoutShebang}`;
10462
+ }
10434
10463
  function registerEnforce(program2) {
10435
10464
  program2.command("install-hooks [target]", { hidden: true }).option("-d, --dir <dir>", "project root").option("--force", "(ignored \u2014 Hivelore-owned hooks are always refreshed, foreign hooks appended)").option("--scope <scope>", "claude: 'user' (~/.claude) or 'project' (.claude/)", "user").option("--uninstall", "claude: remove previously installed hooks").option("--settings <path>", "claude: explicit settings.json path").action(async (target, opts) => {
10436
10465
  const t = (target ?? "git").toLowerCase();
@@ -11154,7 +11183,7 @@ async function buildEnforcementReport(dir, stage, sessionId) {
11154
11183
  findings: [{ severity: "info", code: "enforcement-off", message: "Hivelore enforcement is disabled." }]
11155
11184
  });
11156
11185
  }
11157
- findings.push(...await inspectIntegrationVersions(root, "0.51.0"));
11186
+ findings.push(...await inspectIntegrationVersions(root, "0.52.1"));
11158
11187
  if (config.enforcement?.requireBriefingFirst !== false && stage !== "ci") {
11159
11188
  const hasBriefing = await hasRecentBriefingMarker(paths, sessionId);
11160
11189
  findings.push(hasBriefing ? { severity: "ok", code: "briefing-loaded", message: "A recent Hivelore briefing marker exists." } : {
@@ -12333,18 +12362,8 @@ _hivelore sync --quiet --since ORIG_HEAD || true
12333
12362
  ];
12334
12363
  for (const hook of hooks) {
12335
12364
  const file = path40.join(hooksDir, hook.name);
12336
- if (existsSync42(file)) {
12337
- const current = await readFile18(file, "utf8").catch(() => "");
12338
- if (current.includes(ENFORCE_HOOK_MARKER)) {
12339
- await writeFile25(file, hook.body, "utf8");
12340
- } else {
12341
- await writeFile25(file, `${current.trimEnd()}
12342
-
12343
- ${hook.body}`, "utf8");
12344
- }
12345
- } else {
12346
- await writeFile25(file, hook.body, "utf8");
12347
- }
12365
+ const current = existsSync42(file) ? await readFile18(file, "utf8").catch(() => "") : "";
12366
+ await writeFile25(file, buildHookFileContent(current, hook.body), "utf8");
12348
12367
  await chmod(file, 493);
12349
12368
  }
12350
12369
  ui.success("Installed git hooks: pre-commit, pre-push, commit-msg (blocking) + post-merge, post-rewrite (sync)");
@@ -12826,6 +12845,7 @@ import path42 from "path";
12826
12845
  import { promisify as promisify7 } from "util";
12827
12846
  import "commander";
12828
12847
  import {
12848
+ extractCorrectApproachExamples,
12829
12849
  extractSensorExamples,
12830
12850
  appendSensorEvaluations as appendSensorEvaluations2,
12831
12851
  assessSensorHealth as assessSensorHealth4,
@@ -13120,7 +13140,8 @@ function registerSensors(program2) {
13120
13140
  const currentTargets = await readPresumedCorrectTargets(root, anchorPaths);
13121
13141
  const check = sensorSelfCheck2(sensor, {
13122
13142
  currentTargets,
13123
- badExamples: extractSensorExamples(found.memory.body)
13143
+ badExamples: extractSensorExamples(found.memory.body),
13144
+ correctExamples: extractCorrectApproachExamples(found.memory.body)
13124
13145
  });
13125
13146
  if (currentTargets.length > 0 && !check.silent_on_current) {
13126
13147
  ui.error(
@@ -13129,6 +13150,13 @@ function registerSensors(program2) {
13129
13150
  process.exitCode = 1;
13130
13151
  return;
13131
13152
  }
13153
+ if (check.fires_on_correct === true) {
13154
+ ui.error(
13155
+ "Refusing to block: this sensor fires on the lesson's OWN recommended fix (its `Instead, use:` approach) \u2014 it is inverted and would block the correct code, never the mistake. Point the pattern at the FAULTY usage, or pass --force."
13156
+ );
13157
+ process.exitCode = 1;
13158
+ return;
13159
+ }
13132
13160
  if (check.fires_on_bad === true) {
13133
13161
  ui.success("Self-check passed: fires on the lesson's bad example, silent on current code.");
13134
13162
  } else if (check.fires_on_bad === false) {
@@ -13177,7 +13205,7 @@ function registerSensors(program2) {
13177
13205
  }
13178
13206
  }
13179
13207
  const root2 = findProjectRoot39(opts.dir);
13180
- const { proposeSensor } = await import("./server-Z4M6ERWN.js");
13208
+ const { proposeSensor } = await import("./server-AXRCHDHW.js");
13181
13209
  const out = await proposeSensor(
13182
13210
  {
13183
13211
  memory_id: id,
@@ -13239,6 +13267,7 @@ function registerSensors(program2) {
13239
13267
  ...opts.badExample ? [opts.badExample] : [],
13240
13268
  ...extractSensorExamples(found.memory.body)
13241
13269
  ];
13270
+ const correctExamples = extractCorrectApproachExamples(found.memory.body);
13242
13271
  const sensor = {
13243
13272
  kind: "regex",
13244
13273
  pattern: opts.pattern,
@@ -13251,7 +13280,7 @@ function registerSensors(program2) {
13251
13280
  autogen: false,
13252
13281
  last_fired: null
13253
13282
  };
13254
- const verdict = judgeProposedSensor(sensor, { currentTargets, badExamples });
13283
+ const verdict = judgeProposedSensor(sensor, { currentTargets, badExamples, correctExamples });
13255
13284
  if (opts.json && !verdict.accepted) {
13256
13285
  console.log(JSON.stringify({
13257
13286
  accepted: verdict.accepted,
@@ -13268,6 +13297,8 @@ function registerSensors(program2) {
13268
13297
  ui.error(`Rejected (${verdict.reason}).`);
13269
13298
  if (verdict.reason === "fires-on-current") {
13270
13299
  ui.warn(`Fires on the CURRENT correct code in: ${verdict.self_check.fired_on.join(", ")}. Add/tighten --absent, then re-run.`);
13300
+ } else if (verdict.reason === "fires-on-correct") {
13301
+ ui.warn("Inverted: the pattern matches the lesson's OWN recommended fix (its `Instead, use:` approach) \u2014 it would block correct code, never the mistake. Point --pattern at the FAULTY usage, then re-run.");
13271
13302
  } else if (verdict.reason === "missed-bad-example") {
13272
13303
  ui.warn("Did not match the bad example \u2014 the pattern won't catch the mistake. Adjust --pattern, then re-run.");
13273
13304
  } else if (verdict.reason === "brittle") {
@@ -14244,7 +14275,7 @@ function registerBridges(program2) {
14244
14275
 
14245
14276
  // src/index.ts
14246
14277
  var program = new Command48();
14247
- program.name("hivelore").description("Hivelore - the deterministic policy gate for agent-written code (rules live as repo-native team memory)").version("0.51.0").option("--advanced", "show maintenance and experimental commands in help").showSuggestionAfterError(true);
14278
+ program.name("hivelore").description("Hivelore - the deterministic policy gate for agent-written code (rules live as repo-native team memory)").version("0.52.1").option("--advanced", "show maintenance and experimental commands in help").showSuggestionAfterError(true);
14248
14279
  registerInit(program);
14249
14280
  registerResolveProject(program);
14250
14281
  registerEnforce(program);