principles-disciple 1.7.0 → 1.7.1

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.
@@ -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
  }
@@ -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,11 @@ 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[];
36
41
  private flushEvents;
37
42
  private flushStats;
38
43
  /**
@@ -169,6 +169,13 @@ export class EventLog {
169
169
  this.flushEvents();
170
170
  this.flushStats();
171
171
  }
172
+ /**
173
+ * Return in-memory buffered events that have not been flushed yet.
174
+ * Intended for live runtime summaries that should not lag behind disk snapshots.
175
+ */
176
+ getBufferedEvents() {
177
+ return this.eventBuffer.map((entry) => ({ ...entry, data: { ...entry.data } }));
178
+ }
172
179
  flushEvents() {
173
180
  if (this.eventBuffer.length === 0)
174
181
  return;
@@ -18,6 +18,8 @@ export interface SessionState {
18
18
  cacheHits: number;
19
19
  stuckLoops: number;
20
20
  currentGfi: number;
21
+ gfiBySource?: Record<string, number>;
22
+ lastErrorSource?: string;
21
23
  lastErrorHash: string;
22
24
  consecutiveErrors: number;
23
25
  dailyToolCalls: number;
@@ -41,11 +43,16 @@ export declare function trackLlmOutput(sessionId: string, usage: TokenUsage | un
41
43
  /**
42
44
  * Tracks physical friction based on tool execution failures.
43
45
  */
44
- export declare function trackFriction(sessionId: string, deltaF: number, hash: string, workspaceDir?: string): SessionState;
46
+ export declare function trackFriction(sessionId: string, deltaF: number, hash: string, workspaceDir?: string, options?: {
47
+ source?: string;
48
+ }): SessionState;
45
49
  /**
46
50
  * Resets the friction index upon successful action.
47
51
  */
48
- export declare function resetFriction(sessionId: string, workspaceDir?: string): SessionState;
52
+ export declare function resetFriction(sessionId: string, workspaceDir?: string, options?: {
53
+ source?: string;
54
+ amount?: number;
55
+ }): SessionState;
49
56
  /**
50
57
  * Records that deep thinking (Thinking OS) was performed in this session.
51
58
  * Used by the Thinking OS checkpoint to allow high-risk operations.
@@ -63,6 +70,7 @@ export declare function setInjectedProbationIds(sessionId: string, ids: string[]
63
70
  export declare function getInjectedProbationIds(sessionId: string, workspaceDir?: string): string[];
64
71
  export declare function clearInjectedProbationIds(sessionId: string, workspaceDir?: string): SessionState;
65
72
  export declare function getSession(sessionId: string): SessionState | undefined;
73
+ export declare function listSessions(workspaceDir?: string): SessionState[];
66
74
  export declare function clearSession(sessionId: string): void;
67
75
  export declare function garbageCollectSessions(): void;
68
76
  /**