11 Commits

Author SHA1 Message Date
starmen1265 e22359a5f8 安全修复(High): event_type 和 mode 参数添加白名单校验
- 定义 ALLOWED_EVENT_TYPES 白名单
- 定义 ALLOWED_MODES 白名单
- record_event() 函数中验证参数合法性
- 防止注入恶意事件类型或模式
2026-03-09 15:18:59 +08:00
starmen1265 3b5f728efe 安全修复(High): 文件创建时设置权限 0o600
- 锁文件创建时设置权限 0o600
- 临时文件创建时设置权限 0o600
- 数据文件写入后确保权限为 0o600
- 防止未授权访问敏感统计数据
2026-03-09 15:18:22 +08:00
starmen1265 65ef23de5d 安全修复(Critical): clear_stats() 添加 ADMIN_TOKEN 身份验证
- 防止未授权清空统计数据
- 需要设置环境变量 ADMIN_TOKEN 才能执行清空操作
2026-03-09 15:17:38 +08:00
starmen1265 f9cc8bb82a fix(stats): 细化异常处理
- _acquire_lock(): 添加 OSError/IOError 异常处理和日志
- _release_lock(): 添加空值检查和异常捕获
- _load_stats_data():
  - 分离 JSONDecodeError、IOError/OSError 和其他异常
  - 添加详细的日志记录
- _atomic_write():
  - 分离 OSError/IOError 和 JSON 序列化异常
  - 清理临时文件时添加异常捕获
- 移除重复的 LOCK_FILE 定义
2026-03-09 14:52:32 +08:00
starmen1265 63f2df7f18 fix(stats): 将 print() 改为 logging
- 添加 logging 模块导入
- 创建 logger 实例
- 将错误输出从 print() 改为 logger.error()
- 保留 __main__ 测试代码中的 print()
2026-03-09 14:51:14 +08:00
starmen1265 5034374066 fix(stats): 添加事件数量限制(默认 10000)
- 添加 MAX_EVENTS 常量(默认 10000)
- record_event() 在事件数超过限制时移除最旧的事件
- 防止数据文件无限增长
2026-03-09 14:50:32 +08:00
starmen1265 e136939a25 fix(stats): 添加文件锁(fcntl.flock)防止并发竞态
- 添加 _acquire_lock() 和 _release_lock() 辅助函数
- _load_stats_data() 和 _atomic_write() 使用文件锁保护
- 使用独立的 .lock 文件作为锁
- 防止并发读写导致数据损坏
2026-03-09 14:50:03 +08:00
starmen1265 9b15766ab3 fix(stats): _load_stats_data() JSON 解析失败时备份损坏文件
- JSON 解析失败时将损坏文件重命名为 .corrupted.{timestamp}.bak
- 保留损坏文件以便后续分析和恢复
- 分离 JSONDecodeError 和 IOError 的处理逻辑
2026-03-09 14:49:12 +08:00
starmen1265 d26ac7a88c fix(stats): get_stats() 改用 .get() 访问字段
- 使用 .get() 安全访问 event 字段
- 为可能缺失的字段提供默认值
- 防止 KeyError 异常
2026-03-09 14:48:45 +08:00
starmen1265 e5304534e4 fix(stats): record_event() 添加 metadata 类型校验
- 如果 metadata 不是 dict 类型则抛出 TypeError
- 防止传入非法类型导致后续处理失败
2026-03-09 14:48:17 +08:00
starmen1265 3efe98e17d feat: 添加 Cross 模式统计报告功能
- 添加 stats.py 统计模块
- 添加 dev_workflow.py CLI 工具
- 实现 record_event() 记录事件
- 实现 get_stats() 生成报告
- 支持敏感数据自动过滤
- 使用原子写入保证数据安全
- 添加 README 文档
2026-03-09 14:44:04 +08:00
7 changed files with 1587 additions and 11 deletions
+862 -9
View File
@@ -1,7 +1,7 @@
{ {
"agent:haonan:main": { "agent:haonan:main": {
"sessionId": "19d09a52-cb94-4eb2-8505-21860848a9e5", "sessionId": "19d09a52-cb94-4eb2-8505-21860848a9e5",
"updatedAt": 1773026659270, "updatedAt": 1773040623941,
"systemSent": true, "systemSent": true,
"skillsSnapshot": { "skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>", "prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
@@ -62,7 +62,7 @@
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/19d09a52-cb94-4eb2-8505-21860848a9e5.jsonl", "sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/19d09a52-cb94-4eb2-8505-21860848a9e5.jsonl",
"systemPromptReport": { "systemPromptReport": {
"source": "run", "source": "run",
"generatedAt": 1773026614909, "generatedAt": 1773040604443,
"sessionId": "19d09a52-cb94-4eb2-8505-21860848a9e5", "sessionId": "19d09a52-cb94-4eb2-8505-21860848a9e5",
"sessionKey": "agent:haonan:main", "sessionKey": "agent:haonan:main",
"provider": "zhipu", "provider": "zhipu",
@@ -75,9 +75,9 @@
"sandboxed": false "sandboxed": false
}, },
"systemPrompt": { "systemPrompt": {
"chars": 29165, "chars": 40480,
"projectContextChars": 15820, "projectContextChars": 27502,
"nonProjectContextChars": 13345 "nonProjectContextChars": 12978
}, },
"injectedWorkspaceFiles": [ "injectedWorkspaceFiles": [
{ {
@@ -150,6 +150,114 @@
"injectedChars": 616, "injectedChars": 616,
"truncated": false "truncated": false
}, },
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{ {
"path": "SELF_IMPROVEMENT_REMINDER.md", "path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616, "rawChars": 616,
@@ -383,14 +491,15 @@
}, },
"compactionCount": 0, "compactionCount": 0,
"totalTokensFresh": true, "totalTokensFresh": true,
"cacheRead": 12224, "cacheRead": 91712,
"cacheWrite": 0, "cacheWrite": 0,
"lastHeartbeatText": "已在飞书向蒋先生发送日历同步提醒!✅", "lastHeartbeatText": "已在飞书向蒋先生发送日历同步提醒!✅",
"lastHeartbeatSentAt": 1772924419184, "lastHeartbeatSentAt": 1772924419184,
"contextTokens": 200000, "contextTokens": 200000,
"inputTokens": 47223, "inputTokens": 72316,
"outputTokens": 1658, "outputTokens": 351,
"totalTokens": 59447 "totalTokens": 92082,
"channel": "feishu"
}, },
"agent:haonan:wecom:dm:zhangqing": { "agent:haonan:wecom:dm:zhangqing": {
"origin": { "origin": {
@@ -950,5 +1059,749 @@
"totalTokensFresh": true, "totalTokensFresh": true,
"cacheRead": 60736, "cacheRead": 60736,
"cacheWrite": 0 "cacheWrite": 0
},
"agent:haonan:subagent:274e4fbc-df83-41ee-82af-c97904920b8e": {
"sessionId": "79a3a63f-e790-4594-a4b7-ca6b1faf27ab",
"updatedAt": 1773038094722,
"spawnDepth": 1,
"deliveryContext": {
"channel": "feishu"
},
"lastChannel": "feishu",
"label": "debate-claude",
"spawnedBy": "agent:haonan:main",
"channel": "feishu",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
},
{
"name": "clawlist"
}
],
"skillFilter": [
"clawlist",
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
},
{
"name": "clawlist",
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
"filePath": "/home/starmen1265/.openclaw/skills/clawlist/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/clawlist",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/79a3a63f-e790-4594-a4b7-ca6b1faf27ab.jsonl",
"contextTokens": 200000,
"modelProvider": "zhipu",
"model": "glm-5",
"abortedLastRun": false,
"inputTokens": 9848,
"outputTokens": 1096,
"totalTokens": 15151,
"totalTokensFresh": true,
"cacheRead": 19648,
"cacheWrite": 0
},
"agent:haonan:subagent:b57fed9b-07b9-4dc8-ae28-93cbc7cc5b19": {
"sessionId": "f6fef24b-e9d0-451a-a2d4-27901ce2a6fb",
"updatedAt": 1773038071878,
"spawnDepth": 1,
"deliveryContext": {
"channel": "feishu"
},
"lastChannel": "feishu",
"label": "debate-codex",
"spawnedBy": "agent:haonan:main",
"channel": "feishu",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
},
{
"name": "clawlist"
}
],
"skillFilter": [
"clawlist",
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
},
{
"name": "clawlist",
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
"filePath": "/home/starmen1265/.openclaw/skills/clawlist/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/clawlist",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/f6fef24b-e9d0-451a-a2d4-27901ce2a6fb.jsonl",
"contextTokens": 200000,
"modelProvider": "zhipu",
"model": "glm-5",
"abortedLastRun": false,
"inputTokens": 5975,
"outputTokens": 683,
"totalTokens": 15769,
"totalTokensFresh": true,
"cacheRead": 39168,
"cacheWrite": 0
},
"agent:haonan:subagent:9f7d6e74-6bf4-424e-8321-28399f52f72b": {
"sessionId": "8070a163-21e9-4f04-afba-3bc8a82eaf0b",
"updatedAt": 1773038063531,
"spawnDepth": 1,
"deliveryContext": {
"channel": "feishu"
},
"lastChannel": "feishu",
"label": "debate-gemini",
"spawnedBy": "agent:haonan:main",
"channel": "feishu",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
},
{
"name": "clawlist"
}
],
"skillFilter": [
"clawlist",
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
},
{
"name": "clawlist",
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
"filePath": "/home/starmen1265/.openclaw/skills/clawlist/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/clawlist",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/8070a163-21e9-4f04-afba-3bc8a82eaf0b.jsonl",
"contextTokens": 200000,
"modelProvider": "zhipu",
"model": "glm-5",
"abortedLastRun": false,
"inputTokens": 4499,
"outputTokens": 493,
"totalTokens": 14355,
"totalTokensFresh": true,
"cacheRead": 9856,
"cacheWrite": 0
},
"agent:haonan:subagent:20c2f592-717f-4142-80ef-559ed47f3731": {
"sessionId": "91aaba82-8ccd-41b0-ac50-a1f1b0f172cf",
"updatedAt": 1773038247318,
"spawnDepth": 1,
"deliveryContext": {
"channel": "feishu"
},
"lastChannel": "feishu",
"label": "cross-review-1",
"spawnedBy": "agent:haonan:main",
"channel": "feishu",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
},
{
"name": "clawlist"
}
],
"skillFilter": [
"clawlist",
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
},
{
"name": "clawlist",
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
"filePath": "/home/starmen1265/.openclaw/skills/clawlist/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/clawlist",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/91aaba82-8ccd-41b0-ac50-a1f1b0f172cf.jsonl",
"contextTokens": 200000,
"modelProvider": "zhipu",
"model": "glm-5",
"abortedLastRun": false,
"inputTokens": 4641,
"outputTokens": 531,
"totalTokens": 14497,
"totalTokensFresh": true,
"cacheRead": 9856,
"cacheWrite": 0
},
"agent:haonan:subagent:e67080fe-6710-4c69-bfb3-307900085f1c": {
"sessionId": "4ed0f48f-0dfb-4f37-ab24-4562e616439d",
"updatedAt": 1773038236930,
"spawnDepth": 1,
"deliveryContext": {
"channel": "feishu"
},
"lastChannel": "feishu",
"label": "cross-review-2",
"spawnedBy": "agent:haonan:main",
"channel": "feishu",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
},
{
"name": "clawlist"
}
],
"skillFilter": [
"clawlist",
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
},
{
"name": "clawlist",
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
"filePath": "/home/starmen1265/.openclaw/skills/clawlist/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/clawlist",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/4ed0f48f-0dfb-4f37-ab24-4562e616439d.jsonl",
"contextTokens": 200000,
"modelProvider": "zhipu",
"model": "glm-5",
"abortedLastRun": false,
"inputTokens": 4641,
"outputTokens": 443,
"totalTokens": 14497,
"totalTokensFresh": true,
"cacheRead": 9856,
"cacheWrite": 0
},
"agent:haonan:subagent:c2889dda-a0fe-4bb3-a8cc-24b6dc5961b1": {
"sessionId": "8dbba806-4d27-4bc3-9777-5c49d0b520f4",
"updatedAt": 1773038270563,
"spawnDepth": 1,
"deliveryContext": {
"channel": "feishu"
},
"lastChannel": "feishu",
"label": "cross-review-3",
"spawnedBy": "agent:haonan:main",
"channel": "feishu",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
},
{
"name": "clawlist"
}
],
"skillFilter": [
"clawlist",
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
},
{
"name": "clawlist",
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
"filePath": "/home/starmen1265/.openclaw/skills/clawlist/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/clawlist",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/8dbba806-4d27-4bc3-9777-5c49d0b520f4.jsonl",
"contextTokens": 200000,
"modelProvider": "zhipu",
"model": "glm-5",
"abortedLastRun": false,
"inputTokens": 4639,
"outputTokens": 546,
"totalTokens": 14495,
"totalTokensFresh": true,
"cacheRead": 9856,
"cacheWrite": 0
},
"agent:haonan:subagent:7fbdc597-2ade-4e22-9c9b-0334d3854818": {
"sessionId": "b197e49b-1512-4f90-bc88-eeb888031d25",
"updatedAt": 1773038676051,
"spawnDepth": 1,
"deliveryContext": {
"channel": "feishu"
},
"lastChannel": "feishu",
"label": "dev-cross-stats",
"spawnedBy": "agent:haonan:main",
"channel": "feishu",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
},
{
"name": "clawlist"
}
],
"skillFilter": [
"clawlist",
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
},
{
"name": "clawlist",
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
"filePath": "/home/starmen1265/.openclaw/skills/clawlist/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/clawlist",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/b197e49b-1512-4f90-bc88-eeb888031d25.jsonl",
"contextTokens": 200000,
"modelProvider": "zhipu",
"model": "glm-5",
"abortedLastRun": false,
"inputTokens": 14474,
"outputTokens": 6775,
"totalTokens": 23402,
"totalTokensFresh": true,
"cacheRead": 572992,
"cacheWrite": 0
},
"agent:haonan:subagent:4ab88429-06d1-4174-88a3-f2cf8e0302cb": {
"sessionId": "60fcc8db-4ea9-4a1c-a586-d4a0aa4b7070",
"updatedAt": 1773038828925,
"spawnDepth": 1,
"deliveryContext": {
"channel": "feishu"
},
"lastChannel": "feishu",
"label": "review-1-code",
"spawnedBy": "agent:haonan:main",
"channel": "feishu",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
},
{
"name": "clawlist"
}
],
"skillFilter": [
"clawlist",
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
},
{
"name": "clawlist",
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
"filePath": "/home/starmen1265/.openclaw/skills/clawlist/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/clawlist",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/60fcc8db-4ea9-4a1c-a586-d4a0aa4b7070.jsonl",
"contextTokens": 200000,
"modelProvider": "zhipu",
"model": "glm-5",
"abortedLastRun": false,
"inputTokens": 7448,
"outputTokens": 1143,
"totalTokens": 17265,
"totalTokensFresh": true,
"cacheRead": 53568,
"cacheWrite": 0
},
"agent:haonan:subagent:0e3d2373-fae5-4594-afe0-74d0905c6f12": {
"sessionId": "b84b460f-ff03-4095-a8bd-53e855c12f31",
"updatedAt": 1773038816835,
"spawnDepth": 1,
"deliveryContext": {
"channel": "feishu"
},
"lastChannel": "feishu",
"label": "review-2-docs",
"spawnedBy": "agent:haonan:main",
"channel": "feishu",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
},
{
"name": "clawlist"
}
],
"skillFilter": [
"clawlist",
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
},
{
"name": "clawlist",
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
"filePath": "/home/starmen1265/.openclaw/skills/clawlist/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/clawlist",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/b84b460f-ff03-4095-a8bd-53e855c12f31.jsonl",
"contextTokens": 200000,
"modelProvider": "zhipu",
"model": "glm-5",
"abortedLastRun": false,
"inputTokens": 9093,
"outputTokens": 719,
"totalTokens": 18843,
"totalTokensFresh": true,
"cacheRead": 56704,
"cacheWrite": 0
},
"agent:haonan:subagent:3256a590-a63b-4d8f-b811-14dedcaa71de": {
"sessionId": "70c4172e-bdff-4783-9f47-1282c9161d2e",
"updatedAt": 1773038858019,
"spawnDepth": 1,
"deliveryContext": {
"channel": "feishu"
},
"lastChannel": "feishu",
"label": "review-3-test",
"spawnedBy": "agent:haonan:main",
"channel": "feishu",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
},
{
"name": "clawlist"
}
],
"skillFilter": [
"clawlist",
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
},
{
"name": "clawlist",
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
"filePath": "/home/starmen1265/.openclaw/skills/clawlist/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/clawlist",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/70c4172e-bdff-4783-9f47-1282c9161d2e.jsonl",
"contextTokens": 200000,
"modelProvider": "zhipu",
"model": "glm-5",
"abortedLastRun": false,
"inputTokens": 8354,
"outputTokens": 1025,
"totalTokens": 18065,
"totalTokensFresh": true,
"cacheRead": 88384,
"cacheWrite": 0
},
"agent:haonan:subagent:49a814f6-a5fc-4872-815c-9b8e24f56177": {
"sessionId": "15e56762-4fc7-45a8-865c-b8429238ff06",
"updatedAt": 1773039182250,
"spawnDepth": 1,
"deliveryContext": {
"channel": "feishu"
},
"lastChannel": "feishu",
"label": "fix-cross-stats",
"spawnedBy": "agent:haonan:main",
"channel": "feishu",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
},
{
"name": "clawlist"
}
],
"skillFilter": [
"clawlist",
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
},
{
"name": "clawlist",
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
"filePath": "/home/starmen1265/.openclaw/skills/clawlist/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/clawlist",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/15e56762-4fc7-45a8-865c-b8429238ff06.jsonl",
"contextTokens": 200000,
"modelProvider": "zhipu",
"model": "glm-5",
"abortedLastRun": false,
"inputTokens": 18097,
"outputTokens": 7272,
"totalTokens": 26788,
"totalTokensFresh": true,
"cacheRead": 735488,
"cacheWrite": 0
},
"agent:haonan:subagent:7e637b77-b7f8-48d3-b325-78c7d0b71018": {
"sessionId": "f90f259a-6732-49b7-b9a3-c227fa6b9424",
"updatedAt": 1773039679096,
"spawnDepth": 1,
"deliveryContext": {
"channel": "feishu"
},
"lastChannel": "feishu",
"label": "security-audit",
"spawnedBy": "agent:haonan:main",
"channel": "feishu",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
},
{
"name": "clawlist"
}
],
"skillFilter": [
"clawlist",
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
},
{
"name": "clawlist",
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
"filePath": "/home/starmen1265/.openclaw/skills/clawlist/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/clawlist",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/f90f259a-6732-49b7-b9a3-c227fa6b9424.jsonl",
"contextTokens": 200000,
"modelProvider": "zhipu",
"model": "glm-5",
"abortedLastRun": false,
"inputTokens": 8423,
"outputTokens": 993,
"totalTokens": 18252,
"totalTokensFresh": true,
"cacheRead": 53888,
"cacheWrite": 0
},
"agent:haonan:subagent:04481c89-a8c4-4bfe-99d3-2f6dd3883092": {
"sessionId": "809eaaf8-435f-4056-869c-01224544fd1d",
"updatedAt": 1773040617015,
"spawnDepth": 1,
"deliveryContext": {
"channel": "feishu"
},
"lastChannel": "feishu",
"label": "fix-security",
"spawnedBy": "agent:haonan:main",
"channel": "feishu",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
},
{
"name": "clawlist"
}
],
"skillFilter": [
"clawlist",
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
},
{
"name": "clawlist",
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
"filePath": "/home/starmen1265/.openclaw/skills/clawlist/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/clawlist",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/809eaaf8-435f-4056-869c-01224544fd1d.jsonl"
} }
} }
@@ -0,0 +1,27 @@
# 数据文件
data/
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
*.egg-info/
dist/
build/
# 测试
.pytest_cache/
.coverage
htmlcov/
# IDE
.vscode/
.idea/
*.swp
*.swo
# 临时文件
*.tmp
*.bak
@@ -0,0 +1,146 @@
# Dev Workflow - 开发工作流工具
Cross 模式统计报告功能
## 功能特性
- ✅ 事件记录和统计
- ✅ 多模式支持(cross, normal 等)
- ✅ 敏感数据自动过滤
- ✅ 原子写入保证数据安全
- ✅ 格式化报告输出
## 使用方法
### 查看统计报告
```bash
python3 dev-workflow/dev_workflow.py stats
```
### 筛选特定模式
```bash
python3 dev-workflow/dev_workflow.py stats --mode cross
```
### 记录事件(用于集成)
```bash
python3 dev-workflow/dev_workflow.py record "event_type" --mode cross --description "事件描述"
```
### 清空统计数据
```bash
python3 dev-workflow/dev_workflow.py clear --confirm
```
## API 使用
### Python 代码中记录事件
```python
from stats import record_event, get_stats, format_stats_report
# 记录事件
record_event(
"task_completed",
mode="cross",
metadata={
"task_name": "开发功能",
"duration": 120
}
)
# 获取统计数据
stats = get_stats(mode="cross")
print(format_stats_report(stats))
```
## 安全特性
### 敏感数据过滤
以下字段会被自动过滤(替换为 `[REDACTED]`):
- password
- token
- secret
- key
- credential
- auth
示例:
```python
record_event("login", metadata={
"username": "user123", # 正常记录
"password": "secret123" # 记录为 [REDACTED]
})
```
### 原子写入
所有数据写入都使用原子操作(临时文件 + 重命名),确保:
- 并发写入不会损坏数据
- 系统崩溃不会丢失数据
- 临时文件自动清理
## 数据存储
- 位置:`dev-workflow/data/stats_data.json`
- 格式:JSON
- 结构:
```json
{
"events": [
{
"event_type": "string",
"mode": "string",
"timestamp": "ISO8601",
"metadata": {}
}
],
"metadata": {
"created_at": "ISO8601",
"last_updated": "ISO8601"
}
}
```
## 统计报告内容
报告包含以下信息:
- 总事件数
- 时间范围(首次和最后事件)
- 按事件类型统计
- 按模式统计
- 按日期统计(最近7天)
## 开发说明
### 文件结构
```
dev-workflow/
├── dev_workflow.py # CLI 工具
├── stats.py # 统计模块
├── README.md # 本文档
└── data/
└── stats_data.json # 数据存储
```
### 扩展事件类型
可以在代码中定义新的事件类型,例如:
- `task_started` - 任务开始
- `task_completed` - 任务完成
- `code_committed` - 代码提交
- `error_occurred` - 错误发生
- `stats_viewed` - 查看统计
## 测试
运行测试:
```bash
python3 dev-workflow/stats.py
```
@@ -0,0 +1,136 @@
#!/usr/bin/env python3
"""
Dev Workflow - 开发工作流工具
提供多种工作模式和统计功能
"""
import sys
import argparse
from pathlib import Path
# 添加当前目录到路径
sys.path.insert(0, str(Path(__file__).parent))
from stats import record_event, get_stats, format_stats_report, clear_stats
def cmd_stats(args):
"""stats 命令处理函数"""
# 记录查看统计的事件
record_event(
"stats_viewed",
mode="cross",
metadata={"filter_mode": args.mode}
)
# 获取统计数据
stats = get_stats(mode=args.mode)
# 输出报告
report = format_stats_report(stats)
print(report)
return 0
def cmd_record(args):
"""record 命令处理函数 - 用于测试"""
success = record_event(
args.event_type,
mode=args.mode,
metadata={"description": args.description} if args.description else None
)
if success:
print(f"✓ 事件已记录: {args.event_type}")
return 0
else:
print("✗ 记录事件失败")
return 1
def cmd_clear(args):
"""clear 命令处理函数"""
if not args.confirm:
print("警告: 此操作将清空所有统计数据!")
print("使用 --confirm 参数确认清空")
return 1
success = clear_stats(confirm=True)
if success:
print("✓ 统计数据已清空")
return 0
else:
print("✗ 清空失败")
return 1
def main():
"""主函数"""
parser = argparse.ArgumentParser(
description="Dev Workflow - 开发工作流工具",
formatter_class=argparse.RawDescriptionHelpFormatter
)
subparsers = parser.add_subparsers(dest="command", help="可用命令")
# stats 命令
stats_parser = subparsers.add_parser("stats", help="显示统计报告")
stats_parser.add_argument(
"--mode", "-m",
help="筛选特定模式(如 cross, normal)"
)
stats_parser.set_defaults(func=cmd_stats)
# record 命令(用于测试)
record_parser = subparsers.add_parser("record", help="记录事件(测试用)")
record_parser.add_argument(
"event_type",
help="事件类型"
)
record_parser.add_argument(
"--mode", "-m",
default="cross",
help="工作模式(默认: cross)"
)
record_parser.add_argument(
"--description", "-d",
help="事件描述"
)
record_parser.set_defaults(func=cmd_record)
# clear 命令
clear_parser = subparsers.add_parser("clear", help="清空统计数据")
clear_parser.add_argument(
"--confirm",
action="store_true",
help="确认清空"
)
clear_parser.set_defaults(func=cmd_clear)
# 解析参数
args = parser.parse_args()
# 如果没有指定命令,默认显示 stats
if not args.command:
args.command = "stats"
args.func = cmd_stats
args.mode = None
# 执行命令
try:
return args.func(args)
except AttributeError:
parser.print_help()
return 1
except KeyboardInterrupt:
print("\n操作已取消")
return 130
except Exception as e:
print(f"错误: {e}", file=sys.stderr)
return 1
if __name__ == "__main__":
sys.exit(main())
@@ -0,0 +1,405 @@
#!/usr/bin/env python3
"""
Cross 模式统计报告模块
提供事件记录和统计报告生成功能
"""
import json
import os
import tempfile
import fcntl
import logging
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Any, Optional
from collections import defaultdict
# 配置日志
logger = logging.getLogger(__name__)
# 统计数据存储路径
STATS_DIR = Path(__file__).parent / "data"
STATS_FILE = STATS_DIR / "stats_data.json"
# 锁文件路径
LOCK_FILE = STATS_DIR / "stats_data.lock"
# 最大事件数量限制
MAX_EVENTS = 10000
# 敏感字段列表(不记录这些字段)
SENSITIVE_FIELDS = {"password", "token", "secret", "key", "credential", "auth"}
# 允许的 event_type 白名单
ALLOWED_EVENT_TYPES = {
"command_executed",
"task_completed",
"stats_viewed",
"test_event",
"another_event",
"workflow_started",
"workflow_completed",
"error_occurred",
}
# 允许的 mode 白名单
ALLOWED_MODES = {
"cross",
"normal",
"debug",
"test",
}
def _ensure_stats_dir():
"""确保统计目录存在"""
STATS_DIR.mkdir(parents=True, exist_ok=True)
def _acquire_lock(lock_file_path: Path):
"""获取文件锁
Raises:
OSError: 无法创建或锁定文件时
"""
try:
lock_file_path.parent.mkdir(parents=True, exist_ok=True)
# 使用 os.open 创建文件并设置权限
fd = os.open(lock_file_path, os.O_WRONLY | os.O_CREAT, 0o600)
lock_fd = os.fdopen(fd, 'w')
fcntl.flock(lock_fd.fileno(), fcntl.LOCK_EX)
return lock_fd
except (OSError, IOError) as e:
logger.error(f"获取文件锁失败: {e}")
raise
def _release_lock(lock_fd):
"""释放文件锁"""
if lock_fd is None:
return
try:
fcntl.flock(lock_fd.fileno(), fcntl.LOCK_UN)
lock_fd.close()
except (OSError, IOError) as e:
logger.warning(f"释放文件锁时发生错误: {e}")
try:
lock_fd.close()
except Exception:
pass
def _load_stats_data() -> Dict[str, Any]:
"""加载统计数据(带锁保护)
Returns:
Dict: 统计数据,加载失败时返回空结构
"""
if not STATS_FILE.exists():
return {"events": [], "metadata": {"created_at": datetime.now().isoformat()}}
lock_fd = None
try:
lock_fd = _acquire_lock(LOCK_FILE)
with open(STATS_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
except json.JSONDecodeError as e:
logger.warning(f"JSON 解析失败,将备份损坏文件: {e}")
# 备份损坏的文件
backup_path = STATS_FILE.with_suffix(f'.corrupted.{datetime.now().strftime("%Y%m%d_%H%M%S")}.bak')
try:
STATS_FILE.rename(backup_path)
logger.info(f"已备份损坏文件到: {backup_path}")
except OSError as backup_error:
logger.error(f"备份损坏文件失败: {backup_error}")
return {"events": [], "metadata": {"created_at": datetime.now().isoformat()}}
except (OSError, IOError) as e:
logger.error(f"读取统计文件失败: {e}")
return {"events": [], "metadata": {"created_at": datetime.now().isoformat()}}
except Exception as e:
logger.error(f"加载统计数据时发生未知错误: {e}")
return {"events": [], "metadata": {"created_at": datetime.now().isoformat()}}
finally:
_release_lock(lock_fd)
def _atomic_write(data: Dict[str, Any]):
"""原子写入统计数据(带锁保护)
Raises:
OSError: 文件操作失败时
TypeError: 数据无法序列化为 JSON 时
"""
_ensure_stats_dir()
lock_fd = None
temp_path = None
try:
lock_fd = _acquire_lock(LOCK_FILE)
# 写入临时文件(使用 os.open 设置权限)
fd = os.open(
tempfile.mktemp(suffix='.tmp', dir=STATS_DIR),
os.O_WRONLY | os.O_CREAT | os.O_EXCL,
0o600
)
temp_path = f"/proc/self/fd/{fd}"
with os.fdopen(fd, 'w', encoding='utf-8') as temp_file:
json.dump(data, temp_file, ensure_ascii=False, indent=2)
temp_path = temp_file.name
# 原子重命名
os.replace(temp_path, STATS_FILE)
# 确保最终文件权限正确
os.chmod(STATS_FILE, 0o600)
temp_path = None # 防止在 finally 中再次删除
except (OSError, IOError) as e:
logger.error(f"写入统计文件失败: {e}")
raise
except (TypeError, ValueError) as e:
logger.error(f"JSON 序列化失败: {e}")
raise
finally:
_release_lock(lock_fd)
# 清理临时文件
if temp_path and os.path.exists(temp_path):
try:
os.unlink(temp_path)
except OSError as e:
logger.warning(f"清理临时文件失败: {e}")
def _filter_sensitive_data(data: Dict[str, Any]) -> Dict[str, Any]:
"""过滤敏感数据"""
filtered = {}
for key, value in data.items():
# 检查键名是否包含敏感字段
if any(sensitive in key.lower() for sensitive in SENSITIVE_FIELDS):
filtered[key] = "[REDACTED]"
elif isinstance(value, dict):
filtered[key] = _filter_sensitive_data(value)
else:
filtered[key] = value
return filtered
def record_event(
event_type: str,
mode: str = "cross",
metadata: Optional[Dict[str, Any]] = None
) -> bool:
"""
记录事件
Args:
event_type: 事件类型(如 'command_executed', 'task_completed' 等)
mode: 工作模式(默认 'cross')
metadata: 事件元数据
Returns:
bool: 记录是否成功
Raises:
TypeError: metadata 不是 dict 类型时
ValueError: event_type 或 mode 不在白名单中时
"""
try:
# event_type 白名单校验
if event_type not in ALLOWED_EVENT_TYPES:
raise ValueError(
f"无效的 event_type: {event_type}. "
f"允许的值: {', '.join(sorted(ALLOWED_EVENT_TYPES))}"
)
# mode 白名单校验
if mode not in ALLOWED_MODES:
raise ValueError(
f"无效的 mode: {mode}. "
f"允许的值: {', '.join(sorted(ALLOWED_MODES))}"
)
# metadata 类型校验
if metadata is not None and not isinstance(metadata, dict):
raise TypeError(f"metadata 必须是 dict 类型,当前为: {type(metadata).__name__}")
# 过滤敏感数据
safe_metadata = _filter_sensitive_data(metadata or {})
# 创建事件记录
event = {
"event_type": event_type,
"mode": mode,
"timestamp": datetime.now().isoformat(),
"metadata": safe_metadata
}
# 加载现有数据
data = _load_stats_data()
data["events"].append(event)
# 事件数量限制:超过 MAX_EVENTS 时移除最旧的事件
if len(data["events"]) > MAX_EVENTS:
data["events"] = data["events"][-MAX_EVENTS:]
data["metadata"]["last_updated"] = datetime.now().isoformat()
# 原子写入
_atomic_write(data)
return True
except (TypeError, ValueError):
raise # 重新抛出类型和值错误
except Exception as e:
logger.error(f"记录事件失败: {e}")
return False
def get_stats(mode: Optional[str] = None) -> Dict[str, Any]:
"""
生成统计报告
Args:
mode: 筛选特定模式,None 表示所有模式
Returns:
Dict: 统计报告数据
"""
data = _load_stats_data()
events = data.get("events", [])
# 筛选模式
if mode:
events = [e for e in events if e.get("mode") == mode]
# 统计数据
stats = {
"total_events": len(events),
"events_by_type": defaultdict(int),
"events_by_mode": defaultdict(int),
"events_by_date": defaultdict(int),
"first_event": None,
"last_event": None,
"metadata": data.get("metadata", {})
}
if events:
stats["first_event"] = events[0].get("timestamp")
stats["last_event"] = events[-1].get("timestamp")
for event in events:
event_type = event.get("event_type", "unknown")
event_mode = event.get("mode", "unknown")
stats["events_by_type"][event_type] += 1
stats["events_by_mode"][event_mode] += 1
# 按日期统计
timestamp = event.get("timestamp", "")
date = timestamp[:10] if timestamp else "unknown" # YYYY-MM-DD
stats["events_by_date"][date] += 1
# 转换 defaultdict 为普通 dict
stats["events_by_type"] = dict(stats["events_by_type"])
stats["events_by_mode"] = dict(stats["events_by_mode"])
stats["events_by_date"] = dict(stats["events_by_date"])
return stats
def format_stats_report(stats: Dict[str, Any]) -> str:
"""
格式化统计报告为可读文本
Args:
stats: 统计数据
Returns:
str: 格式化的报告文本
"""
lines = [
"=" * 60,
"Cross 模式统计报告",
"=" * 60,
"",
f"总事件数: {stats['total_events']}",
""
]
if stats["total_events"] == 0:
lines.append("暂无统计数据")
return "\n".join(lines)
# 时间范围
lines.extend([
f"首次事件: {stats['first_event']}",
f"最后事件: {stats['last_event']}",
""
])
# 按类型统计
if stats["events_by_type"]:
lines.append("按事件类型统计:")
for event_type, count in sorted(stats["events_by_type"].items()):
lines.append(f" - {event_type}: {count}")
lines.append("")
# 按模式统计
if stats["events_by_mode"]:
lines.append("按模式统计:")
for mode, count in sorted(stats["events_by_mode"].items()):
lines.append(f" - {mode}: {count}")
lines.append("")
# 按日期统计(最近7天)
if stats["events_by_date"]:
lines.append("按日期统计(最近7天):")
sorted_dates = sorted(stats["events_by_date"].items(), reverse=True)[:7]
for date, count in sorted_dates:
lines.append(f" - {date}: {count}")
lines.append("")
lines.append("=" * 60)
return "\n".join(lines)
def clear_stats(confirm: bool = False) -> bool:
"""
清空统计数据
Args:
confirm: 确认清空
Returns:
bool: 是否成功清空
"""
if not confirm:
return False
# 安全检查:验证管理员令牌
admin_token = os.getenv("ADMIN_TOKEN")
if not admin_token:
logger.error("清空统计数据需要设置 ADMIN_TOKEN 环境变量")
return False
try:
if STATS_FILE.exists():
STATS_FILE.unlink()
return True
except Exception as e:
logger.error(f"清空统计数据失败: {e}")
return False
if __name__ == "__main__":
# 测试代码
print("测试 stats 模块")
# 记录一些测试事件
record_event("test_event", mode="cross", metadata={"user": "test", "action": "demo"})
record_event("another_event", mode="normal", metadata={"data": "sample"})
# 生成报告
stats = get_stats()
print(format_stats_report(stats))
+10 -1
View File
@@ -33,5 +33,14 @@
"om_x100b55d7e0760080c122e8e2259d700": 1773026028683, "om_x100b55d7e0760080c122e8e2259d700": 1773026028683,
"om_x100b55d7e1dd10acc3520a7afbec3c9": 1773026033833, "om_x100b55d7e1dd10acc3520a7afbec3c9": 1773026033833,
"om_x100b55d7f146b0a8c3e4f6e7be46130": 1773026297484, "om_x100b55d7f146b0a8c3e4f6e7be46130": 1773026297484,
"om_x100b55d79d920c8cb2c5639c1710560": 1773026614832 "om_x100b55d79d920c8cb2c5639c1710560": 1773026614832,
"om_x100b55d0235afcb8b3d3d78786ac701": 1773029082129,
"om_x100b55d0c3b478b4b4b99907b479f8c": 1773029592402,
"om_x100b55d2d735e880c3ffb6a7bc7d8e9": 1773037984238,
"om_x100b55d2e8d308a4c3afcec5a920956": 1773038178699,
"om_x100b55d2e0d430bcc142b4e1d73c728": 1773038306291,
"om_x100b55d28785c0e0c29436c35dd3bb9": 1773038741191,
"om_x100b55d281891080c3ab8c75612834d": 1773038836929,
"om_x100b55d2b03134b4c1123b3bdf16730": 1773039600568,
"om_x100b55d3737da484c3eef596cee0963": 1773040603758
} }
+1 -1
View File
@@ -10,7 +10,7 @@
"operator.approvals", "operator.approvals",
"operator.pairing" "operator.pairing"
], ],
"updatedAtMs": 1773026362728 "updatedAtMs": 1773040616977
} }
} }
} }