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,64 +1,81 @@
1
1
  import * as fs from 'fs';
2
2
  import { isRisky } from '../utils/io.js';
3
- export function estimateLineChanges(modification) {
3
+
4
+ export type RiskLevel = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
5
+
6
+ export interface FileModification {
7
+ toolName: string;
8
+ params: any;
9
+ }
10
+
11
+ export function estimateLineChanges(modification: FileModification): number {
4
12
  const { toolName, params } = modification;
13
+
5
14
  if (toolName === 'write_file' || toolName === 'write') {
6
15
  const content = params.content || '';
7
16
  return content.split('\n').length;
8
17
  }
18
+
9
19
  if (toolName === 'replace' || toolName === 'edit') {
10
20
  const newContent = params.new_string || params.newText || '';
11
21
  return newContent.split('\n').length;
12
22
  }
23
+
13
24
  if (toolName === 'apply_patch' || toolName === 'patch') {
14
25
  const patch = params.patch || '';
15
26
  // Rough estimate for patch files
16
- return patch.split('\n').filter((l) => l.startsWith('+') || l.startsWith('-')).length;
27
+ return patch.split('\n').filter((l: string) => l.startsWith('+') || l.startsWith('-')).length;
17
28
  }
29
+
18
30
  if (toolName === 'delete_file') {
19
31
  // Deleting a file is considered a significant change, but we don't know the size.
20
32
  // We'll treat it as a medium-to-large size change.
21
33
  return 50;
22
34
  }
35
+
23
36
  return 0;
24
37
  }
25
- export function assessRiskLevel(filePath, modification, riskPaths) {
38
+
39
+ export function assessRiskLevel(
40
+ filePath: string,
41
+ modification: FileModification,
42
+ riskPaths: string[]
43
+ ): RiskLevel {
26
44
  const isRiskPath = isRisky(filePath, riskPaths);
27
45
  const estimatedLines = estimateLineChanges(modification);
46
+
28
47
  if (isRiskPath) {
29
- if (estimatedLines > 100)
30
- return 'CRITICAL';
48
+ if (estimatedLines > 100) return 'CRITICAL';
31
49
  return 'HIGH';
32
- }
33
- else {
34
- if (estimatedLines > 100)
35
- return 'HIGH';
36
- if (estimatedLines > 10)
37
- return 'MEDIUM';
50
+ } else {
51
+ if (estimatedLines > 100) return 'HIGH';
52
+ if (estimatedLines > 10) return 'MEDIUM';
38
53
  return 'LOW';
39
54
  }
40
55
  }
56
+
41
57
  /**
42
58
  * Get the total line count of a target file.
43
59
  * @param absoluteFilePath - Absolute path to the file
44
60
  * @returns File line count, or null if file doesn't exist or can't be read
45
61
  */
46
- export function getTargetFileLineCount(absoluteFilePath) {
62
+ export function getTargetFileLineCount(absoluteFilePath: string): number | null {
47
63
  try {
48
64
  if (!fs.existsSync(absoluteFilePath)) {
49
65
  return null; // File genuinely doesn't exist
50
66
  }
67
+
51
68
  const stats = fs.statSync(absoluteFilePath);
52
69
  if (!stats.isFile()) {
53
70
  return null; // Not a regular file (directory, device, etc.)
54
71
  }
72
+
55
73
  const content = fs.readFileSync(absoluteFilePath, 'utf-8');
56
74
  return content.split('\n').length;
57
- }
58
- catch (e) {
75
+ } catch (e) {
59
76
  // Log error before falling back to null - this is intentional for security gates
60
77
  const error = e instanceof Error ? e : new Error(String(e));
61
- const errorCode = e.code;
78
+ const errorCode = (e as NodeJS.ErrnoException).code;
62
79
  console.error(`[PD:RISK_CALC] Failed to read file for line count: ${absoluteFilePath}`, {
63
80
  code: errorCode,
64
81
  message: error.message,
@@ -66,6 +83,7 @@ export function getTargetFileLineCount(absoluteFilePath) {
66
83
  return null;
67
84
  }
68
85
  }
86
+
69
87
  /**
70
88
  * Calculate the effective line limit based on percentage of target file.
71
89
  * @param targetLineCount - Total lines in target file
@@ -74,14 +92,22 @@ export function getTargetFileLineCount(absoluteFilePath) {
74
92
  * @param maxLines - Optional upper bound to prevent misconfiguration
75
93
  * @returns Maximum allowed lines (at least minLines, at most maxLines if provided)
76
94
  */
77
- export function calculatePercentageThreshold(targetLineCount, percentage, minLines, maxLines) {
95
+ export function calculatePercentageThreshold(
96
+ targetLineCount: number,
97
+ percentage: number,
98
+ minLines: number,
99
+ maxLines?: number
100
+ ): number {
78
101
  // Clamp percentage to valid range [0, 100]
79
102
  const clampedPercentage = Math.max(0, Math.min(100, percentage));
103
+
80
104
  const calculated = Math.round(targetLineCount * (clampedPercentage / 100));
81
105
  let effectiveLimit = Math.max(calculated, minLines);
106
+
82
107
  // Apply optional upper bound
83
108
  if (maxLines !== undefined && maxLines > 0) {
84
109
  effectiveLimit = Math.min(effectiveLimit, maxLines);
85
110
  }
111
+
86
112
  return effectiveLimit;
87
113
  }
@@ -1,94 +1,153 @@
1
+ import { PluginHookLlmOutputEvent } from '../openclaw-sdk.js';
1
2
  import * as path from 'path';
2
3
  import * as fs from 'fs';
4
+ import { PainConfig } from './config.js';
3
5
  import { SystemLogger } from './system-logger.js';
4
- const sessions = new Map();
6
+ import { EventLogService } from './event-log.js';
7
+
8
+ export interface TokenUsage {
9
+ input?: number;
10
+ output?: number;
11
+ cacheRead?: number;
12
+ cacheWrite?: number;
13
+ total?: number;
14
+ }
15
+
16
+ export interface SessionState {
17
+ sessionId: string;
18
+ sessionKey?: string; // Structured session key from OpenClaw (e.g., agent:main:cron:job-1:run:xxx)
19
+ trigger?: string; // Trigger source: "user" | "cron" | "heartbeat" | "memory" | "subagent"
20
+ workspaceDir?: string;
21
+ toolReadsByFile: Record<string, number>;
22
+ llmTurns: number;
23
+ blockedAttempts: number;
24
+ lastActivityAt: number;
25
+ lastControlActivityAt: number;
26
+ totalInputTokens: number;
27
+ totalOutputTokens: number;
28
+ cacheHits: number;
29
+ // Track consecutive loops of similar lengths/ratios (paralysis)
30
+ stuckLoops: number;
31
+
32
+ // GFI - Track A: Empirical Friction
33
+ currentGfi: number;
34
+ gfiBySource?: Record<string, number>;
35
+ lastErrorSource?: string;
36
+ lastErrorHash: string;
37
+ consecutiveErrors: number;
38
+
39
+ // Daily statistics (persisted)
40
+ dailyToolCalls: number;
41
+ dailyToolFailures: number;
42
+ dailyPainSignals: number;
43
+ dailyGfiPeak: number;
44
+
45
+ // Thinking OS checkpoint - tracks last deep thinking timestamp
46
+ lastThinkingTimestamp: number;
47
+
48
+ // Evolution loop feedback attribution
49
+ injectedProbationIds?: string[];
50
+ }
51
+
52
+
53
+ const sessions = new Map<string, SessionState>();
54
+
5
55
  /** Directory for persisting session state */
6
- let persistDir = null;
56
+ let persistDir: string | null = null;
57
+
7
58
  /** Debounce timers for persistence, one per session */
8
- const persistTimers = new Map();
9
- function logSessionTrackerWarning(message, error) {
59
+ const persistTimers = new Map<string, ReturnType<typeof setTimeout>>();
60
+
61
+ function logSessionTrackerWarning(message: string, error?: unknown): void {
10
62
  const detail = error instanceof Error ? error.message : error ? String(error) : '';
11
63
  const suffix = detail ? `: ${detail}` : '';
64
+ // eslint-disable-next-line no-console
12
65
  console.warn(`[PD:SessionTracker] ${message}${suffix}`);
13
66
  }
14
- function touchActivity(state, kind = 'general') {
67
+
68
+ function touchActivity(state: SessionState, kind: 'general' | 'control' = 'general'): void {
15
69
  const now = Date.now();
16
70
  state.lastActivityAt = now;
17
71
  if (kind === 'control') {
18
72
  state.lastControlActivityAt = now;
19
73
  }
20
74
  }
75
+
21
76
  /**
22
77
  * Initialize persistence for session state.
23
78
  * Call this once during plugin startup.
24
79
  */
25
- export function initPersistence(stateDir) {
80
+ export function initPersistence(stateDir: string): void {
26
81
  persistDir = path.join(stateDir, 'sessions');
27
82
  if (!fs.existsSync(persistDir)) {
28
83
  fs.mkdirSync(persistDir, { recursive: true });
29
84
  }
85
+
30
86
  // Load all existing sessions
31
87
  loadAllSessions();
32
88
  }
89
+
33
90
  /**
34
91
  * Get the file path for a session's persisted state.
35
92
  */
36
- function getSessionPath(sessionId) {
37
- if (!persistDir)
38
- return '';
93
+ function getSessionPath(sessionId: string): string {
94
+ if (!persistDir) return '';
39
95
  // Sanitize sessionId for filesystem
40
96
  const safeId = sessionId.replace(/[/\\:]/g, '_');
41
97
  return path.join(persistDir, `${safeId}.json`);
42
98
  }
99
+
43
100
  /**
44
101
  * Load all persisted sessions from disk.
45
102
  */
46
- function loadAllSessions() {
47
- if (!persistDir || !fs.existsSync(persistDir))
48
- return;
103
+ function loadAllSessions(): void {
104
+ if (!persistDir || !fs.existsSync(persistDir)) return;
105
+
49
106
  try {
50
107
  const files = fs.readdirSync(persistDir).filter(f => f.endsWith('.json'));
51
108
  const now = Date.now();
52
109
  const twoHoursAgo = now - 2 * 60 * 60 * 1000;
110
+
53
111
  for (const file of files) {
54
112
  try {
55
113
  const content = fs.readFileSync(path.join(persistDir, file), 'utf-8');
56
- const state = JSON.parse(content);
114
+ const state = JSON.parse(content) as SessionState;
115
+
57
116
  // Skip abandoned sessions
58
117
  if (state.lastActivityAt < twoHoursAgo) {
59
118
  continue;
60
119
  }
120
+
61
121
  sessions.set(state.sessionId, state);
62
- }
63
- catch (error) {
122
+ } catch (error) {
64
123
  logSessionTrackerWarning(`Failed to load session snapshot ${file}`, error);
65
124
  }
66
125
  }
67
- }
68
- catch (err) {
126
+ } catch (err) {
69
127
  logSessionTrackerWarning('Failed to load persisted sessions', err);
70
128
  }
71
129
  }
130
+
72
131
  /**
73
132
  * Persist a single session to disk.
74
133
  */
75
- function persistSession(state) {
76
- if (!persistDir)
77
- return;
134
+ function persistSession(state: SessionState): void {
135
+ if (!persistDir) return;
136
+
78
137
  const sessionPath = getSessionPath(state.sessionId);
79
- if (!sessionPath)
80
- return;
138
+ if (!sessionPath) return;
139
+
81
140
  try {
82
141
  fs.writeFileSync(sessionPath, JSON.stringify(state, null, 2), 'utf-8');
83
- }
84
- catch (error) {
142
+ } catch (error) {
85
143
  logSessionTrackerWarning(`Failed to persist session ${state.sessionId}`, error);
86
144
  }
87
145
  }
146
+
88
147
  /**
89
148
  * Schedule persistence with debounce.
90
149
  */
91
- function schedulePersistence(state) {
150
+ function schedulePersistence(state: SessionState): void {
92
151
  const existing = persistTimers.get(state.sessionId);
93
152
  if (existing) {
94
153
  clearTimeout(existing);
@@ -96,13 +155,14 @@ function schedulePersistence(state) {
96
155
  const timer = setTimeout(() => {
97
156
  persistSession(state);
98
157
  persistTimers.delete(state.sessionId);
99
- }, 1000); // 1 second debounce
158
+ }, 1000); // 1 second debounce
100
159
  persistTimers.set(state.sessionId, timer);
101
160
  }
161
+
102
162
  /**
103
163
  * Force persist all sessions immediately.
104
164
  */
105
- export function flushAllSessions() {
165
+ export function flushAllSessions(): void {
106
166
  for (const timer of persistTimers.values()) {
107
167
  clearTimeout(timer);
108
168
  }
@@ -111,7 +171,8 @@ export function flushAllSessions() {
111
171
  persistSession(state);
112
172
  }
113
173
  }
114
- function getOrCreateSession(sessionId, workspaceDir, sessionKey, trigger) {
174
+
175
+ function getOrCreateSession(sessionId: string, workspaceDir?: string, sessionKey?: string, trigger?: string): SessionState {
115
176
  let state = sessions.get(sessionId);
116
177
  if (!state) {
117
178
  state = {
@@ -142,6 +203,7 @@ function getOrCreateSession(sessionId, workspaceDir, sessionKey, trigger) {
142
203
  };
143
204
  sessions.set(sessionId, state);
144
205
  }
206
+
145
207
  if (workspaceDir && !state.workspaceDir) {
146
208
  state.workspaceDir = workspaceDir;
147
209
  }
@@ -154,31 +216,37 @@ function getOrCreateSession(sessionId, workspaceDir, sessionKey, trigger) {
154
216
  }
155
217
  return state;
156
218
  }
157
- function ensureGfiLedger(state) {
219
+
220
+ function ensureGfiLedger(state: SessionState): Record<string, number> {
158
221
  if (!state.gfiBySource || typeof state.gfiBySource !== 'object') {
159
222
  state.gfiBySource = {};
160
223
  }
161
224
  return state.gfiBySource;
162
225
  }
163
- export function trackToolRead(sessionId, filePath, workspaceDir) {
226
+
227
+ export function trackToolRead(sessionId: string, filePath: string, workspaceDir?: string): SessionState {
164
228
  const state = getOrCreateSession(sessionId, workspaceDir);
165
229
  const normalizedPath = path.posix.normalize(filePath.replace(/\\/g, '/'));
166
230
  state.toolReadsByFile[normalizedPath] = (state.toolReadsByFile[normalizedPath] || 0) + 1;
167
231
  touchActivity(state);
168
232
  return state;
169
233
  }
170
- export function trackLlmOutput(sessionId, usage, config, workspaceDir, sessionKey, trigger) {
234
+
235
+ export function trackLlmOutput(sessionId: string, usage: TokenUsage | undefined, config?: PainConfig, workspaceDir?: string, sessionKey?: string, trigger?: string): SessionState {
171
236
  const state = getOrCreateSession(sessionId, workspaceDir, sessionKey, trigger);
172
237
  state.llmTurns += 1;
173
238
  touchActivity(state);
239
+
174
240
  if (usage) {
175
241
  state.totalInputTokens += usage.input || 0;
176
242
  state.totalOutputTokens += usage.output || 0;
177
243
  state.cacheHits += usage.cacheRead || 0;
244
+
178
245
  // Use thresholds from config or defaults
179
246
  const minTurns = 5; // Increased from 3 to 5 to prevent false positives on short tasks
180
247
  const outputThreshold = 30; // Decreased from 50. Only penalize truly stunted outputs.
181
248
  const inputThreshold = config ? config.get('thresholds.cognitive_paralysis_input') : 8000; // Increased base to 8k
249
+
182
250
  // Very rough heuristic for empty/paralysis loops: high input context, tiny output, multiple turns
183
251
  if (state.llmTurns > minTurns) {
184
252
  const isTinyOutput = (usage.output || 0) < outputThreshold;
@@ -186,8 +254,7 @@ export function trackLlmOutput(sessionId, usage, config, workspaceDir, sessionKe
186
254
  if (isTinyOutput && isLargeInput) {
187
255
  state.stuckLoops += 1;
188
256
  SystemLogger.log(state.workspaceDir, 'EFFICIENCY_ALARM', `Stuck loop detected (Turn ${state.llmTurns}). Input: ${usage.input}, Output: ${usage.output}. Consecutive: ${state.stuckLoops}`);
189
- }
190
- else {
257
+ } else {
191
258
  // Reset if we broke out of the tiny output loop
192
259
  if (state.stuckLoops > 0) {
193
260
  SystemLogger.log(state.workspaceDir, 'EFFICIENCY_OK', `Broke out of stuck loop after ${state.stuckLoops} turns.`);
@@ -196,22 +263,31 @@ export function trackLlmOutput(sessionId, usage, config, workspaceDir, sessionKe
196
263
  }
197
264
  }
198
265
  }
266
+
199
267
  return state;
200
268
  }
269
+
201
270
  /**
202
271
  * Tracks physical friction based on tool execution failures.
203
272
  */
204
- export function trackFriction(sessionId, deltaF, hash, workspaceDir, options) {
273
+ export function trackFriction(
274
+ sessionId: string,
275
+ deltaF: number,
276
+ hash: string,
277
+ workspaceDir?: string,
278
+ options?: { source?: string }
279
+ ): SessionState {
205
280
  const state = getOrCreateSession(sessionId, workspaceDir);
206
281
  const ledger = ensureGfiLedger(state);
282
+
207
283
  if (hash && hash === state.lastErrorHash) {
208
284
  state.consecutiveErrors++;
209
- }
210
- else {
285
+ } else {
211
286
  state.lastErrorSource = options?.source || (hash ? `unattributed:${hash}` : 'unattributed:unknown');
212
287
  state.lastErrorHash = hash;
213
288
  state.consecutiveErrors = 1;
214
289
  }
290
+
215
291
  // GFI formula with multiplier: GFI = GFI + (Delta_F * 1.5^(n-1))
216
292
  const multiplier = Math.pow(1.5, state.consecutiveErrors - 1);
217
293
  const addedFriction = deltaF * multiplier;
@@ -219,32 +295,48 @@ export function trackFriction(sessionId, deltaF, hash, workspaceDir, options) {
219
295
  const sourceKey = options?.source || (hash ? `unattributed:${hash}` : 'unattributed:unknown');
220
296
  ledger[sourceKey] = (ledger[sourceKey] || 0) + addedFriction;
221
297
  touchActivity(state, 'control');
298
+
222
299
  SystemLogger.log(state.workspaceDir, 'GFI_INC', `Friction added: +${addedFriction.toFixed(1)} (Base: ${deltaF}, Mult: ${multiplier.toFixed(2)}). Total GFI: ${state.currentGfi.toFixed(1)}`);
300
+
223
301
  // Update daily stats
224
302
  state.dailyToolFailures++;
225
303
  state.dailyGfiPeak = Math.max(state.dailyGfiPeak, state.currentGfi);
304
+
226
305
  // Schedule persistence
227
306
  schedulePersistence(state);
307
+
228
308
  return state;
229
309
  }
310
+
230
311
  /**
231
312
  * Resets the friction index upon successful action.
232
313
  */
233
- export function resetFriction(sessionId, workspaceDir, options) {
314
+ export function resetFriction(
315
+ sessionId: string,
316
+ workspaceDir?: string,
317
+ options?: { source?: string; amount?: number }
318
+ ): SessionState {
234
319
  const state = getOrCreateSession(sessionId, workspaceDir);
235
320
  const ledger = ensureGfiLedger(state);
321
+
236
322
  if (options?.source) {
237
323
  const sourceKey = options.source;
238
324
  const currentSource = ledger[sourceKey] || 0;
239
325
  const requestedAmount = Number.isFinite(options.amount) ? Number(options.amount) : currentSource;
240
326
  const amountToRemove = Math.max(0, Math.min(currentSource, requestedAmount));
327
+
241
328
  if (amountToRemove > 0) {
242
329
  ledger[sourceKey] = Math.max(0, currentSource - amountToRemove);
243
330
  if (ledger[sourceKey] === 0) {
244
331
  delete ledger[sourceKey];
245
332
  }
246
333
  state.currentGfi = Math.max(0, (state.currentGfi || 0) - amountToRemove);
247
- SystemLogger.log(state.workspaceDir, 'GFI_SLICE_RESET', `Friction slice reset for ${sourceKey}: -${amountToRemove.toFixed(1)}. Total GFI: ${state.currentGfi.toFixed(1)}`);
334
+ SystemLogger.log(
335
+ state.workspaceDir,
336
+ 'GFI_SLICE_RESET',
337
+ `Friction slice reset for ${sourceKey}: -${amountToRemove.toFixed(1)}. Total GFI: ${state.currentGfi.toFixed(1)}`
338
+ );
339
+
248
340
  if (state.lastErrorSource === sourceKey) {
249
341
  state.consecutiveErrors = 0;
250
342
  state.lastErrorHash = '';
@@ -255,6 +347,7 @@ export function resetFriction(sessionId, workspaceDir, options) {
255
347
  schedulePersistence(state);
256
348
  return state;
257
349
  }
350
+
258
351
  if (state.currentGfi > 0) {
259
352
  SystemLogger.log(state.workspaceDir, 'GFI_RESET', `Friction reset to 0 (Was: ${state.currentGfi.toFixed(1)}). Action successful.`);
260
353
  }
@@ -264,15 +357,18 @@ export function resetFriction(sessionId, workspaceDir, options) {
264
357
  state.consecutiveErrors = 0;
265
358
  state.lastErrorHash = '';
266
359
  touchActivity(state, 'control');
360
+
267
361
  // Schedule persistence
268
362
  schedulePersistence(state);
363
+
269
364
  return state;
270
365
  }
366
+
271
367
  /**
272
368
  * Records that deep thinking (Thinking OS) was performed in this session.
273
369
  * Used by the Thinking OS checkpoint to allow high-risk operations.
274
370
  */
275
- export function recordThinkingCheckpoint(sessionId, workspaceDir) {
371
+ export function recordThinkingCheckpoint(sessionId: string, workspaceDir?: string): SessionState {
276
372
  const state = getOrCreateSession(sessionId, workspaceDir);
277
373
  state.lastThinkingTimestamp = Date.now();
278
374
  touchActivity(state, 'control');
@@ -280,53 +376,61 @@ export function recordThinkingCheckpoint(sessionId, workspaceDir) {
280
376
  schedulePersistence(state);
281
377
  return state;
282
378
  }
379
+
283
380
  /**
284
381
  * Checks if deep thinking was performed recently (within the given window).
285
382
  * @param sessionId - The session to check
286
383
  * @param windowMs - How recent the thinking must be (default: 5 minutes)
287
384
  * @returns true if thinking was recorded within the window
288
385
  */
289
- export function hasRecentThinking(sessionId, windowMs = 5 * 60 * 1000) {
386
+ export function hasRecentThinking(sessionId: string, windowMs: number = 5 * 60 * 1000): boolean {
290
387
  const state = sessions.get(sessionId);
291
- if (!state || !state.lastThinkingTimestamp)
292
- return false;
388
+ if (!state || !state.lastThinkingTimestamp) return false;
293
389
  return (Date.now() - state.lastThinkingTimestamp) < windowMs;
294
390
  }
295
- export function trackBlock(sessionId) {
391
+
392
+ export function trackBlock(sessionId: string): SessionState {
296
393
  const state = getOrCreateSession(sessionId);
297
394
  state.blockedAttempts += 1;
298
395
  touchActivity(state, 'control');
299
396
  schedulePersistence(state);
300
397
  return state;
301
398
  }
302
- export function setInjectedProbationIds(sessionId, ids, workspaceDir) {
399
+
400
+
401
+ export function setInjectedProbationIds(sessionId: string, ids: string[], workspaceDir?: string): SessionState {
303
402
  const state = getOrCreateSession(sessionId, workspaceDir);
304
403
  state.injectedProbationIds = [...ids];
305
404
  touchActivity(state, 'control');
306
405
  schedulePersistence(state);
307
406
  return state;
308
407
  }
309
- export function getInjectedProbationIds(sessionId, workspaceDir) {
408
+
409
+ export function getInjectedProbationIds(sessionId: string, workspaceDir?: string): string[] {
310
410
  const state = getOrCreateSession(sessionId, workspaceDir);
311
411
  return [...(state.injectedProbationIds || [])];
312
412
  }
313
- export function clearInjectedProbationIds(sessionId, workspaceDir) {
413
+
414
+ export function clearInjectedProbationIds(sessionId: string, workspaceDir?: string): SessionState {
314
415
  return setInjectedProbationIds(sessionId, [], workspaceDir);
315
416
  }
316
- export function getSession(sessionId) {
417
+
418
+ export function getSession(sessionId: string): SessionState | undefined {
317
419
  return sessions.get(sessionId);
318
420
  }
319
- export function listSessions(workspaceDir) {
421
+
422
+ export function listSessions(workspaceDir?: string): SessionState[] {
320
423
  return [...sessions.values()]
321
424
  .filter((state) => !workspaceDir || !state.workspaceDir || state.workspaceDir === workspaceDir)
322
425
  .map((state) => ({
323
- ...state,
324
- toolReadsByFile: { ...state.toolReadsByFile },
325
- gfiBySource: state.gfiBySource ? { ...state.gfiBySource } : undefined,
326
- injectedProbationIds: state.injectedProbationIds ? [...state.injectedProbationIds] : undefined,
327
- }));
426
+ ...state,
427
+ toolReadsByFile: { ...state.toolReadsByFile },
428
+ gfiBySource: state.gfiBySource ? { ...state.gfiBySource } : undefined,
429
+ injectedProbationIds: state.injectedProbationIds ? [...state.injectedProbationIds] : undefined,
430
+ }));
328
431
  }
329
- export function clearSession(sessionId) {
432
+
433
+ export function clearSession(sessionId: string): void {
330
434
  const timer = persistTimers.get(sessionId);
331
435
  if (timer) {
332
436
  clearTimeout(timer);
@@ -334,6 +438,7 @@ export function clearSession(sessionId) {
334
438
  }
335
439
  sessions.delete(sessionId);
336
440
  }
441
+
337
442
  /**
338
443
  * Seed a session directly into SessionTracker.sessions for testing.
339
444
  * This bypasses the normal tool-call flow to set up test data for
@@ -343,13 +448,14 @@ export function clearSession(sessionId) {
343
448
  * @param workspaceDir - Workspace directory (optional, for filtering)
344
449
  * @param lastActivityAt - Unix timestamp in ms (default: now)
345
450
  */
346
- export function seedSessionForTest(sessionId, workspaceDir, lastActivityAt) {
451
+ export function seedSessionForTest(sessionId: string, workspaceDir?: string, lastActivityAt?: number): void {
347
452
  const state = getOrCreateSession(sessionId, workspaceDir);
348
453
  state.lastActivityAt = lastActivityAt ?? Date.now();
349
454
  state.lastControlActivityAt = state.lastActivityAt;
350
455
  }
456
+
351
457
  // Memory cleanup for abandoned sessions (older than 2 hours)
352
- export function garbageCollectSessions() {
458
+ export function garbageCollectSessions(): void {
353
459
  const twoHoursAgo = Date.now() - 2 * 60 * 60 * 1000;
354
460
  for (const [id, state] of sessions.entries()) {
355
461
  if (state.lastActivityAt < twoHoursAgo) {
@@ -359,14 +465,14 @@ export function garbageCollectSessions() {
359
465
  persistTimers.delete(id);
360
466
  }
361
467
  sessions.delete(id);
468
+
362
469
  // Also delete persisted file
363
470
  if (persistDir) {
364
471
  const sessionPath = getSessionPath(id);
365
472
  if (sessionPath && fs.existsSync(sessionPath)) {
366
473
  try {
367
474
  fs.unlinkSync(sessionPath);
368
- }
369
- catch (error) {
475
+ } catch (error) {
370
476
  logSessionTrackerWarning(`Failed to delete session snapshot for ${id}`, error);
371
477
  }
372
478
  }
@@ -374,13 +480,19 @@ export function garbageCollectSessions() {
374
480
  }
375
481
  }
376
482
  }
483
+
377
484
  /**
378
485
  * Get daily statistics summary for a session.
379
486
  */
380
- export function getDailySummary(sessionId) {
487
+ export function getDailySummary(sessionId: string): {
488
+ toolCalls: number;
489
+ toolFailures: number;
490
+ painSignals: number;
491
+ gfiPeak: number;
492
+ } | null {
381
493
  const state = sessions.get(sessionId);
382
- if (!state)
383
- return null;
494
+ if (!state) return null;
495
+
384
496
  return {
385
497
  toolCalls: state.dailyToolCalls,
386
498
  toolFailures: state.dailyToolFailures,
@@ -388,10 +500,11 @@ export function getDailySummary(sessionId) {
388
500
  gfiPeak: state.dailyGfiPeak,
389
501
  };
390
502
  }
503
+
391
504
  /**
392
505
  * Reset daily statistics (call at midnight or on new day).
393
506
  */
394
- export function resetDailyStats(sessionId) {
507
+ export function resetDailyStats(sessionId: string): void {
395
508
  const state = sessions.get(sessionId);
396
509
  if (state) {
397
510
  state.dailyToolCalls = 0;