skills-experimental/end-truncating-accumulator-pattern/SKILL.md
# End-Truncating Accumulator Pattern Skill End-Truncating Accumulator Pattern - EndTruncatingAccumulator class + maxSize limit + append truncation from end + isTruncated flag + totalBytesReceived tracking + toString truncation marker + truncation marker KB + MAX_STRING_LENGTH 2^25 + safeJoinLines + firstLineOf indexOf + countCharInString indexOf jumps。 ## 功能概述 从Claude Code的utils/stringUtils.ts提取的End-truncating accumulator模式,用于OpenClaw的大字符串处理。 ## 核心机制 ### EndTruncatingAccumulator Class ```t
npx skillsauth add bianhaifeng789-hue/openclaw-config skills-experimental/end-truncating-accumulator-patternInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
End-Truncating Accumulator Pattern - EndTruncatingAccumulator class + maxSize limit + append truncation from end + isTruncated flag + totalBytesReceived tracking + toString truncation marker + truncation marker KB + MAX_STRING_LENGTH 2^25 + safeJoinLines + firstLineOf indexOf + countCharInString indexOf jumps。
从Claude Code的utils/stringUtils.ts提取的End-truncating accumulator模式,用于OpenClaw的大字符串处理。
export class EndTruncatingAccumulator {
private content: string = ''
private isTruncated = false
private totalBytesReceived = 0
constructor(private readonly maxSize: number = MAX_STRING_LENGTH) {}
append(data: string | Buffer): void {
const str = typeof data === 'string' ? data : data.toString()
this.totalBytesReceived += str.length
if (this.isTruncated && this.content.length >= this.maxSize) {
return // Already at capacity
}
if (this.content.length + str.length > this.maxSize) {
const remainingSpace = this.maxSize - this.content.length
if (remainingSpace > 0) {
this.content += str.slice(0, remainingSpace)
}
this.isTruncated = true
} else {
this.content += str
}
}
toString(): string {
if (!this.isTruncated) {
return this.content
}
const truncatedBytes = this.totalBytesReceived - this.maxSize
const truncatedKB = Math.round(truncatedBytes / 1024)
return this.content + `\n... [output truncated - ${truncatedKB}KB removed]`
}
}
// Accumulator with truncation from end
# maxSize limit
# totalBytesReceived tracking
# truncation marker with KB
private readonly maxSize: number = MAX_STRING_LENGTH
// Max size limit
# Default: 2^25 = 33MB
# Prevent RangeError
append(data: string | Buffer): void {
const str = typeof data === 'string' ? data : data.toString()
this.totalBytesReceived += str.length
if (this.content.length + str.length > this.maxSize) {
const remainingSpace = this.maxSize - this.content.length
if (remainingSpace > 0) {
this.content += str.slice(0, remainingSpace)
}
this.isTruncated = true
} else {
this.content += str
}
}
// Append with truncation
# Truncate from end (preserve beginning)
# Prevents RangeError crashes
private isTruncated = false
// Track truncation state
# true when exceeded maxSize
# Used in toString()
private totalBytesReceived = 0
// Total bytes before truncation
# Track all received data
# Calculate truncated amount
toString(): string {
if (!this.isTruncated) {
return this.content
}
const truncatedBytes = this.totalBytesReceived - this.maxSize
const truncatedKB = Math.round(truncatedBytes / 1024)
return this.content + `\n... [output truncated - ${truncatedKB}KB removed]`
}
// toString with marker
# Show truncated KB amount
# '... [output truncated - 50KB removed]'
const truncatedKB = Math.round(truncatedBytes / 1024)
`\n... [output truncated - ${truncatedKB}KB removed]`
// Show KB amount truncated
# User-friendly
# Actual bytes removed
const MAX_STRING_LENGTH = 2 ** 25
// 33MB max string length
# Prevent RangeError
# Keep RSS modest
# Overflow to disk
export function safeJoinLines(
lines: string[],
delimiter: string = ',',
maxSize: number = MAX_STRING_LENGTH,
): string {
const truncationMarker = '...[truncated]'
let result = ''
for (const line of lines) {
const delimiterToAdd = result ? delimiter : ''
const fullAddition = delimiterToAdd + line
if (result.length + fullAddition.length <= maxSize) {
result += fullAddition
} else {
const remainingSpace = maxSize - result.length - delimiterToAdd.length - truncationMarker.length
if (remainingSpace > 0) {
result += delimiterToAdd + line.slice(0, remainingSpace) + truncationMarker
} else {
result += truncationMarker
}
return result
}
}
return result
}
// Safe join with truncation
# Truncate when exceeds maxSize
# Preserve beginning
export function firstLineOf(s: string): string {
const nl = s.indexOf('\n')
return nl === -1 ? s : s.slice(0, nl)
}
// First line without split allocation
# indexOf('\n') → slice
# No split('\n') array
# Shebang detection
export function countCharInString(
str: { indexOf(search: string, start?: number): number },
char: string,
start = 0,
): number {
let count = 0
let i = str.indexOf(char, start)
while (i !== -1) {
count++
i = str.indexOf(char, i + 1)
}
return count
}
// Count chars with indexOf jumps
# indexOf loop
# Not per-character iteration
# Structurally typed (Buffer works)
{
"content": "first 33MB...",
"isTruncated": true,
"totalBytesReceived": 50000000,
"maxSize": 33554432,
"truncatedKB": 16384
}
exceed maxSize → str.slice(0, remainingSpace) → append partial → preserve beginning → prevent RangeError
# truncate from end
# 保留beginning
# 防止RangeError
totalBytesReceived += str.length → track all data → toString: totalBytesReceived - maxSize → truncated amount
# totalBytesReceived tracking
# 计算truncated amount
# 显示实际删除量
'\n... [output truncated - ${truncatedKB}KB removed]' → KB amount → user-friendly → show actual removal
# truncation marker with KB
# 用户友好
# 显示实际删除量
s.indexOf('\n') → slice(0, nl) → no split('\n') array → no allocation → efficient
# indexOf no split allocation
# 避免split array
# efficient
str.indexOf(char, start) → i = indexOf(char, i+1) → indexOf jumps → not per-char iteration → efficient
# indexOf jumps
# 不per-character iteration
# efficient counting
utils/stringUtils.ts (235 lines)business
IAA 日报飞书输出能力。 支持把固定 CSV 模板一键转换成: - 中文运营结论 - 飞书卡片 JSON - 飞书发送载荷 Use when: - 需要把 IAA 日报直接发到飞书 - 需要从 CSV 一键生成运营日报
data-ai
IAA日报分析模型 功能: - 渠道日报自动分析 - 小时级+日级ROI联动判断 - 按地区输出加量/降量/停投建议 - 按产品类型输出阈值 - 自动识别利润区/观察区/止损区 Use when: - 分析每天投放数据 - 生成运营日报结论 - 判断是否加量/降量/停投 - 对比美加澳/日韩表现 Keywords: - 日报模型, 投放日报, 加量, 降量, 停投, ROI日报, 分地区分析
data-ai
IAA固定日报分析模板 功能: - 固定字段模板(可直接贴每天数据) - 自动输出总盘结论 - 自动输出美加澳/日韩结论 - 自动给出加量/降量/停投建议 - 适配文件修复/清理两类产品 Use when: - 需要固定日报格式 - 每天复盘渠道表现 - 给运营团队出统一结论 Keywords: - 固定模板, 日报模板, ROI模板, IAA日报, 运营模板
development
# HyperlinkPool Pattern Skill HyperlinkPool Pattern - HyperlinkPool class + strings array + stringMap + Index 0 no hyperlink + intern(hyperlink) + get(id) + undefined handling + 5-minute reset + OSC8 hyperlink interning。 ## 功能概述 从Claude Code的ink/screen.ts提取的HyperlinkPool模式,用于OpenClaw的OSC8超链接池管理。 ## 核心机制 ### HyperlinkPool Class ```typescript export class HyperlinkPool { private strings: string[] = [''] // Index 0 = no hyperlink private stringMap = new Map<string, number>() // strings