principles-disciple 1.8.1 → 1.8.2

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 (470) hide show
  1. package/ADVANCED_CONFIG_ZH.md +97 -0
  2. package/AGENT_INSTALL.md +173 -0
  3. package/AGENT_INSTALL_EN.md +173 -0
  4. package/INSTALL.md +256 -0
  5. package/SKILL.md +63 -0
  6. package/docs/COMMAND_REFERENCE.md +76 -0
  7. package/docs/COMMAND_REFERENCE_EN.md +79 -0
  8. package/esbuild.config.js +75 -0
  9. package/openclaw.plugin.json +4 -4
  10. package/package.json +11 -13
  11. package/scripts/build-web.mjs +46 -0
  12. package/scripts/install-dependencies.cjs +47 -0
  13. package/scripts/sync-plugin.mjs +802 -0
  14. package/scripts/verify-build.mjs +109 -0
  15. package/src/agents/nocturnal-dreamer.md +152 -0
  16. package/src/agents/nocturnal-philosopher.md +138 -0
  17. package/src/agents/nocturnal-reflector.md +126 -0
  18. package/src/agents/nocturnal-scribe.md +164 -0
  19. package/src/commands/capabilities.ts +85 -0
  20. package/{dist/commands/context.js → src/commands/context.ts} +78 -38
  21. package/src/commands/evolution-status.ts +146 -0
  22. package/src/commands/export.ts +111 -0
  23. package/src/commands/focus.ts +533 -0
  24. package/src/commands/nocturnal-review.ts +311 -0
  25. package/src/commands/nocturnal-rollout.ts +763 -0
  26. package/src/commands/nocturnal-train.ts +1002 -0
  27. package/{dist/commands/pain.js → src/commands/pain.ts} +68 -49
  28. package/src/commands/principle-rollback.ts +27 -0
  29. package/{dist/commands/rollback.js → src/commands/rollback.ts} +44 -12
  30. package/src/commands/samples.ts +60 -0
  31. package/src/commands/strategy.ts +38 -0
  32. package/{dist/commands/thinking-os.js → src/commands/thinking-os.ts} +59 -36
  33. package/src/commands/workflow-debug.ts +128 -0
  34. package/{dist/config/defaults/runtime.js → src/config/defaults/runtime.ts} +12 -5
  35. package/src/config/errors.ts +163 -0
  36. package/{dist/config/index.d.ts → src/config/index.ts} +2 -1
  37. package/src/constants/diagnostician.ts +66 -0
  38. package/src/constants/tools.ts +62 -0
  39. package/src/core/adaptive-thresholds.ts +476 -0
  40. package/{dist/core/config-service.js → src/core/config-service.ts} +7 -4
  41. package/{dist/core/config.js → src/core/config.ts} +158 -46
  42. package/src/core/control-ui-db.ts +435 -0
  43. package/{dist/core/detection-funnel.js → src/core/detection-funnel.ts} +36 -21
  44. package/{dist/core/detection-service.js → src/core/detection-service.ts} +7 -4
  45. package/{dist/core/dictionary-service.js → src/core/dictionary-service.ts} +7 -4
  46. package/{dist/core/dictionary.js → src/core/dictionary.ts} +57 -34
  47. package/src/core/empathy-keyword-matcher.ts +327 -0
  48. package/src/core/empathy-types.ts +218 -0
  49. package/src/core/event-log.ts +544 -0
  50. package/src/core/evolution-engine.ts +612 -0
  51. package/src/core/evolution-logger.ts +353 -0
  52. package/src/core/evolution-migration.ts +77 -0
  53. package/src/core/evolution-reducer.ts +731 -0
  54. package/src/core/evolution-types.ts +456 -0
  55. package/src/core/external-training-contract.ts +527 -0
  56. package/src/core/focus-history.ts +1458 -0
  57. package/src/core/hygiene/tracker.ts +117 -0
  58. package/{dist/core/init.js → src/core/init.ts} +39 -26
  59. package/src/core/local-worker-routing.ts +617 -0
  60. package/{dist/core/migration.js → src/core/migration.ts} +18 -11
  61. package/src/core/model-deployment-registry.ts +722 -0
  62. package/src/core/model-training-registry.ts +813 -0
  63. package/src/core/nocturnal-arbiter.ts +706 -0
  64. package/src/core/nocturnal-candidate-scoring.ts +392 -0
  65. package/src/core/nocturnal-compliance.ts +1075 -0
  66. package/src/core/nocturnal-dataset.ts +668 -0
  67. package/src/core/nocturnal-executability.ts +428 -0
  68. package/src/core/nocturnal-export.ts +390 -0
  69. package/{dist/core/nocturnal-paths.js → src/core/nocturnal-paths.ts} +49 -23
  70. package/src/core/nocturnal-trajectory-extractor.ts +484 -0
  71. package/src/core/nocturnal-trinity.ts +1384 -0
  72. package/src/core/pain.ts +122 -0
  73. package/{dist/core/path-resolver.js → src/core/path-resolver.ts} +157 -36
  74. package/{dist/core/paths.js → src/core/paths.ts} +13 -4
  75. package/src/core/principle-training-state.ts +450 -0
  76. package/src/core/profile.ts +226 -0
  77. package/src/core/promotion-gate.ts +822 -0
  78. package/{dist/core/risk-calculator.js → src/core/risk-calculator.ts} +42 -16
  79. package/{dist/core/session-tracker.js → src/core/session-tracker.ts} +175 -62
  80. package/src/core/shadow-observation-registry.ts +534 -0
  81. package/{dist/core/system-logger.js → src/core/system-logger.ts} +9 -5
  82. package/src/core/thinking-models.ts +217 -0
  83. package/src/core/training-program.ts +630 -0
  84. package/src/core/trajectory-types.ts +243 -0
  85. package/src/core/trajectory.ts +1673 -0
  86. package/{dist/core/workspace-context.js → src/core/workspace-context.ts} +57 -32
  87. package/src/hooks/bash-risk.ts +171 -0
  88. package/src/hooks/edit-verification.ts +295 -0
  89. package/src/hooks/gate-block-helper.ts +160 -0
  90. package/src/hooks/gate.ts +210 -0
  91. package/src/hooks/gfi-gate.ts +177 -0
  92. package/src/hooks/lifecycle.ts +326 -0
  93. package/{dist/hooks/llm.js → src/hooks/llm.ts} +160 -80
  94. package/src/hooks/message-sanitize.ts +45 -0
  95. package/src/hooks/pain.ts +384 -0
  96. package/src/hooks/progressive-trust-gate.ts +174 -0
  97. package/src/hooks/prompt.ts +920 -0
  98. package/src/hooks/subagent.ts +207 -0
  99. package/src/hooks/thinking-checkpoint.ts +73 -0
  100. package/src/hooks/trajectory-collector.ts +290 -0
  101. package/src/http/principles-console-route.ts +716 -0
  102. package/src/i18n/commands.ts +117 -0
  103. package/src/index.ts +694 -0
  104. package/src/service/central-database.ts +831 -0
  105. package/src/service/control-ui-query-service.ts +888 -0
  106. package/src/service/evolution-query-service.ts +405 -0
  107. package/src/service/evolution-worker.ts +1646 -0
  108. package/src/service/health-query-service.ts +836 -0
  109. package/{dist/service/nocturnal-runtime.js → src/service/nocturnal-runtime.ts} +235 -79
  110. package/src/service/nocturnal-service.ts +1015 -0
  111. package/src/service/nocturnal-target-selector.ts +532 -0
  112. package/src/service/phase3-input-filter.ts +237 -0
  113. package/src/service/runtime-summary-service.ts +757 -0
  114. package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +513 -0
  115. package/{dist/service/subagent-workflow/empathy-observer-workflow-manager.js → src/service/subagent-workflow/empathy-observer-workflow-manager.ts} +240 -117
  116. package/src/service/subagent-workflow/index.ts +51 -0
  117. package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +856 -0
  118. package/src/service/subagent-workflow/runtime-direct-driver.ts +166 -0
  119. package/{dist/service/subagent-workflow/types.d.ts → src/service/subagent-workflow/types.ts} +137 -18
  120. package/src/service/subagent-workflow/workflow-store.ts +328 -0
  121. package/src/service/trajectory-service.ts +15 -0
  122. package/{dist/tools/critique-prompt.js → src/tools/critique-prompt.ts} +25 -8
  123. package/src/tools/deep-reflect.ts +349 -0
  124. package/{dist/tools/model-index.js → src/tools/model-index.ts} +33 -17
  125. package/src/types/event-types.ts +453 -0
  126. package/src/types/hygiene-types.ts +31 -0
  127. package/src/types/principle-tree-schema.ts +244 -0
  128. package/src/types/runtime-summary.ts +49 -0
  129. package/src/types.ts +74 -0
  130. package/src/utils/file-lock.ts +391 -0
  131. package/{dist/utils/glob-match.js → src/utils/glob-match.ts} +21 -20
  132. package/{dist/utils/hashing.js → src/utils/hashing.ts} +6 -4
  133. package/src/utils/io.ts +110 -0
  134. package/{dist/utils/nlp.js → src/utils/nlp.ts} +19 -12
  135. package/{dist/utils/plugin-logger.js → src/utils/plugin-logger.ts} +33 -8
  136. package/src/utils/subagent-probe.ts +94 -0
  137. package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +70 -1
  138. package/templates/pain_settings.json +2 -1
  139. package/tests/README.md +120 -0
  140. package/tests/build-artifacts.test.ts +111 -0
  141. package/tests/commands/evolution-status.test.ts +222 -0
  142. package/tests/commands/evolver.test.ts +22 -0
  143. package/tests/commands/export.test.ts +78 -0
  144. package/tests/commands/nocturnal-review.test.ts +448 -0
  145. package/tests/commands/nocturnal-train.test.ts +97 -0
  146. package/tests/commands/pain.test.ts +108 -0
  147. package/tests/commands/samples.test.ts +65 -0
  148. package/tests/commands/strategy.test.ts +34 -0
  149. package/tests/commands/thinking-os.test.ts +88 -0
  150. package/tests/core/adaptive-thresholds.test.ts +261 -0
  151. package/tests/core/config-service.test.ts +89 -0
  152. package/tests/core/config.test.ts +90 -0
  153. package/tests/core/control-ui-db.test.ts +75 -0
  154. package/tests/core/core-template-guidance.test.ts +21 -0
  155. package/tests/core/detection-funnel.test.ts +63 -0
  156. package/tests/core/detection-service.test.ts +50 -0
  157. package/tests/core/dictionary-service.test.ts +116 -0
  158. package/tests/core/dictionary.test.ts +168 -0
  159. package/tests/core/empathy-keyword-matcher.test.ts +209 -0
  160. package/tests/core/event-log.test.ts +181 -0
  161. package/tests/core/evolution-e2e.test.ts +58 -0
  162. package/tests/core/evolution-engine-gate-integration.test.ts +543 -0
  163. package/tests/core/evolution-engine.test.ts +562 -0
  164. package/tests/core/evolution-logger.test.ts +148 -0
  165. package/tests/core/evolution-migration.test.ts +50 -0
  166. package/tests/core/evolution-paths.test.ts +21 -0
  167. package/tests/core/evolution-reducer.detector-metadata.test.ts +602 -0
  168. package/tests/core/evolution-reducer.test.ts +180 -0
  169. package/tests/core/evolution-types-loop.test.ts +48 -0
  170. package/tests/core/evolution-user-stories.e2e.test.ts +249 -0
  171. package/tests/core/external-training-contract.test.ts +463 -0
  172. package/tests/core/focus-history.test.ts +682 -0
  173. package/tests/core/init-flatten.test.ts +69 -0
  174. package/tests/core/init-refactor.test.ts +87 -0
  175. package/tests/core/init-v1.3.test.ts +46 -0
  176. package/tests/core/init.test.ts +190 -0
  177. package/tests/core/local-worker-routing.test.ts +757 -0
  178. package/tests/core/migration.test.ts +84 -0
  179. package/tests/core/model-deployment-registry.test.ts +845 -0
  180. package/tests/core/model-training-registry.test.ts +889 -0
  181. package/tests/core/nocturnal-arbiter.test.ts +494 -0
  182. package/tests/core/nocturnal-candidate-scoring.test.ts +400 -0
  183. package/tests/core/nocturnal-compliance.test.ts +646 -0
  184. package/tests/core/nocturnal-dataset.test.ts +892 -0
  185. package/tests/core/nocturnal-executability.test.ts +357 -0
  186. package/tests/core/nocturnal-export.test.ts +462 -0
  187. package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +428 -0
  188. package/tests/core/nocturnal-trajectory-extractor.test.ts +634 -0
  189. package/tests/core/nocturnal-trinity.test.ts +953 -0
  190. package/tests/core/pain.test.ts +33 -0
  191. package/tests/core/path-resolver.test.ts +57 -0
  192. package/tests/core/paths-refactor.test.ts +42 -0
  193. package/tests/core/phase7-rollout-integration.test.ts +477 -0
  194. package/tests/core/principle-training-state.test.ts +712 -0
  195. package/tests/core/profile.test.ts +56 -0
  196. package/tests/core/promotion-gate.test.ts +556 -0
  197. package/tests/core/risk-calculator.test.ts +168 -0
  198. package/tests/core/session-tracker.test.ts +191 -0
  199. package/tests/core/training-program.test.ts +472 -0
  200. package/tests/core/trajectory.test.ts +265 -0
  201. package/tests/core/workspace-context-factory.test.ts +18 -0
  202. package/tests/core/workspace-context.test.ts +134 -0
  203. package/tests/fixtures/nocturnal-reviewed-subset.json +183 -0
  204. package/tests/fixtures/production-compatibility.test.ts +147 -0
  205. package/tests/fixtures/production-mock-generator.ts +282 -0
  206. package/tests/hooks/bash-risk-integration.test.ts +137 -0
  207. package/tests/hooks/bash-risk.test.ts +81 -0
  208. package/tests/hooks/edit-verification.test.ts +678 -0
  209. package/tests/hooks/gate-edit-verification-p1.test.ts +632 -0
  210. package/tests/hooks/gate-edit-verification.test.ts +435 -0
  211. package/tests/hooks/gate-pipeline-integration.test.ts +404 -0
  212. package/tests/hooks/gate.test.ts +271 -0
  213. package/tests/hooks/gfi-gate-unit.test.ts +422 -0
  214. package/tests/hooks/gfi-gate.test.ts +669 -0
  215. package/tests/hooks/lifecycle.test.ts +248 -0
  216. package/tests/hooks/llm.test.ts +308 -0
  217. package/tests/hooks/message-sanitize.test.ts +36 -0
  218. package/tests/hooks/pain.test.ts +141 -0
  219. package/tests/hooks/progressive-trust-gate.test.ts +277 -0
  220. package/tests/hooks/prompt.test.ts +1411 -0
  221. package/tests/hooks/subagent.test.ts +467 -0
  222. package/tests/hooks/thinking-gate.test.ts +313 -0
  223. package/tests/http/principles-console-route.test.ts +140 -0
  224. package/tests/hygiene-tracker.test.ts +77 -0
  225. package/tests/index.integration.test.ts +179 -0
  226. package/tests/index.shadow-routing.integration.test.ts +140 -0
  227. package/tests/index.test.ts +9 -0
  228. package/tests/integration/empathy-workflow-integration.test.ts +627 -0
  229. package/tests/service/control-ui-query-service.test.ts +121 -0
  230. package/tests/service/empathy-observer-workflow-manager.test.ts +176 -0
  231. package/tests/service/evolution-worker.test.ts +585 -0
  232. package/tests/service/nocturnal-runtime.test.ts +470 -0
  233. package/tests/service/nocturnal-service.test.ts +577 -0
  234. package/tests/service/nocturnal-target-selector.test.ts +615 -0
  235. package/tests/service/nocturnal-workflow-manager.test.ts +439 -0
  236. package/tests/service/phase3-input-filter.test.ts +289 -0
  237. package/tests/service/runtime-summary-service.test.ts +919 -0
  238. package/tests/task-compliance.test.ts +166 -0
  239. package/tests/test-utils.ts +48 -0
  240. package/tests/tools/critique-prompt.test.ts +260 -0
  241. package/tests/tools/deep-reflect.test.ts +232 -0
  242. package/tests/tools/model-index.test.ts +246 -0
  243. package/tests/ui/app.test.tsx +114 -0
  244. package/tests/utils/file-lock.test.ts +407 -0
  245. package/tests/utils/hashing.test.ts +32 -0
  246. package/tests/utils/io.test.ts +39 -0
  247. package/tests/utils/nlp.test.ts +53 -0
  248. package/tests/utils/plugin-logger.test.ts +156 -0
  249. package/tsconfig.json +16 -0
  250. package/tsconfig.tsbuildinfo +1 -0
  251. package/ui/src/App.tsx +45 -0
  252. package/ui/src/api.ts +216 -0
  253. package/ui/src/charts.tsx +586 -0
  254. package/ui/src/components/ErrorState.tsx +6 -0
  255. package/ui/src/components/Loading.tsx +13 -0
  256. package/ui/src/components/ProtectedRoute.tsx +12 -0
  257. package/ui/src/components/Shell.tsx +91 -0
  258. package/ui/src/components/WorkspaceConfig.tsx +146 -0
  259. package/ui/src/components/index.ts +5 -0
  260. package/ui/src/context/auth.tsx +80 -0
  261. package/ui/src/context/theme.tsx +66 -0
  262. package/ui/src/hooks/useAutoRefresh.ts +39 -0
  263. package/ui/src/i18n/ui.ts +363 -0
  264. package/ui/src/main.tsx +16 -0
  265. package/ui/src/pages/EvolutionPage.tsx +352 -0
  266. package/ui/src/pages/FeedbackPage.tsx +140 -0
  267. package/ui/src/pages/GateMonitorPage.tsx +136 -0
  268. package/ui/src/pages/LoginPage.tsx +88 -0
  269. package/ui/src/pages/OverviewPage.tsx +238 -0
  270. package/ui/src/pages/SamplesPage.tsx +174 -0
  271. package/ui/src/pages/ThinkingModelsPage.tsx +127 -0
  272. package/ui/src/styles.css +1661 -0
  273. package/ui/src/types.ts +368 -0
  274. package/ui/src/utils/format.ts +15 -0
  275. package/vitest.config.ts +23 -0
  276. package/dist/commands/capabilities.d.ts +0 -3
  277. package/dist/commands/capabilities.js +0 -73
  278. package/dist/commands/context.d.ts +0 -5
  279. package/dist/commands/evolution-status.d.ts +0 -4
  280. package/dist/commands/evolution-status.js +0 -117
  281. package/dist/commands/evolver.d.ts +0 -9
  282. package/dist/commands/evolver.js +0 -26
  283. package/dist/commands/export.d.ts +0 -2
  284. package/dist/commands/export.js +0 -98
  285. package/dist/commands/focus.d.ts +0 -14
  286. package/dist/commands/focus.js +0 -457
  287. package/dist/commands/nocturnal-review.d.ts +0 -24
  288. package/dist/commands/nocturnal-review.js +0 -265
  289. package/dist/commands/nocturnal-rollout.d.ts +0 -27
  290. package/dist/commands/nocturnal-rollout.js +0 -671
  291. package/dist/commands/nocturnal-train.d.ts +0 -25
  292. package/dist/commands/nocturnal-train.js +0 -919
  293. package/dist/commands/pain.d.ts +0 -5
  294. package/dist/commands/principle-rollback.d.ts +0 -4
  295. package/dist/commands/principle-rollback.js +0 -22
  296. package/dist/commands/rollback.d.ts +0 -19
  297. package/dist/commands/samples.d.ts +0 -2
  298. package/dist/commands/samples.js +0 -55
  299. package/dist/commands/strategy.d.ts +0 -3
  300. package/dist/commands/strategy.js +0 -29
  301. package/dist/commands/thinking-os.d.ts +0 -2
  302. package/dist/config/defaults/runtime.d.ts +0 -40
  303. package/dist/config/errors.d.ts +0 -84
  304. package/dist/config/errors.js +0 -94
  305. package/dist/config/index.js +0 -7
  306. package/dist/constants/diagnostician.d.ts +0 -12
  307. package/dist/constants/diagnostician.js +0 -56
  308. package/dist/constants/tools.d.ts +0 -17
  309. package/dist/constants/tools.js +0 -54
  310. package/dist/core/adaptive-thresholds.d.ts +0 -186
  311. package/dist/core/adaptive-thresholds.js +0 -300
  312. package/dist/core/config-service.d.ts +0 -15
  313. package/dist/core/config.d.ts +0 -129
  314. package/dist/core/control-ui-db.d.ts +0 -95
  315. package/dist/core/control-ui-db.js +0 -292
  316. package/dist/core/detection-funnel.d.ts +0 -33
  317. package/dist/core/detection-service.d.ts +0 -15
  318. package/dist/core/dictionary-service.d.ts +0 -15
  319. package/dist/core/dictionary.d.ts +0 -38
  320. package/dist/core/event-log.d.ts +0 -82
  321. package/dist/core/event-log.js +0 -463
  322. package/dist/core/evolution-engine.d.ts +0 -118
  323. package/dist/core/evolution-engine.js +0 -464
  324. package/dist/core/evolution-logger.d.ts +0 -137
  325. package/dist/core/evolution-logger.js +0 -256
  326. package/dist/core/evolution-migration.d.ts +0 -5
  327. package/dist/core/evolution-migration.js +0 -65
  328. package/dist/core/evolution-reducer.d.ts +0 -98
  329. package/dist/core/evolution-reducer.js +0 -465
  330. package/dist/core/evolution-types.d.ts +0 -287
  331. package/dist/core/evolution-types.js +0 -78
  332. package/dist/core/external-training-contract.d.ts +0 -276
  333. package/dist/core/external-training-contract.js +0 -269
  334. package/dist/core/focus-history.d.ts +0 -210
  335. package/dist/core/focus-history.js +0 -1185
  336. package/dist/core/hygiene/tracker.d.ts +0 -22
  337. package/dist/core/hygiene/tracker.js +0 -106
  338. package/dist/core/init.d.ts +0 -12
  339. package/dist/core/local-worker-routing.d.ts +0 -175
  340. package/dist/core/local-worker-routing.js +0 -525
  341. package/dist/core/migration.d.ts +0 -6
  342. package/dist/core/model-deployment-registry.d.ts +0 -218
  343. package/dist/core/model-deployment-registry.js +0 -503
  344. package/dist/core/model-training-registry.d.ts +0 -295
  345. package/dist/core/model-training-registry.js +0 -475
  346. package/dist/core/nocturnal-arbiter.d.ts +0 -159
  347. package/dist/core/nocturnal-arbiter.js +0 -534
  348. package/dist/core/nocturnal-candidate-scoring.d.ts +0 -137
  349. package/dist/core/nocturnal-candidate-scoring.js +0 -266
  350. package/dist/core/nocturnal-compliance.d.ts +0 -175
  351. package/dist/core/nocturnal-compliance.js +0 -824
  352. package/dist/core/nocturnal-dataset.d.ts +0 -224
  353. package/dist/core/nocturnal-dataset.js +0 -443
  354. package/dist/core/nocturnal-executability.d.ts +0 -85
  355. package/dist/core/nocturnal-executability.js +0 -331
  356. package/dist/core/nocturnal-export.d.ts +0 -124
  357. package/dist/core/nocturnal-export.js +0 -275
  358. package/dist/core/nocturnal-paths.d.ts +0 -124
  359. package/dist/core/nocturnal-trajectory-extractor.d.ts +0 -242
  360. package/dist/core/nocturnal-trajectory-extractor.js +0 -307
  361. package/dist/core/nocturnal-trinity.d.ts +0 -311
  362. package/dist/core/nocturnal-trinity.js +0 -880
  363. package/dist/core/pain.d.ts +0 -4
  364. package/dist/core/pain.js +0 -70
  365. package/dist/core/path-resolver.d.ts +0 -46
  366. package/dist/core/paths.d.ts +0 -65
  367. package/dist/core/principle-training-state.d.ts +0 -121
  368. package/dist/core/principle-training-state.js +0 -321
  369. package/dist/core/profile.d.ts +0 -62
  370. package/dist/core/profile.js +0 -210
  371. package/dist/core/promotion-gate.d.ts +0 -238
  372. package/dist/core/promotion-gate.js +0 -529
  373. package/dist/core/risk-calculator.d.ts +0 -22
  374. package/dist/core/session-tracker.d.ts +0 -101
  375. package/dist/core/shadow-observation-registry.d.ts +0 -217
  376. package/dist/core/shadow-observation-registry.js +0 -308
  377. package/dist/core/system-logger.d.ts +0 -8
  378. package/dist/core/thinking-models.d.ts +0 -38
  379. package/dist/core/thinking-models.js +0 -170
  380. package/dist/core/training-program.d.ts +0 -233
  381. package/dist/core/training-program.js +0 -433
  382. package/dist/core/trajectory.d.ts +0 -411
  383. package/dist/core/trajectory.js +0 -1307
  384. package/dist/core/workspace-context.d.ts +0 -71
  385. package/dist/hooks/bash-risk.d.ts +0 -57
  386. package/dist/hooks/bash-risk.js +0 -137
  387. package/dist/hooks/edit-verification.d.ts +0 -62
  388. package/dist/hooks/edit-verification.js +0 -256
  389. package/dist/hooks/gate-block-helper.d.ts +0 -44
  390. package/dist/hooks/gate-block-helper.js +0 -119
  391. package/dist/hooks/gate.d.ts +0 -24
  392. package/dist/hooks/gate.js +0 -173
  393. package/dist/hooks/gfi-gate.d.ts +0 -40
  394. package/dist/hooks/gfi-gate.js +0 -113
  395. package/dist/hooks/lifecycle.d.ts +0 -5
  396. package/dist/hooks/lifecycle.js +0 -284
  397. package/dist/hooks/llm.d.ts +0 -13
  398. package/dist/hooks/message-sanitize.d.ts +0 -3
  399. package/dist/hooks/message-sanitize.js +0 -37
  400. package/dist/hooks/pain.d.ts +0 -5
  401. package/dist/hooks/pain.js +0 -301
  402. package/dist/hooks/progressive-trust-gate.d.ts +0 -52
  403. package/dist/hooks/progressive-trust-gate.js +0 -134
  404. package/dist/hooks/prompt.d.ts +0 -49
  405. package/dist/hooks/prompt.js +0 -905
  406. package/dist/hooks/subagent.d.ts +0 -10
  407. package/dist/hooks/subagent.js +0 -387
  408. package/dist/hooks/thinking-checkpoint.d.ts +0 -37
  409. package/dist/hooks/thinking-checkpoint.js +0 -51
  410. package/dist/hooks/trajectory-collector.d.ts +0 -32
  411. package/dist/hooks/trajectory-collector.js +0 -256
  412. package/dist/http/principles-console-route.d.ts +0 -9
  413. package/dist/http/principles-console-route.js +0 -681
  414. package/dist/i18n/commands.d.ts +0 -26
  415. package/dist/i18n/commands.js +0 -116
  416. package/dist/index.d.ts +0 -7
  417. package/dist/index.js +0 -581
  418. package/dist/service/central-database.d.ts +0 -104
  419. package/dist/service/central-database.js +0 -649
  420. package/dist/service/control-ui-query-service.d.ts +0 -221
  421. package/dist/service/control-ui-query-service.js +0 -543
  422. package/dist/service/empathy-observer-manager.d.ts +0 -88
  423. package/dist/service/empathy-observer-manager.js +0 -414
  424. package/dist/service/evolution-query-service.d.ts +0 -155
  425. package/dist/service/evolution-query-service.js +0 -258
  426. package/dist/service/evolution-worker.d.ts +0 -101
  427. package/dist/service/evolution-worker.js +0 -975
  428. package/dist/service/health-query-service.d.ts +0 -170
  429. package/dist/service/health-query-service.js +0 -662
  430. package/dist/service/nocturnal-runtime.d.ts +0 -183
  431. package/dist/service/nocturnal-service.d.ts +0 -163
  432. package/dist/service/nocturnal-service.js +0 -787
  433. package/dist/service/nocturnal-target-selector.d.ts +0 -145
  434. package/dist/service/nocturnal-target-selector.js +0 -315
  435. package/dist/service/phase3-input-filter.d.ts +0 -73
  436. package/dist/service/phase3-input-filter.js +0 -172
  437. package/dist/service/runtime-summary-service.d.ts +0 -122
  438. package/dist/service/runtime-summary-service.js +0 -485
  439. package/dist/service/subagent-workflow/empathy-observer-workflow-manager.d.ts +0 -48
  440. package/dist/service/subagent-workflow/index.d.ts +0 -4
  441. package/dist/service/subagent-workflow/index.js +0 -3
  442. package/dist/service/subagent-workflow/runtime-direct-driver.d.ts +0 -77
  443. package/dist/service/subagent-workflow/runtime-direct-driver.js +0 -75
  444. package/dist/service/subagent-workflow/types.js +0 -11
  445. package/dist/service/subagent-workflow/workflow-store.d.ts +0 -26
  446. package/dist/service/subagent-workflow/workflow-store.js +0 -165
  447. package/dist/service/trajectory-service.d.ts +0 -2
  448. package/dist/service/trajectory-service.js +0 -15
  449. package/dist/tools/critique-prompt.d.ts +0 -14
  450. package/dist/tools/deep-reflect.d.ts +0 -39
  451. package/dist/tools/deep-reflect.js +0 -350
  452. package/dist/tools/model-index.d.ts +0 -9
  453. package/dist/types/event-types.d.ts +0 -306
  454. package/dist/types/event-types.js +0 -106
  455. package/dist/types/hygiene-types.d.ts +0 -20
  456. package/dist/types/hygiene-types.js +0 -12
  457. package/dist/types/runtime-summary.d.ts +0 -47
  458. package/dist/types/runtime-summary.js +0 -1
  459. package/dist/types.d.ts +0 -50
  460. package/dist/types.js +0 -22
  461. package/dist/utils/file-lock.d.ts +0 -71
  462. package/dist/utils/file-lock.js +0 -309
  463. package/dist/utils/glob-match.d.ts +0 -28
  464. package/dist/utils/hashing.d.ts +0 -9
  465. package/dist/utils/io.d.ts +0 -6
  466. package/dist/utils/io.js +0 -106
  467. package/dist/utils/nlp.d.ts +0 -9
  468. package/dist/utils/plugin-logger.d.ts +0 -39
  469. package/dist/utils/subagent-probe.d.ts +0 -34
  470. package/dist/utils/subagent-probe.js +0 -81
@@ -1,44 +1,64 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
- import { trackLlmOutput, recordThinkingCheckpoint, resetFriction } from '../core/session-tracker.js';
3
+ import { PluginHookLlmOutputEvent, PluginHookAgentContext } from '../openclaw-sdk.js';
4
+ import { trackFriction, trackLlmOutput, recordThinkingCheckpoint, resetFriction } from '../core/session-tracker.js';
4
5
  import { writePainFlag } from '../core/pain.js';
5
6
  import { ControlUiDatabase } from '../core/control-ui-db.js';
6
7
  import { DetectionService } from '../core/detection-service.js';
7
8
  import { detectThinkingModelMatches, deriveThinkingScenarios } from '../core/thinking-models.js';
8
9
  import { WorkspaceContext } from '../core/workspace-context.js';
9
10
  import { sanitizeAssistantText } from './message-sanitize.js';
10
- const empathyDedupState = new Map();
11
- const empathyRateState = new Map();
12
- function clamp(value, min, max) {
11
+
12
+ export interface EmpathySignal {
13
+ detected: boolean;
14
+ severity: 'mild' | 'moderate' | 'severe';
15
+ confidence: number;
16
+ reason?: string;
17
+ mode?: 'structured' | 'legacy_tag';
18
+ }
19
+
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
+ function clamp(value: number, min: number, max: number): number {
13
31
  return Math.max(min, Math.min(max, value));
14
32
  }
15
- function normalizeSeverity(input) {
33
+
34
+ function normalizeSeverity(input?: string): 'mild' | 'moderate' | 'severe' {
16
35
  const normalized = (input || '').toLowerCase();
17
- if (normalized === 'severe' || normalized === 'high')
18
- return 'severe';
19
- if (normalized === 'moderate' || normalized === 'medium')
20
- return 'moderate';
36
+ if (normalized === 'severe' || normalized === 'high') return 'severe';
37
+ if (normalized === 'moderate' || normalized === 'medium') return 'moderate';
21
38
  return 'mild';
22
39
  }
23
- function parseConfidence(raw) {
40
+
41
+ function parseConfidence(raw?: string): number {
24
42
  const parsed = Number(raw);
25
- if (!Number.isFinite(parsed))
26
- return 1;
43
+ if (!Number.isFinite(parsed)) return 1;
27
44
  return clamp(parsed, 0, 1);
28
45
  }
29
- function parseTrustedLegacyTag(text) {
46
+
47
+ function parseTrustedLegacyTag(text: string): RegExpMatchArray | null {
30
48
  return text.match(/^\s*\[EMOTIONAL_DAMAGE_DETECTED(?::(mild|moderate|severe))?\]\s*$/i);
31
49
  }
50
+
32
51
  /**
33
52
  * 检测标签是否是被用户诱导/引用输出的(回显),而非 LLM 主动输出的情绪信号
34
53
  */
35
- function isEchoedTag(text, tagMatch) {
54
+ function isEchoedTag(text: string, tagMatch: RegExpMatchArray): boolean {
36
55
  const tagIndex = tagMatch.index ?? 0;
37
56
  const before = text.substring(Math.max(0, tagIndex - 100), tagIndex).toLowerCase();
57
+
38
58
  // 1. 检查是否在引号内(用户引用)
39
59
  const quotesBefore = (before.match(/["'\u300c\u300d\u201c\u201d`]/g) || []).length;
40
- if (quotesBefore % 2 === 1)
41
- return true;
60
+ if (quotesBefore % 2 === 1) return true;
61
+
42
62
  // 2. Strong patterns: 用户指令关键词(任意位置匹配)
43
63
  const strongPatterns = [
44
64
  /用户(说|让|要求|让我输出)/,
@@ -48,9 +68,9 @@ function isEchoedTag(text, tagMatch) {
48
68
  /你让我输出/,
49
69
  ];
50
70
  for (const pattern of strongPatterns) {
51
- if (pattern.test(before))
52
- return true;
71
+ if (pattern.test(before)) return true;
53
72
  }
73
+
54
74
  // 3. Weak patterns: 仅在标签 15 字符内触发
55
75
  const weakPatterns = [
56
76
  { pattern: /echo/, window: 15 },
@@ -59,19 +79,21 @@ function isEchoedTag(text, tagMatch) {
59
79
  ];
60
80
  for (const { pattern, window } of weakPatterns) {
61
81
  const nearTag = text.substring(Math.max(0, tagIndex - window), tagIndex).toLowerCase();
62
- if (pattern.test(nearTag))
63
- return true;
82
+ if (pattern.test(nearTag)) return true;
64
83
  }
84
+
65
85
  // 4. 检查是否在代码块内
66
86
  const codeBlocksBefore = (before.match(/```/g) || []).length;
67
- if (codeBlocksBefore % 2 === 1)
68
- return true;
87
+ if (codeBlocksBefore % 2 === 1) return true;
88
+
69
89
  return false;
70
90
  }
71
- export function extractEmpathySignal(text) {
91
+
92
+ export function extractEmpathySignal(text: string): EmpathySignal {
72
93
  if (!text || typeof text !== 'string') {
73
94
  return { detected: false, severity: 'mild', confidence: 1 };
74
95
  }
96
+
75
97
  const xmlMatch = text.match(/<empathy\s+([^>]*)\/?>(?:<\/empathy>)?/i);
76
98
  if (xmlMatch?.[1]) {
77
99
  const attrs = xmlMatch[1];
@@ -83,11 +105,14 @@ export function extractEmpathySignal(text) {
83
105
  return { detected: true, severity, confidence, reason, mode: 'structured' };
84
106
  }
85
107
  }
108
+
86
109
  const jsonMatch = text.match(/"empathy"\s*:\s*\{[\s\S]*?\}/i);
87
110
  if (jsonMatch) {
88
111
  const jsonText = `{${jsonMatch[0]}}`;
89
112
  try {
90
- const parsed = JSON.parse(jsonText);
113
+ const parsed = JSON.parse(jsonText) as {
114
+ empathy?: { damageDetected?: boolean; severity?: string; confidence?: number; reason?: string };
115
+ };
91
116
  if (parsed.empathy?.damageDetected === true) {
92
117
  return {
93
118
  detected: true,
@@ -97,11 +122,11 @@ export function extractEmpathySignal(text) {
97
122
  mode: 'structured'
98
123
  };
99
124
  }
100
- }
101
- catch {
125
+ } catch {
102
126
  // ignore malformed snippet
103
127
  }
104
128
  }
129
+
105
130
  const tagMatch = parseTrustedLegacyTag(text);
106
131
  if (tagMatch) {
107
132
  if (isEchoedTag(text, tagMatch)) {
@@ -114,22 +139,25 @@ export function extractEmpathySignal(text) {
114
139
  mode: 'legacy_tag'
115
140
  };
116
141
  }
142
+
117
143
  return { detected: false, severity: 'mild', confidence: 1 };
118
144
  }
119
- function mapSeverityToPenalty(severity, config) {
145
+
146
+ function mapSeverityToPenalty(severity: 'mild' | 'moderate' | 'severe', config: ReturnType<typeof WorkspaceContext.fromHookContext>['config']): number {
120
147
  const mild = Number(config.get('empathy_engine.penalties.mild') ?? 10);
121
148
  const moderate = Number(config.get('empathy_engine.penalties.moderate') ?? 25);
122
149
  const severe = Number(config.get('empathy_engine.penalties.severe') ?? 40);
123
- if (severity === 'severe')
124
- return severe;
125
- if (severity === 'moderate')
126
- return moderate;
150
+
151
+ if (severity === 'severe') return severe;
152
+ if (severity === 'moderate') return moderate;
127
153
  return mild;
128
154
  }
129
- function dedupeKey(sessionId, runId, signal) {
155
+
156
+ function dedupeKey(sessionId: string, runId: string, signal: EmpathySignal): string {
130
157
  return `${sessionId}:${runId}:${signal.severity}:${(signal.reason || '').slice(0, 80)}`;
131
158
  }
132
- function shouldDedupe(sessionId, runId, signal, windowMs) {
159
+
160
+ function shouldDedupe(sessionId: string, runId: string, signal: EmpathySignal, windowMs: number): boolean {
133
161
  const key = dedupeKey(sessionId, runId, signal);
134
162
  const now = Date.now();
135
163
  const last = empathyDedupState.get(key);
@@ -139,69 +167,88 @@ function shouldDedupe(sessionId, runId, signal, windowMs) {
139
167
  empathyDedupState.set(key, now);
140
168
  return false;
141
169
  }
142
- function resolveCalibrationFactor(event, config) {
143
- const table = config.get('empathy_engine.model_calibration');
144
- if (!table || typeof table !== 'object')
145
- return 1;
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
+
146
178
  const modelKey = `${event.provider}/${event.model}`;
147
179
  const factor = Number(table[modelKey] ?? 1);
148
- if (!Number.isFinite(factor))
149
- return 1;
180
+ if (!Number.isFinite(factor)) return 1;
150
181
  return clamp(factor, 0.1, 3);
151
182
  }
152
- function applyRateLimit(sessionId, runId, score, config) {
183
+
184
+ function applyRateLimit(
185
+ sessionId: string,
186
+ runId: string,
187
+ score: number,
188
+ config: ReturnType<typeof WorkspaceContext.fromHookContext>['config']
189
+ ): number {
153
190
  const maxPerTurn = Number(config.get('empathy_engine.rate_limit.max_per_turn') ?? 40);
154
191
  const maxPerHour = Number(config.get('empathy_engine.rate_limit.max_per_hour') ?? 120);
155
192
  const now = Date.now();
193
+
156
194
  const prev = empathyRateState.get(sessionId) ?? {
157
195
  turnScore: 0,
158
196
  hourScore: 0,
159
197
  hourWindowStart: now,
160
198
  lastRunId: runId,
161
199
  };
200
+
162
201
  if (prev.lastRunId !== runId) {
163
202
  prev.turnScore = 0;
164
203
  prev.lastRunId = runId;
165
204
  }
205
+
166
206
  if (now - prev.hourWindowStart >= 60 * 60 * 1000) {
167
207
  prev.hourScore = 0;
168
208
  prev.hourWindowStart = now;
169
209
  }
210
+
170
211
  const byTurn = Math.max(0, maxPerTurn - prev.turnScore);
171
212
  const byHour = Math.max(0, maxPerHour - prev.hourScore);
172
213
  const allowed = Math.max(0, Math.min(score, byTurn, byHour));
214
+
173
215
  prev.turnScore += allowed;
174
216
  prev.hourScore += allowed;
175
217
  empathyRateState.set(sessionId, prev);
218
+
176
219
  return allowed;
177
220
  }
178
- export function isEmpathyAuditPayload(text) {
179
- if (!text || typeof text !== 'string')
180
- return false;
221
+
222
+
223
+ export function isEmpathyAuditPayload(text: string): boolean {
224
+ if (!text || typeof text !== 'string') return false;
181
225
  const trimmed = text.trim();
182
- if (/^\{[\s\S]*"damageDetected"[\s\S]*\}$/.test(trimmed))
183
- return true;
184
- if (/^<empathy\s+([^>]*)\/?>/i.test(trimmed))
185
- return true;
186
- if (/^\s*\[EMOTIONAL_DAMAGE_DETECTED(?::(mild|moderate|severe))?\]\s*$/i.test(trimmed))
187
- return true;
226
+ if (/^\{[\s\S]*"damageDetected"[\s\S]*\}$/.test(trimmed)) return true;
227
+ if (/^<empathy\s+([^>]*)\/?>/i.test(trimmed)) return true;
228
+ if (/^\s*\[EMOTIONAL_DAMAGE_DETECTED(?::(mild|moderate|severe))?\]\s*$/i.test(trimmed)) return true;
188
229
  return false;
189
230
  }
190
- export function handleLlmOutput(event, ctx) {
191
- if (!ctx.workspaceDir || !ctx.sessionId)
192
- return;
231
+
232
+ export function handleLlmOutput(
233
+ event: PluginHookLlmOutputEvent,
234
+ ctx: PluginHookAgentContext & { workspaceDir?: string }
235
+ ): void {
236
+ if (!ctx.workspaceDir || !ctx.sessionId) return;
237
+
193
238
  const wctx = WorkspaceContext.fromHookContext(ctx);
194
239
  const config = wctx.config;
195
240
  const eventLog = wctx.eventLog;
241
+
196
242
  // Track this turn in the core session memory
197
243
  const state = trackLlmOutput(ctx.sessionId, event.usage, config, ctx.workspaceDir, ctx.sessionKey, ctx.trigger);
244
+
198
245
  // We need actual assistant text to analyze
199
- if (!event.assistantTexts || event.assistantTexts.length === 0)
200
- return;
246
+ if (!event.assistantTexts || event.assistantTexts.length === 0) return;
247
+
201
248
  const text = event.assistantTexts.join('\n');
202
249
  const signal = extractEmpathySignal(text);
203
250
  const createdAt = new Date().toISOString();
204
- let assistantTurnId = null;
251
+ let assistantTurnId: number | null = null;
205
252
  try {
206
253
  assistantTurnId = wctx.trajectory?.recordAssistantTurn?.({
207
254
  sessionId: ctx.sessionId,
@@ -214,14 +261,15 @@ export function handleLlmOutput(event, ctx) {
214
261
  empathySignalJson: signal,
215
262
  createdAt,
216
263
  });
217
- }
218
- catch (error) {
264
+ } catch (error) {
219
265
  ctx.logger?.warn?.(`[PD:LLM] Failed to persist assistant turn to trajectory: ${String(error)}`);
220
266
  }
267
+
221
268
  // ── Track B: Semantic Pain Detection (V1.3.0 Funnel) ──
222
269
  const detectionText = isEmpathyAuditPayload(text) ? '' : text;
223
270
  const detectionService = DetectionService.get(wctx.stateDir);
224
271
  const detection = detectionService.detect(detectionText);
272
+
225
273
  if (detection.detected) {
226
274
  eventLog.recordRuleMatch(ctx.sessionId, {
227
275
  ruleId: detection.ruleId || detection.source,
@@ -230,6 +278,7 @@ export function handleLlmOutput(event, ctx) {
230
278
  textPreview: detectionText.substring(0, 100)
231
279
  });
232
280
  }
281
+
233
282
  let painScore = detection.detected ? (detection.severity || 0) : 0;
234
283
  let source = detection.detected
235
284
  ? (detection.ruleId ? `llm_${detection.ruleId.toLowerCase()}` : `llm_${detection.source}`)
@@ -237,12 +286,18 @@ export function handleLlmOutput(event, ctx) {
237
286
  let matchedReason = detection.detected
238
287
  ? `Agent triggered pain detection (Source: ${detection.source}${detection.ruleId ? `, Rule: ${detection.ruleId}` : ''})`
239
288
  : '';
289
+
240
290
  // ═══ Natural Language Rollback Detection ═══
241
291
  const rollbackMatch = text.match(/^\s*\[EMPATHY_ROLLBACK_REQUEST\]\s*$/m);
242
292
  if (rollbackMatch) {
243
293
  const eventId = eventLog.getLastEmpathyEventId(ctx.sessionId);
244
294
  if (eventId) {
245
- const rolledBackScore = eventLog.rollbackEmpathyEvent(eventId, ctx.sessionId, 'Natural language rollback request detected', 'natural_language');
295
+ const rolledBackScore = eventLog.rollbackEmpathyEvent(
296
+ eventId,
297
+ ctx.sessionId,
298
+ 'Natural language rollback request detected',
299
+ 'natural_language'
300
+ );
246
301
  if (rolledBackScore > 0) {
247
302
  // Reset GFI after successful rollback
248
303
  resetFriction(ctx.sessionId, ctx.workspaceDir, {
@@ -252,28 +307,37 @@ export function handleLlmOutput(event, ctx) {
252
307
  }
253
308
  }
254
309
  }
310
+
255
311
  // 3. Paralysis Check (from session state tracker)
256
312
  const stuckThreshold = config.get('thresholds.stuck_loops_trigger') || 3;
257
313
  const inputThreshold = config.get('thresholds.cognitive_paralysis_input') || 4000;
258
314
  const paralysisScore = config.get('scores.paralysis') || 40;
315
+
259
316
  if (state.stuckLoops >= stuckThreshold && state.totalInputTokens > inputThreshold && painScore < paralysisScore) {
260
317
  painScore = paralysisScore;
261
318
  source = 'llm_paralysis';
262
319
  matchedReason = `Agent is stuck in low-output loops (${state.stuckLoops} consecutive turns with tiny output but huge context), indicating cognitive paralysis.`;
263
320
  }
321
+
264
322
  // If a pain threshold is crossed, write the autonomous pain flag
265
323
  const painTriggerThreshold = config.get('thresholds.pain_trigger') || 30;
266
324
  if (painScore >= painTriggerThreshold) {
267
325
  // Inject the actual text snippet that triggered this for the diagnostician to read later
268
326
  const snippet = text.length > 200 ? text.substring(0, 100) + '...' + text.substring(text.length - 100) : text;
269
- writePainFlag(ctx.workspaceDir, {
270
- source,
271
- score: String(painScore),
272
- time: new Date().toISOString(),
273
- reason: matchedReason,
274
- is_risky: 'false',
275
- trigger_text_preview: snippet
276
- });
327
+
328
+ try {
329
+ writePainFlag(ctx.workspaceDir, {
330
+ source,
331
+ score: String(painScore),
332
+ time: new Date().toISOString(),
333
+ reason: matchedReason,
334
+ is_risky: 'false',
335
+ trigger_text_preview: snippet
336
+ });
337
+ } catch (e) {
338
+ ctx.logger?.warn?.(`[PD:LLM] Failed to write pain flag: ${String(e)}`);
339
+ }
340
+
277
341
  eventLog.recordPainSignal(ctx.sessionId, {
278
342
  score: painScore,
279
343
  source: source,
@@ -281,6 +345,7 @@ export function handleLlmOutput(event, ctx) {
281
345
  isRisky: false
282
346
  });
283
347
  }
348
+
284
349
  // ═══ Thinking OS: Mental Model Usage Tracking ═══
285
350
  trackThinkingModelUsage({
286
351
  text,
@@ -292,41 +357,56 @@ export function handleLlmOutput(event, ctx) {
292
357
  logger: ctx.logger,
293
358
  });
294
359
  }
295
- function trackThinkingModelUsage(args) {
360
+
361
+ function trackThinkingModelUsage(args: {
362
+ text: string;
363
+ wctx: WorkspaceContext;
364
+ sessionId?: string;
365
+ runId: string;
366
+ assistantTurnId: number | null;
367
+ createdAt: string;
368
+ logger?: PluginHookAgentContext['logger'];
369
+ }): void {
296
370
  const { text, wctx, sessionId, runId, assistantTurnId, createdAt, logger } = args;
297
371
  const logPath = wctx.resolve('THINKING_OS_USAGE');
298
372
  const logDir = path.dirname(logPath);
299
- if (!fs.existsSync(logDir))
300
- fs.mkdirSync(logDir, { recursive: true });
301
- let usageLog = {};
373
+ if (!fs.existsSync(logDir)) fs.mkdirSync(logDir, { recursive: true });
374
+
375
+ let usageLog: Record<string, number> = {};
376
+
302
377
  if (fs.existsSync(logPath)) {
303
378
  try {
304
379
  usageLog = JSON.parse(fs.readFileSync(logPath, 'utf8'));
305
- }
306
- catch (e) {
307
- console.error(`[PD:LLM] Failed to parse thinking OS usage log: ${String(e)}`);
380
+ } catch (e) {
381
+ logger?.error?.(`[PD:LLM] Failed to parse thinking OS usage log: ${String(e)}`);
308
382
  }
309
383
  }
384
+
310
385
  const matches = detectThinkingModelMatches(text);
311
386
  for (const match of matches) {
312
387
  usageLog[match.modelId] = (usageLog[match.modelId] || 0) + 1;
313
388
  }
389
+
314
390
  usageLog['_total_turns'] = (usageLog['_total_turns'] || 0) + 1;
391
+
315
392
  try {
316
393
  fs.writeFileSync(logPath, JSON.stringify(usageLog, null, 2), 'utf8');
394
+ } catch (e) {
395
+ logger?.error?.(`[PD:LLM] Failed to write thinking OS usage log: ${String(e)}`);
317
396
  }
318
- catch (e) {
319
- console.error(`[PD:LLM] Failed to write thinking OS usage log: ${String(e)}`);
320
- }
397
+
321
398
  if (matches.length === 0) {
322
399
  return;
323
400
  }
401
+
324
402
  if (sessionId) {
325
403
  recordThinkingCheckpoint(sessionId, wctx.workspaceDir);
326
404
  }
405
+
327
406
  if (!sessionId || !assistantTurnId) {
328
407
  return;
329
408
  }
409
+
330
410
  const uiDb = new ControlUiDatabase({ workspaceDir: wctx.workspaceDir });
331
411
  try {
332
412
  const recentContext = uiDb.getRecentThinkingContext(sessionId, createdAt);
@@ -344,6 +424,7 @@ function trackThinkingModelUsage(args) {
344
424
  eventType: event.eventType,
345
425
  }));
346
426
  const triggerExcerpt = text.length > 280 ? `${text.slice(0, 277)}...` : text;
427
+
347
428
  for (const match of matches) {
348
429
  const scenarios = deriveThinkingScenarios(match.modelId, {
349
430
  recentToolCalls: toolContext,
@@ -357,6 +438,7 @@ function trackThinkingModelUsage(args) {
357
438
  })),
358
439
  recentPrincipleEvents: principleContext,
359
440
  });
441
+
360
442
  uiDb.recordThinkingModelEvent({
361
443
  sessionId,
362
444
  runId,
@@ -371,11 +453,9 @@ function trackThinkingModelUsage(args) {
371
453
  createdAt,
372
454
  });
373
455
  }
374
- }
375
- catch (error) {
456
+ } catch (error) {
376
457
  logger?.warn?.(`[PD:LLM] Failed to persist thinking model events: ${String(error)}`);
377
- }
378
- finally {
458
+ } finally {
379
459
  uiDb.dispose();
380
460
  }
381
461
  }
@@ -0,0 +1,45 @@
1
+ import type { PluginHookBeforeMessageWriteEvent, PluginHookBeforeMessageWriteResult } from '../openclaw-sdk.js';
2
+
3
+ const INTERNAL_TAG_PATTERNS = [
4
+ /\[EMOTIONAL_DAMAGE_DETECTED(?::(?:mild|moderate|severe))?\]/gi,
5
+ /\[EMPATHY_ROLLBACK_REQUEST\]/gi,
6
+ /<empathy\s+[^>]*\/?>(?:<\/empathy>)?/gi,
7
+ ];
8
+
9
+ export function sanitizeAssistantText(text: string): string {
10
+ let result = text;
11
+ for (const pattern of INTERNAL_TAG_PATTERNS) {
12
+ result = result.replace(pattern, '');
13
+ }
14
+ return result
15
+ .replace(/[ \t]+\n/g, '\n')
16
+ .replace(/\n{3,}/g, '\n\n')
17
+ .trim();
18
+ }
19
+
20
+ export function handleBeforeMessageWrite(
21
+ event: PluginHookBeforeMessageWriteEvent,
22
+ ): PluginHookBeforeMessageWriteResult | void {
23
+ const msg = event.message as { role?: string; content?: unknown } | undefined;
24
+ if (!msg || msg.role !== 'assistant') return;
25
+
26
+ if (typeof msg.content === 'string') {
27
+ const sanitized = sanitizeAssistantText(msg.content);
28
+ if (sanitized !== msg.content) {
29
+ return { message: { ...msg, content: sanitized } as any };
30
+ }
31
+ return;
32
+ }
33
+
34
+ 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) };
38
+ }
39
+ return part;
40
+ });
41
+ return { message: { ...msg, content: next } as any };
42
+ }
43
+
44
+ return;
45
+ }