@hiveai/core 0.17.0 → 0.18.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
@@ -800,6 +800,45 @@ function summarizeImpact(scores) {
800
800
  }
801
801
  return summary;
802
802
  }
803
+ function recommendFeedbackAdjustment(fm, usage, options = {}) {
804
+ const rejectionThreshold = options.rejectionThreshold ?? 2;
805
+ const hasPositiveOutcome = usage.applied_count > 0 || usage.prevented_count > 0;
806
+ if (fm.sensor?.severity === "block" && usage.rejected_count >= 1) {
807
+ return {
808
+ action: "downgrade-block-sensor",
809
+ reason: "A human contested a blocking guardrail; downgrade it to warn so the gate stays helpful while the lesson is reviewed."
810
+ };
811
+ }
812
+ if (!hasPositiveOutcome && usage.rejected_count >= rejectionThreshold) {
813
+ return {
814
+ action: "deprecate-memory",
815
+ reason: `${usage.rejected_count} rejection(s) and no applied/prevented outcomes; deprecate until the lesson is refined.`
816
+ };
817
+ }
818
+ return { action: "none", reason: "No automatic adjustment needed." };
819
+ }
820
+ function applyFeedbackAdjustment(fm, adjustment, now = /* @__PURE__ */ new Date()) {
821
+ if (adjustment.action === "none") return fm;
822
+ const tags = [.../* @__PURE__ */ new Set([...fm.tags, "feedback-contested"])];
823
+ if (adjustment.action === "downgrade-block-sensor" && fm.sensor) {
824
+ return {
825
+ ...fm,
826
+ tags,
827
+ verified_at: now.toISOString(),
828
+ sensor: { ...fm.sensor, severity: "warn" }
829
+ };
830
+ }
831
+ if (adjustment.action === "deprecate-memory") {
832
+ return {
833
+ ...fm,
834
+ tags,
835
+ status: "deprecated",
836
+ stale_reason: adjustment.reason,
837
+ verified_at: now.toISOString()
838
+ };
839
+ }
840
+ return fm;
841
+ }
803
842
 
804
843
  // src/prevention.ts
805
844
  import { appendFile, mkdir as mkdir2, readFile as readFile4 } from "fs/promises";
@@ -865,6 +904,84 @@ function computeRecurrence(events) {
865
904
  rows.sort((a, b) => b.distinct_days - a.distinct_days || b.catches - a.catches);
866
905
  return { recurring_count: rows.length, top: rows };
867
906
  }
907
+ function briefingProofLine(events, options = {}) {
908
+ const now = options.now ?? /* @__PURE__ */ new Date();
909
+ const days = options.days ?? 30;
910
+ const since = now.getTime() - days * MS_PER_DAY2;
911
+ let count = 0;
912
+ for (const e of events) {
913
+ const t = Date.parse(e.at);
914
+ if (!Number.isFinite(t)) continue;
915
+ if (t >= since && t <= now.getTime()) count += 1;
916
+ }
917
+ if (count === 0) return null;
918
+ return `This harness prevented ${count} repeated mistake${count === 1 ? "" : "s"} in the last ${days} days.`;
919
+ }
920
+ function titleFromMemory(loaded) {
921
+ if (!loaded) return "";
922
+ for (const line of loaded.memory.body.split("\n")) {
923
+ const heading = /^#+\s*(.+)$/.exec(line.trim());
924
+ if (heading) return heading[1].trim().slice(0, 96);
925
+ }
926
+ for (const line of loaded.memory.body.split("\n")) {
927
+ const t = line.trim();
928
+ if (t) return t.replace(/^[-*]\s*/, "").slice(0, 96);
929
+ }
930
+ return "";
931
+ }
932
+ function sourceRank(source) {
933
+ return source === "anti-pattern" ? 0 : 1;
934
+ }
935
+ function summarizeCaughtForYou(events, memories, usage, options = {}) {
936
+ const until = options.now ?? /* @__PURE__ */ new Date();
937
+ const sinceMs = options.since === void 0 ? null : options.since instanceof Date ? options.since.getTime() : Date.parse(options.since);
938
+ const untilMs = until.getTime();
939
+ const byIdSource = /* @__PURE__ */ new Map();
940
+ for (const e of events) {
941
+ const t = Date.parse(e.at);
942
+ if (!Number.isFinite(t)) continue;
943
+ if (sinceMs !== null && Number.isFinite(sinceMs) && t < sinceMs) continue;
944
+ if (t > untilMs) continue;
945
+ const key = `${e.id}\0${e.source}`;
946
+ const current = byIdSource.get(key) ?? { id: e.id, source: e.source, catches: 0, last_at: e.at };
947
+ current.catches += 1;
948
+ if (e.at > current.last_at) current.last_at = e.at;
949
+ byIdSource.set(key, current);
950
+ }
951
+ const memoryById = new Map(memories.map((m) => [m.memory.frontmatter.id, m]));
952
+ const rows = [...byIdSource.values()].map((row) => {
953
+ const current = getUsage(usage, row.id).prevented_count;
954
+ const previous = Math.max(0, current - row.catches);
955
+ return {
956
+ id: row.id,
957
+ title: titleFromMemory(memoryById.get(row.id)) || row.id,
958
+ source: row.source,
959
+ catches: row.catches,
960
+ previous_count: previous,
961
+ current_count: current,
962
+ last_at: row.last_at
963
+ };
964
+ }).sort((a, b) => b.last_at.localeCompare(a.last_at) || sourceRank(a.source) - sourceRank(b.source)).slice(0, options.limit ?? 5);
965
+ return {
966
+ total_catches: [...byIdSource.values()].reduce((sum, row) => sum + row.catches, 0),
967
+ since: sinceMs !== null && Number.isFinite(sinceMs) ? new Date(sinceMs).toISOString() : null,
968
+ until: until.toISOString(),
969
+ rows
970
+ };
971
+ }
972
+ function renderCaughtForYou(summary) {
973
+ if (summary.total_catches === 0 || summary.rows.length === 0) return null;
974
+ const lines = [
975
+ `Caught for you: ${summary.total_catches} prevented repeat${summary.total_catches === 1 ? "" : "s"} this session.`
976
+ ];
977
+ for (const row of summary.rows) {
978
+ const gate = row.source === "anti-pattern" ? "Blocked" : "Caught";
979
+ lines.push(
980
+ `- ${gate}: ${row.title} (${row.id}). Prevention ${row.previous_count}->${row.current_count}.`
981
+ );
982
+ }
983
+ return lines.join("\n");
984
+ }
868
985
 
869
986
  // src/context-throttle.ts
870
987
  import { createHash } from "crypto";
@@ -1697,7 +1814,8 @@ var DEFAULT_CONFIG = {
1697
1814
  scoreThreshold: 80,
1698
1815
  cleanupGeneratedArtifacts: true,
1699
1816
  toolProfile: "enforcement",
1700
- policyPacks: ["architecture", "gotchas", "security", "domain", "release"]
1817
+ policyPacks: ["architecture", "gotchas", "security", "domain", "release"],
1818
+ releaseBranch: "main"
1701
1819
  }
1702
1820
  };
1703
1821
  var AUTOPILOT_DEFAULTS = {
@@ -1725,7 +1843,8 @@ var AUTOPILOT_DEFAULTS = {
1725
1843
  scoreThreshold: 85,
1726
1844
  cleanupGeneratedArtifacts: true,
1727
1845
  toolProfile: "enforcement",
1728
- policyPacks: ["architecture", "gotchas", "security", "domain", "release"]
1846
+ policyPacks: ["architecture", "gotchas", "security", "domain", "release"],
1847
+ releaseBranch: "main"
1729
1848
  }
1730
1849
  };
1731
1850
  function antiPatternGateParams(gate) {
@@ -3358,8 +3477,75 @@ function parseSonar(input) {
3358
3477
  }
3359
3478
  return findings;
3360
3479
  }
3361
- function parseFindings(format, input) {
3362
- return format === "sonar" ? parseSonar(input) : parseSarif(input);
3480
+ function parseEslintJson(input, opts = {}) {
3481
+ const docs = asArray(coerceJson(input));
3482
+ const findings = [];
3483
+ const cwd = opts.cwd ? opts.cwd.replace(/\/+$/, "") + "/" : "";
3484
+ for (const fileRaw of docs) {
3485
+ const file = asRecord(fileRaw);
3486
+ const rawPath = typeof file.filePath === "string" ? file.filePath : "";
3487
+ if (!rawPath) continue;
3488
+ const path18 = cwd && rawPath.startsWith(cwd) ? rawPath.slice(cwd.length) : rawPath;
3489
+ for (const msgRaw of asArray(file.messages)) {
3490
+ const msg = asRecord(msgRaw);
3491
+ const ruleId = typeof msg.ruleId === "string" && msg.ruleId ? msg.ruleId : "parse-error";
3492
+ const message = typeof msg.message === "string" ? msg.message.trim() : ruleId;
3493
+ const severity = normalizeFindingSeverity(msg.severity === 2 ? "error" : "warning");
3494
+ const line = typeof msg.line === "number" ? msg.line : void 0;
3495
+ findings.push({
3496
+ tool: "eslint",
3497
+ ruleId,
3498
+ message,
3499
+ severity,
3500
+ path: path18,
3501
+ ...line !== void 0 ? { line } : {},
3502
+ key: findingKey("eslint", ruleId, path18)
3503
+ });
3504
+ }
3505
+ }
3506
+ return findings;
3507
+ }
3508
+ var NPM_AUDIT_SEVERITY = {
3509
+ critical: "blocker",
3510
+ high: "critical",
3511
+ moderate: "major",
3512
+ low: "minor",
3513
+ info: "info"
3514
+ };
3515
+ function parseNpmAudit(input) {
3516
+ const doc = asRecord(coerceJson(input));
3517
+ const vulns = asRecord(doc.vulnerabilities);
3518
+ const findings = [];
3519
+ for (const [name, vulnRaw] of Object.entries(vulns)) {
3520
+ const vuln = asRecord(vulnRaw);
3521
+ const sev = typeof vuln.severity === "string" ? vuln.severity.toLowerCase() : "info";
3522
+ const severity = NPM_AUDIT_SEVERITY[sev] ?? "info";
3523
+ const via = asArray(vuln.via);
3524
+ const firstAdvisory = via.map(asRecord).find((v) => typeof v.title === "string");
3525
+ const title = firstAdvisory && typeof firstAdvisory.title === "string" ? firstAdvisory.title : `Vulnerable dependency: ${name}`;
3526
+ const range = typeof vuln.range === "string" ? ` (affected range: ${vuln.range})` : "";
3527
+ findings.push({
3528
+ tool: "npm-audit",
3529
+ ruleId: name,
3530
+ message: `${title}${range}`,
3531
+ severity,
3532
+ path: "package.json",
3533
+ key: findingKey("npm-audit", name, "package.json")
3534
+ });
3535
+ }
3536
+ return findings;
3537
+ }
3538
+ function parseFindings(format, input, opts = {}) {
3539
+ switch (format) {
3540
+ case "sonar":
3541
+ return parseSonar(input);
3542
+ case "eslint":
3543
+ return parseEslintJson(input, opts);
3544
+ case "npm-audit":
3545
+ return parseNpmAudit(input);
3546
+ default:
3547
+ return parseSarif(input);
3548
+ }
3363
3549
  }
3364
3550
  function normalizeUri(uri) {
3365
3551
  return uri.replace(/^file:\/\//, "").replace(/^\.\//, "");
@@ -3475,6 +3661,23 @@ function suggestGate(precision, rejections, currentGate) {
3475
3661
  }
3476
3662
  return null;
3477
3663
  }
3664
+ function nullableMetricDelta(baseline, current) {
3665
+ if (baseline === null || current === null) return { baseline, current, delta: null };
3666
+ return { baseline: round33(baseline), current: round33(current), delta: round33(current - baseline) };
3667
+ }
3668
+ function compareGatePrecision(baseline, current) {
3669
+ const precision = nullableMetricDelta(baseline.precision, current.precision);
3670
+ const rejections = nullableMetricDelta(baseline.rejections, current.rejections);
3671
+ const falsePositivesIncreased = current.rejections > baseline.rejections;
3672
+ const precisionRegressed = precision.delta !== null && precision.delta < 0;
3673
+ return {
3674
+ precision,
3675
+ rejections,
3676
+ false_positives_increased: falsePositivesIncreased,
3677
+ precision_regressed: precisionRegressed,
3678
+ regressed: falsePositivesIncreased || precisionRegressed
3679
+ };
3680
+ }
3478
3681
 
3479
3682
  // src/dashboard.ts
3480
3683
  var MS_PER_DAY4 = 24 * 60 * 60 * 1e3;
@@ -3583,9 +3786,26 @@ function buildDashboard(memories, usage, options = {}) {
3583
3786
  );
3584
3787
  sensorRows.sort((a, b) => b.last_fired.localeCompare(a.last_fired));
3585
3788
  dormantRows.sort((a, b) => b.age_days - a.age_days);
3789
+ const eventLog = options.preventionEvents ?? [];
3790
+ const recurrence = computeRecurrence(eventLog);
3586
3791
  return {
3587
3792
  generated_at: now.toISOString(),
3588
3793
  inventory,
3794
+ prevention: {
3795
+ total_events: preventionEvents,
3796
+ memories_with_catches: preventionRows.length,
3797
+ top: preventionRows.sort((a, b) => b.prevented_count - a.prevented_count).slice(0, top),
3798
+ trend: computePreventionTrend(eventLog, now),
3799
+ recurrence: {
3800
+ ...recurrence,
3801
+ top: recurrence.top.slice(0, top)
3802
+ }
3803
+ },
3804
+ gate_precision: computeGatePrecision(
3805
+ eventLog,
3806
+ usage,
3807
+ options.antiPatternGate ?? "anchored"
3808
+ ),
3589
3809
  impact: { ...summarizeImpact(impactScores), top: impactRows.slice(0, top) },
3590
3810
  sensors: {
3591
3811
  total: sensorTotal,
@@ -3607,21 +3827,6 @@ function buildDashboard(memories, usage, options = {}) {
3607
3827
  decaying,
3608
3828
  top_dormant: dormantRows.slice(0, top)
3609
3829
  },
3610
- prevention: {
3611
- total_events: preventionEvents,
3612
- memories_with_catches: preventionRows.length,
3613
- top: preventionRows.sort((a, b) => b.prevented_count - a.prevented_count).slice(0, top),
3614
- trend: computePreventionTrend(options.preventionEvents ?? [], now),
3615
- recurrence: {
3616
- ...computeRecurrence(options.preventionEvents ?? []),
3617
- top: computeRecurrence(options.preventionEvents ?? []).top.slice(0, top)
3618
- }
3619
- },
3620
- gate_precision: computeGatePrecision(
3621
- options.preventionEvents ?? [],
3622
- usage,
3623
- options.antiPatternGate ?? "anchored"
3624
- ),
3625
3830
  corpus: {
3626
3831
  memory_files: inventory.total,
3627
3832
  body_chars: bodyChars,
@@ -3794,6 +3999,7 @@ function planConflictResolution(a, b) {
3794
3999
  var REVERT_RE = /^Revert\s+"(.+)"\s*$/i;
3795
4000
  var FIXUP_RE = /^(?:fixup!|hotfix[:!]|fix[:!]\s*revert|revert\s+revert)/i;
3796
4001
  var URGENT_FIX_RE = /\b(hotfix|urgent fix|emergency fix|critical fix|broke production|broken build)\b/i;
4002
+ var WORKAROUND_RE = /\b(workaround|work around|hack(?:y|ish)?|band[- ]?aid|temporary fix|temp fix|quick fix|kludge|monkey[- ]?patch|stop[- ]?gap|FIXME|XXX)\b/i;
3797
4003
  function slugify(text) {
3798
4004
  return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || "reverted-change";
3799
4005
  }
@@ -3811,6 +4017,9 @@ function proposeSeedsFromCommits(commits, limit = 20) {
3811
4017
  } else if (FIXUP_RE.test(subject) || URGENT_FIX_RE.test(subject)) {
3812
4018
  what = subject.replace(FIXUP_RE, "").trim() || subject;
3813
4019
  kind = "fixup";
4020
+ } else if (WORKAROUND_RE.test(subject)) {
4021
+ what = subject;
4022
+ kind = "workaround";
3814
4023
  }
3815
4024
  if (!what || !kind) continue;
3816
4025
  const slug = slugify(what);
@@ -3819,7 +4028,7 @@ function proposeSeedsFromCommits(commits, limit = 20) {
3819
4028
  out.push({
3820
4029
  slug,
3821
4030
  what,
3822
- why_failed: kind === "revert" ? `This change was reverted in commit ${commit.sha} \u2014 it caused a regression and was backed out. Verify the root cause before re-attempting.` : `This area required an urgent fix (commit ${commit.sha}: "${subject}") \u2014 it shipped broken once. Treat changes here with extra care.`,
4031
+ why_failed: kind === "revert" ? `This change was reverted in commit ${commit.sha} \u2014 it caused a regression and was backed out. Verify the root cause before re-attempting.` : kind === "workaround" ? `This area carries a known workaround/stop-gap (commit ${commit.sha}: "${subject}") \u2014 the proper fix is still owed. Understand why the workaround exists before changing it.` : `This area required an urgent fix (commit ${commit.sha}: "${subject}") \u2014 it shipped broken once. Treat changes here with extra care.`,
3823
4032
  paths: (commit.files ?? []).slice(0, 8),
3824
4033
  source_sha: commit.sha,
3825
4034
  kind
@@ -3829,6 +4038,75 @@ function proposeSeedsFromCommits(commits, limit = 20) {
3829
4038
  return out;
3830
4039
  }
3831
4040
 
4041
+ // src/seed.ts
4042
+ var JS_DETECTORS = [
4043
+ ["nestjs", ["@nestjs/core"]],
4044
+ ["nextjs", ["next"]],
4045
+ ["remix", ["@remix-run/react", "@remix-run/node"]],
4046
+ ["react", ["react"]],
4047
+ ["express", ["express"]],
4048
+ ["fastify", ["fastify"]],
4049
+ ["prisma", ["@prisma/client", "prisma"]],
4050
+ ["drizzle", ["drizzle-orm"]],
4051
+ ["zustand", ["zustand"]],
4052
+ ["redux", ["@reduxjs/toolkit", "redux"]],
4053
+ ["reactquery", ["@tanstack/react-query", "react-query"]],
4054
+ ["trpc", ["@trpc/server", "@trpc/client"]],
4055
+ ["mongoose", ["mongoose"]],
4056
+ ["graphql", ["@apollo/client", "@apollo/server", "apollo-server", "graphql"]],
4057
+ ["vue", ["vue", "@vue/core"]],
4058
+ ["tailwind", ["tailwindcss"]],
4059
+ ["vite", ["vite"]],
4060
+ ["sveltekit", ["@sveltejs/kit"]],
4061
+ ["astro", ["astro"]],
4062
+ ["typescript", ["typescript"]],
4063
+ ["monorepo", ["turbo", "nx", "@nrwl/workspace", "@nx/workspace"]]
4064
+ ];
4065
+ var PYTHON_DETECTORS = [
4066
+ ["fastapi", /\bfastapi\b/i],
4067
+ ["django", /\bdjango\b/i],
4068
+ ["flask", /\bflask\b/i]
4069
+ ];
4070
+ function detectFromPackageJson(deps) {
4071
+ const detected = [];
4072
+ for (const [stack, signals] of JS_DETECTORS) {
4073
+ if (signals.some((s) => s in deps)) detected.push(stack);
4074
+ }
4075
+ if (detected.includes("nextjs") || detected.includes("remix")) {
4076
+ return detected.filter((s) => s !== "react");
4077
+ }
4078
+ return detected;
4079
+ }
4080
+ function detectFromRequirementsTxt(content) {
4081
+ return PYTHON_DETECTORS.filter(([, re]) => re.test(content)).map(([s]) => s);
4082
+ }
4083
+ function detectFromGoMod(content) {
4084
+ return /^\s*module\s+\S/m.test(content) ? ["go"] : [];
4085
+ }
4086
+ function detectFromPomXml(content) {
4087
+ return /org\.springframework|spring-boot/.test(content) ? ["spring"] : [];
4088
+ }
4089
+ function detectFromComposerJson(content) {
4090
+ return /laravel\/framework|illuminate\//.test(content) ? ["laravel"] : [];
4091
+ }
4092
+ function detectFromGemfile(content) {
4093
+ return /^\s*gem\s+["']rails["']/m.test(content) || /\brails\b/.test(content) ? ["rails"] : [];
4094
+ }
4095
+ function detectStacksFromManifests(input) {
4096
+ const seen = /* @__PURE__ */ new Set();
4097
+ const add = (stacks) => stacks.forEach((s) => seen.add(s));
4098
+ if (input.packageJsonDeps) add(detectFromPackageJson(input.packageJsonDeps));
4099
+ if (input.requirementsTxt) add(detectFromRequirementsTxt(input.requirementsTxt));
4100
+ if (input.goMod) add(detectFromGoMod(input.goMod));
4101
+ if (input.pomXml) add(detectFromPomXml(input.pomXml));
4102
+ if (input.composerJson) add(detectFromComposerJson(input.composerJson));
4103
+ if (input.gemfile) add(detectFromGemfile(input.gemfile));
4104
+ if (input.hasCsproj) add(["dotnet"]);
4105
+ if (input.hasDockerfile) add(["docker"]);
4106
+ if (input.hasTurboJson || input.hasNxJson) add(["monorepo"]);
4107
+ return Array.from(seen);
4108
+ }
4109
+
3832
4110
  // src/merge-memory.ts
3833
4111
  function safeParse(raw) {
3834
4112
  try {
@@ -3916,10 +4194,149 @@ function classifyMemoryPriority(signals) {
3916
4194
  function priorityRank(priority) {
3917
4195
  return priority === "must_read" ? 3 : priority === "useful" ? 2 : 1;
3918
4196
  }
4197
+
4198
+ // src/bridges.ts
4199
+ var BRIDGE_TARGET_PATH = {
4200
+ claude: "CLAUDE.md",
4201
+ cursor: ".cursor/rules/haive-memories.mdc",
4202
+ cline: ".clinerules",
4203
+ windsurf: ".windsurfrules",
4204
+ continue: ".continuerules",
4205
+ cody: ".sourcegraph/cody-rules.md",
4206
+ zed: ".rules",
4207
+ roo: ".roo/rules/haive.md",
4208
+ gemini: "GEMINI.md",
4209
+ aider: "CONVENTIONS.md",
4210
+ agents: "AGENTS.md",
4211
+ copilot: ".github/copilot-instructions.md"
4212
+ };
4213
+ var BRIDGE_TARGETS = Object.keys(BRIDGE_TARGET_PATH);
4214
+ var BRIDGE_MARKERS = {
4215
+ memoriesStart: "<!-- haive:memories-start -->",
4216
+ memoriesEnd: "<!-- haive:memories-end -->",
4217
+ sensorsStart: "<!-- haive:sensors-start -->",
4218
+ sensorsEnd: "<!-- haive:sensors-end -->"
4219
+ };
4220
+ function bridgeMemorySummary(body) {
4221
+ const firstLine = body.split("\n").map((l) => l.replace(/^#+\s*/, "").trim()).find((l) => l.length > 0) ?? "";
4222
+ const oneLine = firstLine.replace(/\s+/g, " ");
4223
+ return oneLine.length > 140 ? oneLine.slice(0, 137) + "\u2026" : oneLine;
4224
+ }
4225
+ function prepareBridgeData(memories, sensors, opts) {
4226
+ const max = opts?.maxMemories ?? 8;
4227
+ const topMemories = memories.filter((m) => {
4228
+ const s = m.frontmatter.status;
4229
+ if (m.frontmatter.type === "session_recap") return false;
4230
+ if (m.frontmatter.tags?.includes("stack-pack") || m.frontmatter.tags?.includes("seed")) return false;
4231
+ return s === "validated" || s === "proposed";
4232
+ }).sort((a, b) => {
4233
+ const score = (m) => m.frontmatter.status === "validated" ? 2 : 1;
4234
+ return score(b) - score(a);
4235
+ }).slice(0, max).map((m) => ({
4236
+ id: m.frontmatter.id,
4237
+ scope: m.frontmatter.scope,
4238
+ type: m.frontmatter.type,
4239
+ summary: bridgeMemorySummary(m.body),
4240
+ paths: m.frontmatter.anchor?.paths ?? []
4241
+ }));
4242
+ const blockSensors = sensors.filter((s) => s.severity === "block");
4243
+ return { topMemories, blockSensors };
4244
+ }
4245
+ function renderMemoriesBlock(topMemories) {
4246
+ const lines = [
4247
+ BRIDGE_MARKERS.memoriesStart,
4248
+ "<!-- AUTO-GENERATED by haive bridges sync \u2014 do not edit between these markers -->",
4249
+ "<!-- Top memories \u2014 call get_briefing / mem_get for the full body. -->",
4250
+ ""
4251
+ ];
4252
+ if (topMemories.length === 0) {
4253
+ lines.push("_(no validated memories yet \u2014 run `haive sync` to populate)_");
4254
+ } else {
4255
+ for (const m of topMemories) {
4256
+ const scopeNote = m.paths.length > 0 ? ` _(applies to: ${m.paths.slice(0, 4).join(", ")}${m.paths.length > 4 ? ", \u2026" : ""})_` : "";
4257
+ lines.push(`- \`${m.id}\` (${m.scope}/${m.type}) \u2014 ${m.summary}${scopeNote}`);
4258
+ }
4259
+ }
4260
+ lines.push("", BRIDGE_MARKERS.memoriesEnd);
4261
+ return lines.join("\n");
4262
+ }
4263
+ function renderSensorsBlock(blockSensors) {
4264
+ if (blockSensors.length === 0) return "";
4265
+ const lines = [
4266
+ BRIDGE_MARKERS.sensorsStart,
4267
+ "<!-- AUTO-GENERATED by haive bridges sync \u2014 do not edit between these markers -->",
4268
+ "",
4269
+ "## Hard rules \u2014 hAIve block sensors",
4270
+ "",
4271
+ "The patterns below are blocked by the repo enforcement gate.",
4272
+ "Introducing them will fail the pre-commit check (`haive enforce check`).",
4273
+ ""
4274
+ ];
4275
+ for (const s of blockSensors) {
4276
+ const pathNote = s.paths.length > 0 ? ` _(applies to: ${s.paths.join(", ")})_` : "";
4277
+ lines.push(`- **${s.id}**${pathNote}: ${s.message}`);
4278
+ if (s.pattern) lines.push(` - Pattern: \`${s.pattern}\``);
4279
+ }
4280
+ lines.push("", BRIDGE_MARKERS.sensorsEnd);
4281
+ return lines.join("\n");
4282
+ }
4283
+ var HAIVE_PREAMBLE = "This repo uses **[hAIve](https://github.com/Doucs91/hAIve)** for shared context and enforcement.\n\n**Before editing** for a goal: call `get_briefing` (task + files/symbols) to load ranked context.\n**When an approach fails**: call `mem_tried` right away.\n**Before closing**: run `haive enforce finish` and capture learnings via the `post_task` prompt.\n\nIf `get_briefing` returns `action_required`, surface each item to the developer and wait for\nexplicit confirmation before modifying any code.";
4284
+ function renderMarkdownBridge(topMemories, blockSensors, title) {
4285
+ const parts = [
4286
+ `# ${title}`,
4287
+ "",
4288
+ HAIVE_PREAMBLE,
4289
+ "",
4290
+ "## Memories",
4291
+ "",
4292
+ renderMemoriesBlock(topMemories)
4293
+ ];
4294
+ const sensorsBlock = renderSensorsBlock(blockSensors);
4295
+ if (sensorsBlock) {
4296
+ parts.push("", sensorsBlock);
4297
+ }
4298
+ return parts.join("\n") + "\n";
4299
+ }
4300
+ function renderCursorBridge(topMemories, blockSensors) {
4301
+ const frontmatter = [
4302
+ "---",
4303
+ "description: hAIve shared memories & block sensors (auto-generated)",
4304
+ "alwaysApply: true",
4305
+ "---",
4306
+ ""
4307
+ ].join("\n");
4308
+ return frontmatter + renderMarkdownBridge(topMemories, blockSensors, "hAIve rules (Cursor)");
4309
+ }
4310
+ var FORMATTERS = {
4311
+ claude: (m, s) => renderMarkdownBridge(m, s, "CLAUDE.md \u2014 hAIve context"),
4312
+ cursor: (m, s) => renderCursorBridge(m, s),
4313
+ cline: (m, s) => renderMarkdownBridge(m, s, "hAIve rules (Cline)"),
4314
+ windsurf: (m, s) => renderMarkdownBridge(m, s, "hAIve rules (Windsurf)"),
4315
+ continue: (m, s) => renderMarkdownBridge(m, s, "hAIve rules (Continue)"),
4316
+ cody: (m, s) => renderMarkdownBridge(m, s, "hAIve rules (Cody / Sourcegraph)"),
4317
+ zed: (m, s) => renderMarkdownBridge(m, s, "hAIve rules (Zed)"),
4318
+ roo: (m, s) => renderMarkdownBridge(m, s, "hAIve rules (Roo Code)"),
4319
+ gemini: (m, s) => renderMarkdownBridge(m, s, "GEMINI.md \u2014 hAIve context"),
4320
+ aider: (m, s) => renderMarkdownBridge(m, s, "CONVENTIONS.md \u2014 hAIve context (Aider)"),
4321
+ agents: (m, s) => renderMarkdownBridge(m, s, "AGENTS.md \u2014 hAIve context"),
4322
+ copilot: (m, s) => renderMarkdownBridge(m, s, "hAIve rules (GitHub Copilot)")
4323
+ };
4324
+ function generateBridges(memories, sensors, opts) {
4325
+ const { topMemories, blockSensors } = prepareBridgeData(memories, sensors, opts);
4326
+ const targets = opts?.targets ?? BRIDGE_TARGETS;
4327
+ return targets.map((target) => ({
4328
+ target,
4329
+ path: BRIDGE_TARGET_PATH[target],
4330
+ content: FORMATTERS[target](topMemories, blockSensors)
4331
+ }));
4332
+ }
3919
4333
  export {
3920
4334
  AUTOPILOT_DEFAULTS,
3921
4335
  ActivationSchema,
3922
4336
  AnchorSchema,
4337
+ BRIDGE_MARKERS,
4338
+ BRIDGE_TARGETS,
4339
+ BRIDGE_TARGET_PATH,
3923
4340
  BRIEFING_MARKER_TTL_MS,
3924
4341
  BRIEFING_PRESET_DEFAULTS,
3925
4342
  CHARS_PER_TOKEN,
@@ -3962,8 +4379,11 @@ export {
3962
4379
  appendPreventionEvent,
3963
4380
  appendRuntimeJournalEntry,
3964
4381
  appendUsageEvent,
4382
+ applyFeedbackAdjustment,
4383
+ bridgeMemorySummary,
3965
4384
  briefingMarkerPath,
3966
4385
  briefingMarkersDir,
4386
+ briefingProofLine,
3967
4387
  buildCodeMap,
3968
4388
  buildCoverageIndex,
3969
4389
  buildDashboard,
@@ -3976,6 +4396,7 @@ export {
3976
4396
  collectTimelineEntries,
3977
4397
  compactAutoRecapBody,
3978
4398
  compareEvalReports,
4399
+ compareGatePrecision,
3979
4400
  compareImpact,
3980
4401
  compileRegexSensor,
3981
4402
  computeEvalTrend,
@@ -3986,6 +4407,7 @@ export {
3986
4407
  configPath,
3987
4408
  contractLockPath,
3988
4409
  deriveConfidence,
4410
+ detectStacksFromManifests,
3989
4411
  diffContract,
3990
4412
  diffHasDistinctiveOverlap,
3991
4413
  distinctiveCap,
@@ -4007,6 +4429,7 @@ export {
4007
4429
  findingBody,
4008
4430
  findingToDraft,
4009
4431
  firstMemoryOneLine,
4432
+ generateBridges,
4010
4433
  getUsage,
4011
4434
  globToRegExp,
4012
4435
  hasRecentBriefingMarker,
@@ -4043,14 +4466,17 @@ export {
4043
4466
  normalizeFindingSeverity,
4044
4467
  normalizeSessionId,
4045
4468
  overallScore,
4469
+ parseEslintJson,
4046
4470
  parseFindings,
4047
4471
  parseMemory,
4472
+ parseNpmAudit,
4048
4473
  parseSarif,
4049
4474
  parseSince,
4050
4475
  parseSonar,
4051
4476
  pathsOverlap,
4052
4477
  pickSnippetNeedle,
4053
4478
  planConflictResolution,
4479
+ prepareBridgeData,
4054
4480
  preventionLogPath,
4055
4481
  priorityRank,
4056
4482
  prioritySignals,
@@ -4062,11 +4488,13 @@ export {
4062
4488
  readRecentBriefingMarker,
4063
4489
  readRuntimeJournalTail,
4064
4490
  readUsageEvents,
4491
+ recommendFeedbackAdjustment,
4065
4492
  recordApplied,
4066
4493
  recordPrevention,
4067
4494
  recordProjectContextEmission,
4068
4495
  recordRejection,
4069
4496
  relPathFrom,
4497
+ renderCaughtForYou,
4070
4498
  resolveBriefingBudget,
4071
4499
  resolveHaivePaths,
4072
4500
  resolveManifestFiles,
@@ -4090,6 +4518,7 @@ export {
4090
4518
  suggestGate,
4091
4519
  suggestSensorFromMemory,
4092
4520
  suggestTopicKey,
4521
+ summarizeCaughtForYou,
4093
4522
  summarizeImpact,
4094
4523
  synthesizeSelfEvalCases,
4095
4524
  titleFromBody,