@hiveai/core 0.20.1 → 0.23.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
@@ -593,6 +593,19 @@ interface PreventionEvent {
593
593
  declare function preventionLogPath(paths: HaivePaths): string;
594
594
  /** Append one catch to the log. Best-effort, creates the dir on demand. */
595
595
  declare function appendPreventionEvent(paths: HaivePaths, event: PreventionEvent): Promise<void>;
596
+ /**
597
+ * THE single recorder for "a documented lesson intercepted a real mistake". Every gate path —
598
+ * the installed git-hook gate (`enforce check`), the standalone `haive sensors check`, and the
599
+ * `anti_patterns_check` MCP tool — funnels its fired memory ids through here so prevention is
600
+ * recorded once and identically, not bolted onto each entry point (it used to leak: the git-hook
601
+ * gate blocked but never recorded — see the harness-positioning gotcha).
602
+ *
603
+ * Bumps `prevented_count` in usage.json (debounced per memory via {@link recordPrevention}) AND
604
+ * appends one timestamped event per NEW catch to the prevention log. Best-effort: a telemetry
605
+ * write must never break a commit, so failures are swallowed. Returns the ids actually recorded
606
+ * (i.e. not debounced), so callers can report "caught for you" without re-counting.
607
+ */
608
+ declare function recordPreventionHits(paths: HaivePaths, firedIds: string[], source: PreventionSource, now?: Date): Promise<string[]>;
596
609
  /** Read all catch events (skips malformed lines). */
597
610
  declare function loadPreventionEvents(paths: HaivePaths): Promise<PreventionEvent[]>;
598
611
  interface PreventionTrend {
@@ -1217,6 +1230,13 @@ interface HaiveConfig {
1217
1230
  * Default: "anchored" — makes "known bad approaches are blocked" true for the precise case.
1218
1231
  */
1219
1232
  antiPatternGate?: "off" | "review" | "anchored" | "strict";
1233
+ /**
1234
+ * Pre-commit/pre-push decision-coverage behaviour. When true (default), the gate SURFACES the
1235
+ * relevant anchored decisions/policies itself and records them in the session marker at commit
1236
+ * time — no separate `haive briefing` step required. Set false for the strict legacy behaviour
1237
+ * where the commit is blocked until a prior briefing covered those decisions.
1238
+ */
1239
+ autoBrief?: boolean;
1220
1240
  /**
1221
1241
  * Execute `kind: "shell" | "test"` memory sensors during `haive sensors check`.
1222
1242
  * These run arbitrary repo-authored commands, so they are OFF by default; turn on per repo
@@ -2014,14 +2034,20 @@ declare function findUncapturedFailures(failures: FailureObservation[], captureT
2014
2034
  * Pure: the caller supplies hot files (from git history / briefing-radar) and the loaded corpus.
2015
2035
  */
2016
2036
 
2037
+ /** Where a file's "heat" came from: committed git churn, agent edits this/recent sessions, or both. */
2038
+ type HotFileSource = "git" | "agent" | "both";
2017
2039
  interface HotFile {
2018
2040
  path: string;
2019
2041
  /** Number of times the file changed in the lookback window (the "heat"). */
2020
2042
  changes: number;
2043
+ /** Provenance of the heat. Optional for back-compat with git-only callers. */
2044
+ source?: HotFileSource;
2021
2045
  }
2022
2046
  interface CoverageGap {
2023
2047
  path: string;
2024
2048
  changes: number;
2049
+ /** Provenance of the heat that made this file a blind spot. */
2050
+ source?: HotFileSource;
2025
2051
  }
2026
2052
  interface CoverageOptions {
2027
2053
  /** Only flag files with at least this many changes. Default 3. */
@@ -2043,6 +2069,17 @@ declare function isCovered(file: string, coverage: Set<string>): boolean;
2043
2069
  * Highest heat first. These are the highest-value places to add a memory or sensor.
2044
2070
  */
2045
2071
  declare function findCoverageGaps(hotFiles: HotFile[], memories: LoadedMemory[], options?: CoverageOptions): CoverageGap[];
2072
+ /**
2073
+ * Tally a flat list of edited file paths into HotFiles — the agent-edit heat signal from the
2074
+ * PostToolUse observation log (files agents actually touch), complementary to committed git churn.
2075
+ * Pure: the caller reads/normalizes the observation paths.
2076
+ */
2077
+ declare function tallyHotFiles(paths: string[], source?: HotFileSource): HotFile[];
2078
+ /**
2079
+ * Merge two HotFile lists, summing heat per path. A file hot in both lists is tagged `both` so the
2080
+ * report can show that agents AND git churn both point at the same uncovered file (the strongest gap).
2081
+ */
2082
+ declare function mergeHotFiles(a: HotFile[], b: HotFile[]): HotFile[];
2046
2083
 
2047
2084
  interface EvalHistoryEntry {
2048
2085
  /** ISO timestamp of the eval run. */
@@ -2107,6 +2144,26 @@ interface ConflictResolution {
2107
2144
  }
2108
2145
  /** Compare two memories; returns the one that should WIN plus the reason. Pure. */
2109
2146
  declare function planConflictResolution(a: LoadedMemory, b: LoadedMemory): ConflictResolution;
2147
+ interface AppliedConflictResolution {
2148
+ /** Updated frontmatter for the memory to keep (promoted). */
2149
+ winner: MemoryFrontmatter;
2150
+ /** Updated frontmatter for the memory to supersede (deprecated). */
2151
+ loser: MemoryFrontmatter;
2152
+ /** Topic the winner now carries — the consolidation target for future `mem_save` upserts. Null when neither carried one. */
2153
+ topic: string | null;
2154
+ /** True when the winner adopted the loser's topic because it had none. */
2155
+ topic_adopted: boolean;
2156
+ }
2157
+ /**
2158
+ * Turn a {@link ConflictResolution} plan into the two concrete frontmatter updates — the guided
2159
+ * supersede the backlog called for, wired into topic-upsert/revision_count:
2160
+ * - loser → deprecated, stamped with stale_reason + a related_ids link to the winner.
2161
+ * - winner → revision_count++ (it absorbed a contradiction), verified now, linked to the loser,
2162
+ * and it ADOPTS the loser's topic when it had none — so the next `mem_save` on this subject
2163
+ * upserts into the winner instead of spawning a third conflicting memory. An existing winner
2164
+ * topic is never overwritten. Pure: the caller persists both.
2165
+ */
2166
+ declare function applyConflictResolution(winner: LoadedMemory, loser: LoadedMemory, plan: ConflictResolution, now?: Date): AppliedConflictResolution;
2110
2167
 
2111
2168
  /**
2112
2169
  * Cold-start seeding from git history — the harness has value only once the corpus is populated,
@@ -2336,4 +2393,4 @@ declare function prepareBridgeData(memories: Memory[], sensors: BridgeSensor[],
2336
2393
  */
2337
2394
  declare function generateBridges(memories: Memory[], sensors: BridgeSensor[], opts?: GenerateBridgesOptions): BridgeFileOutput[];
2338
2395
 
2339
- export { AUTOPILOT_DEFAULTS, type Activation, type ActivationContext, ActivationSchema, type Anchor, AnchorSchema, type AntiPatternGate, type AutoPromoteRule, BRIDGE_MARKERS, BRIDGE_TARGETS, BRIDGE_TARGET_PATH, BRIEFING_MARKER_TTL_MS, BRIEFING_PRESET_DEFAULTS, type BreakingChange, type BridgeFileOutput, type BridgeMemoryEntry, type BridgeSensor, type BridgeTarget, type BriefingBudgetNumbers, type BriefingBudgetPreset, type BriefingMarker, type BriefingProofLineOptions, type BudgetPart, type BudgetSlice, type BuildCodeMapOptions, CHARS_PER_TOKEN, CODE_MAP_FILE, CODE_STOPWORDS, CONFIG_FILE, type CaughtForYouOptions, type CaughtForYouRow, type CaughtForYouSummary, type CodeExport, type CodeExportKind, type CodeFileEntry, type CodeMap, type CodeMapQueryOptions, type CollectTimelineOpts, type CommandSensorSpec, type ConfidenceLevel, type ConfidenceThresholds, type ConflictCandidatePair, type ConflictCandidatesOpts, type ConflictResolution, type ContractDiffResult, type ContractFile, type ContractSnapshot, type CoverageGap, type CoverageOptions, CrossRepoProvenanceSchema, type CrossRepoReport, type CrossRepoSource, DECAY_DAYS, DEFAULT_AUTO_PROMOTE_RULE, DEFAULT_CONFIDENCE_THRESHOLDS, DEFAULT_CONFIG, DEFAULT_DORMANT_DAYS, DEFAULT_PRIORITY_SIGNALS, type DashboardOptions, type DashboardReport, type DepChange, type DepTrackResult, type DependencySnapshot, type DetectStacksInput, type DetectableStack, type DocFrequency, type DormantRow, type DraftOptions, type DraftsOptions, ENV_WORKAROUND_TAGS, type EvalDelta, type EvalHistoryEntry, type EvalReport, type EvalSpec, type EvalTrend, type FailureCoverageOptions, type FailureObservation, type FeedbackAdjustment, type FeedbackAdjustmentAction, type FeedbackAdjustmentOptions, type Finding, type FindingFormat, type FindingSeverity, GUESSABLE_THRESHOLD, type GatePrecision, type GatePrecisionDelta, type GatePrecisionMetricDelta, type GateTuningSuggestion, type GenerateBridgesOptions, type GitCommit, HAIVE_DIR, type HaiveConfig, type HaivePaths, type HotFile, type ImpactOptions, type ImpactRow, type ImpactScore, type ImpactSummary, type ImpactTier, type LexicalRankResult, type LoadedMemory, MEMORIES_DIR, MIN_WORD_LEN, type Memory, type MemoryDraft, type MemoryFrontmatter, MemoryFrontmatterSchema, type MemoryPriority, type MemoryScope, MemoryScopeSchema, type MemoryStatus, MemoryStatusSchema, type MemoryType, MemoryTypeSchema, type MemoryUsage, type MergeResult, type MetricDelta, PREVENTION_DEBOUNCE_MS, PROJECT_CONTEXT_FILE, PROJECT_CONTEXT_THROTTLE_MS, type PreventionEvent, type PreventionRow, type PreventionSource, type PreventionTrend, type PrioritySignals, RUNTIME_JOURNAL_FILENAME, type RecurrenceReport, type RecurrenceRow, type ResolveProjectInfo, type RetirementSignal, type RetrievalAggregate, type RetrievalCase, type RetrievalCaseResult, type RuntimeJournalEntry, SESSION_RECAP_TTL_MS, STACK_PACK_TAG, type SeedProposal, type SelfEvalOptions, type Sensor, type SensorAggregate, type SensorCase, type SensorCaseResult, type SensorHit, type SensorRow, SensorSchema, type SensorSuggestionOptions, type SensorTarget, type SkillActivation, type TimelineEntry, type TopicStatusPair, type TruncateOptions, type TruncateResult, USAGE_FILE, USAGE_LOG_DIR, USAGE_LOG_FILE, type UncapturedFailure, type UsageAggregate, type UsageEvent, type UsageIndex, type VerifyOptions, type VerifyResult, addedLinesFromDiff, aggregateRetrieval, aggregateSensors, aggregateUsage, allocateBudget, antiPatternGateParams, appendEvalHistory, appendPreventionEvent, appendRuntimeJournalEntry, appendUsageEvent, applyFeedbackAdjustment, bridgeMemorySummary, briefingMarkerPath, briefingMarkersDir, briefingProofLine, buildCodeMap, buildCoverageIndex, buildDashboard, buildDocFrequency, buildFrontmatter, buildReport, bumpRead, classifyMemoryPriority, codeMapPath, collectTimelineEntries, compactAutoRecapBody, compareEvalReports, compareGatePrecision, compareImpact, compileRegexSensor, computeEvalTrend, computeGatePrecision, computeImpact, computePreventionTrend, computeRecurrence, configPath, contractLockPath, deriveConfidence, detectStacksFromManifests, diffContract, diffHasDistinctiveOverlap, distinctiveCap, draftsFromFindings, emptyUsage, emptyUsageIndex, enforcementDir, estimateTokens, evalHistoryPath, evaluateSkillActivation, extractActionsBriefBody, extractSnippet, filterNewDrafts, findCoverageGaps, findLexicalConflictPairs, findProjectRoot, findTopicStatusConflictPairs, findUncapturedFailures, findingBody, findingToDraft, firstMemoryOneLine, generateBridges, getUsage, globToRegExp, hasRecentBriefingMarker, hashProjectContext, inferModulesFromPaths, isAutoPromoteEligible, isAutoRecap, isCovered, isDecaying, isDistinctiveToken, isEnvWorkaroundMemory, isFreshIsoDate, isGlobPath, isLikelyGuessable, isRetiredMemory, isSkill, isSkillSuppressed, isStackPackSeed, listMarkdownFilesRecursive, literalMatchesAllTokens, literalMatchesAnyToken, loadCodeMap, loadConfig, loadConfigSync, loadEvalHistory, loadMemoriesFromDir, loadMemory, loadPreventionEvents, loadUsageIndex, looksLikeGenericAdvice, memoryFilePath, memoryMatchesAnchorPaths, mergeMemoryVersions, newMemoryId, normalizeFindingSeverity, normalizeSessionId, overallScore, parseEslintJson, parseFindings, parseMemory, parseNpmAudit, parseSarif, parseSince, parseSonar, pathsOverlap, pickSnippetNeedle, planConflictResolution, prepareBridgeData, preventionLogPath, priorityRank, prioritySignals, projectContextRecentlyEmitted, proposeSeedsFromCommits, pullCrossRepoSources, queryCodeMap, rankMemoriesLexical, readRecentBriefingMarker, readRuntimeJournalTail, readUsageEvents, recommendFeedbackAdjustment, recordApplied, recordPrevention, recordProjectContextEmission, recordRejection, relPathFrom, renderCaughtForYou, resolveBriefingBudget, resolveHaivePaths, resolveManifestFiles, resolveProjectInfo, retirementSignal, runRegexSensor, runSensors, runtimeJournalPath, saveCodeMap, saveConfig, saveUsageIndex, scoreRetrievalCase, scoreSensorCase, selectCommandSensors, sensorAppliesToPath, sensorTargetsFromDiff, serializeMemory, snapshotContract, specificityScore, stripPrivate, suggestGate, suggestSensorFromMemory, suggestTopicKey, summarizeCaughtForYou, summarizeImpact, synthesizeSelfEvalCases, titleFromBody, tokenizeQuery, tokenizeWords, trackDependencies, trackReads, truncateToTokens, usageLogPath, usageLogSize, usagePath, verifyAnchor, watchContracts, writeBriefingMarker };
2396
+ export { AUTOPILOT_DEFAULTS, type Activation, type ActivationContext, ActivationSchema, type Anchor, AnchorSchema, type AntiPatternGate, type AppliedConflictResolution, type AutoPromoteRule, BRIDGE_MARKERS, BRIDGE_TARGETS, BRIDGE_TARGET_PATH, BRIEFING_MARKER_TTL_MS, BRIEFING_PRESET_DEFAULTS, type BreakingChange, type BridgeFileOutput, type BridgeMemoryEntry, type BridgeSensor, type BridgeTarget, type BriefingBudgetNumbers, type BriefingBudgetPreset, type BriefingMarker, type BriefingProofLineOptions, type BudgetPart, type BudgetSlice, type BuildCodeMapOptions, CHARS_PER_TOKEN, CODE_MAP_FILE, CODE_STOPWORDS, CONFIG_FILE, type CaughtForYouOptions, type CaughtForYouRow, type CaughtForYouSummary, type CodeExport, type CodeExportKind, type CodeFileEntry, type CodeMap, type CodeMapQueryOptions, type CollectTimelineOpts, type CommandSensorSpec, type ConfidenceLevel, type ConfidenceThresholds, type ConflictCandidatePair, type ConflictCandidatesOpts, type ConflictResolution, type ContractDiffResult, type ContractFile, type ContractSnapshot, type CoverageGap, type CoverageOptions, CrossRepoProvenanceSchema, type CrossRepoReport, type CrossRepoSource, DECAY_DAYS, DEFAULT_AUTO_PROMOTE_RULE, DEFAULT_CONFIDENCE_THRESHOLDS, DEFAULT_CONFIG, DEFAULT_DORMANT_DAYS, DEFAULT_PRIORITY_SIGNALS, type DashboardOptions, type DashboardReport, type DepChange, type DepTrackResult, type DependencySnapshot, type DetectStacksInput, type DetectableStack, type DocFrequency, type DormantRow, type DraftOptions, type DraftsOptions, ENV_WORKAROUND_TAGS, type EvalDelta, type EvalHistoryEntry, type EvalReport, type EvalSpec, type EvalTrend, type FailureCoverageOptions, type FailureObservation, type FeedbackAdjustment, type FeedbackAdjustmentAction, type FeedbackAdjustmentOptions, type Finding, type FindingFormat, type FindingSeverity, GUESSABLE_THRESHOLD, type GatePrecision, type GatePrecisionDelta, type GatePrecisionMetricDelta, type GateTuningSuggestion, type GenerateBridgesOptions, type GitCommit, HAIVE_DIR, type HaiveConfig, type HaivePaths, type HotFile, type HotFileSource, type ImpactOptions, type ImpactRow, type ImpactScore, type ImpactSummary, type ImpactTier, type LexicalRankResult, type LoadedMemory, MEMORIES_DIR, MIN_WORD_LEN, type Memory, type MemoryDraft, type MemoryFrontmatter, MemoryFrontmatterSchema, type MemoryPriority, type MemoryScope, MemoryScopeSchema, type MemoryStatus, MemoryStatusSchema, type MemoryType, MemoryTypeSchema, type MemoryUsage, type MergeResult, type MetricDelta, PREVENTION_DEBOUNCE_MS, PROJECT_CONTEXT_FILE, PROJECT_CONTEXT_THROTTLE_MS, type PreventionEvent, type PreventionRow, type PreventionSource, type PreventionTrend, type PrioritySignals, RUNTIME_JOURNAL_FILENAME, type RecurrenceReport, type RecurrenceRow, type ResolveProjectInfo, type RetirementSignal, type RetrievalAggregate, type RetrievalCase, type RetrievalCaseResult, type RuntimeJournalEntry, SESSION_RECAP_TTL_MS, STACK_PACK_TAG, type SeedProposal, type SelfEvalOptions, type Sensor, type SensorAggregate, type SensorCase, type SensorCaseResult, type SensorHit, type SensorRow, SensorSchema, type SensorSuggestionOptions, type SensorTarget, type SkillActivation, type TimelineEntry, type TopicStatusPair, type TruncateOptions, type TruncateResult, USAGE_FILE, USAGE_LOG_DIR, USAGE_LOG_FILE, type UncapturedFailure, type UsageAggregate, type UsageEvent, type UsageIndex, type VerifyOptions, type VerifyResult, addedLinesFromDiff, aggregateRetrieval, aggregateSensors, aggregateUsage, allocateBudget, antiPatternGateParams, appendEvalHistory, appendPreventionEvent, appendRuntimeJournalEntry, appendUsageEvent, applyConflictResolution, applyFeedbackAdjustment, bridgeMemorySummary, briefingMarkerPath, briefingMarkersDir, briefingProofLine, buildCodeMap, buildCoverageIndex, buildDashboard, buildDocFrequency, buildFrontmatter, buildReport, bumpRead, classifyMemoryPriority, codeMapPath, collectTimelineEntries, compactAutoRecapBody, compareEvalReports, compareGatePrecision, compareImpact, compileRegexSensor, computeEvalTrend, computeGatePrecision, computeImpact, computePreventionTrend, computeRecurrence, configPath, contractLockPath, deriveConfidence, detectStacksFromManifests, diffContract, diffHasDistinctiveOverlap, distinctiveCap, draftsFromFindings, emptyUsage, emptyUsageIndex, enforcementDir, estimateTokens, evalHistoryPath, evaluateSkillActivation, extractActionsBriefBody, extractSnippet, filterNewDrafts, findCoverageGaps, findLexicalConflictPairs, findProjectRoot, findTopicStatusConflictPairs, findUncapturedFailures, findingBody, findingToDraft, firstMemoryOneLine, generateBridges, getUsage, globToRegExp, hasRecentBriefingMarker, hashProjectContext, inferModulesFromPaths, isAutoPromoteEligible, isAutoRecap, isCovered, isDecaying, isDistinctiveToken, isEnvWorkaroundMemory, isFreshIsoDate, isGlobPath, isLikelyGuessable, isRetiredMemory, isSkill, isSkillSuppressed, isStackPackSeed, listMarkdownFilesRecursive, literalMatchesAllTokens, literalMatchesAnyToken, loadCodeMap, loadConfig, loadConfigSync, loadEvalHistory, loadMemoriesFromDir, loadMemory, loadPreventionEvents, loadUsageIndex, looksLikeGenericAdvice, memoryFilePath, memoryMatchesAnchorPaths, mergeHotFiles, mergeMemoryVersions, newMemoryId, normalizeFindingSeverity, normalizeSessionId, overallScore, parseEslintJson, parseFindings, parseMemory, parseNpmAudit, parseSarif, parseSince, parseSonar, pathsOverlap, pickSnippetNeedle, planConflictResolution, prepareBridgeData, preventionLogPath, priorityRank, prioritySignals, projectContextRecentlyEmitted, proposeSeedsFromCommits, pullCrossRepoSources, queryCodeMap, rankMemoriesLexical, readRecentBriefingMarker, readRuntimeJournalTail, readUsageEvents, recommendFeedbackAdjustment, recordApplied, recordPrevention, recordPreventionHits, recordProjectContextEmission, recordRejection, relPathFrom, renderCaughtForYou, resolveBriefingBudget, resolveHaivePaths, resolveManifestFiles, resolveProjectInfo, retirementSignal, runRegexSensor, runSensors, runtimeJournalPath, saveCodeMap, saveConfig, saveUsageIndex, scoreRetrievalCase, scoreSensorCase, selectCommandSensors, sensorAppliesToPath, sensorTargetsFromDiff, serializeMemory, snapshotContract, specificityScore, stripPrivate, suggestGate, suggestSensorFromMemory, suggestTopicKey, summarizeCaughtForYou, summarizeImpact, synthesizeSelfEvalCases, tallyHotFiles, titleFromBody, tokenizeQuery, tokenizeWords, trackDependencies, trackReads, truncateToTokens, usageLogPath, usageLogSize, usagePath, verifyAnchor, watchContracts, writeBriefingMarker };
package/dist/index.js CHANGED
@@ -852,6 +852,25 @@ async function appendPreventionEvent(paths, event) {
852
852
  await mkdir2(path6.dirname(file), { recursive: true });
853
853
  await appendFile(file, JSON.stringify(event) + "\n", "utf8");
854
854
  }
855
+ async function recordPreventionHits(paths, firedIds, source, now = /* @__PURE__ */ new Date()) {
856
+ const unique = [...new Set(firedIds)].filter(Boolean);
857
+ if (unique.length === 0) return [];
858
+ const usage = await loadUsageIndex(paths).catch(() => null);
859
+ if (!usage) return [];
860
+ const recordedIds = [];
861
+ for (const id of unique) {
862
+ if (recordPrevention(usage, id, now.getTime())) recordedIds.push(id);
863
+ }
864
+ if (recordedIds.length === 0) return [];
865
+ await saveUsageIndex(paths, usage).catch(() => {
866
+ });
867
+ const at = now.toISOString();
868
+ for (const id of recordedIds) {
869
+ await appendPreventionEvent(paths, { at, id, source }).catch(() => {
870
+ });
871
+ }
872
+ return recordedIds;
873
+ }
855
874
  async function loadPreventionEvents(paths) {
856
875
  const file = preventionLogPath(paths);
857
876
  if (!existsSync4(file)) return [];
@@ -3906,11 +3925,36 @@ function findCoverageGaps(hotFiles, memories, options = {}) {
3906
3925
  for (const hot of hotFiles) {
3907
3926
  if (hot.changes < minChanges) continue;
3908
3927
  if (isCovered(hot.path, coverage)) continue;
3909
- gaps.push({ path: normalizePath(hot.path), changes: hot.changes });
3928
+ gaps.push({ path: normalizePath(hot.path), changes: hot.changes, ...hot.source ? { source: hot.source } : {} });
3910
3929
  }
3911
3930
  gaps.sort((a, b) => b.changes - a.changes);
3912
3931
  return gaps.slice(0, limit);
3913
3932
  }
3933
+ function tallyHotFiles(paths, source = "agent") {
3934
+ const counts = /* @__PURE__ */ new Map();
3935
+ for (const raw of paths) {
3936
+ const norm = normalizePath(raw);
3937
+ if (!norm) continue;
3938
+ counts.set(norm, (counts.get(norm) ?? 0) + 1);
3939
+ }
3940
+ return [...counts.entries()].map(([path18, changes]) => ({ path: path18, changes, source })).sort((a, b) => b.changes - a.changes);
3941
+ }
3942
+ function mergeHotFiles(a, b) {
3943
+ const merged = /* @__PURE__ */ new Map();
3944
+ for (const hot of [...a, ...b]) {
3945
+ const norm = normalizePath(hot.path);
3946
+ if (!norm) continue;
3947
+ const existing = merged.get(norm);
3948
+ if (!existing) {
3949
+ merged.set(norm, { path: norm, changes: hot.changes, ...hot.source ? { source: hot.source } : {} });
3950
+ continue;
3951
+ }
3952
+ existing.changes += hot.changes;
3953
+ if (hot.source && existing.source && hot.source !== existing.source) existing.source = "both";
3954
+ else existing.source = existing.source ?? hot.source;
3955
+ }
3956
+ return [...merged.values()].sort((x, y) => y.changes - x.changes);
3957
+ }
3914
3958
 
3915
3959
  // src/eval-history.ts
3916
3960
  import { appendFile as appendFile4, mkdir as mkdir11, readFile as readFile14 } from "fs/promises";
@@ -3998,6 +4042,30 @@ function planConflictResolution(a, b) {
3998
4042
  stale_reason: `Superseded by ${keepId} (conflict resolved on ${reason}).`
3999
4043
  };
4000
4044
  }
4045
+ function applyConflictResolution(winner, loser, plan, now = /* @__PURE__ */ new Date()) {
4046
+ const ts = now.toISOString();
4047
+ const wf = winner.memory.frontmatter;
4048
+ const lf = loser.memory.frontmatter;
4049
+ const winnerHasTopic = Boolean(wf.topic && wf.topic.trim() !== "");
4050
+ const loserHasTopic = Boolean(lf.topic && lf.topic.trim() !== "");
4051
+ const topicAdopted = !winnerHasTopic && loserHasTopic;
4052
+ const topic = winnerHasTopic ? wf.topic : topicAdopted ? lf.topic : null;
4053
+ const winnerFm = {
4054
+ ...wf,
4055
+ revision_count: wf.revision_count + 1,
4056
+ verified_at: ts,
4057
+ related_ids: [.../* @__PURE__ */ new Set([...wf.related_ids, plan.supersede_id])],
4058
+ ...topic ? { topic } : {}
4059
+ };
4060
+ const loserFm = {
4061
+ ...lf,
4062
+ status: "deprecated",
4063
+ stale_reason: plan.stale_reason,
4064
+ verified_at: ts,
4065
+ related_ids: [.../* @__PURE__ */ new Set([...lf.related_ids, plan.keep_id])]
4066
+ };
4067
+ return { winner: winnerFm, loser: loserFm, topic, topic_adopted: topicAdopted };
4068
+ }
4001
4069
 
4002
4070
  // src/seed-git.ts
4003
4071
  var REVERT_RE = /^Revert\s+"(.+)"\s*$/i;
@@ -4383,6 +4451,7 @@ export {
4383
4451
  appendPreventionEvent,
4384
4452
  appendRuntimeJournalEntry,
4385
4453
  appendUsageEvent,
4454
+ applyConflictResolution,
4386
4455
  applyFeedbackAdjustment,
4387
4456
  bridgeMemorySummary,
4388
4457
  briefingMarkerPath,
@@ -4466,6 +4535,7 @@ export {
4466
4535
  looksLikeGenericAdvice,
4467
4536
  memoryFilePath,
4468
4537
  memoryMatchesAnchorPaths,
4538
+ mergeHotFiles,
4469
4539
  mergeMemoryVersions,
4470
4540
  newMemoryId,
4471
4541
  normalizeFindingSeverity,
@@ -4496,6 +4566,7 @@ export {
4496
4566
  recommendFeedbackAdjustment,
4497
4567
  recordApplied,
4498
4568
  recordPrevention,
4569
+ recordPreventionHits,
4499
4570
  recordProjectContextEmission,
4500
4571
  recordRejection,
4501
4572
  relPathFrom,
@@ -4526,6 +4597,7 @@ export {
4526
4597
  summarizeCaughtForYou,
4527
4598
  summarizeImpact,
4528
4599
  synthesizeSelfEvalCases,
4600
+ tallyHotFiles,
4529
4601
  titleFromBody,
4530
4602
  tokenizeQuery,
4531
4603
  tokenizeWords,