skills-experimental/duration-format-pattern/SKILL.md
# Duration Format Pattern Skill Duration Format Pattern - formatDuration + ms threshold branches + <60s formatSeconds + rounding carry-over + 60s→minutes++ + 24h→days++ + hideTrailingZeros + mostSignificantOnly + days/hours/minutes/seconds cascade + formatSecondsShort decimal + formatNumber Intl.NumberFormat compact + cached formatter。 ## 功能概述 从Claude Code的utils/format.ts提取的Duration format模式,用于OpenClaw的时长格式化。 ## 核心机制 ### formatDuration ```typescript export function formatDuration( ms: nu
npx skillsauth add bianhaifeng789-hue/openclaw-config skills-experimental/duration-format-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.
Duration Format Pattern - formatDuration + ms threshold branches + <60s formatSeconds + rounding carry-over + 60s→minutes++ + 24h→days++ + hideTrailingZeros + mostSignificantOnly + days/hours/minutes/seconds cascade + formatSecondsShort decimal + formatNumber Intl.NumberFormat compact + cached formatter。
从Claude Code的utils/format.ts提取的Duration format模式,用于OpenClaw的时长格式化。
export function formatDuration(
ms: number,
options?: { hideTrailingZeros?: boolean; mostSignificantOnly?: boolean },
): string {
if (ms < 60000) {
// < 60 seconds
if (ms === 0) return '0s'
if (ms < 1) return `${(ms / 1000).toFixed(1)}s`
const s = Math.floor(ms / 1000).toString()
return `${s}s`
}
let days = Math.floor(ms / 86400000)
let hours = Math.floor((ms % 86400000) / 3600000)
let minutes = Math.floor((ms % 3600000) / 60000)
let seconds = Math.round((ms % 60000) / 1000)
// Handle rounding carry-over
if (seconds === 60) { seconds = 0; minutes++ }
if (minutes === 60) { minutes = 0; hours++ }
if (hours === 24) { hours = 0; days++ }
// ...
}
// Format milliseconds to human-readable duration
# Days, hours, minutes, seconds
if (ms < 60000) {
// < 60s: simple seconds format
}
// >= 60s: days/hours/minutes/seconds
// Threshold-based branching
if (ms < 60000) {
if (ms === 0) return '0s'
if (ms < 1) return `${(ms / 1000).toFixed(1)}s` // < 1ms: 0.5s
const s = Math.floor(ms / 1000).toString()
return `${s}s`
}
// < 60 seconds: simple format
# 0 → '0s'
# <1ms → decimal (0.5s)
# >=1ms → integer (5s)
// Handle rounding carry-over (e.g., 59.5s rounds to 60s)
if (seconds === 60) {
seconds = 0
minutes++
}
if (minutes === 60) {
minutes = 0
hours++
}
if (hours === 24) {
hours = 0
days++
}
// Rounding carry-over
# Math.round((ms % 60000) / 1000) → 59.5s → 60s
# 60s → 0s, minutes++
# Cascade carry-over
if (seconds === 60) {
seconds = 0
minutes++
}
// 60 seconds → increment minutes
# Carry-over logic
if (hours === 24) {
hours = 0
days++
}
// 24 hours → increment days
# Cascade carry-over
const hide = options?.hideTrailingZeros
if (days > 0) {
if (hide && hours === 0 && minutes === 0) return `${days}d`
if (hide && minutes === 0) return `${days}d ${hours}h`
return `${days}d ${hours}h ${minutes}m`
}
// Hide trailing zeros
# days with zero hours/minutes → just 'Xd'
# Cascade hiding
if (options?.mostSignificantOnly) {
if (days > 0) return `${days}d`
if (hours > 0) return `${hours}h`
if (minutes > 0) return `${minutes}m`
return `${seconds}s`
}
// Most significant unit only
# Only show largest non-zero unit
// Cascade from largest to smallest
days → hours → minutes → seconds
// Check each threshold
# Days first
# Hours if no days
# Minutes if no hours
# Seconds if no minutes
export function formatSecondsShort(ms: number): string {
return `${(ms / 1000).toFixed(1)}s`
}
// Always 1 decimal place
# 1234 → "1.2s"
# TTFT, hook durations
# Sub-minute timings
export function formatNumber(number: number): string {
const shouldUseConsistentDecimals = number >= 1000
return getNumberFormatter(shouldUseConsistentDecimals)
.format(number) // 1321 → "1.3K"
.toLowerCase() // "1.3K" → "1.3k"
}
// Compact notation: 1321 → "1.3k"
# Intl.NumberFormat compact
# maximumFractionDigits: 1
let numberFormatterForConsistentDecimals: Intl.NumberFormat | null = null
let numberFormatterForInconsistentDecimals: Intl.NumberFormat | null = null
const getNumberFormatter = (useConsistentDecimals: boolean): Intl.NumberFormat => {
if (useConsistentDecimals) {
if (!numberFormatterForConsistentDecimals) {
numberFormatterForConsistentDecimals = new Intl.NumberFormat(...)
}
return numberFormatterForConsistentDecimals
} else {
// ...
}
}
// Cache Intl.NumberFormat
# new Intl.NumberFormat is expensive
# Cache for reuse
# Two formatters: consistent vs inconsistent decimals
{
"ms": 123456789,
"duration": "1d 10h 17m",
"mostSignificantOnly": "1d"
}
Math.round → 60s → seconds=0, minutes++ → minutes=60 → minutes=0, hours++ → cascade
# rounding carry-over cascade
# 59.5s → 60s → carry-over
# cascade handling
hide && hours===0 && minutes===0 → 'Xd' | hide && minutes===0 → 'Xd Xh' → hide trailing zeros
# hide trailing zeros logic
# 隐藏末尾的0值units
# cascade hiding
days>0 → 'Xd' | hours>0 → 'Xh' | minutes>0 → 'Xm' → seconds → most significant only
# most significant only
# 只显示最大非零unit
# 单一unit
new Intl.NumberFormat expensive → cache formatter → reuse → consistent/inconsistent decimals → two caches
# Intl.NumberFormat expensive
# cache formatter
# two caches (consistent vs inconsistent)
(ms/1000).toFixed(1) → always 1 decimal → '1.2s' → sub-minute → TTFT/hook durations
# always 1 decimal place
# sub-minute timings
# fractional second meaningful
utils/format.ts (308 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