principles-disciple 1.7.8 → 1.8.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.
Files changed (32) hide show
  1. package/dist/core/config.d.ts +2 -0
  2. package/dist/core/session-tracker.d.ts +3 -1
  3. package/dist/core/session-tracker.js +12 -3
  4. package/dist/hooks/llm.d.ts +1 -0
  5. package/dist/hooks/llm.js +17 -70
  6. package/dist/hooks/progressive-trust-gate.d.ts +1 -0
  7. package/dist/hooks/progressive-trust-gate.js +45 -0
  8. package/dist/hooks/prompt.d.ts +2 -0
  9. package/dist/hooks/prompt.js +27 -6
  10. package/dist/hooks/subagent.js +2 -2
  11. package/dist/http/principles-console-route.js +114 -0
  12. package/dist/service/empathy-observer-manager.d.ts +46 -10
  13. package/dist/service/empathy-observer-manager.js +249 -64
  14. package/dist/service/evolution-worker.js +1 -0
  15. package/dist/service/health-query-service.d.ts +170 -0
  16. package/dist/service/health-query-service.js +662 -0
  17. package/dist/service/nocturnal-runtime.d.ts +2 -2
  18. package/dist/service/nocturnal-runtime.js +75 -4
  19. package/dist/service/nocturnal-service.js +2 -2
  20. package/dist/service/subagent-workflow/empathy-observer-workflow-manager.d.ts +48 -0
  21. package/dist/service/subagent-workflow/empathy-observer-workflow-manager.js +480 -0
  22. package/dist/service/subagent-workflow/index.d.ts +4 -0
  23. package/dist/service/subagent-workflow/index.js +3 -0
  24. package/dist/service/subagent-workflow/runtime-direct-driver.d.ts +77 -0
  25. package/dist/service/subagent-workflow/runtime-direct-driver.js +75 -0
  26. package/dist/service/subagent-workflow/types.d.ts +259 -0
  27. package/dist/service/subagent-workflow/types.js +11 -0
  28. package/dist/service/subagent-workflow/workflow-store.d.ts +26 -0
  29. package/dist/service/subagent-workflow/workflow-store.js +165 -0
  30. package/dist/tools/deep-reflect.js +2 -2
  31. package/openclaw.plugin.json +6 -1
  32. package/package.json +3 -3
@@ -1,10 +1,14 @@
1
1
  import { WorkspaceContext } from '../core/workspace-context.js';
2
2
  import { trackFriction } from '../core/session-tracker.js';
3
3
  import { isSubagentRuntimeAvailable } from '../utils/subagent-probe.js';
4
- const OBSERVER_SESSION_PREFIX = 'empathy_obs:';
4
+ const OBSERVER_SESSION_PREFIX = 'agent:main:subagent:empathy-obs-';
5
+ // Default timeout for waitForRun (30 seconds)
6
+ const DEFAULT_WAIT_TIMEOUT_MS = 30_000;
5
7
  export class EmpathyObserverManager {
6
8
  static instance;
7
9
  sessionLocks = new Map();
10
+ activeRuns = new Map();
11
+ completedSessions = new Map();
8
12
  constructor() { }
9
13
  static getInstance() {
10
14
  if (!EmpathyObserverManager.instance) {
@@ -13,105 +17,236 @@ export class EmpathyObserverManager {
13
17
  return EmpathyObserverManager.instance;
14
18
  }
15
19
  /**
16
- * Probe whether the subagent runtime is actually functional.
17
- * api.runtime.subagent always exists (it's a Proxy), but in embedded mode
18
- * every method throws "only available during a gateway request".
19
- * We cache the result to avoid repeated probing.
20
+ * Build a safe session key for empathy observer
21
+ * Format: agent:main:subagent:empathy-obs-{safeParentSessionId}-{timestamp}
20
22
  */
21
- subagentAvailableCache = null;
22
- isSubagentAvailable(api) {
23
- if (this.subagentAvailableCache !== null)
24
- return this.subagentAvailableCache;
25
- try {
26
- // Accessing .run on the Proxy is safe; calling it with bad params
27
- // will throw the unavailability error synchronously before any async work.
28
- // We use a deliberate no-op probe: pass an empty object and catch immediately.
29
- const probe = api.runtime?.subagent?.run;
30
- if (typeof probe !== 'function') {
31
- this.subagentAvailableCache = false;
32
- return false;
33
- }
34
- // Call with intentionally invalid params — the unavailable runtime throws
35
- // synchronously, the real runtime returns a rejected Promise.
36
- const result = probe.call(api.runtime.subagent, {});
37
- if (result && typeof result.catch === 'function') {
38
- // It returned a Promise → runtime is real (even if the call fails for bad params)
39
- result.catch(() => { });
40
- this.subagentAvailableCache = true;
23
+ buildEmpathyObserverSessionKey(parentSessionId) {
24
+ const safeParentSessionId = parentSessionId
25
+ .replace(/[^a-zA-Z0-9_-]/g, '_')
26
+ .substring(0, 64);
27
+ const timestamp = Date.now();
28
+ return `${OBSERVER_SESSION_PREFIX}${safeParentSessionId}-${timestamp}`;
29
+ }
30
+ /**
31
+ * Check if a session key is an empathy observer session
32
+ */
33
+ isObserverSession(sessionKey) {
34
+ return isEmpathyObserverSession(sessionKey);
35
+ }
36
+ markCompleted(observerSessionKey) {
37
+ this.completedSessions.set(observerSessionKey, Date.now());
38
+ }
39
+ isCompleted(observerSessionKey) {
40
+ const timestamp = this.completedSessions.get(observerSessionKey);
41
+ if (!timestamp)
42
+ return false;
43
+ if (Date.now() - timestamp > 5 * 60 * 1000) {
44
+ this.completedSessions.delete(observerSessionKey);
45
+ return false;
46
+ }
47
+ return true;
48
+ }
49
+ isActive(parentSessionId) {
50
+ const metadata = this.activeRuns.get(parentSessionId);
51
+ if (!metadata)
52
+ return false;
53
+ if (metadata.timedOutAt || metadata.erroredAt) {
54
+ if (!metadata.observedAt)
41
55
  return true;
56
+ // TTL-based cleanup of orphaned timed-out/error entries:
57
+ // if fallback never fired, expire the block so parent session recovers
58
+ if (Date.now() - metadata.observedAt > 5 * 60 * 1000) {
59
+ this.activeRuns.delete(parentSessionId);
60
+ if (this.sessionLocks.get(parentSessionId) === metadata.observerSessionKey) {
61
+ this.sessionLocks.delete(parentSessionId);
62
+ }
63
+ return false;
42
64
  }
43
- this.subagentAvailableCache = false;
44
- return false;
65
+ return true;
45
66
  }
46
- catch {
47
- // Threw synchronously → unavailable runtime
48
- this.subagentAvailableCache = false;
67
+ if (Date.now() - metadata.startedAt > 5 * 60 * 1000) {
68
+ this.activeRuns.delete(parentSessionId);
69
+ if (this.sessionLocks.get(parentSessionId) === metadata.observerSessionKey) {
70
+ this.sessionLocks.delete(parentSessionId);
71
+ }
49
72
  return false;
50
73
  }
74
+ return true;
75
+ }
76
+ getActiveMetadata(parentSessionId) {
77
+ return this.activeRuns.get(parentSessionId);
51
78
  }
52
79
  shouldTrigger(api, sessionId) {
53
- if (!api || !sessionId)
80
+ if (!api || !sessionId) {
81
+ api?.logger?.warn?.('[PD:EmpathyObserver] shouldTrigger=false: api or sessionId null');
54
82
  return false;
83
+ }
55
84
  const enabled = api.config?.empathy_engine?.enabled !== false;
56
- if (!enabled)
85
+ if (!enabled) {
86
+ api.logger?.warn?.('[PD:EmpathyObserver] shouldTrigger=false: empathy_engine disabled');
87
+ return false;
88
+ }
89
+ // Skip BOOT sessions - they run outside "gateway request" context where subagent.run() is unavailable
90
+ if (sessionId.startsWith('boot-')) {
91
+ api.logger?.warn?.('[PD:EmpathyObserver] shouldTrigger=false: boot session (gateway request context unavailable)');
92
+ return false;
93
+ }
94
+ const subagentOk = isSubagentRuntimeAvailable(api.runtime?.subagent);
95
+ if (!subagentOk) {
96
+ api.logger?.warn?.('[PD:EmpathyObserver] shouldTrigger=false: subagent runtime unavailable');
57
97
  return false;
58
- if (!isSubagentRuntimeAvailable(api.runtime?.subagent))
98
+ }
99
+ if (this.isActive(sessionId)) {
100
+ api.logger?.warn?.(`[PD:EmpathyObserver] shouldTrigger=false: session ${sessionId} has active run`);
59
101
  return false;
60
- return !this.sessionLocks.has(sessionId);
102
+ }
103
+ api.logger?.info?.(`[PD:EmpathyObserver] shouldTrigger=true for session ${sessionId}`);
104
+ return true;
61
105
  }
62
- async spawn(api, sessionId, userMessage) {
106
+ async spawn(api, sessionId, userMessage, workspaceDir) {
63
107
  if (!api)
64
108
  return null;
65
- if (!this.shouldTrigger(api, sessionId))
109
+ if (!this.shouldTrigger(api, sessionId)) {
110
+ api?.logger?.warn?.(`[PD:EmpathyObserver] spawn skipped: shouldTrigger=false for session ${sessionId}`);
66
111
  return null;
67
- if (!userMessage?.trim())
112
+ }
113
+ if (!userMessage?.trim()) {
114
+ api?.logger?.warn?.('[PD:EmpathyObserver] spawn skipped: empty userMessage');
68
115
  return null;
69
- const timestamp = Date.now();
70
- const sessionKey = `${OBSERVER_SESSION_PREFIX}${sessionId}:${timestamp}`;
116
+ }
117
+ const sessionKey = this.buildEmpathyObserverSessionKey(sessionId);
71
118
  this.sessionLocks.set(sessionId, sessionKey);
119
+ api.logger.info(`[PD:EmpathyObserver] Spawn starting for session ${sessionId}, key=${sessionKey}`);
72
120
  const prompt = [
73
121
  'You are an empathy observer.',
74
122
  'Analyze ONLY the user message and return strict JSON (no markdown):',
75
123
  '{"damageDetected": boolean, "severity": "mild|moderate|severe", "confidence": number, "reason": string}',
76
124
  `User message: ${JSON.stringify(userMessage.trim())}`,
77
125
  ].join('\n');
126
+ let runId;
78
127
  try {
79
- await api.runtime.subagent.run({
128
+ const result = await api.runtime.subagent.run({
80
129
  sessionKey,
81
130
  message: prompt,
82
131
  lane: 'subagent',
83
132
  deliver: false,
84
- idempotencyKey: `${sessionId}:${timestamp}`,
133
+ idempotencyKey: `${sessionId}:${Date.now()}`,
134
+ expectsCompletionMessage: true,
85
135
  });
86
- api.logger.info(`[PD:EmpathyObserver] Spawned observer ${sessionKey}`);
87
- return sessionKey;
136
+ runId = result.runId;
137
+ api.logger.info(`[PD:EmpathyObserver] Spawn succeeded for ${sessionKey}, runId=${runId}`);
88
138
  }
89
139
  catch (error) {
90
140
  this.sessionLocks.delete(sessionId);
91
- api.logger.warn(`[PD:EmpathyObserver] Failed to spawn observer for ${sessionId}: ${String(error)}`);
141
+ api.logger.warn(`[PD:EmpathyObserver] Spawn failed for ${sessionId}: ${String(error)}`);
92
142
  return null;
93
143
  }
144
+ this.activeRuns.set(sessionId, {
145
+ runId,
146
+ parentSessionId: sessionId,
147
+ observerSessionKey: sessionKey,
148
+ workspaceDir,
149
+ startedAt: Date.now(),
150
+ });
151
+ this.finalizeRun(api, sessionId, sessionKey, workspaceDir).catch(async (err) => {
152
+ api.logger.warn(`[PD:EmpathyObserver] finalizeRun failed (will retry once): ${String(err)}`);
153
+ await new Promise((r) => setTimeout(r, 2000));
154
+ try {
155
+ await this.finalizeRun(api, sessionId, sessionKey, workspaceDir);
156
+ }
157
+ catch (retryErr) {
158
+ api.logger.warn(`[PD:EmpathyObserver] finalizeRun retry also failed: ${String(retryErr)}`);
159
+ }
160
+ });
161
+ return sessionKey;
94
162
  }
95
- async reap(api, targetSessionKey, workspaceDir) {
96
- if (!api || !workspaceDir || !this.isObserverSession(targetSessionKey))
163
+ /**
164
+ * Main回收链路: 使用 waitForRun 驱动回收
165
+ * 仅在 ok 时回收; timeout/exception 保留 session 由 fallback 处理
166
+ */
167
+ async finalizeRun(api, parentSessionId, observerSessionKey, workspaceDir) {
168
+ const metadata = this.activeRuns.get(parentSessionId);
169
+ const runId = metadata?.runId;
170
+ if (!runId) {
171
+ api.logger.warn(`[PD:EmpathyObserver] finalizeRun: no runId for ${observerSessionKey}`);
172
+ this.cleanupState(parentSessionId, observerSessionKey);
97
173
  return;
98
- const sessionId = this.extractParentSessionId(targetSessionKey);
99
- const unlock = () => {
100
- if (sessionId && this.sessionLocks.get(sessionId) === targetSessionKey) {
101
- this.sessionLocks.delete(sessionId);
174
+ }
175
+ api.logger.info(`[PD:EmpathyObserver] finalizeRun: waiting for runId=${runId}`);
176
+ let waitResult;
177
+ try {
178
+ waitResult = await api.runtime.subagent.waitForRun({
179
+ runId,
180
+ timeoutMs: DEFAULT_WAIT_TIMEOUT_MS,
181
+ });
182
+ api.logger.info(`[PD:EmpathyObserver] finalizeRun: wait completed status=${waitResult.status}`);
183
+ }
184
+ catch (error) {
185
+ api.logger.warn(`[PD:EmpathyObserver] finalizeRun: waitForRun threw for ${runId}: ${String(error)}`);
186
+ const updatedMetadata = this.activeRuns.get(parentSessionId);
187
+ if (updatedMetadata) {
188
+ updatedMetadata.erroredAt = Date.now();
189
+ updatedMetadata.observedAt = Date.now();
190
+ }
191
+ this.cleanupState(parentSessionId, observerSessionKey, false);
192
+ return;
193
+ }
194
+ if (waitResult.status === 'timeout') {
195
+ api.logger.warn(`[PD:EmpathyObserver] finalizeRun: observer wait timed out; deferring cleanup for ${observerSessionKey}`);
196
+ const updatedMetadata = this.activeRuns.get(parentSessionId);
197
+ if (updatedMetadata) {
198
+ updatedMetadata.timedOutAt = Date.now();
199
+ updatedMetadata.observedAt = Date.now();
102
200
  }
103
- };
201
+ this.cleanupState(parentSessionId, observerSessionKey, false);
202
+ return;
203
+ }
204
+ if (waitResult.status === 'error') {
205
+ api.logger.warn(`[PD:EmpathyObserver] finalizeRun: observer run errored: ${waitResult.error}; deferring cleanup for ${observerSessionKey}`);
206
+ const updatedMetadata = this.activeRuns.get(parentSessionId);
207
+ if (updatedMetadata) {
208
+ updatedMetadata.erroredAt = Date.now();
209
+ updatedMetadata.observedAt = Date.now();
210
+ }
211
+ this.cleanupState(parentSessionId, observerSessionKey, false);
212
+ return;
213
+ }
214
+ // Set observedAt before reapBySession so TTL cleanup works even if reapBySession fails
215
+ const updatedMetadata = this.activeRuns.get(parentSessionId);
216
+ if (updatedMetadata) {
217
+ updatedMetadata.observedAt = Date.now();
218
+ }
219
+ await this.reapBySession(api, observerSessionKey, parentSessionId, workspaceDir);
220
+ }
221
+ /**
222
+ * 统一回收入口: reap + deleteSession + 清理状态
223
+ */
224
+ async reapBySession(api, observerSessionKey, parentSessionId, workspaceDir) {
225
+ if (this.isCompleted(observerSessionKey)) {
226
+ api.logger.info(`[PD:EmpathyObserver] reapBySession: already processed ${observerSessionKey}, skipping`);
227
+ this.cleanupState(parentSessionId, observerSessionKey);
228
+ return;
229
+ }
230
+ api.logger.info(`[PD:EmpathyObserver] reapBySession starting for ${observerSessionKey}`);
231
+ const storedMetadata = this.activeRuns.get(parentSessionId);
232
+ // Use original parentSessionId from metadata, NOT extracted from session key
233
+ // (session key may have been sanitized/truncated and doesn't match original)
234
+ const sessionId = storedMetadata?.parentSessionId || this.extractParentSessionId(observerSessionKey) || parentSessionId;
235
+ let finalized = false;
104
236
  try {
105
237
  const messages = await api.runtime.subagent.getSessionMessages({
106
- sessionKey: targetSessionKey,
238
+ sessionKey: observerSessionKey,
107
239
  limit: 20,
108
240
  });
241
+ api.logger.info(`[PD:EmpathyObserver] Retrieved messages for ${observerSessionKey}`);
109
242
  const rawText = this.extractAssistantText(messages.messages, messages.assistantTexts);
243
+ api.logger?.debug?.(`[PD:EmpathyObserver] Raw observer output for ${observerSessionKey}: ${JSON.stringify(rawText)}`);
110
244
  const parsed = this.parseJsonPayload(rawText, api.logger);
245
+ api.logger.info(`[PD:EmpathyObserver] Payload parsed: ${JSON.stringify(parsed)}`);
111
246
  if (parsed?.damageDetected && sessionId) {
112
- const wctx = WorkspaceContext.fromHookContext({ workspaceDir });
247
+ const wctx = WorkspaceContext.fromHookContext({ workspaceDir: workspaceDir || '' });
113
248
  const score = this.scoreFromSeverity(parsed.severity, wctx.config);
114
- trackFriction(sessionId, score, `observer_empathy_${parsed.severity || 'mild'}`, workspaceDir, { source: 'user_empathy' });
249
+ trackFriction(sessionId, score, `observer_empathy_${parsed.severity || 'mild'}`, workspaceDir || '', { source: 'user_empathy' });
115
250
  const eventId = `emp_obs_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
116
251
  wctx.eventLog.recordPainSignal(sessionId, {
117
252
  score,
@@ -144,25 +279,72 @@ export class EmpathyObserverManager {
144
279
  }
145
280
  api.logger.info(`[PD:EmpathyObserver] Applied GFI +${score} for ${sessionId}`);
146
281
  }
282
+ else {
283
+ api.logger.info(`[PD:EmpathyObserver] No damage detected or no sessionId for ${observerSessionKey}`);
284
+ }
285
+ finalized = true;
147
286
  }
148
287
  catch (error) {
149
- api.logger.warn(`[PD:EmpathyObserver] Failed to reap ${targetSessionKey}: ${String(error)}`);
288
+ api.logger.warn(`[PD:EmpathyObserver] reapBySession failed to read messages for ${observerSessionKey}: ${String(error)}`);
289
+ }
290
+ // Only delete the session if we successfully read messages (finalized=true).
291
+ // When finalized=false (getSessionMessages failed), preserve the session so
292
+ // the subagent_ended fallback can retry or the TTL expiry can unblock the parent.
293
+ if (finalized) {
294
+ try {
295
+ await api.runtime.subagent.deleteSession({ sessionKey: observerSessionKey });
296
+ api.logger.info(`[PD:EmpathyObserver] deleteSession succeeded for ${observerSessionKey}`);
297
+ }
298
+ catch (error) {
299
+ api.logger.warn(`[PD:EmpathyObserver] deleteSession failed for ${observerSessionKey}: ${String(error)}`);
300
+ }
301
+ this.markCompleted(observerSessionKey);
150
302
  }
151
- finally {
152
- unlock();
303
+ // Only delete from activeRuns if finalized; otherwise preserve entry for subagent_ended fallback
304
+ this.cleanupState(parentSessionId, observerSessionKey, finalized);
305
+ }
306
+ /**
307
+ * Fallback回收: 由 subagent_ended 触发
308
+ * 仅在主链路未处理时执行补救回收
309
+ */
310
+ async reap(api, targetSessionKey, workspaceDir) {
311
+ if (!api || !this.isObserverSession(targetSessionKey))
312
+ return;
313
+ if (this.isCompleted(targetSessionKey)) {
314
+ api.logger.info(`[PD:EmpathyObserver] reap fallback: already processed ${targetSessionKey}, skipping`);
315
+ return;
153
316
  }
317
+ // Find the original parentSessionId by matching observerSessionKey in activeRuns
318
+ // (the session key may have been sanitized, so we can't rely on extraction alone)
319
+ let parentSessionId = '';
320
+ for (const [key, metadata] of this.activeRuns) {
321
+ if (metadata.observerSessionKey === targetSessionKey) {
322
+ parentSessionId = key;
323
+ break;
324
+ }
325
+ }
326
+ // Fallback: extract from session key (may be truncated but better than nothing for logging)
327
+ if (!parentSessionId) {
328
+ parentSessionId = this.extractParentSessionId(targetSessionKey) || '';
329
+ }
330
+ await this.reapBySession(api, targetSessionKey, parentSessionId, workspaceDir);
154
331
  }
155
- isObserverSession(sessionKey) {
156
- return typeof sessionKey === 'string' && sessionKey.startsWith(OBSERVER_SESSION_PREFIX);
332
+ cleanupState(parentSessionId, observerSessionKey, deleteFromActiveRuns = true) {
333
+ if (deleteFromActiveRuns) {
334
+ this.activeRuns.delete(parentSessionId);
335
+ }
336
+ if (this.sessionLocks.get(parentSessionId) === observerSessionKey) {
337
+ this.sessionLocks.delete(parentSessionId);
338
+ }
157
339
  }
340
+ /**
341
+ * Extract parent session ID from observer session key
342
+ */
158
343
  extractParentSessionId(sessionKey) {
159
344
  if (!this.isObserverSession(sessionKey))
160
345
  return null;
161
- const rest = sessionKey.slice(OBSERVER_SESSION_PREFIX.length);
162
- const marker = rest.lastIndexOf(':');
163
- if (marker <= 0)
164
- return null;
165
- return rest.slice(0, marker);
346
+ const match = sessionKey.match(/empathy-obs-(.+)-(\d+)$/);
347
+ return match ? match[1] : null;
166
348
  }
167
349
  parseJsonPayload(rawText, logger) {
168
350
  if (!rawText?.trim())
@@ -227,3 +409,6 @@ export class EmpathyObserverManager {
227
409
  }
228
410
  }
229
411
  export const empathyObserverManager = EmpathyObserverManager.getInstance();
412
+ export function isEmpathyObserverSession(sessionKey) {
413
+ return typeof sessionKey === 'string' && sessionKey.startsWith(OBSERVER_SESSION_PREFIX);
414
+ }
@@ -922,6 +922,7 @@ export const EvolutionWorkerService = {
922
922
  // This makes nocturnal-runtime a visible part of the worker lifecycle.
923
923
  // Phase 2.4: Enqueue sleep_reflection when workspace is idle and not in cooldown.
924
924
  const idleResult = checkWorkspaceIdle(wctx.workspaceDir, {});
925
+ logger?.info?.(`[PD:EvolutionWorker] HEARTBEAT cycle=${new Date().toISOString()} idle=${idleResult.isIdle} idleForMs=${idleResult.idleForMs} userActiveSessions=${idleResult.userActiveSessions} abandonedSessions=${idleResult.abandonedSessionIds.length} lastActivityEpoch=${idleResult.mostRecentActivityAt}`);
925
926
  if (idleResult.isIdle) {
926
927
  logger?.debug?.(`[PD:EvolutionWorker] Workspace idle (${idleResult.idleForMs}ms since last activity)`);
927
928
  // Phase 2.4: Enqueue sleep_reflection task if not in global cooldown
@@ -0,0 +1,170 @@
1
+ type HealthStage = 'healthy' | 'warning' | 'critical';
2
+ export declare class HealthQueryService {
3
+ private readonly workspaceDir;
4
+ private readonly stateDir;
5
+ private readonly trajectory;
6
+ private readonly config;
7
+ private readonly eventLog;
8
+ private readonly evolutionReducer;
9
+ private readonly uiDb;
10
+ private readonly tableColumnCache;
11
+ constructor(workspaceDir: string);
12
+ dispose(): void;
13
+ getOverviewHealth(): {
14
+ gfi: {
15
+ current: number;
16
+ peakToday: number;
17
+ threshold: number;
18
+ };
19
+ trust: {
20
+ stage: number;
21
+ stageLabel: string;
22
+ score: number;
23
+ };
24
+ evolution: {
25
+ tier: string;
26
+ points: number;
27
+ };
28
+ painFlag: {
29
+ active: boolean;
30
+ source: string | null;
31
+ score: number | null;
32
+ };
33
+ principles: {
34
+ candidate: number;
35
+ probation: number;
36
+ active: number;
37
+ deprecated: number;
38
+ };
39
+ queue: {
40
+ pending: number;
41
+ inProgress: number;
42
+ completed: number;
43
+ };
44
+ activeStage: HealthStage;
45
+ };
46
+ getEvolutionPrinciples(): {
47
+ principles: {
48
+ summary: {
49
+ candidate: number;
50
+ probation: number;
51
+ active: number;
52
+ deprecated: number;
53
+ };
54
+ recent: Array<{
55
+ principleId: string;
56
+ status: string;
57
+ triggerPattern: string;
58
+ action: string;
59
+ fromStatus: string;
60
+ toStatus: string;
61
+ timestamp: string;
62
+ }>;
63
+ };
64
+ nocturnalTraining: {
65
+ queue: {
66
+ pending: number;
67
+ inProgress: number;
68
+ completed: number;
69
+ };
70
+ trinityRecords: Array<{
71
+ artifactId: string;
72
+ status: string;
73
+ createdAt: string;
74
+ }>;
75
+ arbiterPassRate: number;
76
+ orpoSampleCount: number;
77
+ deployments: Array<{
78
+ modelId: string;
79
+ status: string;
80
+ checkpointPath: string | null;
81
+ }>;
82
+ };
83
+ painSourceDistribution: Record<string, number>;
84
+ activeStage: string;
85
+ };
86
+ getFeedbackGfi(): {
87
+ current: number;
88
+ peakToday: number;
89
+ threshold: number;
90
+ trend: Array<{
91
+ hour: string;
92
+ value: number;
93
+ }>;
94
+ sources: Record<string, number>;
95
+ };
96
+ getFeedbackEmpathyEvents(limit?: number): Array<{
97
+ timestamp: string;
98
+ severity: string;
99
+ score: number;
100
+ reason: string;
101
+ origin: string;
102
+ gfiAfter: number;
103
+ }>;
104
+ getFeedbackGateBlocks(limit?: number): Array<{
105
+ timestamp: string;
106
+ toolName: string;
107
+ reason: string;
108
+ gfi: number;
109
+ trustStage: number;
110
+ }>;
111
+ getGateStats(): {
112
+ today: {
113
+ gfiBlocks: number;
114
+ stageBlocks: number;
115
+ p03Blocks: number;
116
+ bypassAttempts: number;
117
+ p16Exemptions: number;
118
+ };
119
+ trust: {
120
+ stage: number;
121
+ score: number;
122
+ status: string;
123
+ };
124
+ evolution: {
125
+ tier: string;
126
+ points: number;
127
+ status: string;
128
+ };
129
+ };
130
+ getGateBlocks(limit?: number): Array<{
131
+ timestamp: string;
132
+ toolName: string;
133
+ filePath: string | null;
134
+ reason: string;
135
+ gateType: string;
136
+ gfi: number;
137
+ trustStage: number;
138
+ }>;
139
+ private readTrust;
140
+ private readEvolutionScore;
141
+ private readQueueStats;
142
+ private readPainFlag;
143
+ private getCurrentSession;
144
+ private getGfiThreshold;
145
+ private computeHealthStage;
146
+ private getTrustStageLabel;
147
+ private inferTrustStageFromScore;
148
+ private normalizeTierName;
149
+ private readRecentPrincipleChanges;
150
+ private mapPrincipleEvent;
151
+ private readNocturnalTraining;
152
+ private readPainSourceDistribution;
153
+ private readEvolutionActiveStage;
154
+ private readMergedEvents;
155
+ private readPersistedEvents;
156
+ private getBufferedEvents;
157
+ private getEventDedupKey;
158
+ private readGateBlocksRaw;
159
+ private resolveGateBlockGfi;
160
+ private resolveGateBlockTrustStage;
161
+ private resolveGateType;
162
+ private hasTableColumn;
163
+ private scoreToStatus;
164
+ private evolutionToStatus;
165
+ private safeListFiles;
166
+ private readJsonFile;
167
+ private asNumber;
168
+ private asNullableNumber;
169
+ }
170
+ export {};