context-mode 1.0.88 → 1.0.89
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.openclaw-plugin/openclaw.plugin.json +1 -1
- package/.openclaw-plugin/package.json +1 -1
- package/build/adapters/claude-code/index.js +15 -1
- package/build/cli.js +100 -47
- package/build/pi-extension.js +24 -7
- package/build/server.js +88 -12
- package/build/store.d.ts +3 -0
- package/build/store.js +59 -9
- package/build/truncate.d.ts +6 -0
- package/build/truncate.js +51 -29
- package/cli.bundle.mjs +139 -132
- package/hooks/pretooluse.mjs +38 -16
- package/hooks/session-snapshot.bundle.mjs +14 -14
- package/insight/server.mjs +25 -7
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/server.bundle.mjs +99 -95
package/build/truncate.js
CHANGED
|
@@ -6,6 +6,43 @@
|
|
|
6
6
|
* consumer can import them without pulling in the full store or executor.
|
|
7
7
|
*/
|
|
8
8
|
// ─────────────────────────────────────────────────────────
|
|
9
|
+
// Internal: byte-safe prefix
|
|
10
|
+
// ─────────────────────────────────────────────────────────
|
|
11
|
+
/**
|
|
12
|
+
* Return the longest character-prefix of `str` whose UTF-8 encoding is at
|
|
13
|
+
* most `maxBytes` bytes. Uses binary search to avoid O(n²) scanning. Returns
|
|
14
|
+
* "" when `maxBytes` is <= 0 so callers never exceed their budget.
|
|
15
|
+
*
|
|
16
|
+
* Guards against splitting a UTF-16 surrogate pair: if the prefix would end
|
|
17
|
+
* on a lone high surrogate, back off one code unit so the result round-trips
|
|
18
|
+
* through UTF-8 without producing a U+FFFD replacement character.
|
|
19
|
+
*/
|
|
20
|
+
function byteSafePrefix(str, maxBytes) {
|
|
21
|
+
if (maxBytes <= 0)
|
|
22
|
+
return "";
|
|
23
|
+
if (Buffer.byteLength(str) <= maxBytes)
|
|
24
|
+
return str;
|
|
25
|
+
let lo = 0;
|
|
26
|
+
let hi = str.length;
|
|
27
|
+
while (lo < hi) {
|
|
28
|
+
const mid = (lo + hi + 1) >> 1;
|
|
29
|
+
if (Buffer.byteLength(str.slice(0, mid)) <= maxBytes) {
|
|
30
|
+
lo = mid;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
hi = mid - 1;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// If we landed between a high and low surrogate, back off so the prefix
|
|
37
|
+
// ends on a valid code point boundary.
|
|
38
|
+
if (lo > 0) {
|
|
39
|
+
const code = str.charCodeAt(lo - 1);
|
|
40
|
+
if (code >= 0xd800 && code <= 0xdbff)
|
|
41
|
+
lo -= 1;
|
|
42
|
+
}
|
|
43
|
+
return str.slice(0, lo);
|
|
44
|
+
}
|
|
45
|
+
// ─────────────────────────────────────────────────────────
|
|
9
46
|
// JSON truncation
|
|
10
47
|
// ─────────────────────────────────────────────────────────
|
|
11
48
|
/**
|
|
@@ -14,6 +51,9 @@
|
|
|
14
51
|
* "... [truncated]" is appended. The result is NOT guaranteed to be valid
|
|
15
52
|
* JSON after truncation — it is suitable only for display/logging.
|
|
16
53
|
*
|
|
54
|
+
* The returned string is always <= `maxBytes` bytes. When `maxBytes` is
|
|
55
|
+
* smaller than the marker, the marker itself is byte-safely truncated.
|
|
56
|
+
*
|
|
17
57
|
* @param value - Any JSON-serializable value.
|
|
18
58
|
* @param maxBytes - Maximum byte length of the returned string.
|
|
19
59
|
* @param indent - JSON indentation spaces (default 2). Pass 0 for compact.
|
|
@@ -22,24 +62,13 @@ export function truncateJSON(value, maxBytes, indent = 2) {
|
|
|
22
62
|
const serialized = JSON.stringify(value, null, indent) ?? "null";
|
|
23
63
|
if (Buffer.byteLength(serialized) <= maxBytes)
|
|
24
64
|
return serialized;
|
|
25
|
-
// Find the largest character slice that stays within maxBytes once encoded.
|
|
26
|
-
// Buffer.byteLength is O(n) but we only call it once per truncation.
|
|
27
65
|
const marker = "... [truncated]";
|
|
28
66
|
const markerBytes = Buffer.byteLength(marker);
|
|
29
|
-
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const mid = (lo + hi + 1) >> 1;
|
|
35
|
-
if (Buffer.byteLength(serialized.slice(0, mid)) <= budget) {
|
|
36
|
-
lo = mid;
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
hi = mid - 1;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return serialized.slice(0, lo) + marker;
|
|
67
|
+
// Degenerate budget: can't fit serialized content + marker. Fit as much of
|
|
68
|
+
// the marker as we can so the return still honors `maxBytes`.
|
|
69
|
+
if (maxBytes <= markerBytes)
|
|
70
|
+
return byteSafePrefix(marker, maxBytes);
|
|
71
|
+
return byteSafePrefix(serialized, maxBytes - markerBytes) + marker;
|
|
43
72
|
}
|
|
44
73
|
// ─────────────────────────────────────────────────────────
|
|
45
74
|
// XML / HTML escaping
|
|
@@ -68,6 +97,9 @@ export function escapeXML(str) {
|
|
|
68
97
|
* byte-safe slice with an ellipsis appended. Useful for single-value fields
|
|
69
98
|
* (e.g., tool response strings) where head+tail splitting is not needed.
|
|
70
99
|
*
|
|
100
|
+
* The returned string is always <= `maxBytes` bytes. When `maxBytes` is
|
|
101
|
+
* smaller than the ellipsis marker, the marker itself is byte-safely truncated.
|
|
102
|
+
*
|
|
71
103
|
* @param str - Input string.
|
|
72
104
|
* @param maxBytes - Hard byte cap.
|
|
73
105
|
*/
|
|
@@ -76,17 +108,7 @@ export function capBytes(str, maxBytes) {
|
|
|
76
108
|
return str;
|
|
77
109
|
const marker = "...";
|
|
78
110
|
const markerBytes = Buffer.byteLength(marker);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
while (lo < hi) {
|
|
83
|
-
const mid = (lo + hi + 1) >> 1;
|
|
84
|
-
if (Buffer.byteLength(str.slice(0, mid)) <= budget) {
|
|
85
|
-
lo = mid;
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
hi = mid - 1;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return str.slice(0, lo) + marker;
|
|
111
|
+
if (maxBytes <= markerBytes)
|
|
112
|
+
return byteSafePrefix(marker, maxBytes);
|
|
113
|
+
return byteSafePrefix(str, maxBytes - markerBytes) + marker;
|
|
92
114
|
}
|