principles-disciple 1.8.0 → 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 (460) 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 +6 -1
  10. package/package.json +13 -15
  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} +185 -63
  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} +166 -139
  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} +263 -36
  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/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +603 -0
  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/src/service/subagent-workflow/types.ts +378 -0
  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 -127
  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 -99
  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 -12
  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 -51
  403. package/dist/hooks/progressive-trust-gate.js +0 -89
  404. package/dist/hooks/prompt.d.ts +0 -47
  405. package/dist/hooks/prompt.js +0 -884
  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 -567
  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 -52
  423. package/dist/service/empathy-observer-manager.js +0 -229
  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 -974
  428. package/dist/service/nocturnal-runtime.d.ts +0 -183
  429. package/dist/service/nocturnal-service.d.ts +0 -163
  430. package/dist/service/nocturnal-service.js +0 -787
  431. package/dist/service/nocturnal-target-selector.d.ts +0 -145
  432. package/dist/service/nocturnal-target-selector.js +0 -315
  433. package/dist/service/phase3-input-filter.d.ts +0 -73
  434. package/dist/service/phase3-input-filter.js +0 -172
  435. package/dist/service/runtime-summary-service.d.ts +0 -122
  436. package/dist/service/runtime-summary-service.js +0 -485
  437. package/dist/service/trajectory-service.d.ts +0 -2
  438. package/dist/service/trajectory-service.js +0 -15
  439. package/dist/tools/critique-prompt.d.ts +0 -14
  440. package/dist/tools/deep-reflect.d.ts +0 -39
  441. package/dist/tools/deep-reflect.js +0 -350
  442. package/dist/tools/model-index.d.ts +0 -9
  443. package/dist/types/event-types.d.ts +0 -306
  444. package/dist/types/event-types.js +0 -106
  445. package/dist/types/hygiene-types.d.ts +0 -20
  446. package/dist/types/hygiene-types.js +0 -12
  447. package/dist/types/runtime-summary.d.ts +0 -47
  448. package/dist/types/runtime-summary.js +0 -1
  449. package/dist/types.d.ts +0 -50
  450. package/dist/types.js +0 -22
  451. package/dist/utils/file-lock.d.ts +0 -71
  452. package/dist/utils/file-lock.js +0 -309
  453. package/dist/utils/glob-match.d.ts +0 -28
  454. package/dist/utils/hashing.d.ts +0 -9
  455. package/dist/utils/io.d.ts +0 -6
  456. package/dist/utils/io.js +0 -106
  457. package/dist/utils/nlp.d.ts +0 -9
  458. package/dist/utils/plugin-logger.d.ts +0 -39
  459. package/dist/utils/subagent-probe.d.ts +0 -34
  460. 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,11 +171,14 @@ export function flushAllSessions() {
111
171
  persistSession(state);
112
172
  }
113
173
  }
114
- function getOrCreateSession(sessionId, workspaceDir) {
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 = {
118
179
  sessionId,
180
+ sessionKey,
181
+ trigger,
119
182
  workspaceDir,
120
183
  toolReadsByFile: {},
121
184
  llmTurns: 0,
@@ -140,36 +203,50 @@ function getOrCreateSession(sessionId, workspaceDir) {
140
203
  };
141
204
  sessions.set(sessionId, state);
142
205
  }
206
+
143
207
  if (workspaceDir && !state.workspaceDir) {
144
208
  state.workspaceDir = workspaceDir;
145
209
  }
210
+ // Update sessionKey and trigger if provided (they may be more recent)
211
+ if (sessionKey && !state.sessionKey) {
212
+ state.sessionKey = sessionKey;
213
+ }
214
+ if (trigger && !state.trigger) {
215
+ state.trigger = trigger;
216
+ }
146
217
  return state;
147
218
  }
148
- function ensureGfiLedger(state) {
219
+
220
+ function ensureGfiLedger(state: SessionState): Record<string, number> {
149
221
  if (!state.gfiBySource || typeof state.gfiBySource !== 'object') {
150
222
  state.gfiBySource = {};
151
223
  }
152
224
  return state.gfiBySource;
153
225
  }
154
- export function trackToolRead(sessionId, filePath, workspaceDir) {
226
+
227
+ export function trackToolRead(sessionId: string, filePath: string, workspaceDir?: string): SessionState {
155
228
  const state = getOrCreateSession(sessionId, workspaceDir);
156
229
  const normalizedPath = path.posix.normalize(filePath.replace(/\\/g, '/'));
157
230
  state.toolReadsByFile[normalizedPath] = (state.toolReadsByFile[normalizedPath] || 0) + 1;
158
231
  touchActivity(state);
159
232
  return state;
160
233
  }
161
- export function trackLlmOutput(sessionId, usage, config, workspaceDir) {
162
- const state = getOrCreateSession(sessionId, workspaceDir);
234
+
235
+ export function trackLlmOutput(sessionId: string, usage: TokenUsage | undefined, config?: PainConfig, workspaceDir?: string, sessionKey?: string, trigger?: string): SessionState {
236
+ const state = getOrCreateSession(sessionId, workspaceDir, sessionKey, trigger);
163
237
  state.llmTurns += 1;
164
238
  touchActivity(state);
239
+
165
240
  if (usage) {
166
241
  state.totalInputTokens += usage.input || 0;
167
242
  state.totalOutputTokens += usage.output || 0;
168
243
  state.cacheHits += usage.cacheRead || 0;
244
+
169
245
  // Use thresholds from config or defaults
170
246
  const minTurns = 5; // Increased from 3 to 5 to prevent false positives on short tasks
171
247
  const outputThreshold = 30; // Decreased from 50. Only penalize truly stunted outputs.
172
248
  const inputThreshold = config ? config.get('thresholds.cognitive_paralysis_input') : 8000; // Increased base to 8k
249
+
173
250
  // Very rough heuristic for empty/paralysis loops: high input context, tiny output, multiple turns
174
251
  if (state.llmTurns > minTurns) {
175
252
  const isTinyOutput = (usage.output || 0) < outputThreshold;
@@ -177,8 +254,7 @@ export function trackLlmOutput(sessionId, usage, config, workspaceDir) {
177
254
  if (isTinyOutput && isLargeInput) {
178
255
  state.stuckLoops += 1;
179
256
  SystemLogger.log(state.workspaceDir, 'EFFICIENCY_ALARM', `Stuck loop detected (Turn ${state.llmTurns}). Input: ${usage.input}, Output: ${usage.output}. Consecutive: ${state.stuckLoops}`);
180
- }
181
- else {
257
+ } else {
182
258
  // Reset if we broke out of the tiny output loop
183
259
  if (state.stuckLoops > 0) {
184
260
  SystemLogger.log(state.workspaceDir, 'EFFICIENCY_OK', `Broke out of stuck loop after ${state.stuckLoops} turns.`);
@@ -187,22 +263,31 @@ export function trackLlmOutput(sessionId, usage, config, workspaceDir) {
187
263
  }
188
264
  }
189
265
  }
266
+
190
267
  return state;
191
268
  }
269
+
192
270
  /**
193
271
  * Tracks physical friction based on tool execution failures.
194
272
  */
195
- 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 {
196
280
  const state = getOrCreateSession(sessionId, workspaceDir);
197
281
  const ledger = ensureGfiLedger(state);
282
+
198
283
  if (hash && hash === state.lastErrorHash) {
199
284
  state.consecutiveErrors++;
200
- }
201
- else {
285
+ } else {
202
286
  state.lastErrorSource = options?.source || (hash ? `unattributed:${hash}` : 'unattributed:unknown');
203
287
  state.lastErrorHash = hash;
204
288
  state.consecutiveErrors = 1;
205
289
  }
290
+
206
291
  // GFI formula with multiplier: GFI = GFI + (Delta_F * 1.5^(n-1))
207
292
  const multiplier = Math.pow(1.5, state.consecutiveErrors - 1);
208
293
  const addedFriction = deltaF * multiplier;
@@ -210,32 +295,48 @@ export function trackFriction(sessionId, deltaF, hash, workspaceDir, options) {
210
295
  const sourceKey = options?.source || (hash ? `unattributed:${hash}` : 'unattributed:unknown');
211
296
  ledger[sourceKey] = (ledger[sourceKey] || 0) + addedFriction;
212
297
  touchActivity(state, 'control');
298
+
213
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
+
214
301
  // Update daily stats
215
302
  state.dailyToolFailures++;
216
303
  state.dailyGfiPeak = Math.max(state.dailyGfiPeak, state.currentGfi);
304
+
217
305
  // Schedule persistence
218
306
  schedulePersistence(state);
307
+
219
308
  return state;
220
309
  }
310
+
221
311
  /**
222
312
  * Resets the friction index upon successful action.
223
313
  */
224
- export function resetFriction(sessionId, workspaceDir, options) {
314
+ export function resetFriction(
315
+ sessionId: string,
316
+ workspaceDir?: string,
317
+ options?: { source?: string; amount?: number }
318
+ ): SessionState {
225
319
  const state = getOrCreateSession(sessionId, workspaceDir);
226
320
  const ledger = ensureGfiLedger(state);
321
+
227
322
  if (options?.source) {
228
323
  const sourceKey = options.source;
229
324
  const currentSource = ledger[sourceKey] || 0;
230
325
  const requestedAmount = Number.isFinite(options.amount) ? Number(options.amount) : currentSource;
231
326
  const amountToRemove = Math.max(0, Math.min(currentSource, requestedAmount));
327
+
232
328
  if (amountToRemove > 0) {
233
329
  ledger[sourceKey] = Math.max(0, currentSource - amountToRemove);
234
330
  if (ledger[sourceKey] === 0) {
235
331
  delete ledger[sourceKey];
236
332
  }
237
333
  state.currentGfi = Math.max(0, (state.currentGfi || 0) - amountToRemove);
238
- 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
+
239
340
  if (state.lastErrorSource === sourceKey) {
240
341
  state.consecutiveErrors = 0;
241
342
  state.lastErrorHash = '';
@@ -246,6 +347,7 @@ export function resetFriction(sessionId, workspaceDir, options) {
246
347
  schedulePersistence(state);
247
348
  return state;
248
349
  }
350
+
249
351
  if (state.currentGfi > 0) {
250
352
  SystemLogger.log(state.workspaceDir, 'GFI_RESET', `Friction reset to 0 (Was: ${state.currentGfi.toFixed(1)}). Action successful.`);
251
353
  }
@@ -255,15 +357,18 @@ export function resetFriction(sessionId, workspaceDir, options) {
255
357
  state.consecutiveErrors = 0;
256
358
  state.lastErrorHash = '';
257
359
  touchActivity(state, 'control');
360
+
258
361
  // Schedule persistence
259
362
  schedulePersistence(state);
363
+
260
364
  return state;
261
365
  }
366
+
262
367
  /**
263
368
  * Records that deep thinking (Thinking OS) was performed in this session.
264
369
  * Used by the Thinking OS checkpoint to allow high-risk operations.
265
370
  */
266
- export function recordThinkingCheckpoint(sessionId, workspaceDir) {
371
+ export function recordThinkingCheckpoint(sessionId: string, workspaceDir?: string): SessionState {
267
372
  const state = getOrCreateSession(sessionId, workspaceDir);
268
373
  state.lastThinkingTimestamp = Date.now();
269
374
  touchActivity(state, 'control');
@@ -271,53 +376,61 @@ export function recordThinkingCheckpoint(sessionId, workspaceDir) {
271
376
  schedulePersistence(state);
272
377
  return state;
273
378
  }
379
+
274
380
  /**
275
381
  * Checks if deep thinking was performed recently (within the given window).
276
382
  * @param sessionId - The session to check
277
383
  * @param windowMs - How recent the thinking must be (default: 5 minutes)
278
384
  * @returns true if thinking was recorded within the window
279
385
  */
280
- export function hasRecentThinking(sessionId, windowMs = 5 * 60 * 1000) {
386
+ export function hasRecentThinking(sessionId: string, windowMs: number = 5 * 60 * 1000): boolean {
281
387
  const state = sessions.get(sessionId);
282
- if (!state || !state.lastThinkingTimestamp)
283
- return false;
388
+ if (!state || !state.lastThinkingTimestamp) return false;
284
389
  return (Date.now() - state.lastThinkingTimestamp) < windowMs;
285
390
  }
286
- export function trackBlock(sessionId) {
391
+
392
+ export function trackBlock(sessionId: string): SessionState {
287
393
  const state = getOrCreateSession(sessionId);
288
394
  state.blockedAttempts += 1;
289
395
  touchActivity(state, 'control');
290
396
  schedulePersistence(state);
291
397
  return state;
292
398
  }
293
- export function setInjectedProbationIds(sessionId, ids, workspaceDir) {
399
+
400
+
401
+ export function setInjectedProbationIds(sessionId: string, ids: string[], workspaceDir?: string): SessionState {
294
402
  const state = getOrCreateSession(sessionId, workspaceDir);
295
403
  state.injectedProbationIds = [...ids];
296
404
  touchActivity(state, 'control');
297
405
  schedulePersistence(state);
298
406
  return state;
299
407
  }
300
- export function getInjectedProbationIds(sessionId, workspaceDir) {
408
+
409
+ export function getInjectedProbationIds(sessionId: string, workspaceDir?: string): string[] {
301
410
  const state = getOrCreateSession(sessionId, workspaceDir);
302
411
  return [...(state.injectedProbationIds || [])];
303
412
  }
304
- export function clearInjectedProbationIds(sessionId, workspaceDir) {
413
+
414
+ export function clearInjectedProbationIds(sessionId: string, workspaceDir?: string): SessionState {
305
415
  return setInjectedProbationIds(sessionId, [], workspaceDir);
306
416
  }
307
- export function getSession(sessionId) {
417
+
418
+ export function getSession(sessionId: string): SessionState | undefined {
308
419
  return sessions.get(sessionId);
309
420
  }
310
- export function listSessions(workspaceDir) {
421
+
422
+ export function listSessions(workspaceDir?: string): SessionState[] {
311
423
  return [...sessions.values()]
312
424
  .filter((state) => !workspaceDir || !state.workspaceDir || state.workspaceDir === workspaceDir)
313
425
  .map((state) => ({
314
- ...state,
315
- toolReadsByFile: { ...state.toolReadsByFile },
316
- gfiBySource: state.gfiBySource ? { ...state.gfiBySource } : undefined,
317
- injectedProbationIds: state.injectedProbationIds ? [...state.injectedProbationIds] : undefined,
318
- }));
426
+ ...state,
427
+ toolReadsByFile: { ...state.toolReadsByFile },
428
+ gfiBySource: state.gfiBySource ? { ...state.gfiBySource } : undefined,
429
+ injectedProbationIds: state.injectedProbationIds ? [...state.injectedProbationIds] : undefined,
430
+ }));
319
431
  }
320
- export function clearSession(sessionId) {
432
+
433
+ export function clearSession(sessionId: string): void {
321
434
  const timer = persistTimers.get(sessionId);
322
435
  if (timer) {
323
436
  clearTimeout(timer);
@@ -325,6 +438,7 @@ export function clearSession(sessionId) {
325
438
  }
326
439
  sessions.delete(sessionId);
327
440
  }
441
+
328
442
  /**
329
443
  * Seed a session directly into SessionTracker.sessions for testing.
330
444
  * This bypasses the normal tool-call flow to set up test data for
@@ -334,13 +448,14 @@ export function clearSession(sessionId) {
334
448
  * @param workspaceDir - Workspace directory (optional, for filtering)
335
449
  * @param lastActivityAt - Unix timestamp in ms (default: now)
336
450
  */
337
- export function seedSessionForTest(sessionId, workspaceDir, lastActivityAt) {
451
+ export function seedSessionForTest(sessionId: string, workspaceDir?: string, lastActivityAt?: number): void {
338
452
  const state = getOrCreateSession(sessionId, workspaceDir);
339
453
  state.lastActivityAt = lastActivityAt ?? Date.now();
340
454
  state.lastControlActivityAt = state.lastActivityAt;
341
455
  }
456
+
342
457
  // Memory cleanup for abandoned sessions (older than 2 hours)
343
- export function garbageCollectSessions() {
458
+ export function garbageCollectSessions(): void {
344
459
  const twoHoursAgo = Date.now() - 2 * 60 * 60 * 1000;
345
460
  for (const [id, state] of sessions.entries()) {
346
461
  if (state.lastActivityAt < twoHoursAgo) {
@@ -350,14 +465,14 @@ export function garbageCollectSessions() {
350
465
  persistTimers.delete(id);
351
466
  }
352
467
  sessions.delete(id);
468
+
353
469
  // Also delete persisted file
354
470
  if (persistDir) {
355
471
  const sessionPath = getSessionPath(id);
356
472
  if (sessionPath && fs.existsSync(sessionPath)) {
357
473
  try {
358
474
  fs.unlinkSync(sessionPath);
359
- }
360
- catch (error) {
475
+ } catch (error) {
361
476
  logSessionTrackerWarning(`Failed to delete session snapshot for ${id}`, error);
362
477
  }
363
478
  }
@@ -365,13 +480,19 @@ export function garbageCollectSessions() {
365
480
  }
366
481
  }
367
482
  }
483
+
368
484
  /**
369
485
  * Get daily statistics summary for a session.
370
486
  */
371
- export function getDailySummary(sessionId) {
487
+ export function getDailySummary(sessionId: string): {
488
+ toolCalls: number;
489
+ toolFailures: number;
490
+ painSignals: number;
491
+ gfiPeak: number;
492
+ } | null {
372
493
  const state = sessions.get(sessionId);
373
- if (!state)
374
- return null;
494
+ if (!state) return null;
495
+
375
496
  return {
376
497
  toolCalls: state.dailyToolCalls,
377
498
  toolFailures: state.dailyToolFailures,
@@ -379,10 +500,11 @@ export function getDailySummary(sessionId) {
379
500
  gfiPeak: state.dailyGfiPeak,
380
501
  };
381
502
  }
503
+
382
504
  /**
383
505
  * Reset daily statistics (call at midnight or on new day).
384
506
  */
385
- export function resetDailyStats(sessionId) {
507
+ export function resetDailyStats(sessionId: string): void {
386
508
  const state = sessions.get(sessionId);
387
509
  if (state) {
388
510
  state.dailyToolCalls = 0;