claude-memory-layer 1.0.45 → 1.0.46
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/README.md +1 -0
- package/dist/cli/index.js +55 -8
- package/dist/cli/index.js.map +2 -2
- package/dist/core/index.js +137 -20
- package/dist/core/index.js.map +2 -2
- package/dist/hooks/post-tool-use.js +54 -7
- package/dist/hooks/post-tool-use.js.map +2 -2
- package/dist/hooks/semantic-daemon.js +54 -7
- package/dist/hooks/semantic-daemon.js.map +2 -2
- package/dist/hooks/session-end.js +54 -7
- package/dist/hooks/session-end.js.map +2 -2
- package/dist/hooks/session-start.js +54 -7
- package/dist/hooks/session-start.js.map +2 -2
- package/dist/hooks/stop.js +54 -7
- package/dist/hooks/stop.js.map +2 -2
- package/dist/hooks/user-prompt-submit.js +54 -7
- package/dist/hooks/user-prompt-submit.js.map +2 -2
- package/dist/index.js +137 -20
- package/dist/index.js.map +2 -2
- package/dist/mcp/index.js +163 -37
- package/dist/mcp/index.js.map +2 -2
- package/dist/server/api/index.js +54 -7
- package/dist/server/api/index.js.map +2 -2
- package/dist/server/index.js +54 -7
- package/dist/server/index.js.map +2 -2
- package/dist/services/memory-service.js +54 -7
- package/dist/services/memory-service.js.map +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10662,6 +10662,18 @@ var COMMAND_ARTIFACT_PATTERNS = [
|
|
|
10662
10662
|
/<local-command-stdout>[\s\S]*?<\/local-command-stdout>/i,
|
|
10663
10663
|
/<local-command-stderr>[\s\S]*?<\/local-command-stderr>/i
|
|
10664
10664
|
];
|
|
10665
|
+
var LOW_SIGNAL_CONTEXT_PATTERNS = [
|
|
10666
|
+
/<environment_context\b[\s\S]*<\/environment_context>/i,
|
|
10667
|
+
/<turn_aborted>/i,
|
|
10668
|
+
/^#\s*AGENTS\.md\s+instructions\b[\s\S]*<INSTRUCTIONS>/i,
|
|
10669
|
+
/^\s*(?:understood[,\s.]*)?(?:stopping|stopped|pausing|paused)\s+here\b[\s\S]{0,180}\blet\s+me\s+know\s+when\s+you(?:'d|\s+would)?\s+like\s+to\s+continue\b/i,
|
|
10670
|
+
/^\s*\[?CONTEXT\s+COMPACTION\s*[—-]\s*REFERENCE\s+ONLY\]?\b[\s\S]{0,600}\b(?:earlier\s+turns\s+were\s+compacted|handoff\s+from\s+a\s+previous\s+context\s+window|active\s+task)\b/i,
|
|
10671
|
+
/^\s*Summary\s+generation\s+was\s+unavailable\.\s*\d+\s+message\(s\)\s+were\s+removed\s+to\s+free\s+context\s+space\b/i,
|
|
10672
|
+
/^\s*---\s*END\s+OF\s+CONTEXT\s+SUMMARY\b/i,
|
|
10673
|
+
/^\s*\[Your\s+active\s+task\s+list\s+was\s+preserved\s+across\s+context\s+compression\]/i,
|
|
10674
|
+
/^➜\s+\S+\s+git:\([^)]*\)\s+/i,
|
|
10675
|
+
/^\$\s+\S+/i
|
|
10676
|
+
];
|
|
10665
10677
|
var CONTINUATION_QUERY_PATTERNS = [
|
|
10666
10678
|
/^\s*(?:continue|resume|next|what(?:'s| is)? next|next\s+(?:step|task|action)|recommended\s+(?:next\s+)?(?:step|task|action)|what should (?:we|i) do next)\??\s*$/i,
|
|
10667
10679
|
/^\s*(?:응\s*)?(?:이어서(?:\s*진행(?:해줘)?)?|계속(?:\s*해줘)?|다음\s*(?:단계|작업|추천\s*작업|추천|할\s*일)?(?:은|는)?(?:\s*(?:뭐야|진행(?:해줘)?))?\??|남은\s*(?:추가(?:로)?\s*)?(?:(?:할\s*만한\s*)?(?:작업|일)|할\s*일)?(?:은|는)?\s*(?:있어|있나|있나요|뭐야)\??|추천\s*작업(?:은|는)?(?:\s*뭐야)?\??|진행해줘)\s*$/i
|
|
@@ -10673,7 +10685,7 @@ var SHORT_REPAIR_FOLLOW_UP_PATTERNS = [
|
|
|
10673
10685
|
var CURRENT_STATE_QUERY_PATTERNS = [
|
|
10674
10686
|
/\bcurrent\b.*\b(?:state|status|deployment|blocker|pr|pull request)\b/i,
|
|
10675
10687
|
/\b(?:still|as current|current)\b.*\b(?:unresolved|open|pending|not completed)\b/i,
|
|
10676
|
-
/\b(?:old|obsolete|stale|resolved|already resolved)\b.*\b(?:current|still|unresolved|open|
|
|
10688
|
+
/\b(?:old|obsolete|stale|resolved|already resolved)\b.*\b(?:current|still|unresolved|open|status)\b/i,
|
|
10677
10689
|
/(?:현재|아직|이전|오래된|해결된).*(?:상태|미해결|열린|블로커|PR|풀리퀘스트)/i
|
|
10678
10690
|
];
|
|
10679
10691
|
var STALE_CONTENT_PATTERNS = [
|
|
@@ -10819,6 +10831,21 @@ function isCommandArtifactQuery(query) {
|
|
|
10819
10831
|
if (normalized.includes("command-name") || normalized.includes("command-message")) return true;
|
|
10820
10832
|
return COMMAND_ARTIFACT_PATTERNS.some((pattern) => pattern.test(trimmed));
|
|
10821
10833
|
}
|
|
10834
|
+
function isCommandArtifactContent(content) {
|
|
10835
|
+
const trimmed = content.trim();
|
|
10836
|
+
if (!trimmed) return false;
|
|
10837
|
+
const normalized = trimmed.toLowerCase();
|
|
10838
|
+
if (normalized.includes("local-command-stdout") || normalized.includes("local-command-stderr")) return true;
|
|
10839
|
+
if (normalized.includes("command-name") || normalized.includes("command-message")) return true;
|
|
10840
|
+
return COMMAND_ARTIFACT_PATTERNS.some((pattern) => pattern.test(trimmed));
|
|
10841
|
+
}
|
|
10842
|
+
function isLowSignalContextContent(content) {
|
|
10843
|
+
const trimmed = content.trim();
|
|
10844
|
+
if (!trimmed) return true;
|
|
10845
|
+
if (isCommandArtifactContent(trimmed)) return true;
|
|
10846
|
+
if (LOW_SIGNAL_CONTEXT_PATTERNS.some((pattern) => pattern.test(trimmed))) return true;
|
|
10847
|
+
return false;
|
|
10848
|
+
}
|
|
10822
10849
|
function isGenericContinuationQuery(query) {
|
|
10823
10850
|
const trimmed = query.trim();
|
|
10824
10851
|
if (!trimmed) return false;
|
|
@@ -10836,6 +10863,16 @@ function isShortRepairFollowUpQuery(query) {
|
|
|
10836
10863
|
if (tokens.length > 8) return false;
|
|
10837
10864
|
return SHORT_REPAIR_FOLLOW_UP_PATTERNS.some((pattern) => pattern.test(trimmed));
|
|
10838
10865
|
}
|
|
10866
|
+
function isLowConfidenceContextFallbackQuery(query) {
|
|
10867
|
+
const trimmed = query.trim();
|
|
10868
|
+
if (!trimmed) return false;
|
|
10869
|
+
if (isGenericContinuationQuery(trimmed) || isShortRepairFollowUpQuery(trimmed)) return true;
|
|
10870
|
+
const terms = new Set(tokenizeQualityText(trimmed));
|
|
10871
|
+
if ((terms.has("compacted") || terms.has("compaction")) && terms.has("handoff")) return false;
|
|
10872
|
+
const hasContinuationRecall = /^(?:continue|resume)\b/i.test(trimmed) && (terms.has("work") || terms.has("step") || terms.has("task") || terms.has("last") || terms.has("completed"));
|
|
10873
|
+
const hasValidationGateRecall = terms.has("validation") && (terms.has("gate") || terms.has("check")) && (terms.has("run") || terms.has("before") || terms.has("commit") || terms.has("committing") || terms.has("change"));
|
|
10874
|
+
return hasContinuationRecall || hasValidationGateRecall;
|
|
10875
|
+
}
|
|
10839
10876
|
function isCurrentStateQuery(query) {
|
|
10840
10877
|
const trimmed = query.trim();
|
|
10841
10878
|
if (!trimmed) return false;
|
|
@@ -11103,7 +11140,14 @@ var Retriever = class {
|
|
|
11103
11140
|
};
|
|
11104
11141
|
fallbackTrace.push("fallback:summary");
|
|
11105
11142
|
}
|
|
11106
|
-
const
|
|
11143
|
+
const selectedResults = current.results.slice(0, opts.topK).filter((result2) => {
|
|
11144
|
+
if (current.matchResult.confidence !== "none") return true;
|
|
11145
|
+
if (isLowConfidenceContextFallbackQuery(query)) {
|
|
11146
|
+
return (result2.semanticScore ?? result2.score) >= 0.5 || result2.score >= 0.5;
|
|
11147
|
+
}
|
|
11148
|
+
return (result2.semanticScore ?? result2.score) >= 0.62 || result2.score >= 0.62;
|
|
11149
|
+
});
|
|
11150
|
+
const memories = await this.enrichResults(selectedResults, opts, query);
|
|
11107
11151
|
const context = this.buildContext(memories, opts.maxTokens);
|
|
11108
11152
|
return {
|
|
11109
11153
|
memories,
|
|
@@ -11111,7 +11155,7 @@ var Retriever = class {
|
|
|
11111
11155
|
totalTokens: this.estimateTokens(context),
|
|
11112
11156
|
context,
|
|
11113
11157
|
fallbackTrace,
|
|
11114
|
-
selectedDebug:
|
|
11158
|
+
selectedDebug: selectedResults.map((r) => this.debugDetailForResult(r)),
|
|
11115
11159
|
candidateDebug: (current.candidateResults || []).slice(0, Math.max(opts.topK * 3, 20)).map((r) => this.debugDetailForResult(r)),
|
|
11116
11160
|
rawQueryText: current.queryRewriteKind ? query : void 0,
|
|
11117
11161
|
effectiveQueryText: current.effectiveQueryText,
|
|
@@ -11206,6 +11250,7 @@ var Retriever = class {
|
|
|
11206
11250
|
if (isCurrentStateQuery(options.query)) {
|
|
11207
11251
|
filtered = filtered.filter((result2) => !isStaleOrSupersededContent(result2.content));
|
|
11208
11252
|
}
|
|
11253
|
+
filtered = filtered.filter((result2) => !isLowSignalContextContent(result2.content));
|
|
11209
11254
|
filtered = filtered.filter(
|
|
11210
11255
|
(result2) => this.isGraphPathResult(result2) || hasDiscriminativeTermOverlap(options.query, result2.content)
|
|
11211
11256
|
);
|
|
@@ -11546,7 +11591,7 @@ var Retriever = class {
|
|
|
11546
11591
|
async retrieveRecent(limit = 100) {
|
|
11547
11592
|
return this.eventStore.getRecentEvents(limit);
|
|
11548
11593
|
}
|
|
11549
|
-
async enrichResults(results, options) {
|
|
11594
|
+
async enrichResults(results, options, query) {
|
|
11550
11595
|
const memories = [];
|
|
11551
11596
|
for (const result2 of results) {
|
|
11552
11597
|
const event = await this.eventStore.getEvent(result2.eventId);
|
|
@@ -11556,13 +11601,13 @@ var Retriever = class {
|
|
|
11556
11601
|
}
|
|
11557
11602
|
let sessionContext;
|
|
11558
11603
|
if (options.includeSessionContext) {
|
|
11559
|
-
sessionContext = await this.getSessionContext(event.sessionId, event.id);
|
|
11604
|
+
sessionContext = await this.getSessionContext(event.sessionId, event.id, query);
|
|
11560
11605
|
}
|
|
11561
11606
|
memories.push({ event, score: result2.score, sessionContext });
|
|
11562
11607
|
}
|
|
11563
11608
|
return memories;
|
|
11564
11609
|
}
|
|
11565
|
-
async getSessionContext(sessionId, eventId) {
|
|
11610
|
+
async getSessionContext(sessionId, eventId, query) {
|
|
11566
11611
|
const sessionEvents = await this.eventStore.getSessionEvents(sessionId);
|
|
11567
11612
|
const eventIndex = sessionEvents.findIndex((e) => e.id === eventId);
|
|
11568
11613
|
if (eventIndex === -1) return void 0;
|
|
@@ -11570,7 +11615,9 @@ var Retriever = class {
|
|
|
11570
11615
|
const end = Math.min(sessionEvents.length, eventIndex + 2);
|
|
11571
11616
|
const contextEvents = sessionEvents.slice(start, end);
|
|
11572
11617
|
if (contextEvents.length <= 1) return void 0;
|
|
11573
|
-
|
|
11618
|
+
const suppressStaleState = isCurrentStateQuery(query);
|
|
11619
|
+
const contextLines = contextEvents.filter((e) => e.id !== eventId).filter((e) => !isLowSignalContextContent(e.content)).filter((e) => !(suppressStaleState && isStaleOrSupersededContent(e.content))).map((e) => `[${e.eventType}]: ${e.content.slice(0, 200)}...`);
|
|
11620
|
+
return contextLines.length > 0 ? contextLines.join("\n") : void 0;
|
|
11574
11621
|
}
|
|
11575
11622
|
buildUnifiedContext(projectResult, sharedMemories) {
|
|
11576
11623
|
let context = projectResult.context;
|
|
@@ -17118,12 +17165,13 @@ var productValidationMatrix = [
|
|
|
17118
17165
|
requirements: [
|
|
17119
17166
|
"Expose an agent-ready project context pack that combines relevant retrieval results with recent project timeline.",
|
|
17120
17167
|
"Support projectPath scoping so Hermes, Codex, and Claude Code can share the same project memory backend.",
|
|
17121
|
-
"Keep output compact and citation-oriented so agents can follow up with source-ref or timeline tools."
|
|
17168
|
+
"Keep output compact and citation-oriented so agents can follow up with source-ref or timeline tools.",
|
|
17169
|
+
"Document MCP-only context-pack budget controls (`maxChars`, approximate `maxTokens`, and `compression: off|safe|aggressive`) and make the CLI/API parity boundary explicit."
|
|
17122
17170
|
],
|
|
17123
17171
|
evidence: [
|
|
17124
|
-
{ kind: "test", ref: "tests/extensions/mcp-context-tools.test.ts", note: "Asserts context-pack output, projectPath routing, compact relevant memory citations, and recent timeline inclusion." },
|
|
17125
|
-
{ kind: "source", ref: "src/extensions/mcp/handlers.ts", note: "mem-context-pack handler formats relevant memories plus session summaries." },
|
|
17126
|
-
{ kind: "source", ref: "src/extensions/mcp/tools.ts", note: "MCP tool schema advertises projectPath, topK, recentLimit, and
|
|
17172
|
+
{ kind: "test", ref: "tests/extensions/mcp-context-tools.test.ts", note: "Asserts context-pack output, projectPath routing, compact relevant memory citations, sourceRef preservation, maxChars/maxTokens budget enforcement, compression modes, and recent timeline inclusion." },
|
|
17173
|
+
{ kind: "source", ref: "src/extensions/mcp/handlers.ts", note: "mem-context-pack handler formats relevant memories plus session summaries and validates MCP-only budget/compression arguments before storage access." },
|
|
17174
|
+
{ kind: "source", ref: "src/extensions/mcp/tools.ts", note: "MCP tool schema advertises projectPath, topK, recentLimit, sessionLimit, maxChars, maxTokens, and compression options; CLI/API parity is documented as MCP-only for context-pack generation." }
|
|
17127
17175
|
]
|
|
17128
17176
|
},
|
|
17129
17177
|
{
|
|
@@ -17696,10 +17744,11 @@ var ContextCompressor = class {
|
|
|
17696
17744
|
compress(content, options) {
|
|
17697
17745
|
const source = safeLabel(options.source) || "unknown";
|
|
17698
17746
|
const mode = options.mode;
|
|
17747
|
+
const sourceRef = safeSourceRef(options.sourceRef ?? sourceRefFromMetadata(options.metadata ?? {}));
|
|
17699
17748
|
const contentType = detectContextContentType(content, options.metadata ?? {});
|
|
17700
17749
|
const originalLines = nonEmptyLines(content).length;
|
|
17701
17750
|
if (mode === "off") {
|
|
17702
|
-
return result(content, {
|
|
17751
|
+
return withSourceRefHint(result(content, {
|
|
17703
17752
|
mode,
|
|
17704
17753
|
source,
|
|
17705
17754
|
contentType,
|
|
@@ -17708,21 +17757,21 @@ var ContextCompressor = class {
|
|
|
17708
17757
|
originalLines,
|
|
17709
17758
|
omittedLines: 0,
|
|
17710
17759
|
signalCount: 0
|
|
17711
|
-
});
|
|
17760
|
+
}), sourceRef);
|
|
17712
17761
|
}
|
|
17713
17762
|
if (contentType === "log") {
|
|
17714
|
-
return this.compressLog(content, mode, source, contentType);
|
|
17763
|
+
return withSourceRefHint(this.compressLog(content, mode, source, contentType), sourceRef);
|
|
17715
17764
|
}
|
|
17716
17765
|
if (contentType === "markdown") {
|
|
17717
|
-
return this.compressMarkdown(content, mode, source, contentType);
|
|
17766
|
+
return withSourceRefHint(this.compressMarkdown(content, mode, source, contentType), sourceRef);
|
|
17718
17767
|
}
|
|
17719
17768
|
if (contentType === "diff") {
|
|
17720
|
-
return this.compressDiff(content, mode, source, contentType);
|
|
17769
|
+
return withSourceRefHint(this.compressDiff(content, mode, source, contentType), sourceRef);
|
|
17721
17770
|
}
|
|
17722
17771
|
if (contentType === "code") {
|
|
17723
|
-
return this.compressCode(content, mode, source, contentType);
|
|
17772
|
+
return withSourceRefHint(this.compressCode(content, mode, source, contentType), sourceRef);
|
|
17724
17773
|
}
|
|
17725
|
-
return this.compressPlain(content, mode, source, contentType);
|
|
17774
|
+
return withSourceRefHint(this.compressPlain(content, mode, source, contentType), sourceRef);
|
|
17726
17775
|
}
|
|
17727
17776
|
compressLog(content, mode, source, contentType) {
|
|
17728
17777
|
const lines = nonEmptyLines(content);
|
|
@@ -17860,11 +17909,15 @@ function summarizeCompressionTelemetry(metadata) {
|
|
|
17860
17909
|
const totalOriginalChars = metadata.reduce((sum, item) => sum + item.originalChars, 0);
|
|
17861
17910
|
const totalCompressedChars = metadata.reduce((sum, item) => sum + item.compressedChars, 0);
|
|
17862
17911
|
const totalSavedChars = metadata.reduce((sum, item) => sum + item.savedChars, 0);
|
|
17912
|
+
const totalOmittedLines = metadata.reduce((sum, item) => sum + item.omittedLines, 0);
|
|
17913
|
+
const sourceRefsPreserved = metadata.filter((item) => item.sourceRefPreserved).length;
|
|
17863
17914
|
return {
|
|
17864
17915
|
totalItems: metadata.length,
|
|
17865
17916
|
totalOriginalChars,
|
|
17866
17917
|
totalCompressedChars,
|
|
17867
17918
|
totalSavedChars,
|
|
17919
|
+
totalOmittedLines,
|
|
17920
|
+
sourceRefsPreserved,
|
|
17868
17921
|
bySource: summarizeBy(metadata, "source"),
|
|
17869
17922
|
byStrategy: summarizeBy(metadata, "strategy")
|
|
17870
17923
|
};
|
|
@@ -17878,12 +17931,16 @@ function summarizeBy(metadata, key) {
|
|
|
17878
17931
|
items: 0,
|
|
17879
17932
|
originalChars: 0,
|
|
17880
17933
|
compressedChars: 0,
|
|
17881
|
-
savedChars: 0
|
|
17934
|
+
savedChars: 0,
|
|
17935
|
+
omittedLines: 0,
|
|
17936
|
+
sourceRefsPreserved: 0
|
|
17882
17937
|
};
|
|
17883
17938
|
existing.items += 1;
|
|
17884
17939
|
existing.originalChars += item.originalChars;
|
|
17885
17940
|
existing.compressedChars += item.compressedChars;
|
|
17886
17941
|
existing.savedChars += item.savedChars;
|
|
17942
|
+
existing.omittedLines += item.omittedLines;
|
|
17943
|
+
if (item.sourceRefPreserved) existing.sourceRefsPreserved += 1;
|
|
17887
17944
|
groups.set(groupKey, existing);
|
|
17888
17945
|
}
|
|
17889
17946
|
return Array.from(groups.values()).sort((a, b) => String(a[key] ?? "").localeCompare(String(b[key] ?? "")));
|
|
@@ -17898,7 +17955,8 @@ function result(text, base) {
|
|
|
17898
17955
|
...base,
|
|
17899
17956
|
compressedChars,
|
|
17900
17957
|
savedChars,
|
|
17901
|
-
compressionRatio
|
|
17958
|
+
compressionRatio,
|
|
17959
|
+
sourceRefPreserved: false
|
|
17902
17960
|
}
|
|
17903
17961
|
};
|
|
17904
17962
|
}
|
|
@@ -17947,6 +18005,65 @@ function safeLabel(value) {
|
|
|
17947
18005
|
const cleaned = value.replace(/[^A-Za-z0-9_.:-]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 80);
|
|
17948
18006
|
return cleaned || void 0;
|
|
17949
18007
|
}
|
|
18008
|
+
function sourceRefFromMetadata(metadata) {
|
|
18009
|
+
const explicit = firstString(metadata, ["sourceRef", "source_ref", "sourceReference", "source_reference"]);
|
|
18010
|
+
if (explicit) return explicit;
|
|
18011
|
+
const citation = firstString(metadata, ["citationId", "citation_id", "memoryCitationId", "memory_citation_id"]);
|
|
18012
|
+
if (citation) return citation.startsWith("mem:") ? citation : `mem:${citation}`;
|
|
18013
|
+
const eventId = firstString(metadata, ["eventId", "event_id"]);
|
|
18014
|
+
if (eventId) return eventId.startsWith("event:") ? eventId : `event:${eventId}`;
|
|
18015
|
+
return void 0;
|
|
18016
|
+
}
|
|
18017
|
+
function firstString(metadata, keys) {
|
|
18018
|
+
for (const key of keys) {
|
|
18019
|
+
const value = metadata[key];
|
|
18020
|
+
if (typeof value === "string" && value.trim().length > 0) return value.trim();
|
|
18021
|
+
}
|
|
18022
|
+
return void 0;
|
|
18023
|
+
}
|
|
18024
|
+
function safeSourceRef(value) {
|
|
18025
|
+
if (!value) return void 0;
|
|
18026
|
+
const normalized = value.trim().replace(/^\[?(mem|event):/i, (_, prefix) => `${prefix.toLowerCase()}:`).replace(/\]?$/g, "");
|
|
18027
|
+
if (!normalized || /(?:password|secret|api[_-]?key|token|bearer)/i.test(normalized)) return void 0;
|
|
18028
|
+
const cleaned = normalized.replace(/[^A-Za-z0-9_.:-]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 140);
|
|
18029
|
+
return cleaned || void 0;
|
|
18030
|
+
}
|
|
18031
|
+
function withSourceRefHint(compression, sourceRef) {
|
|
18032
|
+
if (!sourceRef) return compression;
|
|
18033
|
+
if (compression.metadata.mode === "off" || compression.metadata.strategy === "none") {
|
|
18034
|
+
return {
|
|
18035
|
+
text: compression.text,
|
|
18036
|
+
metadata: {
|
|
18037
|
+
...compression.metadata,
|
|
18038
|
+
sourceRef,
|
|
18039
|
+
sourceRefPreserved: false
|
|
18040
|
+
}
|
|
18041
|
+
};
|
|
18042
|
+
}
|
|
18043
|
+
const hint = `sourceRef=${sourceRef} expand=mem-source-ref`;
|
|
18044
|
+
const text = compression.text.includes(hint) ? compression.text : addSourceRefHint(compression.text, hint);
|
|
18045
|
+
const compressedChars = text.length;
|
|
18046
|
+
const savedChars = Math.max(0, compression.metadata.originalChars - compressedChars);
|
|
18047
|
+
const compressionRatio = compression.metadata.originalChars > 0 ? compressedChars / compression.metadata.originalChars : 1;
|
|
18048
|
+
return {
|
|
18049
|
+
text,
|
|
18050
|
+
metadata: {
|
|
18051
|
+
...compression.metadata,
|
|
18052
|
+
sourceRef,
|
|
18053
|
+
sourceRefPreserved: text.includes(`sourceRef=${sourceRef}`) && text.includes("expand=mem-source-ref"),
|
|
18054
|
+
compressedChars,
|
|
18055
|
+
savedChars,
|
|
18056
|
+
compressionRatio
|
|
18057
|
+
}
|
|
18058
|
+
};
|
|
18059
|
+
}
|
|
18060
|
+
function addSourceRefHint(text, hint) {
|
|
18061
|
+
if (text.startsWith("[compressed ")) {
|
|
18062
|
+
return text.replace(/^\[([^\]]+)\]/, `[$1; ${hint}]`);
|
|
18063
|
+
}
|
|
18064
|
+
return `[${hint}]
|
|
18065
|
+
${text}`;
|
|
18066
|
+
}
|
|
17950
18067
|
|
|
17951
18068
|
// src/core/task/task-matcher.ts
|
|
17952
18069
|
var DEFAULT_CONFIG7 = {
|