principles-disciple 1.5.4 โ†’ 1.7.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 (88) hide show
  1. package/dist/commands/context.d.ts +5 -0
  2. package/dist/commands/context.js +312 -0
  3. package/dist/commands/evolution-status.d.ts +4 -0
  4. package/dist/commands/evolution-status.js +138 -0
  5. package/dist/commands/export.d.ts +2 -0
  6. package/dist/commands/export.js +45 -0
  7. package/dist/commands/focus.d.ts +14 -0
  8. package/dist/commands/focus.js +582 -0
  9. package/dist/commands/pain.js +143 -6
  10. package/dist/commands/principle-rollback.d.ts +4 -0
  11. package/dist/commands/principle-rollback.js +22 -0
  12. package/dist/commands/rollback.d.ts +19 -0
  13. package/dist/commands/rollback.js +119 -0
  14. package/dist/commands/samples.d.ts +2 -0
  15. package/dist/commands/samples.js +55 -0
  16. package/dist/core/config.d.ts +37 -0
  17. package/dist/core/config.js +47 -0
  18. package/dist/core/control-ui-db.d.ts +68 -0
  19. package/dist/core/control-ui-db.js +274 -0
  20. package/dist/core/detection-funnel.d.ts +1 -1
  21. package/dist/core/detection-funnel.js +4 -0
  22. package/dist/core/dictionary.d.ts +2 -0
  23. package/dist/core/dictionary.js +13 -0
  24. package/dist/core/event-log.d.ts +22 -1
  25. package/dist/core/event-log.js +319 -0
  26. package/dist/core/evolution-engine.d.ts +5 -5
  27. package/dist/core/evolution-engine.js +18 -18
  28. package/dist/core/evolution-migration.d.ts +5 -0
  29. package/dist/core/evolution-migration.js +65 -0
  30. package/dist/core/evolution-reducer.d.ts +69 -0
  31. package/dist/core/evolution-reducer.js +369 -0
  32. package/dist/core/evolution-types.d.ts +103 -0
  33. package/dist/core/focus-history.d.ts +65 -0
  34. package/dist/core/focus-history.js +266 -0
  35. package/dist/core/init.js +30 -7
  36. package/dist/core/migration.js +0 -2
  37. package/dist/core/path-resolver.d.ts +3 -0
  38. package/dist/core/path-resolver.js +90 -31
  39. package/dist/core/paths.d.ts +7 -8
  40. package/dist/core/paths.js +48 -40
  41. package/dist/core/profile.js +1 -1
  42. package/dist/core/session-tracker.d.ts +4 -0
  43. package/dist/core/session-tracker.js +15 -0
  44. package/dist/core/thinking-models.d.ts +38 -0
  45. package/dist/core/thinking-models.js +170 -0
  46. package/dist/core/trajectory.d.ts +184 -0
  47. package/dist/core/trajectory.js +817 -0
  48. package/dist/core/trust-engine.d.ts +2 -0
  49. package/dist/core/trust-engine.js +30 -4
  50. package/dist/core/workspace-context.d.ts +13 -0
  51. package/dist/core/workspace-context.js +50 -7
  52. package/dist/hooks/gate.js +301 -30
  53. package/dist/hooks/llm.d.ts +8 -0
  54. package/dist/hooks/llm.js +347 -69
  55. package/dist/hooks/message-sanitize.d.ts +3 -0
  56. package/dist/hooks/message-sanitize.js +37 -0
  57. package/dist/hooks/pain.js +105 -5
  58. package/dist/hooks/prompt.d.ts +20 -11
  59. package/dist/hooks/prompt.js +558 -158
  60. package/dist/hooks/subagent.d.ts +9 -2
  61. package/dist/hooks/subagent.js +40 -3
  62. package/dist/http/principles-console-route.d.ts +2 -0
  63. package/dist/http/principles-console-route.js +257 -0
  64. package/dist/i18n/commands.js +48 -20
  65. package/dist/index.js +264 -8
  66. package/dist/service/control-ui-query-service.d.ts +217 -0
  67. package/dist/service/control-ui-query-service.js +537 -0
  68. package/dist/service/empathy-observer-manager.d.ts +42 -0
  69. package/dist/service/empathy-observer-manager.js +147 -0
  70. package/dist/service/evolution-worker.d.ts +10 -0
  71. package/dist/service/evolution-worker.js +156 -24
  72. package/dist/service/trajectory-service.d.ts +2 -0
  73. package/dist/service/trajectory-service.js +15 -0
  74. package/dist/tools/agent-spawn.d.ts +27 -6
  75. package/dist/tools/agent-spawn.js +339 -87
  76. package/dist/tools/deep-reflect.d.ts +27 -7
  77. package/dist/tools/deep-reflect.js +282 -113
  78. package/dist/types/event-types.d.ts +84 -2
  79. package/dist/types/event-types.js +33 -0
  80. package/dist/types.d.ts +52 -0
  81. package/dist/types.js +24 -1
  82. package/openclaw.plugin.json +43 -11
  83. package/package.json +16 -6
  84. package/templates/langs/zh/core/HEARTBEAT.md +28 -4
  85. package/templates/langs/zh/skills/pd-daily/SKILL.md +97 -13
  86. package/templates/pain_settings.json +54 -2
  87. package/templates/workspace/.principles/PROFILE.json +2 -0
  88. package/templates/workspace/okr/CURRENT_FOCUS.md +57 -0
@@ -0,0 +1,5 @@
1
+ import type { PluginCommandContext, PluginCommandResult } from '../openclaw-sdk.js';
2
+ /**
3
+ * Main command handler
4
+ */
5
+ export declare function handleContextCommand(ctx: PluginCommandContext): PluginCommandResult;
@@ -0,0 +1,312 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { defaultContextConfig } from '../types.js';
4
+ import { loadContextInjectionConfig } from '../hooks/prompt.js';
5
+ /**
6
+ * Get workspace directory from context
7
+ */
8
+ function getWorkspaceDir(ctx) {
9
+ const workspaceDir = ctx.config?.workspaceDir || process.cwd();
10
+ if (!workspaceDir) {
11
+ throw new Error('[PD:Context] workspaceDir is required but not provided');
12
+ }
13
+ return workspaceDir;
14
+ }
15
+ /**
16
+ * Save context injection config to PROFILE.json
17
+ */
18
+ function saveConfig(workspaceDir, config) {
19
+ const profilePath = path.join(workspaceDir, '.principles', 'PROFILE.json');
20
+ try {
21
+ // Ensure directory exists
22
+ const dir = path.dirname(profilePath);
23
+ if (!fs.existsSync(dir)) {
24
+ fs.mkdirSync(dir, { recursive: true });
25
+ }
26
+ // Load existing profile or create new one
27
+ let profile = {};
28
+ if (fs.existsSync(profilePath)) {
29
+ const raw = fs.readFileSync(profilePath, 'utf-8');
30
+ profile = JSON.parse(raw);
31
+ }
32
+ // Update contextInjection
33
+ profile.contextInjection = config;
34
+ // Write back
35
+ fs.writeFileSync(profilePath, JSON.stringify(profile, null, 2), 'utf-8');
36
+ return true;
37
+ }
38
+ catch (e) {
39
+ console.error(`[PD:Context] Failed to save config: ${String(e)}`);
40
+ return false;
41
+ }
42
+ }
43
+ /**
44
+ * Format project focus value for display
45
+ */
46
+ function formatProjectFocus(value, isZh) {
47
+ const labels = {
48
+ full: { zh: '๐Ÿ“ฆ ๅฎŒๆ•ด', en: '๐Ÿ“ฆ Full' },
49
+ summary: { zh: '๐Ÿ“ ๆ‘˜่ฆ', en: '๐Ÿ“ Summary' },
50
+ off: { zh: 'โŒ ๅ…ณ้—ญ', en: 'โŒ Off' }
51
+ };
52
+ return labels[value][isZh ? 'zh' : 'en'];
53
+ }
54
+ /**
55
+ * Show current context injection status
56
+ */
57
+ function showStatus(workspaceDir, isZh) {
58
+ const config = loadContextInjectionConfig(workspaceDir);
59
+ if (isZh) {
60
+ return `
61
+ ๐Ÿ“Š **ไธŠไธ‹ๆ–‡ๆณจๅ…ฅ็Šถๆ€**
62
+
63
+ | ๅ†…ๅฎน | ็Šถๆ€ | ่ฏดๆ˜Ž |
64
+ |------|------|------|
65
+ | ๆ ธๅฟƒๅŽŸๅˆ™ | โœ… ๅง‹็ปˆๅผ€ๅฏ | ไธๅฏๅ…ณ้—ญ |
66
+ | ๆ€็ปดๆจกๅž‹ | ${config.thinkingOs ? 'โœ… ๅผ€ๅฏ' : 'โŒ ๅ…ณ้—ญ'} | /pd-context thinking on/off |
67
+ | ไฟกไปปๅˆ†ๆ•ฐ | ${config.trustScore ? 'โœ… ๅผ€ๅฏ' : 'โŒ ๅ…ณ้—ญ'} | /pd-context trust on/off |
68
+ | ๅๆ€ๆ—ฅๅฟ— | ${config.reflectionLog ? 'โœ… ๅผ€ๅฏ' : 'โŒ ๅ…ณ้—ญ'} | /pd-context reflection on/off |
69
+ | ้กน็›ฎไธŠไธ‹ๆ–‡ | ${formatProjectFocus(config.projectFocus, isZh)} | /pd-context focus full/summary/off |
70
+
71
+ ๐Ÿ’ก ่พ“ๅ…ฅ \`/pd-context help\` ๆŸฅ็œ‹ๆ›ดๅคš้€‰้กน
72
+ `.trim();
73
+ }
74
+ else {
75
+ return `
76
+ ๐Ÿ“Š **Context Injection Status**
77
+
78
+ | Content | Status | Control |
79
+ |---------|--------|---------|
80
+ | Core Principles | โœ… Always ON | Not configurable |
81
+ | Thinking OS | ${config.thinkingOs ? 'โœ… ON' : 'โŒ OFF'} | /pd-context thinking on/off |
82
+ | Trust Score | ${config.trustScore ? 'โœ… ON' : 'โŒ OFF'} | /pd-context trust on/off |
83
+ | Reflection Log | ${config.reflectionLog ? 'โœ… ON' : 'โŒ OFF'} | /pd-context reflection on/off |
84
+ | Project Context | ${formatProjectFocus(config.projectFocus, isZh)} | /pd-context focus full/summary/off |
85
+
86
+ ๐Ÿ’ก Type \`/pd-context help\` for more options
87
+ `.trim();
88
+ }
89
+ }
90
+ /**
91
+ * Toggle a boolean setting
92
+ */
93
+ function toggleSetting(workspaceDir, key, value, isZh) {
94
+ const config = loadContextInjectionConfig(workspaceDir);
95
+ const oldValue = config[key];
96
+ if (value === 'on') {
97
+ config[key] = true;
98
+ }
99
+ else if (value === 'off') {
100
+ config[key] = false;
101
+ }
102
+ else {
103
+ return isZh
104
+ ? `โŒ ๆ— ๆ•ˆๅ€ผ: "${value}"ใ€‚ไฝฟ็”จ "on" ๆˆ– "off"ใ€‚`
105
+ : `โŒ Invalid value: "${value}". Use "on" or "off".`;
106
+ }
107
+ const newValue = config[key];
108
+ const keyName = isZh
109
+ ? { thinkingOs: 'ๆ€็ปดๆจกๅž‹', trustScore: 'ไฟกไปปๅˆ†ๆ•ฐ', reflectionLog: 'ๅๆ€ๆ—ฅๅฟ—' }[key]
110
+ : key;
111
+ // No change needed
112
+ if (oldValue === newValue) {
113
+ return isZh
114
+ ? `โ„น๏ธ ${keyName} ๅทฒ็ปๆ˜ฏ ${newValue ? 'ๅผ€ๅฏ' : 'ๅ…ณ้—ญ'} ็Šถๆ€`
115
+ : `โ„น๏ธ ${keyName} is already ${newValue ? 'ON' : 'OFF'}`;
116
+ }
117
+ if (saveConfig(workspaceDir, config)) {
118
+ // Verify the save by re-reading
119
+ const verifyConfig = loadContextInjectionConfig(workspaceDir);
120
+ const verifyValue = verifyConfig[key];
121
+ if (verifyValue !== newValue) {
122
+ return isZh
123
+ ? `โš ๏ธ ${keyName} ไฟๅญ˜ๅŽ้ชŒ่ฏๅคฑ่ดฅ๏ผŒ่ฏท้‡่ฏ•`
124
+ : `โš ๏ธ ${keyName} verification failed after save, please retry`;
125
+ }
126
+ const arrow = isZh ? 'โ†’' : 'โ†’';
127
+ const oldLabel = oldValue ? (isZh ? 'ๅผ€ๅฏ' : 'ON') : (isZh ? 'ๅ…ณ้—ญ' : 'OFF');
128
+ const newLabel = newValue ? (isZh ? 'ๅผ€ๅฏ' : 'ON') : (isZh ? 'ๅ…ณ้—ญ' : 'OFF');
129
+ return isZh
130
+ ? `โœ… ${keyName} ๅทฒๆ›ดๆ–ฐ: ${oldLabel} ${arrow} ${newLabel}\n\n๐Ÿ’ก ไธ‹ๆฌกๅฏน่ฏๆ—ถ็”Ÿๆ•ˆ`
131
+ : `โœ… ${keyName} updated: ${oldLabel} ${arrow} ${newLabel}\n\n๐Ÿ’ก Takes effect on next turn`;
132
+ }
133
+ else {
134
+ return isZh
135
+ ? `โŒ ไฟๅญ˜้…็ฝฎๅคฑ่ดฅ`
136
+ : `โŒ Failed to save configuration`;
137
+ }
138
+ }
139
+ /**
140
+ * Set project focus mode
141
+ */
142
+ function setProjectFocus(workspaceDir, value, isZh) {
143
+ const config = loadContextInjectionConfig(workspaceDir);
144
+ const oldValue = config.projectFocus;
145
+ const validModes = ['full', 'summary', 'off'];
146
+ if (!validModes.includes(value)) {
147
+ return isZh
148
+ ? `โŒ ๆ— ๆ•ˆๅ€ผ: "${value}"ใ€‚ไฝฟ็”จ "full"ใ€"summary" ๆˆ– "off"ใ€‚`
149
+ : `โŒ Invalid value: "${value}". Use "full", "summary", or "off".`;
150
+ }
151
+ const newValue = value;
152
+ config.projectFocus = newValue;
153
+ // No change needed
154
+ if (oldValue === newValue) {
155
+ return isZh
156
+ ? `โ„น๏ธ ้กน็›ฎไธŠไธ‹ๆ–‡ๅทฒ็ปๆ˜ฏ ${formatProjectFocus(newValue, isZh)} ็Šถๆ€`
157
+ : `โ„น๏ธ Project context is already ${formatProjectFocus(newValue, isZh)}`;
158
+ }
159
+ if (saveConfig(workspaceDir, config)) {
160
+ // Verify the save by re-reading
161
+ const verifyConfig = loadContextInjectionConfig(workspaceDir);
162
+ if (verifyConfig.projectFocus !== newValue) {
163
+ return isZh
164
+ ? `โš ๏ธ ้กน็›ฎไธŠไธ‹ๆ–‡ไฟๅญ˜ๅŽ้ชŒ่ฏๅคฑ่ดฅ๏ผŒ่ฏท้‡่ฏ•`
165
+ : `โš ๏ธ Project context verification failed after save, please retry`;
166
+ }
167
+ const arrow = 'โ†’';
168
+ return isZh
169
+ ? `โœ… ้กน็›ฎไธŠไธ‹ๆ–‡ๅทฒๆ›ดๆ–ฐ: ${formatProjectFocus(oldValue, isZh)} ${arrow} ${formatProjectFocus(newValue, isZh)}\n\n๐Ÿ’ก ไธ‹ๆฌกๅฏน่ฏๆ—ถ็”Ÿๆ•ˆ`
170
+ : `โœ… Project context updated: ${formatProjectFocus(oldValue, isZh)} ${arrow} ${formatProjectFocus(newValue, isZh)}\n\n๐Ÿ’ก Takes effect on next turn`;
171
+ }
172
+ else {
173
+ return isZh
174
+ ? `โŒ ไฟๅญ˜้…็ฝฎๅคฑ่ดฅ`
175
+ : `โŒ Failed to save configuration`;
176
+ }
177
+ }
178
+ /**
179
+ * Apply a preset configuration
180
+ */
181
+ function applyPreset(workspaceDir, preset, isZh) {
182
+ let config;
183
+ switch (preset) {
184
+ case 'minimal':
185
+ config = {
186
+ thinkingOs: false,
187
+ trustScore: true,
188
+ reflectionLog: false,
189
+ projectFocus: 'off',
190
+ evolutionContext: { ...defaultContextConfig.evolutionContext }
191
+ };
192
+ break;
193
+ case 'standard':
194
+ config = {
195
+ thinkingOs: true,
196
+ trustScore: true,
197
+ reflectionLog: false,
198
+ projectFocus: 'off',
199
+ evolutionContext: { ...defaultContextConfig.evolutionContext }
200
+ };
201
+ break;
202
+ case 'full':
203
+ config = {
204
+ thinkingOs: true,
205
+ trustScore: true,
206
+ reflectionLog: true,
207
+ projectFocus: 'summary',
208
+ evolutionContext: { ...defaultContextConfig.evolutionContext }
209
+ };
210
+ break;
211
+ }
212
+ if (saveConfig(workspaceDir, config)) {
213
+ const presetName = isZh
214
+ ? { minimal: 'ๆœ€ๅฐๆจกๅผ', standard: 'ๆ ‡ๅ‡†ๆจกๅผ', full: 'ๅฎŒๆ•ดๆจกๅผ' }[preset]
215
+ : `${preset} mode`;
216
+ return isZh
217
+ ? `โœ… ๅทฒๅบ”็”จ้ข„่ฎพ: ${presetName}\n\n${showStatus(workspaceDir, isZh)}`
218
+ : `โœ… Applied preset: ${presetName}\n\n${showStatus(workspaceDir, isZh)}`;
219
+ }
220
+ else {
221
+ return isZh
222
+ ? `โŒ ไฟๅญ˜้…็ฝฎๅคฑ่ดฅ`
223
+ : `โŒ Failed to save configuration`;
224
+ }
225
+ }
226
+ /**
227
+ * Show help message
228
+ */
229
+ function showHelp(isZh) {
230
+ if (isZh) {
231
+ return `
232
+ ๐Ÿ“– **/pd-context ๅ‘ฝไปคๅธฎๅŠฉ**
233
+
234
+ **ๆŸฅ็œ‹็Šถๆ€**:
235
+ \`/pd-context status\` - ๆ˜พ็คบๅฝ“ๅ‰ไธŠไธ‹ๆ–‡ๆณจๅ…ฅ็Šถๆ€
236
+
237
+ **ๅ•้กนๆŽงๅˆถ**:
238
+ \`/pd-context thinking on/off\` - ๅผ€ๅ…ณๆ€็ปดๆจกๅž‹
239
+ \`/pd-context trust on/off\` - ๅผ€ๅ…ณไฟกไปปๅˆ†ๆ•ฐ
240
+ \`/pd-context reflection on/off\` - ๅผ€ๅ…ณๅๆ€ๆ—ฅๅฟ—
241
+ \`/pd-context focus full/summary/off\` - ่ฎพ็ฝฎ้กน็›ฎไธŠไธ‹ๆ–‡ๆจกๅผ
242
+
243
+ **้ข„่ฎพๆจกๅผ**:
244
+ \`/pd-context minimal\` - ๆœ€ๅฐๆจกๅผ๏ผˆไป…ไฟกไปปๅˆ†ๆ•ฐ๏ผ‰
245
+ \`/pd-context standard\` - ๆ ‡ๅ‡†ๆจกๅผ๏ผˆๅŽŸๅˆ™+ๆ€็ปดๆจกๅž‹+ไฟกไปปๅˆ†ๆ•ฐ๏ผ‰
246
+ \`/pd-context full\` - ๅฎŒๆ•ดๆจกๅผ๏ผˆๅ…จ้ƒจๅผ€ๅฏ๏ผ‰
247
+
248
+ **ๆณจๆ„**: ๆ ธๅฟƒๅŽŸๅˆ™ๅง‹็ปˆๆณจๅ…ฅ๏ผŒไธๅฏๅ…ณ้—ญใ€‚
249
+ `.trim();
250
+ }
251
+ else {
252
+ return `
253
+ ๐Ÿ“– **/pd-context Command Help**
254
+
255
+ **View Status**:
256
+ \`/pd-context status\` - Show current context injection status
257
+
258
+ **Individual Control**:
259
+ \`/pd-context thinking on/off\` - Toggle Thinking OS
260
+ \`/pd-context trust on/off\` - Toggle Trust Score
261
+ \`/pd-context reflection on/off\` - Toggle Reflection Log
262
+ \`/pd-context focus full/summary/off\` - Set Project Context mode
263
+
264
+ **Presets**:
265
+ \`/pd-context minimal\` - Minimal mode (trust score only)
266
+ \`/pd-context standard\` - Standard mode (principles + thinking + trust)
267
+ \`/pd-context full\` - Full mode (all enabled)
268
+
269
+ **Note**: Core Principles are always injected and cannot be disabled.
270
+ `.trim();
271
+ }
272
+ }
273
+ /**
274
+ * Main command handler
275
+ */
276
+ export function handleContextCommand(ctx) {
277
+ const workspaceDir = getWorkspaceDir(ctx);
278
+ const args = (ctx.args || '').trim().split(/\s+/);
279
+ const subCommand = args[0]?.toLowerCase() || 'status';
280
+ const value = args[1]?.toLowerCase() || '';
281
+ // Detect language from context
282
+ const isZh = ctx.config?.language === 'zh';
283
+ let result;
284
+ switch (subCommand) {
285
+ case 'status':
286
+ result = showStatus(workspaceDir, isZh);
287
+ break;
288
+ case 'thinking':
289
+ result = toggleSetting(workspaceDir, 'thinkingOs', value, isZh);
290
+ break;
291
+ case 'trust':
292
+ result = toggleSetting(workspaceDir, 'trustScore', value, isZh);
293
+ break;
294
+ case 'reflection':
295
+ result = toggleSetting(workspaceDir, 'reflectionLog', value, isZh);
296
+ break;
297
+ case 'focus':
298
+ result = setProjectFocus(workspaceDir, value, isZh);
299
+ break;
300
+ case 'minimal':
301
+ case 'standard':
302
+ case 'full':
303
+ result = applyPreset(workspaceDir, subCommand, isZh);
304
+ break;
305
+ case 'help':
306
+ result = showHelp(isZh);
307
+ break;
308
+ default:
309
+ result = showHelp(isZh);
310
+ }
311
+ return { text: result };
312
+ }
@@ -0,0 +1,4 @@
1
+ import type { PluginCommandContext } from '../openclaw-sdk.js';
2
+ export declare function handleEvolutionStatusCommand(ctx: PluginCommandContext): {
3
+ text: string;
4
+ };
@@ -0,0 +1,138 @@
1
+ import { EvolutionReducerImpl } from '../core/evolution-reducer.js';
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
+ }
28
+ }
29
+ catch {
30
+ // Ignore errors, return zeros
31
+ }
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
+ }
45
+ }
46
+ catch {
47
+ // Ignore errors
48
+ }
49
+ return { painScore: 0, painSource: 'none' };
50
+ }
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
79
+ }
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') };
112
+ }
113
+ // English
114
+ const lines = [
115
+ '๐Ÿ“ˆ Evolution Status',
116
+ 'โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”',
117
+ '',
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}`,
122
+ '',
123
+ '๐Ÿ“Š Evolution Rules',
124
+ 'โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”',
125
+ `- candidate principles: ${stats.candidateCount}`,
126
+ `- probation principles: ${stats.probationCount}`,
127
+ `- active principles: ${stats.activeCount}`,
128
+ `- deprecated principles: ${stats.deprecatedCount}`,
129
+ `- last promoted: ${stats.lastPromotedAt ?? 'none'}`,
130
+ '',
131
+ '๐Ÿ“‹ Evolution Queue',
132
+ 'โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”',
133
+ `- Pending: ${queueStats.pending}`,
134
+ `- In Progress: ${queueStats.inProgress}`,
135
+ `- Completed: ${queueStats.completed}`,
136
+ ];
137
+ return { text: lines.join('\n') };
138
+ }
@@ -0,0 +1,2 @@
1
+ import type { PluginCommandContext, PluginCommandResult } from '../openclaw-sdk.js';
2
+ export declare function handleExportCommand(ctx: PluginCommandContext): PluginCommandResult;
@@ -0,0 +1,45 @@
1
+ import { WorkspaceContext } from '../core/workspace-context.js';
2
+ function isZh(ctx) {
3
+ return String(ctx.config?.language || 'en').startsWith('zh');
4
+ }
5
+ export function handleExportCommand(ctx) {
6
+ const workspaceDir = ctx.config?.workspaceDir || process.cwd();
7
+ const zh = isZh(ctx);
8
+ const args = (ctx.args || '').trim();
9
+ const [subcommand = 'corrections'] = args.split(/\s+/).filter(Boolean);
10
+ const wctx = WorkspaceContext.fromHookContext({ workspaceDir, ...ctx.config });
11
+ if (subcommand !== 'analytics' && subcommand !== 'corrections') {
12
+ return {
13
+ text: zh
14
+ ? 'ๆ— ๆ•ˆ็š„ๅฏผๅ‡บ็ฑปๅž‹ใ€‚่ฏทไฝฟ็”จ `analytics` ๆˆ– `corrections [--redacted]`ใ€‚'
15
+ : 'Invalid export target. Use `analytics` or `corrections [--redacted]`.',
16
+ };
17
+ }
18
+ try {
19
+ if (subcommand === 'analytics') {
20
+ const result = wctx.trajectory.exportAnalytics();
21
+ return {
22
+ text: zh
23
+ ? `ๅทฒๅฏผๅ‡บ analytics ๅฟซ็…งๅˆฐ ${result.filePath}๏ผŒๅ…ฑ ${result.count} ๆก่šๅˆ่ฎฐๅฝ•ใ€‚`
24
+ : `Exported analytics snapshot to ${result.filePath} (${result.count} aggregated rows).`,
25
+ };
26
+ }
27
+ const redacted = args.includes('--redacted');
28
+ const result = wctx.trajectory.exportCorrections({
29
+ mode: redacted ? 'redacted' : 'raw',
30
+ approvedOnly: true,
31
+ });
32
+ return {
33
+ text: zh
34
+ ? `ๅทฒๅฏผๅ‡บ็บ ้”™ๆ ทๆœฌๅˆฐ ${result.filePath}๏ผŒๆจกๅผ ${result.mode}๏ผŒๅ…ฑ ${result.count} ๆกใ€‚`
35
+ : `Exported correction samples to ${result.filePath} (mode=${result.mode}, count=${result.count}).`,
36
+ };
37
+ }
38
+ catch {
39
+ return {
40
+ text: zh
41
+ ? 'ๅฏผๅ‡บๅคฑ่ดฅ๏ผŒ่ฏทๆฃ€ๆŸฅๆ—ฅๅฟ—ใ€‚'
42
+ : 'Export failed. Check logs.',
43
+ };
44
+ }
45
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * /pd-focus ๅ‘ฝไปค - ็ฎก็† CURRENT_FOCUS.md
3
+ *
4
+ * ๅŠŸ่ƒฝ๏ผš
5
+ * - status: ๆŸฅ็œ‹ๅฝ“ๅ‰็Šถๆ€ๅ’Œๅކๅฒ็‰ˆๆœฌ
6
+ * - compress: ๆ‰‹ๅŠจๅŽ‹็ผฉๅนถๅค‡ไปฝ
7
+ * - history: ๆŸฅ็œ‹ๅކๅฒ็‰ˆๆœฌๅˆ—่กจ
8
+ * - rollback: ๅ›žๆปšๅˆฐๆŒ‡ๅฎšๅކๅฒ็‰ˆๆœฌ
9
+ */
10
+ import type { PluginCommandContext, PluginCommandResult, OpenClawPluginApi } from '../openclaw-sdk.js';
11
+ /**
12
+ * ๅค„็† /pd-focus ๅ‘ฝไปค
13
+ */
14
+ export declare function handleFocusCommand(ctx: PluginCommandContext, api: OpenClawPluginApi): Promise<PluginCommandResult>;