skills-experimental/activity-manager/SKILL.md
Activity time tracking for user vs CLI operations. Deduplicate overlapping activities. Track active time with timeout. Singleton instance. Use when managing user activity, tracking idle time, or handling away/return states.
npx skillsauth add bianhaifeng789-hue/openclaw-config activity-managerInstall 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.
追踪用户和 CLI 的活动时间,用于统计和报告。
场景:
Claude Code 方案:activityManager.ts + Singleton OpenClaw 飞书适配:飞书用户活动追踪 + Stats Heatmap
// 用户交互(打字、命令等)
recordUserActivity(): void {
// 不记录 CLI 活动期间的用户时间
if (!isCLIActive && lastUserActivityTime !== 0) {
const timeSinceLastActivity = (now - lastUserActivityTime) / 1000
// 只有在 timeout 窗口内才记录(5s)
if (timeSinceLastActivity < timeoutSeconds) {
activeTimeCounter.add(timeSinceLastActivity, { type: 'user' })
}
}
lastUserActivityTime = now
}
// CLI 执行(工具调用、AI 响应等)
startCLIActivity(operationId: string): void {
// 如果操作已存在,先结束(防止重叠)
if (activeOperations.has(operationId)) {
endCLIActivity(operationId)
}
const wasEmpty = activeOperations.size === 0
activeOperations.add(operationId)
if (wasEmpty) {
isCLIActive = true
lastCLIRecordedTime = now
}
}
endCLIActivity(operationId: string): void {
activeOperations.delete(operationId)
if (activeOperations.size === 0) {
// 记录 CLI 时间
const cliTime = (now - lastCLIRecordedTime) / 1000
activeTimeCounter.add(cliTime, { type: 'cli' })
isCLIActive = false
}
}
interface ActiveTimeCounter {
add(seconds: number, options: { type: 'user' | 'cli' }): void
getTotal(): { userTime: number; cliTime: number }
}
{
"config": {"wide_screen_mode": true},
"elements": [
{
"tag": "div",
"text": {
"tag": "lark_md",
"content": "**⏱️ Activity Summary**\n\n---\n\n**活跃时间统计**:\n\n| 类型 | 时间 | 占比 |\n|------|------|------|\n| **用户** | 15 分钟 | 25% |\n| **CLI** | 45 分钟 | 75% |\n| **总计** | 60 分钟 | 100% |\n\n---\n\n**当前状态**:\n• **CLI 活跃**:是\n• **活跃操作**:3 个\n• **最后用户活动**:2 分钟前"
}
}
]
}
Activity Manager:
1. 单例实例
2. 管理 active operations set
3. 追踪 last activity timestamps
4. Deduplicate overlapping activities
class ActivityManager {
private activeOperations = new Set<string>()
private lastUserActivityTime: number = 0
private lastCLIRecordedTime: number
private isCLIActive: boolean = false
private readonly USER_ACTIVITY_TIMEOUT_MS = 5000 // 5 seconds
// Singleton
static getInstance(): ActivityManager
}
// memory/activity-manager-state.json
{
"sessions": [
{
"sessionId": "session-1",
"userTime": 900, // seconds
"cliTime": 2700, // seconds
"startTime": "2026-04-12T00:00:00Z",
"endTime": "2026-04-12T01:00:00Z"
}
],
"stats": {
"totalUserTime": 0,
"totalCLITime": 0,
"totalSessions": 0
},
"current": {
"isCLIActive": false,
"activeOperations": [],
"lastUserActivity": null
}
}
| Claude Code | OpenClaw 飞书场景 | |-------------|------------------| | ActivityManager.getInstance() | Skill + 单例 | | recordUserActivity() | 飞书用户消息触发 | | startCLIActivity() | 工具调用开始 | | endCLIActivity() | 工具调用结束 | | USER_ACTIVITY_TIMEOUT_MS | 5s timeout |
此 Skill 在 heartbeat 时自动检查并记录活动时间。
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