principles-disciple 1.6.0 → 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 (67) hide show
  1. package/dist/commands/context.js +7 -3
  2. package/dist/commands/evolution-status.d.ts +4 -0
  3. package/dist/commands/evolution-status.js +138 -0
  4. package/dist/commands/export.d.ts +2 -0
  5. package/dist/commands/export.js +45 -0
  6. package/dist/commands/focus.js +9 -6
  7. package/dist/commands/pain.js +8 -0
  8. package/dist/commands/principle-rollback.d.ts +4 -0
  9. package/dist/commands/principle-rollback.js +22 -0
  10. package/dist/commands/samples.d.ts +2 -0
  11. package/dist/commands/samples.js +55 -0
  12. package/dist/core/config.d.ts +5 -0
  13. package/dist/core/control-ui-db.d.ts +68 -0
  14. package/dist/core/control-ui-db.js +274 -0
  15. package/dist/core/detection-funnel.d.ts +1 -1
  16. package/dist/core/detection-funnel.js +4 -0
  17. package/dist/core/dictionary.d.ts +2 -0
  18. package/dist/core/dictionary.js +13 -0
  19. package/dist/core/event-log.d.ts +2 -1
  20. package/dist/core/event-log.js +3 -0
  21. package/dist/core/evolution-engine.d.ts +5 -5
  22. package/dist/core/evolution-engine.js +18 -18
  23. package/dist/core/evolution-migration.d.ts +5 -0
  24. package/dist/core/evolution-migration.js +65 -0
  25. package/dist/core/evolution-reducer.d.ts +69 -0
  26. package/dist/core/evolution-reducer.js +369 -0
  27. package/dist/core/evolution-types.d.ts +103 -0
  28. package/dist/core/path-resolver.js +75 -36
  29. package/dist/core/paths.d.ts +7 -8
  30. package/dist/core/paths.js +48 -40
  31. package/dist/core/profile.js +1 -1
  32. package/dist/core/session-tracker.d.ts +4 -0
  33. package/dist/core/session-tracker.js +15 -0
  34. package/dist/core/thinking-models.d.ts +38 -0
  35. package/dist/core/thinking-models.js +170 -0
  36. package/dist/core/trajectory.d.ts +184 -0
  37. package/dist/core/trajectory.js +817 -0
  38. package/dist/core/trust-engine.d.ts +2 -0
  39. package/dist/core/trust-engine.js +30 -4
  40. package/dist/core/workspace-context.d.ts +13 -0
  41. package/dist/core/workspace-context.js +50 -7
  42. package/dist/hooks/gate.js +117 -48
  43. package/dist/hooks/llm.js +114 -69
  44. package/dist/hooks/pain.js +105 -5
  45. package/dist/hooks/prompt.d.ts +11 -14
  46. package/dist/hooks/prompt.js +283 -57
  47. package/dist/hooks/subagent.js +27 -1
  48. package/dist/http/principles-console-route.d.ts +2 -0
  49. package/dist/http/principles-console-route.js +257 -0
  50. package/dist/i18n/commands.js +16 -0
  51. package/dist/index.js +83 -4
  52. package/dist/service/control-ui-query-service.d.ts +217 -0
  53. package/dist/service/control-ui-query-service.js +537 -0
  54. package/dist/service/evolution-worker.d.ts +9 -0
  55. package/dist/service/evolution-worker.js +152 -22
  56. package/dist/service/trajectory-service.d.ts +2 -0
  57. package/dist/service/trajectory-service.js +15 -0
  58. package/dist/tools/agent-spawn.d.ts +27 -6
  59. package/dist/tools/agent-spawn.js +339 -87
  60. package/dist/tools/deep-reflect.d.ts +27 -7
  61. package/dist/tools/deep-reflect.js +210 -121
  62. package/dist/types/event-types.d.ts +9 -2
  63. package/dist/types.d.ts +10 -0
  64. package/dist/types.js +5 -0
  65. package/openclaw.plugin.json +43 -11
  66. package/package.json +14 -4
  67. package/templates/langs/zh/skills/pd-daily/SKILL.md +97 -13
@@ -0,0 +1,257 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { ControlUiQueryService } from '../service/control-ui-query-service.js';
4
+ const ROUTE_PREFIX = '/plugins/principles';
5
+ const API_PREFIX = `${ROUTE_PREFIX}/api`;
6
+ const ASSETS_PREFIX = `${ROUTE_PREFIX}/assets`;
7
+ function json(res, statusCode, payload) {
8
+ const body = JSON.stringify(payload, null, 2);
9
+ res.statusCode = statusCode;
10
+ res.setHeader('Content-Type', 'application/json; charset=utf-8');
11
+ res.end(body);
12
+ }
13
+ function text(res, statusCode, body) {
14
+ res.statusCode = statusCode;
15
+ res.setHeader('Content-Type', 'text/plain; charset=utf-8');
16
+ res.end(body);
17
+ }
18
+ function contentTypeFor(filePath) {
19
+ const ext = path.extname(filePath).toLowerCase();
20
+ switch (ext) {
21
+ case '.html':
22
+ return 'text/html; charset=utf-8';
23
+ case '.css':
24
+ return 'text/css; charset=utf-8';
25
+ case '.js':
26
+ return 'application/javascript; charset=utf-8';
27
+ case '.json':
28
+ return 'application/json; charset=utf-8';
29
+ case '.svg':
30
+ return 'image/svg+xml';
31
+ default:
32
+ return 'application/octet-stream';
33
+ }
34
+ }
35
+ async function readJsonBody(req) {
36
+ const chunks = [];
37
+ for await (const chunk of req) {
38
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
39
+ }
40
+ if (chunks.length === 0)
41
+ return {};
42
+ const body = Buffer.concat(chunks).toString('utf8');
43
+ try {
44
+ return JSON.parse(body);
45
+ }
46
+ catch {
47
+ throw new Error('invalid_json');
48
+ }
49
+ }
50
+ function safeStaticPath(rootDir, requestPath) {
51
+ const relative = requestPath.startsWith(ASSETS_PREFIX)
52
+ ? requestPath.slice(ASSETS_PREFIX.length).replace(/^\/+/, '')
53
+ : '';
54
+ const normalized = path.normalize(relative);
55
+ const webRoot = path.join(rootDir, 'dist', 'web');
56
+ const assetsRoot = path.join(webRoot, 'assets');
57
+ const target = path.join(assetsRoot, normalized);
58
+ const relativeTarget = path.relative(assetsRoot, target);
59
+ if (relativeTarget.startsWith('..') || path.isAbsolute(relativeTarget)) {
60
+ return null;
61
+ }
62
+ return target;
63
+ }
64
+ function serveFile(res, filePath) {
65
+ if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
66
+ return false;
67
+ }
68
+ res.statusCode = 200;
69
+ res.setHeader('Content-Type', contentTypeFor(filePath));
70
+ const stream = fs.createReadStream(filePath);
71
+ stream.on('error', () => {
72
+ res.statusCode = 500;
73
+ res.end('Internal Server Error');
74
+ });
75
+ stream.pipe(res);
76
+ return true;
77
+ }
78
+ function createService(api) {
79
+ const workspaceDir = api.resolvePath('.');
80
+ return new ControlUiQueryService(workspaceDir);
81
+ }
82
+ function handleApiRoute(api, pathname, req, res) {
83
+ const service = createService(api);
84
+ const url = new URL(req.url || pathname, 'http://127.0.0.1');
85
+ const method = (req.method || 'GET').toUpperCase();
86
+ const done = (fn) => {
87
+ try {
88
+ const payload = fn();
89
+ json(res, 200, payload);
90
+ return true;
91
+ }
92
+ catch (error) {
93
+ api.logger.warn(`[PD:ControlUI] API request failed for ${pathname}: ${String(error)}`);
94
+ json(res, 500, { error: 'internal_error', message: String(error) });
95
+ return true;
96
+ }
97
+ finally {
98
+ service.dispose();
99
+ }
100
+ };
101
+ if (pathname === `${API_PREFIX}/overview` && method === 'GET') {
102
+ return done(() => service.getOverview());
103
+ }
104
+ if (pathname === `${API_PREFIX}/samples` && method === 'GET') {
105
+ return done(() => service.listSamples({
106
+ status: url.searchParams.get('status') ?? undefined,
107
+ qualityMin: url.searchParams.has('qualityMin') ? Number(url.searchParams.get('qualityMin')) : undefined,
108
+ dateFrom: url.searchParams.get('dateFrom') ?? undefined,
109
+ dateTo: url.searchParams.get('dateTo') ?? undefined,
110
+ failureMode: url.searchParams.get('failureMode') ?? undefined,
111
+ page: url.searchParams.has('page') ? Number(url.searchParams.get('page')) : undefined,
112
+ pageSize: url.searchParams.has('pageSize') ? Number(url.searchParams.get('pageSize')) : undefined,
113
+ }));
114
+ }
115
+ const sampleDetailMatch = pathname.match(/^\/plugins\/principles\/api\/samples\/([^/]+)$/);
116
+ if (sampleDetailMatch && method === 'GET') {
117
+ try {
118
+ const detail = service.getSampleDetail(decodeURIComponent(sampleDetailMatch[1]));
119
+ if (!detail) {
120
+ json(res, 404, { error: 'not_found', message: 'Sample not found.' });
121
+ return true;
122
+ }
123
+ json(res, 200, detail);
124
+ return true;
125
+ }
126
+ catch (error) {
127
+ api.logger.warn(`[PD:ControlUI] API request failed for ${pathname}: ${String(error)}`);
128
+ json(res, 500, { error: 'internal_error', message: String(error) });
129
+ return true;
130
+ }
131
+ finally {
132
+ service.dispose();
133
+ }
134
+ }
135
+ const sampleReviewMatch = pathname.match(/^\/plugins\/principles\/api\/samples\/([^/]+)\/review$/);
136
+ if (sampleReviewMatch && method === 'POST') {
137
+ return (async () => {
138
+ try {
139
+ const body = await readJsonBody(req);
140
+ const decision = body.decision === 'approved' || body.decision === 'rejected'
141
+ ? body.decision
142
+ : null;
143
+ if (!decision) {
144
+ json(res, 400, { error: 'bad_request', message: 'decision must be approved or rejected' });
145
+ return true;
146
+ }
147
+ const record = service.reviewSample(decodeURIComponent(sampleReviewMatch[1]), decision, typeof body.note === 'string' ? body.note : undefined);
148
+ json(res, 200, record);
149
+ return true;
150
+ }
151
+ catch (error) {
152
+ if (error instanceof Error && error.message === 'invalid_json') {
153
+ json(res, 400, { error: 'bad_request', message: 'Request body must be valid JSON.' });
154
+ return true;
155
+ }
156
+ api.logger.warn(`[PD:ControlUI] Review request failed for ${pathname}: ${String(error)}`);
157
+ json(res, 500, { error: 'internal_error', message: String(error) });
158
+ return true;
159
+ }
160
+ finally {
161
+ service.dispose();
162
+ }
163
+ })();
164
+ }
165
+ if (pathname === `${API_PREFIX}/thinking` && method === 'GET') {
166
+ return done(() => service.getThinkingOverview());
167
+ }
168
+ const thinkingDetailMatch = pathname.match(/^\/plugins\/principles\/api\/thinking\/models\/([^/]+)$/);
169
+ if (thinkingDetailMatch && method === 'GET') {
170
+ try {
171
+ const detail = service.getThinkingModelDetail(decodeURIComponent(thinkingDetailMatch[1]));
172
+ if (!detail) {
173
+ json(res, 404, { error: 'not_found', message: 'Thinking model not found.' });
174
+ return true;
175
+ }
176
+ json(res, 200, detail);
177
+ return true;
178
+ }
179
+ catch (error) {
180
+ api.logger.warn(`[PD:ControlUI] API request failed for ${pathname}: ${String(error)}`);
181
+ json(res, 500, { error: 'internal_error', message: String(error) });
182
+ return true;
183
+ }
184
+ finally {
185
+ service.dispose();
186
+ }
187
+ }
188
+ if (pathname === `${API_PREFIX}/export/corrections` && method === 'GET') {
189
+ try {
190
+ const mode = url.searchParams.get('mode') === 'redacted' ? 'redacted' : 'raw';
191
+ const result = service.exportCorrections(mode);
192
+ if (!fs.existsSync(result.filePath)) {
193
+ json(res, 404, { error: 'not_found', message: 'Export file not found.' });
194
+ return true;
195
+ }
196
+ res.statusCode = 200;
197
+ res.setHeader('Content-Type', 'application/x-ndjson; charset=utf-8');
198
+ res.setHeader('Content-Disposition', `attachment; filename="${path.basename(result.filePath)}"`);
199
+ const stream = fs.createReadStream(result.filePath);
200
+ stream.on('error', () => {
201
+ res.statusCode = 500;
202
+ res.end('Internal Server Error');
203
+ });
204
+ stream.pipe(res);
205
+ return true;
206
+ }
207
+ catch (error) {
208
+ api.logger.warn(`[PD:ControlUI] Export request failed for ${pathname}: ${String(error)}`);
209
+ json(res, 500, { error: 'internal_error', message: String(error) });
210
+ return true;
211
+ }
212
+ finally {
213
+ service.dispose();
214
+ }
215
+ }
216
+ service.dispose();
217
+ json(res, 404, { error: 'not_found', message: 'Unknown Principles Console API route.' });
218
+ return true;
219
+ }
220
+ export function createPrinciplesConsoleRoute(api) {
221
+ return {
222
+ path: ROUTE_PREFIX,
223
+ auth: 'gateway',
224
+ match: 'prefix',
225
+ async handler(req, res) {
226
+ const url = new URL(req.url || ROUTE_PREFIX, 'http://127.0.0.1');
227
+ const pathname = url.pathname;
228
+ const method = (req.method || 'GET').toUpperCase();
229
+ if (!pathname.startsWith(ROUTE_PREFIX)) {
230
+ return false;
231
+ }
232
+ if (pathname.startsWith(API_PREFIX)) {
233
+ return handleApiRoute(api, pathname, req, res);
234
+ }
235
+ if (pathname.startsWith(ASSETS_PREFIX)) {
236
+ if (method !== 'GET' && method !== 'HEAD') {
237
+ text(res, 405, 'Method Not Allowed');
238
+ return true;
239
+ }
240
+ const assetPath = safeStaticPath(api.rootDir, pathname);
241
+ if (!assetPath || !serveFile(res, assetPath)) {
242
+ text(res, 404, 'Asset Not Found');
243
+ }
244
+ return true;
245
+ }
246
+ if (method !== 'GET' && method !== 'HEAD') {
247
+ text(res, 405, 'Method Not Allowed');
248
+ return true;
249
+ }
250
+ const indexPath = path.join(api.rootDir, 'dist', 'web', 'index.html');
251
+ if (!serveFile(res, indexPath)) {
252
+ text(res, 503, 'Principles Console UI is not built yet.');
253
+ }
254
+ return true;
255
+ },
256
+ };
257
+ }
@@ -66,9 +66,25 @@ export const commandDescriptions = {
66
66
  zh: '管理 CURRENT_FOCUS.md [status|history|compress|rollback] - 查看/压缩/回滚焦点文件',
67
67
  en: 'Manage CURRENT_FOCUS.md [status|history|compress|rollback] - View/compress/rollback focus file'
68
68
  },
69
+ 'pd-evolution-status': {
70
+ zh: '查看 evolution 闭环状态(candidate/probation/active)',
71
+ en: 'Show evolution loop status (candidate/probation/active)'
72
+ },
73
+ 'pd-principle-rollback': {
74
+ zh: '回滚原则并加入黑名单 <principle-id> [reason]',
75
+ en: 'Rollback principle and blacklist pattern <principle-id> [reason]'
76
+ },
69
77
  'pd-rollback': {
70
78
  zh: '回滚情绪事件惩罚 <event-id>|last',
71
79
  en: 'Rollback empathy event penalty <event-id>|last'
80
+ },
81
+ 'pd-export': {
82
+ zh: '导出 analytics 或纠错样本 [analytics|corrections --redacted]',
83
+ en: 'Export analytics or correction samples [analytics|corrections --redacted]'
84
+ },
85
+ 'pd-samples': {
86
+ zh: '查看或审核纠错样本 [review approve|reject <sample-id> [note]]',
87
+ en: 'List or review correction samples [review approve|reject <sample-id> [note]]'
72
88
  }
73
89
  };
74
90
  /**
package/dist/index.js CHANGED
@@ -15,13 +15,19 @@ import { handlePainCommand } from './commands/pain.js';
15
15
  import { handleContextCommand } from './commands/context.js';
16
16
  import { handleFocusCommand } from './commands/focus.js';
17
17
  import { handleRollbackCommand } from './commands/rollback.js';
18
+ import { handleEvolutionStatusCommand } from './commands/evolution-status.js';
19
+ import { handlePrincipleRollbackCommand } from './commands/principle-rollback.js';
20
+ import { handleExportCommand } from './commands/export.js';
21
+ import { handleSamplesCommand } from './commands/samples.js';
18
22
  import { EvolutionWorkerService } from './service/evolution-worker.js';
23
+ import { TrajectoryService } from './service/trajectory-service.js';
19
24
  import { ensureWorkspaceTemplates } from './core/init.js';
20
25
  import { migrateDirectoryStructure } from './core/migration.js';
21
26
  import { SystemLogger } from './core/system-logger.js';
22
- import { deepReflectTool } from './tools/deep-reflect.js';
23
- import { agentSpawnTool } from './tools/agent-spawn.js';
27
+ import { createDeepReflectTool } from './tools/deep-reflect.js';
28
+ import { createAgentSpawnTool } from './tools/agent-spawn.js';
24
29
  import { PathResolver } from './core/path-resolver.js';
30
+ import { createPrinciplesConsoleRoute } from './http/principles-console-route.js';
25
31
  // Track initialization to avoid repeated calls
26
32
  let workspaceInitialized = false;
27
33
  const plugin = {
@@ -30,6 +36,7 @@ const plugin = {
30
36
  register(api) {
31
37
  api.logger.info("Principles Disciple Plugin registered.");
32
38
  PathResolver.setExtensionRoot(api.rootDir);
39
+ api.registerHttpRoute(createPrinciplesConsoleRoute(api));
33
40
  const language = api.pluginConfig?.language || 'en';
34
41
  // ── Hook: Prompt Building ──
35
42
  api.on('before_prompt_build', async (event, ctx) => {
@@ -121,6 +128,7 @@ const plugin = {
121
128
  try {
122
129
  EvolutionWorkerService.api = api;
123
130
  api.registerService(EvolutionWorkerService);
131
+ api.registerService(TrajectoryService);
124
132
  }
125
133
  catch (err) {
126
134
  api.logger.error(`[PD] Failed to register EvolutionWorkerService: ${String(err)}`);
@@ -196,6 +204,8 @@ const plugin = {
196
204
  | \`/pd-status\` | 查看进化状态 | 想了解当前 GFI 和 Pain 情况 |
197
205
  | \`/pd-trust\` | 查看信任分数 | 想知道自己的权限等级 |
198
206
  | \`/pd-focus\` | 焦点文件管理 | 查看/压缩/回滚历史版本 |
207
+ | \`/pd-export\` | 导出分析/样本 | 导出 analytics 或纠错样本 |
208
+ | \`/pd-samples\` | 审核纠错样本 | 查看待审核样本并批准/拒绝 |
199
209
 
200
210
  ## ⚙️ 配置管理
201
211
  | 命令 | 用途 | 使用时机 |
@@ -253,6 +263,8 @@ const plugin = {
253
263
  | \`/pd-status\` | View evolution status | Check GFI and Pain status |
254
264
  | \`/pd-trust\` | View trust score | Check your permission level |
255
265
  | \`/pd-focus\` | Focus file management | View/compress/rollback history |
266
+ | \`/pd-export\` | Export analytics/samples | Export analytics or correction samples |
267
+ | \`/pd-samples\` | Review correction samples | Review pending correction samples |
256
268
 
257
269
  ## ⚙️ Configuration
258
270
  | Command | Purpose | When to Use |
@@ -356,6 +368,39 @@ const plugin = {
356
368
  }
357
369
  }
358
370
  });
371
+ api.registerCommand({
372
+ name: "pd-evolution-status",
373
+ description: getCommandDescription('pd-evolution-status', language),
374
+ handler: (ctx) => {
375
+ try {
376
+ const workspaceDir = api.resolvePath('.');
377
+ if (ctx.config)
378
+ ctx.config.workspaceDir = workspaceDir;
379
+ return handleEvolutionStatusCommand(ctx);
380
+ }
381
+ catch (err) {
382
+ api.logger.error(`[PD] Command /pd-evolution-status failed: ${String(err)}`);
383
+ return { text: language === 'zh' ? "命令执行失败,请检查日志。" : "Command failed. Check logs." };
384
+ }
385
+ }
386
+ });
387
+ api.registerCommand({
388
+ name: "pd-principle-rollback",
389
+ description: getCommandDescription('pd-principle-rollback', language),
390
+ acceptsArgs: true,
391
+ handler: (ctx) => {
392
+ try {
393
+ const workspaceDir = api.resolvePath('.');
394
+ if (ctx.config)
395
+ ctx.config.workspaceDir = workspaceDir;
396
+ return handlePrincipleRollbackCommand(ctx);
397
+ }
398
+ catch (err) {
399
+ api.logger.error(`[PD] Command /pd-principle-rollback failed: ${String(err)}`);
400
+ return { text: language === 'zh' ? "命令执行失败,请检查日志。" : "Command failed. Check logs." };
401
+ }
402
+ }
403
+ });
359
404
  api.registerCommand({
360
405
  name: "pd-rollback",
361
406
  description: getCommandDescription('pd-rollback', language),
@@ -374,8 +419,42 @@ const plugin = {
374
419
  }
375
420
  });
376
421
  // ── Tools ──
377
- api.registerTool(deepReflectTool);
378
- api.registerTool(agentSpawnTool);
422
+ api.registerCommand({
423
+ name: "pd-export",
424
+ description: getCommandDescription('pd-export', language),
425
+ acceptsArgs: true,
426
+ handler: (ctx) => {
427
+ try {
428
+ const workspaceDir = api.resolvePath('.');
429
+ if (ctx.config)
430
+ ctx.config.workspaceDir = workspaceDir;
431
+ return handleExportCommand(ctx);
432
+ }
433
+ catch (err) {
434
+ api.logger.error(`[PD] Command /pd-export failed: ${String(err)}`);
435
+ return { text: language === 'zh' ? "导出失败,请检查日志。" : "Export failed. Check logs." };
436
+ }
437
+ }
438
+ });
439
+ api.registerCommand({
440
+ name: "pd-samples",
441
+ description: getCommandDescription('pd-samples', language),
442
+ acceptsArgs: true,
443
+ handler: (ctx) => {
444
+ try {
445
+ const workspaceDir = api.resolvePath('.');
446
+ if (ctx.config)
447
+ ctx.config.workspaceDir = workspaceDir;
448
+ return handleSamplesCommand(ctx);
449
+ }
450
+ catch (err) {
451
+ api.logger.error(`[PD] Command /pd-samples failed: ${String(err)}`);
452
+ return { text: language === 'zh' ? "样本命令执行失败,请检查日志。" : "Samples command failed. Check logs." };
453
+ }
454
+ }
455
+ });
456
+ api.registerTool(createDeepReflectTool(api));
457
+ api.registerTool(createAgentSpawnTool(api));
379
458
  }
380
459
  };
381
460
  export default plugin;
@@ -0,0 +1,217 @@
1
+ export interface OverviewResponse {
2
+ workspaceDir: string;
3
+ generatedAt: string;
4
+ dataFreshness: string | null;
5
+ summary: {
6
+ repeatErrorRate: number;
7
+ userCorrectionRate: number;
8
+ pendingSamples: number;
9
+ approvedSamples: number;
10
+ thinkingCoverageRate: number;
11
+ painEvents: number;
12
+ principleEventCount: number;
13
+ };
14
+ dailyTrend: Array<{
15
+ day: string;
16
+ toolCalls: number;
17
+ failures: number;
18
+ userCorrections: number;
19
+ thinkingTurns: number;
20
+ }>;
21
+ topRegressions: Array<{
22
+ toolName: string;
23
+ errorType: string;
24
+ occurrences: number;
25
+ }>;
26
+ sampleQueue: {
27
+ counters: Record<string, number>;
28
+ preview: Array<{
29
+ sampleId: string;
30
+ sessionId: string;
31
+ qualityScore: number;
32
+ reviewStatus: string;
33
+ createdAt: string;
34
+ }>;
35
+ };
36
+ thinkingSummary: {
37
+ activeModels: number;
38
+ dormantModels: number;
39
+ effectiveModels: number;
40
+ coverageRate: number;
41
+ };
42
+ }
43
+ export interface SampleListFilters {
44
+ status?: string;
45
+ qualityMin?: number;
46
+ dateFrom?: string;
47
+ dateTo?: string;
48
+ failureMode?: string;
49
+ page?: number;
50
+ pageSize?: number;
51
+ }
52
+ export interface SamplesResponse {
53
+ counters: Record<string, number>;
54
+ items: Array<{
55
+ sampleId: string;
56
+ sessionId: string;
57
+ reviewStatus: string;
58
+ qualityScore: number;
59
+ failureMode: string;
60
+ relatedThinkingCount: number;
61
+ createdAt: string;
62
+ updatedAt: string;
63
+ diffExcerpt: string;
64
+ }>;
65
+ pagination: {
66
+ page: number;
67
+ pageSize: number;
68
+ total: number;
69
+ totalPages: number;
70
+ };
71
+ }
72
+ export interface SampleDetailResponse {
73
+ sampleId: string;
74
+ sessionId: string;
75
+ reviewStatus: string;
76
+ qualityScore: number;
77
+ createdAt: string;
78
+ updatedAt: string;
79
+ badAttempt: {
80
+ assistantTurnId: number;
81
+ rawText: string;
82
+ sanitizedText: string;
83
+ createdAt: string;
84
+ };
85
+ userCorrection: {
86
+ userTurnId: number;
87
+ rawText: string;
88
+ correctionCue: string | null;
89
+ createdAt: string;
90
+ };
91
+ recoveryToolSpan: Array<{
92
+ id: number;
93
+ toolName: string;
94
+ }>;
95
+ relatedPrinciples: Array<{
96
+ principleId: string | null;
97
+ eventType: string;
98
+ createdAt: string;
99
+ }>;
100
+ relatedThinkingHits: Array<{
101
+ id: number;
102
+ modelId: string;
103
+ modelName: string;
104
+ matchedPattern: string;
105
+ scenarios: string[];
106
+ createdAt: string;
107
+ triggerExcerpt: string;
108
+ }>;
109
+ reviewHistory: Array<{
110
+ reviewStatus: string;
111
+ note: string | null;
112
+ createdAt: string;
113
+ }>;
114
+ }
115
+ export interface ThinkingModelSummary {
116
+ modelId: string;
117
+ name: string;
118
+ description: string;
119
+ hits: number;
120
+ coverageRate: number;
121
+ successRate: number;
122
+ failureRate: number;
123
+ painRate: number;
124
+ correctionRate: number;
125
+ correctionSampleRate: number;
126
+ commonScenarios: string[];
127
+ recommendation: 'reinforce' | 'rework' | 'archive';
128
+ }
129
+ export interface ThinkingOverviewResponse {
130
+ summary: {
131
+ totalModels: number;
132
+ activeModels: number;
133
+ dormantModels: number;
134
+ effectiveModels: number;
135
+ coverageRate: number;
136
+ };
137
+ topModels: ThinkingModelSummary[];
138
+ dormantModels: Array<{
139
+ modelId: string;
140
+ name: string;
141
+ description: string;
142
+ }>;
143
+ effectiveModels: ThinkingModelSummary[];
144
+ scenarioMatrix: Array<{
145
+ modelId: string;
146
+ modelName: string;
147
+ scenario: string;
148
+ hits: number;
149
+ }>;
150
+ coverageTrend: Array<{
151
+ day: string;
152
+ assistantTurns: number;
153
+ thinkingTurns: number;
154
+ coverageRate: number;
155
+ }>;
156
+ }
157
+ export interface ThinkingModelDetailResponse {
158
+ modelMeta: {
159
+ modelId: string;
160
+ name: string;
161
+ description: string;
162
+ hits: number;
163
+ coverageRate: number;
164
+ recommendation: 'reinforce' | 'rework' | 'archive';
165
+ };
166
+ usageTrend: Array<{
167
+ day: string;
168
+ hits: number;
169
+ }>;
170
+ scenarioDistribution: Array<{
171
+ scenario: string;
172
+ hits: number;
173
+ }>;
174
+ outcomeStats: {
175
+ events: number;
176
+ successRate: number;
177
+ failureRate: number;
178
+ painRate: number;
179
+ correctionRate: number;
180
+ correctionSampleRate: number;
181
+ };
182
+ recentEvents: Array<{
183
+ id: number;
184
+ createdAt: string;
185
+ matchedPattern: string;
186
+ scenarios: string[];
187
+ triggerExcerpt: string;
188
+ toolContext: Array<{
189
+ toolName: string;
190
+ outcome: string;
191
+ errorType?: string | null;
192
+ }>;
193
+ painContext: Array<{
194
+ source: string;
195
+ score: number;
196
+ }>;
197
+ principleContext: Array<{
198
+ principleId: string | null;
199
+ eventType: string;
200
+ }>;
201
+ }>;
202
+ }
203
+ export declare class ControlUiQueryService {
204
+ private readonly workspaceDir;
205
+ private readonly trajectory;
206
+ private readonly uiDb;
207
+ constructor(workspaceDir: string);
208
+ dispose(): void;
209
+ getOverview(): OverviewResponse;
210
+ listSamples(filters?: SampleListFilters): SamplesResponse;
211
+ getSampleDetail(sampleId: string): SampleDetailResponse | null;
212
+ reviewSample(sampleId: string, decision: 'approved' | 'rejected', note?: string): import("../core/trajectory.js").CorrectionSampleRecord;
213
+ exportCorrections(mode: 'raw' | 'redacted'): import("../core/trajectory.js").TrajectoryExportResult;
214
+ getThinkingOverview(): ThinkingOverviewResponse;
215
+ getThinkingModelDetail(modelId: string): ThinkingModelDetailResponse | null;
216
+ private loadThinkingModelSummaries;
217
+ }