principles-disciple 1.11.0 → 1.13.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 (233) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +66 -0
  3. package/esbuild.config.js +1 -1
  4. package/openclaw.plugin.json +4 -4
  5. package/package.json +2 -3
  6. package/run-nocturnal.mjs +30 -0
  7. package/scripts/db-migrate.mjs +170 -0
  8. package/scripts/sync-plugin.mjs +250 -6
  9. package/src/commands/archive-impl.ts +136 -0
  10. package/src/commands/capabilities.ts +4 -2
  11. package/src/commands/context.ts +5 -1
  12. package/src/commands/disable-impl.ts +151 -0
  13. package/src/commands/evolution-status.ts +64 -19
  14. package/src/commands/export.ts +8 -6
  15. package/src/commands/focus.ts +8 -20
  16. package/src/commands/nocturnal-review.ts +5 -7
  17. package/src/commands/nocturnal-rollout.ts +1 -12
  18. package/src/commands/nocturnal-train.ts +21 -47
  19. package/src/commands/pain.ts +10 -5
  20. package/src/commands/principle-rollback.ts +4 -2
  21. package/src/commands/promote-impl.ts +274 -0
  22. package/src/commands/rollback-impl.ts +234 -0
  23. package/src/commands/rollback.ts +6 -3
  24. package/src/commands/samples.ts +2 -0
  25. package/src/commands/thinking-os.ts +3 -4
  26. package/src/commands/workflow-debug.ts +2 -1
  27. package/src/config/errors.ts +1 -0
  28. package/src/core/AGENTS.md +34 -0
  29. package/src/core/adaptive-thresholds.ts +4 -3
  30. package/src/core/code-implementation-storage.ts +241 -0
  31. package/src/core/config.ts +5 -2
  32. package/src/core/control-ui-db.ts +29 -10
  33. package/src/core/detection-funnel.ts +12 -7
  34. package/src/core/diagnostician-task-store.ts +156 -0
  35. package/src/core/dictionary.ts +4 -4
  36. package/src/core/empathy-keyword-matcher.ts +7 -3
  37. package/src/core/empathy-types.ts +13 -2
  38. package/src/core/event-log.ts +14 -6
  39. package/src/core/evolution-engine.ts +27 -31
  40. package/src/core/evolution-logger.ts +3 -2
  41. package/src/core/evolution-reducer.ts +110 -31
  42. package/src/core/evolution-types.ts +10 -0
  43. package/src/core/external-training-contract.ts +1 -0
  44. package/src/core/focus-history.ts +38 -24
  45. package/src/core/hygiene/tracker.ts +10 -6
  46. package/src/core/init.ts +5 -2
  47. package/src/core/migration.ts +3 -3
  48. package/src/core/model-deployment-registry.ts +6 -4
  49. package/src/core/model-training-registry.ts +5 -3
  50. package/src/core/nocturnal-arbiter.ts +13 -14
  51. package/src/core/nocturnal-artifact-lineage.ts +117 -0
  52. package/src/core/nocturnal-artificer.ts +257 -0
  53. package/src/core/nocturnal-candidate-scoring.ts +4 -2
  54. package/src/core/nocturnal-compliance.ts +67 -19
  55. package/src/core/nocturnal-dataset.ts +95 -2
  56. package/src/core/nocturnal-executability.ts +2 -3
  57. package/src/core/nocturnal-export.ts +6 -3
  58. package/src/core/nocturnal-rule-implementation-validator.ts +245 -0
  59. package/src/core/nocturnal-trajectory-extractor.ts +10 -3
  60. package/src/core/nocturnal-trinity.ts +319 -61
  61. package/src/core/pain-context-extractor.ts +29 -15
  62. package/src/core/pain.ts +7 -5
  63. package/src/core/path-resolver.ts +16 -15
  64. package/src/core/paths.ts +2 -1
  65. package/src/core/pd-task-reconciler.ts +463 -0
  66. package/src/core/pd-task-service.ts +42 -0
  67. package/src/core/pd-task-store.ts +77 -0
  68. package/src/core/pd-task-types.ts +128 -0
  69. package/src/core/principle-internalization/deprecated-readiness.ts +91 -0
  70. package/src/core/principle-internalization/internalization-routing-policy.ts +208 -0
  71. package/src/core/principle-internalization/lifecycle-metrics.ts +149 -0
  72. package/src/core/principle-internalization/lifecycle-read-model.ts +243 -0
  73. package/src/core/principle-internalization/lifecycle-refresh.ts +11 -0
  74. package/src/core/principle-internalization/principle-lifecycle-service.ts +167 -0
  75. package/src/core/principle-training-state.ts +95 -370
  76. package/src/core/principle-tree-ledger.ts +733 -0
  77. package/src/core/principle-tree-migration.ts +195 -0
  78. package/src/core/profile.ts +3 -1
  79. package/src/core/promotion-gate.ts +14 -18
  80. package/src/core/replay-engine.ts +562 -0
  81. package/src/core/risk-calculator.ts +6 -4
  82. package/src/core/rule-host-helpers.ts +39 -0
  83. package/src/core/rule-host-types.ts +82 -0
  84. package/src/core/rule-host.ts +245 -0
  85. package/src/core/rule-implementation-runtime.ts +38 -0
  86. package/src/core/schema/db-types.ts +16 -0
  87. package/src/core/schema/index.ts +26 -0
  88. package/src/core/schema/migration-runner.ts +207 -0
  89. package/src/core/schema/migrations/001-init-trajectory.ts +211 -0
  90. package/src/core/schema/migrations/002-init-central.ts +122 -0
  91. package/src/core/schema/migrations/003-init-workflow.ts +55 -0
  92. package/src/core/schema/migrations/004-add-thinking-and-gfi.ts +74 -0
  93. package/src/core/schema/migrations/index.ts +31 -0
  94. package/src/core/schema/schema-definitions.ts +650 -0
  95. package/src/core/session-tracker.ts +6 -4
  96. package/src/core/shadow-observation-registry.ts +6 -3
  97. package/src/core/system-logger.ts +2 -2
  98. package/src/core/thinking-models.ts +182 -46
  99. package/src/core/thinking-os-parser.ts +156 -0
  100. package/src/core/training-program.ts +7 -7
  101. package/src/core/trajectory.ts +42 -36
  102. package/src/core/workspace-context.ts +77 -11
  103. package/src/core/workspace-dir-validation.ts +152 -0
  104. package/src/hooks/AGENTS.md +31 -0
  105. package/src/hooks/bash-risk.ts +3 -1
  106. package/src/hooks/edit-verification.ts +9 -5
  107. package/src/hooks/gate-block-helper.ts +5 -1
  108. package/src/hooks/gate.ts +152 -5
  109. package/src/hooks/gfi-gate.ts +9 -2
  110. package/src/hooks/lifecycle-routing.ts +124 -0
  111. package/src/hooks/lifecycle.ts +12 -12
  112. package/src/hooks/llm.ts +17 -109
  113. package/src/hooks/message-sanitize.ts +5 -3
  114. package/src/hooks/pain.ts +19 -15
  115. package/src/hooks/progressive-trust-gate.ts +7 -1
  116. package/src/hooks/prompt.ts +169 -60
  117. package/src/hooks/subagent.ts +5 -4
  118. package/src/hooks/thinking-checkpoint.ts +2 -0
  119. package/src/hooks/trajectory-collector.ts +15 -12
  120. package/src/http/principles-console-route.ts +31 -68
  121. package/src/i18n/commands.ts +2 -2
  122. package/src/index.ts +130 -40
  123. package/src/service/central-database.ts +131 -43
  124. package/src/service/central-health-service.ts +47 -0
  125. package/src/service/central-overview-service.ts +135 -0
  126. package/src/service/central-sync-service.ts +87 -0
  127. package/src/service/control-ui-query-service.ts +46 -36
  128. package/src/service/event-log-auditor.ts +261 -0
  129. package/src/service/evolution-query-service.ts +23 -22
  130. package/src/service/evolution-worker.ts +565 -261
  131. package/src/service/health-query-service.ts +213 -36
  132. package/src/service/nocturnal-runtime.ts +8 -4
  133. package/src/service/nocturnal-service.ts +503 -59
  134. package/src/service/nocturnal-target-selector.ts +5 -7
  135. package/src/service/runtime-summary-service.ts +2 -1
  136. package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +25 -336
  137. package/src/service/subagent-workflow/dynamic-timeout.ts +30 -0
  138. package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +48 -386
  139. package/src/service/subagent-workflow/index.ts +2 -0
  140. package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +169 -284
  141. package/src/service/subagent-workflow/runtime-direct-driver.ts +114 -16
  142. package/src/service/subagent-workflow/subagent-error-utils.ts +25 -0
  143. package/src/service/subagent-workflow/types.ts +9 -4
  144. package/src/service/subagent-workflow/workflow-manager-base.ts +573 -0
  145. package/src/service/subagent-workflow/workflow-store.ts +71 -11
  146. package/src/service/trajectory-service.ts +2 -1
  147. package/src/tools/critique-prompt.ts +1 -1
  148. package/src/tools/deep-reflect.ts +175 -209
  149. package/src/tools/model-index.ts +2 -1
  150. package/src/types/event-types.ts +2 -2
  151. package/src/types/principle-tree-schema.ts +29 -23
  152. package/src/utils/file-lock.ts +5 -3
  153. package/src/utils/io.ts +5 -2
  154. package/src/utils/nlp.ts +5 -46
  155. package/src/utils/node-vm-polyfill.ts +11 -0
  156. package/src/utils/plugin-logger.ts +2 -0
  157. package/src/utils/retry.ts +572 -0
  158. package/src/utils/subagent-probe.ts +1 -1
  159. package/templates/langs/en/core/AGENTS.md +0 -13
  160. package/templates/langs/en/core/SOUL.md +1 -31
  161. package/templates/langs/en/core/TOOLS.md +0 -4
  162. package/templates/langs/en/principles/THINKING_OS.md +77 -0
  163. package/templates/langs/en/skills/admin/SKILL.md +0 -1
  164. package/templates/langs/en/skills/evolution-framework-update/SKILL.md +1 -1
  165. package/templates/langs/en/skills/pd-diagnostician/SKILL.md +18 -5
  166. package/templates/langs/zh/core/AGENTS.md +0 -22
  167. package/templates/langs/zh/core/SOUL.md +1 -31
  168. package/templates/langs/zh/core/TOOLS.md +0 -4
  169. package/templates/langs/zh/principles/THINKING_OS.md +77 -0
  170. package/templates/langs/zh/skills/admin/SKILL.md +0 -1
  171. package/templates/langs/zh/skills/evolution-framework-update/SKILL.md +1 -1
  172. package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +25 -4
  173. package/tests/commands/evolution-status.test.ts +119 -0
  174. package/tests/commands/implementation-lifecycle.test.ts +362 -0
  175. package/tests/core/code-implementation-storage.test.ts +398 -0
  176. package/tests/core/evolution-reducer.detector-metadata.test.ts +28 -28
  177. package/tests/core/nocturnal-artifact-lineage.test.ts +53 -0
  178. package/tests/core/nocturnal-artificer.test.ts +241 -0
  179. package/tests/core/nocturnal-compliance-p-principles.test.ts +133 -0
  180. package/tests/core/nocturnal-rule-implementation-validator.test.ts +127 -0
  181. package/tests/core/pd-task-store.test.ts +126 -0
  182. package/tests/core/principle-internalization/deprecated-readiness.test.ts +193 -0
  183. package/tests/core/principle-internalization/internalization-routing-policy.test.ts +212 -0
  184. package/tests/core/principle-internalization/lifecycle-metrics.test.ts +350 -0
  185. package/tests/core/principle-internalization/principle-lifecycle-service.test.ts +211 -0
  186. package/tests/core/principle-training-state.test.ts +228 -1
  187. package/tests/core/principle-tree-ledger.test.ts +423 -0
  188. package/tests/core/regression-v1-9-1.test.ts +265 -0
  189. package/tests/core/replay-engine.test.ts +234 -0
  190. package/tests/core/rule-host-helpers.test.ts +120 -0
  191. package/tests/core/rule-host.test.ts +389 -0
  192. package/tests/core/rule-implementation-runtime.test.ts +64 -0
  193. package/tests/core/workspace-context.test.ts +53 -0
  194. package/tests/core/workspace-dir-validation.test.ts +272 -0
  195. package/tests/hooks/gate-rule-host-pipeline.test.ts +385 -0
  196. package/tests/hooks/pain.test.ts +74 -10
  197. package/tests/hooks/prompt.test.ts +63 -1
  198. package/tests/integration/principle-lifecycle.e2e.test.ts +197 -0
  199. package/tests/integration/tool-hooks-workspace-dir.e2e.test.ts +211 -0
  200. package/tests/service/data-endpoints-regression.test.ts +834 -0
  201. package/tests/service/evolution-worker.test.ts +0 -123
  202. package/tests/service/nocturnal-service-code-candidate.test.ts +330 -0
  203. package/tests/utils/nlp.test.ts +1 -19
  204. package/tests/utils/retry.test.ts +327 -0
  205. package/ui/src/App.tsx +1 -1
  206. package/ui/src/api.ts +4 -0
  207. package/ui/src/charts.tsx +366 -0
  208. package/ui/src/components/WorkspaceConfig.tsx +107 -75
  209. package/ui/src/i18n/ui.ts +89 -31
  210. package/ui/src/pages/EvolutionPage.tsx +1 -1
  211. package/ui/src/pages/OverviewPage.tsx +441 -81
  212. package/ui/src/pages/ThinkingModelsPage.tsx +287 -69
  213. package/ui/src/styles.css +43 -0
  214. package/ui/src/types.ts +17 -1
  215. package/src/agents/nocturnal-dreamer.md +0 -152
  216. package/src/agents/nocturnal-philosopher.md +0 -138
  217. package/src/agents/nocturnal-reflector.md +0 -126
  218. package/src/agents/nocturnal-scribe.md +0 -164
  219. package/templates/workspace/.principles/00-kernel.md +0 -51
  220. package/templates/workspace/.principles/DECISION_POLICY.json +0 -44
  221. package/templates/workspace/.principles/PRINCIPLES.md +0 -20
  222. package/templates/workspace/.principles/PROFILE.json +0 -54
  223. package/templates/workspace/.principles/PROFILE.schema.json +0 -56
  224. package/templates/workspace/.principles/THINKING_OS.md +0 -64
  225. package/templates/workspace/.principles/THINKING_OS_ARCHIVE.md +0 -7
  226. package/templates/workspace/.principles/THINKING_OS_CANDIDATES.md +0 -9
  227. package/templates/workspace/.principles/models/_INDEX.md +0 -27
  228. package/templates/workspace/.principles/models/first_principles.md +0 -62
  229. package/templates/workspace/.principles/models/marketing_4p.md +0 -52
  230. package/templates/workspace/.principles/models/porter_five.md +0 -63
  231. package/templates/workspace/.principles/models/swot.md +0 -60
  232. package/templates/workspace/.principles/models/user_story_map.md +0 -63
  233. package/templates/workspace/.state/WORKBOARD.json +0 -4
package/src/hooks/llm.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
- import { PluginHookLlmOutputEvent, PluginHookAgentContext } from '../openclaw-sdk.js';
4
- import { trackFriction, trackLlmOutput, recordThinkingCheckpoint, resetFriction } from '../core/session-tracker.js';
3
+ import type { PluginHookLlmOutputEvent, PluginHookAgentContext } from '../openclaw-sdk.js';
4
+ import { trackLlmOutput, recordThinkingCheckpoint, resetFriction } from '../core/session-tracker.js';
5
5
  import { buildPainFlag, writePainFlag } from '../core/pain.js';
6
+ import { normalizeSeverity } from '../core/empathy-types.js';
6
7
  import { ControlUiDatabase } from '../core/control-ui-db.js';
7
8
  import { DetectionService } from '../core/detection-service.js';
8
9
  import { detectThinkingModelMatches, deriveThinkingScenarios } from '../core/thinking-models.js';
@@ -17,27 +18,10 @@ export interface EmpathySignal {
17
18
  mode?: 'structured' | 'legacy_tag';
18
19
  }
19
20
 
20
- type EmpathyRateState = {
21
- turnScore: number;
22
- hourScore: number;
23
- hourWindowStart: number;
24
- lastRunId?: string;
25
- };
26
-
27
- const empathyDedupState = new Map<string, number>();
28
- const empathyRateState = new Map<string, EmpathyRateState>();
29
-
30
21
  function clamp(value: number, min: number, max: number): number {
31
22
  return Math.max(min, Math.min(max, value));
32
23
  }
33
24
 
34
- function normalizeSeverity(input?: string): 'mild' | 'moderate' | 'severe' {
35
- const normalized = (input || '').toLowerCase();
36
- if (normalized === 'severe' || normalized === 'high') return 'severe';
37
- if (normalized === 'moderate' || normalized === 'medium') return 'moderate';
38
- return 'mild';
39
- }
40
-
41
25
  function parseConfidence(raw?: string): number {
42
26
  const parsed = Number(raw);
43
27
  if (!Number.isFinite(parsed)) return 1;
@@ -45,7 +29,7 @@ function parseConfidence(raw?: string): number {
45
29
  }
46
30
 
47
31
  function parseTrustedLegacyTag(text: string): RegExpMatchArray | null {
48
- return text.match(/^\s*\[EMOTIONAL_DAMAGE_DETECTED(?::(mild|moderate|severe))?\]\s*$/i);
32
+ return /^\s*\[EMOTIONAL_DAMAGE_DETECTED(?::(mild|moderate|severe))?\]\s*$/i.exec(text);
49
33
  }
50
34
 
51
35
  /**
@@ -94,19 +78,19 @@ export function extractEmpathySignal(text: string): EmpathySignal {
94
78
  return { detected: false, severity: 'mild', confidence: 1 };
95
79
  }
96
80
 
97
- const xmlMatch = text.match(/<empathy\s+([^>]*)\/?>(?:<\/empathy>)?/i);
81
+ const xmlMatch = /<empathy\s+([^>]*)\/?>(?:<\/empathy>)?/i.exec(text);
98
82
  if (xmlMatch?.[1]) {
99
- const attrs = xmlMatch[1];
100
- const signal = attrs.match(/signal\s*=\s*"([^"]+)"/i)?.[1]?.toLowerCase();
83
+ const [, attrs] = xmlMatch;
84
+ const signal = (/signal\s*=\s*"([^"]+)"/i.exec(attrs))?.[1]?.toLowerCase();
101
85
  if (signal === 'damage' || signal === 'pain' || signal === 'frustration') {
102
- const severity = normalizeSeverity(attrs.match(/severity\s*=\s*"([^"]+)"/i)?.[1]);
103
- const confidence = parseConfidence(attrs.match(/confidence\s*=\s*"([^"]+)"/i)?.[1]);
104
- const reason = attrs.match(/reason\s*=\s*"([^"]+)"/i)?.[1];
86
+ const severity = normalizeSeverity((/severity\s*=\s*"([^"]+)"/i.exec(attrs))?.[1]);
87
+ const confidence = parseConfidence((/confidence\s*=\s*"([^"]+)"/i.exec(attrs))?.[1]);
88
+ const reason = (/reason\s*=\s*"([^"]+)"/i.exec(attrs))?.[1];
105
89
  return { detected: true, severity, confidence, reason, mode: 'structured' };
106
90
  }
107
91
  }
108
92
 
109
- const jsonMatch = text.match(/"empathy"\s*:\s*\{[\s\S]*?\}/i);
93
+ const jsonMatch = /"empathy"\s*:\s*\{[\s\S]*?\}/i.exec(text);
110
94
  if (jsonMatch) {
111
95
  const jsonText = `{${jsonMatch[0]}}`;
112
96
  try {
@@ -143,83 +127,6 @@ export function extractEmpathySignal(text: string): EmpathySignal {
143
127
  return { detected: false, severity: 'mild', confidence: 1 };
144
128
  }
145
129
 
146
- function mapSeverityToPenalty(severity: 'mild' | 'moderate' | 'severe', config: ReturnType<typeof WorkspaceContext.fromHookContext>['config']): number {
147
- const mild = Number(config.get('empathy_engine.penalties.mild') ?? 10);
148
- const moderate = Number(config.get('empathy_engine.penalties.moderate') ?? 25);
149
- const severe = Number(config.get('empathy_engine.penalties.severe') ?? 40);
150
-
151
- if (severity === 'severe') return severe;
152
- if (severity === 'moderate') return moderate;
153
- return mild;
154
- }
155
-
156
- function dedupeKey(sessionId: string, runId: string, signal: EmpathySignal): string {
157
- return `${sessionId}:${runId}:${signal.severity}:${(signal.reason || '').slice(0, 80)}`;
158
- }
159
-
160
- function shouldDedupe(sessionId: string, runId: string, signal: EmpathySignal, windowMs: number): boolean {
161
- const key = dedupeKey(sessionId, runId, signal);
162
- const now = Date.now();
163
- const last = empathyDedupState.get(key);
164
- if (typeof last === 'number' && now - last <= windowMs) {
165
- return true;
166
- }
167
- empathyDedupState.set(key, now);
168
- return false;
169
- }
170
-
171
- function resolveCalibrationFactor(
172
- event: PluginHookLlmOutputEvent,
173
- config: ReturnType<typeof WorkspaceContext.fromHookContext>['config']
174
- ): number {
175
- const table = config.get('empathy_engine.model_calibration') as Record<string, number> | undefined;
176
- if (!table || typeof table !== 'object') return 1;
177
-
178
- const modelKey = `${event.provider}/${event.model}`;
179
- const factor = Number(table[modelKey] ?? 1);
180
- if (!Number.isFinite(factor)) return 1;
181
- return clamp(factor, 0.1, 3);
182
- }
183
-
184
- function applyRateLimit(
185
- sessionId: string,
186
- runId: string,
187
- score: number,
188
- config: ReturnType<typeof WorkspaceContext.fromHookContext>['config']
189
- ): number {
190
- const maxPerTurn = Number(config.get('empathy_engine.rate_limit.max_per_turn') ?? 40);
191
- const maxPerHour = Number(config.get('empathy_engine.rate_limit.max_per_hour') ?? 120);
192
- const now = Date.now();
193
-
194
- const prev = empathyRateState.get(sessionId) ?? {
195
- turnScore: 0,
196
- hourScore: 0,
197
- hourWindowStart: now,
198
- lastRunId: runId,
199
- };
200
-
201
- if (prev.lastRunId !== runId) {
202
- prev.turnScore = 0;
203
- prev.lastRunId = runId;
204
- }
205
-
206
- if (now - prev.hourWindowStart >= 60 * 60 * 1000) {
207
- prev.hourScore = 0;
208
- prev.hourWindowStart = now;
209
- }
210
-
211
- const byTurn = Math.max(0, maxPerTurn - prev.turnScore);
212
- const byHour = Math.max(0, maxPerHour - prev.hourScore);
213
- const allowed = Math.max(0, Math.min(score, byTurn, byHour));
214
-
215
- prev.turnScore += allowed;
216
- prev.hourScore += allowed;
217
- empathyRateState.set(sessionId, prev);
218
-
219
- return allowed;
220
- }
221
-
222
-
223
130
  export function isEmpathyAuditPayload(text: string): boolean {
224
131
  if (!text || typeof text !== 'string') return false;
225
132
  const trimmed = text.trim();
@@ -236,8 +143,8 @@ export function handleLlmOutput(
236
143
  if (!ctx.workspaceDir || !ctx.sessionId) return;
237
144
 
238
145
  const wctx = WorkspaceContext.fromHookContext(ctx);
239
- const config = wctx.config;
240
- const eventLog = wctx.eventLog;
146
+ const {config} = wctx;
147
+ const {eventLog} = wctx;
241
148
 
242
149
  // Track this turn in the core session memory
243
150
  const state = trackLlmOutput(ctx.sessionId, event.usage, config, ctx.workspaceDir, ctx.sessionKey, ctx.trigger);
@@ -288,7 +195,7 @@ export function handleLlmOutput(
288
195
  : '';
289
196
 
290
197
  // ═══ Natural Language Rollback Detection ═══
291
- const rollbackMatch = text.match(/^\s*\[EMPATHY_ROLLBACK_REQUEST\]\s*$/m);
198
+ const rollbackMatch = /^\s*\[EMPATHY_ROLLBACK_REQUEST\]\s*$/m.exec(text);
292
199
  if (rollbackMatch) {
293
200
  const eventId = eventLog.getLastEmpathyEventId(ctx.sessionId);
294
201
  if (eventId) {
@@ -348,6 +255,7 @@ export function handleLlmOutput(
348
255
  }
349
256
 
350
257
  // ═══ Thinking OS: Mental Model Usage Tracking ═══
258
+ /* eslint-disable @typescript-eslint/no-use-before-define -- Reason: trackThinkingModelUsage is defined later in this file */
351
259
  trackThinkingModelUsage({
352
260
  text,
353
261
  wctx,
@@ -383,12 +291,12 @@ function trackThinkingModelUsage(args: {
383
291
  }
384
292
  }
385
293
 
386
- const matches = detectThinkingModelMatches(text);
294
+ const matches = detectThinkingModelMatches(text, wctx.workspaceDir);
387
295
  for (const match of matches) {
388
296
  usageLog[match.modelId] = (usageLog[match.modelId] || 0) + 1;
389
297
  }
390
298
 
391
- usageLog['_total_turns'] = (usageLog['_total_turns'] || 0) + 1;
299
+ usageLog._total_turns = (usageLog._total_turns || 0) + 1;
392
300
 
393
301
  try {
394
302
  fs.writeFileSync(logPath, JSON.stringify(usageLog, null, 2), 'utf8');
@@ -26,18 +26,20 @@ export function handleBeforeMessageWrite(
26
26
  if (typeof msg.content === 'string') {
27
27
  const sanitized = sanitizeAssistantText(msg.content);
28
28
  if (sanitized !== msg.content) {
29
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Reason: message content is dynamically modified, type preserved from event.message union
29
30
  return { message: { ...msg, content: sanitized } as any };
30
31
  }
31
32
  return;
32
33
  }
33
34
 
34
35
  if (Array.isArray(msg.content)) {
35
- const next = msg.content.map((part: any) => {
36
- if (part && typeof part === 'object' && part.type === 'text' && typeof part.text === 'string') {
37
- return { ...part, text: sanitizeAssistantText(part.text) };
36
+ const next = msg.content.map((part: unknown) => {
37
+ if (part && typeof part === 'object' && (part as { type?: string }).type === 'text' && typeof (part as { text?: unknown }).text === 'string') {
38
+ return { ...part, text: sanitizeAssistantText((part as { text: string }).text) };
38
39
  }
39
40
  return part;
40
41
  });
42
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Reason: message content is dynamically modified, type preserved from event.message union
41
43
  return { message: { ...msg, content: next } as any };
42
44
  }
43
45
 
package/src/hooks/pain.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import * as fs from 'fs';
2
- import * as path from 'path';
3
2
  import { isRisky, normalizePath } from '../utils/io.js';
4
3
  import { normalizeProfile } from '../core/profile.js';
5
4
  import { computePainScore, buildPainFlag, writePainFlag, trackPrincipleValue } from '../core/pain.js';
@@ -50,14 +49,14 @@ export function handleAfterToolCall(
50
49
  ctx: PluginHookToolContext & { workspaceDir?: string; pluginConfig?: Record<string, unknown> },
51
50
  api?: OpenClawPluginApi
52
51
  ): void {
53
- const effectiveWorkspaceDir = ctx.workspaceDir || (api as any)?.workspaceDir || api?.resolvePath?.('.');
52
+ const effectiveWorkspaceDir = ctx.workspaceDir || (api as unknown as { workspaceDir?: string })?.workspaceDir || api?.resolvePath?.('.');
54
53
  if (!effectiveWorkspaceDir) {
55
54
  return;
56
55
  }
57
56
 
58
57
  const wctx = WorkspaceContext.fromHookContext({ ...ctx, workspaceDir: effectiveWorkspaceDir });
59
- const config = wctx.config;
60
- const eventLog = wctx.eventLog;
58
+ const {config} = wctx;
59
+ const {eventLog} = wctx;
61
60
  const sessionId = ctx.sessionId || 'unknown';
62
61
  const sessionState = ctx.sessionId ? getSession(ctx.sessionId) : undefined;
63
62
  const gfiBefore = sessionState?.currentGfi ?? 0;
@@ -115,7 +114,7 @@ export function handleAfterToolCall(
115
114
  }
116
115
 
117
116
  // 1. Determine if this was a failure
118
- const exitCode = (event.result && typeof event.result === 'object') ? (event.result as any).exitCode : 0;
117
+ const exitCode = (event.result && typeof event.result === 'object') ? (event.result as Record<string, unknown>).exitCode : 0;
119
118
  const isFailure = !!event.error || (exitCode !== 0 && exitCode !== undefined);
120
119
 
121
120
  if (isFailure) {
@@ -127,6 +126,7 @@ export function handleAfterToolCall(
127
126
  const updatedState = trackFriction(sessionId, deltaF, hash, effectiveWorkspaceDir);
128
127
 
129
128
  // ── Trust Engine: Record failure ──
129
+ /* eslint-disable @typescript-eslint/no-use-before-define -- Reason: extractErrorType is defined later in this file */
130
130
  const errorType = extractErrorType(event.error || errorText);
131
131
  const filePath = params.file_path || params.path || params.file;
132
132
  const relPath = typeof filePath === 'string' ? normalizePath(filePath, effectiveWorkspaceDir) : 'unknown';
@@ -158,14 +158,14 @@ export function handleAfterToolCall(
158
158
  errorType,
159
159
  gfi: updatedState.currentGfi,
160
160
  consecutiveErrors: updatedState.consecutiveErrors,
161
- exitCode,
161
+ exitCode: exitCode as number | undefined,
162
162
  });
163
163
  wctx.trajectory?.recordToolCall?.({
164
164
  sessionId,
165
165
  toolName: event.toolName,
166
166
  outcome: 'failure',
167
167
  durationMs: event.durationMs,
168
- exitCode,
168
+ exitCode: exitCode as number | undefined,
169
169
  errorType,
170
170
  errorMessage: event.error ? String(event.error) : undefined,
171
171
  gfiBefore,
@@ -305,14 +305,18 @@ export function handleAfterToolCall(
305
305
  principle.valueMetrics = metrics;
306
306
  // Persist to training state (best-effort, non-critical)
307
307
  try {
308
- const storePath = path.join(wctx.stateDir, 'principle_training_state.json');
309
- if (fs.existsSync(storePath)) {
310
- const store = JSON.parse(fs.readFileSync(storePath, 'utf8'));
311
- if (store[id]) {
312
- store[id].valueMetrics = metrics;
313
- fs.writeFileSync(storePath, JSON.stringify(store, null, 2), 'utf8');
314
- }
315
- }
308
+ wctx.principleTreeLedger.updatePrincipleValueMetrics(id, {
309
+ principleId: id,
310
+ painPreventedCount: metrics.painPreventedCount,
311
+ lastPainPreventedAt: metrics.lastPainPreventedAt,
312
+ calculatedAt: metrics.calculatedAt,
313
+ avgPainSeverityPrevented: 0,
314
+ totalOpportunities: 0,
315
+ adheredCount: 0,
316
+ violatedCount: 0,
317
+ implementationCost: 0,
318
+ benefitScore: 0,
319
+ });
316
320
  } catch {
317
321
  // Non-critical — metrics tracked in memory
318
322
  }
@@ -23,7 +23,6 @@
23
23
 
24
24
  import type { PluginHookBeforeToolCallEvent, PluginHookBeforeToolCallResult } from '../openclaw-sdk.js';
25
25
  import type { WorkspaceContext } from '../core/workspace-context.js';
26
- import { normalizePath } from '../utils/io.js';
27
26
  import { checkEvolutionGate } from '../core/evolution-engine.js';
28
27
  import { recordGateBlockAndReturn } from './gate-block-helper.js';
29
28
 
@@ -87,12 +86,15 @@ export function buildEvolutionGateReason(
87
86
  /**
88
87
  * Internal helper to call the shared block helper with progressive-trust-gate source tag.
89
88
  */
89
+ /* eslint-disable @typescript-eslint/max-params -- Reason: Helper function requires all parameters for block recording */
90
90
  function block(
91
91
  filePath: string,
92
92
  reason: string,
93
93
  wctx: WorkspaceContext,
94
94
  toolName: string,
95
+ /* eslint-disable no-unused-vars -- Reason: type-only callback params in logger type */
95
96
  logger: { warn?: (message: string) => void; error?: (message: string) => void },
97
+ /* eslint-enable no-unused-vars */
96
98
  sessionId?: string
97
99
  ): PluginHookBeforeToolCallResult {
98
100
  return recordGateBlockAndReturn(wctx, {
@@ -117,13 +119,16 @@ function block(
117
119
  * @param profile - Gate profile containing risk_paths config
118
120
  * @returns PluginHookBeforeToolCallResult to block, or undefined to allow
119
121
  */
122
+ /* eslint-disable @typescript-eslint/max-params -- Reason: Gate function requires all parameters for comprehensive checks */
120
123
  export function checkProgressiveTrustGate(
121
124
  event: PluginHookBeforeToolCallEvent,
122
125
  wctx: WorkspaceContext,
123
126
  relPath: string,
124
127
  risky: boolean,
125
128
  lineChanges: number,
129
+ /* eslint-disable no-unused-vars -- Reason: type-only callback params in logger type */
126
130
  logger: { warn?: (message: string) => void; error?: (message: string) => void; info?: (message: string) => void },
131
+ /* eslint-enable no-unused-vars */
127
132
  ctx: { workspaceDir?: string; sessionId?: string },
128
133
  profile?: { risk_paths: string[]; core_governance_files?: string[] }
129
134
  ): PluginHookBeforeToolCallResult | void {
@@ -146,6 +151,7 @@ export function checkProgressiveTrustGate(
146
151
  });
147
152
 
148
153
  const currentTier = epDecision.currentTier ?? 1;
154
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define -- Reason: mutual recursion between helper functions - reordering would break logical grouping
149
155
  const tierName = getTierName(currentTier);
150
156
 
151
157
  logger.info?.(`[PD_GATE] EP Gate: Tier ${currentTier} (${tierName}), Tool: ${event.toolName}, Risk: ${risky}, Allowed: ${epDecision.allowed}`);