principles-disciple 1.5.4 → 1.6.0

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.
Files changed (43) hide show
  1. package/dist/commands/context.d.ts +5 -0
  2. package/dist/commands/context.js +308 -0
  3. package/dist/commands/focus.d.ts +14 -0
  4. package/dist/commands/focus.js +579 -0
  5. package/dist/commands/pain.js +135 -6
  6. package/dist/commands/rollback.d.ts +19 -0
  7. package/dist/commands/rollback.js +119 -0
  8. package/dist/core/config.d.ts +32 -0
  9. package/dist/core/config.js +47 -0
  10. package/dist/core/event-log.d.ts +21 -1
  11. package/dist/core/event-log.js +316 -0
  12. package/dist/core/focus-history.d.ts +65 -0
  13. package/dist/core/focus-history.js +266 -0
  14. package/dist/core/init.js +30 -7
  15. package/dist/core/migration.js +0 -2
  16. package/dist/core/path-resolver.d.ts +3 -0
  17. package/dist/core/path-resolver.js +20 -0
  18. package/dist/hooks/gate.js +203 -1
  19. package/dist/hooks/llm.d.ts +8 -0
  20. package/dist/hooks/llm.js +234 -1
  21. package/dist/hooks/message-sanitize.d.ts +3 -0
  22. package/dist/hooks/message-sanitize.js +37 -0
  23. package/dist/hooks/prompt.d.ts +12 -0
  24. package/dist/hooks/prompt.js +309 -135
  25. package/dist/hooks/subagent.d.ts +9 -2
  26. package/dist/hooks/subagent.js +13 -2
  27. package/dist/i18n/commands.js +32 -20
  28. package/dist/index.js +181 -4
  29. package/dist/service/empathy-observer-manager.d.ts +42 -0
  30. package/dist/service/empathy-observer-manager.js +147 -0
  31. package/dist/service/evolution-worker.d.ts +1 -0
  32. package/dist/service/evolution-worker.js +4 -2
  33. package/dist/tools/deep-reflect.js +80 -0
  34. package/dist/types/event-types.d.ts +77 -2
  35. package/dist/types/event-types.js +33 -0
  36. package/dist/types.d.ts +42 -0
  37. package/dist/types.js +19 -1
  38. package/openclaw.plugin.json +1 -1
  39. package/package.json +3 -3
  40. package/templates/langs/zh/core/HEARTBEAT.md +28 -4
  41. package/templates/pain_settings.json +54 -2
  42. package/templates/workspace/.principles/PROFILE.json +2 -0
  43. package/templates/workspace/okr/CURRENT_FOCUS.md +57 -0
@@ -8,6 +8,65 @@ function createProgressBar(value, max, length = 10) {
8
8
  const emptyLength = length - filledLength;
9
9
  return `[${'█'.repeat(filledLength)}${'░'.repeat(emptyLength)}]`;
10
10
  }
11
+ /**
12
+ * Creates a mini bar for daily trends
13
+ */
14
+ function createMiniBar(count, max, length = 6) {
15
+ const filledLength = Math.round((count / max) * length);
16
+ return '█'.repeat(filledLength) + '░'.repeat(length - filledLength);
17
+ }
18
+ /**
19
+ * Format empathy stats for display
20
+ */
21
+ function formatEmpathyCard(stats, range, isZh) {
22
+ if (stats.totalEvents === 0 && stats.dedupedCount === 0) {
23
+ return isZh
24
+ ? `🫀 **情绪事件统计** (${range})\n 暂无数据`
25
+ : `🫀 **Empathy Events** (${range})\n No data available`;
26
+ }
27
+ const lines = [];
28
+ lines.push(isZh ? `🫀 **情绪事件统计** (${range})` : `🫀 **Empathy Events** (${range})`);
29
+ lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
30
+ // Total events
31
+ const totalLabel = isZh ? '📊 总事件' : '📊 Total Events';
32
+ lines.push(`${totalLabel}: ${stats.totalEvents} 次`);
33
+ lines.push(` ├─ 😟 mild: ${stats.bySeverity.mild} 次 (${stats.scoreBySeverity.mild}分)`);
34
+ lines.push(` ├─ 😠 moderate: ${stats.bySeverity.moderate} 次 (${stats.scoreBySeverity.moderate}分)`);
35
+ lines.push(` └─ 😡 severe: ${stats.bySeverity.severe} 次 (${stats.scoreBySeverity.severe}分)`);
36
+ lines.push('');
37
+ // Dedupe hit rate
38
+ const dedupeRate = (stats.dedupeHitRate * 100).toFixed(0);
39
+ const dedupeLabel = isZh ? '🔄 去重命中率' : '🔄 Dedupe Hit Rate';
40
+ lines.push(`${dedupeLabel}: ${dedupeRate}% (${stats.dedupedCount}/${stats.totalEvents + stats.dedupedCount})`);
41
+ if (stats.dedupedCount > 0) {
42
+ lines.push(isZh ? ' ↳ 避免了重复惩罚' : ' ↳ Prevented duplicate penalties');
43
+ }
44
+ lines.push('');
45
+ // Rollback info
46
+ if (stats.rollbackCount > 0) {
47
+ const rollbackLabel = isZh ? '↩️ 已回滚' : '↩️ Rolled Back';
48
+ lines.push(`${rollbackLabel}: ${stats.rollbackCount} 次 (${stats.rolledBackScore}分)`);
49
+ lines.push('');
50
+ }
51
+ // Daily trend
52
+ if (stats.dailyTrend.length > 1) {
53
+ const trendLabel = isZh ? '📈 趋势 (按天)' : '📈 Trend (by day)';
54
+ lines.push(`${trendLabel}:`);
55
+ const maxCount = Math.max(...stats.dailyTrend.map(d => d.count), 1);
56
+ for (const day of stats.dailyTrend) {
57
+ const bar = createMiniBar(day.count, maxCount, 6);
58
+ const dateStr = day.date.slice(5); // MM-DD
59
+ lines.push(` ${dateStr}: ${bar} ${day.count}次`);
60
+ }
61
+ }
62
+ // Detection mode distribution
63
+ if (stats.byDetectionMode.structured > 0 || stats.byDetectionMode.legacy_tag > 0) {
64
+ lines.push('');
65
+ const modeLabel = isZh ? '🔍 检测模式' : '🔍 Detection Mode';
66
+ lines.push(`${modeLabel}: 结构化 ${stats.byDetectionMode.structured} | 标签 ${stats.byDetectionMode.legacy_tag}`);
67
+ }
68
+ return lines.join('\n');
69
+ }
11
70
  /**
12
71
  * Handles the /pd-status command
13
72
  */
@@ -18,6 +77,10 @@ export function handlePainCommand(ctx) {
18
77
  const isZh = lang === 'zh';
19
78
  const sessionId = ctx.sessionId;
20
79
  const args = (ctx.args || '').trim();
80
+ // Handle empathy subcommand
81
+ if (args.startsWith('empathy')) {
82
+ return handleEmpathySubcommand(wctx, args, sessionId, isZh);
83
+ }
21
84
  if (args === 'reset') {
22
85
  if (sessionId) {
23
86
  resetFriction(sessionId);
@@ -40,6 +103,24 @@ export function handlePainCommand(ctx) {
40
103
  const trustStage = trust.getStage();
41
104
  const gfiBar = createProgressBar(gfi, 100, 15);
42
105
  const trustBar = createProgressBar(trustScore, 100, 15);
106
+ // Determine Mental Mode (aligned with prompt.ts logic)
107
+ let mentalMode = '';
108
+ if (isZh) {
109
+ if (gfi >= 70)
110
+ mentalMode = '🚑 救赎模式 (HUMBLE_RECOVERY)';
111
+ else if (gfi >= 40)
112
+ mentalMode = '🤝 安抚模式 (CONCILIATORY)';
113
+ else
114
+ mentalMode = '⚡ 高效模式 (EFFICIENT)';
115
+ }
116
+ else {
117
+ if (gfi >= 70)
118
+ mentalMode = '🚑 HUMBLE_RECOVERY';
119
+ else if (gfi >= 40)
120
+ mentalMode = '🤝 CONCILIATORY';
121
+ else
122
+ mentalMode = '⚡ EFFICIENT';
123
+ }
43
124
  // Determine health status based on GFI
44
125
  let healthLabel = 'Healthy';
45
126
  let suggestionText = '';
@@ -77,20 +158,30 @@ export function handlePainCommand(ctx) {
77
158
  else
78
159
  healthLabel = 'Healthy 🟢';
79
160
  }
161
+ // Get session empathy stats for inline display
162
+ const sessionEmpathy = sessionId ? wctx.eventLog.getEmpathyStats('session', sessionId) : null;
163
+ let empathyInline = '';
164
+ if (sessionEmpathy && sessionEmpathy.totalEvents > 0) {
165
+ empathyInline = isZh
166
+ ? `\n🫀 **情绪事件 (当前会话)**: ${sessionEmpathy.totalEvents} 次 (${sessionEmpathy.totalPenaltyScore}分)`
167
+ : `\n🫀 **Empathy Events (Session)**: ${sessionEmpathy.totalEvents} (${sessionEmpathy.totalPenaltyScore}pts)`;
168
+ }
80
169
  if (isZh) {
81
170
  let text = `📊 **Principles Disciple - 系统健康度监控**\n`;
82
171
  text += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`;
83
172
  text += `💊 **当前疲劳指数 (GFI)**: ${gfiBar} ${gfi}/100\n`;
84
173
  text += `💰 **当前信任积分 (Trust)**: ${trustBar} ${trustScore}/100 (Stage ${trustStage})\n`;
85
- text += ` ↳ 状态诊断: ${healthLabel}\n\n`;
86
- text += `🧠 **痛苦进化词典**: 已吸收 ${stats.totalRules} 条规则\n`;
174
+ text += `🧠 **当前心智模式**: ${mentalMode}\n`;
175
+ text += ` ↳ 状态诊断: ${healthLabel}\n`;
176
+ text += empathyInline;
177
+ text += `\n\n🧠 **痛苦进化词典**: 已吸收 ${stats.totalRules} 条规则\n`;
87
178
  text += ` ↳ 累计帮您拦截了 ${stats.totalHits} 次无效操作\n`;
88
179
  text += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`;
89
180
  if (suggestionText) {
90
181
  text += suggestionText;
91
182
  }
92
183
  else {
93
- text += `*💡 提示: 如果 AI 陷入死循环,您可以使用 \`/pd-status reset\` 来强制清零疲劳值。*`;
184
+ text += `*💡 提示: 使用 \`/pd-status empathy\` 查看详细情绪事件统计。*`;
94
185
  }
95
186
  return { text };
96
187
  }
@@ -99,16 +190,54 @@ export function handlePainCommand(ctx) {
99
190
  text += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`;
100
191
  text += `💊 **Current Friction (GFI)**: ${gfiBar} ${gfi}/100\n`;
101
192
  text += `💰 **Current Trust Score**: ${trustBar} ${trustScore}/100 (Stage ${trustStage})\n`;
102
- text += ` ↳ Diagnosis: ${healthLabel}\n\n`;
103
- text += `🧠 **Evolution Dictionary**: ${stats.totalRules} active rules\n`;
193
+ text += `🧠 **Current Mental Mode**: ${mentalMode}\n`;
194
+ text += ` ↳ Diagnosis: ${healthLabel}\n`;
195
+ text += empathyInline;
196
+ text += `\n\n🧠 **Evolution Dictionary**: ${stats.totalRules} active rules\n`;
104
197
  text += ` ↳ Successfully blocked ${stats.totalHits} invalid operations\n`;
105
198
  text += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`;
106
199
  if (suggestionText) {
107
200
  text += suggestionText;
108
201
  }
109
202
  else {
110
- text += `*💡 Hint: If the AI is stuck in a loop, use \`/pd-status reset\` to clear friction and restart.*`;
203
+ text += `*💡 Hint: Use \`/pd-status empathy\` to view detailed empathy event statistics.*`;
111
204
  }
112
205
  return { text };
113
206
  }
114
207
  }
208
+ /**
209
+ * Handle /pd-status empathy subcommand
210
+ */
211
+ function handleEmpathySubcommand(wctx, args, sessionId, isZh) {
212
+ // Parse range argument
213
+ let range = 'today';
214
+ if (args.includes('--week') || args.includes('-w')) {
215
+ range = 'week';
216
+ }
217
+ else if (args.includes('--session') || args.includes('-s')) {
218
+ range = 'session';
219
+ }
220
+ else if (args.includes('--today') || args.includes('-t')) {
221
+ range = 'today';
222
+ }
223
+ // Validate session range
224
+ if (range === 'session' && !sessionId) {
225
+ return {
226
+ text: isZh
227
+ ? `❌ 无法获取会话统计,请在聊天会话中使用此命令。`
228
+ : `❌ Session not found. Use this command in a chat session.`
229
+ };
230
+ }
231
+ const stats = wctx.eventLog.getEmpathyStats(range, sessionId);
232
+ const rangeLabel = isZh
233
+ ? { today: '今天', week: '最近 7 天', session: '当前会话' }[range]
234
+ : { today: 'Today', week: 'Last 7 Days', session: 'Current Session' }[range];
235
+ let text = formatEmpathyCard(stats, rangeLabel, isZh);
236
+ // Add usage hint
237
+ if (range === 'today') {
238
+ text += isZh
239
+ ? `\n\n*💡 使用 \`/pd-status empathy --week\` 查看周统计,\`--session\` 查看会话统计。*`
240
+ : `\n\n*💡 Use \`/pd-status empathy --week\` for weekly stats, \`--session\` for session stats.*`;
241
+ }
242
+ return { text };
243
+ }
@@ -0,0 +1,19 @@
1
+ import { WorkspaceContext } from '../core/workspace-context.js';
2
+ import type { PluginCommandContext, PluginCommandResult } from '../openclaw-sdk.js';
3
+ /**
4
+ * Handles the /pd-rollback command
5
+ *
6
+ * Usage:
7
+ * /pd-rollback <event-id> - Rollback a specific empathy event by ID
8
+ * /pd-rollback last - Rollback the last empathy event in current session
9
+ */
10
+ export declare function handleRollbackCommand(ctx: PluginCommandContext): PluginCommandResult;
11
+ /**
12
+ * Handle natural language rollback request
13
+ * Called from prompt hook when user says things like "撤销刚才的惩罚"
14
+ */
15
+ export declare function handleNaturalLanguageRollback(wctx: WorkspaceContext, sessionId: string | undefined, reason: string): {
16
+ success: boolean;
17
+ score: number;
18
+ message: string;
19
+ };
@@ -0,0 +1,119 @@
1
+ import { WorkspaceContext } from '../core/workspace-context.js';
2
+ import { resetFriction } from '../core/session-tracker.js';
3
+ /**
4
+ * Handles the /pd-rollback command
5
+ *
6
+ * Usage:
7
+ * /pd-rollback <event-id> - Rollback a specific empathy event by ID
8
+ * /pd-rollback last - Rollback the last empathy event in current session
9
+ */
10
+ export function handleRollbackCommand(ctx) {
11
+ const workspaceDir = ctx.config?.workspaceDir || process.cwd();
12
+ const wctx = WorkspaceContext.fromHookContext({ workspaceDir, ...ctx.config });
13
+ const lang = ctx.config?.language || 'en';
14
+ const isZh = lang === 'zh';
15
+ const sessionId = ctx.sessionId;
16
+ const args = (ctx.args || '').trim();
17
+ if (!args) {
18
+ return {
19
+ text: isZh
20
+ ? `❌ 请指定要回滚的事件 ID 或使用 "last" 回滚最近一次事件。
21
+
22
+ 用法:
23
+ /pd-rollback <event-id> - 回滚指定事件
24
+ /pd-rollback last - 回滚当前会话最近一次事件`
25
+ : `❌ Please specify an event ID or use "last" to rollback the most recent event.
26
+
27
+ Usage:
28
+ /pd-rollback <event-id> - Rollback a specific event
29
+ /pd-rollback last - Rollback the last event in current session`
30
+ };
31
+ }
32
+ if (!sessionId) {
33
+ return {
34
+ text: isZh
35
+ ? `❌ 无法识别当前会话,请在聊天会话中使用此命令。`
36
+ : `❌ Session ID not found. Use this command in a chat session.`
37
+ };
38
+ }
39
+ let eventId = null;
40
+ let triggerMethod = 'user_command';
41
+ if (args === 'last') {
42
+ // Find the last empathy event in current session
43
+ eventId = wctx.eventLog.getLastEmpathyEventId(sessionId);
44
+ if (!eventId) {
45
+ return {
46
+ text: isZh
47
+ ? `❌ 当前会话没有可回滚的情绪事件。`
48
+ : `❌ No empathy events found in current session to rollback.`
49
+ };
50
+ }
51
+ }
52
+ else {
53
+ // Use the provided event ID
54
+ eventId = args;
55
+ }
56
+ // Perform rollback
57
+ const rolledBackScore = wctx.eventLog.rollbackEmpathyEvent(eventId, sessionId, isZh ? '用户手动回滚' : 'User manual rollback', 'user_command');
58
+ if (rolledBackScore === 0) {
59
+ return {
60
+ text: isZh
61
+ ? `❌ 无法回滚事件 "${eventId}"。可能事件不存在或已被去重。`
62
+ : `❌ Failed to rollback event "${eventId}". Event may not exist or was deduped.`
63
+ };
64
+ }
65
+ // Reduce the GFI by the rolled back score
66
+ resetFriction(sessionId);
67
+ return {
68
+ text: isZh
69
+ ? `✅ 已回滚情绪事件
70
+ 📋 事件 ID: ${eventId}
71
+ 💰 撤销分数: ${rolledBackScore} 分
72
+
73
+ 💡 提示: 已重置当前会话的疲劳指数。`
74
+ : `✅ Empathy event rolled back successfully
75
+ 📋 Event ID: ${eventId}
76
+ 💰 Score recovered: ${rolledBackScore} pts
77
+
78
+ 💡 Hint: Session friction has been reset.`
79
+ };
80
+ }
81
+ /**
82
+ * Handle natural language rollback request
83
+ * Called from prompt hook when user says things like "撤销刚才的惩罚"
84
+ */
85
+ export function handleNaturalLanguageRollback(wctx, sessionId, reason) {
86
+ const isZh = wctx.config.get('language') === 'zh';
87
+ if (!sessionId) {
88
+ return {
89
+ success: false,
90
+ score: 0,
91
+ message: isZh ? '无法识别当前会话' : 'Session not found'
92
+ };
93
+ }
94
+ const eventId = wctx.eventLog.getLastEmpathyEventId(sessionId);
95
+ if (!eventId) {
96
+ return {
97
+ success: false,
98
+ score: 0,
99
+ message: isZh ? '当前会话没有可回滚的情绪事件' : 'No empathy events to rollback'
100
+ };
101
+ }
102
+ const rolledBackScore = wctx.eventLog.rollbackEmpathyEvent(eventId, sessionId, reason, 'natural_language');
103
+ if (rolledBackScore === 0) {
104
+ return {
105
+ success: false,
106
+ score: 0,
107
+ message: isZh ? '回滚失败,事件可能不存在' : 'Rollback failed, event may not exist'
108
+ };
109
+ }
110
+ // Reduce the GFI
111
+ resetFriction(sessionId);
112
+ return {
113
+ success: true,
114
+ score: rolledBackScore,
115
+ message: isZh
116
+ ? `已回滚 ${rolledBackScore} 分`
117
+ : `Rolled back ${rolledBackScore} pts`
118
+ };
119
+ }
@@ -13,6 +13,23 @@ export interface DeepReflectionSettings {
13
13
  timeout_ms?: number;
14
14
  modelsDir?: string;
15
15
  }
16
+ export interface GfiGateSettings {
17
+ enabled: boolean;
18
+ thresholds: {
19
+ low_risk_block: number;
20
+ high_risk_block: number;
21
+ large_change_block: number;
22
+ };
23
+ large_change_lines: number;
24
+ trust_stage_multipliers: {
25
+ '1': number;
26
+ '2': number;
27
+ '3': number;
28
+ '4': number;
29
+ };
30
+ bash_safe_patterns: string[];
31
+ bash_dangerous_patterns: string[];
32
+ }
16
33
  export interface TrustSettings {
17
34
  stages: {
18
35
  stage_1_observer: number;
@@ -79,6 +96,21 @@ export interface PainSettings {
79
96
  };
80
97
  trust: TrustSettings;
81
98
  deep_reflection?: DeepReflectionSettings;
99
+ empathy_engine?: {
100
+ enabled?: boolean;
101
+ dedupe_window_ms?: number;
102
+ penalties?: {
103
+ mild?: number;
104
+ moderate?: number;
105
+ severe?: number;
106
+ };
107
+ rate_limit?: {
108
+ max_per_turn?: number;
109
+ max_per_hour?: number;
110
+ };
111
+ model_calibration?: Record<string, number>;
112
+ };
113
+ gfi_gate?: GfiGateSettings;
82
114
  }
83
115
  export declare const DEFAULT_SETTINGS: PainSettings;
84
116
  export declare class PainConfig {
@@ -89,6 +89,53 @@ export const DEFAULT_SETTINGS = {
89
89
  default_model: 'T-01',
90
90
  default_depth: 2,
91
91
  timeout_ms: 60000
92
+ },
93
+ empathy_engine: {
94
+ enabled: true,
95
+ dedupe_window_ms: 60000,
96
+ penalties: {
97
+ mild: 10,
98
+ moderate: 25,
99
+ severe: 40,
100
+ },
101
+ rate_limit: {
102
+ max_per_turn: 40,
103
+ max_per_hour: 120,
104
+ },
105
+ model_calibration: {}
106
+ },
107
+ gfi_gate: {
108
+ enabled: true,
109
+ thresholds: {
110
+ low_risk_block: 70, // TIER 1: write, edit, spawn_agent
111
+ high_risk_block: 40, // TIER 2: delete_file, move_file
112
+ large_change_block: 50, // 大规模修改警告阈值
113
+ },
114
+ large_change_lines: 50,
115
+ trust_stage_multipliers: {
116
+ '1': 0.5, // Observer: 更严格,阈值减半
117
+ '2': 0.75, // Editor: 阈值降低 25%
118
+ '3': 1.0, // Developer: 标准阈值
119
+ '4': 1.5, // Architect: 更宽松,阈值提高 50%
120
+ },
121
+ bash_safe_patterns: [
122
+ '^(ls|dir|pwd|which|where|echo|env|cat|type|head|tail|less|more)\\b',
123
+ '^git\\s+(status|log|diff|branch|show|remote)\\b',
124
+ '^npm\\s+(run|test|build|start)\\b',
125
+ '^make\\s*$', // 只允许纯 make 命令
126
+ '^make\\s+(-j\\d+|--jobs\\s*\\d+)$', // 允许 make -j4 等
127
+ '^(gradle|mvn)\\s+(clean|build|test|compile)\\b', // 只允许安全参数
128
+ ],
129
+ bash_dangerous_patterns: [
130
+ 'rm\\s+(-[a-z]*r[a-z]*f|-rf)',
131
+ 'del\\s+/s',
132
+ 'rmdir\\s+/s',
133
+ 'git\\s+(push\\s+.*--force|reset\\s+--hard|clean\\s+-fd)',
134
+ 'npm\\s+publish',
135
+ 'pip\\s+upload',
136
+ 'docker\\s+push',
137
+ '(curl|wget).*\\|\\s*(ba)?sh',
138
+ ],
92
139
  }
93
140
  };
94
141
  export class PainConfig {
@@ -1,4 +1,4 @@
1
- import type { DailyStats, ToolCallEventData, PainSignalEventData, RuleMatchEventData, RulePromotionEventData, HookExecutionEventData, GateBlockEventData, PlanApprovalEventData, EvolutionTaskEventData, DeepReflectionEventData, TrustChangeEventData } from '../types/event-types.js';
1
+ import type { DailyStats, EmpathyEventStats, ToolCallEventData, PainSignalEventData, RuleMatchEventData, RulePromotionEventData, HookExecutionEventData, GateBlockEventData, PlanApprovalEventData, EvolutionTaskEventData, DeepReflectionEventData, TrustChangeEventData, EmpathyRollbackEventData } from '../types/event-types.js';
2
2
  import type { PluginLogger } from '../openclaw-sdk.js';
3
3
  /**
4
4
  * EventLog - Structured event logging with daily statistics aggregation.
@@ -23,6 +23,7 @@ export declare class EventLog {
23
23
  recordEvolutionTask(data: EvolutionTaskEventData): void;
24
24
  recordDeepReflection(sessionId: string | undefined, data: DeepReflectionEventData): void;
25
25
  recordTrustChange(sessionId: string | undefined, data: TrustChangeEventData): void;
26
+ recordEmpathyRollback(sessionId: string | undefined, data: EmpathyRollbackEventData): void;
26
27
  recordError(sessionId: string | undefined, message: string, context?: Record<string, unknown>): void;
27
28
  recordWarn(sessionId: string | undefined, message: string, context?: Record<string, unknown>): void;
28
29
  private record;
@@ -38,6 +39,25 @@ export declare class EventLog {
38
39
  * Returns empty stats if no events recorded for that date.
39
40
  */
40
41
  getDailyStats(date: string): DailyStats;
42
+ /**
43
+ * Get aggregated empathy statistics for multiple time ranges.
44
+ * @param range 'today' | 'week' | 'session'
45
+ * @param sessionId Optional session ID for session-scoped stats
46
+ */
47
+ getEmpathyStats(range: 'today' | 'week' | 'session', sessionId?: string): EmpathyEventStats;
48
+ /**
49
+ * Aggregate empathy stats for a specific session.
50
+ */
51
+ private aggregateSessionEmpathy;
52
+ /**
53
+ * Rollback an empathy event by ID.
54
+ * Returns the rolled back score, or 0 if event not found.
55
+ */
56
+ rollbackEmpathyEvent(eventId: string, sessionId: string | undefined, reason: string, triggeredBy: 'user_command' | 'natural_language' | 'system'): number;
57
+ /**
58
+ * Get the last empathy event ID for a session (for rollback).
59
+ */
60
+ getLastEmpathyEventId(sessionId: string): string | null;
41
61
  /**
42
62
  * Dispose of the EventLog, flushing pending data and clearing timer.
43
63
  */