principles-disciple 1.7.0 → 1.7.2

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 (35) hide show
  1. package/dist/commands/evolution-status.js +114 -118
  2. package/dist/commands/rollback.js +9 -3
  3. package/dist/commands/trust.js +64 -81
  4. package/dist/constants/tools.d.ts +17 -0
  5. package/dist/constants/tools.js +54 -0
  6. package/dist/core/event-log.d.ts +10 -1
  7. package/dist/core/event-log.js +69 -118
  8. package/dist/core/evolution-engine.d.ts +3 -4
  9. package/dist/core/evolution-engine.js +60 -118
  10. package/dist/core/migration.js +1 -1
  11. package/dist/core/session-tracker.d.ts +11 -2
  12. package/dist/core/session-tracker.js +99 -20
  13. package/dist/core/trust-engine.d.ts +5 -2
  14. package/dist/core/trust-engine.js +24 -48
  15. package/dist/hooks/gate.js +72 -78
  16. package/dist/hooks/llm.js +5 -2
  17. package/dist/hooks/prompt.js +12 -1
  18. package/dist/hooks/subagent.js +109 -48
  19. package/dist/hooks/trajectory-collector.d.ts +32 -0
  20. package/dist/hooks/trajectory-collector.js +256 -0
  21. package/dist/index.js +22 -0
  22. package/dist/service/control-ui-query-service.d.ts +2 -0
  23. package/dist/service/control-ui-query-service.js +2 -0
  24. package/dist/service/empathy-observer-manager.d.ts +2 -0
  25. package/dist/service/empathy-observer-manager.js +43 -1
  26. package/dist/service/evolution-worker.d.ts +23 -1
  27. package/dist/service/evolution-worker.js +247 -132
  28. package/dist/service/runtime-summary-service.d.ts +83 -0
  29. package/dist/service/runtime-summary-service.js +358 -0
  30. package/dist/tools/agent-spawn.js +23 -0
  31. package/dist/types/event-types.d.ts +1 -0
  32. package/dist/utils/file-lock.d.ts +7 -0
  33. package/dist/utils/file-lock.js +66 -27
  34. package/openclaw.plugin.json +13 -12
  35. package/package.json +1 -1
@@ -1,138 +1,134 @@
1
1
  import { EvolutionReducerImpl } from '../core/evolution-reducer.js';
2
2
  import { normalizeLanguage } from '../i18n/commands.js';
3
- import { getAgentScorecard } from '../core/trust-engine.js';
4
- import { EventLogService } from '../core/event-log.js';
5
- import * as fs from 'fs';
6
- import * as path from 'path';
7
- function getQueueStats(workspaceDir) {
8
- const stateDir = path.join(workspaceDir, '.state', 'principles');
9
- const queuePath = path.join(stateDir, 'evolution_queue.json');
10
- let pending = 0;
11
- let completed = 0;
12
- let inProgress = 0;
13
- try {
14
- if (fs.existsSync(queuePath)) {
15
- const queue = JSON.parse(fs.readFileSync(queuePath, 'utf-8'));
16
- for (const item of queue) {
17
- if (item.status === 'completed') {
18
- completed++;
19
- }
20
- else if (item.status === 'in_progress') {
21
- inProgress++;
22
- }
23
- else {
24
- pending++;
25
- }
26
- }
27
- }
3
+ import { RuntimeSummaryService } from '../service/runtime-summary-service.js';
4
+ function formatAge(ageSeconds, lang) {
5
+ if (ageSeconds === null) {
6
+ return '--';
28
7
  }
29
- catch {
30
- // Ignore errors, return zeros
8
+ if (ageSeconds < 60) {
9
+ return lang === 'zh' ? `${ageSeconds} \u79d2` : `${ageSeconds}s`;
31
10
  }
32
- return { pending, completed, inProgress };
33
- }
34
- function getCurrentPain(workspaceDir) {
35
- const stateDir = path.join(workspaceDir, '.state', 'principles');
36
- const painFlagPath = path.join(stateDir, '.pain_flag');
37
- try {
38
- if (fs.existsSync(painFlagPath)) {
39
- const data = JSON.parse(fs.readFileSync(painFlagPath, 'utf-8'));
40
- return {
41
- painScore: data.score || 0,
42
- painSource: data.source || 'none'
43
- };
44
- }
11
+ const minutes = Math.floor(ageSeconds / 60);
12
+ if (minutes < 60) {
13
+ return lang === 'zh' ? `${minutes} \u5206\u949f` : `${minutes}m`;
45
14
  }
46
- catch {
47
- // Ignore errors
15
+ const hours = Math.floor(minutes / 60);
16
+ if (hours < 24) {
17
+ return lang === 'zh' ? `${hours} \u5c0f\u65f6` : `${hours}h`;
48
18
  }
49
- return { painScore: 0, painSource: 'none' };
19
+ const days = Math.floor(hours / 24);
20
+ return lang === 'zh' ? `${days} \u5929` : `${days}d`;
50
21
  }
51
- export function handleEvolutionStatusCommand(ctx) {
52
- const workspaceDir = ctx.config?.workspaceDir || process.cwd();
53
- const reducer = new EvolutionReducerImpl({ workspaceDir });
54
- const stats = reducer.getStats();
55
- // Get Trust Score
56
- let trustScore = 0;
57
- let trustStage = 1;
58
- try {
59
- const scorecard = getAgentScorecard(workspaceDir);
60
- trustScore = scorecard.trust_score ?? 0;
61
- trustStage = trustScore >= 80 ? 4 : trustScore >= 60 ? 3 : trustScore >= 30 ? 2 : 1;
62
- }
63
- catch {
64
- // Ignore errors, use defaults
65
- }
66
- // Get EventLog for GFI and Pain stats
67
- let gfiPeak = 0;
68
- let painSignals = 0;
69
- try {
70
- const stateDir = path.join(workspaceDir, '.state', 'principles');
71
- const eventLog = EventLogService.get(stateDir);
72
- const today = new Date().toISOString().split('T')[0];
73
- const dailyStats = eventLog.getDailyStats(today);
74
- gfiPeak = dailyStats.gfi?.peak ?? 0;
75
- painSignals = dailyStats.pain?.signalsDetected ?? 0;
76
- }
77
- catch {
78
- // Ignore errors, use defaults
22
+ function formatNumber(value) {
23
+ if (value === null || Number.isNaN(value)) {
24
+ return '--';
79
25
  }
80
- // Get Queue Stats
81
- const queueStats = getQueueStats(workspaceDir);
82
- // Get Current Pain
83
- const currentPain = getCurrentPain(workspaceDir);
84
- // Determine language - handle both 'zh' and 'zh-CN' formats
85
- const rawLang = ctx.config?.language || 'en';
86
- const lang = normalizeLanguage(rawLang);
87
- if (lang === 'zh') {
88
- const lines = [
89
- '📈 Evolution 状态',
90
- '━━━━━━━━━━━━━━━━━━━━━━━━━━━━',
91
- '',
92
- `🛡️ Trust Score: ${trustScore}/100 (Stage ${trustStage})`,
93
- `😴 GFI Peak: ${gfiPeak.toFixed(1)}`,
94
- `⚡ Current Pain: ${currentPain.painScore} pts (${currentPain.painSource})`,
95
- `📈 Pain Signals Today: ${painSignals}`,
96
- '',
97
- '📊 Evolution Rules',
98
- '━━━━━━━━━━━━━━━━━━━━━━━━━━━━',
99
- `- 候选原则: ${stats.candidateCount}`,
100
- `- 观察期原则: ${stats.probationCount}`,
101
- `- 生效原则: ${stats.activeCount}`,
102
- `- 已废弃原则: ${stats.deprecatedCount}`,
103
- `- 最近晋升时间: ${stats.lastPromotedAt ?? '无'}`,
104
- '',
105
- '📋 Evolution Queue',
106
- '━━━━━━━━━━━━━━━━━━━━━━━━━━━━',
107
- `- 待处理: ${queueStats.pending} 项`,
108
- `- 进行中: ${queueStats.inProgress} 项`,
109
- `- 已完成: ${queueStats.completed} 项`,
110
- ];
111
- return { text: lines.join('\n') };
26
+ return Number.isInteger(value) ? String(value) : value.toFixed(1);
27
+ }
28
+ function formatStage(value) {
29
+ return value === null ? '--' : String(value);
30
+ }
31
+ function formatSources(sources) {
32
+ if (sources.length === 0) {
33
+ return '--';
112
34
  }
113
- // English
35
+ return sources
36
+ .map((source) => source.score === undefined
37
+ ? source.source
38
+ : `${source.source}(${formatNumber(source.score)})`)
39
+ .join(', ');
40
+ }
41
+ function buildEnglishOutput(workspaceDir, sessionId, warnings, stats, summary) {
114
42
  const lines = [
115
- '📈 Evolution Status',
116
- '━━━━━━━━━━━━━━━━━━━━━━━━━━━━',
43
+ 'Evolution Status',
44
+ '================',
45
+ '',
46
+ 'Control Plane',
47
+ `- Legacy Trust: ${formatNumber(summary.legacyTrust.score)}/100 (stage ${formatStage(summary.legacyTrust.stage)}, legacy/frozen, ${summary.legacyTrust.rewardPolicy})`,
48
+ `- Session GFI: current ${formatNumber(summary.gfi.current)}, peak ${formatNumber(summary.gfi.peak)} (${summary.gfi.dataQuality})`,
49
+ `- GFI Sources: ${formatSources(summary.gfi.sources)}`,
50
+ `- Pain Flag: ${summary.pain.activeFlag ? 'active' : 'inactive'}${summary.pain.activeFlagSource ? ` (${summary.pain.activeFlagSource})` : ''}`,
51
+ `- Last Pain Signal: ${summary.pain.lastSignal ? `${summary.pain.lastSignal.source}${summary.pain.lastSignal.reason ? ` - ${summary.pain.lastSignal.reason}` : ''}` : '--'}`,
52
+ `- Gate Events: blocks ${formatNumber(summary.gate.recentBlocks)}, bypasses ${formatNumber(summary.gate.recentBypasses)} (${summary.gate.dataQuality})`,
117
53
  '',
118
- `🛡️ Trust Score: ${trustScore}/100 (Stage ${trustStage})`,
119
- `😴 GFI Peak: ${gfiPeak.toFixed(1)}`,
120
- `⚡ Current Pain: ${currentPain.painScore} pts (${currentPain.painSource})`,
121
- `📈 Pain Signals Today: ${painSignals}`,
54
+ 'Evolution',
55
+ `- Queue: pending ${summary.evolution.queue.pending}, in_progress ${summary.evolution.queue.inProgress}, completed ${summary.evolution.queue.completed} (${summary.evolution.dataQuality})`,
56
+ `- Directive: ${summary.evolution.directive.exists ? 'present' : 'missing'}, active ${summary.evolution.directive.active === null ? '--' : summary.evolution.directive.active ? 'yes' : 'no'}, age ${formatAge(summary.evolution.directive.ageSeconds, 'en')}`,
57
+ `- Directive Task: ${summary.evolution.directive.taskPreview ?? '--'}`,
122
58
  '',
123
- '📊 Evolution Rules',
124
- '━━━━━━━━━━━━━━━━━━━━━━━━━━━━',
59
+ 'Principles',
125
60
  `- candidate principles: ${stats.candidateCount}`,
126
61
  `- probation principles: ${stats.probationCount}`,
127
62
  `- active principles: ${stats.activeCount}`,
128
63
  `- deprecated principles: ${stats.deprecatedCount}`,
129
64
  `- last promoted: ${stats.lastPromotedAt ?? 'none'}`,
130
65
  '',
131
- '📋 Evolution Queue',
132
- '━━━━━━━━━━━━━━━━━━━━━━━━━━━━',
133
- `- Pending: ${queueStats.pending}`,
134
- `- In Progress: ${queueStats.inProgress}`,
135
- `- Completed: ${queueStats.completed}`,
66
+ 'Metadata',
67
+ `- workspace: ${workspaceDir}`,
68
+ `- session: ${sessionId ?? '--'} (${summary.metadata.selectedSessionReason})`,
69
+ `- generatedAt: ${summary.metadata.generatedAt}`,
136
70
  ];
137
- return { text: lines.join('\n') };
71
+ if (warnings.length > 0) {
72
+ lines.push('', 'Warnings');
73
+ for (const warning of warnings) {
74
+ lines.push(`- ${warning}`);
75
+ }
76
+ }
77
+ return lines.join('\n');
78
+ }
79
+ function buildChineseOutput(workspaceDir, sessionId, warnings, stats, summary) {
80
+ const lines = [
81
+ '\u8fdb\u5316\u72b6\u6001',
82
+ '================',
83
+ '',
84
+ '\u63a7\u5236\u9762',
85
+ `- Legacy Trust: ${formatNumber(summary.legacyTrust.score)}/100\uff08\u9636\u6bb5 ${formatStage(summary.legacyTrust.stage)}\uff0clegacy/frozen\uff0c${summary.legacyTrust.rewardPolicy}\uff09`,
86
+ `- \u4f1a\u8bdd GFI: \u5f53\u524d ${formatNumber(summary.gfi.current)}\uff0c\u5cf0\u503c ${formatNumber(summary.gfi.peak)}\uff08${summary.gfi.dataQuality}\uff09`,
87
+ `- GFI \u6765\u6e90: ${formatSources(summary.gfi.sources)}`,
88
+ `- Pain Flag: ${summary.pain.activeFlag ? 'active' : 'inactive'}${summary.pain.activeFlagSource ? `\uff08${summary.pain.activeFlagSource}\uff09` : ''}`,
89
+ `- \u6700\u8fd1 Pain \u4fe1\u53f7: ${summary.pain.lastSignal ? `${summary.pain.lastSignal.source}${summary.pain.lastSignal.reason ? ` - ${summary.pain.lastSignal.reason}` : ''}` : '--'}`,
90
+ `- Gate \u4e8b\u4ef6: block ${formatNumber(summary.gate.recentBlocks)}\uff0cbypass ${formatNumber(summary.gate.recentBypasses)}\uff08${summary.gate.dataQuality}\uff09`,
91
+ '',
92
+ '\u8fdb\u5316',
93
+ `- \u961f\u5217: pending ${summary.evolution.queue.pending}\uff0cin_progress ${summary.evolution.queue.inProgress}\uff0ccompleted ${summary.evolution.queue.completed}\uff08${summary.evolution.dataQuality}\uff09`,
94
+ `- Directive: ${summary.evolution.directive.exists ? 'present' : 'missing'}\uff0cactive ${summary.evolution.directive.active === null ? '--' : summary.evolution.directive.active ? 'yes' : 'no'}\uff0cage ${formatAge(summary.evolution.directive.ageSeconds, 'zh')}`,
95
+ `- Directive \u4efb\u52a1: ${summary.evolution.directive.taskPreview ?? '--'}`,
96
+ '',
97
+ '\u539f\u5219\u7edf\u8ba1',
98
+ `- \u5019\u9009\u539f\u5219: ${stats.candidateCount}`,
99
+ `- \u89c2\u5bdf\u671f\u539f\u5219: ${stats.probationCount}`,
100
+ `- \u751f\u6548\u539f\u5219: ${stats.activeCount}`,
101
+ `- \u5df2\u5e9f\u5f03\u539f\u5219: ${stats.deprecatedCount}`,
102
+ `- \u6700\u8fd1\u664b\u5347: ${stats.lastPromotedAt ?? '\u65e0'}`,
103
+ '',
104
+ '\u5143\u6570\u636e',
105
+ `- \u5de5\u4f5c\u533a: ${workspaceDir}`,
106
+ `- Session: ${sessionId ?? '--'}\uff08${summary.metadata.selectedSessionReason}\uff09`,
107
+ `- \u751f\u6210\u65f6\u95f4: ${summary.metadata.generatedAt}`,
108
+ ];
109
+ if (warnings.length > 0) {
110
+ lines.push('', '警告');
111
+ for (const warning of warnings) {
112
+ lines.push(`- ${warning}`);
113
+ }
114
+ }
115
+ return lines.join('\n');
116
+ }
117
+ export function handleEvolutionStatusCommand(ctx) {
118
+ const workspaceDir = ctx.config?.workspaceDir || process.cwd();
119
+ const sessionId = ctx.sessionId ?? null;
120
+ const reducer = new EvolutionReducerImpl({ workspaceDir });
121
+ const stats = reducer.getStats();
122
+ const summary = RuntimeSummaryService.getSummary(workspaceDir, { sessionId });
123
+ const rawLang = ctx.config?.language || 'en';
124
+ const lang = normalizeLanguage(rawLang);
125
+ const warnings = summary.metadata.warnings.slice(0, 12);
126
+ if (lang === 'zh') {
127
+ return {
128
+ text: buildChineseOutput(workspaceDir, summary.metadata.sessionId, warnings, stats, summary),
129
+ };
130
+ }
131
+ return {
132
+ text: buildEnglishOutput(workspaceDir, summary.metadata.sessionId, warnings, stats, summary),
133
+ };
138
134
  }
@@ -63,7 +63,10 @@ Usage:
63
63
  };
64
64
  }
65
65
  // Reduce the GFI by the rolled back score
66
- resetFriction(sessionId);
66
+ resetFriction(sessionId, workspaceDir, {
67
+ source: 'user_empathy',
68
+ amount: rolledBackScore,
69
+ });
67
70
  return {
68
71
  text: isZh
69
72
  ? `✅ 已回滚情绪事件
@@ -107,8 +110,11 @@ export function handleNaturalLanguageRollback(wctx, sessionId, reason) {
107
110
  message: isZh ? '回滚失败,事件可能不存在' : 'Rollback failed, event may not exist'
108
111
  };
109
112
  }
110
- // Reduce the GFI
111
- resetFriction(sessionId);
113
+ // Reduce only the empathy slice instead of wiping the whole session GFI.
114
+ resetFriction(sessionId, wctx.workspaceDir, {
115
+ source: 'user_empathy',
116
+ amount: rolledBackScore,
117
+ });
112
118
  return {
113
119
  success: true,
114
120
  score: rolledBackScore,
@@ -1,11 +1,15 @@
1
1
  import { WorkspaceContext } from '../core/workspace-context.js';
2
- /**
3
- * Creates a visual progress bar (e.g., [██████░░░░])
4
- */
5
- function createProgressBar(value, max, length = 10) {
6
- const filledLength = Math.round((value / max) * length);
7
- const emptyLength = length - filledLength;
8
- return `[${'█'.repeat(filledLength)}${'░'.repeat(emptyLength)}]`;
2
+ function createProgressBar(value, max, length = 12) {
3
+ const safeValue = Math.max(0, Math.min(max, value));
4
+ const filledLength = Math.round((safeValue / max) * length);
5
+ const emptyLength = Math.max(0, length - filledLength);
6
+ return `[${'#'.repeat(filledLength)}${'-'.repeat(emptyLength)}]`;
7
+ }
8
+ function formatStageTitle(stage, isZh) {
9
+ const titles = isZh
10
+ ? ['Observer', 'Editor', 'Developer', 'Architect']
11
+ : ['Observer', 'Editor', 'Developer', 'Architect'];
12
+ return titles[Math.max(0, Math.min(3, stage - 1))] ?? 'Unknown';
9
13
  }
10
14
  export function handleTrustCommand(ctx) {
11
15
  const { workspaceDir } = ctx;
@@ -14,82 +18,61 @@ export function handleTrustCommand(ctx) {
14
18
  const wctx = WorkspaceContext.fromHookContext(ctx);
15
19
  const trustEngine = wctx.trust;
16
20
  const trustScore = trustEngine.getScore();
17
- const trustSettings = wctx.config.get('trust');
21
+ const stage = trustEngine.getStage();
18
22
  const isZh = wctx.config.get('language') === 'zh';
19
- let stage = 2;
20
- let title = isZh ? '编辑者' : 'Editor';
21
- let permissions = isZh
22
- ? `- 允许小范围修改 (< ${trustSettings.limits.stage_2_max_lines} 行)\n- 禁止修改风险目录`
23
- : `- Small modifications (< ${trustSettings.limits.stage_2_max_lines} lines)\n- Non-risk paths only`;
24
- let nextLevel = `Trust Score >= ${trustSettings.stages.stage_3_developer}`;
25
- if (trustScore < trustSettings.stages.stage_1_observer) {
26
- stage = 1;
27
- title = isZh ? '观察者 (只读模式)' : 'Observer (Read-only)';
28
- permissions = isZh ? '- 仅限只读访问\n- 仅限诊断工具' : '- Read-only access\n- Diagnosis tools only';
29
- nextLevel = `Trust Score >= ${trustSettings.stages.stage_1_observer}`;
30
- }
31
- else if (trustScore < trustSettings.stages.stage_2_editor) {
32
- // Default stage 2
33
- nextLevel = `Trust Score >= ${trustSettings.stages.stage_2_editor}`;
34
- }
35
- else if (trustScore < trustSettings.stages.stage_3_developer) {
36
- stage = 3;
37
- title = isZh ? '开发者' : 'Developer';
38
- permissions = isZh
39
- ? `- 允许中等范围修改 (< ${trustSettings.limits.stage_3_max_lines} 行)\n- 风险目录修改需要有 PLAN (计划)`
40
- : `- Medium modifications (< ${trustSettings.limits.stage_3_max_lines} lines)\n- Risk paths require READY plan`;
41
- nextLevel = `Trust Score >= ${trustSettings.stages.stage_3_developer}`;
42
- }
43
- else {
44
- stage = 4;
45
- title = isZh ? '架构师' : 'Architect';
46
- permissions = isZh ? '- 🚨 **无限制访问**\n- 计划和审计非强制要求' : '- 🚨 **UNRESTRICTED access**\n- Plan and Audit are optional';
47
- nextLevel = isZh ? '已达最高级' : 'MAX LEVEL REACHED';
48
- }
49
- const progressBar = createProgressBar(trustScore, 100, 15);
23
+ const scorecard = trustEngine.getScorecard();
50
24
  const hygiene = wctx.hygiene.getStats();
51
- const persistenceScore = Math.min(100, hygiene.persistenceCount * 10); // 10 points per persistence
52
- const hygieneBar = createProgressBar(persistenceScore, 100, 15);
25
+ const trustBar = createProgressBar(trustScore, 100);
26
+ const hygieneScore = Math.min(100, hygiene.persistenceCount * 10);
27
+ const hygieneBar = createProgressBar(hygieneScore, 100);
28
+ const rewardPolicy = scorecard.reward_policy ?? 'frozen_all_positive';
29
+ const lastUpdated = scorecard.last_updated ?? '--';
53
30
  if (isZh) {
54
- return `
55
- 📊 **Principles Disciple - 系统状态看板**
56
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
57
- 🛡️ **安全阶级**: Stage ${stage} (${title})
58
- 💰 **信任积分**: ${progressBar} ${trustScore}/100
59
- 🧠 **认知卫生**: ${hygieneBar} ${hygiene.persistenceCount} 次落盘 (今日)
60
-
61
- **当前操作权限**:
62
- ${permissions}
63
-
64
- **今日知识沉淀**:
65
- - 物理落盘: ${hygiene.persistenceCount}
66
- - 累计字符: ${hygiene.totalCharsPersisted} chars
67
- - 空间整理: ${hygiene.groomingExecutedCount > 0 ? '🟢 良好' : '🟡 待整理'}
68
-
69
- **下一次晋升条件**: ${nextLevel}
70
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
71
- *💡 提示:勤记笔记 (PLAN.md/memory) 有助于对抗上下文遗忘,提升系统稳定性。*
72
- `.trim();
73
- }
74
- else {
75
- return `
76
- 📊 **Principles Disciple - System Dashboard**
77
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
78
- 🛡️ **Security Stage**: Stage ${stage} (${title})
79
- 💰 **Trust Score**: ${progressBar} ${trustScore}/100
80
- 🧠 **Cognitive Hygiene**: ${hygieneBar} ${hygiene.persistenceCount} actions (Today)
81
-
82
- **Current Permissions**:
83
- ${permissions}
84
-
85
- **Knowledge Assets Today**:
86
- - Physical Persists: ${hygiene.persistenceCount} actions
87
- - Total Chars: ${hygiene.totalCharsPersisted} chars
88
- - Workspace Grooming: ${hygiene.groomingExecutedCount > 0 ? '🟢 Good' : '🟡 Pending'}
89
-
90
- **Next Promotion Requirement**: ${nextLevel}
91
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
92
- *💡 Hint: Frequent notes (PLAN.md/memory) prevent amnesia and ensure task continuity.*
93
- `.trim();
31
+ return [
32
+ 'Principles Disciple - Legacy Trust',
33
+ '=================================',
34
+ '',
35
+ `- Legacy Trust: ${trustBar} ${trustScore}/100`,
36
+ `- Stage: ${stage} (${formatStageTitle(stage, true)})`,
37
+ `- Status: legacy/frozen`,
38
+ `- Reward Policy: ${rewardPolicy}`,
39
+ `- Last Updated: ${lastUpdated}`,
40
+ '',
41
+ '说明',
42
+ '- 这是兼容旧控制面的 legacy trust 视图,不再代表新的长期能力模型。',
43
+ '- `tool_success` `subagent_success` 不再自动提升 trust。',
44
+ '- 当前观察窗口内,trust 主要保留为兼容读数与 gate 兼容输入。',
45
+ '',
46
+ '认知卫生',
47
+ `- Persistence: ${hygieneBar} ${hygiene.persistenceCount} actions today`,
48
+ `- Total Chars Persisted: ${hygiene.totalCharsPersisted}`,
49
+ `- Workspace Grooming: ${hygiene.groomingExecutedCount > 0 ? 'done' : 'pending'}`,
50
+ '',
51
+ '下一步',
52
+ '- 在进入 Phase 3 capability shadow 之前,先看 production observation 数据是否稳定。',
53
+ ].join('\n');
94
54
  }
55
+ return [
56
+ 'Principles Disciple - Legacy Trust',
57
+ '=================================',
58
+ '',
59
+ `- Legacy Trust: ${trustBar} ${trustScore}/100`,
60
+ `- Stage: ${stage} (${formatStageTitle(stage, false)})`,
61
+ '- Status: legacy/frozen',
62
+ `- Reward Policy: ${rewardPolicy}`,
63
+ `- Last Updated: ${lastUpdated}`,
64
+ '',
65
+ 'Notes',
66
+ '- This is a compatibility view of legacy trust, not the future long-term capability model.',
67
+ '- `tool_success` and `subagent_success` no longer raise trust automatically.',
68
+ '- During the current observation window, trust remains mainly for compatibility reads and gate compatibility.',
69
+ '',
70
+ 'Cognitive Hygiene',
71
+ `- Persistence: ${hygieneBar} ${hygiene.persistenceCount} actions today`,
72
+ `- Total Chars Persisted: ${hygiene.totalCharsPersisted}`,
73
+ `- Workspace Grooming: ${hygiene.groomingExecutedCount > 0 ? 'done' : 'pending'}`,
74
+ '',
75
+ 'Next',
76
+ '- Do not move into Phase 3 capability shadow until production observation data is stable.',
77
+ ].join('\n');
95
78
  }
@@ -0,0 +1,17 @@
1
+ export declare const READ_ONLY_TOOL_NAMES: readonly ["read", "read_file", "read_many_files", "image_read", "search_file_content", "grep", "grep_search", "list_directory", "ls", "glob", "lsp_hover", "lsp_goto_definition", "lsp_find_references", "web_fetch", "web_search", "ref_search_documentation", "ref_read_url", "resolve-library-id", "get-library-docs", "memory_recall", "save_memory", "todo_read", "todo_write", "ask_user", "ask_user_question", "deep_reflect", "pd-status", "trust", "report"];
2
+ export declare const LOW_RISK_WRITE_TOOL_NAMES: readonly ["write", "write_file", "edit", "edit_file", "replace", "apply_patch", "insert", "patch"];
3
+ export declare const BASH_TOOL_NAMES: readonly ["bash", "run_shell_command", "exec", "execute", "shell", "cmd"];
4
+ export declare const HIGH_RISK_TOOL_NAMES: readonly ["delete_file", "move_file", "bash", "run_shell_command", "exec", "execute", "shell", "cmd"];
5
+ export declare const AGENT_TOOL_NAMES: readonly ["pd_run_worker", "sessions_spawn"];
6
+ export declare const CONTENT_LIMITED_TOOL_NAMES: readonly ["write", "write_file", "edit", "edit_file", "replace", "apply_patch", "insert", "patch"];
7
+ export declare const CONSTRUCTIVE_TOOL_NAMES: readonly ["write", "write_file", "edit", "edit_file", "replace", "apply_patch", "insert", "patch", "delete_file", "move_file", "bash", "run_shell_command", "exec", "execute", "shell", "cmd", "pd_run_worker", "sessions_spawn", "evolve-task", "init-strategy"];
8
+ export declare const EXPLORATORY_TOOL_NAMES: readonly ["read", "read_file", "read_many_files", "image_read", "search_file_content", "grep", "grep_search", "list_directory", "ls", "glob", "lsp_hover", "lsp_goto_definition", "lsp_find_references", "web_fetch", "web_search", "ref_search_documentation", "ref_read_url", "resolve-library-id", "get-library-docs", "memory_recall", "save_memory", "todo_read", "todo_write", "ask_user", "ask_user_question", "deep_reflect", "pd-status", "trust", "report"];
9
+ export declare const READ_ONLY_TOOLS: Set<string>;
10
+ export declare const LOW_RISK_WRITE_TOOLS: Set<string>;
11
+ export declare const HIGH_RISK_TOOLS: Set<string>;
12
+ export declare const BASH_TOOLS_SET: Set<string>;
13
+ export declare const AGENT_TOOLS: Set<string>;
14
+ export declare const CONTENT_LIMITED_TOOLS: Set<string>;
15
+ export declare const CONSTRUCTIVE_TOOLS: Set<string>;
16
+ export declare const EXPLORATORY_TOOLS: Set<string>;
17
+ export declare const WRITE_TOOLS: Set<string>;
@@ -0,0 +1,54 @@
1
+ export const READ_ONLY_TOOL_NAMES = [
2
+ 'read', 'read_file', 'read_many_files', 'image_read',
3
+ 'search_file_content', 'grep', 'grep_search', 'list_directory', 'ls', 'glob',
4
+ 'lsp_hover', 'lsp_goto_definition', 'lsp_find_references',
5
+ 'web_fetch', 'web_search', 'ref_search_documentation', 'ref_read_url',
6
+ 'resolve-library-id', 'get-library-docs',
7
+ 'memory_recall', 'save_memory', 'todo_read', 'todo_write',
8
+ 'ask_user', 'ask_user_question',
9
+ 'deep_reflect',
10
+ 'pd-status', 'trust', 'report',
11
+ ];
12
+ export const LOW_RISK_WRITE_TOOL_NAMES = [
13
+ 'write', 'write_file',
14
+ 'edit', 'edit_file', 'replace', 'apply_patch', 'insert', 'patch',
15
+ ];
16
+ // BASH aliases must be defined before HIGH_RISK_TOOL_NAMES
17
+ export const BASH_TOOL_NAMES = [
18
+ 'bash', 'run_shell_command', 'exec', 'execute', 'shell', 'cmd',
19
+ ];
20
+ export const HIGH_RISK_TOOL_NAMES = [
21
+ 'delete_file', 'move_file',
22
+ // Include all BASH aliases for consistent high-risk classification
23
+ ...BASH_TOOL_NAMES,
24
+ ];
25
+ export const AGENT_TOOL_NAMES = [
26
+ 'pd_run_worker', 'sessions_spawn',
27
+ ];
28
+ export const CONTENT_LIMITED_TOOL_NAMES = [
29
+ ...LOW_RISK_WRITE_TOOL_NAMES,
30
+ ];
31
+ export const CONSTRUCTIVE_TOOL_NAMES = [
32
+ ...LOW_RISK_WRITE_TOOL_NAMES,
33
+ 'delete_file', 'move_file',
34
+ // Include all BASH aliases for consistent constructive classification
35
+ ...BASH_TOOL_NAMES,
36
+ ...AGENT_TOOL_NAMES,
37
+ 'evolve-task', 'init-strategy',
38
+ ];
39
+ export const EXPLORATORY_TOOL_NAMES = [
40
+ ...READ_ONLY_TOOL_NAMES,
41
+ ];
42
+ export const READ_ONLY_TOOLS = new Set(READ_ONLY_TOOL_NAMES);
43
+ export const LOW_RISK_WRITE_TOOLS = new Set(LOW_RISK_WRITE_TOOL_NAMES);
44
+ export const HIGH_RISK_TOOLS = new Set(HIGH_RISK_TOOL_NAMES);
45
+ export const BASH_TOOLS_SET = new Set(BASH_TOOL_NAMES);
46
+ export const AGENT_TOOLS = new Set(AGENT_TOOL_NAMES);
47
+ export const CONTENT_LIMITED_TOOLS = new Set(CONTENT_LIMITED_TOOL_NAMES);
48
+ export const CONSTRUCTIVE_TOOLS = new Set(CONSTRUCTIVE_TOOL_NAMES);
49
+ export const EXPLORATORY_TOOLS = new Set(EXPLORATORY_TOOL_NAMES);
50
+ export const WRITE_TOOLS = new Set([
51
+ ...LOW_RISK_WRITE_TOOL_NAMES,
52
+ 'delete_file',
53
+ 'move_file',
54
+ ]);
@@ -1,4 +1,4 @@
1
- import type { DailyStats, EmpathyEventStats, ToolCallEventData, PainSignalEventData, RuleMatchEventData, RulePromotionEventData, HookExecutionEventData, GateBlockEventData, GateBypassEventData, PlanApprovalEventData, EvolutionTaskEventData, DeepReflectionEventData, TrustChangeEventData, EmpathyRollbackEventData } from '../types/event-types.js';
1
+ import type { EventLogEntry, DailyStats, EmpathyEventStats, ToolCallEventData, PainSignalEventData, RuleMatchEventData, RulePromotionEventData, HookExecutionEventData, GateBlockEventData, GateBypassEventData, 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.
@@ -33,6 +33,14 @@ export declare class EventLog {
33
33
  private updateStats;
34
34
  private startFlushTimer;
35
35
  flush(): void;
36
+ /**
37
+ * Return in-memory buffered events that have not been flushed yet.
38
+ * Intended for live runtime summaries that should not lag behind disk snapshots.
39
+ */
40
+ getBufferedEvents(): EventLogEntry[];
41
+ private getEventDedupKey;
42
+ private readPersistedEvents;
43
+ private getMergedEvents;
36
44
  private flushEvents;
37
45
  private flushStats;
38
46
  /**
@@ -71,4 +79,5 @@ export declare class EventLogService {
71
79
  private static instances;
72
80
  static get(stateDir: string, logger?: PluginLogger): EventLog;
73
81
  static flushAll(): void;
82
+ static disposeAll(): void;
74
83
  }