@hivelore/core 0.58.1 → 0.59.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.d.ts CHANGED
@@ -2745,7 +2745,10 @@ declare const SENSOR_ABSENT_LOOKBACK = 2;
2745
2745
  declare function compileRegexSensor(sensor: Sensor): RegExp | null;
2746
2746
  /**
2747
2747
  * Blank comment spans in scannable text so a sensor's regex matches CODE, not the prose that
2748
- * documents it. Returns `content` unchanged for unknown file types. Pure.
2748
+ * documents it including MULTI-LINE block comments whose forbidden token sits on a middle line
2749
+ * that starts with neither the opener nor `*` (field report 2026-09-04 §3.1: a `bg-emerald-600` in a
2750
+ * multi-line CSS comment still tripped the sensor because the earlier fix was purely per-line).
2751
+ * Returns `content` unchanged for unknown file types. Pure.
2749
2752
  */
2750
2753
  declare function stripCommentsForScan(content: string, path: string): string;
2751
2754
  /**
package/dist/index.js CHANGED
@@ -960,7 +960,7 @@ function applyFeedbackAdjustment(fm, adjustment, now = /* @__PURE__ */ new Date(
960
960
  }
961
961
 
962
962
  // src/prevention.ts
963
- import { appendFile, mkdir as mkdir2, readFile as readFile4, writeFile as writeFile2 } from "fs/promises";
963
+ import { appendFile, mkdir as mkdir2, readFile as readFile4 } from "fs/promises";
964
964
  import { existsSync as existsSync4 } from "fs";
965
965
  import path6 from "path";
966
966
  function preventionLogPath(paths) {
@@ -988,22 +988,8 @@ async function recordPreventionHits(paths, firedIds, source, now = /* @__PURE__
988
988
  await appendPreventionEvent(paths, { at, id, source, ...details[id] }).catch(() => {
989
989
  });
990
990
  }
991
- await stampSensorLastFired(paths, recordedIds, at).catch(() => {
992
- });
993
991
  return recordedIds;
994
992
  }
995
- async function stampSensorLastFired(paths, ids, at) {
996
- if (ids.length === 0 || !existsSync4(paths.memoriesDir)) return;
997
- const wanted = new Set(ids);
998
- const loaded = await loadMemoriesFromDir(paths.memoriesDir);
999
- for (const { memory, filePath } of loaded) {
1000
- const fm = memory.frontmatter;
1001
- if (!wanted.has(fm.id) || !fm.sensor || fm.sensor.last_fired === at) continue;
1002
- const next = { ...memory, frontmatter: { ...fm, sensor: { ...fm.sensor, last_fired: at } } };
1003
- await writeFile2(filePath, serializeMemory(next), "utf8").catch(() => {
1004
- });
1005
- }
1006
- }
1007
993
  function buildPreventionReceipt(events, memories, usage, options) {
1008
994
  const now = options.now ?? /* @__PURE__ */ new Date();
1009
995
  const sinceMs = options.since.getTime();
@@ -1704,6 +1690,11 @@ function bridgeMemorySummary(body) {
1704
1690
  const oneLine2 = firstLine.replace(/\s+/g, " ");
1705
1691
  return oneLine2.length > 140 ? oneLine2.slice(0, 137) + "\u2026" : oneLine2;
1706
1692
  }
1693
+ function breadcrumbTypeRank(type) {
1694
+ if (type === "attempt") return 0;
1695
+ if (type === "architecture" || type === "decision") return 1;
1696
+ return 2;
1697
+ }
1707
1698
  function prepareBridgeData(memories, sensors, opts) {
1708
1699
  const max = opts?.maxMemories ?? 8;
1709
1700
  const topMemories = memories.filter((m) => {
@@ -1713,8 +1704,12 @@ function prepareBridgeData(memories, sensors, opts) {
1713
1704
  if (m.frontmatter.tags?.includes("stack-pack") || m.frontmatter.tags?.includes("seed")) return false;
1714
1705
  return s === "validated" || s === "proposed";
1715
1706
  }).sort((a, b) => {
1716
- const score = (m) => m.frontmatter.status === "validated" ? 2 : 1;
1717
- return score(b) - score(a);
1707
+ const statusScore = (m) => m.frontmatter.status === "validated" ? 0 : 1;
1708
+ const s = statusScore(a) - statusScore(b);
1709
+ if (s !== 0) return s;
1710
+ const r = breadcrumbTypeRank(a.frontmatter.type) - breadcrumbTypeRank(b.frontmatter.type);
1711
+ if (r !== 0) return r;
1712
+ return b.frontmatter.id.localeCompare(a.frontmatter.id);
1718
1713
  }).slice(0, max).map((m) => ({
1719
1714
  id: m.frontmatter.id,
1720
1715
  scope: m.frontmatter.scope,
@@ -1758,7 +1753,6 @@ function renderSensorsBlock(blockSensors) {
1758
1753
  for (const s of blockSensors) {
1759
1754
  const pathNote = s.paths.length > 0 ? ` _(applies to: ${s.paths.join(", ")})_` : "";
1760
1755
  lines.push(`- **${s.id}**${pathNote}: ${s.message}`);
1761
- if (s.pattern) lines.push(` - Pattern: \`${s.pattern}\``);
1762
1756
  }
1763
1757
  lines.push("", BRIDGE_MARKERS.sensorsEnd);
1764
1758
  return lines.join("\n");
@@ -1926,13 +1920,21 @@ function commentSyntaxForPath(path22) {
1926
1920
  if (dot < 0) return null;
1927
1921
  return COMMENT_SYNTAX_BY_EXT[base.slice(dot + 1).toLowerCase()] ?? null;
1928
1922
  }
1929
- function blankCommentsOnLine(line, syntax) {
1930
- if (syntax.starContinuation && /^\*(\s|\/|$)/.test(line.trimStart())) {
1931
- return " ".repeat(line.length);
1932
- }
1923
+ function blankCommentsOnLine(line, syntax, inBlock) {
1933
1924
  let out = "";
1934
1925
  let stringDelim = null;
1935
- for (let i = 0; i < line.length; i++) {
1926
+ let i = 0;
1927
+ if (inBlock) {
1928
+ if (!syntax.block) return { text: line, inBlock: false };
1929
+ const close = syntax.block[1];
1930
+ const closeIdx = line.indexOf(close);
1931
+ if (closeIdx === -1) return { text: " ".repeat(line.length), inBlock: true };
1932
+ out += " ".repeat(closeIdx + close.length);
1933
+ i = closeIdx + close.length;
1934
+ } else if (syntax.starContinuation && /^\*(\s|\/|$)/.test(line.trimStart())) {
1935
+ return { text: " ".repeat(line.length), inBlock: false };
1936
+ }
1937
+ for (; i < line.length; i++) {
1936
1938
  const ch = line[i];
1937
1939
  if (stringDelim) {
1938
1940
  out += ch;
@@ -1953,9 +1955,12 @@ function blankCommentsOnLine(line, syntax) {
1953
1955
  const [open, close] = syntax.block;
1954
1956
  if (line.startsWith(open, i)) {
1955
1957
  const closeIdx = line.indexOf(close, i + open.length);
1956
- const end = closeIdx === -1 ? line.length : closeIdx + close.length;
1958
+ if (closeIdx === -1) {
1959
+ out += " ".repeat(line.length - i);
1960
+ return { text: out, inBlock: true };
1961
+ }
1962
+ const end = closeIdx + close.length;
1957
1963
  out += " ".repeat(end - i);
1958
- if (closeIdx === -1) break;
1959
1964
  i = end - 1;
1960
1965
  continue;
1961
1966
  }
@@ -1971,12 +1976,19 @@ function blankCommentsOnLine(line, syntax) {
1971
1976
  if (hitLineComment) break;
1972
1977
  out += ch;
1973
1978
  }
1974
- return out;
1979
+ return { text: out, inBlock: false };
1975
1980
  }
1976
1981
  function stripCommentsForScan(content, path22) {
1977
1982
  const syntax = commentSyntaxForPath(path22);
1978
1983
  if (!syntax) return content;
1979
- return content.split("\n").map((l) => blankCommentsOnLine(l, syntax)).join("\n");
1984
+ let inBlock = false;
1985
+ const out = [];
1986
+ for (const line of content.split("\n")) {
1987
+ const res = blankCommentsOnLine(line, syntax, inBlock);
1988
+ out.push(res.text);
1989
+ inBlock = res.inBlock;
1990
+ }
1991
+ return out.join("\n");
1980
1992
  }
1981
1993
  function runRegexSensor(memoryId, sensor, target) {
1982
1994
  const re = compileRegexSensor(sensor);