openclaw-hybrid-memory 2026.5.310 → 2026.6.10

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 (535) hide show
  1. package/api/plugin-runtime.ts +2 -0
  2. package/backends/facts-db/contradictions.ts +1 -1
  3. package/cli/cmd-extract-directives.ts +225 -11
  4. package/cli/cmd-extract-proposals.ts +5 -6
  5. package/cli/cmd-extract-reinforcement.ts +71 -0
  6. package/cli/cmd-feedback.ts +15 -9
  7. package/cli/commands/manage/register-reflection-pipeline.ts +247 -13
  8. package/cli/commands/manage/register-storage-maintenance.ts +224 -15
  9. package/cli/commands/manage/storage-stats-helpers.ts +13 -2
  10. package/cli/context.ts +9 -19
  11. package/cli/distill.ts +31 -1
  12. package/cli/register.ts +28 -38
  13. package/dist/api/plugin-runtime.js.map +1 -1
  14. package/dist/backends/agent-health-store.js.map +1 -1
  15. package/dist/backends/apitap-store.js.map +1 -1
  16. package/dist/backends/audit-store.js.map +1 -1
  17. package/dist/backends/base-sqlite-store.js.map +1 -1
  18. package/dist/backends/cost-tracker.js.map +1 -1
  19. package/dist/backends/credentials-db.js +2 -3
  20. package/dist/backends/credentials-db.js.map +1 -1
  21. package/dist/backends/crystallization-store.js.map +1 -1
  22. package/dist/backends/edict-store.js.map +1 -1
  23. package/dist/backends/event-bus.js.map +1 -1
  24. package/dist/backends/event-log.js.map +1 -1
  25. package/dist/backends/facts-db/cache-manager.js.map +1 -1
  26. package/dist/backends/facts-db/clusters.js.map +1 -1
  27. package/dist/backends/facts-db/contradictions.js +1 -1
  28. package/dist/backends/facts-db/contradictions.js.map +1 -1
  29. package/dist/backends/facts-db/crud.js.map +1 -1
  30. package/dist/backends/facts-db/db-connection.js.map +1 -1
  31. package/dist/backends/facts-db/entity-autolink.js.map +1 -1
  32. package/dist/backends/facts-db/entity-layer.js.map +1 -1
  33. package/dist/backends/facts-db/episodes.js.map +1 -1
  34. package/dist/backends/facts-db/fact-queries.js.map +1 -1
  35. package/dist/backends/facts-db/fact-read-queries.js.map +1 -1
  36. package/dist/backends/facts-db/facts-db-layer1.js.map +1 -1
  37. package/dist/backends/facts-db/facts-db-layer2.js.map +1 -1
  38. package/dist/backends/facts-db/facts-db-layer3.js.map +1 -1
  39. package/dist/backends/facts-db/fts-text.js.map +1 -1
  40. package/dist/backends/facts-db/generated-skills/policy.js.map +1 -1
  41. package/dist/backends/facts-db/generated-skills.js.map +1 -1
  42. package/dist/backends/facts-db/housekeeping.js.map +1 -1
  43. package/dist/backends/facts-db/links.js.map +1 -1
  44. package/dist/backends/facts-db/maintenance.js.map +1 -1
  45. package/dist/backends/facts-db/procedures/crud.js.map +1 -1
  46. package/dist/backends/facts-db/procedures/internal.js.map +1 -1
  47. package/dist/backends/facts-db/procedures/promotion.js.map +1 -1
  48. package/dist/backends/facts-db/procedures/search.js.map +1 -1
  49. package/dist/backends/facts-db/procedures/stats.js.map +1 -1
  50. package/dist/backends/facts-db/reinforcement.js.map +1 -1
  51. package/dist/backends/facts-db/row-mapper.js.map +1 -1
  52. package/dist/backends/facts-db/scan-cursors.js.map +1 -1
  53. package/dist/backends/facts-db/schema-bootstrap.js.map +1 -1
  54. package/dist/backends/facts-db/scope-sql.js.map +1 -1
  55. package/dist/backends/facts-db/search.js.map +1 -1
  56. package/dist/backends/facts-db/stats.js.map +1 -1
  57. package/dist/backends/facts-db/types.js.map +1 -1
  58. package/dist/backends/facts-db/variants.js.map +1 -1
  59. package/dist/backends/identity-reflection-store.js.map +1 -1
  60. package/dist/backends/issue-store.js.map +1 -1
  61. package/dist/backends/learnings-db.js.map +1 -1
  62. package/dist/backends/migrations/facts-migrations.js.map +1 -1
  63. package/dist/backends/migrations/procedures.js.map +1 -1
  64. package/dist/backends/narratives-db.js.map +1 -1
  65. package/dist/backends/persona-state-store.js.map +1 -1
  66. package/dist/backends/proposals-db.js.map +1 -1
  67. package/dist/backends/scope-filter-sql.js.map +1 -1
  68. package/dist/backends/sqlite-schema-meta.js.map +1 -1
  69. package/dist/backends/tool-proposal-store.js.map +1 -1
  70. package/dist/backends/vector-db/constants.js.map +1 -1
  71. package/dist/backends/vector-db/path-utils.js.map +1 -1
  72. package/dist/backends/vector-db/runtime-locks.js.map +1 -1
  73. package/dist/backends/vector-db/vector-db-class.js.map +1 -1
  74. package/dist/backends/wal.js.map +1 -1
  75. package/dist/backends/workflow-store.js.map +1 -1
  76. package/dist/benchmark/shadow-eval.js.map +1 -1
  77. package/dist/cli/active-tasks.js.map +1 -1
  78. package/dist/cli/backup.js.map +1 -1
  79. package/dist/cli/benchmark.js.map +1 -1
  80. package/dist/cli/cmd-backfill.js.map +1 -1
  81. package/dist/cli/cmd-config.js.map +1 -1
  82. package/dist/cli/cmd-credentials.js.map +1 -1
  83. package/dist/cli/cmd-demo.js.map +1 -1
  84. package/dist/cli/cmd-distill.js.map +1 -1
  85. package/dist/cli/cmd-doctor.js.map +1 -1
  86. package/dist/cli/cmd-examples.js.map +1 -1
  87. package/dist/cli/cmd-extract-daily.js.map +1 -1
  88. package/dist/cli/cmd-extract-directives.js +141 -10
  89. package/dist/cli/cmd-extract-directives.js.map +1 -1
  90. package/dist/cli/cmd-extract-procedures.js.map +1 -1
  91. package/dist/cli/cmd-extract-proposals.js +3 -2
  92. package/dist/cli/cmd-extract-proposals.js.map +1 -1
  93. package/dist/cli/cmd-extract-reinforcement.js +39 -0
  94. package/dist/cli/cmd-extract-reinforcement.js.map +1 -1
  95. package/dist/cli/cmd-extract-sessions.js.map +1 -1
  96. package/dist/cli/cmd-feedback.js +9 -4
  97. package/dist/cli/cmd-feedback.js.map +1 -1
  98. package/dist/cli/cmd-health.js.map +1 -1
  99. package/dist/cli/cmd-providers.js.map +1 -1
  100. package/dist/cli/cmd-selfcorrection.js.map +1 -1
  101. package/dist/cli/cmd-setup.js.map +1 -1
  102. package/dist/cli/cmd-status.js.map +1 -1
  103. package/dist/cli/cmd-store.js.map +1 -1
  104. package/dist/cli/cmd-user-friendly.js.map +1 -1
  105. package/dist/cli/cmd-verify.js.map +1 -1
  106. package/dist/cli/commands/manage/bindings.js.map +1 -1
  107. package/dist/cli/commands/manage/dream-cycle-followup.js.map +1 -1
  108. package/dist/cli/commands/manage/maintenance-heartbeat.js.map +1 -1
  109. package/dist/cli/commands/manage/register-agents-audit-runall.js.map +1 -1
  110. package/dist/cli/commands/manage/register-analyze-maintenance-logs.js.map +1 -1
  111. package/dist/cli/commands/manage/register-budget-proposals.js.map +1 -1
  112. package/dist/cli/commands/manage/register-config-cli.js.map +1 -1
  113. package/dist/cli/commands/manage/register-corrections-and-pipeline.js.map +1 -1
  114. package/dist/cli/commands/manage/register-corrections.js.map +1 -1
  115. package/dist/cli/commands/manage/register-council.js.map +1 -1
  116. package/dist/cli/commands/manage/register-credentials-scope.js.map +1 -1
  117. package/dist/cli/commands/manage/register-digest.js.map +1 -1
  118. package/dist/cli/commands/manage/register-lifecycle.js.map +1 -1
  119. package/dist/cli/commands/manage/register-procedure-lifecycle.js.map +1 -1
  120. package/dist/cli/commands/manage/register-reconcile-cron-ledgers.js.map +1 -1
  121. package/dist/cli/commands/manage/register-reflection-pipeline.js +144 -7
  122. package/dist/cli/commands/manage/register-reflection-pipeline.js.map +1 -1
  123. package/dist/cli/commands/manage/register-self-correction-feedback.js.map +1 -1
  124. package/dist/cli/commands/manage/register-storage-and-stats.js.map +1 -1
  125. package/dist/cli/commands/manage/register-storage-entities-decay.js.map +1 -1
  126. package/dist/cli/commands/manage/register-storage-graph-audit.js.map +1 -1
  127. package/dist/cli/commands/manage/register-storage-maintenance.js +152 -9
  128. package/dist/cli/commands/manage/register-storage-maintenance.js.map +1 -1
  129. package/dist/cli/commands/manage/register-validate-cron-exit.js.map +1 -1
  130. package/dist/cli/commands/manage/storage-stats-helpers.js +10 -3
  131. package/dist/cli/commands/manage/storage-stats-helpers.js.map +1 -1
  132. package/dist/cli/commands/register-manage-commands.js.map +1 -1
  133. package/dist/cli/config-feature-summaries.js.map +1 -1
  134. package/dist/cli/config-output-sink.js.map +1 -1
  135. package/dist/cli/distill-session-jsonl.js.map +1 -1
  136. package/dist/cli/distill.js +10 -1
  137. package/dist/cli/distill.js.map +1 -1
  138. package/dist/cli/global-verbose.js.map +1 -1
  139. package/dist/cli/goals.js.map +1 -1
  140. package/dist/cli/hybrid-mem-commander-utils.js.map +1 -1
  141. package/dist/cli/install/config-merge.js.map +1 -1
  142. package/dist/cli/install/cron-jobs.js.map +1 -1
  143. package/dist/cli/install/embedding-detect.js.map +1 -1
  144. package/dist/cli/install/run-install.js.map +1 -1
  145. package/dist/cli/install/workspace.js.map +1 -1
  146. package/dist/cli/proposals.js.map +1 -1
  147. package/dist/cli/register.js.map +1 -1
  148. package/dist/cli/shared.js.map +1 -1
  149. package/dist/cli/skills.js.map +1 -1
  150. package/dist/cli/task-queue-status.js.map +1 -1
  151. package/dist/cli/verified.js.map +1 -1
  152. package/dist/cli/verify/fact-count.js.map +1 -1
  153. package/dist/cli/verify/openclaw-config.js.map +1 -1
  154. package/dist/cli/verify/plugin-config-credentials.js.map +1 -1
  155. package/dist/cli/verify/sections/config-cron.js.map +1 -1
  156. package/dist/cli/verify/sections/embeddings.js.map +1 -1
  157. package/dist/cli/verify/sections/infrastructure.js.map +1 -1
  158. package/dist/cli/verify/sections/llm-models.js.map +1 -1
  159. package/dist/cli/verify/sections/reconcile.js.map +1 -1
  160. package/dist/cli/verify/verify-run-state.js.map +1 -1
  161. package/dist/cli/verify-llm-azure-auth.js.map +1 -1
  162. package/dist/cli/verify.js.map +1 -1
  163. package/dist/config/hybrid-schema.js.map +1 -1
  164. package/dist/config/index.js.map +1 -1
  165. package/dist/config/maintenance-fallback-policy.js.map +1 -1
  166. package/dist/config/parsers/capture.js.map +1 -1
  167. package/dist/config/parsers/core.js.map +1 -1
  168. package/dist/config/parsers/features.js.map +1 -1
  169. package/dist/config/parsers/index.js.map +1 -1
  170. package/dist/config/parsers/maintenance.js.map +1 -1
  171. package/dist/config/parsers/retrieval.js.map +1 -1
  172. package/dist/config/parsers/sensors.js.map +1 -1
  173. package/dist/config/skill-sections.js.map +1 -1
  174. package/dist/config/skill-size-limits.js.map +1 -1
  175. package/dist/config/types/agents.js.map +1 -1
  176. package/dist/config/types/bootstrap.js.map +1 -1
  177. package/dist/config/types/core.js.map +1 -1
  178. package/dist/config/types/index.js.map +1 -1
  179. package/dist/config/utils.js.map +1 -1
  180. package/dist/index-help.js.map +1 -1
  181. package/dist/index-testing-exports.js.map +1 -1
  182. package/dist/index.d.ts +1 -1
  183. package/dist/index.js +2 -2
  184. package/dist/index.js.map +1 -1
  185. package/dist/lifecycle/hook-resolution-api.js.map +1 -1
  186. package/dist/lifecycle/hooks.js +0 -1
  187. package/dist/lifecycle/hooks.js.map +1 -1
  188. package/dist/lifecycle/resolve-agent-id.js.map +1 -1
  189. package/dist/lifecycle/session-state.js.map +1 -1
  190. package/dist/lifecycle/stage-active-task.js.map +1 -1
  191. package/dist/lifecycle/stage-auth-failure.js.map +1 -1
  192. package/dist/lifecycle/stage-capture/run-capture.js.map +1 -1
  193. package/dist/lifecycle/stage-capture.js.map +1 -1
  194. package/dist/lifecycle/stage-cleanup.js.map +1 -1
  195. package/dist/lifecycle/stage-credential-hint.js.map +1 -1
  196. package/dist/lifecycle/stage-frustration.js.map +1 -1
  197. package/dist/lifecycle/stage-goal-stewardship.js.map +1 -1
  198. package/dist/lifecycle/stage-goal-subagent.js.map +1 -1
  199. package/dist/lifecycle/stage-injection.js +1 -1
  200. package/dist/lifecycle/stage-injection.js.map +1 -1
  201. package/dist/lifecycle/stage-recall/run-recall.js.map +1 -1
  202. package/dist/lifecycle/stage-recall.js.map +1 -1
  203. package/dist/lifecycle/stage-setup.js.map +1 -1
  204. package/dist/routes/dashboard/collectors.js.map +1 -1
  205. package/dist/routes/dashboard/html.js.map +1 -1
  206. package/dist/routes/dashboard/server.js.map +1 -1
  207. package/dist/routes/dashboard-graph.js.map +1 -1
  208. package/dist/routes/graphql-resolvers.js.map +1 -1
  209. package/dist/routes/graphql-server.js.map +1 -1
  210. package/dist/services/active-task-checkpoint.js.map +1 -1
  211. package/dist/services/active-task-injection.js.map +1 -1
  212. package/dist/services/active-task.js.map +1 -1
  213. package/dist/services/adaptive-catch-up-pacing.js +25 -0
  214. package/dist/services/adaptive-catch-up-pacing.js.map +1 -0
  215. package/dist/services/adaptive-maintenance-llm.js.map +1 -1
  216. package/dist/services/adaptive-model-limits.js.map +1 -1
  217. package/dist/services/ambient-retrieval.js.map +1 -1
  218. package/dist/services/apitap-service.js.map +1 -1
  219. package/dist/services/audit-health-exit-info.js.map +1 -1
  220. package/dist/services/audit-health-json.js.map +1 -1
  221. package/dist/services/auth-failure-detect.js.map +1 -1
  222. package/dist/services/auto-capture.js.map +1 -1
  223. package/dist/services/auto-classifier.js.map +1 -1
  224. package/dist/services/auto-skills-audit.js.map +1 -1
  225. package/dist/services/bootstrap-optional.js.map +1 -1
  226. package/dist/services/bootstrap-priority.js.map +1 -1
  227. package/dist/services/bootstrap.js.map +1 -1
  228. package/dist/services/capture-provenance.js.map +1 -1
  229. package/dist/services/capture-utils.js.map +1 -1
  230. package/dist/services/chat.js +22 -3
  231. package/dist/services/chat.js.map +1 -1
  232. package/dist/services/classification-scope.js.map +1 -1
  233. package/dist/services/classification.js.map +1 -1
  234. package/dist/services/cli-sql-dump.js.map +1 -1
  235. package/dist/services/consolidation.js.map +1 -1
  236. package/dist/services/context-audit.js +1 -1
  237. package/dist/services/context-audit.js.map +1 -1
  238. package/dist/services/context-budget.js.map +1 -1
  239. package/dist/services/context-engine.js.map +1 -1
  240. package/dist/services/contextual-variants.js.map +1 -1
  241. package/dist/services/continuous-verifier.js.map +1 -1
  242. package/dist/services/contradiction-adjudicator.js.map +1 -1
  243. package/dist/services/cost-context.js.map +1 -1
  244. package/dist/services/cost-feature-labels.js.map +1 -1
  245. package/dist/services/credential-migration.js.map +1 -1
  246. package/dist/services/credential-scanner.js.map +1 -1
  247. package/dist/services/credential-validation.js.map +1 -1
  248. package/dist/services/cron-exit-validator.js.map +1 -1
  249. package/dist/services/cron-guard.js.map +1 -1
  250. package/dist/services/cron-job-bash-harness.js +52 -5
  251. package/dist/services/cron-job-bash-harness.js.map +1 -1
  252. package/dist/services/cron-maintenance-reconciler.js +1 -3
  253. package/dist/services/cron-maintenance-reconciler.js.map +1 -1
  254. package/dist/services/cross-agent-learning.js.map +1 -1
  255. package/dist/services/crystallization-proposer.js.map +1 -1
  256. package/dist/services/dedupe-policy.js.map +1 -1
  257. package/dist/services/deprecated-cron-commands.js.map +1 -1
  258. package/dist/services/directive-extract.js.map +1 -1
  259. package/dist/services/document-chunker.js.map +1 -1
  260. package/dist/services/document-grader.js.map +1 -1
  261. package/dist/services/dream-cycle.js.map +1 -1
  262. package/dist/services/embedding-migration.js.map +1 -1
  263. package/dist/services/embedding-registry.js.map +1 -1
  264. package/dist/services/embeddings/chain-provider.js.map +1 -1
  265. package/dist/services/embeddings/factory.js.map +1 -1
  266. package/dist/services/embeddings/fallback-provider.js.map +1 -1
  267. package/dist/services/embeddings/ollama-provider.js.map +1 -1
  268. package/dist/services/embeddings/onnx-provider.js.map +1 -1
  269. package/dist/services/embeddings/openai-provider.js.map +1 -1
  270. package/dist/services/embeddings/shared.js +3 -3
  271. package/dist/services/embeddings/shared.js.map +1 -1
  272. package/dist/services/embeddings/types.js.map +1 -1
  273. package/dist/services/entity-enrichment-adaptive.js +128 -0
  274. package/dist/services/entity-enrichment-adaptive.js.map +1 -0
  275. package/dist/services/entity-enrichment-cli.js +389 -42
  276. package/dist/services/entity-enrichment-cli.js.map +1 -1
  277. package/dist/services/entity-enrichment.js +31 -5
  278. package/dist/services/entity-enrichment.js.map +1 -1
  279. package/dist/services/error-reporter/noisy-errors.js.map +1 -1
  280. package/dist/services/error-reporter/sanitize.js.map +1 -1
  281. package/dist/services/error-reporter.js.map +1 -1
  282. package/dist/services/event-hub-repair.js.map +1 -1
  283. package/dist/services/export-memory.js.map +1 -1
  284. package/dist/services/fact-extraction.js.map +1 -1
  285. package/dist/services/feedback-effectiveness.js.map +1 -1
  286. package/dist/services/find-duplicates.js.map +1 -1
  287. package/dist/services/frustration-detector.js.map +1 -1
  288. package/dist/services/fts-search.js.map +1 -1
  289. package/dist/services/gap-detector.js.map +1 -1
  290. package/dist/services/generated-skill-lifecycle.js.map +1 -1
  291. package/dist/services/generated-skill-validation.js.map +1 -1
  292. package/dist/services/goal-active-task-mirror.js.map +1 -1
  293. package/dist/services/goal-circuit-breaker.js.map +1 -1
  294. package/dist/services/goal-health.js.map +1 -1
  295. package/dist/services/goal-registry.js.map +1 -1
  296. package/dist/services/goal-stewardship-heartbeat.js.map +1 -1
  297. package/dist/services/goal-stewardship-llm-triage.js.map +1 -1
  298. package/dist/services/goal-stewardship-verify-cron.js.map +1 -1
  299. package/dist/services/goal-stewardship.js.map +1 -1
  300. package/dist/services/goal-subagent.js.map +1 -1
  301. package/dist/services/graph-retrieval.js.map +1 -1
  302. package/dist/services/humanizer-score.js.map +1 -1
  303. package/dist/services/hybrid-mem-cron-default-job-steps.js.map +1 -1
  304. package/dist/services/hyde-helper.js.map +1 -1
  305. package/dist/services/identity-reflection.js.map +1 -1
  306. package/dist/services/implicit-feedback-extract.js.map +1 -1
  307. package/dist/services/index.js.map +1 -1
  308. package/dist/services/ingest-utils.js.map +1 -1
  309. package/dist/services/intent-template.js.map +1 -1
  310. package/dist/services/json-array-parser.js.map +1 -1
  311. package/dist/services/knowledge-gaps.js.map +1 -1
  312. package/dist/services/language-keywords-build.js.map +1 -1
  313. package/dist/services/lifecycle/github-adapter.js.map +1 -1
  314. package/dist/services/llm-rate-limit-headers.js +1 -2
  315. package/dist/services/llm-rate-limit-headers.js.map +1 -1
  316. package/dist/services/maintenance-auto-fix.js.map +1 -1
  317. package/dist/services/maintenance-log-analyzer.js +7 -1
  318. package/dist/services/maintenance-log-analyzer.js.map +1 -1
  319. package/dist/services/maintenance-timestamp.js.map +1 -1
  320. package/dist/services/memory-diagnostics.js.map +1 -1
  321. package/dist/services/memory-index.js.map +1 -1
  322. package/dist/services/merge-results.js.map +1 -1
  323. package/dist/services/model-capabilities.js.map +1 -1
  324. package/dist/services/model-pricing.js.map +1 -1
  325. package/dist/services/narrative-recall.js.map +1 -1
  326. package/dist/services/openclaw-session-artifact.js.map +1 -1
  327. package/dist/services/passive-observer.js.map +1 -1
  328. package/dist/services/pattern-detector-hash.js.map +1 -1
  329. package/dist/services/pattern-detector.js.map +1 -1
  330. package/dist/services/pending-autopilot/foundation.js.map +1 -1
  331. package/dist/services/pending-autopilot/redaction.js.map +1 -1
  332. package/dist/services/pending-autopilot/store.js.map +1 -1
  333. package/dist/services/pending-autopilot/types.js.map +1 -1
  334. package/dist/services/pending-digest-autopilot-cron.js.map +1 -1
  335. package/dist/services/pending-digest-autopilot.js.map +1 -1
  336. package/dist/services/pending-review-digest.js.map +1 -1
  337. package/dist/services/persona-proposal-triage.js.map +1 -1
  338. package/dist/services/persona-state-promotion.js.map +1 -1
  339. package/dist/services/post-compaction-recall.js.map +1 -1
  340. package/dist/services/pre-consolidation-flush.js.map +1 -1
  341. package/dist/services/pre-finalization-guard.js.map +1 -1
  342. package/dist/services/procedure-cluster.js.map +1 -1
  343. package/dist/services/procedure-extractor.js.map +1 -1
  344. package/dist/services/procedure-promotion/duplicate-skill-cache.js.map +1 -1
  345. package/dist/services/procedure-promotion-policy.js.map +1 -1
  346. package/dist/services/procedure-selection-metrics.js.map +1 -1
  347. package/dist/services/procedure-skill-eval.js.map +1 -1
  348. package/dist/services/procedure-skill-generator.js.map +1 -1
  349. package/dist/services/procedure-skill-recipe.js.map +1 -1
  350. package/dist/services/procedure-skill-shrink.js.map +1 -1
  351. package/dist/services/procedure-skill-workflow.js.map +1 -1
  352. package/dist/services/provenance.js.map +1 -1
  353. package/dist/services/public-export-bundle.js.map +1 -1
  354. package/dist/services/python-bridge.js.map +1 -1
  355. package/dist/services/query-expander.js.map +1 -1
  356. package/dist/services/query-validator.js.map +1 -1
  357. package/dist/services/recall-pipeline.js.map +1 -1
  358. package/dist/services/recall-timing.js.map +1 -1
  359. package/dist/services/recent-http-attempts.js.map +1 -1
  360. package/dist/services/reflection/shared.js.map +1 -1
  361. package/dist/services/reflection.js.map +1 -1
  362. package/dist/services/reinforcement-extract.js.map +1 -1
  363. package/dist/services/reranker.js.map +1 -1
  364. package/dist/services/responses-adapter.js.map +1 -1
  365. package/dist/services/retrieval-aliases.js.map +1 -1
  366. package/dist/services/retrieval-mode-policy.js.map +1 -1
  367. package/dist/services/retrieval-orchestrator/packing.js.map +1 -1
  368. package/dist/services/retrieval-orchestrator.d.ts +2 -3
  369. package/dist/services/retrieval-orchestrator.js.map +1 -1
  370. package/dist/services/rrf-fusion.js.map +1 -1
  371. package/dist/services/self-correction-extract.js.map +1 -1
  372. package/dist/services/session-observability.js.map +1 -1
  373. package/dist/services/session-pre-filter.js.map +1 -1
  374. package/dist/services/shortest-path.js.map +1 -1
  375. package/dist/services/skill-allowed-tools.js.map +1 -1
  376. package/dist/services/skill-creator-validator.js.map +1 -1
  377. package/dist/services/skill-crystallizer-helpers.js.map +1 -1
  378. package/dist/services/skill-crystallizer.js.map +1 -1
  379. package/dist/services/skill-description-builder.js.map +1 -1
  380. package/dist/services/skill-eval-synthesizer.js.map +1 -1
  381. package/dist/services/skill-examples-builder.js.map +1 -1
  382. package/dist/services/skill-frontmatter.js.map +1 -1
  383. package/dist/services/skill-name-validator.js.map +1 -1
  384. package/dist/services/skill-prompt-injection.js.map +1 -1
  385. package/dist/services/skill-reference-sidecar.js.map +1 -1
  386. package/dist/services/skill-script-bundler.js.map +1 -1
  387. package/dist/services/skill-validator.js.map +1 -1
  388. package/dist/services/startup-memory-attribution.js.map +1 -1
  389. package/dist/services/task-hygiene.js.map +1 -1
  390. package/dist/services/task-ledger/canonical.js.map +1 -1
  391. package/dist/services/task-ledger-facts.js.map +1 -1
  392. package/dist/services/task-queue-leases.js.map +1 -1
  393. package/dist/services/task-queue-watchdog.js.map +1 -1
  394. package/dist/services/tool-effectiveness.js.map +1 -1
  395. package/dist/services/tool-proposer.js.map +1 -1
  396. package/dist/services/tools-md-section.js.map +1 -1
  397. package/dist/services/topic-clusters.js.map +1 -1
  398. package/dist/services/trajectory-tracker.js.map +1 -1
  399. package/dist/services/vector-backend-observability.js.map +1 -1
  400. package/dist/services/vector-lifecycle-audit.js.map +1 -1
  401. package/dist/services/vector-maintenance.js.map +1 -1
  402. package/dist/services/vector-search.js.map +1 -1
  403. package/dist/services/verification-store.js.map +1 -1
  404. package/dist/services/verified-fact-triage.js.map +1 -1
  405. package/dist/services/wal-helpers.js.map +1 -1
  406. package/dist/services/workflow-tracker.js.map +1 -1
  407. package/dist/setup/bootstrap-databases.js.map +1 -1
  408. package/dist/setup/cli-context/cli-services.js.map +1 -1
  409. package/dist/setup/cli-context/help-text.js.map +1 -1
  410. package/dist/setup/cli-context/metadata.js.map +1 -1
  411. package/dist/setup/cli-context/register-cli-with-help.js.map +1 -1
  412. package/dist/setup/cli-context/register-full.js.map +1 -1
  413. package/dist/setup/cli-context/register-help.js.map +1 -1
  414. package/dist/setup/cost-instrumentation.js.map +1 -1
  415. package/dist/setup/hybrid-memory-generation-state.js.map +1 -1
  416. package/dist/setup/hybrid-memory-reload-coordinator.js +13 -13
  417. package/dist/setup/hybrid-memory-reload-coordinator.js.map +1 -1
  418. package/dist/setup/plugin-service.js.map +1 -1
  419. package/dist/setup/provider-router.js.map +1 -1
  420. package/dist/setup/register-context-engine.js.map +1 -1
  421. package/dist/setup/register-hooks.js.map +1 -1
  422. package/dist/setup/register-plugin.js +25 -21
  423. package/dist/setup/register-plugin.js.map +1 -1
  424. package/dist/setup/register-tools.js.map +1 -1
  425. package/dist/setup/reregister-policy.js +2 -2
  426. package/dist/setup/reregister-policy.js.map +1 -1
  427. package/dist/setup/tool-installers.js.map +1 -1
  428. package/dist/setup/workspace-bootstrap.js.map +1 -1
  429. package/dist/src/worker/narratives.js.map +1 -1
  430. package/dist/tools/apitap-tools.js.map +1 -1
  431. package/dist/tools/credential-tools.js.map +1 -1
  432. package/dist/tools/crystallization-tools.js.map +1 -1
  433. package/dist/tools/dashboard-routes.js.map +1 -1
  434. package/dist/tools/document-tools.js.map +1 -1
  435. package/dist/tools/goal-tools.js.map +1 -1
  436. package/dist/tools/graph-tools.js.map +1 -1
  437. package/dist/tools/issue-tools.js.map +1 -1
  438. package/dist/tools/memory/build-runtime.js.map +1 -1
  439. package/dist/tools/memory/helpers.js.map +1 -1
  440. package/dist/tools/memory/register-checkpoint-tools.js.map +1 -1
  441. package/dist/tools/memory/register-directory-tools.js.map +1 -1
  442. package/dist/tools/memory/register-edict-tools.js.map +1 -1
  443. package/dist/tools/memory/register-episode-tools.js.map +1 -1
  444. package/dist/tools/memory/register-recall-tools.js.map +1 -1
  445. package/dist/tools/memory/register-store-tools.js.map +1 -1
  446. package/dist/tools/memory-tools.js.map +1 -1
  447. package/dist/tools/persona-tools.js.map +1 -1
  448. package/dist/tools/provenance-tools.js.map +1 -1
  449. package/dist/tools/public-api-routes.js.map +1 -1
  450. package/dist/tools/safe-register-http-route.js.map +1 -1
  451. package/dist/tools/self-extension-tools.js.map +1 -1
  452. package/dist/tools/task-hygiene-tools.js.map +1 -1
  453. package/dist/tools/utility-tools.js.map +1 -1
  454. package/dist/tools/verification-tools.js.map +1 -1
  455. package/dist/tools/workflow-tools.js.map +1 -1
  456. package/dist/types/issue-types.js.map +1 -1
  457. package/dist/types/learnings-types.js.map +1 -1
  458. package/dist/types/memory.js.map +1 -1
  459. package/dist/utils/apim-gateway-fetch.js.map +1 -1
  460. package/dist/utils/atomic-write.js.map +1 -1
  461. package/dist/utils/auth-failover.js.map +1 -1
  462. package/dist/utils/auth.js.map +1 -1
  463. package/dist/utils/compaction-model-watchdog.js.map +1 -1
  464. package/dist/utils/consolidation-controls.js.map +1 -1
  465. package/dist/utils/constants.js.map +1 -1
  466. package/dist/utils/date-detector.js.map +1 -1
  467. package/dist/utils/dates.js.map +1 -1
  468. package/dist/utils/decay.js.map +1 -1
  469. package/dist/utils/duration.js.map +1 -1
  470. package/dist/utils/embed-call.js.map +1 -1
  471. package/dist/utils/entity-lookup-resolve.js.map +1 -1
  472. package/dist/utils/entity-mention-quality.js.map +1 -1
  473. package/dist/utils/entity-stopwords.js.map +1 -1
  474. package/dist/utils/env-manager.js.map +1 -1
  475. package/dist/utils/error-tracking.js.map +1 -1
  476. package/dist/utils/event-loop-yield.js.map +1 -1
  477. package/dist/utils/extract-last-user-message.js.map +1 -1
  478. package/dist/utils/extraction-from-template.js.map +1 -1
  479. package/dist/utils/fact-embeddings.js.map +1 -1
  480. package/dist/utils/file-snapshot.js.map +1 -1
  481. package/dist/utils/format.js.map +1 -1
  482. package/dist/utils/fs.js.map +1 -1
  483. package/dist/utils/gh-repo-arg.js.map +1 -1
  484. package/dist/utils/hybrid-mem-json-cli.js.map +1 -1
  485. package/dist/utils/language-keywords.js.map +1 -1
  486. package/dist/utils/lifecycle-generation.js.map +1 -1
  487. package/dist/utils/llm-json-array.js.map +1 -1
  488. package/dist/utils/llm-selection.js.map +1 -1
  489. package/dist/utils/logger.js.map +1 -1
  490. package/dist/utils/model-provider-family.js.map +1 -1
  491. package/dist/utils/model-tier.js.map +1 -1
  492. package/dist/utils/openclaw-agent-defaults.js.map +1 -1
  493. package/dist/utils/path.js.map +1 -1
  494. package/dist/utils/plugin-root.js.map +1 -1
  495. package/dist/utils/plugin-update-check.js.map +1 -1
  496. package/dist/utils/procedure-risk.js.map +1 -1
  497. package/dist/utils/progress-indicators.js.map +1 -1
  498. package/dist/utils/prompt-loader.js.map +1 -1
  499. package/dist/utils/provenance.js.map +1 -1
  500. package/dist/utils/provider-detection.js.map +1 -1
  501. package/dist/utils/registration-superseded.js.map +1 -1
  502. package/dist/utils/salience.js.map +1 -1
  503. package/dist/utils/sanitize-messages.js.map +1 -1
  504. package/dist/utils/scope-filter.js.map +1 -1
  505. package/dist/utils/skill-discovery.js.map +1 -1
  506. package/dist/utils/sqlite-file-perms.js.map +1 -1
  507. package/dist/utils/sqlite-outcome-compat.js.map +1 -1
  508. package/dist/utils/sqlite-transaction.js.map +1 -1
  509. package/dist/utils/stable-stringify.js.map +1 -1
  510. package/dist/utils/subagent-ended-utils.js.map +1 -1
  511. package/dist/utils/tags.js.map +1 -1
  512. package/dist/utils/text.js.map +1 -1
  513. package/dist/utils/timeout.js.map +1 -1
  514. package/dist/utils/typebox.js.map +1 -1
  515. package/dist/utils/version-check.js.map +1 -1
  516. package/dist/utils/wal-replay.js.map +1 -1
  517. package/dist/versionInfo.js.map +1 -1
  518. package/index.ts +2 -2
  519. package/lifecycle/hooks.ts +0 -1
  520. package/npm-shrinkwrap.json +487 -186
  521. package/openclaw.plugin.json +1 -1
  522. package/package.json +2 -2
  523. package/services/adaptive-catch-up-pacing.ts +28 -0
  524. package/services/chat.ts +34 -1
  525. package/services/cron-job-bash-harness.ts +52 -5
  526. package/services/embeddings/shared.ts +5 -2
  527. package/services/entity-enrichment-adaptive.ts +245 -0
  528. package/services/entity-enrichment-cli.ts +553 -47
  529. package/services/entity-enrichment.ts +43 -2
  530. package/services/llm-rate-limit-headers.ts +1 -4
  531. package/services/maintenance-log-analyzer.ts +13 -9
  532. package/services/reinforcement-extract.ts +19 -0
  533. package/setup/hybrid-memory-reload-coordinator.ts +26 -0
  534. package/setup/register-plugin.ts +62 -32
  535. package/setup/reregister-policy.ts +10 -5
@@ -1 +1 @@
1
- {"version":3,"file":"run-capture.js","names":["msgObj","tcObj"],"sources":["../../../lifecycle/stage-capture/run-capture.ts"],"sourcesContent":["/**\n * Lifecycle stage: Capture (Phase 2.3).\n * On agent_end: frustration assistant capture, event log session_end, clearSessionState,\n * compaction (if enabled), autoCapture, credential hint, tool-call credential capture.\n * Single timeout: 60s.\n */\n\nimport { dirname, join } from \"node:path\";\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport { getCronModelConfig, getDefaultCronModel } from \"../../config/index.js\";\nimport type { MemoryCategory } from \"../../config.js\";\nimport \"../../config.js\";\nimport { detectCredentialPatterns } from \"../../services/auto-capture.js\";\nimport {\n getAutoCaptureExtractionConfidence,\n getAutoCaptureExtractionMethod,\n resolveCaptureProvenance,\n} from \"../../services/capture-provenance.js\";\nimport {\n classifyMemoryOperation,\n classifyMemoryOperationsBatch,\n type MemoryClassification,\n} from \"../../services/classification.js\";\nimport { validateScopedClassificationTarget } from \"../../services/classification-scope.js\";\nimport { extractCredentialsFromToolCalls } from \"../../services/credential-scanner.js\";\nimport { isOllamaCircuitBreakerOpen } from \"../../services/embeddings.js\";\nimport { capturePluginError } from \"../../services/error-reporter.js\";\nimport { extractStructuredFields } from \"../../services/fact-extraction.js\";\nimport { formatQualityLoopEntry, runHumanizerScore } from \"../../services/humanizer-score.js\";\nimport { cleanupEvictedVector, deleteVectorForFactId } from \"../../services/vector-maintenance.js\";\nimport type { MemoryEntry } from \"../../types/memory.js\";\nimport { atomicWriteFile } from \"../../utils/atomic-write.js\";\nimport { CLI_STORE_IMPORTANCE } from \"../../utils/constants.js\";\nimport { persistCanonicalFactEmbedding } from \"../../utils/fact-embeddings.js\";\nimport { isStaleLifecycleGeneration } from \"../../utils/lifecycle-generation.js\";\nimport { isRecallContextSuperseded, shouldSuppressStaleLifecycleError } from \"../../utils/registration-superseded.js\";\nimport { extractTags } from \"../../utils/tags.js\";\nimport { truncateForStorage } from \"../../utils/text.js\";\nimport { resolveAgentIdFromHookEvent } from \"../resolve-agent-id.js\";\nimport type { LifecycleContext, SessionState } from \"../types.js\";\n\nconst _CAPTURE_STAGE_TIMEOUT_MS = 60_000;\n\nfunction suppressCaptureStageError(ctx: LifecycleContext, api: ClawdbotPluginApi, err: unknown): boolean {\n if (!shouldSuppressStaleLifecycleError(ctx, err)) return false;\n api.logger.debug?.(\"memory-hybrid: capture skipped (registration superseded during reload)\");\n return true;\n}\n\n/** Outcome indicator patterns for episodic memory auto-capture (#781). */\ninterface OutcomePattern {\n regex: RegExp;\n label?: string;\n}\n\n/** Patterns that indicate a successful outcome. */\nconst SUCCESS_PATTERNS: OutcomePattern[] = [\n // Git merge / PR merge\n { regex: /✅\\s*(?:merged|Merge)/i, label: \"merged\" },\n { regex: /\\b(?:successfully\\s+)?(?:merged|Merge)\\b/i, label: \"merged\" },\n // Checkmark / success\n { regex: /✅/i, label: \"success\" },\n // Explicit success language\n { regex: /\\bsucceeded\\b/i, label: \"succeeded\" },\n { regex: /\\bcompleted(?:\\s+successfully)?\\b/i, label: \"completed\" },\n { regex: /\\bfixed\\b/i, label: \"fixed\" },\n { regex: /\\bpassed\\b/i, label: \"passed\" },\n { regex: /\\bdeployed\\b/i, label: \"deployed\" },\n { regex: /\\bresolved\\b/i, label: \"resolved\" },\n];\n\n/** Patterns that indicate a failed outcome. */\nconst FAILURE_PATTERNS: OutcomePattern[] = [\n // Cross mark\n { regex: /❌/i, label: \"failed\" },\n // Explicit failure\n { regex: /\\bfailed\\b/i, label: \"failed\" },\n { regex: /\\bfailure\\b/i, label: \"failure\" },\n { regex: /\\bFAILED\\b/i, label: \"failed\" },\n // Error\n { regex: /\\berror\\b/i, label: \"error\" },\n { regex: /\\bcrashed\\b/i, label: \"crashed\" },\n { regex: /\\bbroke\\b/i, label: \"broke\" },\n { regex: /\\bbug\\b/i, label: \"bug\" },\n { regex: /\\brejected\\b/i, label: \"rejected\" },\n { regex: /\\bdenied\\b/i, label: \"denied\" },\n { regex: /\\brevert(?:ed)?\\b/i, label: \"reverted\" },\n { regex: /\\brollback\\b/i, label: \"rollback\" },\n];\n\n/**\n * Extract text content from the last assistant message in a message array.\n * Returns undefined if no assistant message is found or if the content is empty.\n */\nfunction extractLastAssistantText(messages: unknown[]): string | undefined {\n const assistantMsgs = messages.filter(\n (m) => m && typeof m === \"object\" && (m as { role?: string }).role === \"assistant\",\n );\n const lastAssistant = assistantMsgs[assistantMsgs.length - 1] as { content?: unknown } | undefined;\n if (!lastAssistant) return undefined;\n\n if (typeof lastAssistant.content === \"string\") {\n return lastAssistant.content;\n }\n if (Array.isArray(lastAssistant.content)) {\n const textBlocks: string[] = [];\n for (const block of lastAssistant.content) {\n if (\n block &&\n typeof block === \"object\" &&\n \"type\" in block &&\n (block as { type?: string }).type === \"text\" &&\n \"text\" in block &&\n typeof (block as { text?: unknown }).text === \"string\"\n ) {\n textBlocks.push((block as { text: string }).text);\n }\n }\n if (textBlocks.length > 0) return textBlocks.join(\" \");\n }\n return undefined;\n}\n\nexport async function runCapture(\n event: unknown,\n api: ClawdbotPluginApi,\n ctx: LifecycleContext,\n sessionState: SessionState,\n): Promise<void> {\n const { resolveSessionKey, clearSessionState, frustrationStateMap } = sessionState;\n const sessionKey = resolveSessionKey(event, api) ?? ctx.currentAgentIdRef.value ?? \"default\";\n\n if (isStaleLifecycleGeneration(ctx)) {\n clearSessionState(sessionKey);\n return;\n }\n const abortIfSuperseded = (phase: string): boolean => {\n if (!isRecallContextSuperseded(ctx)) return false;\n api.logger.debug?.(`memory-hybrid: capture skipped (registration superseded during reload) phase=${phase}`);\n return true;\n };\n\n if (abortIfSuperseded(\"start\")) {\n clearSessionState(sessionKey);\n return;\n }\n\n const ev = event as { success?: boolean; messages?: unknown[] };\n const messages = ev?.messages ?? [];\n\n const assistantText = messages.length > 0 ? extractLastAssistantText(messages as unknown[]) : undefined;\n\n // 1. Frustration: append last assistant message to session turn history\n if (assistantText?.trim()) {\n try {\n const state = frustrationStateMap.get(sessionKey);\n if (state) {\n state.turns.push({ role: \"assistant\", content: assistantText });\n if (state.turns.length > 20) state.turns.splice(0, state.turns.length - 20);\n frustrationStateMap.set(sessionKey, state);\n }\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"frustration-assistant-capture\",\n subsystem: \"frustration\",\n severity: \"info\",\n });\n }\n }\n }\n\n // 2. Humanizer quality-loop scoring (Issue #616 — Phase 1: evaluator only, no rewriting)\n if (ctx.cfg.humanizer?.enabled && assistantText?.trim()) {\n try {\n const humCfg = ctx.cfg.humanizer;\n const result = await runHumanizerScore(assistantText, {\n bin: humCfg.bin,\n minTextLength: humCfg.minTextLength,\n maxTextLength: humCfg.maxTextLength,\n });\n if (result !== null) {\n const entryText = formatQualityLoopEntry(result, {\n modelTag: humCfg.modelTag,\n skillTag: humCfg.skillTag,\n });\n const storeResult = ctx.factsDb.storeWithResult({\n text: entryText,\n category: \"quality_loop\",\n importance: 0.6,\n entity: null,\n key: null,\n value: null,\n source: \"humanizer\",\n decayClass: \"normal\",\n });\n if (!storeResult.skipped) {\n await cleanupEvictedVector({\n vectorDb: ctx.vectorDb,\n evictedFactId: storeResult.evictedFactId,\n logger: api.logger,\n context: \"humanizer-score\",\n });\n api.logger.debug?.(`memory-hybrid: humanizer_score=${result.score.toFixed(2)} stored`);\n }\n }\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"humanizer-score-capture\",\n subsystem: \"humanizer\",\n severity: \"info\",\n });\n api.logger.debug?.(`memory-hybrid: humanizer scoring skipped: ${String(err)}`);\n }\n }\n }\n if (abortIfSuperseded(\"post-humanizer\")) {\n clearSessionState(sessionKey);\n return;\n }\n\n // 3. Event log session_end\n if (ctx.eventLog) {\n try {\n ctx.eventLog.append({\n sessionId: sessionKey,\n timestamp: new Date().toISOString(),\n eventType: \"action_taken\",\n content: { action: \"session_end\", agentId: ctx.currentAgentIdRef.value },\n });\n } catch {\n // Non-fatal\n }\n }\n\n // 4. Compaction on session end\n if (isStaleLifecycleGeneration(ctx)) {\n clearSessionState(sessionKey);\n return;\n }\n if (ctx.cfg.memoryTiering.enabled && ctx.cfg.memoryTiering.compactionOnSessionEnd) {\n try {\n const counts = ctx.factsDb.runCompaction({\n inactivePreferenceDays: ctx.cfg.memoryTiering.inactivePreferenceDays,\n hotMaxTokens: ctx.cfg.memoryTiering.hotMaxTokens,\n hotMaxFacts: ctx.cfg.memoryTiering.hotMaxFacts,\n coldAfterInactivityDays: ctx.cfg.memoryTiering.coldAfterInactivityDays,\n hotMinAccessCount: ctx.cfg.memoryTiering.hotMinAccessCount,\n hotAccessWindowDays: ctx.cfg.memoryTiering.hotAccessWindowDays,\n hotPreferenceImportance: ctx.cfg.memoryTiering.hotPreferenceImportance,\n hotByRecallWindowDays: ctx.cfg.memoryTiering.hotByRecall.windowDays,\n hotByRecallTopN: ctx.cfg.memoryTiering.hotByRecall.topN,\n structuralByCategoryEnabled: ctx.cfg.memoryTiering.structuralByCategory,\n structuralPermanentEnabled: ctx.cfg.memoryTiering.structuralPermanent,\n });\n if (counts.hot + counts.warm + counts.cold > 0) {\n api.logger.info?.(`memory-hybrid: tier compaction — hot=${counts.hot} warm=${counts.warm} cold=${counts.cold}`);\n }\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"compaction\",\n subsystem: \"memory-tiering\",\n });\n api.logger.warn(`memory-hybrid: compaction failed: ${err}`);\n }\n }\n }\n if (abortIfSuperseded(\"post-compaction\")) {\n clearSessionState(sessionKey);\n return;\n }\n\n // 5. Centralized session state cleanup (Issue #463)\n // Moved here to ensure it only runs after compaction and supersession checks\n clearSessionState(sessionKey);\n api.logger.debug?.(`memory-hybrid: cleared all session state for ${sessionKey}`);\n\n // 6. Auto-capture from conversation messages\n if (isStaleLifecycleGeneration(ctx)) {\n clearSessionState(sessionKey);\n return;\n }\n if (ctx.cfg.autoCapture && ev.success && messages.length > 0) {\n try {\n const captureProvenance = resolveCaptureProvenance(event, api, sessionKey);\n if (!captureProvenance.shouldAutoCapture) {\n api.logger.debug?.(\n `memory-hybrid: skipped conversational auto-capture for ${captureProvenance.origin} session (${captureProvenance.reason ?? \"provenance blocked\"})`,\n );\n }\n\n const candidates: Array<{ role: \"user\" | \"assistant\"; text: string; sourceTurn: number }> = [];\n for (let turnIndex = 0; turnIndex < (messages as unknown[]).length; turnIndex++) {\n const msg = (messages as unknown[])[turnIndex];\n if (!msg || typeof msg !== \"object\") continue;\n const msgObj = msg as Record<string, unknown>;\n const role = msgObj.role;\n if (role !== \"user\" && role !== \"assistant\") continue;\n const content = msgObj.content;\n if (typeof content === \"string\") {\n candidates.push({ role, text: content, sourceTurn: turnIndex + 1 });\n continue;\n }\n if (Array.isArray(content)) {\n for (const block of content) {\n if (\n block &&\n typeof block === \"object\" &&\n \"type\" in block &&\n (block as Record<string, unknown>).type === \"text\" &&\n \"text\" in block &&\n typeof (block as Record<string, unknown>).text === \"string\"\n ) {\n candidates.push({\n role,\n text: (block as Record<string, unknown>).text as string,\n sourceTurn: turnIndex + 1,\n });\n }\n }\n }\n }\n const toCapture = captureProvenance.shouldAutoCapture\n ? candidates.filter((candidate) => candidate.text && ctx.shouldCapture(candidate.text))\n : [];\n if (toCapture.length > 0) {\n let stored = 0;\n const classifyModel = ctx.cfg.store.classifyModel ?? getDefaultCronModel(getCronModelConfig(ctx.cfg), \"nano\");\n const classifyMicroBatch = Math.max(1, Math.min(10, ctx.cfg.autoClassify?.batchSize ?? 10));\n\n type CapturePrepared = {\n candidate: (typeof toCapture)[number];\n textToStore: string;\n category: MemoryCategory;\n extracted: ReturnType<typeof extractStructuredFields>;\n summary: string | undefined;\n vector: number[] | undefined;\n similarFacts: MemoryEntry[];\n };\n\n const prepared: CapturePrepared[] = [];\n for (const candidate of toCapture.slice(0, 3)) {\n if (abortIfSuperseded(\"auto-capture-prepare\")) {\n clearSessionState(sessionKey);\n return;\n }\n let textToStore = candidate.text;\n textToStore = truncateForStorage(textToStore, ctx.cfg.captureMaxChars);\n const category: MemoryCategory = ctx.detectCategory(textToStore);\n const extracted = extractStructuredFields(textToStore, category);\n if (ctx.factsDb.hasDuplicate(textToStore, \"auto-capture\")) {\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"auto-capture:duplicate\",\n target: textToStore.slice(0, 80),\n outcome: \"skipped\",\n sessionId: captureProvenance.sessionId ?? undefined,\n context: { category },\n });\n continue;\n }\n const summaryThreshold = ctx.cfg.autoRecall.summaryThreshold;\n const summary =\n summaryThreshold > 0 && textToStore.length > summaryThreshold\n ? `${textToStore.slice(0, ctx.cfg.autoRecall.summaryMaxChars).trim()}…`\n : undefined;\n let vector: number[] | undefined;\n if (ctx.cfg.retrieval.strategies.includes(\"semantic\")) {\n try {\n vector = await ctx.embeddings.embed(textToStore);\n } catch (err) {\n const asErr = err instanceof Error ? err : new Error(String(err));\n if (!suppressCaptureStageError(ctx, api, asErr) && !isOllamaCircuitBreakerOpen(asErr)) {\n capturePluginError(asErr, {\n operation: \"auto-capture-embedding\",\n subsystem: \"auto-capture\",\n });\n }\n if (!suppressCaptureStageError(ctx, api, asErr)) {\n api.logger.warn(`memory-hybrid: auto-capture embedding failed: ${err}`);\n }\n }\n }\n let similarFacts: MemoryEntry[] = [];\n if (ctx.cfg.store.classifyBeforeWrite) {\n similarFacts = vector\n ? await ctx.findSimilarByEmbedding(ctx.vectorDb, ctx.factsDb, vector, 3, 0.3, {\n scope: \"global\",\n scopeTarget: null,\n })\n : [];\n if (similarFacts.length === 0) {\n similarFacts = ctx.factsDb.findSimilarForClassification(\n textToStore,\n extracted.entity,\n extracted.key,\n 3,\n \"global\",\n null,\n );\n }\n }\n prepared.push({ candidate, textToStore, category, extracted, summary, vector, similarFacts });\n }\n\n const classificationByIndex = new Map<number, MemoryClassification>();\n if (ctx.cfg.store.classifyBeforeWrite) {\n const withSimilar = prepared\n .map((p, i) => (p.similarFacts.length > 0 ? i : -1))\n .filter((i): i is number => i >= 0);\n for (let s = 0; s < withSimilar.length; s += classifyMicroBatch) {\n const idxs = withSimilar.slice(s, s + classifyMicroBatch);\n const inputs = idxs.map((pi) => ({\n candidateText: prepared[pi].textToStore,\n candidateEntity: prepared[pi].extracted.entity,\n candidateKey: prepared[pi].extracted.key,\n existingFacts: prepared[pi].similarFacts,\n }));\n const outs = await classifyMemoryOperationsBatch(inputs, ctx.openai, classifyModel, api.logger);\n idxs.forEach((pi, j) => {\n classificationByIndex.set(pi, outs[j]);\n });\n }\n }\n\n for (let pi = 0; pi < prepared.length; pi++) {\n if (abortIfSuperseded(\"auto-capture-store\")) {\n clearSessionState(sessionKey);\n return;\n }\n const { candidate, textToStore, category, extracted, summary, vector, similarFacts } = prepared[pi];\n if (ctx.cfg.store.classifyBeforeWrite) {\n if (similarFacts.length > 0) {\n try {\n let classification = classificationByIndex.get(pi);\n if (!classification) {\n api.logger.warn?.(\n `memory-hybrid: auto-capture missing batch classification for index ${pi}; falling back to single-call classify`,\n );\n classification = await classifyMemoryOperation(\n textToStore,\n extracted.entity,\n extracted.key,\n similarFacts,\n ctx.openai,\n classifyModel,\n api.logger,\n );\n }\n if (classification.action === \"NOOP\") {\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"auto-capture:noop\",\n target: textToStore.slice(0, 80),\n outcome: \"skipped\",\n sessionId: captureProvenance.sessionId ?? undefined,\n context: { reason: classification.reason ?? \"no-op\", category },\n });\n continue;\n }\n if (classification.action === \"DELETE\" && classification.targetId) {\n const target = validateScopedClassificationTarget({\n targetId: classification.targetId,\n candidates: similarFacts,\n getById: (id) => ctx.factsDb.getById(id),\n scope: \"global\",\n scopeTarget: null,\n warn: (message) => api.logger.warn?.(message),\n warnMessage: `memory-hybrid: blocked cross-scope or unknown auto-capture DELETE target ${classification.targetId}`,\n });\n if (!target) continue;\n ctx.factsDb.supersede(classification.targetId, null);\n ctx.aliasDb?.deleteByFactId(classification.targetId);\n await deleteVectorForFactId({\n vectorDb: ctx.vectorDb,\n factId: classification.targetId,\n logger: api.logger,\n context: \"stage-capture-delete-action\",\n });\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"auto-capture:delete\",\n target: classification.targetId,\n outcome: \"success\",\n sessionId: captureProvenance.sessionId ?? undefined,\n context: { reason: classification.reason ?? \"delete\", textPreview: textToStore.slice(0, 80) },\n });\n api.logger.info?.(`memory-hybrid: auto-capture DELETE — retracted ${classification.targetId}`);\n continue;\n }\n if (classification.action === \"UPDATE\" && classification.targetId) {\n const oldFact = validateScopedClassificationTarget({\n targetId: classification.targetId,\n candidates: similarFacts,\n getById: (id) => ctx.factsDb.getById(id),\n scope: \"global\",\n scopeTarget: null,\n warn: (message) => api.logger.warn?.(message),\n warnMessage: `memory-hybrid: blocked cross-scope auto-capture UPDATE target ${classification.targetId}`,\n });\n if (oldFact) {\n const preservedScope = oldFact.scope ?? \"global\";\n const preservedScopeTarget = preservedScope === \"global\" ? null : (oldFact.scopeTarget ?? null);\n if (preservedScope !== \"global\" && !preservedScopeTarget) {\n api.logger.warn?.(\n `memory-hybrid: blocked auto-capture UPDATE target ${classification.targetId} due to missing non-global scopeTarget`,\n );\n continue;\n }\n const finalImportance = Math.max(0.7, oldFact.importance);\n const walEntryId = await ctx.walWrite(\n \"update\",\n {\n text: textToStore,\n category,\n importance: finalImportance,\n entity: extracted.entity || oldFact.entity,\n key: extracted.key || oldFact.key,\n value: extracted.value || oldFact.value,\n source: \"auto-capture\",\n decayClass: oldFact.decayClass,\n summary,\n tags: extractTags(textToStore, extracted.entity),\n provenanceSession: captureProvenance.sessionId,\n sourceTurn: candidate.sourceTurn,\n extractionMethod: getAutoCaptureExtractionMethod(candidate.role, captureProvenance),\n extractionConfidence: getAutoCaptureExtractionConfidence(candidate.role),\n vector,\n embeddingModelName: vector ? ctx.embeddings.modelName : undefined,\n },\n api.logger,\n classification.targetId,\n );\n const nowSec = Math.floor(Date.now() / 1000);\n const storeResult = ctx.factsDb.storeWithResult({\n text: textToStore,\n category,\n importance: finalImportance,\n entity: extracted.entity || oldFact.entity,\n key: extracted.key || oldFact.key,\n value: extracted.value || oldFact.value,\n source: \"auto-capture\",\n decayClass: oldFact.decayClass,\n summary,\n tags: extractTags(textToStore, extracted.entity),\n validFrom: nowSec,\n supersedesId: classification.targetId,\n scope: preservedScope,\n scopeTarget: preservedScopeTarget,\n provenanceSession: captureProvenance.sessionId,\n sourceTurn: candidate.sourceTurn,\n extractionMethod: getAutoCaptureExtractionMethod(candidate.role, captureProvenance),\n extractionConfidence: getAutoCaptureExtractionConfidence(candidate.role),\n });\n if (storeResult.skipped) {\n await ctx.walRemove(walEntryId, api.logger);\n continue;\n }\n const newEntry = storeResult.entry;\n // CRITICAL FIX (#2): Delete vector for evicted fact to prevent orphaned vectors\n await cleanupEvictedVector({\n vectorDb: ctx.vectorDb,\n evictedFactId: storeResult.evictedFactId,\n logger: api.logger,\n context: \"stage-capture\",\n });\n ctx.factsDb.supersede(classification.targetId, newEntry.id);\n ctx.aliasDb?.deleteByFactId(classification.targetId);\n await deleteVectorForFactId({\n vectorDb: ctx.vectorDb,\n factId: classification.targetId,\n logger: api.logger,\n context: \"stage-capture-update-superseded\",\n });\n try {\n if (storeResult.embeddingStale || vector) {\n // `storeWithResult()` can return an existing deduped fact whose text\n // differs from `textToStore`; keep vector content aligned to stored text.\n const canonicalText = newEntry.text;\n const canonicalVector =\n vector && canonicalText === textToStore ? vector : await ctx.embeddings.embed(canonicalText);\n ctx.factsDb.setEmbeddingModel(newEntry.id, ctx.embeddings.modelName);\n if (storeResult.embeddingStale || !(await ctx.vectorDb.hasDuplicate(canonicalVector))) {\n await ctx.vectorDb.store({\n text: canonicalText,\n vector: canonicalVector,\n importance: finalImportance,\n category,\n id: newEntry.id,\n });\n }\n persistCanonicalFactEmbedding(\n ctx.factsDb,\n newEntry.id,\n ctx.embeddings.modelName,\n canonicalVector,\n \"auto-capture-fact-embeddings\",\n \"auto-capture\",\n api.logger.warn?.bind(api.logger),\n );\n }\n } catch (vecErr) {\n capturePluginError(vecErr instanceof Error ? vecErr : new Error(String(vecErr)), {\n operation: storeResult.embeddingStale\n ? \"auto-capture-stale-vector-update\"\n : \"auto-capture-vector-update\",\n subsystem: \"auto-capture\",\n });\n api.logger.warn(\n storeResult.embeddingStale\n ? `memory-hybrid: stale vector re-embed failed for merged fact ${newEntry.id.slice(0, 8)} — LanceDB vector encodes pre-merge text; nightly re-index will repair: ${vecErr}`\n : `memory-hybrid: vector capture failed: ${vecErr}`,\n );\n }\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"auto-capture:updated\",\n target: newEntry.id,\n outcome: \"success\",\n sessionId: captureProvenance.sessionId ?? undefined,\n context: { supersededId: classification.targetId, category, entity: extracted.entity },\n });\n api.logger.info?.(\n `memory-hybrid: auto-capture UPDATE — superseded ${classification.targetId} with ${newEntry.id}`,\n );\n stored++;\n await ctx.walRemove(walEntryId, api.logger);\n continue;\n } // close if (oldFact) guard\n // Validation failed: fall through to default ADD-style store path\n }\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"auto-capture-classification\",\n subsystem: \"auto-capture\",\n });\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"auto-capture:classification-error\",\n outcome: \"failed\",\n error: String(err).slice(0, 200),\n sessionId: captureProvenance.sessionId ?? undefined,\n });\n api.logger.warn(`memory-hybrid: auto-capture classification failed: ${err}`);\n }\n }\n }\n }\n const walEntryId = await ctx.walWrite(\n \"store\",\n {\n text: textToStore,\n category,\n importance: CLI_STORE_IMPORTANCE,\n entity: extracted.entity,\n key: extracted.key,\n value: extracted.value,\n source: \"auto-capture\",\n summary,\n tags: extractTags(textToStore, extracted.entity),\n provenanceSession: captureProvenance.sessionId,\n sourceTurn: candidate.sourceTurn,\n extractionMethod: getAutoCaptureExtractionMethod(candidate.role, captureProvenance),\n extractionConfidence: getAutoCaptureExtractionConfidence(candidate.role),\n vector,\n embeddingModelName: vector ? ctx.embeddings.modelName : undefined,\n },\n api.logger,\n );\n const storeResult = ctx.factsDb.storeWithResult({\n text: textToStore,\n category,\n importance: CLI_STORE_IMPORTANCE,\n entity: extracted.entity,\n key: extracted.key,\n value: extracted.value,\n source: \"auto-capture\",\n summary,\n tags: extractTags(textToStore, extracted.entity),\n provenanceSession: captureProvenance.sessionId,\n sourceTurn: candidate.sourceTurn,\n extractionMethod: getAutoCaptureExtractionMethod(candidate.role, captureProvenance),\n extractionConfidence: getAutoCaptureExtractionConfidence(candidate.role),\n });\n const storedEntry = storeResult.entry;\n // Guard: skip post-store ops when pre-store guard blocked the write (#1560, #1561)\n if (!storeResult.skipped) {\n await cleanupEvictedVector({\n vectorDb: ctx.vectorDb,\n evictedFactId: storeResult.evictedFactId,\n logger: api.logger,\n context: \"stage-capture\",\n });\n try {\n if (storeResult.embeddingStale) {\n // Merge case: the existing fact's text was updated in-place.\n // Re-embed the merged text and force-replace the stale LanceDB vector.\n // If embed fails, the vector encodes stale pre-merge text; the dream-cycle\n // re-index will repair it on the next nightly run.\n const mergedVector = await ctx.embeddings.embed(storedEntry.text);\n ctx.factsDb.setEmbeddingModel(storedEntry.id, ctx.embeddings.modelName);\n await ctx.vectorDb.store({\n text: storedEntry.text,\n vector: mergedVector,\n importance: CLI_STORE_IMPORTANCE,\n category,\n id: storedEntry.id,\n });\n persistCanonicalFactEmbedding(\n ctx.factsDb,\n storedEntry.id,\n ctx.embeddings.modelName,\n mergedVector,\n \"auto-capture-fact-embeddings\",\n \"auto-capture\",\n api.logger.warn?.bind(api.logger),\n );\n } else if (vector) {\n const canonicalText = storedEntry.text;\n const canonicalVector =\n canonicalText === textToStore ? vector : await ctx.embeddings.embed(canonicalText);\n ctx.factsDb.setEmbeddingModel(storedEntry.id, ctx.embeddings.modelName);\n if (!(await ctx.vectorDb.hasDuplicate(canonicalVector))) {\n await ctx.vectorDb.store({\n text: canonicalText,\n vector: canonicalVector,\n importance: CLI_STORE_IMPORTANCE,\n category,\n id: storedEntry.id,\n });\n }\n persistCanonicalFactEmbedding(\n ctx.factsDb,\n storedEntry.id,\n ctx.embeddings.modelName,\n canonicalVector,\n \"auto-capture-fact-embeddings\",\n \"auto-capture\",\n api.logger.warn?.bind(api.logger),\n );\n }\n } catch (vecErr) {\n if (!suppressCaptureStageError(ctx, api, vecErr)) {\n capturePluginError(vecErr instanceof Error ? vecErr : new Error(String(vecErr)), {\n operation: storeResult.embeddingStale\n ? \"auto-capture-stale-vector-store\"\n : \"auto-capture-vector-store\",\n subsystem: \"auto-capture\",\n });\n api.logger.warn(\n storeResult.embeddingStale\n ? `memory-hybrid: stale vector re-embed failed for merged fact ${storedEntry.id.slice(0, 8)} — LanceDB vector encodes pre-merge text; nightly re-index will repair: ${vecErr}`\n : `memory-hybrid: vector capture failed: ${vecErr}`,\n );\n }\n }\n stored++;\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"auto-capture:stored\",\n target: storedEntry.id,\n outcome: \"success\",\n sessionId: captureProvenance.sessionId ?? undefined,\n context: { category, entity: extracted.entity, role: candidate.role },\n });\n }\n await ctx.walRemove(walEntryId, api.logger);\n }\n if (stored > 0) api.logger.info(`memory-hybrid: auto-captured ${stored} memories`);\n }\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"auto-capture\",\n subsystem: \"auto-capture\",\n });\n api.logger.warn(`memory-hybrid: capture failed: ${String(err)}`);\n }\n }\n }\n\n // 6b. Episodic memory auto-capture (#781): scan conversation for outcome-indicating phrases\n // and create episode records. This runs regardless of autoCapture config flag, because\n // capturing outcomes is low-cost and high-value for the episodic history.\n if (isStaleLifecycleGeneration(ctx)) {\n clearSessionState(sessionKey);\n return;\n }\n {\n if (abortIfSuperseded(\"episodic-capture\")) {\n clearSessionState(sessionKey);\n return;\n }\n const sessionId = sessionKey;\n const agentId = ctx.currentAgentIdRef.value ?? undefined;\n // Collect all text from the session for scanning\n const sessionTexts: Array<{ text: string; turnIndex: number }> = [];\n for (let turnIndex = 0; turnIndex < (messages as unknown[]).length; turnIndex++) {\n const msg = (messages as unknown[])[turnIndex];\n if (!msg || typeof msg !== \"object\") continue;\n const msgObj = msg as Record<string, unknown>;\n const content = msgObj.content;\n if (typeof content === \"string\") {\n sessionTexts.push({ text: content, turnIndex });\n } else if (Array.isArray(content)) {\n for (const block of content) {\n if (\n block &&\n typeof block === \"object\" &&\n \"text\" in block &&\n typeof (block as Record<string, unknown>).text === \"string\"\n ) {\n sessionTexts.push({ text: (block as Record<string, unknown>).text as string, turnIndex });\n }\n }\n }\n }\n\n for (const { text } of sessionTexts) {\n if (abortIfSuperseded(\"episodic-capture-loop\")) {\n clearSessionState(sessionKey);\n return;\n }\n // Scan for success indicators\n for (const pattern of SUCCESS_PATTERNS) {\n const match = pattern.regex.exec(text);\n if (match) {\n const eventText = pattern.label ? `Agent reported: ${pattern.label}` : match[0];\n const existing = ctx.factsDb.searchEpisodes({\n query: eventText,\n since: Math.floor(Date.now() / 1000) - 300, // within last 5 min\n limit: 1,\n });\n if (existing.length === 0) {\n try {\n const episode = ctx.factsDb.recordEpisode({\n event: eventText,\n outcome: \"success\",\n timestamp: Math.floor(Date.now() / 1000),\n context: text.slice(0, 500),\n sessionId,\n agentId,\n scope: \"session\",\n scopeTarget: sessionId,\n tags: pattern.label ? [pattern.label] : [],\n });\n api.logger.debug?.(`memory-hybrid: auto-captured success episode: ${episode.id}`);\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"episode-auto-capture-success\",\n subsystem: \"episodes\",\n severity: \"info\",\n });\n }\n }\n }\n break; // only one episode per message\n }\n }\n\n // Scan for failure indicators\n for (const pattern of FAILURE_PATTERNS) {\n const match = pattern.regex.exec(text);\n if (match) {\n const eventText = pattern.label ? `Agent reported: ${pattern.label}` : match[0];\n const existing = ctx.factsDb.searchEpisodes({\n query: eventText,\n since: Math.floor(Date.now() / 1000) - 300,\n limit: 1,\n });\n if (existing.length === 0) {\n try {\n const episode = ctx.factsDb.recordEpisode({\n event: eventText,\n outcome: \"failure\",\n timestamp: Math.floor(Date.now() / 1000),\n context: text.slice(0, 500),\n sessionId,\n agentId,\n scope: \"session\",\n scopeTarget: sessionId,\n tags: pattern.label ? [pattern.label] : [],\n // failures get importance >= 0.8 automatically via recordEpisode\n });\n api.logger.debug?.(`memory-hybrid: auto-captured failure episode: ${episode.id}`);\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"episode-auto-capture-failure\",\n subsystem: \"episodes\",\n severity: \"info\",\n });\n }\n }\n }\n break;\n }\n }\n }\n }\n\n // 7. Credential auto-detect: persist hint for next turn\n if (isStaleLifecycleGeneration(ctx)) {\n clearSessionState(sessionKey);\n return;\n }\n if (\n ctx.cfg.credentials.enabled &&\n ctx.cfg.credentials.autoDetect &&\n ctx.cfg.verbosity !== \"silent\" &&\n messages.length > 0\n ) {\n if (abortIfSuperseded(\"credential-hint-capture\")) {\n clearSessionState(sessionKey);\n return;\n }\n const pendingPath = join(dirname(ctx.resolvedSqlitePath), \"credentials-pending.json\");\n try {\n const texts: string[] = [];\n for (const msg of messages as unknown[]) {\n if (!msg || typeof msg !== \"object\") continue;\n const msgObj = msg as Record<string, unknown>;\n const content = msgObj.content;\n if (typeof content === \"string\") texts.push(content);\n else if (Array.isArray(content)) {\n for (const block of content) {\n if (\n block &&\n typeof block === \"object\" &&\n \"type\" in block &&\n (block as Record<string, unknown>).type === \"text\" &&\n \"text\" in block\n ) {\n const t = (block as Record<string, unknown>).text;\n if (typeof t === \"string\") texts.push(t);\n }\n }\n }\n }\n const allText = texts.join(\"\\n\");\n const detected = detectCredentialPatterns(allText);\n if (detected.length > 0) {\n // Write atomically (temp-then-rename) to avoid partial state on crash.\n atomicWriteFile(\n pendingPath,\n JSON.stringify({\n hints: detected.map((d) => d.hint),\n at: Date.now(),\n }),\n );\n api.logger.info(\n `memory-hybrid: credential patterns detected (${detected.map((d) => d.hint).join(\", \")}) — will prompt next turn`,\n );\n }\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"credential-auto-detect\",\n subsystem: \"credentials\",\n });\n api.logger.warn(`memory-hybrid: credential auto-detect failed: ${err}`);\n }\n }\n }\n\n // 8. Tool-call credential auto-capture\n if (isStaleLifecycleGeneration(ctx)) {\n clearSessionState(sessionKey);\n return;\n }\n if (ctx.cfg.credentials.enabled && ctx.cfg.credentials.autoCapture?.toolCalls && messages.length > 0) {\n if (abortIfSuperseded(\"credential-tool-call-capture\")) {\n clearSessionState(sessionKey);\n return;\n }\n const logCaptures = ctx.cfg.credentials.autoCapture.logCaptures !== false;\n try {\n for (const msg of messages as unknown[]) {\n if (abortIfSuperseded(\"credential-tool-call-loop\")) {\n clearSessionState(sessionKey);\n return;\n }\n if (!msg || typeof msg !== \"object\") continue;\n const msgObj = msg as Record<string, unknown>;\n if (msgObj.role !== \"assistant\") continue;\n const toolCalls = msgObj.tool_calls;\n if (!Array.isArray(toolCalls)) continue;\n for (const tc of toolCalls) {\n if (!tc || typeof tc !== \"object\") continue;\n const tcObj = tc as Record<string, unknown>;\n const fn = tcObj.function as Record<string, unknown> | undefined;\n if (!fn) continue;\n const args = fn.arguments;\n if (typeof args !== \"string\" || args.length === 0) continue;\n let parsedArgs: Record<string, unknown> = {};\n try {\n parsedArgs = JSON.parse(args);\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err as Error, {\n operation: \"json-parse-tool-args\",\n severity: \"info\",\n subsystem: \"lifecycle\",\n });\n }\n }\n const argsToScan = Object.values(parsedArgs)\n .filter((v): v is string => typeof v === \"string\")\n .join(\" \");\n const creds = extractCredentialsFromToolCalls(argsToScan || args);\n for (const cred of creds) {\n if (ctx.credentialsDb) {\n const stored = ctx.credentialsDb.storeIfNew({\n service: cred.service,\n type: cred.type,\n value: cred.value,\n url: cred.url,\n notes: cred.notes,\n });\n if (stored && logCaptures) {\n api.logger.info(`memory-hybrid: auto-captured credential for ${cred.service} (${cred.type})`);\n }\n } else {\n const text = `Credential for ${cred.service} (${cred.type})${cred.url ? ` — ${cred.url}` : \"\"}${cred.notes ? `. ${cred.notes}` : \"\"}.`;\n const storeResult = ctx.factsDb.storeWithResult({\n text,\n category: \"technical\" as MemoryCategory,\n importance: 0.9,\n entity: \"Credentials\",\n key: cred.service,\n value: cred.value,\n source: \"conversation\",\n decayClass: \"permanent\",\n tags: [\"auth\", \"credential\"],\n });\n if (storeResult.skipped) {\n continue;\n }\n const entry = storeResult.entry;\n // Guard: skip post-store ops when pre-store guard blocked the write (#1560, #1561)\n if (!storeResult.skipped) {\n // CRITICAL FIX (#2): Delete vector for evicted fact to prevent orphaned vectors\n await cleanupEvictedVector({\n vectorDb: ctx.vectorDb,\n evictedFactId: storeResult.evictedFactId,\n logger: api.logger,\n context: \"stage-capture\",\n });\n if (ctx.cfg.retrieval.strategies.includes(\"semantic\")) {\n try {\n if (storeResult.embeddingStale) {\n // Merge case: re-embed the merged text to keep the vector in sync.\n // If embed fails, the vector encodes stale pre-merge text; nightly re-index will repair.\n const mergedVector = await ctx.embeddings.embed(entry.text);\n ctx.factsDb.setEmbeddingModel(entry.id, ctx.embeddings.modelName);\n await ctx.vectorDb.store({\n text: entry.text,\n vector: mergedVector,\n importance: 0.9,\n category: \"technical\",\n id: entry.id,\n });\n persistCanonicalFactEmbedding(\n ctx.factsDb,\n entry.id,\n ctx.embeddings.modelName,\n mergedVector,\n \"auto-capture-fact-embeddings\",\n \"auto-capture\",\n api.logger.warn?.bind(api.logger),\n );\n } else {\n const vector = await ctx.embeddings.embed(entry.text);\n ctx.factsDb.setEmbeddingModel(entry.id, ctx.embeddings.modelName);\n if (!(await ctx.vectorDb.hasDuplicate(vector))) {\n await ctx.vectorDb.store({\n text: entry.text,\n vector,\n importance: 0.9,\n category: \"technical\",\n id: entry.id,\n });\n persistCanonicalFactEmbedding(\n ctx.factsDb,\n entry.id,\n ctx.embeddings.modelName,\n vector,\n \"auto-capture-fact-embeddings\",\n \"auto-capture\",\n api.logger.warn?.bind(api.logger),\n );\n }\n }\n } catch (err) {\n const asErr = err instanceof Error ? err : new Error(String(err));\n if (!suppressCaptureStageError(ctx, api, asErr) && !isOllamaCircuitBreakerOpen(asErr)) {\n capturePluginError(asErr, {\n operation: storeResult.embeddingStale\n ? \"tool-call-credential-stale-vector-update\"\n : \"tool-call-credential-vector-store\",\n subsystem: \"credentials\",\n });\n }\n if (!suppressCaptureStageError(ctx, api, asErr)) {\n api.logger.warn(\n storeResult.embeddingStale\n ? `memory-hybrid: stale vector re-embed failed for merged credential fact ${entry.id.slice(0, 8)} — nightly re-index will repair: ${err}`\n : `memory-hybrid: vector store for credential fact failed: ${err}`,\n );\n }\n }\n }\n if (logCaptures) {\n api.logger.info(`memory-hybrid: auto-captured credential for ${cred.service} (${cred.type})`);\n }\n } // close if (!storeResult.skipped) guard (#1560, #1561)\n }\n }\n }\n }\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"tool-call-credential-auto-capture\",\n subsystem: \"credentials\",\n });\n const errMsg = err instanceof Error ? err.stack || err.message : String(err);\n api.logger.warn(`memory-hybrid: tool-call credential auto-capture failed: ${errMsg}`);\n }\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"run-capture.js","names":["msgObj","tcObj"],"sources":["../../../lifecycle/stage-capture/run-capture.ts"],"sourcesContent":["/**\n * Lifecycle stage: Capture (Phase 2.3).\n * On agent_end: frustration assistant capture, event log session_end, clearSessionState,\n * compaction (if enabled), autoCapture, credential hint, tool-call credential capture.\n * Single timeout: 60s.\n */\n\nimport { dirname, join } from \"node:path\";\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport { getCronModelConfig, getDefaultCronModel } from \"../../config/index.js\";\nimport type { MemoryCategory } from \"../../config.js\";\nimport \"../../config.js\";\nimport { detectCredentialPatterns } from \"../../services/auto-capture.js\";\nimport {\n getAutoCaptureExtractionConfidence,\n getAutoCaptureExtractionMethod,\n resolveCaptureProvenance,\n} from \"../../services/capture-provenance.js\";\nimport {\n classifyMemoryOperation,\n classifyMemoryOperationsBatch,\n type MemoryClassification,\n} from \"../../services/classification.js\";\nimport { validateScopedClassificationTarget } from \"../../services/classification-scope.js\";\nimport { extractCredentialsFromToolCalls } from \"../../services/credential-scanner.js\";\nimport { isOllamaCircuitBreakerOpen } from \"../../services/embeddings.js\";\nimport { capturePluginError } from \"../../services/error-reporter.js\";\nimport { extractStructuredFields } from \"../../services/fact-extraction.js\";\nimport { formatQualityLoopEntry, runHumanizerScore } from \"../../services/humanizer-score.js\";\nimport { cleanupEvictedVector, deleteVectorForFactId } from \"../../services/vector-maintenance.js\";\nimport type { MemoryEntry } from \"../../types/memory.js\";\nimport { atomicWriteFile } from \"../../utils/atomic-write.js\";\nimport { CLI_STORE_IMPORTANCE } from \"../../utils/constants.js\";\nimport { persistCanonicalFactEmbedding } from \"../../utils/fact-embeddings.js\";\nimport { isStaleLifecycleGeneration } from \"../../utils/lifecycle-generation.js\";\nimport { isRecallContextSuperseded, shouldSuppressStaleLifecycleError } from \"../../utils/registration-superseded.js\";\nimport { extractTags } from \"../../utils/tags.js\";\nimport { truncateForStorage } from \"../../utils/text.js\";\nimport { resolveAgentIdFromHookEvent } from \"../resolve-agent-id.js\";\nimport type { LifecycleContext, SessionState } from \"../types.js\";\n\nconst _CAPTURE_STAGE_TIMEOUT_MS = 60_000;\n\nfunction suppressCaptureStageError(ctx: LifecycleContext, api: ClawdbotPluginApi, err: unknown): boolean {\n if (!shouldSuppressStaleLifecycleError(ctx, err)) return false;\n api.logger.debug?.(\"memory-hybrid: capture skipped (registration superseded during reload)\");\n return true;\n}\n\n/** Outcome indicator patterns for episodic memory auto-capture (#781). */\ninterface OutcomePattern {\n regex: RegExp;\n label?: string;\n}\n\n/** Patterns that indicate a successful outcome. */\nconst SUCCESS_PATTERNS: OutcomePattern[] = [\n // Git merge / PR merge\n { regex: /✅\\s*(?:merged|Merge)/i, label: \"merged\" },\n { regex: /\\b(?:successfully\\s+)?(?:merged|Merge)\\b/i, label: \"merged\" },\n // Checkmark / success\n { regex: /✅/i, label: \"success\" },\n // Explicit success language\n { regex: /\\bsucceeded\\b/i, label: \"succeeded\" },\n { regex: /\\bcompleted(?:\\s+successfully)?\\b/i, label: \"completed\" },\n { regex: /\\bfixed\\b/i, label: \"fixed\" },\n { regex: /\\bpassed\\b/i, label: \"passed\" },\n { regex: /\\bdeployed\\b/i, label: \"deployed\" },\n { regex: /\\bresolved\\b/i, label: \"resolved\" },\n];\n\n/** Patterns that indicate a failed outcome. */\nconst FAILURE_PATTERNS: OutcomePattern[] = [\n // Cross mark\n { regex: /❌/i, label: \"failed\" },\n // Explicit failure\n { regex: /\\bfailed\\b/i, label: \"failed\" },\n { regex: /\\bfailure\\b/i, label: \"failure\" },\n { regex: /\\bFAILED\\b/i, label: \"failed\" },\n // Error\n { regex: /\\berror\\b/i, label: \"error\" },\n { regex: /\\bcrashed\\b/i, label: \"crashed\" },\n { regex: /\\bbroke\\b/i, label: \"broke\" },\n { regex: /\\bbug\\b/i, label: \"bug\" },\n { regex: /\\brejected\\b/i, label: \"rejected\" },\n { regex: /\\bdenied\\b/i, label: \"denied\" },\n { regex: /\\brevert(?:ed)?\\b/i, label: \"reverted\" },\n { regex: /\\brollback\\b/i, label: \"rollback\" },\n];\n\n/**\n * Extract text content from the last assistant message in a message array.\n * Returns undefined if no assistant message is found or if the content is empty.\n */\nfunction extractLastAssistantText(messages: unknown[]): string | undefined {\n const assistantMsgs = messages.filter(\n (m) => m && typeof m === \"object\" && (m as { role?: string }).role === \"assistant\",\n );\n const lastAssistant = assistantMsgs[assistantMsgs.length - 1] as { content?: unknown } | undefined;\n if (!lastAssistant) return undefined;\n\n if (typeof lastAssistant.content === \"string\") {\n return lastAssistant.content;\n }\n if (Array.isArray(lastAssistant.content)) {\n const textBlocks: string[] = [];\n for (const block of lastAssistant.content) {\n if (\n block &&\n typeof block === \"object\" &&\n \"type\" in block &&\n (block as { type?: string }).type === \"text\" &&\n \"text\" in block &&\n typeof (block as { text?: unknown }).text === \"string\"\n ) {\n textBlocks.push((block as { text: string }).text);\n }\n }\n if (textBlocks.length > 0) return textBlocks.join(\" \");\n }\n return undefined;\n}\n\nexport async function runCapture(\n event: unknown,\n api: ClawdbotPluginApi,\n ctx: LifecycleContext,\n sessionState: SessionState,\n): Promise<void> {\n const { resolveSessionKey, clearSessionState, frustrationStateMap } = sessionState;\n const sessionKey = resolveSessionKey(event, api) ?? ctx.currentAgentIdRef.value ?? \"default\";\n\n if (isStaleLifecycleGeneration(ctx)) {\n clearSessionState(sessionKey);\n return;\n }\n const abortIfSuperseded = (phase: string): boolean => {\n if (!isRecallContextSuperseded(ctx)) return false;\n api.logger.debug?.(`memory-hybrid: capture skipped (registration superseded during reload) phase=${phase}`);\n return true;\n };\n\n if (abortIfSuperseded(\"start\")) {\n clearSessionState(sessionKey);\n return;\n }\n\n const ev = event as { success?: boolean; messages?: unknown[] };\n const messages = ev?.messages ?? [];\n\n const assistantText = messages.length > 0 ? extractLastAssistantText(messages as unknown[]) : undefined;\n\n // 1. Frustration: append last assistant message to session turn history\n if (assistantText?.trim()) {\n try {\n const state = frustrationStateMap.get(sessionKey);\n if (state) {\n state.turns.push({ role: \"assistant\", content: assistantText });\n if (state.turns.length > 20) state.turns.splice(0, state.turns.length - 20);\n frustrationStateMap.set(sessionKey, state);\n }\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"frustration-assistant-capture\",\n subsystem: \"frustration\",\n severity: \"info\",\n });\n }\n }\n }\n\n // 2. Humanizer quality-loop scoring (Issue #616 — Phase 1: evaluator only, no rewriting)\n if (ctx.cfg.humanizer?.enabled && assistantText?.trim()) {\n try {\n const humCfg = ctx.cfg.humanizer;\n const result = await runHumanizerScore(assistantText, {\n bin: humCfg.bin,\n minTextLength: humCfg.minTextLength,\n maxTextLength: humCfg.maxTextLength,\n });\n if (result !== null) {\n const entryText = formatQualityLoopEntry(result, {\n modelTag: humCfg.modelTag,\n skillTag: humCfg.skillTag,\n });\n const storeResult = ctx.factsDb.storeWithResult({\n text: entryText,\n category: \"quality_loop\",\n importance: 0.6,\n entity: null,\n key: null,\n value: null,\n source: \"humanizer\",\n decayClass: \"normal\",\n });\n if (!storeResult.skipped) {\n await cleanupEvictedVector({\n vectorDb: ctx.vectorDb,\n evictedFactId: storeResult.evictedFactId,\n logger: api.logger,\n context: \"humanizer-score\",\n });\n api.logger.debug?.(`memory-hybrid: humanizer_score=${result.score.toFixed(2)} stored`);\n }\n }\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"humanizer-score-capture\",\n subsystem: \"humanizer\",\n severity: \"info\",\n });\n api.logger.debug?.(`memory-hybrid: humanizer scoring skipped: ${String(err)}`);\n }\n }\n }\n if (abortIfSuperseded(\"post-humanizer\")) {\n clearSessionState(sessionKey);\n return;\n }\n\n // 3. Event log session_end\n if (ctx.eventLog) {\n try {\n ctx.eventLog.append({\n sessionId: sessionKey,\n timestamp: new Date().toISOString(),\n eventType: \"action_taken\",\n content: { action: \"session_end\", agentId: ctx.currentAgentIdRef.value },\n });\n } catch {\n // Non-fatal\n }\n }\n\n // 4. Compaction on session end\n if (isStaleLifecycleGeneration(ctx)) {\n clearSessionState(sessionKey);\n return;\n }\n if (ctx.cfg.memoryTiering.enabled && ctx.cfg.memoryTiering.compactionOnSessionEnd) {\n try {\n const counts = ctx.factsDb.runCompaction({\n inactivePreferenceDays: ctx.cfg.memoryTiering.inactivePreferenceDays,\n hotMaxTokens: ctx.cfg.memoryTiering.hotMaxTokens,\n hotMaxFacts: ctx.cfg.memoryTiering.hotMaxFacts,\n coldAfterInactivityDays: ctx.cfg.memoryTiering.coldAfterInactivityDays,\n hotMinAccessCount: ctx.cfg.memoryTiering.hotMinAccessCount,\n hotAccessWindowDays: ctx.cfg.memoryTiering.hotAccessWindowDays,\n hotPreferenceImportance: ctx.cfg.memoryTiering.hotPreferenceImportance,\n hotByRecallWindowDays: ctx.cfg.memoryTiering.hotByRecall.windowDays,\n hotByRecallTopN: ctx.cfg.memoryTiering.hotByRecall.topN,\n structuralByCategoryEnabled: ctx.cfg.memoryTiering.structuralByCategory,\n structuralPermanentEnabled: ctx.cfg.memoryTiering.structuralPermanent,\n });\n if (counts.hot + counts.warm + counts.cold > 0) {\n api.logger.info?.(`memory-hybrid: tier compaction — hot=${counts.hot} warm=${counts.warm} cold=${counts.cold}`);\n }\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"compaction\",\n subsystem: \"memory-tiering\",\n });\n api.logger.warn(`memory-hybrid: compaction failed: ${err}`);\n }\n }\n }\n if (abortIfSuperseded(\"post-compaction\")) {\n clearSessionState(sessionKey);\n return;\n }\n\n // 5. Centralized session state cleanup (Issue #463)\n // Moved here to ensure it only runs after compaction and supersession checks\n clearSessionState(sessionKey);\n api.logger.debug?.(`memory-hybrid: cleared all session state for ${sessionKey}`);\n\n // 6. Auto-capture from conversation messages\n if (isStaleLifecycleGeneration(ctx)) {\n clearSessionState(sessionKey);\n return;\n }\n if (ctx.cfg.autoCapture && ev.success && messages.length > 0) {\n try {\n const captureProvenance = resolveCaptureProvenance(event, api, sessionKey);\n if (!captureProvenance.shouldAutoCapture) {\n api.logger.debug?.(\n `memory-hybrid: skipped conversational auto-capture for ${captureProvenance.origin} session (${captureProvenance.reason ?? \"provenance blocked\"})`,\n );\n }\n\n const candidates: Array<{ role: \"user\" | \"assistant\"; text: string; sourceTurn: number }> = [];\n for (let turnIndex = 0; turnIndex < (messages as unknown[]).length; turnIndex++) {\n const msg = (messages as unknown[])[turnIndex];\n if (!msg || typeof msg !== \"object\") continue;\n const msgObj = msg as Record<string, unknown>;\n const role = msgObj.role;\n if (role !== \"user\" && role !== \"assistant\") continue;\n const content = msgObj.content;\n if (typeof content === \"string\") {\n candidates.push({ role, text: content, sourceTurn: turnIndex + 1 });\n continue;\n }\n if (Array.isArray(content)) {\n for (const block of content) {\n if (\n block &&\n typeof block === \"object\" &&\n \"type\" in block &&\n (block as Record<string, unknown>).type === \"text\" &&\n \"text\" in block &&\n typeof (block as Record<string, unknown>).text === \"string\"\n ) {\n candidates.push({\n role,\n text: (block as Record<string, unknown>).text as string,\n sourceTurn: turnIndex + 1,\n });\n }\n }\n }\n }\n const toCapture = captureProvenance.shouldAutoCapture\n ? candidates.filter((candidate) => candidate.text && ctx.shouldCapture(candidate.text))\n : [];\n if (toCapture.length > 0) {\n let stored = 0;\n const classifyModel = ctx.cfg.store.classifyModel ?? getDefaultCronModel(getCronModelConfig(ctx.cfg), \"nano\");\n const classifyMicroBatch = Math.max(1, Math.min(10, ctx.cfg.autoClassify?.batchSize ?? 10));\n\n type CapturePrepared = {\n candidate: (typeof toCapture)[number];\n textToStore: string;\n category: MemoryCategory;\n extracted: ReturnType<typeof extractStructuredFields>;\n summary: string | undefined;\n vector: number[] | undefined;\n similarFacts: MemoryEntry[];\n };\n\n const prepared: CapturePrepared[] = [];\n for (const candidate of toCapture.slice(0, 3)) {\n if (abortIfSuperseded(\"auto-capture-prepare\")) {\n clearSessionState(sessionKey);\n return;\n }\n let textToStore = candidate.text;\n textToStore = truncateForStorage(textToStore, ctx.cfg.captureMaxChars);\n const category: MemoryCategory = ctx.detectCategory(textToStore);\n const extracted = extractStructuredFields(textToStore, category);\n if (ctx.factsDb.hasDuplicate(textToStore, \"auto-capture\")) {\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"auto-capture:duplicate\",\n target: textToStore.slice(0, 80),\n outcome: \"skipped\",\n sessionId: captureProvenance.sessionId ?? undefined,\n context: { category },\n });\n continue;\n }\n const summaryThreshold = ctx.cfg.autoRecall.summaryThreshold;\n const summary =\n summaryThreshold > 0 && textToStore.length > summaryThreshold\n ? `${textToStore.slice(0, ctx.cfg.autoRecall.summaryMaxChars).trim()}…`\n : undefined;\n let vector: number[] | undefined;\n if (ctx.cfg.retrieval.strategies.includes(\"semantic\")) {\n try {\n vector = await ctx.embeddings.embed(textToStore);\n } catch (err) {\n const asErr = err instanceof Error ? err : new Error(String(err));\n if (!suppressCaptureStageError(ctx, api, asErr) && !isOllamaCircuitBreakerOpen(asErr)) {\n capturePluginError(asErr, {\n operation: \"auto-capture-embedding\",\n subsystem: \"auto-capture\",\n });\n }\n if (!suppressCaptureStageError(ctx, api, asErr)) {\n api.logger.warn(`memory-hybrid: auto-capture embedding failed: ${err}`);\n }\n }\n }\n let similarFacts: MemoryEntry[] = [];\n if (ctx.cfg.store.classifyBeforeWrite) {\n similarFacts = vector\n ? await ctx.findSimilarByEmbedding(ctx.vectorDb, ctx.factsDb, vector, 3, 0.3, {\n scope: \"global\",\n scopeTarget: null,\n })\n : [];\n if (similarFacts.length === 0) {\n similarFacts = ctx.factsDb.findSimilarForClassification(\n textToStore,\n extracted.entity,\n extracted.key,\n 3,\n \"global\",\n null,\n );\n }\n }\n prepared.push({ candidate, textToStore, category, extracted, summary, vector, similarFacts });\n }\n\n const classificationByIndex = new Map<number, MemoryClassification>();\n if (ctx.cfg.store.classifyBeforeWrite) {\n const withSimilar = prepared\n .map((p, i) => (p.similarFacts.length > 0 ? i : -1))\n .filter((i): i is number => i >= 0);\n for (let s = 0; s < withSimilar.length; s += classifyMicroBatch) {\n const idxs = withSimilar.slice(s, s + classifyMicroBatch);\n const inputs = idxs.map((pi) => ({\n candidateText: prepared[pi].textToStore,\n candidateEntity: prepared[pi].extracted.entity,\n candidateKey: prepared[pi].extracted.key,\n existingFacts: prepared[pi].similarFacts,\n }));\n const outs = await classifyMemoryOperationsBatch(inputs, ctx.openai, classifyModel, api.logger);\n idxs.forEach((pi, j) => {\n classificationByIndex.set(pi, outs[j]);\n });\n }\n }\n\n for (let pi = 0; pi < prepared.length; pi++) {\n if (abortIfSuperseded(\"auto-capture-store\")) {\n clearSessionState(sessionKey);\n return;\n }\n const { candidate, textToStore, category, extracted, summary, vector, similarFacts } = prepared[pi];\n if (ctx.cfg.store.classifyBeforeWrite) {\n if (similarFacts.length > 0) {\n try {\n let classification = classificationByIndex.get(pi);\n if (!classification) {\n api.logger.warn?.(\n `memory-hybrid: auto-capture missing batch classification for index ${pi}; falling back to single-call classify`,\n );\n classification = await classifyMemoryOperation(\n textToStore,\n extracted.entity,\n extracted.key,\n similarFacts,\n ctx.openai,\n classifyModel,\n api.logger,\n );\n }\n if (classification.action === \"NOOP\") {\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"auto-capture:noop\",\n target: textToStore.slice(0, 80),\n outcome: \"skipped\",\n sessionId: captureProvenance.sessionId ?? undefined,\n context: { reason: classification.reason ?? \"no-op\", category },\n });\n continue;\n }\n if (classification.action === \"DELETE\" && classification.targetId) {\n const target = validateScopedClassificationTarget({\n targetId: classification.targetId,\n candidates: similarFacts,\n getById: (id) => ctx.factsDb.getById(id),\n scope: \"global\",\n scopeTarget: null,\n warn: (message) => api.logger.warn?.(message),\n warnMessage: `memory-hybrid: blocked cross-scope or unknown auto-capture DELETE target ${classification.targetId}`,\n });\n if (!target) continue;\n ctx.factsDb.supersede(classification.targetId, null);\n ctx.aliasDb?.deleteByFactId(classification.targetId);\n await deleteVectorForFactId({\n vectorDb: ctx.vectorDb,\n factId: classification.targetId,\n logger: api.logger,\n context: \"stage-capture-delete-action\",\n });\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"auto-capture:delete\",\n target: classification.targetId,\n outcome: \"success\",\n sessionId: captureProvenance.sessionId ?? undefined,\n context: { reason: classification.reason ?? \"delete\", textPreview: textToStore.slice(0, 80) },\n });\n api.logger.info?.(`memory-hybrid: auto-capture DELETE — retracted ${classification.targetId}`);\n continue;\n }\n if (classification.action === \"UPDATE\" && classification.targetId) {\n const oldFact = validateScopedClassificationTarget({\n targetId: classification.targetId,\n candidates: similarFacts,\n getById: (id) => ctx.factsDb.getById(id),\n scope: \"global\",\n scopeTarget: null,\n warn: (message) => api.logger.warn?.(message),\n warnMessage: `memory-hybrid: blocked cross-scope auto-capture UPDATE target ${classification.targetId}`,\n });\n if (oldFact) {\n const preservedScope = oldFact.scope ?? \"global\";\n const preservedScopeTarget = preservedScope === \"global\" ? null : (oldFact.scopeTarget ?? null);\n if (preservedScope !== \"global\" && !preservedScopeTarget) {\n api.logger.warn?.(\n `memory-hybrid: blocked auto-capture UPDATE target ${classification.targetId} due to missing non-global scopeTarget`,\n );\n continue;\n }\n const finalImportance = Math.max(0.7, oldFact.importance);\n const walEntryId = await ctx.walWrite(\n \"update\",\n {\n text: textToStore,\n category,\n importance: finalImportance,\n entity: extracted.entity || oldFact.entity,\n key: extracted.key || oldFact.key,\n value: extracted.value || oldFact.value,\n source: \"auto-capture\",\n decayClass: oldFact.decayClass,\n summary,\n tags: extractTags(textToStore, extracted.entity),\n provenanceSession: captureProvenance.sessionId,\n sourceTurn: candidate.sourceTurn,\n extractionMethod: getAutoCaptureExtractionMethod(candidate.role, captureProvenance),\n extractionConfidence: getAutoCaptureExtractionConfidence(candidate.role),\n vector,\n embeddingModelName: vector ? ctx.embeddings.modelName : undefined,\n },\n api.logger,\n classification.targetId,\n );\n const nowSec = Math.floor(Date.now() / 1000);\n const storeResult = ctx.factsDb.storeWithResult({\n text: textToStore,\n category,\n importance: finalImportance,\n entity: extracted.entity || oldFact.entity,\n key: extracted.key || oldFact.key,\n value: extracted.value || oldFact.value,\n source: \"auto-capture\",\n decayClass: oldFact.decayClass,\n summary,\n tags: extractTags(textToStore, extracted.entity),\n validFrom: nowSec,\n supersedesId: classification.targetId,\n scope: preservedScope,\n scopeTarget: preservedScopeTarget,\n provenanceSession: captureProvenance.sessionId,\n sourceTurn: candidate.sourceTurn,\n extractionMethod: getAutoCaptureExtractionMethod(candidate.role, captureProvenance),\n extractionConfidence: getAutoCaptureExtractionConfidence(candidate.role),\n });\n if (storeResult.skipped) {\n await ctx.walRemove(walEntryId, api.logger);\n continue;\n }\n const newEntry = storeResult.entry;\n // CRITICAL FIX (#2): Delete vector for evicted fact to prevent orphaned vectors\n await cleanupEvictedVector({\n vectorDb: ctx.vectorDb,\n evictedFactId: storeResult.evictedFactId,\n logger: api.logger,\n context: \"stage-capture\",\n });\n ctx.factsDb.supersede(classification.targetId, newEntry.id);\n ctx.aliasDb?.deleteByFactId(classification.targetId);\n await deleteVectorForFactId({\n vectorDb: ctx.vectorDb,\n factId: classification.targetId,\n logger: api.logger,\n context: \"stage-capture-update-superseded\",\n });\n try {\n if (storeResult.embeddingStale || vector) {\n // `storeWithResult()` can return an existing deduped fact whose text\n // differs from `textToStore`; keep vector content aligned to stored text.\n const canonicalText = newEntry.text;\n const canonicalVector =\n vector && canonicalText === textToStore ? vector : await ctx.embeddings.embed(canonicalText);\n ctx.factsDb.setEmbeddingModel(newEntry.id, ctx.embeddings.modelName);\n if (storeResult.embeddingStale || !(await ctx.vectorDb.hasDuplicate(canonicalVector))) {\n await ctx.vectorDb.store({\n text: canonicalText,\n vector: canonicalVector,\n importance: finalImportance,\n category,\n id: newEntry.id,\n });\n }\n persistCanonicalFactEmbedding(\n ctx.factsDb,\n newEntry.id,\n ctx.embeddings.modelName,\n canonicalVector,\n \"auto-capture-fact-embeddings\",\n \"auto-capture\",\n api.logger.warn?.bind(api.logger),\n );\n }\n } catch (vecErr) {\n capturePluginError(vecErr instanceof Error ? vecErr : new Error(String(vecErr)), {\n operation: storeResult.embeddingStale\n ? \"auto-capture-stale-vector-update\"\n : \"auto-capture-vector-update\",\n subsystem: \"auto-capture\",\n });\n api.logger.warn(\n storeResult.embeddingStale\n ? `memory-hybrid: stale vector re-embed failed for merged fact ${newEntry.id.slice(0, 8)} — LanceDB vector encodes pre-merge text; nightly re-index will repair: ${vecErr}`\n : `memory-hybrid: vector capture failed: ${vecErr}`,\n );\n }\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"auto-capture:updated\",\n target: newEntry.id,\n outcome: \"success\",\n sessionId: captureProvenance.sessionId ?? undefined,\n context: { supersededId: classification.targetId, category, entity: extracted.entity },\n });\n api.logger.info?.(\n `memory-hybrid: auto-capture UPDATE — superseded ${classification.targetId} with ${newEntry.id}`,\n );\n stored++;\n await ctx.walRemove(walEntryId, api.logger);\n continue;\n } // close if (oldFact) guard\n // Validation failed: fall through to default ADD-style store path\n }\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"auto-capture-classification\",\n subsystem: \"auto-capture\",\n });\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"auto-capture:classification-error\",\n outcome: \"failed\",\n error: String(err).slice(0, 200),\n sessionId: captureProvenance.sessionId ?? undefined,\n });\n api.logger.warn(`memory-hybrid: auto-capture classification failed: ${err}`);\n }\n }\n }\n }\n const walEntryId = await ctx.walWrite(\n \"store\",\n {\n text: textToStore,\n category,\n importance: CLI_STORE_IMPORTANCE,\n entity: extracted.entity,\n key: extracted.key,\n value: extracted.value,\n source: \"auto-capture\",\n summary,\n tags: extractTags(textToStore, extracted.entity),\n provenanceSession: captureProvenance.sessionId,\n sourceTurn: candidate.sourceTurn,\n extractionMethod: getAutoCaptureExtractionMethod(candidate.role, captureProvenance),\n extractionConfidence: getAutoCaptureExtractionConfidence(candidate.role),\n vector,\n embeddingModelName: vector ? ctx.embeddings.modelName : undefined,\n },\n api.logger,\n );\n const storeResult = ctx.factsDb.storeWithResult({\n text: textToStore,\n category,\n importance: CLI_STORE_IMPORTANCE,\n entity: extracted.entity,\n key: extracted.key,\n value: extracted.value,\n source: \"auto-capture\",\n summary,\n tags: extractTags(textToStore, extracted.entity),\n provenanceSession: captureProvenance.sessionId,\n sourceTurn: candidate.sourceTurn,\n extractionMethod: getAutoCaptureExtractionMethod(candidate.role, captureProvenance),\n extractionConfidence: getAutoCaptureExtractionConfidence(candidate.role),\n });\n const storedEntry = storeResult.entry;\n // Guard: skip post-store ops when pre-store guard blocked the write (#1560, #1561)\n if (!storeResult.skipped) {\n await cleanupEvictedVector({\n vectorDb: ctx.vectorDb,\n evictedFactId: storeResult.evictedFactId,\n logger: api.logger,\n context: \"stage-capture\",\n });\n try {\n if (storeResult.embeddingStale) {\n // Merge case: the existing fact's text was updated in-place.\n // Re-embed the merged text and force-replace the stale LanceDB vector.\n // If embed fails, the vector encodes stale pre-merge text; the dream-cycle\n // re-index will repair it on the next nightly run.\n const mergedVector = await ctx.embeddings.embed(storedEntry.text);\n ctx.factsDb.setEmbeddingModel(storedEntry.id, ctx.embeddings.modelName);\n await ctx.vectorDb.store({\n text: storedEntry.text,\n vector: mergedVector,\n importance: CLI_STORE_IMPORTANCE,\n category,\n id: storedEntry.id,\n });\n persistCanonicalFactEmbedding(\n ctx.factsDb,\n storedEntry.id,\n ctx.embeddings.modelName,\n mergedVector,\n \"auto-capture-fact-embeddings\",\n \"auto-capture\",\n api.logger.warn?.bind(api.logger),\n );\n } else if (vector) {\n const canonicalText = storedEntry.text;\n const canonicalVector =\n canonicalText === textToStore ? vector : await ctx.embeddings.embed(canonicalText);\n ctx.factsDb.setEmbeddingModel(storedEntry.id, ctx.embeddings.modelName);\n if (!(await ctx.vectorDb.hasDuplicate(canonicalVector))) {\n await ctx.vectorDb.store({\n text: canonicalText,\n vector: canonicalVector,\n importance: CLI_STORE_IMPORTANCE,\n category,\n id: storedEntry.id,\n });\n }\n persistCanonicalFactEmbedding(\n ctx.factsDb,\n storedEntry.id,\n ctx.embeddings.modelName,\n canonicalVector,\n \"auto-capture-fact-embeddings\",\n \"auto-capture\",\n api.logger.warn?.bind(api.logger),\n );\n }\n } catch (vecErr) {\n if (!suppressCaptureStageError(ctx, api, vecErr)) {\n capturePluginError(vecErr instanceof Error ? vecErr : new Error(String(vecErr)), {\n operation: storeResult.embeddingStale\n ? \"auto-capture-stale-vector-store\"\n : \"auto-capture-vector-store\",\n subsystem: \"auto-capture\",\n });\n api.logger.warn(\n storeResult.embeddingStale\n ? `memory-hybrid: stale vector re-embed failed for merged fact ${storedEntry.id.slice(0, 8)} — LanceDB vector encodes pre-merge text; nightly re-index will repair: ${vecErr}`\n : `memory-hybrid: vector capture failed: ${vecErr}`,\n );\n }\n }\n stored++;\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"auto-capture:stored\",\n target: storedEntry.id,\n outcome: \"success\",\n sessionId: captureProvenance.sessionId ?? undefined,\n context: { category, entity: extracted.entity, role: candidate.role },\n });\n }\n await ctx.walRemove(walEntryId, api.logger);\n }\n if (stored > 0) api.logger.info(`memory-hybrid: auto-captured ${stored} memories`);\n }\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"auto-capture\",\n subsystem: \"auto-capture\",\n });\n api.logger.warn(`memory-hybrid: capture failed: ${String(err)}`);\n }\n }\n }\n\n // 6b. Episodic memory auto-capture (#781): scan conversation for outcome-indicating phrases\n // and create episode records. This runs regardless of autoCapture config flag, because\n // capturing outcomes is low-cost and high-value for the episodic history.\n if (isStaleLifecycleGeneration(ctx)) {\n clearSessionState(sessionKey);\n return;\n }\n {\n if (abortIfSuperseded(\"episodic-capture\")) {\n clearSessionState(sessionKey);\n return;\n }\n const sessionId = sessionKey;\n const agentId = ctx.currentAgentIdRef.value ?? undefined;\n // Collect all text from the session for scanning\n const sessionTexts: Array<{ text: string; turnIndex: number }> = [];\n for (let turnIndex = 0; turnIndex < (messages as unknown[]).length; turnIndex++) {\n const msg = (messages as unknown[])[turnIndex];\n if (!msg || typeof msg !== \"object\") continue;\n const msgObj = msg as Record<string, unknown>;\n const content = msgObj.content;\n if (typeof content === \"string\") {\n sessionTexts.push({ text: content, turnIndex });\n } else if (Array.isArray(content)) {\n for (const block of content) {\n if (\n block &&\n typeof block === \"object\" &&\n \"text\" in block &&\n typeof (block as Record<string, unknown>).text === \"string\"\n ) {\n sessionTexts.push({ text: (block as Record<string, unknown>).text as string, turnIndex });\n }\n }\n }\n }\n\n for (const { text } of sessionTexts) {\n if (abortIfSuperseded(\"episodic-capture-loop\")) {\n clearSessionState(sessionKey);\n return;\n }\n // Scan for success indicators\n for (const pattern of SUCCESS_PATTERNS) {\n const match = pattern.regex.exec(text);\n if (match) {\n const eventText = pattern.label ? `Agent reported: ${pattern.label}` : match[0];\n const existing = ctx.factsDb.searchEpisodes({\n query: eventText,\n since: Math.floor(Date.now() / 1000) - 300, // within last 5 min\n limit: 1,\n });\n if (existing.length === 0) {\n try {\n const episode = ctx.factsDb.recordEpisode({\n event: eventText,\n outcome: \"success\",\n timestamp: Math.floor(Date.now() / 1000),\n context: text.slice(0, 500),\n sessionId,\n agentId,\n scope: \"session\",\n scopeTarget: sessionId,\n tags: pattern.label ? [pattern.label] : [],\n });\n api.logger.debug?.(`memory-hybrid: auto-captured success episode: ${episode.id}`);\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"episode-auto-capture-success\",\n subsystem: \"episodes\",\n severity: \"info\",\n });\n }\n }\n }\n break; // only one episode per message\n }\n }\n\n // Scan for failure indicators\n for (const pattern of FAILURE_PATTERNS) {\n const match = pattern.regex.exec(text);\n if (match) {\n const eventText = pattern.label ? `Agent reported: ${pattern.label}` : match[0];\n const existing = ctx.factsDb.searchEpisodes({\n query: eventText,\n since: Math.floor(Date.now() / 1000) - 300,\n limit: 1,\n });\n if (existing.length === 0) {\n try {\n const episode = ctx.factsDb.recordEpisode({\n event: eventText,\n outcome: \"failure\",\n timestamp: Math.floor(Date.now() / 1000),\n context: text.slice(0, 500),\n sessionId,\n agentId,\n scope: \"session\",\n scopeTarget: sessionId,\n tags: pattern.label ? [pattern.label] : [],\n // failures get importance >= 0.8 automatically via recordEpisode\n });\n api.logger.debug?.(`memory-hybrid: auto-captured failure episode: ${episode.id}`);\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"episode-auto-capture-failure\",\n subsystem: \"episodes\",\n severity: \"info\",\n });\n }\n }\n }\n break;\n }\n }\n }\n }\n\n // 7. Credential auto-detect: persist hint for next turn\n if (isStaleLifecycleGeneration(ctx)) {\n clearSessionState(sessionKey);\n return;\n }\n if (\n ctx.cfg.credentials.enabled &&\n ctx.cfg.credentials.autoDetect &&\n ctx.cfg.verbosity !== \"silent\" &&\n messages.length > 0\n ) {\n if (abortIfSuperseded(\"credential-hint-capture\")) {\n clearSessionState(sessionKey);\n return;\n }\n const pendingPath = join(dirname(ctx.resolvedSqlitePath), \"credentials-pending.json\");\n try {\n const texts: string[] = [];\n for (const msg of messages as unknown[]) {\n if (!msg || typeof msg !== \"object\") continue;\n const msgObj = msg as Record<string, unknown>;\n const content = msgObj.content;\n if (typeof content === \"string\") texts.push(content);\n else if (Array.isArray(content)) {\n for (const block of content) {\n if (\n block &&\n typeof block === \"object\" &&\n \"type\" in block &&\n (block as Record<string, unknown>).type === \"text\" &&\n \"text\" in block\n ) {\n const t = (block as Record<string, unknown>).text;\n if (typeof t === \"string\") texts.push(t);\n }\n }\n }\n }\n const allText = texts.join(\"\\n\");\n const detected = detectCredentialPatterns(allText);\n if (detected.length > 0) {\n // Write atomically (temp-then-rename) to avoid partial state on crash.\n atomicWriteFile(\n pendingPath,\n JSON.stringify({\n hints: detected.map((d) => d.hint),\n at: Date.now(),\n }),\n );\n api.logger.info(\n `memory-hybrid: credential patterns detected (${detected.map((d) => d.hint).join(\", \")}) — will prompt next turn`,\n );\n }\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"credential-auto-detect\",\n subsystem: \"credentials\",\n });\n api.logger.warn(`memory-hybrid: credential auto-detect failed: ${err}`);\n }\n }\n }\n\n // 8. Tool-call credential auto-capture\n if (isStaleLifecycleGeneration(ctx)) {\n clearSessionState(sessionKey);\n return;\n }\n if (ctx.cfg.credentials.enabled && ctx.cfg.credentials.autoCapture?.toolCalls && messages.length > 0) {\n if (abortIfSuperseded(\"credential-tool-call-capture\")) {\n clearSessionState(sessionKey);\n return;\n }\n const logCaptures = ctx.cfg.credentials.autoCapture.logCaptures !== false;\n try {\n for (const msg of messages as unknown[]) {\n if (abortIfSuperseded(\"credential-tool-call-loop\")) {\n clearSessionState(sessionKey);\n return;\n }\n if (!msg || typeof msg !== \"object\") continue;\n const msgObj = msg as Record<string, unknown>;\n if (msgObj.role !== \"assistant\") continue;\n const toolCalls = msgObj.tool_calls;\n if (!Array.isArray(toolCalls)) continue;\n for (const tc of toolCalls) {\n if (!tc || typeof tc !== \"object\") continue;\n const tcObj = tc as Record<string, unknown>;\n const fn = tcObj.function as Record<string, unknown> | undefined;\n if (!fn) continue;\n const args = fn.arguments;\n if (typeof args !== \"string\" || args.length === 0) continue;\n let parsedArgs: Record<string, unknown> = {};\n try {\n parsedArgs = JSON.parse(args);\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err as Error, {\n operation: \"json-parse-tool-args\",\n severity: \"info\",\n subsystem: \"lifecycle\",\n });\n }\n }\n const argsToScan = Object.values(parsedArgs)\n .filter((v): v is string => typeof v === \"string\")\n .join(\" \");\n const creds = extractCredentialsFromToolCalls(argsToScan || args);\n for (const cred of creds) {\n if (ctx.credentialsDb) {\n const stored = ctx.credentialsDb.storeIfNew({\n service: cred.service,\n type: cred.type,\n value: cred.value,\n url: cred.url,\n notes: cred.notes,\n });\n if (stored && logCaptures) {\n api.logger.info(`memory-hybrid: auto-captured credential for ${cred.service} (${cred.type})`);\n }\n } else {\n const text = `Credential for ${cred.service} (${cred.type})${cred.url ? ` — ${cred.url}` : \"\"}${cred.notes ? `. ${cred.notes}` : \"\"}.`;\n const storeResult = ctx.factsDb.storeWithResult({\n text,\n category: \"technical\" as MemoryCategory,\n importance: 0.9,\n entity: \"Credentials\",\n key: cred.service,\n value: cred.value,\n source: \"conversation\",\n decayClass: \"permanent\",\n tags: [\"auth\", \"credential\"],\n });\n if (storeResult.skipped) {\n continue;\n }\n const entry = storeResult.entry;\n // Guard: skip post-store ops when pre-store guard blocked the write (#1560, #1561)\n if (!storeResult.skipped) {\n // CRITICAL FIX (#2): Delete vector for evicted fact to prevent orphaned vectors\n await cleanupEvictedVector({\n vectorDb: ctx.vectorDb,\n evictedFactId: storeResult.evictedFactId,\n logger: api.logger,\n context: \"stage-capture\",\n });\n if (ctx.cfg.retrieval.strategies.includes(\"semantic\")) {\n try {\n if (storeResult.embeddingStale) {\n // Merge case: re-embed the merged text to keep the vector in sync.\n // If embed fails, the vector encodes stale pre-merge text; nightly re-index will repair.\n const mergedVector = await ctx.embeddings.embed(entry.text);\n ctx.factsDb.setEmbeddingModel(entry.id, ctx.embeddings.modelName);\n await ctx.vectorDb.store({\n text: entry.text,\n vector: mergedVector,\n importance: 0.9,\n category: \"technical\",\n id: entry.id,\n });\n persistCanonicalFactEmbedding(\n ctx.factsDb,\n entry.id,\n ctx.embeddings.modelName,\n mergedVector,\n \"auto-capture-fact-embeddings\",\n \"auto-capture\",\n api.logger.warn?.bind(api.logger),\n );\n } else {\n const vector = await ctx.embeddings.embed(entry.text);\n ctx.factsDb.setEmbeddingModel(entry.id, ctx.embeddings.modelName);\n if (!(await ctx.vectorDb.hasDuplicate(vector))) {\n await ctx.vectorDb.store({\n text: entry.text,\n vector,\n importance: 0.9,\n category: \"technical\",\n id: entry.id,\n });\n persistCanonicalFactEmbedding(\n ctx.factsDb,\n entry.id,\n ctx.embeddings.modelName,\n vector,\n \"auto-capture-fact-embeddings\",\n \"auto-capture\",\n api.logger.warn?.bind(api.logger),\n );\n }\n }\n } catch (err) {\n const asErr = err instanceof Error ? err : new Error(String(err));\n if (!suppressCaptureStageError(ctx, api, asErr) && !isOllamaCircuitBreakerOpen(asErr)) {\n capturePluginError(asErr, {\n operation: storeResult.embeddingStale\n ? \"tool-call-credential-stale-vector-update\"\n : \"tool-call-credential-vector-store\",\n subsystem: \"credentials\",\n });\n }\n if (!suppressCaptureStageError(ctx, api, asErr)) {\n api.logger.warn(\n storeResult.embeddingStale\n ? `memory-hybrid: stale vector re-embed failed for merged credential fact ${entry.id.slice(0, 8)} — nightly re-index will repair: ${err}`\n : `memory-hybrid: vector store for credential fact failed: ${err}`,\n );\n }\n }\n }\n if (logCaptures) {\n api.logger.info(`memory-hybrid: auto-captured credential for ${cred.service} (${cred.type})`);\n }\n } // close if (!storeResult.skipped) guard (#1560, #1561)\n }\n }\n }\n }\n } catch (err) {\n if (!suppressCaptureStageError(ctx, api, err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"tool-call-credential-auto-capture\",\n subsystem: \"credentials\",\n });\n const errMsg = err instanceof Error ? err.stack || err.message : String(err);\n api.logger.warn(`memory-hybrid: tool-call credential auto-capture failed: ${errMsg}`);\n }\n }\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"stage-capture.js","names":[],"sources":["../../lifecycle/stage-capture.ts"],"sourcesContent":["/**\n * Lifecycle stage: Capture (Phase 2.3).\n * On agent_end: frustration assistant capture, event log session_end, clearSessionState,\n * compaction (if enabled), autoCapture, credential hint, tool-call credential capture.\n * Single timeout: 60s.\n */\n\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport { withTimeout } from \"../utils/timeout.js\";\nimport type { LifecycleContext, SessionState } from \"./types.js\";\nimport { runCapture } from \"./stage-capture/run-capture.js\";\n\nconst CAPTURE_STAGE_TIMEOUT_MS = 60_000;\n\nexport async function runCaptureStage(\n event: unknown,\n api: ClawdbotPluginApi,\n ctx: LifecycleContext,\n sessionState: SessionState,\n): Promise<void> {\n await withTimeout(CAPTURE_STAGE_TIMEOUT_MS, () => runCapture(event, api, ctx, sessionState));\n}\n"],"mappings":";;;AAYA,MAAM,2BAA2B;AAEjC,eAAsB,gBACpB,OACA,KACA,KACA,cACe;CACf,MAAM,YAAY,gCAAgC,WAAW,OAAO,KAAK,KAAK,aAAa,CAAC"}
1
+ {"version":3,"file":"stage-capture.js","names":[],"sources":["../../lifecycle/stage-capture.ts"],"sourcesContent":["/**\n * Lifecycle stage: Capture (Phase 2.3).\n * On agent_end: frustration assistant capture, event log session_end, clearSessionState,\n * compaction (if enabled), autoCapture, credential hint, tool-call credential capture.\n * Single timeout: 60s.\n */\n\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport { withTimeout } from \"../utils/timeout.js\";\nimport type { LifecycleContext, SessionState } from \"./types.js\";\nimport { runCapture } from \"./stage-capture/run-capture.js\";\n\nconst CAPTURE_STAGE_TIMEOUT_MS = 60_000;\n\nexport async function runCaptureStage(\n event: unknown,\n api: ClawdbotPluginApi,\n ctx: LifecycleContext,\n sessionState: SessionState,\n): Promise<void> {\n await withTimeout(CAPTURE_STAGE_TIMEOUT_MS, () => runCapture(event, api, ctx, sessionState));\n}\n"],"mappings":";;;AAYA,MAAM,2BAA2B;AAEjC,eAAsB,gBACpB,OACA,KACA,KACA,cACe;CACf,MAAM,YAAY,gCAAgC,WAAW,OAAO,KAAK,KAAK,YAAY,CAAC;AAC7F"}
@@ -1 +1 @@
1
- {"version":3,"file":"stage-cleanup.js","names":[],"sources":["../../lifecycle/stage-cleanup.ts"],"sourcesContent":["/**\n * Lifecycle stage: Cleanup (Phase 2.3).\n * OpenClaw typed hooks **subagent_spawned** / **subagent_ended** (issue #966), stale session sweep timer, dispose.\n * Exports: consumePendingTaskSignals, registerCleanupHandlers, createStaleSweepTimer, getDispose.\n */\n\nimport { join } from \"node:path\";\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport {\n type ActiveTaskEntry,\n type PendingTaskSignal,\n completeTask,\n deleteSignal,\n flushCompletedTaskToMemory,\n isSubagentSession,\n readActiveTaskFile,\n readActiveTaskFileWithMtime,\n readPendingSignals,\n upsertTask,\n writeActiveTaskFileGuarded,\n writeActiveTaskFileOptimistic,\n} from \"../services/active-task.js\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport {\n consumePendingTaskSignalsFacts,\n loadTaskLedgerFromFacts,\n syncActiveTaskEntryToFacts,\n} from \"../services/task-ledger-facts.js\";\nimport { parseDuration } from \"../utils/duration.js\";\nimport {\n type SubagentEndedEvent,\n findActiveTaskForSubagentEnd,\n subagentEndedIsSuccess,\n} from \"../utils/subagent-ended-utils.js\";\nimport { resolveAgentIdFromHookEvent } from \"./resolve-agent-id.js\";\nimport type { LifecycleContext, SessionState } from \"./types.js\";\n\nconst STALE_SESSION_TTL_MS = 30 * 60 * 1000; // 30 minutes\nconst STALE_SWEEP_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes\n\n/** OpenClaw core dispatch shapes — see issue #966 / runSubagentSpawned */\ntype SubagentSpawnedEvent = {\n childSessionKey?: string;\n /** Legacy / alternate field names from older handlers */\n sessionKey?: string;\n label?: string;\n task?: string;\n agentId?: string;\n runId?: string;\n};\n\n/**\n * Read all pending task signals from `memory/task-signals/*.json` and apply\n * their status changes to ACTIVE-TASKS.md or the facts ledger. Called after subagent completes.\n */\nasync function consumePendingTaskSignals(\n activeTaskPath: string,\n workspaceRoot: string,\n staleMinutes: number,\n flushOnComplete: boolean,\n logger: { info?: (msg: string) => void; warn?: (msg: string) => void; debug?: (msg: string) => void } | undefined,\n ledger: \"markdown\" | \"facts\",\n factsDb: import(\"../backends/facts-db.js\").FactsDB,\n vectorDb: import(\"../backends/vector-db.js\").VectorDB,\n embeddings: import(\"../services/embeddings.js\").EmbeddingProvider,\n sessionKey?: string,\n): Promise<void> {\n if (isSubagentSession(sessionKey)) {\n logger?.debug?.(\"memory-hybrid: skipping pending task signal consumption in sub-agent session\");\n return;\n }\n\n if (ledger === \"facts\") {\n await consumePendingTaskSignalsFacts(\n workspaceRoot,\n staleMinutes,\n flushOnComplete,\n factsDb,\n vectorDb,\n embeddings,\n logger,\n );\n return;\n }\n\n const memoryDir = join(workspaceRoot, \"memory\");\n let signals: PendingTaskSignal[];\n try {\n signals = await readPendingSignals(memoryDir);\n } catch (err) {\n logger?.warn?.(`memory-hybrid: failed to read pending task signals: ${err}`);\n return;\n }\n\n if (signals.length === 0) return;\n\n const signalTtlMs = Math.max(staleMinutes * 60 * 1000, 24 * 60 * 60 * 1000);\n const nowMs = Date.now();\n const isSignalExpired = (signal: PendingTaskSignal): boolean => {\n const parsed = Date.parse(signal.timestamp);\n if (Number.isNaN(parsed)) return true;\n return nowMs - parsed > signalTtlMs;\n };\n\n signals = [...signals].sort((a, b) => {\n const at = Date.parse(a.timestamp);\n const bt = Date.parse(b.timestamp);\n if (Number.isNaN(at) || Number.isNaN(bt)) return a._filePath.localeCompare(b._filePath);\n return at === bt ? a._filePath.localeCompare(b._filePath) : at - bt;\n });\n\n let taskFile: Awaited<ReturnType<typeof readActiveTaskFileWithMtime>> | undefined;\n try {\n taskFile = await readActiveTaskFileWithMtime(activeTaskPath, staleMinutes);\n } catch (err) {\n logger?.warn?.(`memory-hybrid: failed to read ACTIVE-TASKS.md for signal consumption: ${err}`);\n return;\n }\n\n if (!taskFile) {\n const expiredSignals = signals.filter(isSignalExpired);\n if (expiredSignals.length > 0) {\n for (const signal of expiredSignals) await deleteSignal(signal._filePath).catch(() => {});\n logger?.info?.(\n `memory-hybrid: pruned ${expiredSignals.length} expired task signal(s) while ACTIVE-TASKS.md is missing`,\n );\n }\n logger?.info?.(\"memory-hybrid: ACTIVE-TASKS.md missing; deferring pending task signals\");\n return;\n }\n\n const knownMtime = taskFile.mtime;\n\n const findMatchingTask = (activeEntries: ActiveTaskEntry[], signal: PendingTaskSignal): ActiveTaskEntry | null => {\n const byLabel = activeEntries.filter((t) => t.label === signal.taskRef);\n if (byLabel.length === 1) return byLabel[0];\n if (byLabel.length > 1) {\n logger?.warn?.(`memory-hybrid: multiple active tasks share label ${signal.taskRef}; leaving signal pending`);\n return null;\n }\n const byDescription = activeEntries.filter((t) => t.description === signal.taskRef);\n if (byDescription.length === 1) {\n logger?.warn?.(\n `memory-hybrid: matched signal for \"${signal.taskRef}\" by description (not label); sub-agents should use the exact task label in taskRef for reliable matching`,\n );\n return byDescription[0];\n }\n if (byDescription.length > 1) {\n logger?.warn?.(\n `memory-hybrid: multiple active tasks match description ${signal.taskRef}; leaving signal pending`,\n );\n return null;\n }\n return null;\n };\n\n const applySignals = (\n activeEntries: ActiveTaskEntry[],\n completedEntries: ActiveTaskEntry[],\n ): {\n active: ActiveTaskEntry[];\n completed: ActiveTaskEntry[];\n processedSignals: PendingTaskSignal[];\n expiredSignals: PendingTaskSignal[];\n completedToFlush: ActiveTaskEntry[];\n } => {\n let updatedActive = [...activeEntries];\n const updatedCompleted = [...completedEntries];\n const processedSignals: PendingTaskSignal[] = [];\n const expiredSignals: PendingTaskSignal[] = [];\n const completedToFlush: ActiveTaskEntry[] = [];\n\n for (const signal of signals) {\n try {\n const updatedTimestamp = (() => {\n const t = Date.parse(signal.timestamp);\n return Number.isNaN(t) ? new Date().toISOString() : signal.timestamp;\n })();\n\n const existing = findMatchingTask(updatedActive, signal);\n if (!existing) {\n if (isSignalExpired(signal)) expiredSignals.push(signal);\n else logger?.warn?.(`memory-hybrid: no matching active task for signal ${signal.taskRef}; leaving pending`);\n continue;\n }\n\n if (signal.signal === \"completed\") {\n const { updated, completed } = completeTask(updatedActive, existing.label);\n if (completed) {\n updatedActive = updated;\n updatedCompleted.push({\n ...completed,\n updated: updatedTimestamp,\n handoff: signal._handoff ?? completed.handoff,\n });\n processedSignals.push(signal);\n completedToFlush.push({\n ...completed,\n updated: updatedTimestamp,\n handoff: signal._handoff ?? completed.handoff,\n });\n }\n continue;\n }\n\n if (signal.signal !== \"blocked\" && signal.signal !== \"escalate\" && signal.signal !== \"update\") {\n if (isSignalExpired(signal)) expiredSignals.push(signal);\n else\n logger?.warn?.(\n `memory-hybrid: unhandled task signal \"${signal.signal}\" for ${signal.taskRef}; leaving pending`,\n );\n continue;\n }\n\n const newStatus: ActiveTaskEntry[\"status\"] =\n signal.signal === \"blocked\" ? \"Stalled\" : signal.signal === \"escalate\" ? \"Waiting\" : existing.status;\n const updatedEntry: ActiveTaskEntry = {\n ...existing,\n status: newStatus,\n next: signal.summary ? `[Signal: ${signal.signal}] ${signal.summary}` : existing.next,\n updated: updatedTimestamp,\n handoff: signal._handoff ?? existing.handoff,\n };\n updatedActive = upsertTask(updatedActive, updatedEntry, true);\n processedSignals.push(signal);\n } catch (err) {\n logger?.warn?.(`memory-hybrid: failed to process signal from ${signal._filePath}: ${err}`);\n }\n }\n\n return {\n active: updatedActive,\n completed: updatedCompleted,\n processedSignals,\n expiredSignals,\n completedToFlush,\n };\n };\n\n let latestResult = applySignals(taskFile.active, taskFile.completed);\n let { processedSignals, expiredSignals, completedToFlush } = latestResult;\n\n if (processedSignals.length === 0) {\n if (expiredSignals.length > 0) {\n for (const signal of expiredSignals) await deleteSignal(signal._filePath).catch(() => {});\n logger?.info?.(`memory-hybrid: pruned ${expiredSignals.length} expired task signal(s) with no matching task`);\n }\n return;\n }\n\n let wrote = false;\n try {\n wrote = await writeActiveTaskFileOptimistic(\n activeTaskPath,\n latestResult.active,\n latestResult.completed,\n knownMtime,\n async (fresh) => {\n latestResult = applySignals(fresh.active, fresh.completed);\n processedSignals = latestResult.processedSignals;\n expiredSignals = latestResult.expiredSignals;\n completedToFlush = latestResult.completedToFlush;\n return [latestResult.active, latestResult.completed];\n },\n 3,\n staleMinutes,\n );\n } catch (err) {\n logger?.warn?.(`memory-hybrid: failed to write ACTIVE-TASKS.md after signal consumption: ${err}`);\n }\n\n if (wrote) {\n for (const signal of processedSignals) await deleteSignal(signal._filePath).catch(() => {});\n for (const signal of expiredSignals) await deleteSignal(signal._filePath).catch(() => {});\n if (flushOnComplete && completedToFlush.length > 0) {\n const memoryDir = join(workspaceRoot, \"memory\");\n for (const completed of completedToFlush) {\n await flushCompletedTaskToMemory(completed, memoryDir).catch(() => {});\n }\n }\n logger?.info?.(`memory-hybrid: consumed ${processedSignals.length} pending task signal(s) from sub-agents`);\n } else if (expiredSignals.length > 0) {\n for (const signal of expiredSignals) await deleteSignal(signal._filePath).catch(() => {});\n logger?.info?.(`memory-hybrid: pruned ${expiredSignals.length} expired task signal(s) after write abort`);\n }\n}\n\nfunction sweepStaleSessions(sessionState: SessionState): number {\n const now = Date.now();\n const cutoff = now - STALE_SESSION_TTL_MS;\n let swept = 0;\n for (const [sessionKey, lastActive] of sessionState.sessionLastActivity) {\n if (lastActive < cutoff) {\n sessionState.clearSessionState(sessionKey);\n sessionState.capabilityHintsSessionsSeen.delete(sessionKey);\n swept++;\n }\n }\n return swept;\n}\n\n/**\n * Start the periodic stale session sweep timer. Returns the timer handle for dispose.\n */\nexport function createStaleSweepTimer(sessionState: SessionState): ReturnType<typeof setInterval> {\n return setInterval(() => {\n try {\n sweepStaleSessions(sessionState);\n } catch (err) {\n // Suppress expected database connection errors during shutdown\n const e = err instanceof Error ? err : new Error(String(err));\n if (!/database connection is not open/i.test(e.message)) {\n capturePluginError(e, {\n operation: \"stale-session-sweep\",\n subsystem: \"active-task\",\n });\n }\n }\n }, STALE_SWEEP_INTERVAL_MS);\n}\n\n/**\n * Return a dispose function that clears the sweep timer and all session maps.\n */\nexport function getDispose(timerRef: ReturnType<typeof setInterval> | null, sessionState: SessionState): () => void {\n return () => {\n if (timerRef) clearInterval(timerRef);\n sessionState.clearAll?.();\n };\n}\n\n/**\n * Register **subagent_spawned** and **subagent_ended** handlers (active-task checkpoint + signal consumption).\n * Hook names must match OpenClaw `PLUGIN_HOOK_NAMES` (issue #966).\n */\nexport function registerCleanupHandlers(\n api: ClawdbotPluginApi,\n ctx: LifecycleContext,\n _sessionState: SessionState,\n resolvedActiveTaskPath: string,\n workspaceRoot: string,\n): void {\n if (!ctx.cfg.activeTask.enabled || !ctx.cfg.activeTask.autoCheckpoint) return;\n\n api.on(\"subagent_spawned\", async (event: unknown) => {\n try {\n const ev = event as SubagentSpawnedEvent;\n const childOrSession = ev.childSessionKey ?? ev.sessionKey;\n const label = ev.label ?? childOrSession ?? `subagent-${Date.now()}`;\n const description = ev.task ?? `Subagent task (session: ${childOrSession ?? \"unknown\"})`;\n const staleMinutes = parseDuration(ctx.cfg.activeTask.staleThreshold);\n const now = new Date().toISOString();\n\n if (ctx.cfg.activeTask.ledger === \"facts\") {\n if (isSubagentSession(api.context?.sessionKey)) {\n api.logger.debug?.(\"memory-hybrid: skipped facts ledger checkpoint in subagent_spawned (sub-agent session)\");\n return;\n }\n const { active: existingActive } = loadTaskLedgerFromFacts(ctx.factsDb);\n const existing = existingActive.find((t) => t.label === label);\n const entry: ActiveTaskEntry = {\n label,\n description,\n status: \"In progress\",\n subagent: childOrSession,\n started: existing?.started ?? now,\n updated: now,\n };\n await syncActiveTaskEntryToFacts(ctx.factsDb, ctx.vectorDb, ctx.embeddings, entry, api.logger);\n api.logger.info?.(`memory-hybrid: auto-checkpoint — facts ledger task [${label}] for subagent spawn`);\n return;\n }\n\n const taskFile = await readActiveTaskFile(resolvedActiveTaskPath, staleMinutes);\n const existingActive = taskFile?.active ?? [];\n const existingCompleted = taskFile?.completed ?? [];\n const existing = existingActive.find((t) => t.label === label);\n const entry: ActiveTaskEntry = {\n label,\n description,\n status: \"In progress\",\n subagent: childOrSession,\n started: existing?.started ?? now,\n updated: now,\n };\n const updated = upsertTask(existingActive, entry);\n const writeResult = await writeActiveTaskFileGuarded(\n resolvedActiveTaskPath,\n updated,\n existingCompleted,\n api.context?.sessionKey,\n );\n if (writeResult.skipped) {\n api.logger.debug?.(`memory-hybrid: skipped ACTIVE-TASKS.md write in subagent_spawned: ${writeResult.reason}`);\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"cleanup:active-task-write-skipped\",\n outcome: \"skipped\",\n sessionId: api.context?.sessionKey,\n context: { reason: writeResult.reason, taskLabel: label },\n });\n } else {\n api.logger.info?.(`memory-hybrid: auto-checkpoint — created active task [${label}] for subagent spawn`);\n }\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"active-task-subagent-spawned\",\n subsystem: \"active-task\",\n });\n api.logger.debug?.(`memory-hybrid: active task auto-checkpoint on subagent_spawned failed: ${err}`);\n }\n });\n\n api.on(\"subagent_ended\", async (event: unknown) => {\n try {\n const ev = event as SubagentEndedEvent;\n const staleMinutes = parseDuration(ctx.cfg.activeTask.staleThreshold);\n const targetKey = ev.targetSessionKey ?? ev.sessionKey;\n if (!ev.label && !targetKey) {\n await consumePendingTaskSignals(\n resolvedActiveTaskPath,\n workspaceRoot,\n staleMinutes,\n ctx.cfg.activeTask.flushOnComplete,\n api.logger,\n ctx.cfg.activeTask.ledger,\n ctx.factsDb,\n ctx.vectorDb,\n ctx.embeddings,\n api.context?.sessionKey,\n );\n return;\n }\n\n let taskFile: { active: ActiveTaskEntry[]; completed: ActiveTaskEntry[] } | null = null;\n if (ctx.cfg.activeTask.ledger === \"facts\") {\n const { active, completed } = loadTaskLedgerFromFacts(ctx.factsDb);\n taskFile = { active, completed };\n } else {\n taskFile = await readActiveTaskFile(resolvedActiveTaskPath, staleMinutes);\n }\n if (!taskFile) {\n await consumePendingTaskSignals(\n resolvedActiveTaskPath,\n workspaceRoot,\n staleMinutes,\n ctx.cfg.activeTask.flushOnComplete,\n api.logger,\n ctx.cfg.activeTask.ledger,\n ctx.factsDb,\n ctx.vectorDb,\n ctx.embeddings,\n api.context?.sessionKey,\n );\n return;\n }\n\n const existingTask = findActiveTaskForSubagentEnd(taskFile.active, ev);\n if (!existingTask) {\n await consumePendingTaskSignals(\n resolvedActiveTaskPath,\n workspaceRoot,\n staleMinutes,\n ctx.cfg.activeTask.flushOnComplete,\n api.logger,\n ctx.cfg.activeTask.ledger,\n ctx.factsDb,\n ctx.vectorDb,\n ctx.embeddings,\n api.context?.sessionKey,\n );\n return;\n }\n\n const taskLabel = existingTask.label;\n const now = new Date().toISOString();\n const newStatus = subagentEndedIsSuccess(ev) ? \"Done\" : \"Failed\";\n const subSession = isSubagentSession(api.context?.sessionKey);\n\n if (newStatus === \"Done\") {\n const { updated, completed } = completeTask(taskFile.active, taskLabel);\n if (completed) {\n if (ctx.cfg.activeTask.ledger === \"facts\") {\n if (subSession) {\n api.logger.debug?.(\n \"memory-hybrid: skipped facts ledger write in subagent_ended (Done, sub-agent session)\",\n );\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"cleanup:facts-ledger-write-skipped\",\n outcome: \"skipped\",\n sessionId: api.context?.sessionKey,\n context: { reason: \"sub-agent session\", taskLabel: completed?.label },\n });\n } else {\n const doneEntry: ActiveTaskEntry = { ...completed, status: \"Done\", updated: now };\n await syncActiveTaskEntryToFacts(ctx.factsDb, ctx.vectorDb, ctx.embeddings, doneEntry, api.logger);\n if (ctx.cfg.activeTask.flushOnComplete) {\n const memoryDir = join(workspaceRoot, \"memory\");\n await flushCompletedTaskToMemory(doneEntry, memoryDir).catch(() => {});\n }\n api.logger.info?.(\n `memory-hybrid: auto-checkpoint — updated task [${taskLabel}] to ${newStatus} on subagent_ended`,\n );\n }\n } else {\n const writeResult = await writeActiveTaskFileGuarded(\n resolvedActiveTaskPath,\n updated,\n [...taskFile.completed, completed],\n api.context?.sessionKey,\n );\n if (writeResult.skipped) {\n api.logger.debug?.(\n `memory-hybrid: skipped ACTIVE-TASKS.md write in subagent_ended (Done): ${writeResult.reason}`,\n );\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"cleanup:active-task-write-skipped\",\n outcome: \"skipped\",\n sessionId: api.context?.sessionKey,\n context: { reason: writeResult.reason, taskLabel },\n });\n } else {\n if (ctx.cfg.activeTask.flushOnComplete) {\n const memoryDir = join(workspaceRoot, \"memory\");\n await flushCompletedTaskToMemory(completed, memoryDir).catch(() => {});\n }\n api.logger.info?.(\n `memory-hybrid: auto-checkpoint — updated task [${taskLabel}] to ${newStatus} on subagent_ended`,\n );\n }\n }\n }\n } else {\n const errHint = ev.error ?? ev.reason;\n const updatedEntry: ActiveTaskEntry = {\n ...existingTask,\n status: \"Failed\",\n updated: now,\n next: errHint ? `Fix: ${String(errHint).slice(0, 100)}` : existingTask.next,\n };\n if (ctx.cfg.activeTask.ledger === \"facts\") {\n if (subSession) {\n api.logger.debug?.(\n \"memory-hybrid: skipped facts ledger write in subagent_ended (Failed, sub-agent session)\",\n );\n } else {\n await syncActiveTaskEntryToFacts(ctx.factsDb, ctx.vectorDb, ctx.embeddings, updatedEntry, api.logger);\n api.logger.info?.(\n `memory-hybrid: auto-checkpoint — updated task [${taskLabel}] to ${newStatus} on subagent_ended`,\n );\n }\n } else {\n const updated = upsertTask(taskFile.active, updatedEntry);\n const writeResult = await writeActiveTaskFileGuarded(\n resolvedActiveTaskPath,\n updated,\n taskFile.completed,\n api.context?.sessionKey,\n );\n if (writeResult.skipped) {\n api.logger.debug?.(\n `memory-hybrid: skipped ACTIVE-TASKS.md write in subagent_ended (Failed): ${writeResult.reason}`,\n );\n } else {\n api.logger.info?.(\n `memory-hybrid: auto-checkpoint — updated task [${taskLabel}] to ${newStatus} on subagent_ended`,\n );\n }\n }\n }\n\n await consumePendingTaskSignals(\n resolvedActiveTaskPath,\n workspaceRoot,\n staleMinutes,\n ctx.cfg.activeTask.flushOnComplete,\n api.logger,\n ctx.cfg.activeTask.ledger,\n ctx.factsDb,\n ctx.vectorDb,\n ctx.embeddings,\n api.context?.sessionKey,\n );\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"active-task-subagent-ended\",\n subsystem: \"active-task\",\n });\n api.logger.debug?.(`memory-hybrid: active task auto-checkpoint on subagent_ended failed: ${err}`);\n }\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"stage-cleanup.js","names":[],"sources":["../../lifecycle/stage-cleanup.ts"],"sourcesContent":["/**\n * Lifecycle stage: Cleanup (Phase 2.3).\n * OpenClaw typed hooks **subagent_spawned** / **subagent_ended** (issue #966), stale session sweep timer, dispose.\n * Exports: consumePendingTaskSignals, registerCleanupHandlers, createStaleSweepTimer, getDispose.\n */\n\nimport { join } from \"node:path\";\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport {\n type ActiveTaskEntry,\n type PendingTaskSignal,\n completeTask,\n deleteSignal,\n flushCompletedTaskToMemory,\n isSubagentSession,\n readActiveTaskFile,\n readActiveTaskFileWithMtime,\n readPendingSignals,\n upsertTask,\n writeActiveTaskFileGuarded,\n writeActiveTaskFileOptimistic,\n} from \"../services/active-task.js\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport {\n consumePendingTaskSignalsFacts,\n loadTaskLedgerFromFacts,\n syncActiveTaskEntryToFacts,\n} from \"../services/task-ledger-facts.js\";\nimport { parseDuration } from \"../utils/duration.js\";\nimport {\n type SubagentEndedEvent,\n findActiveTaskForSubagentEnd,\n subagentEndedIsSuccess,\n} from \"../utils/subagent-ended-utils.js\";\nimport { resolveAgentIdFromHookEvent } from \"./resolve-agent-id.js\";\nimport type { LifecycleContext, SessionState } from \"./types.js\";\n\nconst STALE_SESSION_TTL_MS = 30 * 60 * 1000; // 30 minutes\nconst STALE_SWEEP_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes\n\n/** OpenClaw core dispatch shapes — see issue #966 / runSubagentSpawned */\ntype SubagentSpawnedEvent = {\n childSessionKey?: string;\n /** Legacy / alternate field names from older handlers */\n sessionKey?: string;\n label?: string;\n task?: string;\n agentId?: string;\n runId?: string;\n};\n\n/**\n * Read all pending task signals from `memory/task-signals/*.json` and apply\n * their status changes to ACTIVE-TASKS.md or the facts ledger. Called after subagent completes.\n */\nasync function consumePendingTaskSignals(\n activeTaskPath: string,\n workspaceRoot: string,\n staleMinutes: number,\n flushOnComplete: boolean,\n logger: { info?: (msg: string) => void; warn?: (msg: string) => void; debug?: (msg: string) => void } | undefined,\n ledger: \"markdown\" | \"facts\",\n factsDb: import(\"../backends/facts-db.js\").FactsDB,\n vectorDb: import(\"../backends/vector-db.js\").VectorDB,\n embeddings: import(\"../services/embeddings.js\").EmbeddingProvider,\n sessionKey?: string,\n): Promise<void> {\n if (isSubagentSession(sessionKey)) {\n logger?.debug?.(\"memory-hybrid: skipping pending task signal consumption in sub-agent session\");\n return;\n }\n\n if (ledger === \"facts\") {\n await consumePendingTaskSignalsFacts(\n workspaceRoot,\n staleMinutes,\n flushOnComplete,\n factsDb,\n vectorDb,\n embeddings,\n logger,\n );\n return;\n }\n\n const memoryDir = join(workspaceRoot, \"memory\");\n let signals: PendingTaskSignal[];\n try {\n signals = await readPendingSignals(memoryDir);\n } catch (err) {\n logger?.warn?.(`memory-hybrid: failed to read pending task signals: ${err}`);\n return;\n }\n\n if (signals.length === 0) return;\n\n const signalTtlMs = Math.max(staleMinutes * 60 * 1000, 24 * 60 * 60 * 1000);\n const nowMs = Date.now();\n const isSignalExpired = (signal: PendingTaskSignal): boolean => {\n const parsed = Date.parse(signal.timestamp);\n if (Number.isNaN(parsed)) return true;\n return nowMs - parsed > signalTtlMs;\n };\n\n signals = [...signals].sort((a, b) => {\n const at = Date.parse(a.timestamp);\n const bt = Date.parse(b.timestamp);\n if (Number.isNaN(at) || Number.isNaN(bt)) return a._filePath.localeCompare(b._filePath);\n return at === bt ? a._filePath.localeCompare(b._filePath) : at - bt;\n });\n\n let taskFile: Awaited<ReturnType<typeof readActiveTaskFileWithMtime>> | undefined;\n try {\n taskFile = await readActiveTaskFileWithMtime(activeTaskPath, staleMinutes);\n } catch (err) {\n logger?.warn?.(`memory-hybrid: failed to read ACTIVE-TASKS.md for signal consumption: ${err}`);\n return;\n }\n\n if (!taskFile) {\n const expiredSignals = signals.filter(isSignalExpired);\n if (expiredSignals.length > 0) {\n for (const signal of expiredSignals) await deleteSignal(signal._filePath).catch(() => {});\n logger?.info?.(\n `memory-hybrid: pruned ${expiredSignals.length} expired task signal(s) while ACTIVE-TASKS.md is missing`,\n );\n }\n logger?.info?.(\"memory-hybrid: ACTIVE-TASKS.md missing; deferring pending task signals\");\n return;\n }\n\n const knownMtime = taskFile.mtime;\n\n const findMatchingTask = (activeEntries: ActiveTaskEntry[], signal: PendingTaskSignal): ActiveTaskEntry | null => {\n const byLabel = activeEntries.filter((t) => t.label === signal.taskRef);\n if (byLabel.length === 1) return byLabel[0];\n if (byLabel.length > 1) {\n logger?.warn?.(`memory-hybrid: multiple active tasks share label ${signal.taskRef}; leaving signal pending`);\n return null;\n }\n const byDescription = activeEntries.filter((t) => t.description === signal.taskRef);\n if (byDescription.length === 1) {\n logger?.warn?.(\n `memory-hybrid: matched signal for \"${signal.taskRef}\" by description (not label); sub-agents should use the exact task label in taskRef for reliable matching`,\n );\n return byDescription[0];\n }\n if (byDescription.length > 1) {\n logger?.warn?.(\n `memory-hybrid: multiple active tasks match description ${signal.taskRef}; leaving signal pending`,\n );\n return null;\n }\n return null;\n };\n\n const applySignals = (\n activeEntries: ActiveTaskEntry[],\n completedEntries: ActiveTaskEntry[],\n ): {\n active: ActiveTaskEntry[];\n completed: ActiveTaskEntry[];\n processedSignals: PendingTaskSignal[];\n expiredSignals: PendingTaskSignal[];\n completedToFlush: ActiveTaskEntry[];\n } => {\n let updatedActive = [...activeEntries];\n const updatedCompleted = [...completedEntries];\n const processedSignals: PendingTaskSignal[] = [];\n const expiredSignals: PendingTaskSignal[] = [];\n const completedToFlush: ActiveTaskEntry[] = [];\n\n for (const signal of signals) {\n try {\n const updatedTimestamp = (() => {\n const t = Date.parse(signal.timestamp);\n return Number.isNaN(t) ? new Date().toISOString() : signal.timestamp;\n })();\n\n const existing = findMatchingTask(updatedActive, signal);\n if (!existing) {\n if (isSignalExpired(signal)) expiredSignals.push(signal);\n else logger?.warn?.(`memory-hybrid: no matching active task for signal ${signal.taskRef}; leaving pending`);\n continue;\n }\n\n if (signal.signal === \"completed\") {\n const { updated, completed } = completeTask(updatedActive, existing.label);\n if (completed) {\n updatedActive = updated;\n updatedCompleted.push({\n ...completed,\n updated: updatedTimestamp,\n handoff: signal._handoff ?? completed.handoff,\n });\n processedSignals.push(signal);\n completedToFlush.push({\n ...completed,\n updated: updatedTimestamp,\n handoff: signal._handoff ?? completed.handoff,\n });\n }\n continue;\n }\n\n if (signal.signal !== \"blocked\" && signal.signal !== \"escalate\" && signal.signal !== \"update\") {\n if (isSignalExpired(signal)) expiredSignals.push(signal);\n else\n logger?.warn?.(\n `memory-hybrid: unhandled task signal \"${signal.signal}\" for ${signal.taskRef}; leaving pending`,\n );\n continue;\n }\n\n const newStatus: ActiveTaskEntry[\"status\"] =\n signal.signal === \"blocked\" ? \"Stalled\" : signal.signal === \"escalate\" ? \"Waiting\" : existing.status;\n const updatedEntry: ActiveTaskEntry = {\n ...existing,\n status: newStatus,\n next: signal.summary ? `[Signal: ${signal.signal}] ${signal.summary}` : existing.next,\n updated: updatedTimestamp,\n handoff: signal._handoff ?? existing.handoff,\n };\n updatedActive = upsertTask(updatedActive, updatedEntry, true);\n processedSignals.push(signal);\n } catch (err) {\n logger?.warn?.(`memory-hybrid: failed to process signal from ${signal._filePath}: ${err}`);\n }\n }\n\n return {\n active: updatedActive,\n completed: updatedCompleted,\n processedSignals,\n expiredSignals,\n completedToFlush,\n };\n };\n\n let latestResult = applySignals(taskFile.active, taskFile.completed);\n let { processedSignals, expiredSignals, completedToFlush } = latestResult;\n\n if (processedSignals.length === 0) {\n if (expiredSignals.length > 0) {\n for (const signal of expiredSignals) await deleteSignal(signal._filePath).catch(() => {});\n logger?.info?.(`memory-hybrid: pruned ${expiredSignals.length} expired task signal(s) with no matching task`);\n }\n return;\n }\n\n let wrote = false;\n try {\n wrote = await writeActiveTaskFileOptimistic(\n activeTaskPath,\n latestResult.active,\n latestResult.completed,\n knownMtime,\n async (fresh) => {\n latestResult = applySignals(fresh.active, fresh.completed);\n processedSignals = latestResult.processedSignals;\n expiredSignals = latestResult.expiredSignals;\n completedToFlush = latestResult.completedToFlush;\n return [latestResult.active, latestResult.completed];\n },\n 3,\n staleMinutes,\n );\n } catch (err) {\n logger?.warn?.(`memory-hybrid: failed to write ACTIVE-TASKS.md after signal consumption: ${err}`);\n }\n\n if (wrote) {\n for (const signal of processedSignals) await deleteSignal(signal._filePath).catch(() => {});\n for (const signal of expiredSignals) await deleteSignal(signal._filePath).catch(() => {});\n if (flushOnComplete && completedToFlush.length > 0) {\n const memoryDir = join(workspaceRoot, \"memory\");\n for (const completed of completedToFlush) {\n await flushCompletedTaskToMemory(completed, memoryDir).catch(() => {});\n }\n }\n logger?.info?.(`memory-hybrid: consumed ${processedSignals.length} pending task signal(s) from sub-agents`);\n } else if (expiredSignals.length > 0) {\n for (const signal of expiredSignals) await deleteSignal(signal._filePath).catch(() => {});\n logger?.info?.(`memory-hybrid: pruned ${expiredSignals.length} expired task signal(s) after write abort`);\n }\n}\n\nfunction sweepStaleSessions(sessionState: SessionState): number {\n const now = Date.now();\n const cutoff = now - STALE_SESSION_TTL_MS;\n let swept = 0;\n for (const [sessionKey, lastActive] of sessionState.sessionLastActivity) {\n if (lastActive < cutoff) {\n sessionState.clearSessionState(sessionKey);\n sessionState.capabilityHintsSessionsSeen.delete(sessionKey);\n swept++;\n }\n }\n return swept;\n}\n\n/**\n * Start the periodic stale session sweep timer. Returns the timer handle for dispose.\n */\nexport function createStaleSweepTimer(sessionState: SessionState): ReturnType<typeof setInterval> {\n return setInterval(() => {\n try {\n sweepStaleSessions(sessionState);\n } catch (err) {\n // Suppress expected database connection errors during shutdown\n const e = err instanceof Error ? err : new Error(String(err));\n if (!/database connection is not open/i.test(e.message)) {\n capturePluginError(e, {\n operation: \"stale-session-sweep\",\n subsystem: \"active-task\",\n });\n }\n }\n }, STALE_SWEEP_INTERVAL_MS);\n}\n\n/**\n * Return a dispose function that clears the sweep timer and all session maps.\n */\nexport function getDispose(timerRef: ReturnType<typeof setInterval> | null, sessionState: SessionState): () => void {\n return () => {\n if (timerRef) clearInterval(timerRef);\n sessionState.clearAll?.();\n };\n}\n\n/**\n * Register **subagent_spawned** and **subagent_ended** handlers (active-task checkpoint + signal consumption).\n * Hook names must match OpenClaw `PLUGIN_HOOK_NAMES` (issue #966).\n */\nexport function registerCleanupHandlers(\n api: ClawdbotPluginApi,\n ctx: LifecycleContext,\n _sessionState: SessionState,\n resolvedActiveTaskPath: string,\n workspaceRoot: string,\n): void {\n if (!ctx.cfg.activeTask.enabled || !ctx.cfg.activeTask.autoCheckpoint) return;\n\n api.on(\"subagent_spawned\", async (event: unknown) => {\n try {\n const ev = event as SubagentSpawnedEvent;\n const childOrSession = ev.childSessionKey ?? ev.sessionKey;\n const label = ev.label ?? childOrSession ?? `subagent-${Date.now()}`;\n const description = ev.task ?? `Subagent task (session: ${childOrSession ?? \"unknown\"})`;\n const staleMinutes = parseDuration(ctx.cfg.activeTask.staleThreshold);\n const now = new Date().toISOString();\n\n if (ctx.cfg.activeTask.ledger === \"facts\") {\n if (isSubagentSession(api.context?.sessionKey)) {\n api.logger.debug?.(\"memory-hybrid: skipped facts ledger checkpoint in subagent_spawned (sub-agent session)\");\n return;\n }\n const { active: existingActive } = loadTaskLedgerFromFacts(ctx.factsDb);\n const existing = existingActive.find((t) => t.label === label);\n const entry: ActiveTaskEntry = {\n label,\n description,\n status: \"In progress\",\n subagent: childOrSession,\n started: existing?.started ?? now,\n updated: now,\n };\n await syncActiveTaskEntryToFacts(ctx.factsDb, ctx.vectorDb, ctx.embeddings, entry, api.logger);\n api.logger.info?.(`memory-hybrid: auto-checkpoint — facts ledger task [${label}] for subagent spawn`);\n return;\n }\n\n const taskFile = await readActiveTaskFile(resolvedActiveTaskPath, staleMinutes);\n const existingActive = taskFile?.active ?? [];\n const existingCompleted = taskFile?.completed ?? [];\n const existing = existingActive.find((t) => t.label === label);\n const entry: ActiveTaskEntry = {\n label,\n description,\n status: \"In progress\",\n subagent: childOrSession,\n started: existing?.started ?? now,\n updated: now,\n };\n const updated = upsertTask(existingActive, entry);\n const writeResult = await writeActiveTaskFileGuarded(\n resolvedActiveTaskPath,\n updated,\n existingCompleted,\n api.context?.sessionKey,\n );\n if (writeResult.skipped) {\n api.logger.debug?.(`memory-hybrid: skipped ACTIVE-TASKS.md write in subagent_spawned: ${writeResult.reason}`);\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"cleanup:active-task-write-skipped\",\n outcome: \"skipped\",\n sessionId: api.context?.sessionKey,\n context: { reason: writeResult.reason, taskLabel: label },\n });\n } else {\n api.logger.info?.(`memory-hybrid: auto-checkpoint — created active task [${label}] for subagent spawn`);\n }\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"active-task-subagent-spawned\",\n subsystem: \"active-task\",\n });\n api.logger.debug?.(`memory-hybrid: active task auto-checkpoint on subagent_spawned failed: ${err}`);\n }\n });\n\n api.on(\"subagent_ended\", async (event: unknown) => {\n try {\n const ev = event as SubagentEndedEvent;\n const staleMinutes = parseDuration(ctx.cfg.activeTask.staleThreshold);\n const targetKey = ev.targetSessionKey ?? ev.sessionKey;\n if (!ev.label && !targetKey) {\n await consumePendingTaskSignals(\n resolvedActiveTaskPath,\n workspaceRoot,\n staleMinutes,\n ctx.cfg.activeTask.flushOnComplete,\n api.logger,\n ctx.cfg.activeTask.ledger,\n ctx.factsDb,\n ctx.vectorDb,\n ctx.embeddings,\n api.context?.sessionKey,\n );\n return;\n }\n\n let taskFile: { active: ActiveTaskEntry[]; completed: ActiveTaskEntry[] } | null = null;\n if (ctx.cfg.activeTask.ledger === \"facts\") {\n const { active, completed } = loadTaskLedgerFromFacts(ctx.factsDb);\n taskFile = { active, completed };\n } else {\n taskFile = await readActiveTaskFile(resolvedActiveTaskPath, staleMinutes);\n }\n if (!taskFile) {\n await consumePendingTaskSignals(\n resolvedActiveTaskPath,\n workspaceRoot,\n staleMinutes,\n ctx.cfg.activeTask.flushOnComplete,\n api.logger,\n ctx.cfg.activeTask.ledger,\n ctx.factsDb,\n ctx.vectorDb,\n ctx.embeddings,\n api.context?.sessionKey,\n );\n return;\n }\n\n const existingTask = findActiveTaskForSubagentEnd(taskFile.active, ev);\n if (!existingTask) {\n await consumePendingTaskSignals(\n resolvedActiveTaskPath,\n workspaceRoot,\n staleMinutes,\n ctx.cfg.activeTask.flushOnComplete,\n api.logger,\n ctx.cfg.activeTask.ledger,\n ctx.factsDb,\n ctx.vectorDb,\n ctx.embeddings,\n api.context?.sessionKey,\n );\n return;\n }\n\n const taskLabel = existingTask.label;\n const now = new Date().toISOString();\n const newStatus = subagentEndedIsSuccess(ev) ? \"Done\" : \"Failed\";\n const subSession = isSubagentSession(api.context?.sessionKey);\n\n if (newStatus === \"Done\") {\n const { updated, completed } = completeTask(taskFile.active, taskLabel);\n if (completed) {\n if (ctx.cfg.activeTask.ledger === \"facts\") {\n if (subSession) {\n api.logger.debug?.(\n \"memory-hybrid: skipped facts ledger write in subagent_ended (Done, sub-agent session)\",\n );\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"cleanup:facts-ledger-write-skipped\",\n outcome: \"skipped\",\n sessionId: api.context?.sessionKey,\n context: { reason: \"sub-agent session\", taskLabel: completed?.label },\n });\n } else {\n const doneEntry: ActiveTaskEntry = { ...completed, status: \"Done\", updated: now };\n await syncActiveTaskEntryToFacts(ctx.factsDb, ctx.vectorDb, ctx.embeddings, doneEntry, api.logger);\n if (ctx.cfg.activeTask.flushOnComplete) {\n const memoryDir = join(workspaceRoot, \"memory\");\n await flushCompletedTaskToMemory(doneEntry, memoryDir).catch(() => {});\n }\n api.logger.info?.(\n `memory-hybrid: auto-checkpoint — updated task [${taskLabel}] to ${newStatus} on subagent_ended`,\n );\n }\n } else {\n const writeResult = await writeActiveTaskFileGuarded(\n resolvedActiveTaskPath,\n updated,\n [...taskFile.completed, completed],\n api.context?.sessionKey,\n );\n if (writeResult.skipped) {\n api.logger.debug?.(\n `memory-hybrid: skipped ACTIVE-TASKS.md write in subagent_ended (Done): ${writeResult.reason}`,\n );\n ctx.auditStore?.append({\n agentId: resolveAgentIdFromHookEvent(event, api) ?? ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"cleanup:active-task-write-skipped\",\n outcome: \"skipped\",\n sessionId: api.context?.sessionKey,\n context: { reason: writeResult.reason, taskLabel },\n });\n } else {\n if (ctx.cfg.activeTask.flushOnComplete) {\n const memoryDir = join(workspaceRoot, \"memory\");\n await flushCompletedTaskToMemory(completed, memoryDir).catch(() => {});\n }\n api.logger.info?.(\n `memory-hybrid: auto-checkpoint — updated task [${taskLabel}] to ${newStatus} on subagent_ended`,\n );\n }\n }\n }\n } else {\n const errHint = ev.error ?? ev.reason;\n const updatedEntry: ActiveTaskEntry = {\n ...existingTask,\n status: \"Failed\",\n updated: now,\n next: errHint ? `Fix: ${String(errHint).slice(0, 100)}` : existingTask.next,\n };\n if (ctx.cfg.activeTask.ledger === \"facts\") {\n if (subSession) {\n api.logger.debug?.(\n \"memory-hybrid: skipped facts ledger write in subagent_ended (Failed, sub-agent session)\",\n );\n } else {\n await syncActiveTaskEntryToFacts(ctx.factsDb, ctx.vectorDb, ctx.embeddings, updatedEntry, api.logger);\n api.logger.info?.(\n `memory-hybrid: auto-checkpoint — updated task [${taskLabel}] to ${newStatus} on subagent_ended`,\n );\n }\n } else {\n const updated = upsertTask(taskFile.active, updatedEntry);\n const writeResult = await writeActiveTaskFileGuarded(\n resolvedActiveTaskPath,\n updated,\n taskFile.completed,\n api.context?.sessionKey,\n );\n if (writeResult.skipped) {\n api.logger.debug?.(\n `memory-hybrid: skipped ACTIVE-TASKS.md write in subagent_ended (Failed): ${writeResult.reason}`,\n );\n } else {\n api.logger.info?.(\n `memory-hybrid: auto-checkpoint — updated task [${taskLabel}] to ${newStatus} on subagent_ended`,\n );\n }\n }\n }\n\n await consumePendingTaskSignals(\n resolvedActiveTaskPath,\n workspaceRoot,\n staleMinutes,\n ctx.cfg.activeTask.flushOnComplete,\n api.logger,\n ctx.cfg.activeTask.ledger,\n ctx.factsDb,\n ctx.vectorDb,\n ctx.embeddings,\n api.context?.sessionKey,\n );\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"active-task-subagent-ended\",\n subsystem: \"active-task\",\n });\n api.logger.debug?.(`memory-hybrid: active task auto-checkpoint on subagent_ended failed: ${err}`);\n }\n });\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"stage-credential-hint.js","names":[],"sources":["../../lifecycle/stage-credential-hint.ts"],"sourcesContent":["/**\n * Lifecycle: credential hint injection (Phase 2.3).\n * Reads credentials-pending.json and injects hint on before_agent_start when enabled.\n */\n\nimport { access, readFile, unlink } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport type { LifecycleContext } from \"./types.js\";\n\nconst PENDING_TTL_MS = 5 * 60 * 1000; // 5 min\n\nexport function registerCredentialHint(api: ClawdbotPluginApi, ctx: LifecycleContext): void {\n if (!ctx.cfg.credentials.enabled || !ctx.cfg.credentials.autoDetect || ctx.cfg.verbosity === \"silent\") return;\n\n const pendingPath = join(dirname(ctx.resolvedSqlitePath), \"credentials-pending.json\");\n\n api.on(\"before_agent_start\", async () => {\n try {\n await access(pendingPath);\n } catch {\n return;\n }\n try {\n const raw = (await readFile(pendingPath, \"utf-8\")).trim();\n if (raw.length === 0) {\n await unlink(pendingPath).catch(() => {});\n return;\n }\n let data: { hints?: string[]; at?: number };\n try {\n data = JSON.parse(raw) as { hints?: string[]; at?: number };\n } catch (parseErr) {\n api.logger?.warn?.(\n `memory-hybrid: credentials-pending.json invalid or truncated JSON (${raw.length} chars), removing: ${parseErr instanceof Error ? parseErr.message : String(parseErr)}`,\n );\n await unlink(pendingPath).catch(() => {});\n return;\n }\n const at = typeof data.at === \"number\" ? data.at : 0;\n if (Date.now() - at > PENDING_TTL_MS) {\n await unlink(pendingPath).catch(() => {});\n return;\n }\n const hints = Array.isArray(data.hints) ? data.hints : [];\n if (hints.length === 0) {\n await unlink(pendingPath).catch(() => {});\n return;\n }\n await unlink(pendingPath).catch(() => {});\n const hintText = hints.join(\", \");\n return {\n prependContext: `\\n<credential-hint>\\nA credential may have been shared in the previous exchange (${hintText}). Consider asking the user if they want to store it securely with credential_store.\\n</credential-hint>\\n`,\n };\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\") {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"credential-hint-read\",\n subsystem: \"credentials\",\n });\n }\n await unlink(pendingPath).catch(() => {});\n }\n });\n}\n"],"mappings":";;;;;;;;AAWA,MAAM,iBAAiB,MAAS;AAEhC,SAAgB,uBAAuB,KAAwB,KAA6B;CAC1F,IAAI,CAAC,IAAI,IAAI,YAAY,WAAW,CAAC,IAAI,IAAI,YAAY,cAAc,IAAI,IAAI,cAAc,UAAU;CAEvG,MAAM,cAAc,KAAK,QAAQ,IAAI,mBAAmB,EAAE,2BAA2B;CAErF,IAAI,GAAG,sBAAsB,YAAY;EACvC,IAAI;GACF,MAAM,OAAO,YAAY;UACnB;GACN;;EAEF,IAAI;GACF,MAAM,OAAO,MAAM,SAAS,aAAa,QAAQ,EAAE,MAAM;GACzD,IAAI,IAAI,WAAW,GAAG;IACpB,MAAM,OAAO,YAAY,CAAC,YAAY,GAAG;IACzC;;GAEF,IAAI;GACJ,IAAI;IACF,OAAO,KAAK,MAAM,IAAI;YACf,UAAU;IACjB,IAAI,QAAQ,OACV,sEAAsE,IAAI,OAAO,qBAAqB,oBAAoB,QAAQ,SAAS,UAAU,OAAO,SAAS,GACtK;IACD,MAAM,OAAO,YAAY,CAAC,YAAY,GAAG;IACzC;;GAEF,MAAM,KAAK,OAAO,KAAK,OAAO,WAAW,KAAK,KAAK;GACnD,IAAI,KAAK,KAAK,GAAG,KAAK,gBAAgB;IACpC,MAAM,OAAO,YAAY,CAAC,YAAY,GAAG;IACzC;;GAEF,MAAM,QAAQ,MAAM,QAAQ,KAAK,MAAM,GAAG,KAAK,QAAQ,EAAE;GACzD,IAAI,MAAM,WAAW,GAAG;IACtB,MAAM,OAAO,YAAY,CAAC,YAAY,GAAG;IACzC;;GAEF,MAAM,OAAO,YAAY,CAAC,YAAY,GAAG;GAEzC,OAAO,EACL,gBAAgB,oFAFD,MAAM,KAAK,KAEkF,CAAC,6GAC9G;WACM,KAAK;GAEZ,IADc,IAA8B,SAC/B,UACX,mBAAmB,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC,EAAE;IACtE,WAAW;IACX,WAAW;IACZ,CAAC;GAEJ,MAAM,OAAO,YAAY,CAAC,YAAY,GAAG;;GAE3C"}
1
+ {"version":3,"file":"stage-credential-hint.js","names":[],"sources":["../../lifecycle/stage-credential-hint.ts"],"sourcesContent":["/**\n * Lifecycle: credential hint injection (Phase 2.3).\n * Reads credentials-pending.json and injects hint on before_agent_start when enabled.\n */\n\nimport { access, readFile, unlink } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport type { LifecycleContext } from \"./types.js\";\n\nconst PENDING_TTL_MS = 5 * 60 * 1000; // 5 min\n\nexport function registerCredentialHint(api: ClawdbotPluginApi, ctx: LifecycleContext): void {\n if (!ctx.cfg.credentials.enabled || !ctx.cfg.credentials.autoDetect || ctx.cfg.verbosity === \"silent\") return;\n\n const pendingPath = join(dirname(ctx.resolvedSqlitePath), \"credentials-pending.json\");\n\n api.on(\"before_agent_start\", async () => {\n try {\n await access(pendingPath);\n } catch {\n return;\n }\n try {\n const raw = (await readFile(pendingPath, \"utf-8\")).trim();\n if (raw.length === 0) {\n await unlink(pendingPath).catch(() => {});\n return;\n }\n let data: { hints?: string[]; at?: number };\n try {\n data = JSON.parse(raw) as { hints?: string[]; at?: number };\n } catch (parseErr) {\n api.logger?.warn?.(\n `memory-hybrid: credentials-pending.json invalid or truncated JSON (${raw.length} chars), removing: ${parseErr instanceof Error ? parseErr.message : String(parseErr)}`,\n );\n await unlink(pendingPath).catch(() => {});\n return;\n }\n const at = typeof data.at === \"number\" ? data.at : 0;\n if (Date.now() - at > PENDING_TTL_MS) {\n await unlink(pendingPath).catch(() => {});\n return;\n }\n const hints = Array.isArray(data.hints) ? data.hints : [];\n if (hints.length === 0) {\n await unlink(pendingPath).catch(() => {});\n return;\n }\n await unlink(pendingPath).catch(() => {});\n const hintText = hints.join(\", \");\n return {\n prependContext: `\\n<credential-hint>\\nA credential may have been shared in the previous exchange (${hintText}). Consider asking the user if they want to store it securely with credential_store.\\n</credential-hint>\\n`,\n };\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\") {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"credential-hint-read\",\n subsystem: \"credentials\",\n });\n }\n await unlink(pendingPath).catch(() => {});\n }\n });\n}\n"],"mappings":";;;;;;;;AAWA,MAAM,iBAAiB,MAAS;AAEhC,SAAgB,uBAAuB,KAAwB,KAA6B;CAC1F,IAAI,CAAC,IAAI,IAAI,YAAY,WAAW,CAAC,IAAI,IAAI,YAAY,cAAc,IAAI,IAAI,cAAc,UAAU;CAEvG,MAAM,cAAc,KAAK,QAAQ,IAAI,kBAAkB,GAAG,0BAA0B;CAEpF,IAAI,GAAG,sBAAsB,YAAY;EACvC,IAAI;GACF,MAAM,OAAO,WAAW;EAC1B,QAAQ;GACN;EACF;EACA,IAAI;GACF,MAAM,OAAO,MAAM,SAAS,aAAa,OAAO,GAAG,KAAK;GACxD,IAAI,IAAI,WAAW,GAAG;IACpB,MAAM,OAAO,WAAW,EAAE,YAAY,CAAC,CAAC;IACxC;GACF;GACA,IAAI;GACJ,IAAI;IACF,OAAO,KAAK,MAAM,GAAG;GACvB,SAAS,UAAU;IACjB,IAAI,QAAQ,OACV,sEAAsE,IAAI,OAAO,qBAAqB,oBAAoB,QAAQ,SAAS,UAAU,OAAO,QAAQ,GACtK;IACA,MAAM,OAAO,WAAW,EAAE,YAAY,CAAC,CAAC;IACxC;GACF;GACA,MAAM,KAAK,OAAO,KAAK,OAAO,WAAW,KAAK,KAAK;GACnD,IAAI,KAAK,IAAI,IAAI,KAAK,gBAAgB;IACpC,MAAM,OAAO,WAAW,EAAE,YAAY,CAAC,CAAC;IACxC;GACF;GACA,MAAM,QAAQ,MAAM,QAAQ,KAAK,KAAK,IAAI,KAAK,QAAQ,CAAC;GACxD,IAAI,MAAM,WAAW,GAAG;IACtB,MAAM,OAAO,WAAW,EAAE,YAAY,CAAC,CAAC;IACxC;GACF;GACA,MAAM,OAAO,WAAW,EAAE,YAAY,CAAC,CAAC;GAExC,OAAO,EACL,gBAAgB,oFAFD,MAAM,KAAK,IAEiF,EAAE,4GAC/G;EACF,SAAS,KAAK;GAEZ,IADc,IAA8B,SAC/B,UACX,mBAAmB,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,GAAG;IACtE,WAAW;IACX,WAAW;GACb,CAAC;GAEH,MAAM,OAAO,WAAW,EAAE,YAAY,CAAC,CAAC;EAC1C;CACF,CAAC;AACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"stage-frustration.js","names":[],"sources":["../../lifecycle/stage-frustration.ts"],"sourcesContent":["/**\n * Lifecycle: frustration detection and tool-hint injection (Phase 2.3).\n */\n\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport { buildFrustrationHint, detectFrustration, exportAsImplicitSignals } from \"../services/frustration-detector.js\";\nimport { ToolEffectivenessStore, generateToolHint } from \"../services/tool-effectiveness.js\";\nimport { withHookResolutionApi } from \"./hook-resolution-api.js\";\nimport type { LifecycleContext, SessionState } from \"./types.js\";\n\nlet cachedToolStore: ToolEffectivenessStore | null = null;\nlet cachedToolStorePath: string | null = null;\n\nfunction getToolEffectivenessStore(resolvedSqlitePath: string): ToolEffectivenessStore {\n const effectivenessDbPath = resolvedSqlitePath.replace(/(\\.[^.]+)?$/, \"-tool-effectiveness.db\");\n if (!cachedToolStore || cachedToolStorePath !== effectivenessDbPath) {\n cachedToolStore = new ToolEffectivenessStore(effectivenessDbPath);\n cachedToolStorePath = effectivenessDbPath;\n }\n return cachedToolStore;\n}\n\nexport function registerFrustrationHandlers(\n api: ClawdbotPluginApi,\n ctx: LifecycleContext,\n sessionState: SessionState,\n): void {\n if (ctx.cfg.frustrationDetection?.enabled === false) return;\n const fCfg = ctx.cfg.frustrationDetection;\n const { resolveSessionKey, frustrationStateMap } = sessionState;\n const currentAgentIdRef = ctx.currentAgentIdRef;\n\n // Must use the two-argument hook signature so cron/embedded identity on hookCtx is visible (#1005).\n api.on(\"before_agent_start\", async (event: unknown, hookCtx: unknown) => {\n const rApi = withHookResolutionApi(api, hookCtx);\n const e = event as {\n prompt?: string;\n messages?: Array<{ role?: string; content?: unknown }>;\n agentId?: string;\n session?: { agentId?: string };\n };\n const sessionKey = resolveSessionKey(event, rApi) ?? currentAgentIdRef.value ?? \"default\";\n\n try {\n let userContent: string | undefined;\n if (typeof e.prompt === \"string\" && e.prompt.trim().length > 0) {\n userContent = e.prompt;\n } else if (Array.isArray(e.messages)) {\n const userMsgs = e.messages.filter((m) => m && typeof m === \"object\" && m.role === \"user\");\n const lastUser = userMsgs[userMsgs.length - 1];\n if (lastUser && typeof lastUser.content === \"string\") userContent = lastUser.content;\n }\n\n if (!userContent || userContent.trim().length < 5) return;\n\n const state = frustrationStateMap.get(sessionKey) ?? { level: 0, turns: [] };\n state.turns.push({ role: \"user\", content: userContent });\n if (state.turns.length > 20) state.turns.splice(0, state.turns.length - 20);\n\n const frustrationResult = detectFrustration(state.turns, fCfg, state.level);\n state.level = frustrationResult.level;\n frustrationStateMap.set(sessionKey, state);\n\n const implicitSignals = exportAsImplicitSignals(frustrationResult);\n if (implicitSignals.length > 0) {\n try {\n const rawDb = ctx.factsDb.getRawDb();\n const insert = rawDb.prepare(`\n INSERT OR IGNORE INTO implicit_signals\n (session_file, signal_type, confidence, polarity, user_message, agent_message, preceding_turns, source)\n VALUES (?, ?, ?, ?, ?, ?, ?, 'frustration')\n `);\n for (const sig of implicitSignals) {\n insert.run(\n sessionKey,\n sig.type,\n sig.confidence,\n sig.polarity,\n userContent.slice(0, 500),\n \"\",\n state.turns.length,\n );\n }\n api.logger.debug?.(\n `memory-hybrid: frustration exported ${implicitSignals.length} implicit signal(s) for session ${sessionKey}`,\n );\n } catch (fsErr) {\n capturePluginError(fsErr instanceof Error ? fsErr : new Error(String(fsErr)), {\n operation: \"frustration-export-implicit-signals\",\n subsystem: \"frustration\",\n severity: \"info\",\n });\n }\n }\n\n if (ctx.cfg.verbosity === \"silent\") return;\n\n const hint = buildFrustrationHint(frustrationResult, fCfg);\n let toolHintText = \"\";\n if (ctx.cfg.toolEffectiveness?.enabled !== false && ctx.cfg.toolEffectiveness?.injectHints !== false) {\n try {\n const toolStore = getToolEffectivenessStore(ctx.resolvedSqlitePath);\n const contextLabel = currentAgentIdRef.value ?? \"general\";\n toolHintText = generateToolHint(toolStore, contextLabel);\n } catch (thErr) {\n capturePluginError(thErr instanceof Error ? thErr : new Error(String(thErr)), {\n operation: \"generate-tool-hint\",\n subsystem: \"tool-effectiveness\",\n severity: \"info\",\n });\n }\n }\n\n const combinedPrepend = [\n hint ? `\\n<frustration-signal>${hint}</frustration-signal>\\n` : \"\",\n toolHintText ? `\\n<tool-hint>${toolHintText}</tool-hint>\\n` : \"\",\n ].join(\"\");\n\n if (combinedPrepend) {\n if (hint) api.logger.debug?.(`memory-hybrid: ${hint}`);\n return { prependContext: combinedPrepend };\n }\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"frustration-detection\",\n subsystem: \"frustration\",\n severity: \"info\",\n });\n }\n return undefined;\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"stage-frustration.js","names":[],"sources":["../../lifecycle/stage-frustration.ts"],"sourcesContent":["/**\n * Lifecycle: frustration detection and tool-hint injection (Phase 2.3).\n */\n\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport { buildFrustrationHint, detectFrustration, exportAsImplicitSignals } from \"../services/frustration-detector.js\";\nimport { ToolEffectivenessStore, generateToolHint } from \"../services/tool-effectiveness.js\";\nimport { withHookResolutionApi } from \"./hook-resolution-api.js\";\nimport type { LifecycleContext, SessionState } from \"./types.js\";\n\nlet cachedToolStore: ToolEffectivenessStore | null = null;\nlet cachedToolStorePath: string | null = null;\n\nfunction getToolEffectivenessStore(resolvedSqlitePath: string): ToolEffectivenessStore {\n const effectivenessDbPath = resolvedSqlitePath.replace(/(\\.[^.]+)?$/, \"-tool-effectiveness.db\");\n if (!cachedToolStore || cachedToolStorePath !== effectivenessDbPath) {\n cachedToolStore = new ToolEffectivenessStore(effectivenessDbPath);\n cachedToolStorePath = effectivenessDbPath;\n }\n return cachedToolStore;\n}\n\nexport function registerFrustrationHandlers(\n api: ClawdbotPluginApi,\n ctx: LifecycleContext,\n sessionState: SessionState,\n): void {\n if (ctx.cfg.frustrationDetection?.enabled === false) return;\n const fCfg = ctx.cfg.frustrationDetection;\n const { resolveSessionKey, frustrationStateMap } = sessionState;\n const currentAgentIdRef = ctx.currentAgentIdRef;\n\n // Must use the two-argument hook signature so cron/embedded identity on hookCtx is visible (#1005).\n api.on(\"before_agent_start\", async (event: unknown, hookCtx: unknown) => {\n const rApi = withHookResolutionApi(api, hookCtx);\n const e = event as {\n prompt?: string;\n messages?: Array<{ role?: string; content?: unknown }>;\n agentId?: string;\n session?: { agentId?: string };\n };\n const sessionKey = resolveSessionKey(event, rApi) ?? currentAgentIdRef.value ?? \"default\";\n\n try {\n let userContent: string | undefined;\n if (typeof e.prompt === \"string\" && e.prompt.trim().length > 0) {\n userContent = e.prompt;\n } else if (Array.isArray(e.messages)) {\n const userMsgs = e.messages.filter((m) => m && typeof m === \"object\" && m.role === \"user\");\n const lastUser = userMsgs[userMsgs.length - 1];\n if (lastUser && typeof lastUser.content === \"string\") userContent = lastUser.content;\n }\n\n if (!userContent || userContent.trim().length < 5) return;\n\n const state = frustrationStateMap.get(sessionKey) ?? { level: 0, turns: [] };\n state.turns.push({ role: \"user\", content: userContent });\n if (state.turns.length > 20) state.turns.splice(0, state.turns.length - 20);\n\n const frustrationResult = detectFrustration(state.turns, fCfg, state.level);\n state.level = frustrationResult.level;\n frustrationStateMap.set(sessionKey, state);\n\n const implicitSignals = exportAsImplicitSignals(frustrationResult);\n if (implicitSignals.length > 0) {\n try {\n const rawDb = ctx.factsDb.getRawDb();\n const insert = rawDb.prepare(`\n INSERT OR IGNORE INTO implicit_signals\n (session_file, signal_type, confidence, polarity, user_message, agent_message, preceding_turns, source)\n VALUES (?, ?, ?, ?, ?, ?, ?, 'frustration')\n `);\n for (const sig of implicitSignals) {\n insert.run(\n sessionKey,\n sig.type,\n sig.confidence,\n sig.polarity,\n userContent.slice(0, 500),\n \"\",\n state.turns.length,\n );\n }\n api.logger.debug?.(\n `memory-hybrid: frustration exported ${implicitSignals.length} implicit signal(s) for session ${sessionKey}`,\n );\n } catch (fsErr) {\n capturePluginError(fsErr instanceof Error ? fsErr : new Error(String(fsErr)), {\n operation: \"frustration-export-implicit-signals\",\n subsystem: \"frustration\",\n severity: \"info\",\n });\n }\n }\n\n if (ctx.cfg.verbosity === \"silent\") return;\n\n const hint = buildFrustrationHint(frustrationResult, fCfg);\n let toolHintText = \"\";\n if (ctx.cfg.toolEffectiveness?.enabled !== false && ctx.cfg.toolEffectiveness?.injectHints !== false) {\n try {\n const toolStore = getToolEffectivenessStore(ctx.resolvedSqlitePath);\n const contextLabel = currentAgentIdRef.value ?? \"general\";\n toolHintText = generateToolHint(toolStore, contextLabel);\n } catch (thErr) {\n capturePluginError(thErr instanceof Error ? thErr : new Error(String(thErr)), {\n operation: \"generate-tool-hint\",\n subsystem: \"tool-effectiveness\",\n severity: \"info\",\n });\n }\n }\n\n const combinedPrepend = [\n hint ? `\\n<frustration-signal>${hint}</frustration-signal>\\n` : \"\",\n toolHintText ? `\\n<tool-hint>${toolHintText}</tool-hint>\\n` : \"\",\n ].join(\"\");\n\n if (combinedPrepend) {\n if (hint) api.logger.debug?.(`memory-hybrid: ${hint}`);\n return { prependContext: combinedPrepend };\n }\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"frustration-detection\",\n subsystem: \"frustration\",\n severity: \"info\",\n });\n }\n return undefined;\n });\n}\n"],"mappings":"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"}