@nathanvale/chatline 0.0.1 → 0.0.2-next.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/CHANGELOG.md +6 -0
- package/dist/bin/index.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/cli/commands/clean.d.ts +0 -17
- package/dist/cli/commands/clean.d.ts.map +0 -1
- package/dist/cli/commands/clean.js +0 -142
- package/dist/cli/commands/clean.js.map +0 -1
- package/dist/cli/commands/doctor.d.ts +0 -17
- package/dist/cli/commands/doctor.d.ts.map +0 -1
- package/dist/cli/commands/doctor.js +0 -202
- package/dist/cli/commands/doctor.js.map +0 -1
- package/dist/cli/commands/enrich-ai.d.ts +0 -17
- package/dist/cli/commands/enrich-ai.d.ts.map +0 -1
- package/dist/cli/commands/enrich-ai.js +0 -371
- package/dist/cli/commands/enrich-ai.js.map +0 -1
- package/dist/cli/commands/index.d.ts +0 -16
- package/dist/cli/commands/index.d.ts.map +0 -1
- package/dist/cli/commands/index.js +0 -16
- package/dist/cli/commands/index.js.map +0 -1
- package/dist/cli/commands/ingest-csv.d.ts +0 -17
- package/dist/cli/commands/ingest-csv.d.ts.map +0 -1
- package/dist/cli/commands/ingest-csv.js +0 -138
- package/dist/cli/commands/ingest-csv.js.map +0 -1
- package/dist/cli/commands/ingest-db.d.ts +0 -17
- package/dist/cli/commands/ingest-db.d.ts.map +0 -1
- package/dist/cli/commands/ingest-db.js +0 -159
- package/dist/cli/commands/ingest-db.js.map +0 -1
- package/dist/cli/commands/init.d.ts +0 -17
- package/dist/cli/commands/init.d.ts.map +0 -1
- package/dist/cli/commands/init.js +0 -110
- package/dist/cli/commands/init.js.map +0 -1
- package/dist/cli/commands/normalize-link.d.ts +0 -16
- package/dist/cli/commands/normalize-link.d.ts.map +0 -1
- package/dist/cli/commands/normalize-link.js +0 -144
- package/dist/cli/commands/normalize-link.js.map +0 -1
- package/dist/cli/commands/render-markdown.d.ts +0 -17
- package/dist/cli/commands/render-markdown.d.ts.map +0 -1
- package/dist/cli/commands/render-markdown.js +0 -218
- package/dist/cli/commands/render-markdown.js.map +0 -1
- package/dist/cli/commands/stats.d.ts +0 -17
- package/dist/cli/commands/stats.d.ts.map +0 -1
- package/dist/cli/commands/stats.js +0 -175
- package/dist/cli/commands/stats.js.map +0 -1
- package/dist/cli/commands/validate.d.ts +0 -17
- package/dist/cli/commands/validate.d.ts.map +0 -1
- package/dist/cli/commands/validate.js +0 -152
- package/dist/cli/commands/validate.js.map +0 -1
- package/dist/cli/index.d.ts +0 -13
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js +0 -121
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/types.d.ts +0 -93
- package/dist/cli/types.d.ts.map +0 -1
- package/dist/cli/types.js +0 -7
- package/dist/cli/types.js.map +0 -1
- package/dist/cli/utils.d.ts +0 -29
- package/dist/cli/utils.d.ts.map +0 -1
- package/dist/cli/utils.js +0 -53
- package/dist/cli/utils.js.map +0 -1
- package/dist/cli.d.ts +0 -9
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -1805
- package/dist/config/generator.d.ts +0 -90
- package/dist/config/generator.d.ts.map +0 -1
- package/dist/config/generator.js +0 -320
- package/dist/config/generator.js.map +0 -1
- package/dist/config/loader.d.ts +0 -107
- package/dist/config/loader.d.ts.map +0 -1
- package/dist/config/loader.js +0 -251
- package/dist/config/loader.js.map +0 -1
- package/dist/config/schema.d.ts +0 -107
- package/dist/config/schema.d.ts.map +0 -1
- package/dist/config/schema.js +0 -169
- package/dist/config/schema.js.map +0 -1
- package/dist/enrich/audio-transcription.d.ts +0 -77
- package/dist/enrich/audio-transcription.d.ts.map +0 -1
- package/dist/enrich/audio-transcription.js +0 -370
- package/dist/enrich/audio-transcription.js.map +0 -1
- package/dist/enrich/checkpoint.d.ts +0 -137
- package/dist/enrich/checkpoint.d.ts.map +0 -1
- package/dist/enrich/checkpoint.js +0 -205
- package/dist/enrich/checkpoint.js.map +0 -1
- package/dist/enrich/idempotency.d.ts +0 -90
- package/dist/enrich/idempotency.d.ts.map +0 -1
- package/dist/enrich/idempotency.js +0 -188
- package/dist/enrich/idempotency.js.map +0 -1
- package/dist/enrich/image-analysis.d.ts +0 -62
- package/dist/enrich/image-analysis.d.ts.map +0 -1
- package/dist/enrich/image-analysis.js +0 -264
- package/dist/enrich/image-analysis.js.map +0 -1
- package/dist/enrich/index.d.ts +0 -60
- package/dist/enrich/index.d.ts.map +0 -1
- package/dist/enrich/index.js +0 -74
- package/dist/enrich/index.js.map +0 -1
- package/dist/enrich/link-enrichment.d.ts +0 -37
- package/dist/enrich/link-enrichment.d.ts.map +0 -1
- package/dist/enrich/link-enrichment.js +0 -202
- package/dist/enrich/link-enrichment.js.map +0 -1
- package/dist/enrich/pdf-video-handling.d.ts +0 -49
- package/dist/enrich/pdf-video-handling.d.ts.map +0 -1
- package/dist/enrich/pdf-video-handling.js +0 -325
- package/dist/enrich/pdf-video-handling.js.map +0 -1
- package/dist/enrich/progress-tracker.d.ts +0 -120
- package/dist/enrich/progress-tracker.d.ts.map +0 -1
- package/dist/enrich/progress-tracker.js +0 -220
- package/dist/enrich/progress-tracker.js.map +0 -1
- package/dist/enrich/providers/firecrawl.d.ts +0 -18
- package/dist/enrich/providers/firecrawl.d.ts.map +0 -1
- package/dist/enrich/providers/firecrawl.js +0 -48
- package/dist/enrich/providers/firecrawl.js.map +0 -1
- package/dist/enrich/providers/generic.d.ts +0 -16
- package/dist/enrich/providers/generic.d.ts.map +0 -1
- package/dist/enrich/providers/generic.js +0 -36
- package/dist/enrich/providers/generic.js.map +0 -1
- package/dist/enrich/providers/index.d.ts +0 -14
- package/dist/enrich/providers/index.d.ts.map +0 -1
- package/dist/enrich/providers/index.js +0 -13
- package/dist/enrich/providers/index.js.map +0 -1
- package/dist/enrich/providers/instagram.d.ts +0 -16
- package/dist/enrich/providers/instagram.d.ts.map +0 -1
- package/dist/enrich/providers/instagram.js +0 -43
- package/dist/enrich/providers/instagram.js.map +0 -1
- package/dist/enrich/providers/spotify.d.ts +0 -16
- package/dist/enrich/providers/spotify.d.ts.map +0 -1
- package/dist/enrich/providers/spotify.js +0 -45
- package/dist/enrich/providers/spotify.js.map +0 -1
- package/dist/enrich/providers/twitter.d.ts +0 -16
- package/dist/enrich/providers/twitter.d.ts.map +0 -1
- package/dist/enrich/providers/twitter.js +0 -43
- package/dist/enrich/providers/twitter.js.map +0 -1
- package/dist/enrich/providers/types.d.ts +0 -47
- package/dist/enrich/providers/types.d.ts.map +0 -1
- package/dist/enrich/providers/types.js +0 -15
- package/dist/enrich/providers/types.js.map +0 -1
- package/dist/enrich/providers/youtube.d.ts +0 -16
- package/dist/enrich/providers/youtube.d.ts.map +0 -1
- package/dist/enrich/providers/youtube.js +0 -43
- package/dist/enrich/providers/youtube.js.map +0 -1
- package/dist/enrich/rate-limiting.d.ts +0 -118
- package/dist/enrich/rate-limiting.d.ts.map +0 -1
- package/dist/enrich/rate-limiting.js +0 -258
- package/dist/enrich/rate-limiting.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/ingest/dedup-merge.d.ts +0 -82
- package/dist/ingest/dedup-merge.d.ts.map +0 -1
- package/dist/ingest/dedup-merge.js +0 -262
- package/dist/ingest/dedup-merge.js.map +0 -1
- package/dist/ingest/ingest-csv.d.ts +0 -62
- package/dist/ingest/ingest-csv.d.ts.map +0 -1
- package/dist/ingest/ingest-csv.js +0 -300
- package/dist/ingest/ingest-csv.js.map +0 -1
- package/dist/ingest/ingest-db.d.ts +0 -64
- package/dist/ingest/ingest-db.d.ts.map +0 -1
- package/dist/ingest/ingest-db.js +0 -172
- package/dist/ingest/ingest-db.js.map +0 -1
- package/dist/ingest/link-replies-and-tapbacks.d.ts +0 -53
- package/dist/ingest/link-replies-and-tapbacks.d.ts.map +0 -1
- package/dist/ingest/link-replies-and-tapbacks.js +0 -381
- package/dist/ingest/link-replies-and-tapbacks.js.map +0 -1
- package/dist/normalize/date-converters.d.ts +0 -45
- package/dist/normalize/date-converters.d.ts.map +0 -1
- package/dist/normalize/date-converters.js +0 -166
- package/dist/normalize/date-converters.js.map +0 -1
- package/dist/normalize/path-validator.d.ts +0 -65
- package/dist/normalize/path-validator.d.ts.map +0 -1
- package/dist/normalize/path-validator.js +0 -221
- package/dist/normalize/path-validator.js.map +0 -1
- package/dist/normalize/validate-normalized.d.ts +0 -45
- package/dist/normalize/validate-normalized.d.ts.map +0 -1
- package/dist/normalize/validate-normalized.js +0 -144
- package/dist/normalize/validate-normalized.js.map +0 -1
- package/dist/render/embeds-blockquotes.d.ts +0 -84
- package/dist/render/embeds-blockquotes.d.ts.map +0 -1
- package/dist/render/embeds-blockquotes.js +0 -204
- package/dist/render/embeds-blockquotes.js.map +0 -1
- package/dist/render/grouping.d.ts +0 -78
- package/dist/render/grouping.d.ts.map +0 -1
- package/dist/render/grouping.js +0 -134
- package/dist/render/grouping.js.map +0 -1
- package/dist/render/index.d.ts +0 -47
- package/dist/render/index.d.ts.map +0 -1
- package/dist/render/index.js +0 -245
- package/dist/render/index.js.map +0 -1
- package/dist/render/reply-rendering.d.ts +0 -88
- package/dist/render/reply-rendering.d.ts.map +0 -1
- package/dist/render/reply-rendering.js +0 -196
- package/dist/render/reply-rendering.js.map +0 -1
- package/dist/schema/message.d.ts +0 -125
- package/dist/schema/message.d.ts.map +0 -1
- package/dist/schema/message.js +0 -331
- package/dist/schema/message.js.map +0 -1
- package/dist/utils/delta-detection.d.ts +0 -107
- package/dist/utils/delta-detection.d.ts.map +0 -1
- package/dist/utils/delta-detection.js +0 -199
- package/dist/utils/delta-detection.js.map +0 -1
- package/dist/utils/enrichment-merge.d.ts +0 -135
- package/dist/utils/enrichment-merge.d.ts.map +0 -1
- package/dist/utils/enrichment-merge.js +0 -280
- package/dist/utils/enrichment-merge.js.map +0 -1
- package/dist/utils/human.d.ts +0 -15
- package/dist/utils/human.d.ts.map +0 -1
- package/dist/utils/human.js +0 -27
- package/dist/utils/human.js.map +0 -1
- package/dist/utils/incremental-state.d.ts +0 -133
- package/dist/utils/incremental-state.d.ts.map +0 -1
- package/dist/utils/incremental-state.js +0 -237
- package/dist/utils/incremental-state.js.map +0 -1
- package/dist/utils/logger.d.ts +0 -40
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js +0 -176
- package/dist/utils/logger.js.map +0 -1
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Delta Detection Module (INCREMENTAL--T02)
|
|
3
|
-
*
|
|
4
|
-
* Identifies new messages for enrichment by comparing current normalized state
|
|
5
|
-
* with previous enrichment state.
|
|
6
|
-
*
|
|
7
|
-
* Implements:
|
|
8
|
-
* - AC01: Load previous state from .imessage-state.json
|
|
9
|
-
* - AC02: Diff normalized messages against enrichedGuids
|
|
10
|
-
* - AC03: Return only new GUIDs for enrichment
|
|
11
|
-
* - AC04: Handle state file missing (treat as first run)
|
|
12
|
-
* - AC05: Log delta summary: Found X new messages to enrich
|
|
13
|
-
*
|
|
14
|
-
* Architecture:
|
|
15
|
-
* - DeltaResult: Complete delta detection output
|
|
16
|
-
* - detectDelta: Main entry point for delta detection
|
|
17
|
-
* - extractGuidsFromMessages: Convert messages to GUID set
|
|
18
|
-
* - computeDelta: Core diff logic
|
|
19
|
-
* - logDeltaSummary: Human-readable delta report
|
|
20
|
-
*/
|
|
21
|
-
import { humanInfo } from '#utils/human';
|
|
22
|
-
import { createLogger } from '#utils/logger';
|
|
23
|
-
import { detectNewMessages, loadIncrementalState } from './incremental-state';
|
|
24
|
-
// ============================================================================
|
|
25
|
-
// AC01 + AC04: Load previous state safely
|
|
26
|
-
// ============================================================================
|
|
27
|
-
/**
|
|
28
|
-
* AC01 + AC04: Load incremental state from disk
|
|
29
|
-
*
|
|
30
|
-
* Handles missing state file gracefully:
|
|
31
|
-
* - Returns null if file doesn't exist (first run)
|
|
32
|
-
* - Returns null if JSON is corrupted
|
|
33
|
-
* - Returns parsed state if valid
|
|
34
|
-
*
|
|
35
|
-
* @param stateFilePath - Path to .imessage-state.json
|
|
36
|
-
* @returns IncrementalState if found and valid, null if missing or corrupted
|
|
37
|
-
*/
|
|
38
|
-
async function loadPreviousState(stateFilePath) {
|
|
39
|
-
return loadIncrementalState(stateFilePath);
|
|
40
|
-
}
|
|
41
|
-
// ============================================================================
|
|
42
|
-
// AC02 + AC03: Extract GUIDs and compute delta
|
|
43
|
-
// ============================================================================
|
|
44
|
-
/**
|
|
45
|
-
* AC02 + AC03: Extract message GUIDs from normalized messages
|
|
46
|
-
*
|
|
47
|
-
* Converts Message[] to Set<guid> for efficient delta computation
|
|
48
|
-
*
|
|
49
|
-
* @param messages - Normalized messages to process
|
|
50
|
-
* @returns Set of unique message GUIDs
|
|
51
|
-
*/
|
|
52
|
-
export function extractGuidsFromMessages(messages) {
|
|
53
|
-
const guids = new Set();
|
|
54
|
-
for (const msg of messages) {
|
|
55
|
-
guids.add(msg.guid);
|
|
56
|
-
}
|
|
57
|
-
return guids;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* AC02 + AC03: Compute delta between current and previous state
|
|
61
|
-
*
|
|
62
|
-
* Performance: O(n + m) where:
|
|
63
|
-
* - n = number of current messages
|
|
64
|
-
* - m = number of previously enriched messages
|
|
65
|
-
*
|
|
66
|
-
* Uses Set-based deduplication for O(1) lookup
|
|
67
|
-
*
|
|
68
|
-
* @param currentGuids - Set of message GUIDs from normalized state
|
|
69
|
-
* @param previousState - Prior state with enriched GUIDs (null if first run)
|
|
70
|
-
* @returns New GUIDs not in previous state
|
|
71
|
-
*/
|
|
72
|
-
function computeDelta(currentGuids, previousState) {
|
|
73
|
-
if (!previousState) {
|
|
74
|
-
// First run: all current messages are "new"
|
|
75
|
-
return Array.from(currentGuids);
|
|
76
|
-
}
|
|
77
|
-
// Use existing delta detection from incremental-state module
|
|
78
|
-
return detectNewMessages(currentGuids, previousState);
|
|
79
|
-
}
|
|
80
|
-
// ============================================================================
|
|
81
|
-
// AC05: Delta Summary Logging
|
|
82
|
-
// ============================================================================
|
|
83
|
-
/**
|
|
84
|
-
* AC05: Log human-readable delta summary
|
|
85
|
-
*
|
|
86
|
-
* Outputs lines like:
|
|
87
|
-
* - "Found 142 new messages to enrich"
|
|
88
|
-
* - "Previously enriched: 358"
|
|
89
|
-
* - "This is your first enrichment run"
|
|
90
|
-
* - "Delta: 28.3% of 500 total messages"
|
|
91
|
-
*
|
|
92
|
-
* @param result - DeltaResult to summarize
|
|
93
|
-
*/
|
|
94
|
-
export function logDeltaSummary(result) {
|
|
95
|
-
const logger = createLogger('utils:delta-detection');
|
|
96
|
-
const newCount = result.newCount;
|
|
97
|
-
const totalCount = result.totalMessages;
|
|
98
|
-
const previousCount = result.previousEnrichedCount;
|
|
99
|
-
// Log delta summary (AC05)
|
|
100
|
-
if (result.isFirstRun) {
|
|
101
|
-
// Structured log (machine consumption)
|
|
102
|
-
logger.info('First enrichment run', { totalMessages: totalCount });
|
|
103
|
-
// Human-friendly console output retained for tests & CLI UX
|
|
104
|
-
// Format expected by tests: contains both 'First enrichment run' and '<N> messages'
|
|
105
|
-
humanInfo(`First enrichment run: ${totalCount} messages`);
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
const percentNew = totalCount > 0 ? (newCount / totalCount) * 100 : 0;
|
|
109
|
-
// Structured log
|
|
110
|
-
logger.info('Delta detected', {
|
|
111
|
-
newMessages: newCount,
|
|
112
|
-
percentNew,
|
|
113
|
-
totalMessages: totalCount,
|
|
114
|
-
previouslyEnriched: previousCount,
|
|
115
|
-
});
|
|
116
|
-
// Human-readable lines expected by tests
|
|
117
|
-
// Includes phrases: 'Delta detected', '<X> new messages', '<Y.Y%>' and 'Previously enriched: <N>'
|
|
118
|
-
humanInfo(`Delta detected: ${newCount} new messages (${percentNew.toFixed(1)}%) of ${totalCount} total messages`);
|
|
119
|
-
humanInfo(`Previously enriched: ${previousCount}`);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
// ============================================================================
|
|
123
|
-
// AC01-AC05: Main entry point for delta detection
|
|
124
|
-
// ============================================================================
|
|
125
|
-
/**
|
|
126
|
-
* AC01-AC05: Perform complete delta detection
|
|
127
|
-
*
|
|
128
|
-
* Workflow:
|
|
129
|
-
* 1. AC04: Load previous state (null if missing)
|
|
130
|
-
* 2. AC02: Extract current message GUIDs
|
|
131
|
-
* 3. AC03: Compute delta (new GUIDs only)
|
|
132
|
-
* 4. AC05: Log summary
|
|
133
|
-
*
|
|
134
|
-
* Returns DeltaResult with:
|
|
135
|
-
* - newGuids to enrich
|
|
136
|
-
* - metadata for progress tracking
|
|
137
|
-
* - state to update after enrichment
|
|
138
|
-
*
|
|
139
|
-
* @param messages - Normalized messages from normalize-link stage
|
|
140
|
-
* @param stateFilePath - Path to .imessage-state.json
|
|
141
|
-
* @returns DeltaResult with new GUIDs and metadata
|
|
142
|
-
* @throws Error if state file can't be read (permission denied, etc.)
|
|
143
|
-
*/
|
|
144
|
-
export async function detectDelta(messages, stateFilePath) {
|
|
145
|
-
// AC01 + AC04: Load previous state (null if missing)
|
|
146
|
-
const previousState = await loadPreviousState(stateFilePath);
|
|
147
|
-
const isFirstRun = previousState === null;
|
|
148
|
-
// AC02 + AC03: Extract current GUIDs and compute delta
|
|
149
|
-
const currentGuids = extractGuidsFromMessages(messages);
|
|
150
|
-
const newGuids = computeDelta(currentGuids, previousState);
|
|
151
|
-
// Build result
|
|
152
|
-
const result = {
|
|
153
|
-
newGuids,
|
|
154
|
-
totalMessages: messages.length,
|
|
155
|
-
previousEnrichedCount: previousState?.enrichedGuids.length ?? 0,
|
|
156
|
-
newCount: newGuids.length,
|
|
157
|
-
isFirstRun,
|
|
158
|
-
state: previousState ?? {
|
|
159
|
-
version: '1.0',
|
|
160
|
-
lastEnrichedAt: new Date().toISOString(),
|
|
161
|
-
totalMessages: messages.length,
|
|
162
|
-
enrichedGuids: [],
|
|
163
|
-
pipelineConfig: {
|
|
164
|
-
configHash: '',
|
|
165
|
-
},
|
|
166
|
-
enrichmentStats: null,
|
|
167
|
-
},
|
|
168
|
-
};
|
|
169
|
-
// AC05: Log summary
|
|
170
|
-
logDeltaSummary(result);
|
|
171
|
-
return result;
|
|
172
|
-
}
|
|
173
|
-
// ============================================================================
|
|
174
|
-
// Utility: Get delta statistics for progress reporting
|
|
175
|
-
// ============================================================================
|
|
176
|
-
/**
|
|
177
|
-
* Calculate delta statistics for progress monitoring
|
|
178
|
-
*
|
|
179
|
-
* Useful for:
|
|
180
|
-
* - Progress bars (show percentage to enrich)
|
|
181
|
-
* - ETA calculation
|
|
182
|
-
* - Summary reports
|
|
183
|
-
*
|
|
184
|
-
* @param result - DeltaResult to analyze
|
|
185
|
-
* @returns Statistics object with counts and percentages
|
|
186
|
-
*/
|
|
187
|
-
export function getDeltaStats(result) {
|
|
188
|
-
const total = result.totalMessages;
|
|
189
|
-
const newCount = result.newCount;
|
|
190
|
-
const previousCount = result.previousEnrichedCount;
|
|
191
|
-
return {
|
|
192
|
-
total,
|
|
193
|
-
new: newCount,
|
|
194
|
-
previous: previousCount,
|
|
195
|
-
percentNew: total > 0 ? (newCount / total) * 100 : 0,
|
|
196
|
-
percentPrevious: total > 0 ? (previousCount / total) * 100 : 0,
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
//# sourceMappingURL=delta-detection.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"delta-detection.js","sourceRoot":"","sources":["../../src/utils/delta-detection.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Enrichment Merge Module (INCREMENTAL--T03)
|
|
3
|
-
*
|
|
4
|
-
* Implements merge strategy for incremental enrichment results into existing
|
|
5
|
-
* enriched JSON, preserving prior work and handling new enrichments.
|
|
6
|
-
*
|
|
7
|
-
* Implements:
|
|
8
|
-
* - AC01: Load existing enriched.json if exists
|
|
9
|
-
* - AC02: Merge new enrichments by GUID (new messages + updates)
|
|
10
|
-
* - AC03: Preserve existing enrichments (no overwrites unless --force-refresh)
|
|
11
|
-
* - AC04: Update statistics in state file
|
|
12
|
-
* - AC05: Backup previous enriched.json as enriched.json.backup
|
|
13
|
-
*
|
|
14
|
-
* Architecture:
|
|
15
|
-
* - MergeResult: Complete merge operation output
|
|
16
|
-
* - MergeOptions: Configuration for merge behavior
|
|
17
|
-
* - loadExistingEnriched: Load prior enriched.json safely
|
|
18
|
-
* - mergeEnrichments: Core merge logic with preservation
|
|
19
|
-
* - backupEnrichedJson: Atomic backup creation
|
|
20
|
-
* - updateMergeStatistics: Statistics calculation
|
|
21
|
-
*/
|
|
22
|
-
import type { ExportEnvelope, Message } from '#schema/message';
|
|
23
|
-
/**
|
|
24
|
-
* Options for merge behavior
|
|
25
|
-
*/
|
|
26
|
-
export type MergeOptions = {
|
|
27
|
-
/** Force refresh overwrites existing enrichments (default: false) */
|
|
28
|
-
forceRefresh?: boolean;
|
|
29
|
-
};
|
|
30
|
-
/**
|
|
31
|
-
* Statistics from merge operation
|
|
32
|
-
*/
|
|
33
|
-
export type MergeStatistics = {
|
|
34
|
-
/** Number of messages merged (existing GUIDs updated) */
|
|
35
|
-
mergedCount: number;
|
|
36
|
-
/** Number of messages added (new GUIDs) */
|
|
37
|
-
addedCount: number;
|
|
38
|
-
/** Number of messages with preserved enrichments */
|
|
39
|
-
preservedCount: number;
|
|
40
|
-
/** Total messages in result */
|
|
41
|
-
totalMessages: number;
|
|
42
|
-
/** Percentage of messages that were merged */
|
|
43
|
-
mergedPercentage?: number;
|
|
44
|
-
/** Percentage of messages that were added */
|
|
45
|
-
addedPercentage?: number;
|
|
46
|
-
};
|
|
47
|
-
/**
|
|
48
|
-
* Result of merge operation
|
|
49
|
-
*/
|
|
50
|
-
export type MergeResult = {
|
|
51
|
-
/** Merged messages with enrichments preserved/updated */
|
|
52
|
-
messages: Message[];
|
|
53
|
-
/** Statistics about the merge operation */
|
|
54
|
-
statistics: MergeStatistics;
|
|
55
|
-
/** Count of messages merged */
|
|
56
|
-
mergedCount: number;
|
|
57
|
-
/** Count of messages added */
|
|
58
|
-
addedCount: number;
|
|
59
|
-
/** Count of messages with preserved enrichments */
|
|
60
|
-
preservedCount: number;
|
|
61
|
-
};
|
|
62
|
-
/**
|
|
63
|
-
* AC01: Load existing enriched JSON safely
|
|
64
|
-
*
|
|
65
|
-
* Handles:
|
|
66
|
-
* - File doesn't exist (returns null)
|
|
67
|
-
* - JSON is corrupted (returns null)
|
|
68
|
-
* - Schema version mismatch (returns null or handles gracefully)
|
|
69
|
-
* - Preserves all enrichment data
|
|
70
|
-
*
|
|
71
|
-
* @param filePath - Path to existing enriched.json
|
|
72
|
-
* @returns ExportEnvelope if valid, null if missing or corrupted
|
|
73
|
-
*/
|
|
74
|
-
export declare function loadExistingEnriched(filePath: string): Promise<ExportEnvelope | null>;
|
|
75
|
-
/**
|
|
76
|
-
* AC02 + AC03: Merge new enrichments with existing messages
|
|
77
|
-
*
|
|
78
|
-
* Strategy:
|
|
79
|
-
* 1. Build index of existing messages by GUID
|
|
80
|
-
* 2. For each new message:
|
|
81
|
-
* - If GUID exists: merge enrichments (preserve existing unless --force-refresh)
|
|
82
|
-
* - If GUID is new: add message
|
|
83
|
-
* 3. Preserve enrichment order and structure
|
|
84
|
-
*
|
|
85
|
-
* @param existingMessages - Messages from prior enriched.json
|
|
86
|
-
* @param newMessages - New/updated messages from enrichment
|
|
87
|
-
* @param options - Merge options (forceRefresh, etc.)
|
|
88
|
-
* @returns MergeResult with merged messages and statistics
|
|
89
|
-
*/
|
|
90
|
-
export declare function mergeEnrichments(existingMessages: Message[], newMessages: Message[], options?: MergeOptions): MergeResult;
|
|
91
|
-
/**
|
|
92
|
-
* AC04: Calculate and update merge statistics
|
|
93
|
-
*
|
|
94
|
-
* Computes merge percentages and summary information
|
|
95
|
-
*
|
|
96
|
-
* @param stats - Raw statistics
|
|
97
|
-
* @returns Updated statistics with percentages
|
|
98
|
-
*/
|
|
99
|
-
export declare function updateMergeStatistics(stats: MergeStatistics): MergeStatistics;
|
|
100
|
-
/**
|
|
101
|
-
* AC05: Create atomic backup of existing enriched.json
|
|
102
|
-
*
|
|
103
|
-
* Pattern:
|
|
104
|
-
* 1. Read existing file
|
|
105
|
-
* 2. Write to enriched.json.backup (overwrite if exists)
|
|
106
|
-
* 3. Ensures no data loss on merge
|
|
107
|
-
*
|
|
108
|
-
* @param filePath - Path to enriched.json to backup
|
|
109
|
-
* @throws Error if source file can't be read
|
|
110
|
-
*/
|
|
111
|
-
export declare function backupEnrichedJson(filePath: string): Promise<void>;
|
|
112
|
-
/**
|
|
113
|
-
* Create a new MergeResult with given parameters
|
|
114
|
-
*
|
|
115
|
-
* @param messages - Merged messages
|
|
116
|
-
* @param options - Statistics options
|
|
117
|
-
* @returns Complete MergeResult
|
|
118
|
-
*/
|
|
119
|
-
export declare function createEnrichmentMergeResult(messages: Message[], options: {
|
|
120
|
-
mergedCount: number;
|
|
121
|
-
addedCount: number;
|
|
122
|
-
preservedCount: number;
|
|
123
|
-
}): MergeResult;
|
|
124
|
-
/**
|
|
125
|
-
* AC05: Log human-readable merge summary
|
|
126
|
-
*
|
|
127
|
-
* Outputs lines like:
|
|
128
|
-
* - "Merged 50 existing messages with new enrichments"
|
|
129
|
-
* - "Added 10 new messages to enriched.json"
|
|
130
|
-
* - "Preserved 60 enrichments from prior run"
|
|
131
|
-
*
|
|
132
|
-
* @param result - MergeResult to summarize
|
|
133
|
-
*/
|
|
134
|
-
export declare function logMergeSummary(result: MergeResult): void;
|
|
135
|
-
//# sourceMappingURL=enrichment-merge.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"enrichment-merge.d.ts","sourceRoot":"","sources":["../../src/utils/enrichment-merge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAU9D;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IAC1B,qEAAqE;IACrE,YAAY,CAAC,EAAE,OAAO,CAAA;CACtB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC7B,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAA;IAEnB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAA;IAElB,oDAAoD;IACpD,cAAc,EAAE,MAAM,CAAA;IAEtB,+BAA+B;IAC/B,aAAa,EAAE,MAAM,CAAA;IAErB,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAEzB,6CAA6C;IAC7C,eAAe,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG;IACzB,yDAAyD;IACzD,QAAQ,EAAE,OAAO,EAAE,CAAA;IAEnB,2CAA2C;IAC3C,UAAU,EAAE,eAAe,CAAA;IAE3B,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAA;IAEnB,8BAA8B;IAC9B,UAAU,EAAE,MAAM,CAAA;IAElB,mDAAmD;IACnD,cAAc,EAAE,MAAM,CAAA;CACtB,CAAA;AAMD;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,CACzC,QAAQ,EAAE,MAAM,GACd,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAmBhC;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAC/B,gBAAgB,EAAE,OAAO,EAAE,EAC3B,WAAW,EAAE,OAAO,EAAE,EACtB,OAAO,GAAE,YAAiB,GACxB,WAAW,CAoEb;AAqED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,eAAe,GAAG,eAAe,CAQ7E;AAMD;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIxE;AAMD;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAC1C,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE;IACR,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,MAAM,CAAA;CACtB,GACC,WAAW,CAiBb;AAMD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAqBzD"}
|
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Enrichment Merge Module (INCREMENTAL--T03)
|
|
3
|
-
*
|
|
4
|
-
* Implements merge strategy for incremental enrichment results into existing
|
|
5
|
-
* enriched JSON, preserving prior work and handling new enrichments.
|
|
6
|
-
*
|
|
7
|
-
* Implements:
|
|
8
|
-
* - AC01: Load existing enriched.json if exists
|
|
9
|
-
* - AC02: Merge new enrichments by GUID (new messages + updates)
|
|
10
|
-
* - AC03: Preserve existing enrichments (no overwrites unless --force-refresh)
|
|
11
|
-
* - AC04: Update statistics in state file
|
|
12
|
-
* - AC05: Backup previous enriched.json as enriched.json.backup
|
|
13
|
-
*
|
|
14
|
-
* Architecture:
|
|
15
|
-
* - MergeResult: Complete merge operation output
|
|
16
|
-
* - MergeOptions: Configuration for merge behavior
|
|
17
|
-
* - loadExistingEnriched: Load prior enriched.json safely
|
|
18
|
-
* - mergeEnrichments: Core merge logic with preservation
|
|
19
|
-
* - backupEnrichedJson: Atomic backup creation
|
|
20
|
-
* - updateMergeStatistics: Statistics calculation
|
|
21
|
-
*/
|
|
22
|
-
import { promises as fs } from 'node:fs';
|
|
23
|
-
import { createLogger } from '#utils/logger';
|
|
24
|
-
// ============================================================================
|
|
25
|
-
// AC01: Load existing enriched.json
|
|
26
|
-
// ============================================================================
|
|
27
|
-
/**
|
|
28
|
-
* AC01: Load existing enriched JSON safely
|
|
29
|
-
*
|
|
30
|
-
* Handles:
|
|
31
|
-
* - File doesn't exist (returns null)
|
|
32
|
-
* - JSON is corrupted (returns null)
|
|
33
|
-
* - Schema version mismatch (returns null or handles gracefully)
|
|
34
|
-
* - Preserves all enrichment data
|
|
35
|
-
*
|
|
36
|
-
* @param filePath - Path to existing enriched.json
|
|
37
|
-
* @returns ExportEnvelope if valid, null if missing or corrupted
|
|
38
|
-
*/
|
|
39
|
-
export async function loadExistingEnriched(filePath) {
|
|
40
|
-
try {
|
|
41
|
-
const content = await fs.readFile(filePath, 'utf-8');
|
|
42
|
-
const parsed = JSON.parse(content);
|
|
43
|
-
// Validate basic structure
|
|
44
|
-
if (!parsed.messages || !Array.isArray(parsed.messages)) {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
return parsed;
|
|
48
|
-
}
|
|
49
|
-
catch (error) {
|
|
50
|
-
// File doesn't exist or is corrupted
|
|
51
|
-
if (error instanceof Error && error.message.includes('ENOENT')) {
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
// JSON parse error or other read error
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
// ============================================================================
|
|
59
|
-
// AC02 + AC03: Merge enrichments by GUID
|
|
60
|
-
// ============================================================================
|
|
61
|
-
/**
|
|
62
|
-
* AC02 + AC03: Merge new enrichments with existing messages
|
|
63
|
-
*
|
|
64
|
-
* Strategy:
|
|
65
|
-
* 1. Build index of existing messages by GUID
|
|
66
|
-
* 2. For each new message:
|
|
67
|
-
* - If GUID exists: merge enrichments (preserve existing unless --force-refresh)
|
|
68
|
-
* - If GUID is new: add message
|
|
69
|
-
* 3. Preserve enrichment order and structure
|
|
70
|
-
*
|
|
71
|
-
* @param existingMessages - Messages from prior enriched.json
|
|
72
|
-
* @param newMessages - New/updated messages from enrichment
|
|
73
|
-
* @param options - Merge options (forceRefresh, etc.)
|
|
74
|
-
* @returns MergeResult with merged messages and statistics
|
|
75
|
-
*/
|
|
76
|
-
export function mergeEnrichments(existingMessages, newMessages, options = {}) {
|
|
77
|
-
// Build index of existing messages by GUID
|
|
78
|
-
const existingByGuid = new Map();
|
|
79
|
-
for (const msg of existingMessages) {
|
|
80
|
-
existingByGuid.set(msg.guid, msg);
|
|
81
|
-
}
|
|
82
|
-
// Track merge statistics
|
|
83
|
-
let mergedCount = 0;
|
|
84
|
-
let addedCount = 0;
|
|
85
|
-
let preservedCount = 0;
|
|
86
|
-
// Track GUIDs we've processed to avoid duplicates
|
|
87
|
-
const processedGuids = new Set();
|
|
88
|
-
// Result messages with merged enrichments
|
|
89
|
-
const resultMessages = [];
|
|
90
|
-
// Process new messages
|
|
91
|
-
for (const newMsg of newMessages) {
|
|
92
|
-
const existing = existingByGuid.get(newMsg.guid);
|
|
93
|
-
if (existing) {
|
|
94
|
-
// Message exists: merge enrichments
|
|
95
|
-
if (!processedGuids.has(newMsg.guid)) {
|
|
96
|
-
const merged = mergeMessageEnrichments(existing, newMsg, options);
|
|
97
|
-
resultMessages.push(merged);
|
|
98
|
-
mergedCount++;
|
|
99
|
-
// Count preserved enrichments
|
|
100
|
-
if (merged.messageKind === 'media' &&
|
|
101
|
-
merged.media?.enrichment &&
|
|
102
|
-
merged.media.enrichment.length > 0) {
|
|
103
|
-
preservedCount++;
|
|
104
|
-
}
|
|
105
|
-
processedGuids.add(newMsg.guid);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
// New message: add to result
|
|
110
|
-
if (!processedGuids.has(newMsg.guid)) {
|
|
111
|
-
resultMessages.push(newMsg);
|
|
112
|
-
addedCount++;
|
|
113
|
-
processedGuids.add(newMsg.guid);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
const totalMessages = resultMessages.length;
|
|
118
|
-
return {
|
|
119
|
-
messages: resultMessages,
|
|
120
|
-
statistics: {
|
|
121
|
-
mergedCount,
|
|
122
|
-
addedCount,
|
|
123
|
-
preservedCount,
|
|
124
|
-
totalMessages,
|
|
125
|
-
mergedPercentage: totalMessages > 0 ? (mergedCount / totalMessages) * 100 : 0,
|
|
126
|
-
addedPercentage: totalMessages > 0 ? (addedCount / totalMessages) * 100 : 0,
|
|
127
|
-
},
|
|
128
|
-
mergedCount,
|
|
129
|
-
addedCount,
|
|
130
|
-
preservedCount,
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* AC02 + AC03: Merge enrichments for a single message
|
|
135
|
-
*
|
|
136
|
-
* Preservation logic:
|
|
137
|
-
* - If forceRefresh: use new enrichments
|
|
138
|
-
* - Otherwise:
|
|
139
|
-
* - Preserve existing enrichments by kind
|
|
140
|
-
* - Append new enrichments for different kinds
|
|
141
|
-
* - Skip enrichments for kinds that already exist (unless force)
|
|
142
|
-
*
|
|
143
|
-
* @param existing - Existing message with enrichments
|
|
144
|
-
* @param newMsg - New message with enrichments
|
|
145
|
-
* @param options - Merge options
|
|
146
|
-
* @returns Merged message with preserved enrichments
|
|
147
|
-
*/
|
|
148
|
-
function mergeMessageEnrichments(existing, newMsg, options) {
|
|
149
|
-
// If not media message, just return existing (no enrichment to merge)
|
|
150
|
-
if (existing.messageKind !== 'media' || !existing.media) {
|
|
151
|
-
return existing;
|
|
152
|
-
}
|
|
153
|
-
// If no new enrichments, keep existing as-is
|
|
154
|
-
if (!newMsg.media?.enrichment || newMsg.media.enrichment.length === 0) {
|
|
155
|
-
return existing;
|
|
156
|
-
}
|
|
157
|
-
// If forceRefresh, use all new enrichments
|
|
158
|
-
if (options.forceRefresh) {
|
|
159
|
-
return {
|
|
160
|
-
...existing,
|
|
161
|
-
media: {
|
|
162
|
-
...existing.media,
|
|
163
|
-
enrichment: newMsg.media.enrichment,
|
|
164
|
-
},
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
// Otherwise: preserve existing, append new for different kinds
|
|
168
|
-
const existingEnrichment = existing.media.enrichment ?? [];
|
|
169
|
-
const newEnrichment = newMsg.media.enrichment ?? [];
|
|
170
|
-
// Build set of existing enrichment kinds
|
|
171
|
-
const existingKinds = new Set(existingEnrichment.map((e) => e.kind));
|
|
172
|
-
// Only add new enrichments for kinds not already present
|
|
173
|
-
const mergedEnrichment = [
|
|
174
|
-
...existingEnrichment,
|
|
175
|
-
...newEnrichment.filter((e) => !existingKinds.has(e.kind)),
|
|
176
|
-
];
|
|
177
|
-
return {
|
|
178
|
-
...existing,
|
|
179
|
-
media: {
|
|
180
|
-
...existing.media,
|
|
181
|
-
enrichment: mergedEnrichment,
|
|
182
|
-
},
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
// ============================================================================
|
|
186
|
-
// AC04: Update merge statistics
|
|
187
|
-
// ============================================================================
|
|
188
|
-
/**
|
|
189
|
-
* AC04: Calculate and update merge statistics
|
|
190
|
-
*
|
|
191
|
-
* Computes merge percentages and summary information
|
|
192
|
-
*
|
|
193
|
-
* @param stats - Raw statistics
|
|
194
|
-
* @returns Updated statistics with percentages
|
|
195
|
-
*/
|
|
196
|
-
export function updateMergeStatistics(stats) {
|
|
197
|
-
const total = stats.totalMessages;
|
|
198
|
-
return {
|
|
199
|
-
...stats,
|
|
200
|
-
mergedPercentage: total > 0 ? (stats.mergedCount / total) * 100 : 0,
|
|
201
|
-
addedPercentage: total > 0 ? (stats.addedCount / total) * 100 : 0,
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
// ============================================================================
|
|
205
|
-
// AC05: Backup existing enriched.json
|
|
206
|
-
// ============================================================================
|
|
207
|
-
/**
|
|
208
|
-
* AC05: Create atomic backup of existing enriched.json
|
|
209
|
-
*
|
|
210
|
-
* Pattern:
|
|
211
|
-
* 1. Read existing file
|
|
212
|
-
* 2. Write to enriched.json.backup (overwrite if exists)
|
|
213
|
-
* 3. Ensures no data loss on merge
|
|
214
|
-
*
|
|
215
|
-
* @param filePath - Path to enriched.json to backup
|
|
216
|
-
* @throws Error if source file can't be read
|
|
217
|
-
*/
|
|
218
|
-
export async function backupEnrichedJson(filePath) {
|
|
219
|
-
const backupPath = `${filePath}.backup`;
|
|
220
|
-
const content = await fs.readFile(filePath, 'utf-8');
|
|
221
|
-
await fs.writeFile(backupPath, content, 'utf-8');
|
|
222
|
-
}
|
|
223
|
-
// ============================================================================
|
|
224
|
-
// Helper: Create enrichment merge result
|
|
225
|
-
// ============================================================================
|
|
226
|
-
/**
|
|
227
|
-
* Create a new MergeResult with given parameters
|
|
228
|
-
*
|
|
229
|
-
* @param messages - Merged messages
|
|
230
|
-
* @param options - Statistics options
|
|
231
|
-
* @returns Complete MergeResult
|
|
232
|
-
*/
|
|
233
|
-
export function createEnrichmentMergeResult(messages, options) {
|
|
234
|
-
return {
|
|
235
|
-
messages,
|
|
236
|
-
statistics: {
|
|
237
|
-
mergedCount: options.mergedCount,
|
|
238
|
-
addedCount: options.addedCount,
|
|
239
|
-
preservedCount: options.preservedCount,
|
|
240
|
-
totalMessages: messages.length,
|
|
241
|
-
mergedPercentage: messages.length > 0 ? (options.mergedCount / messages.length) * 100 : 0,
|
|
242
|
-
addedPercentage: messages.length > 0 ? (options.addedCount / messages.length) * 100 : 0,
|
|
243
|
-
},
|
|
244
|
-
mergedCount: options.mergedCount,
|
|
245
|
-
addedCount: options.addedCount,
|
|
246
|
-
preservedCount: options.preservedCount,
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
// ============================================================================
|
|
250
|
-
// Helper: Log merge summary
|
|
251
|
-
// ============================================================================
|
|
252
|
-
/**
|
|
253
|
-
* AC05: Log human-readable merge summary
|
|
254
|
-
*
|
|
255
|
-
* Outputs lines like:
|
|
256
|
-
* - "Merged 50 existing messages with new enrichments"
|
|
257
|
-
* - "Added 10 new messages to enriched.json"
|
|
258
|
-
* - "Preserved 60 enrichments from prior run"
|
|
259
|
-
*
|
|
260
|
-
* @param result - MergeResult to summarize
|
|
261
|
-
*/
|
|
262
|
-
export function logMergeSummary(result) {
|
|
263
|
-
const { mergedCount, addedCount, preservedCount } = result;
|
|
264
|
-
const logger = createLogger('utils:enrichment-merge');
|
|
265
|
-
if (mergedCount > 0) {
|
|
266
|
-
logger.info('Merged existing messages with new enrichments', {
|
|
267
|
-
mergedCount,
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
if (addedCount > 0) {
|
|
271
|
-
logger.info('Added new messages to enriched.json', { addedCount });
|
|
272
|
-
}
|
|
273
|
-
if (preservedCount > 0) {
|
|
274
|
-
logger.info('Preserved enrichments from prior run', { preservedCount });
|
|
275
|
-
}
|
|
276
|
-
if (mergedCount === 0 && addedCount === 0) {
|
|
277
|
-
logger.info('No new enrichments to merge');
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
//# sourceMappingURL=enrichment-merge.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"enrichment-merge.js","sourceRoot":"","sources":["../../src/utils/enrichment-merge.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/human.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Human Output Helper
|
|
3
|
-
*
|
|
4
|
-
* Centralizes human-facing console output so we can globally toggle it
|
|
5
|
-
* (e.g. suppressed when --json or LOG_FORMAT=json-only is active).
|
|
6
|
-
* Tests that spy on console.* remain compatible.
|
|
7
|
-
*/
|
|
8
|
-
export type HumanLoggerOptions = {
|
|
9
|
-
enabled?: boolean;
|
|
10
|
-
};
|
|
11
|
-
export declare function setHumanLoggingEnabled(enabled: boolean): void;
|
|
12
|
-
export declare function humanInfo(...args: Array<unknown>): void;
|
|
13
|
-
export declare function humanWarn(...args: Array<unknown>): void;
|
|
14
|
-
export declare function humanError(...args: Array<unknown>): void;
|
|
15
|
-
//# sourceMappingURL=human.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"human.d.ts","sourceRoot":"","sources":["../../src/utils/human.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,kBAAkB,GAAG;IAChC,OAAO,CAAC,EAAE,OAAO,CAAA;CACjB,CAAA;AAID,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE7D;AAeD,wBAAgB,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI,CAEvD;AAED,wBAAgB,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI,CAEvD;AAED,wBAAgB,UAAU,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI,CAExD"}
|