acp-kernel 0.0.42 → 0.0.43
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/DESIGN.md +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +296 -30
- package/dist/index.js.map +1 -1
- package/dist/parse-compress-input.d.ts +32 -0
- package/dist/parse-compress-input.d.ts.map +1 -0
- package/dist/rebuild.d.ts +3 -8
- package/dist/rebuild.d.ts.map +1 -1
- package/package.json +1 -1
package/DESIGN.md
CHANGED
|
@@ -201,6 +201,7 @@ A default `countTokens` ships with the core (word-level + unicode CJK tokenizer,
|
|
|
201
201
|
| prune (range → summary block) | **core** `processTurn` (pure) |
|
|
202
202
|
| boundary resolution / search | **core** `resolveBoundaries` (pure) |
|
|
203
203
|
| block allocation / state mutation / tiers | **core** `applyCompression` (pure) |
|
|
204
|
+
| compress **argument parsing** (lenient: fences, trailing commas, truncated-array salvage; field-name variants) | **core** `parseCompressArgs` (pure; diagnostics are data — adapters emit them) |
|
|
204
205
|
| young→old promotion / batch merge | **core** `sync-blocks` node (`advanceSurvival`) + `merge-blocks` node (pure) |
|
|
205
206
|
| emergency truncation (context near full) | **core** `emergency-truncate` node — the LAST safety valve; no age-based GC |
|
|
206
207
|
| protected-tools filtering logic | **core** (pure: message + config → bool) |
|
package/dist/index.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export { hideConsumedCompressCalls } from "./hide-consumed.js";
|
|
|
25
25
|
export type { HideConsumedResult } from "./hide-consumed.js";
|
|
26
26
|
export { rebuildCompressionState } from "./rebuild.js";
|
|
27
27
|
export type { RebuildResult, RebuildPorts } from "./rebuild.js";
|
|
28
|
+
export { parseCompressArgs } from "./parse-compress-input.js";
|
|
29
|
+
export type { CompressParseDiagnostics, CompressParseKind, ParsedCompressInput } from "./parse-compress-input.js";
|
|
28
30
|
export { renderVisibleRefs, renderRefsNode, createRenderRefsNode, } from "./render-refs.js";
|
|
29
31
|
export type { RenderStrategy } from "./render-refs.js";
|
|
30
32
|
export { resolveTransformChannel } from "./transform-channel.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1336,7 +1336,7 @@ function createCore(ports = {}) {
|
|
|
1336
1336
|
if (!hasBlockBoundaryRange && totalRangeChars < input.config.compress.minCompressRange) {
|
|
1337
1337
|
const live = activeBlocks(state).map((b) => b.blockId).sort((x, y) => numericBlockId(x) - numericBlockId(y));
|
|
1338
1338
|
const liveHint = live.length > 0 ? ` Current active blocks span ${live[0]}..${live[live.length - 1]} \u2014 retry with startId/endId set to active block IDs in that span.` : "";
|
|
1339
|
-
const gateMessage = resolvableCount === 0 && consumedRanges.length === 0 && unknownCount > 0 ? `None of the ${input.ranges.length} requested range(s) resolved \u2014 every ref failed with "does not exist in this session". Refs recorded before an earlier compress are stale: each successful compress renumbers the remaining refs. Run acp_status, then
|
|
1339
|
+
const gateMessage = resolvableCount === 0 && consumedRanges.length === 0 && unknownCount > 0 ? `None of the ${input.ranges.length} requested range(s) resolved \u2014 every ref failed with "does not exist in this session". Refs recorded before an earlier compress are stale: each successful compress renumbers the remaining refs. Run acp_status, then call the compress tool again using only the refs it reports.` : consumedRanges.length > 0 ? `Requested range(s) already compressed (e.g. ${consumedRanges[0].startRef}..${consumedRanges[0].endRef}) \u2014 your refs are stale: a prior compress renumbered the remaining refs, so this range now falls inside an active block. Run acp_status, then call the compress tool again using only the CURRENT compressible ranges it reports.${liveHint}` : `Total compressible content too small (${totalRangeChars} chars across ${countedRanges} range(s), min ${input.config.compress.minCompressRange}). Combine more messages into your range(s) to meet the threshold.`;
|
|
1340
1340
|
return {
|
|
1341
1341
|
state: input.state,
|
|
1342
1342
|
result: {
|
|
@@ -2776,6 +2776,298 @@ Call with blockId to get the full summary.`);
|
|
|
2776
2776
|
return lines.join("\n");
|
|
2777
2777
|
}
|
|
2778
2778
|
|
|
2779
|
+
// src/parse-compress-input.ts
|
|
2780
|
+
function parseCompressArgs(input, opts) {
|
|
2781
|
+
const callId = opts?.callId;
|
|
2782
|
+
const diag = { ok: false, kind: "ok", invalidItems: 0 };
|
|
2783
|
+
if (input === null || input === void 0) {
|
|
2784
|
+
diag.kind = "empty-input";
|
|
2785
|
+
return finish([], diag);
|
|
2786
|
+
}
|
|
2787
|
+
if (typeof input === "string") {
|
|
2788
|
+
return parseStringInput(input, callId, diag);
|
|
2789
|
+
}
|
|
2790
|
+
if (typeof input !== "object" || Array.isArray(input)) {
|
|
2791
|
+
diag.kind = "not-object";
|
|
2792
|
+
return finish([], diag);
|
|
2793
|
+
}
|
|
2794
|
+
return parseObjectValue(input, callId, diag);
|
|
2795
|
+
}
|
|
2796
|
+
function parseStringInput(raw, callId, diag) {
|
|
2797
|
+
diag.rawPrefix = raw.slice(0, 800);
|
|
2798
|
+
diag.length = raw.length;
|
|
2799
|
+
const cleaned = stripFence(raw.trim());
|
|
2800
|
+
if (cleaned === "") {
|
|
2801
|
+
diag.kind = "empty-input";
|
|
2802
|
+
return finish([], diag);
|
|
2803
|
+
}
|
|
2804
|
+
let value = tryParseLenient(cleaned);
|
|
2805
|
+
if (typeof value === "string") {
|
|
2806
|
+
const inner = tryParseLenient(stripFence(value));
|
|
2807
|
+
if (inner !== void 0) value = inner;
|
|
2808
|
+
}
|
|
2809
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
2810
|
+
return parseObjectValue(value, callId, diag);
|
|
2811
|
+
}
|
|
2812
|
+
if (value !== void 0) {
|
|
2813
|
+
diag.kind = "not-object";
|
|
2814
|
+
return finish([], diag);
|
|
2815
|
+
}
|
|
2816
|
+
const entries = salvageContentEntries(cleaned);
|
|
2817
|
+
return finishSalvage(entries, callId, diag, looksTruncated(cleaned));
|
|
2818
|
+
}
|
|
2819
|
+
function parseObjectValue(value, callId, diag) {
|
|
2820
|
+
diag.keys = Object.keys(value);
|
|
2821
|
+
const content = value["content"];
|
|
2822
|
+
if (content === void 0) {
|
|
2823
|
+
const single = validateEntry(value, callId);
|
|
2824
|
+
if (single) {
|
|
2825
|
+
diag.kind = "ok";
|
|
2826
|
+
return finish([single], diag);
|
|
2827
|
+
}
|
|
2828
|
+
diag.kind = "missing-content";
|
|
2829
|
+
return finish([], diag);
|
|
2830
|
+
}
|
|
2831
|
+
let entries;
|
|
2832
|
+
let salvaged = false;
|
|
2833
|
+
if (Array.isArray(content)) {
|
|
2834
|
+
entries = content;
|
|
2835
|
+
} else if (typeof content === "string") {
|
|
2836
|
+
const parsed = parseContentArray(content);
|
|
2837
|
+
if (parsed === null) {
|
|
2838
|
+
diag.kind = "content-not-array";
|
|
2839
|
+
return finish([], diag);
|
|
2840
|
+
}
|
|
2841
|
+
entries = parsed.entries;
|
|
2842
|
+
salvaged = parsed.salvaged;
|
|
2843
|
+
} else {
|
|
2844
|
+
diag.kind = "content-not-array";
|
|
2845
|
+
return finish([], diag);
|
|
2846
|
+
}
|
|
2847
|
+
const { ranges, invalid } = validateEntries(entries, callId);
|
|
2848
|
+
const topTopic = stringOr(value["topic"]);
|
|
2849
|
+
const topMaxChars = value["summaryMaxChars"];
|
|
2850
|
+
const hasTopMaxChars = typeof topMaxChars === "number" && Number.isFinite(topMaxChars);
|
|
2851
|
+
if (topTopic !== void 0 || hasTopMaxChars) {
|
|
2852
|
+
for (const r of ranges) {
|
|
2853
|
+
if (r.topic === void 0 && topTopic !== void 0) r.topic = topTopic;
|
|
2854
|
+
if (r.summaryMaxChars === void 0 && hasTopMaxChars) r.summaryMaxChars = topMaxChars;
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2857
|
+
diag.invalidItems = invalid;
|
|
2858
|
+
diag.kind = salvaged ? "truncated" : ranges.length > 0 ? "ok" : "no-valid-ranges";
|
|
2859
|
+
return finish(ranges, diag);
|
|
2860
|
+
}
|
|
2861
|
+
function parseContentArray(s) {
|
|
2862
|
+
const cleaned = stripFence(s.trim());
|
|
2863
|
+
let value = cleaned === "" ? void 0 : tryParseLenient(cleaned);
|
|
2864
|
+
if (typeof value === "string") {
|
|
2865
|
+
value = tryParseLenient(stripFence(value));
|
|
2866
|
+
}
|
|
2867
|
+
if (Array.isArray(value)) {
|
|
2868
|
+
return { entries: value, salvaged: false };
|
|
2869
|
+
}
|
|
2870
|
+
if (value === void 0) {
|
|
2871
|
+
const entries = salvageContentEntries('{"content": ' + cleaned);
|
|
2872
|
+
return { entries, salvaged: entries.length > 0 };
|
|
2873
|
+
}
|
|
2874
|
+
return null;
|
|
2875
|
+
}
|
|
2876
|
+
function finish(ranges, diag) {
|
|
2877
|
+
diag.ok = ranges.length > 0;
|
|
2878
|
+
return { ranges, diagnostics: diag };
|
|
2879
|
+
}
|
|
2880
|
+
function finishSalvage(entries, callId, diag, truncatedShape) {
|
|
2881
|
+
const { ranges, invalid } = validateEntries(entries, callId);
|
|
2882
|
+
diag.invalidItems = invalid;
|
|
2883
|
+
diag.kind = entries.length > 0 || truncatedShape ? "truncated" : "malformed-json";
|
|
2884
|
+
return finish(ranges, diag);
|
|
2885
|
+
}
|
|
2886
|
+
function validateEntries(entries, callId) {
|
|
2887
|
+
const ranges = [];
|
|
2888
|
+
let invalid = 0;
|
|
2889
|
+
for (const entry of entries) {
|
|
2890
|
+
const range = validateEntry(entry, callId);
|
|
2891
|
+
if (range !== null) ranges.push(range);
|
|
2892
|
+
else invalid++;
|
|
2893
|
+
}
|
|
2894
|
+
return { ranges, invalid };
|
|
2895
|
+
}
|
|
2896
|
+
function validateEntry(entry, callId) {
|
|
2897
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) return null;
|
|
2898
|
+
const e = entry;
|
|
2899
|
+
const start = stringOr(e["startRef"]) ?? stringOr(e["startId"]) ?? stringOr(e["messageId"]);
|
|
2900
|
+
const end = stringOr(e["endRef"]) ?? stringOr(e["endId"]) ?? stringOr(e["messageId"]);
|
|
2901
|
+
if (start === void 0 || end === void 0) return null;
|
|
2902
|
+
const summary = stringOr(e["summary"]);
|
|
2903
|
+
if (summary === void 0) return null;
|
|
2904
|
+
const range = { startRef: start, endRef: end, summary };
|
|
2905
|
+
const topic = stringOr(e["topic"]);
|
|
2906
|
+
if (topic !== void 0) range.topic = topic;
|
|
2907
|
+
const maxChars = e["summaryMaxChars"];
|
|
2908
|
+
if (typeof maxChars === "number" && Number.isFinite(maxChars)) range.summaryMaxChars = maxChars;
|
|
2909
|
+
if (callId !== void 0) range.compressCallId = callId;
|
|
2910
|
+
return range;
|
|
2911
|
+
}
|
|
2912
|
+
function stringOr(value) {
|
|
2913
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
2914
|
+
}
|
|
2915
|
+
function tryParseLenient(s) {
|
|
2916
|
+
if (s === "") return void 0;
|
|
2917
|
+
try {
|
|
2918
|
+
return JSON.parse(s);
|
|
2919
|
+
} catch {
|
|
2920
|
+
}
|
|
2921
|
+
const noTrailingCommas = stripTrailingCommas(s);
|
|
2922
|
+
if (noTrailingCommas !== s) {
|
|
2923
|
+
try {
|
|
2924
|
+
return JSON.parse(noTrailingCommas);
|
|
2925
|
+
} catch {
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
const fixed = escapeRawNewlinesInStrings(noTrailingCommas);
|
|
2929
|
+
if (fixed !== noTrailingCommas) {
|
|
2930
|
+
try {
|
|
2931
|
+
return JSON.parse(fixed);
|
|
2932
|
+
} catch {
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
return void 0;
|
|
2936
|
+
}
|
|
2937
|
+
function stripFence(s) {
|
|
2938
|
+
if (!s.startsWith("```")) return s;
|
|
2939
|
+
const firstNewline = s.indexOf("\n");
|
|
2940
|
+
if (firstNewline === -1) return s;
|
|
2941
|
+
const bodyStart = firstNewline + 1;
|
|
2942
|
+
const end = s.lastIndexOf("```");
|
|
2943
|
+
return end > bodyStart ? s.slice(bodyStart, end).trim() : s.slice(bodyStart).trim();
|
|
2944
|
+
}
|
|
2945
|
+
function stripTrailingCommas(s) {
|
|
2946
|
+
let out = "";
|
|
2947
|
+
let inString = false;
|
|
2948
|
+
let escaped = false;
|
|
2949
|
+
for (let i = 0; i < s.length; i++) {
|
|
2950
|
+
const ch = s.charAt(i);
|
|
2951
|
+
if (inString) {
|
|
2952
|
+
out += ch;
|
|
2953
|
+
if (escaped) escaped = false;
|
|
2954
|
+
else if (ch === "\\") escaped = true;
|
|
2955
|
+
else if (ch === '"') inString = false;
|
|
2956
|
+
continue;
|
|
2957
|
+
}
|
|
2958
|
+
if (ch === '"') {
|
|
2959
|
+
inString = true;
|
|
2960
|
+
out += ch;
|
|
2961
|
+
continue;
|
|
2962
|
+
}
|
|
2963
|
+
if (ch === ",") {
|
|
2964
|
+
let j = i + 1;
|
|
2965
|
+
while (j < s.length && (s.charAt(j) === " " || s.charAt(j) === " " || s.charAt(j) === "\n" || s.charAt(j) === "\r")) j++;
|
|
2966
|
+
if (j < s.length && (s.charAt(j) === "}" || s.charAt(j) === "]")) continue;
|
|
2967
|
+
}
|
|
2968
|
+
out += ch;
|
|
2969
|
+
}
|
|
2970
|
+
return out;
|
|
2971
|
+
}
|
|
2972
|
+
function escapeRawNewlinesInStrings(s) {
|
|
2973
|
+
let out = "";
|
|
2974
|
+
let inString = false;
|
|
2975
|
+
let escaped = false;
|
|
2976
|
+
for (let i = 0; i < s.length; i++) {
|
|
2977
|
+
const ch = s.charAt(i);
|
|
2978
|
+
if (!inString) {
|
|
2979
|
+
if (ch === '"') inString = true;
|
|
2980
|
+
out += ch;
|
|
2981
|
+
continue;
|
|
2982
|
+
}
|
|
2983
|
+
if (escaped) {
|
|
2984
|
+
out += ch;
|
|
2985
|
+
escaped = false;
|
|
2986
|
+
continue;
|
|
2987
|
+
}
|
|
2988
|
+
if (ch === "\\") {
|
|
2989
|
+
out += ch;
|
|
2990
|
+
escaped = true;
|
|
2991
|
+
continue;
|
|
2992
|
+
}
|
|
2993
|
+
if (ch === "\n") {
|
|
2994
|
+
out += "\\n";
|
|
2995
|
+
continue;
|
|
2996
|
+
}
|
|
2997
|
+
if (ch === "\r") {
|
|
2998
|
+
out += "\\r";
|
|
2999
|
+
continue;
|
|
3000
|
+
}
|
|
3001
|
+
if (ch === " ") {
|
|
3002
|
+
out += "\\t";
|
|
3003
|
+
continue;
|
|
3004
|
+
}
|
|
3005
|
+
if (ch === '"') inString = false;
|
|
3006
|
+
out += ch;
|
|
3007
|
+
}
|
|
3008
|
+
return out;
|
|
3009
|
+
}
|
|
3010
|
+
function looksTruncated(s) {
|
|
3011
|
+
let depth = 0;
|
|
3012
|
+
let inString = false;
|
|
3013
|
+
let escaped = false;
|
|
3014
|
+
for (let i = 0; i < s.length; i++) {
|
|
3015
|
+
const ch = s.charAt(i);
|
|
3016
|
+
if (inString) {
|
|
3017
|
+
if (escaped) escaped = false;
|
|
3018
|
+
else if (ch === "\\") escaped = true;
|
|
3019
|
+
else if (ch === '"') inString = false;
|
|
3020
|
+
continue;
|
|
3021
|
+
}
|
|
3022
|
+
if (ch === '"') {
|
|
3023
|
+
inString = true;
|
|
3024
|
+
continue;
|
|
3025
|
+
}
|
|
3026
|
+
if (ch === "{" || ch === "[") depth++;
|
|
3027
|
+
else if (ch === "}" || ch === "]") depth--;
|
|
3028
|
+
}
|
|
3029
|
+
return depth > 0 || inString;
|
|
3030
|
+
}
|
|
3031
|
+
function salvageContentEntries(raw) {
|
|
3032
|
+
const match = /"content"\s*:\s*\[/.exec(raw);
|
|
3033
|
+
if (match === null) return [];
|
|
3034
|
+
const arrayStart = match.index + match[0].length - 1;
|
|
3035
|
+
const entries = [];
|
|
3036
|
+
let depth = 0;
|
|
3037
|
+
let inString = false;
|
|
3038
|
+
let escaped = false;
|
|
3039
|
+
let entryStart = -1;
|
|
3040
|
+
for (let i = arrayStart + 1; i < raw.length; i++) {
|
|
3041
|
+
const ch = raw.charAt(i);
|
|
3042
|
+
if (inString) {
|
|
3043
|
+
if (escaped) escaped = false;
|
|
3044
|
+
else if (ch === "\\") escaped = true;
|
|
3045
|
+
else if (ch === '"') inString = false;
|
|
3046
|
+
continue;
|
|
3047
|
+
}
|
|
3048
|
+
if (ch === '"') {
|
|
3049
|
+
inString = true;
|
|
3050
|
+
continue;
|
|
3051
|
+
}
|
|
3052
|
+
if (ch === "{" || ch === "[") {
|
|
3053
|
+
if (depth === 0 && ch === "{" && entryStart === -1) entryStart = i;
|
|
3054
|
+
depth++;
|
|
3055
|
+
continue;
|
|
3056
|
+
}
|
|
3057
|
+
if (ch === "}" || ch === "]") {
|
|
3058
|
+
depth--;
|
|
3059
|
+
if (depth < 0) break;
|
|
3060
|
+
if (depth === 0 && entryStart !== -1) {
|
|
3061
|
+
const entrySlice = raw.slice(entryStart, i + 1);
|
|
3062
|
+
entryStart = -1;
|
|
3063
|
+
const parsed = tryParseLenient(entrySlice);
|
|
3064
|
+
if (parsed !== void 0) entries.push(parsed);
|
|
3065
|
+
}
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
return entries;
|
|
3069
|
+
}
|
|
3070
|
+
|
|
2779
3071
|
// src/rebuild.ts
|
|
2780
3072
|
function rebuildCompressionState(state, messages, config, ports = {}) {
|
|
2781
3073
|
const core = createCore({ countTokens: ports.countTokens ?? defaultCountTokens });
|
|
@@ -2787,7 +3079,7 @@ function rebuildCompressionState(state, messages, config, ports = {}) {
|
|
|
2787
3079
|
const invocations = collectCompressInvocations(messages);
|
|
2788
3080
|
let blocksRebuilt = 0;
|
|
2789
3081
|
for (const invocation of invocations) {
|
|
2790
|
-
const ranges =
|
|
3082
|
+
const { ranges } = parseCompressArgs(invocation.raw, { callId: invocation.callId });
|
|
2791
3083
|
if (ranges.length === 0) continue;
|
|
2792
3084
|
const result = core.applyCompression({ ranges, messages, state: working, config });
|
|
2793
3085
|
working = result.state;
|
|
@@ -2799,37 +3091,10 @@ function collectCompressInvocations(messages) {
|
|
|
2799
3091
|
const invocations = [];
|
|
2800
3092
|
for (const message of messages) {
|
|
2801
3093
|
if (message.toolName !== "compress" || message.contentType !== "tool-call") continue;
|
|
2802
|
-
|
|
2803
|
-
try {
|
|
2804
|
-
input = JSON.parse(message.text ?? "");
|
|
2805
|
-
} catch {
|
|
2806
|
-
continue;
|
|
2807
|
-
}
|
|
2808
|
-
invocations.push({ callId: message.toolCallId, input });
|
|
3094
|
+
invocations.push({ callId: message.toolCallId, raw: message.text ?? "" });
|
|
2809
3095
|
}
|
|
2810
3096
|
return invocations;
|
|
2811
3097
|
}
|
|
2812
|
-
function extractRanges(input, callId) {
|
|
2813
|
-
const content = input?.content;
|
|
2814
|
-
if (!Array.isArray(content)) return [];
|
|
2815
|
-
const ranges = [];
|
|
2816
|
-
for (const entry of content) {
|
|
2817
|
-
if (!entry || typeof entry !== "object") continue;
|
|
2818
|
-
const e = entry;
|
|
2819
|
-
if (typeof e.summary !== "string") continue;
|
|
2820
|
-
const start = e.startId ?? e.messageId;
|
|
2821
|
-
const end = e.endId ?? e.messageId;
|
|
2822
|
-
if (typeof start !== "string" || typeof end !== "string") continue;
|
|
2823
|
-
ranges.push({
|
|
2824
|
-
startRef: start,
|
|
2825
|
-
endRef: end,
|
|
2826
|
-
summary: e.summary,
|
|
2827
|
-
topic: typeof e.topic === "string" ? e.topic : void 0,
|
|
2828
|
-
compressCallId: callId
|
|
2829
|
-
});
|
|
2830
|
-
}
|
|
2831
|
-
return ranges;
|
|
2832
|
-
}
|
|
2833
3098
|
|
|
2834
3099
|
// src/transform-channel.ts
|
|
2835
3100
|
function resolveTransformChannel(explicit, wireViable) {
|
|
@@ -3264,6 +3529,7 @@ export {
|
|
|
3264
3529
|
messageDocs,
|
|
3265
3530
|
parseBlockIdArg,
|
|
3266
3531
|
parseBoundary,
|
|
3532
|
+
parseCompressArgs,
|
|
3267
3533
|
parseCompressInput,
|
|
3268
3534
|
prune,
|
|
3269
3535
|
rawForRef,
|