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.
- package/dist/commands/context.d.ts +5 -0
- package/dist/commands/context.js +308 -0
- package/dist/commands/focus.d.ts +14 -0
- package/dist/commands/focus.js +579 -0
- package/dist/commands/pain.js +135 -6
- package/dist/commands/rollback.d.ts +19 -0
- package/dist/commands/rollback.js +119 -0
- package/dist/core/config.d.ts +32 -0
- package/dist/core/config.js +47 -0
- package/dist/core/event-log.d.ts +21 -1
- package/dist/core/event-log.js +316 -0
- package/dist/core/focus-history.d.ts +65 -0
- package/dist/core/focus-history.js +266 -0
- package/dist/core/init.js +30 -7
- package/dist/core/migration.js +0 -2
- package/dist/core/path-resolver.d.ts +3 -0
- package/dist/core/path-resolver.js +20 -0
- package/dist/hooks/gate.js +203 -1
- package/dist/hooks/llm.d.ts +8 -0
- package/dist/hooks/llm.js +234 -1
- package/dist/hooks/message-sanitize.d.ts +3 -0
- package/dist/hooks/message-sanitize.js +37 -0
- package/dist/hooks/prompt.d.ts +12 -0
- package/dist/hooks/prompt.js +309 -135
- package/dist/hooks/subagent.d.ts +9 -2
- package/dist/hooks/subagent.js +13 -2
- package/dist/i18n/commands.js +32 -20
- package/dist/index.js +181 -4
- package/dist/service/empathy-observer-manager.d.ts +42 -0
- package/dist/service/empathy-observer-manager.js +147 -0
- package/dist/service/evolution-worker.d.ts +1 -0
- package/dist/service/evolution-worker.js +4 -2
- package/dist/tools/deep-reflect.js +80 -0
- package/dist/types/event-types.d.ts +77 -2
- package/dist/types/event-types.js +33 -0
- package/dist/types.d.ts +42 -0
- package/dist/types.js +19 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +3 -3
- package/templates/langs/zh/core/HEARTBEAT.md +28 -4
- package/templates/pain_settings.json +54 -2
- package/templates/workspace/.principles/PROFILE.json +2 -0
- package/templates/workspace/okr/CURRENT_FOCUS.md +57 -0
package/dist/commands/pain.js
CHANGED
|
@@ -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 +=
|
|
86
|
-
text +=
|
|
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 += `*💡 提示:
|
|
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 +=
|
|
103
|
-
text +=
|
|
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:
|
|
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
|
+
}
|
package/dist/core/config.d.ts
CHANGED
|
@@ -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 {
|
package/dist/core/config.js
CHANGED
|
@@ -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 {
|
package/dist/core/event-log.d.ts
CHANGED
|
@@ -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
|
*/
|