@hiveai/core 0.21.0 → 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 {
@@ -2021,14 +2034,20 @@ declare function findUncapturedFailures(failures: FailureObservation[], captureT
2021
2034
  * Pure: the caller supplies hot files (from git history / briefing-radar) and the loaded corpus.
2022
2035
  */
2023
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";
2024
2039
  interface HotFile {
2025
2040
  path: string;
2026
2041
  /** Number of times the file changed in the lookback window (the "heat"). */
2027
2042
  changes: number;
2043
+ /** Provenance of the heat. Optional for back-compat with git-only callers. */
2044
+ source?: HotFileSource;
2028
2045
  }
2029
2046
  interface CoverageGap {
2030
2047
  path: string;
2031
2048
  changes: number;
2049
+ /** Provenance of the heat that made this file a blind spot. */
2050
+ source?: HotFileSource;
2032
2051
  }
2033
2052
  interface CoverageOptions {
2034
2053
  /** Only flag files with at least this many changes. Default 3. */
@@ -2050,6 +2069,17 @@ declare function isCovered(file: string, coverage: Set<string>): boolean;
2050
2069
  * Highest heat first. These are the highest-value places to add a memory or sensor.
2051
2070
  */
2052
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[];
2053
2083
 
2054
2084
  interface EvalHistoryEntry {
2055
2085
  /** ISO timestamp of the eval run. */
@@ -2114,6 +2144,26 @@ interface ConflictResolution {
2114
2144
  }
2115
2145
  /** Compare two memories; returns the one that should WIN plus the reason. Pure. */
2116
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;
2117
2167
 
2118
2168
  /**
2119
2169
  * Cold-start seeding from git history — the harness has value only once the corpus is populated,
@@ -2343,4 +2393,4 @@ declare function prepareBridgeData(memories: Memory[], sensors: BridgeSensor[],
2343
2393
  */
2344
2394
  declare function generateBridges(memories: Memory[], sensors: BridgeSensor[], opts?: GenerateBridgesOptions): BridgeFileOutput[];
2345
2395
 
2346
- 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,