@wrongstack/core 0.313.1 → 0.316.1

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 (290) hide show
  1. package/dist/chronicle/index.js +31 -31
  2. package/dist/chronicle/legacy-journal-import.d.ts +0 -6
  3. package/dist/chronicle/metrics-ingest.d.ts +14 -0
  4. package/dist/chronicle/metrics-schema.d.ts +10 -1
  5. package/dist/chronicle/metrics-store.d.ts +20 -2
  6. package/dist/chronicle/project-server.js +39 -31
  7. package/dist/chronicle/sink.d.ts +13 -0
  8. package/dist/chronicle/sqlite-journal.d.ts +20 -2
  9. package/dist/{chunk-WOEZV3Q4.js → chunk-25LSLC3G.js} +2 -1
  10. package/dist/{chunk-AI4LLQ2U.js → chunk-27QIURLN.js} +229 -12
  11. package/dist/{chunk-I45KAW2N.js → chunk-3AGWVSS7.js} +38 -450
  12. package/dist/chunk-3BDV7RL3.js +211 -0
  13. package/dist/{chunk-NFAYHPRH.js → chunk-3ECENVHL.js} +10 -8
  14. package/dist/{chunk-FW5LDDMJ.js → chunk-45WI72ZB.js} +1576 -1156
  15. package/dist/{chunk-AT4V4XGI.js → chunk-4BMVPOHO.js} +539 -313
  16. package/dist/{chunk-YBUJCZ57.js → chunk-4I7HGVVA.js} +17 -5
  17. package/dist/{chunk-JVGPR3TS.js → chunk-4LCZVJVF.js} +7 -55
  18. package/dist/{chunk-4ZHTKJHM.js → chunk-4SJNS7OB.js} +36 -2
  19. package/dist/{chunk-AD7ZFZCS.js → chunk-5BMIE7QG.js} +3 -3
  20. package/dist/{chunk-IQ35HMQL.js → chunk-5YPSXQXM.js} +71 -24
  21. package/dist/chunk-6FHWXLPT.js +10 -0
  22. package/dist/{chunk-FIV4IJL7.js → chunk-6H5GEOET.js} +163 -20
  23. package/dist/{chunk-VB3H5WWB.js → chunk-6NWEVFEL.js} +2 -2
  24. package/dist/{chunk-E6I5RXVK.js → chunk-AYW5YINX.js} +2 -2
  25. package/dist/{chunk-DEIQMBD2.js → chunk-B7F4WVP4.js} +2 -2
  26. package/dist/{chunk-XQ2XGIBF.js → chunk-BPBKKBUK.js} +6 -7
  27. package/dist/{chunk-K4YUNKU7.js → chunk-BYD345OX.js} +2 -2
  28. package/dist/{chunk-LZDDLNCZ.js → chunk-C27KDLOX.js} +4 -4
  29. package/dist/{chunk-6AKOTGLM.js → chunk-CU546ESW.js} +7 -7
  30. package/dist/{chunk-ZZ4V3WIZ.js → chunk-DLHHXUAM.js} +10 -1
  31. package/dist/{chunk-BAKVJLEV.js → chunk-DOTHQSJ2.js} +28 -16
  32. package/dist/{chunk-KBZGE6LN.js → chunk-DYLPMV4Q.js} +4 -3
  33. package/dist/{chunk-52RTVH4M.js → chunk-F3JWNST7.js} +2 -2
  34. package/dist/{chunk-WEBMSQP2.js → chunk-FC2ZGRF3.js} +21 -4
  35. package/dist/{chunk-FHAMQS7Q.js → chunk-FCBTO76Z.js} +76 -146
  36. package/dist/{chunk-4LJJYBAU.js → chunk-FHZVFYSL.js} +9 -1
  37. package/dist/{chunk-W4A6QA3D.js → chunk-FWNLEZYG.js} +4 -3
  38. package/dist/{chunk-OJZEX73F.js → chunk-GDQ7CZRQ.js} +5 -1
  39. package/dist/{chunk-QVOVMXJR.js → chunk-GJJGJB2R.js} +32 -9
  40. package/dist/{chunk-4XV6IR37.js → chunk-HI3JGZR2.js} +7 -6
  41. package/dist/{chunk-FSWCWSTS.js → chunk-HMLIGAU7.js} +26 -26
  42. package/dist/{chunk-PFXFQQRT.js → chunk-HXKZ7OBQ.js} +7 -43
  43. package/dist/{chunk-2FQL4PDC.js → chunk-I7DALG7J.js} +5 -5
  44. package/dist/{chunk-GM54GJBU.js → chunk-IRUTEHCE.js} +3 -3
  45. package/dist/{chunk-TYW2GI5I.js → chunk-J2WRWR37.js} +40 -13
  46. package/dist/{chunk-ZEHUCJHY.js → chunk-JFPJ6LLQ.js} +2 -2
  47. package/dist/chunk-JMULFFLN.js +9 -0
  48. package/dist/{chunk-RD6DEE36.js → chunk-JO4MGB6Z.js} +94 -8
  49. package/dist/{chunk-5DSMEVA4.js → chunk-K6BXGITA.js} +7 -7
  50. package/dist/{chunk-O74MJHXU.js → chunk-KZMSZV32.js} +2 -2
  51. package/dist/{chunk-GFJOMSHG.js → chunk-LA7CLDRW.js} +6 -2
  52. package/dist/{chunk-M2WF6AXG.js → chunk-LSMMOS2Z.js} +7 -3
  53. package/dist/{chunk-ASX6AW36.js → chunk-LXWCMQNJ.js} +3 -3
  54. package/dist/{chunk-WZO23AWO.js → chunk-M27LIEKV.js} +72 -22
  55. package/dist/{chunk-JTHKOYWU.js → chunk-MJPHJRAL.js} +15 -15
  56. package/dist/{chunk-G5AAKEEZ.js → chunk-MTL4O5YR.js} +5 -5
  57. package/dist/chunk-NHJ75HXY.js +1 -0
  58. package/dist/{chunk-ZYU2YOJ6.js → chunk-NIOAGFPB.js} +29 -15
  59. package/dist/{chunk-Y2GE5TSI.js → chunk-NS52ISWS.js} +2 -2
  60. package/dist/{chunk-UIWONWVG.js → chunk-NSOFPKGT.js} +541 -148
  61. package/dist/{chunk-RCQYT2I4.js → chunk-NVIZG63R.js} +2 -2
  62. package/dist/{chunk-EPC3GZD4.js → chunk-OOYZPOXM.js} +2 -2
  63. package/dist/{chunk-7ZHZE5EO.js → chunk-OSGLYW5J.js} +2 -2
  64. package/dist/{chunk-CE4ZOCOI.js → chunk-PFCMSSUF.js} +9 -9
  65. package/dist/{chunk-GFXZTHNI.js → chunk-PGRVXIMY.js} +5 -5
  66. package/dist/{chunk-JJPMWPB6.js → chunk-PISBFBJN.js} +6 -6
  67. package/dist/chunk-POOOIWE5.js +9 -0
  68. package/dist/{chunk-5RP3QTRL.js → chunk-PQNS3U7Z.js} +20 -3
  69. package/dist/{chunk-3E244UDA.js → chunk-QSTSJOCK.js} +52 -6
  70. package/dist/{chunk-YUPMXOGP.js → chunk-RFQMOKWK.js} +3 -3
  71. package/dist/chunk-RTOTNK3P.js +484 -0
  72. package/dist/{chunk-SN2DQRL6.js → chunk-RXKSDUAU.js} +7 -7
  73. package/dist/{chunk-T3KGZBU5.js → chunk-S45JPKQN.js} +189 -43
  74. package/dist/{chunk-YNCVSFGF.js → chunk-SAFHACFA.js} +4 -1
  75. package/dist/{chunk-KI4L2DUL.js → chunk-TCCHINEF.js} +114 -19
  76. package/dist/{chunk-AWNQ6ED6.js → chunk-THEGTRAG.js} +7 -2
  77. package/dist/{chunk-2KKODIQU.js → chunk-TR4LQE7L.js} +15 -15
  78. package/dist/{chunk-GPQ3NJPR.js → chunk-TWJMGXCI.js} +3 -3
  79. package/dist/{chunk-H72H4XDU.js → chunk-U45AXT5D.js} +9 -9
  80. package/dist/{chunk-62V2AFVG.js → chunk-U4FWBSO3.js} +160 -73
  81. package/dist/{chunk-A455ATZB.js → chunk-UBGDX6FI.js} +8 -1
  82. package/dist/chunk-UJILKYES.js +75 -0
  83. package/dist/{chunk-KSJ5UTP7.js → chunk-ULMAQV3T.js} +84 -4
  84. package/dist/{chunk-CB2HFKTP.js → chunk-VVBP6KGT.js} +1 -1
  85. package/dist/{chunk-RPOA7IAE.js → chunk-W5VITDM2.js} +43 -25
  86. package/dist/{chunk-QRTG4XTI.js → chunk-WAHQVNWT.js} +7 -1
  87. package/dist/{chunk-SQP64RCS.js → chunk-WGGYRBXH.js} +3019 -2976
  88. package/dist/{chunk-K3G6JBUC.js → chunk-WLYKU45P.js} +679 -141
  89. package/dist/chunk-WP7BVANJ.js +53 -0
  90. package/dist/{chunk-GAZEWQEZ.js → chunk-XF4VUMKW.js} +2 -2
  91. package/dist/{chunk-PAAWLLZX.js → chunk-Y5YXDM7D.js} +2 -2
  92. package/dist/{chunk-65RDIOR2.js → chunk-YOPAUVU4.js} +162 -44
  93. package/dist/{chunk-FFSX2QDQ.js → chunk-YPT4A46F.js} +3 -3
  94. package/dist/chunk-YWXT3JNM.js +425 -0
  95. package/dist/{chunk-EFEHDQGY.js → chunk-ZHZ2Y2DH.js} +64 -10
  96. package/dist/{chunk-CQQL4ZOQ.js → chunk-ZT7JNIGX.js} +4 -3
  97. package/dist/coordination/agent-monitor.d.ts +9 -1
  98. package/dist/coordination/agent-subagent-runner.d.ts +1 -1
  99. package/dist/coordination/agents/agent-prompts.d.ts +8 -0
  100. package/dist/coordination/agents/index.d.ts +33 -1
  101. package/dist/coordination/agents/index.js +52 -22
  102. package/dist/coordination/agents/phase3-wave1-platform.d.ts +1 -3
  103. package/dist/coordination/agents/phase3-wave2-meta.d.ts +1 -3
  104. package/dist/coordination/agents/phase8-wave3-products.d.ts +1 -3
  105. package/dist/coordination/agents/phase9-wave4-platform-meta.d.ts +1 -3
  106. package/dist/coordination/agents/project-agent-identity.d.ts +11 -11
  107. package/dist/coordination/agents/types.d.ts +13 -2
  108. package/dist/coordination/brain-monitor.d.ts +30 -7
  109. package/dist/coordination/collab-debug.d.ts +1 -1
  110. package/dist/coordination/collab-pause.d.ts +1 -1
  111. package/dist/coordination/delegate-tool.d.ts +7 -5
  112. package/dist/coordination/director-kanban-queue-helpers.d.ts +1 -0
  113. package/dist/coordination/director-options.d.ts +7 -0
  114. package/dist/coordination/director-spawn-model.d.ts +17 -0
  115. package/dist/coordination/director-tools.d.ts +2 -2
  116. package/dist/coordination/director.d.ts +12 -0
  117. package/dist/coordination/dispatcher.d.ts +8 -0
  118. package/dist/coordination/fleet-bus.d.ts +35 -4
  119. package/dist/coordination/fleet-supervisor.d.ts +10 -2
  120. package/dist/coordination/fleet.d.ts +16 -7
  121. package/dist/coordination/index.d.ts +4 -0
  122. package/dist/coordination/index.js +86 -49
  123. package/dist/coordination/kanban-dispatch-port.d.ts +2 -2
  124. package/dist/coordination/mailbox-http-router.d.ts +4 -3
  125. package/dist/coordination/mailbox-http-validation.d.ts +1 -1
  126. package/dist/coordination/mailbox-project-server.js +15 -15
  127. package/dist/coordination/mailbox-types.d.ts +24 -6
  128. package/dist/coordination/model-tier-leader.d.ts +122 -0
  129. package/dist/coordination/model-tier.d.ts +122 -0
  130. package/dist/coordination/multi-agent-coordinator.d.ts +24 -0
  131. package/dist/coordination/origin-session.d.ts +16 -0
  132. package/dist/coordination/provider-status-tracker.d.ts +37 -5
  133. package/dist/coordination/session-note-hub.d.ts +44 -0
  134. package/dist/coordination/session-note-tool.d.ts +10 -0
  135. package/dist/core/agent.d.ts +1 -1
  136. package/dist/core/context.d.ts +22 -3
  137. package/dist/core/index.d.ts +2 -0
  138. package/dist/core/index.js +130 -38
  139. package/dist/core/request-conversation-binding.d.ts +37 -0
  140. package/dist/core/session-notes.d.ts +25 -0
  141. package/dist/core/system-prompt-builder.d.ts +11 -2
  142. package/dist/core/system-prompt-variants.d.ts +78 -0
  143. package/dist/design/index.js +3 -3
  144. package/dist/execution/auto-compaction-middleware.d.ts +11 -0
  145. package/dist/execution/autonomy-brain.d.ts +2 -1
  146. package/dist/execution/autonomy-prompt-contributor.d.ts +7 -2
  147. package/dist/execution/compaction-core.d.ts +4 -4
  148. package/dist/execution/eternal-autonomy.d.ts +1 -1
  149. package/dist/execution/index.js +138 -129
  150. package/dist/execution/model-runtime.d.ts +0 -7
  151. package/dist/execution/parallel-eternal-engine.d.ts +7 -7
  152. package/dist/extension/index.js +3 -3
  153. package/dist/goal/index.js +6 -6
  154. package/dist/hooks/index.js +3 -3
  155. package/dist/hq/index.js +14 -12
  156. package/dist/hq/persistence/event-log.d.ts +0 -1
  157. package/dist/hq/persistence.d.ts +4 -4
  158. package/dist/hq/publisher.d.ts +2 -0
  159. package/dist/index.d.ts +14 -11
  160. package/dist/index.js +728 -635
  161. package/dist/infrastructure/index.d.ts +4 -4
  162. package/dist/infrastructure/index.js +281 -260
  163. package/dist/infrastructure/token-counter.d.ts +9 -0
  164. package/dist/kernel/events/agent-events.d.ts +77 -3
  165. package/dist/kernel/events/brain-events.d.ts +12 -0
  166. package/dist/kernel/events/provider-events.d.ts +7 -1
  167. package/dist/kernel/events/session-events.d.ts +14 -0
  168. package/dist/kernel/events/tool-events.d.ts +13 -0
  169. package/dist/kernel/index.js +4 -4
  170. package/dist/mailbox-attach.d.ts +1 -1
  171. package/dist/models/index.js +10 -9
  172. package/dist/observability/event-bridge.d.ts +25 -5
  173. package/dist/observability/index.d.ts +9 -8
  174. package/dist/observability/index.js +459 -351
  175. package/dist/observability/tool-usage-source.d.ts +65 -0
  176. package/dist/plugin/index.d.ts +5 -0
  177. package/dist/plugin/index.js +66 -50
  178. package/dist/plugins/auto-review-plugin.d.ts +3 -2
  179. package/dist/plugins/review-finding-commands.d.ts +0 -8
  180. package/dist/{review-finding-store-DKAV3AS6.js → plugins/review-finding-store.js} +7 -6
  181. package/dist/plugins/review-finding-types.js +19 -0
  182. package/dist/plugins/review-report-integration.js +21 -0
  183. package/dist/{review-report-store-OWY3EC3N.js → plugins/review-report-store.js} +7 -6
  184. package/dist/plugins/review-report-types.js +13 -0
  185. package/dist/prompts/index.js +5 -5
  186. package/dist/registry/index.js +3 -3
  187. package/dist/registry/tool-registry.d.ts +59 -9
  188. package/dist/{registry-R23UBE7H.js → registry-7N4O3E7W.js} +5 -5
  189. package/dist/security/capabilities.d.ts +6 -0
  190. package/dist/security/file-permissions.d.ts +1 -1
  191. package/dist/security/index.js +47 -33
  192. package/dist/security/permission-policy.d.ts +12 -1
  193. package/dist/security/secret-scrubber.d.ts +15 -0
  194. package/dist/session-catalog/index.d.ts +1 -0
  195. package/dist/session-catalog/index.js +19 -14
  196. package/dist/session-catalog/project-server.js +30 -13
  197. package/dist/session-catalog/protocol.d.ts +32 -1
  198. package/dist/session-catalog/registry.d.ts +17 -1
  199. package/dist/session-catalog/session-agents.d.ts +56 -0
  200. package/dist/session-catalog/store-rebuild.d.ts +14 -0
  201. package/dist/session-catalog/store-schema.d.ts +26 -0
  202. package/dist/session-catalog/store.d.ts +27 -1
  203. package/dist/session-note-attach.d.ts +9 -0
  204. package/dist/skills/index.js +5 -5
  205. package/dist/statusline/index.d.ts +43 -0
  206. package/dist/statusline/index.js +102 -0
  207. package/dist/storage/board-store-port.d.ts +2 -2
  208. package/dist/storage/config-loader/in-project-policy.d.ts +29 -0
  209. package/dist/storage/config-loader.d.ts +3 -2
  210. package/dist/storage/file-session-writer.d.ts +4 -2
  211. package/dist/storage/goal-coordination.d.ts +6 -1
  212. package/dist/storage/goal-kanban.d.ts +4 -1
  213. package/dist/storage/index.d.ts +12 -4
  214. package/dist/storage/index.js +76 -61
  215. package/dist/storage/input-history-store.d.ts +2 -4
  216. package/dist/storage/memory-curator.d.ts +133 -0
  217. package/dist/storage/session-agent-attribution.d.ts +39 -0
  218. package/dist/storage/session-doctor.d.ts +109 -0
  219. package/dist/storage/session-event-bridge.d.ts +5 -7
  220. package/dist/storage/session-outcome.d.ts +42 -0
  221. package/dist/storage/session-recovery.d.ts +55 -0
  222. package/dist/storage/session-store/load-session-data.d.ts +11 -0
  223. package/dist/storage/session-store/prune-helpers.d.ts +1 -1
  224. package/dist/storage/session-store/resume-session.d.ts +0 -2
  225. package/dist/storage/session-store/types.d.ts +8 -0
  226. package/dist/storage/session-store.d.ts +3 -3
  227. package/dist/storage/session-summary-tracker.d.ts +8 -1
  228. package/dist/storage/session-write-buffer.d.ts +18 -0
  229. package/dist/storage/session-writer-truncate.d.ts +2 -0
  230. package/dist/tasking/index.js +2 -2
  231. package/dist/tools/fallback-manage-tools.d.ts +6 -4
  232. package/dist/tools/index.js +21 -21
  233. package/dist/tools/model-tier-set-tool.d.ts +66 -0
  234. package/dist/types/agent-bridge.d.ts +2 -1
  235. package/dist/types/config/mcp-features.d.ts +7 -0
  236. package/dist/types/config/model-tiers.d.ts +148 -0
  237. package/dist/types/config/root.d.ts +9 -0
  238. package/dist/types/config/tools.d.ts +73 -0
  239. package/dist/types/config.d.ts +1 -0
  240. package/dist/types/context.d.ts +2 -0
  241. package/dist/types/default-config.d.ts +6 -0
  242. package/dist/types/errors.d.ts +2 -1
  243. package/dist/types/index.d.ts +11 -9
  244. package/dist/types/index.js +25 -15
  245. package/dist/types/multi-agent.d.ts +43 -0
  246. package/dist/types/plugin.d.ts +1 -1
  247. package/dist/types/provider.d.ts +15 -0
  248. package/dist/types/runtime-capability-manifest.d.ts +1 -1
  249. package/dist/types/secret-scrubber.d.ts +15 -0
  250. package/dist/types/session-markers.d.ts +37 -10
  251. package/dist/types/session-markers.js +1 -1
  252. package/dist/types/session-timeline.d.ts +197 -0
  253. package/dist/types/session-timeline.js +12 -0
  254. package/dist/types/session.d.ts +172 -11
  255. package/dist/types/system-prompt.d.ts +27 -0
  256. package/dist/utils/config-backup.d.ts +9 -1
  257. package/dist/utils/heap-watchdog.js +2 -2
  258. package/dist/utils/index.js +50 -48
  259. package/dist/utils/message-invariants.d.ts +4 -1
  260. package/dist/utils/regex-guard.d.ts +1 -1
  261. package/dist/utils/socket-path.d.ts +1 -1
  262. package/dist/utils/token-estimate.d.ts +6 -2
  263. package/dist/utils/wstack-paths.d.ts +2 -0
  264. package/dist/wiring/proxy-rewrite.d.ts +28 -0
  265. package/dist/wiring/proxy-rewrite.js +7 -1
  266. package/dist/worktree/index.js +2 -2
  267. package/instructions/agents/explore-companion.md +45 -18
  268. package/instructions/agents/memory-curator.md +34 -22
  269. package/instructions/coordination/director-preamble.md +12 -7
  270. package/instructions/coordination/subagent-baseline.md +26 -5
  271. package/instructions/leader-after-task.md +4 -1
  272. package/instructions/llm/chimera-review.md +30 -9
  273. package/instructions/llm/memory-curator.md +31 -0
  274. package/instructions/sections/tool/delegation-compact.md +2 -0
  275. package/instructions/sections/tool/delegation-full.md +5 -1
  276. package/instructions/sections/tool/mailbox-compact.md +5 -1
  277. package/instructions/sections/tool/mailbox-full.md +3 -0
  278. package/instructions/sections/tool/session-note-compact.md +3 -0
  279. package/instructions/sections/tool/session-note-full.md +15 -0
  280. package/instructions/system-lite.md +9 -4
  281. package/instructions/system-pro.md +66 -143
  282. package/instructions/system.md +73 -175
  283. package/package.json +32 -4
  284. package/dist/chunk-2BUUIMQB.js +0 -225
  285. package/dist/chunk-FAYRX2AD.js +0 -13
  286. package/dist/chunk-H5E77KUJ.js +0 -15
  287. package/dist/chunk-M7BS2K6U.js +0 -1
  288. package/dist/coordination/agents.d.ts +0 -8
  289. package/dist/coordination/transport.d.ts +0 -2
  290. package/dist/storage/session-writer/session-writer-summary-tracker.d.ts +0 -28
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-SWUFN7XM.js";
4
4
  import {
5
5
  normalizeInlineProviderModels
6
- } from "./chunk-IQ35HMQL.js";
6
+ } from "./chunk-5YPSXQXM.js";
7
7
  import {
8
8
  decryptConfigSecrets
9
9
  } from "./chunk-YY6APYUM.js";
@@ -13,30 +13,28 @@ import {
13
13
  scrubPersistedSessionEvent,
14
14
  scrubPersistedSessionSummary,
15
15
  sessionContentPreview,
16
+ summarizeSessionFile,
16
17
  userInputTitle
17
- } from "./chunk-UIWONWVG.js";
18
- import {
19
- SECRET_FILE_MODE
20
- } from "./chunk-H5E77KUJ.js";
21
- import {
22
- DefaultSecretScrubber
23
- } from "./chunk-3E244UDA.js";
24
- import {
25
- MEMORY_TYPE_LABELS
26
- } from "./chunk-57GEWK5X.js";
18
+ } from "./chunk-NSOFPKGT.js";
27
19
  import {
28
20
  compileUserRegex
29
- } from "./chunk-TYW2GI5I.js";
21
+ } from "./chunk-J2WRWR37.js";
30
22
  import {
31
23
  safeParse
32
- } from "./chunk-RPOA7IAE.js";
24
+ } from "./chunk-W5VITDM2.js";
33
25
  import {
34
26
  sessionScopedPath
35
- } from "./chunk-AD7ZFZCS.js";
27
+ } from "./chunk-5BMIE7QG.js";
36
28
  import {
37
29
  readBundledInstructionText,
38
30
  renderInstructionTemplate
39
31
  } from "./chunk-5S437PRC.js";
32
+ import {
33
+ DefaultSecretScrubber
34
+ } from "./chunk-QSTSJOCK.js";
35
+ import {
36
+ SECRET_FILE_MODE
37
+ } from "./chunk-6FHWXLPT.js";
40
38
  import {
41
39
  isPidAlive
42
40
  } from "./chunk-TRT2HRWZ.js";
@@ -44,19 +42,22 @@ import {
44
42
  atomicWrite,
45
43
  ensureDir,
46
44
  withFileLock
47
- } from "./chunk-7ZHZE5EO.js";
45
+ } from "./chunk-OSGLYW5J.js";
46
+ import {
47
+ MEMORY_TYPE_LABELS
48
+ } from "./chunk-57GEWK5X.js";
49
+ import {
50
+ expectDefined
51
+ } from "./chunk-PFZO3C6H.js";
48
52
  import {
49
53
  ConfigError,
50
54
  ERROR_CODES,
51
55
  SessionError,
52
56
  WrongStackError
53
- } from "./chunk-WOEZV3Q4.js";
57
+ } from "./chunk-25LSLC3G.js";
54
58
  import {
55
59
  toErrorMessage
56
60
  } from "./chunk-TBRL2RCC.js";
57
- import {
58
- expectDefined
59
- } from "./chunk-PFZO3C6H.js";
60
61
 
61
62
  // src/session-catalog/session-registry.ts
62
63
  import * as fs2 from "node:fs/promises";
@@ -109,8 +110,8 @@ async function breakStaleLock(lockPath) {
109
110
  const ownerPid = Number.parseInt(trimmed.slice(colonIdx + 1), 10);
110
111
  if (ownerHost === HOST_NAME && Number.isInteger(ownerPid) && ownerPid > 0) {
111
112
  if (isPidAlive(ownerPid)) {
112
- const stat7 = await fs.stat(lockPath);
113
- if (Date.now() - stat7.mtimeMs > SAME_HOST_STALE_MS) {
113
+ const stat8 = await fs.stat(lockPath);
114
+ if (Date.now() - stat8.mtimeMs > SAME_HOST_STALE_MS) {
114
115
  return await breakStaleLockVerified(lockPath, async () => {
115
116
  const st = await fs.stat(lockPath);
116
117
  return Date.now() - st.mtimeMs > SAME_HOST_STALE_MS;
@@ -196,9 +197,9 @@ async function pruneStaleTempFiles(filePath) {
196
197
  for (const name of await fs.readdir(dir)) {
197
198
  const isTemp = (name.startsWith(`${base}.`) || name.startsWith(`.${base}.`)) && name.endsWith(".tmp");
198
199
  if (!isTemp) continue;
199
- const stat7 = await fs.stat(path.join(dir, name)).catch(() => null);
200
- if (!stat7) continue;
201
- if (now - stat7.mtimeMs > STALE_TMP_MS) stale.push({ name, mtimeMs: stat7.mtimeMs });
200
+ const stat8 = await fs.stat(path.join(dir, name)).catch(() => null);
201
+ if (!stat8) continue;
202
+ if (now - stat8.mtimeMs > STALE_TMP_MS) stale.push({ name, mtimeMs: stat8.mtimeMs });
202
203
  }
203
204
  stale.sort((a, b) => a.mtimeMs - b.mtimeMs);
204
205
  await Promise.all(
@@ -293,10 +294,6 @@ var SessionRegistry = class {
293
294
  await this.atomicUpdate((registry) => {
294
295
  const now = Date.now();
295
296
  for (const [id, existing] of Object.entries(registry)) {
296
- if (existing.pid === entry.pid) {
297
- if (id !== entry.sessionId) delete registry[id];
298
- continue;
299
- }
300
297
  const heartbeatAt = Date.parse(existing.lastHeartbeatAt);
301
298
  if (!Number.isFinite(heartbeatAt) || now - heartbeatAt > PID_CHECK_AFTER_MS && !pidAlive(existing.pid)) {
302
299
  delete registry[id];
@@ -1035,7 +1032,8 @@ var DefaultAttachmentStore = class {
1035
1032
  let ref;
1036
1033
  if (m[3] !== void 0) {
1037
1034
  const wantPath = m[3];
1038
- ref = findLast(this.refs, (r) => r.kind === "file" && refPath(r) === wantPath);
1035
+ const norm = (s) => s?.replace(/\\/g, "/");
1036
+ ref = findLast(this.refs, (r) => r.kind === "file" && norm(refPath(r)) === norm(wantPath));
1039
1037
  } else {
1040
1038
  const kind = prefixToKind(m[1]);
1041
1039
  const seq = Number(m[2]);
@@ -1123,6 +1121,19 @@ async function loadCompletedWorkCheckpoint(filePath, events, traceId) {
1123
1121
  try {
1124
1122
  raw = await fsp2.readFile(filePath, "utf8");
1125
1123
  } catch (err) {
1124
+ const code = err.code;
1125
+ if (code === "ENOENT") {
1126
+ events?.emit("storage.read", {
1127
+ sessionId: traceId ?? "~boot~",
1128
+ store: "completed-work",
1129
+ filePath,
1130
+ operation: "load",
1131
+ outcome: "success",
1132
+ durationMs: Date.now() - t0,
1133
+ ...traceId !== void 0 && { traceId }
1134
+ });
1135
+ return null;
1136
+ }
1126
1137
  events?.emit("storage.error", {
1127
1138
  sessionId: traceId ?? "~boot~",
1128
1139
  store: "completed-work",
@@ -1307,7 +1318,7 @@ var DefaultConfigStore = class {
1307
1318
  }
1308
1319
  const prev = this.current;
1309
1320
  this.current = next;
1310
- for (const w of this.watchers) {
1321
+ for (const w of [...this.watchers]) {
1311
1322
  try {
1312
1323
  w(next, prev);
1313
1324
  } catch (err) {
@@ -1409,13 +1420,11 @@ var InputHistoryStore = class {
1409
1420
  }
1410
1421
  /**
1411
1422
  * Heuristic: did the scrubber actually redact anything? DefaultSecretScrubber
1412
- * replaces matches with "***REDACTED***", so a residual marker means a secret
1413
- * was detected. Subclasses of SecretScrubber that use a different sentinel
1414
- * can be accommodated by widening this check in the future; for now the
1415
- * marker check covers the shipped scrubber.
1423
+ * replaces matches with "[REDACTED:<type>]" (and legacy mocks with
1424
+ * "***REDACTED***"), so a residual marker means a secret was detected.
1416
1425
  */
1417
1426
  looksRedacted(text) {
1418
- return text.includes("***REDACTED***");
1427
+ return text.includes("***REDACTED***") || /\[REDACTED:[a-zA-Z0-9_-]+\]/.test(text);
1419
1428
  }
1420
1429
  };
1421
1430
 
@@ -1577,8 +1586,8 @@ var FileMemoryBackend = class {
1577
1586
  }
1578
1587
  async getMtime(file) {
1579
1588
  try {
1580
- const stat7 = await fs5.stat(file);
1581
- return stat7.mtimeMs;
1589
+ const stat8 = await fs5.stat(file);
1590
+ return stat8.mtimeMs;
1582
1591
  } catch {
1583
1592
  return 0;
1584
1593
  }
@@ -1631,13 +1640,13 @@ var FileMemoryBackend = class {
1631
1640
  await withFileLock(file, async () => {
1632
1641
  const handle = await fs5.open(file, "a+", SECRET_FILE_MODE);
1633
1642
  try {
1634
- const stat7 = await handle.stat();
1643
+ const stat8 = await handle.stat();
1635
1644
  let prefix = "";
1636
- if (stat7.size === 0) {
1645
+ if (stat8.size === 0) {
1637
1646
  prefix = "# Agent Memory\n\n";
1638
1647
  } else {
1639
1648
  const tail = Buffer.allocUnsafe(1);
1640
- const { bytesRead } = await handle.read(tail, 0, 1, stat7.size - 1);
1649
+ const { bytesRead } = await handle.read(tail, 0, 1, stat8.size - 1);
1641
1650
  if (bytesRead === 1 && tail[0] !== 10) prefix = "\n";
1642
1651
  }
1643
1652
  await handle.appendFile(`${prefix}${line}`, "utf8");
@@ -1828,8 +1837,8 @@ ${existingEntries.map((e) => `- [${e.ts.slice(0, 10)}] ${e.text}`).join("\n")}`
1828
1837
  });
1829
1838
  }
1830
1839
  function relativeEvidencePath(projectRoot, filePath) {
1831
- const relative3 = path6.relative(projectRoot, filePath);
1832
- return relative3 && !relative3.startsWith("..") && !path6.isAbsolute(relative3) ? relative3.replaceAll("\\", "/") : filePath.replaceAll("\\", "/");
1840
+ const relative4 = path6.relative(projectRoot, filePath);
1841
+ return relative4 && !relative4.startsWith("..") && !path6.isAbsolute(relative4) ? relative4.replaceAll("\\", "/") : filePath.replaceAll("\\", "/");
1833
1842
  }
1834
1843
  function safeCommandEvidence(value) {
1835
1844
  if (typeof value !== "string") return void 0;
@@ -2038,6 +2047,252 @@ function buildSessionDigestText(finalText, iterations, factsAdded) {
2038
2047
  return `Session digest (${iterations} iter${factsAdded > 0 ? `, ${factsAdded} facts added` : ""}): ` + summary + (cleaned.length > 400 ? "\u2026" : "");
2039
2048
  }
2040
2049
 
2050
+ // src/storage/memory-curator.ts
2051
+ import * as path7 from "node:path";
2052
+ function toSageKind2(type) {
2053
+ switch (type) {
2054
+ case "decision":
2055
+ case "convention":
2056
+ case "preference":
2057
+ case "anti_pattern":
2058
+ case "warning":
2059
+ case "workflow":
2060
+ case "bug_root_cause":
2061
+ case "file_note":
2062
+ case "symbol_note":
2063
+ case "command_note":
2064
+ return type;
2065
+ default:
2066
+ return "fact";
2067
+ }
2068
+ }
2069
+ function importanceFromPriority2(priority) {
2070
+ switch (priority) {
2071
+ case "critical":
2072
+ return 0.95;
2073
+ case "high":
2074
+ return 0.8;
2075
+ case "medium":
2076
+ return 0.55;
2077
+ case "low":
2078
+ return 0.25;
2079
+ default:
2080
+ return 0.6;
2081
+ }
2082
+ }
2083
+ function relativePath(projectRoot, filePath) {
2084
+ const rel = path7.relative(projectRoot, filePath);
2085
+ return rel && !rel.startsWith("..") && !path7.isAbsolute(rel) ? rel.replaceAll("\\", "/") : filePath.replaceAll("\\", "/");
2086
+ }
2087
+ function formatCandidateRecord(record) {
2088
+ const anchors = record.anchors && record.anchors.length > 0 ? ` [anchors: ${record.anchors.map((a) => a.path ? `${a.type}:${a.path}` : a.type).join(", ")}]` : "";
2089
+ const tags = record.tags && record.tags.length > 0 ? ` [tags: ${record.tags.join(", ")}]` : "";
2090
+ const status = record.status ? ` (status: ${record.status})` : "";
2091
+ const kind = record.kind ? ` [${record.kind}]` : "";
2092
+ return `- ID: ${record.id}${status}${kind}: "${record.text}"${tags}${anchors} (importance: ${record.importance ?? 0.6}, confidence: ${record.confidence ?? 0.8})`;
2093
+ }
2094
+ var SessionMemoryCurator = class {
2095
+ name = "session-memory-curator";
2096
+ owner = "core";
2097
+ Sage;
2098
+ provider;
2099
+ model;
2100
+ maxTargetMemories;
2101
+ oneShotOrchestrator;
2102
+ constructor(opts) {
2103
+ this.Sage = opts.Sage;
2104
+ this.provider = opts.provider;
2105
+ this.model = opts.model;
2106
+ this.maxTargetMemories = opts.maxTargetMemories ?? 10;
2107
+ this.oneShotOrchestrator = opts.oneShotOrchestrator;
2108
+ }
2109
+ afterRun = async (ctx, result) => {
2110
+ if (result.status !== "done") return;
2111
+ if (!this.Sage?.updateSage) return;
2112
+ const provider = this.provider ?? ctx.provider;
2113
+ if (!provider?.complete && !this.oneShotOrchestrator) return;
2114
+ const projectRoot = ctx.projectRoot ?? ctx.cwd ?? "";
2115
+ const writtenFiles = [...ctx.writtenFiles ?? []].slice(0, 6).map((f) => relativePath(projectRoot, f));
2116
+ const targetMap = /* @__PURE__ */ new Map();
2117
+ try {
2118
+ for (const file of writtenFiles) {
2119
+ if (targetMap.size >= this.maxTargetMemories) break;
2120
+ if (this.Sage.retrieveForPath) {
2121
+ const matched = await this.Sage.retrieveForPath({
2122
+ path: file,
2123
+ limit: 4,
2124
+ includeStatuses: ["active", "stale"]
2125
+ });
2126
+ for (const m of matched) {
2127
+ if (m.id && !targetMap.has(m.id)) {
2128
+ targetMap.set(m.id, m);
2129
+ }
2130
+ }
2131
+ } else if (this.Sage.searchSage) {
2132
+ const searchHits = await this.Sage.searchSage(file, {
2133
+ limit: 4,
2134
+ scope: "project",
2135
+ includeStatuses: ["active", "stale"]
2136
+ });
2137
+ for (const m of searchHits) {
2138
+ if (m.id && !targetMap.has(m.id)) {
2139
+ targetMap.set(m.id, m);
2140
+ }
2141
+ }
2142
+ }
2143
+ }
2144
+ if (this.Sage.listCandidates && targetMap.size < this.maxTargetMemories) {
2145
+ const candidates = await this.Sage.listCandidates(false);
2146
+ for (const c of candidates) {
2147
+ if (targetMap.size >= this.maxTargetMemories) break;
2148
+ if (c.memoryId && !targetMap.has(c.memoryId) && this.Sage.getSage) {
2149
+ const mem = await this.Sage.getSage(c.memoryId);
2150
+ if (mem?.id) {
2151
+ targetMap.set(mem.id, mem);
2152
+ }
2153
+ }
2154
+ }
2155
+ }
2156
+ if (targetMap.size === 0) return;
2157
+ const candidatesBlock = [...targetMap.values()].slice(0, this.maxTargetMemories).map(formatCandidateRecord).join("\n");
2158
+ const prompt = renderInstructionTemplate(
2159
+ readBundledInstructionText("llm/memory-curator.md"),
2160
+ {
2161
+ writtenFiles: writtenFiles.length > 0 ? writtenFiles.join(", ") : "(none)",
2162
+ summary: (result.finalText ?? "").slice(0, 800),
2163
+ candidates: candidatesBlock
2164
+ }
2165
+ );
2166
+ const _model = this.model ?? ctx.model;
2167
+ let text = "";
2168
+ if (this.oneShotOrchestrator) {
2169
+ const oneShotResult = await this.oneShotOrchestrator.call({
2170
+ system: prompt,
2171
+ userPrompt: "Review candidate memories against session changes and return JSON operations.",
2172
+ model: _model ?? "deepseek-chat",
2173
+ maxTokens: 400,
2174
+ timeoutMs: 1e4
2175
+ });
2176
+ text = oneShotResult.text;
2177
+ } else if (provider?.complete) {
2178
+ const signal = AbortSignal.timeout(1e4);
2179
+ const response = await provider.complete(
2180
+ {
2181
+ model: _model,
2182
+ system: [{ type: "text", text: prompt }],
2183
+ messages: [
2184
+ {
2185
+ role: "user",
2186
+ content: "Review candidate memories against session changes and return JSON operations."
2187
+ }
2188
+ ],
2189
+ maxTokens: 400
2190
+ },
2191
+ { signal }
2192
+ );
2193
+ text = response.content.filter((b) => b.type === "text").map((b) => b.text).join("").trim();
2194
+ }
2195
+ if (!text) return;
2196
+ const jsonMatch = text.match(/\{[\s\S]*\}/);
2197
+ if (!jsonMatch) return;
2198
+ const parsed = JSON.parse(jsonMatch[0]);
2199
+ if (!Array.isArray(parsed.operations) || parsed.operations.length === 0) return;
2200
+ let supersededCount = 0;
2201
+ let mergedCount = 0;
2202
+ let splitCount = 0;
2203
+ let recalibratedCount = 0;
2204
+ for (const op of parsed.operations.slice(0, 15)) {
2205
+ try {
2206
+ if (!op || typeof op !== "object") continue;
2207
+ if (op.action === "supersede" && typeof op.targetId === "string") {
2208
+ const target = targetMap.get(op.targetId);
2209
+ if (target?.persistence === "permanent") continue;
2210
+ await this.Sage.updateSage(op.targetId, {
2211
+ status: "superseded",
2212
+ ...op.supersededBy ? { supersedes: [op.supersededBy] } : {}
2213
+ });
2214
+ supersededCount++;
2215
+ } else if (op.action === "contradict" && typeof op.targetId === "string") {
2216
+ const target = targetMap.get(op.targetId);
2217
+ if (target?.persistence === "permanent") continue;
2218
+ await this.Sage.updateSage(op.targetId, {
2219
+ status: "contradicted",
2220
+ ...op.contradictsWith ? { contradicts: [op.contradictsWith] } : {}
2221
+ });
2222
+ supersededCount++;
2223
+ } else if (op.action === "merge" && Array.isArray(op.targetIds) && op.text?.trim()) {
2224
+ const remembered = await this.Sage.rememberSage({
2225
+ text: op.text.trim(),
2226
+ kind: toSageKind2(op.type),
2227
+ importance: importanceFromPriority2(op.priority),
2228
+ confidence: typeof op.confidence === "number" ? op.confidence : 0.85,
2229
+ tags: op.tags,
2230
+ anchors: op.anchors,
2231
+ persistence: "long_lived",
2232
+ supersedes: op.targetIds,
2233
+ sources: [{ type: "session", sessionId: ctx.session.id }]
2234
+ });
2235
+ const newId = remembered?.id;
2236
+ for (const oldId of op.targetIds) {
2237
+ const old = targetMap.get(oldId);
2238
+ if (old?.persistence !== "permanent") {
2239
+ await this.Sage.updateSage(oldId, {
2240
+ status: "superseded",
2241
+ ...newId ? { supersedes: [newId] } : {}
2242
+ });
2243
+ }
2244
+ }
2245
+ mergedCount++;
2246
+ } else if (op.action === "split" && typeof op.targetId === "string" && Array.isArray(op.items)) {
2247
+ for (const item of op.items.slice(0, 4)) {
2248
+ if (!item.text?.trim()) continue;
2249
+ await this.Sage.rememberSage({
2250
+ text: item.text.trim(),
2251
+ kind: toSageKind2(item.type),
2252
+ importance: importanceFromPriority2(item.priority),
2253
+ confidence: typeof item.confidence === "number" ? item.confidence : 0.85,
2254
+ tags: item.tags,
2255
+ anchors: item.anchors,
2256
+ persistence: "long_lived",
2257
+ supersedes: [op.targetId],
2258
+ sources: [{ type: "session", sessionId: ctx.session.id }]
2259
+ });
2260
+ }
2261
+ const target = targetMap.get(op.targetId);
2262
+ if (target?.persistence !== "permanent") {
2263
+ await this.Sage.updateSage(op.targetId, { status: "superseded" });
2264
+ }
2265
+ splitCount++;
2266
+ } else if (op.action === "recalibrate" && typeof op.targetId === "string") {
2267
+ const patch = {};
2268
+ if (typeof op.importance === "number") patch.importance = Math.max(0, Math.min(1, op.importance));
2269
+ if (typeof op.confidence === "number") patch.confidence = Math.max(0, Math.min(1, op.confidence));
2270
+ if (typeof op.freshness === "number") patch.freshness = Math.max(0, Math.min(1, op.freshness));
2271
+ if (typeof op.status === "string" && ["active", "stale", "archived"].includes(op.status)) {
2272
+ const target = targetMap.get(op.targetId);
2273
+ if (target?.persistence !== "permanent" || op.status === "active") {
2274
+ patch.status = op.status;
2275
+ }
2276
+ }
2277
+ if (Object.keys(patch).length > 0) {
2278
+ await this.Sage.updateSage(op.targetId, patch);
2279
+ recalibratedCount++;
2280
+ }
2281
+ }
2282
+ } catch {
2283
+ }
2284
+ }
2285
+ if (supersededCount > 0 || mergedCount > 0 || splitCount > 0 || recalibratedCount > 0) {
2286
+ process.stderr.write(
2287
+ `[memory] Session curation: ${supersededCount} superseded, ${mergedCount} merged, ${splitCount} split, ${recalibratedCount} recalibrated
2288
+ `
2289
+ );
2290
+ }
2291
+ } catch {
2292
+ }
2293
+ };
2294
+ };
2295
+
2041
2296
  // src/storage/memory-graph-backend.ts
2042
2297
  import * as fs6 from "node:fs/promises";
2043
2298
  var GraphMemoryBackend = class _GraphMemoryBackend {
@@ -2389,9 +2644,63 @@ function simpleHash(s) {
2389
2644
  return Math.abs(h).toString(36);
2390
2645
  }
2391
2646
 
2647
+ // src/storage/orphan-lock-cleaner.ts
2648
+ import * as fsp3 from "node:fs/promises";
2649
+ import * as path8 from "node:path";
2650
+ async function cleanOrphanLocks(projectRoot, options) {
2651
+ const result = {
2652
+ cleanedGitLocks: [],
2653
+ cleanedWorktrees: [],
2654
+ errors: []
2655
+ };
2656
+ const pidAlive2 = options?.isPidAlive ?? isPidAlive;
2657
+ const maxAgeMs = options?.maxLockAgeMs ?? 10 * 60 * 1e3;
2658
+ const now = Date.now();
2659
+ const worktreesDir = path8.join(projectRoot, ".wrongstack", "worktrees");
2660
+ try {
2661
+ const entries = await fsp3.readdir(worktreesDir, { withFileTypes: true });
2662
+ for (const entry of entries) {
2663
+ if (!entry.isDirectory()) continue;
2664
+ const wtPath = path8.join(worktreesDir, entry.name);
2665
+ const lockPath = path8.join(wtPath, ".lock");
2666
+ try {
2667
+ const lockStat = await fsp3.stat(lockPath).catch(() => null);
2668
+ if (lockStat) {
2669
+ const raw = await fsp3.readFile(lockPath, "utf8").catch(() => "");
2670
+ const pid = parseInt(raw.trim(), 10);
2671
+ if (Number.isInteger(pid) && pid > 0) {
2672
+ if (!pidAlive2(pid)) {
2673
+ try {
2674
+ await fsp3.unlink(lockPath);
2675
+ result.cleanedWorktrees.push(wtPath);
2676
+ } catch (unlinkErr) {
2677
+ result.errors.push(`Failed removing stale lock ${lockPath}: ${toErrorMessage(unlinkErr)}`);
2678
+ }
2679
+ }
2680
+ } else if (now - lockStat.mtimeMs > maxAgeMs) {
2681
+ try {
2682
+ await fsp3.unlink(lockPath);
2683
+ result.cleanedWorktrees.push(wtPath);
2684
+ } catch (unlinkErr) {
2685
+ result.errors.push(`Failed removing expired lock ${lockPath}: ${toErrorMessage(unlinkErr)}`);
2686
+ }
2687
+ }
2688
+ }
2689
+ } catch (err) {
2690
+ result.errors.push(`Failed inspecting worktree ${entry.name}: ${toErrorMessage(err)}`);
2691
+ }
2692
+ }
2693
+ } catch (err) {
2694
+ if (err.code !== "ENOENT") {
2695
+ result.errors.push(`Failed reading worktrees dir: ${toErrorMessage(err)}`);
2696
+ }
2697
+ }
2698
+ return result;
2699
+ }
2700
+
2392
2701
  // src/storage/plan-store.ts
2393
2702
  import { randomUUID as randomUUID4 } from "node:crypto";
2394
- import * as fsp3 from "node:fs/promises";
2703
+ import * as fsp4 from "node:fs/promises";
2395
2704
  function assertPlanMutationInvariants(previous, updated) {
2396
2705
  const ids = updated.items.map((item) => item.id);
2397
2706
  const uniqueIds = new Set(ids);
@@ -2419,7 +2728,7 @@ async function loadPlan(filePath, events) {
2419
2728
  const t0 = Date.now();
2420
2729
  let raw;
2421
2730
  try {
2422
- raw = await fsp3.readFile(filePath, "utf8");
2731
+ raw = await fsp4.readFile(filePath, "utf8");
2423
2732
  } catch (err) {
2424
2733
  events?.emit("storage.error", {
2425
2734
  sessionId: "~boot~",
@@ -2731,7 +3040,7 @@ ${cat}:`);
2731
3040
  // src/storage/provider-config-watcher.ts
2732
3041
  import * as syncFs from "node:fs";
2733
3042
  import * as fs7 from "node:fs/promises";
2734
- import * as path7 from "node:path";
3043
+ import * as path9 from "node:path";
2735
3044
  async function readProviderSnapshot(configPath, vault, warn) {
2736
3045
  let raw;
2737
3046
  try {
@@ -2807,7 +3116,7 @@ function serializeSnapshot(s) {
2807
3116
  function watchProviderConfig(configPath, vault, onChange, opts = {}) {
2808
3117
  const debounceMs = opts.debounceMs ?? 200;
2809
3118
  const warn = opts.warn;
2810
- const base = path7.basename(configPath);
3119
+ const base = path9.basename(configPath);
2811
3120
  let timer;
2812
3121
  let closed = false;
2813
3122
  let lastSerialized;
@@ -2818,7 +3127,7 @@ function watchProviderConfig(configPath, vault, onChange, opts = {}) {
2818
3127
  });
2819
3128
  let watcher;
2820
3129
  try {
2821
- watcher = syncFs.watch(path7.dirname(configPath), { recursive: false });
3130
+ watcher = syncFs.watch(path9.dirname(configPath), { recursive: false });
2822
3131
  } catch (err) {
2823
3132
  warn?.(`Provider config watcher could not start: ${err.message}`);
2824
3133
  return { close: () => {
@@ -2861,8 +3170,8 @@ function watchProviderConfig(configPath, vault, onChange, opts = {}) {
2861
3170
  }
2862
3171
 
2863
3172
  // src/storage/queue-store.ts
2864
- import * as fsp4 from "node:fs/promises";
2865
- import * as path8 from "node:path";
3173
+ import * as fsp5 from "node:fs/promises";
3174
+ import * as path10 from "node:path";
2866
3175
  var QUEUE_MAX_ITEMS = 100;
2867
3176
  var QUEUE_MAX_BYTES = 16 * 1024 * 1024;
2868
3177
  var QUEUE_MAX_ITEM_BYTES = 8 * 1024 * 1024;
@@ -2895,7 +3204,7 @@ var QueueStore = class {
2895
3204
  traceId;
2896
3205
  logger;
2897
3206
  constructor(opts) {
2898
- this.file = path8.join(opts.dir, "queue.json");
3207
+ this.file = path10.join(opts.dir, "queue.json");
2899
3208
  this.events = opts.events;
2900
3209
  this.traceId = opts.traceId;
2901
3210
  this.logger = opts.logger;
@@ -2964,12 +3273,12 @@ var QueueStore = class {
2964
3273
  const t0 = Date.now();
2965
3274
  let raw;
2966
3275
  try {
2967
- const stat7 = await fsp4.stat(this.file);
2968
- if (stat7.size > QUEUE_MAX_BYTES) {
3276
+ const stat8 = await fsp5.stat(this.file);
3277
+ if (stat8.size > QUEUE_MAX_BYTES) {
2969
3278
  this.logWarn("Queue file exceeds the safe read budget; ignoring it", {
2970
3279
  event: "queue_store.read_budget_exceeded",
2971
3280
  path: this.file,
2972
- bytes: stat7.size,
3281
+ bytes: stat8.size,
2973
3282
  maxBytes: QUEUE_MAX_BYTES
2974
3283
  });
2975
3284
  this.events?.emit("storage.read", {
@@ -2984,7 +3293,7 @@ var QueueStore = class {
2984
3293
  });
2985
3294
  return [];
2986
3295
  }
2987
- raw = await fsp4.readFile(this.file, "utf8");
3296
+ raw = await fsp5.readFile(this.file, "utf8");
2988
3297
  } catch (err) {
2989
3298
  const code = err.code;
2990
3299
  if (code === "ENOENT") {
@@ -3071,7 +3380,7 @@ var QueueStore = class {
3071
3380
  async clear() {
3072
3381
  const t0 = Date.now();
3073
3382
  try {
3074
- await fsp4.unlink(this.file);
3383
+ await fsp5.unlink(this.file);
3075
3384
  this.events?.emit("storage.write", {
3076
3385
  sessionId: this.traceId ?? "~boot~",
3077
3386
  store: "queue",
@@ -3109,9 +3418,9 @@ function isPersistedQueueItem(v) {
3109
3418
  }
3110
3419
 
3111
3420
  // src/storage/recovery-lock.ts
3112
- import * as fsp5 from "node:fs/promises";
3421
+ import * as fsp6 from "node:fs/promises";
3113
3422
  import * as os from "node:os";
3114
- import * as path9 from "node:path";
3423
+ import * as path11 from "node:path";
3115
3424
  var LOCK_FILE = "active.json";
3116
3425
  var DEFAULT_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
3117
3426
  var RecoveryLock = class {
@@ -3122,7 +3431,7 @@ var RecoveryLock = class {
3122
3431
  sessionStore;
3123
3432
  probe;
3124
3433
  constructor(opts) {
3125
- this.file = path9.join(opts.dir, LOCK_FILE);
3434
+ this.file = path11.join(opts.dir, LOCK_FILE);
3126
3435
  this.pid = opts.pid ?? process.pid;
3127
3436
  this.hostname = opts.hostname ?? os.hostname();
3128
3437
  this.maxAgeMs = opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
@@ -3160,13 +3469,14 @@ var RecoveryLock = class {
3160
3469
  if (this.sessionStore) {
3161
3470
  try {
3162
3471
  const data = await this.sessionStore.load(lock.sessionId);
3163
- const lastEnd = data.events.findLastIndex((e) => e.type === "session_end");
3164
- const closed = lastEnd >= 0 && !data.events.slice(lastEnd + 1).some(
3472
+ const events = Array.isArray(data?.events) ? data.events : [];
3473
+ const lastEnd = events.findLastIndex ? events.findLastIndex((e) => e.type === "session_end") : -1;
3474
+ const closed = lastEnd >= 0 && !events.slice(lastEnd + 1).some(
3165
3475
  (e) => e.type === "user_input" || e.type === "llm_response" || e.type === "in_flight_start"
3166
3476
  );
3167
3477
  if (closed) return null;
3168
- messageCount = data.messages.length;
3169
- for (const event of data.events) {
3478
+ messageCount = Array.isArray(data?.messages) ? data.messages.length : 0;
3479
+ for (const event of events) {
3170
3480
  if (event.type !== "user_input") continue;
3171
3481
  if (title === void 0) title = userInputTitle(event.content);
3172
3482
  lastUserMessage = sessionContentPreview(event.content);
@@ -3196,7 +3506,7 @@ var RecoveryLock = class {
3196
3506
  * null return before calling this.
3197
3507
  */
3198
3508
  async write(sessionId) {
3199
- await ensureDir(path9.dirname(this.file));
3509
+ await ensureDir(path11.dirname(this.file));
3200
3510
  const lock = {
3201
3511
  v: 1,
3202
3512
  sessionId,
@@ -3205,7 +3515,7 @@ var RecoveryLock = class {
3205
3515
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
3206
3516
  };
3207
3517
  try {
3208
- await fsp5.writeFile(this.file, JSON.stringify(lock), { flag: "wx", mode: 384 });
3518
+ await fsp6.writeFile(this.file, JSON.stringify(lock), { flag: "wx", mode: 384 });
3209
3519
  } catch (err) {
3210
3520
  const code = err.code;
3211
3521
  if (code === "EEXIST") {
@@ -3221,7 +3531,7 @@ var RecoveryLock = class {
3221
3531
  */
3222
3532
  async clear() {
3223
3533
  try {
3224
- await fsp5.unlink(this.file);
3534
+ await fsp6.unlink(this.file);
3225
3535
  } catch (err) {
3226
3536
  const code = err.code;
3227
3537
  if (code === "ENOENT") return;
@@ -3231,7 +3541,7 @@ var RecoveryLock = class {
3231
3541
  async readLock() {
3232
3542
  let raw;
3233
3543
  try {
3234
- raw = await fsp5.readFile(this.file, "utf8");
3544
+ raw = await fsp6.readFile(this.file, "utf8");
3235
3545
  } catch (err) {
3236
3546
  const code = err.code;
3237
3547
  if (code === "ENOENT") return null;
@@ -3253,55 +3563,9 @@ function isLockFile(v) {
3253
3563
  }
3254
3564
  var defaultIsPidAlive = isPidAlive;
3255
3565
 
3256
- // src/storage/orphan-lock-cleaner.ts
3257
- import * as fsp6 from "node:fs/promises";
3258
- import * as path10 from "node:path";
3259
- async function cleanOrphanLocks(projectRoot, options) {
3260
- const result = {
3261
- cleanedGitLocks: [],
3262
- cleanedWorktrees: [],
3263
- errors: []
3264
- };
3265
- const pidAlive2 = options?.isPidAlive ?? isPidAlive;
3266
- const maxAgeMs = options?.maxLockAgeMs ?? 10 * 60 * 1e3;
3267
- const now = Date.now();
3268
- const worktreesDir = path10.join(projectRoot, ".wrongstack", "worktrees");
3269
- try {
3270
- const entries = await fsp6.readdir(worktreesDir, { withFileTypes: true });
3271
- for (const entry of entries) {
3272
- if (!entry.isDirectory()) continue;
3273
- const wtPath = path10.join(worktreesDir, entry.name);
3274
- const lockPath = path10.join(wtPath, ".lock");
3275
- try {
3276
- const lockStat = await fsp6.stat(lockPath).catch(() => null);
3277
- if (lockStat) {
3278
- const raw = await fsp6.readFile(lockPath, "utf8").catch(() => "");
3279
- const pid = parseInt(raw.trim(), 10);
3280
- if (Number.isInteger(pid) && pid > 0) {
3281
- if (!pidAlive2(pid)) {
3282
- await fsp6.unlink(lockPath).catch(() => void 0);
3283
- result.cleanedWorktrees.push(wtPath);
3284
- }
3285
- } else if (now - lockStat.mtimeMs > maxAgeMs) {
3286
- await fsp6.unlink(lockPath).catch(() => void 0);
3287
- result.cleanedWorktrees.push(wtPath);
3288
- }
3289
- }
3290
- } catch (err) {
3291
- result.errors.push(`Failed inspecting worktree ${entry.name}: ${toErrorMessage(err)}`);
3292
- }
3293
- }
3294
- } catch (err) {
3295
- if (err.code !== "ENOENT") {
3296
- result.errors.push(`Failed reading worktrees dir: ${toErrorMessage(err)}`);
3297
- }
3298
- }
3299
- return result;
3300
- }
3301
-
3302
3566
  // src/storage/replay-log-store.ts
3303
3567
  import * as fs8 from "node:fs/promises";
3304
- import * as path11 from "node:path";
3568
+ import * as path12 from "node:path";
3305
3569
  function storageErrorString(err) {
3306
3570
  if (err instanceof Error) {
3307
3571
  const code = err.code;
@@ -3355,11 +3619,12 @@ var ReplayLogStore = class _ReplayLogStore {
3355
3619
  const line = JSON.stringify(entry) + "\n";
3356
3620
  let offset2 = 0;
3357
3621
  try {
3358
- const stat7 = await fs8.stat(fp);
3359
- offset2 = stat7.size;
3622
+ const stat8 = await fs8.stat(fp);
3623
+ offset2 = stat8.size;
3360
3624
  } catch (err) {
3361
3625
  if (err.code !== "ENOENT") throw err;
3362
3626
  }
3627
+ await fs8.mkdir(path12.dirname(fp), { recursive: true });
3363
3628
  await fs8.appendFile(fp, line, { encoding: "utf8", mode: SECRET_FILE_MODE });
3364
3629
  cache.set(hash, { entry, offset: offset2, length: Buffer.byteLength(line, "utf8") });
3365
3630
  this.diskCount.set(input.sessionId, currentCount + 1);
@@ -3506,13 +3771,13 @@ var ReplayLogStore = class _ReplayLogStore {
3506
3771
  for (const entry of entries) {
3507
3772
  if (entry.name.startsWith(".")) continue;
3508
3773
  if (entry.isDirectory()) {
3509
- if (depth === 0) await scan(path11.join(dir, entry.name), entry.name, depth + 1);
3774
+ if (depth === 0) await scan(path12.join(dir, entry.name), entry.name, depth + 1);
3510
3775
  continue;
3511
3776
  }
3512
3777
  if (!entry.isFile() || !entry.name.endsWith(".replay.jsonl")) continue;
3513
3778
  const base = entry.name.slice(0, -".replay.jsonl".length);
3514
3779
  const sessionId = prefix ? `${prefix}/${base}` : base;
3515
- const fp = path11.join(dir, entry.name);
3780
+ const fp = path12.join(dir, entry.name);
3516
3781
  out.push({
3517
3782
  sessionId,
3518
3783
  entryCount: await this.countEntries(fp),
@@ -3721,6 +3986,28 @@ var ReplayLogStore = class _ReplayLogStore {
3721
3986
  }
3722
3987
  };
3723
3988
 
3989
+ // src/storage/session-agent-attribution.ts
3990
+ function stampAgentId(event, agentId) {
3991
+ if (event.agentId !== void 0) return event;
3992
+ return { ...event, agentId };
3993
+ }
3994
+ function withAgentAttribution(writer, agentId) {
3995
+ const cleanId = agentId?.trim();
3996
+ if (!cleanId) return writer;
3997
+ return new Proxy(writer, {
3998
+ get(target, property, receiver) {
3999
+ if (property === "append") {
4000
+ return (event) => target.append(stampAgentId(event, cleanId));
4001
+ }
4002
+ if (property === "appendBatch") {
4003
+ return (events) => target.appendBatch(events.map((event) => stampAgentId(event, cleanId)));
4004
+ }
4005
+ const value = Reflect.get(target, property, receiver);
4006
+ return typeof value === "function" ? value.bind(target) : value;
4007
+ }
4008
+ });
4009
+ }
4010
+
3724
4011
  // src/storage/session-analyzer.ts
3725
4012
  var SessionAnalyzer = class {
3726
4013
  analyze(events) {
@@ -3802,9 +4089,9 @@ var SessionAnalyzer = class {
3802
4089
  if (!filter.toolNames.includes(toolEvent.name)) return false;
3803
4090
  }
3804
4091
  if (filter.timeRange) {
3805
- const ts = new Date(e.ts).getTime();
3806
- const start = new Date(filter.timeRange.start).getTime();
3807
- const end = new Date(filter.timeRange.end).getTime();
4092
+ const ts = Date.parse(e.ts) || 0;
4093
+ const start = Date.parse(filter.timeRange.start) || 0;
4094
+ const end = Date.parse(filter.timeRange.end) || Number.POSITIVE_INFINITY;
3808
4095
  if (ts < start || ts > end) return false;
3809
4096
  }
3810
4097
  return true;
@@ -3815,12 +4102,253 @@ var SessionAnalyzer = class {
3815
4102
  const firstEvent = events[0];
3816
4103
  const lastEvent = events[events.length - 1];
3817
4104
  if (!firstEvent || !lastEvent) return 0;
3818
- const first = new Date(firstEvent.ts).getTime();
3819
- const last = new Date(lastEvent.ts).getTime();
3820
- return last - first;
4105
+ const first = Date.parse(firstEvent.ts) || 0;
4106
+ const last = Date.parse(lastEvent.ts) || 0;
4107
+ return Math.max(0, last - first);
3821
4108
  }
3822
4109
  };
3823
4110
 
4111
+ // src/storage/session-doctor.ts
4112
+ import { createReadStream } from "node:fs";
4113
+ import * as fsp7 from "node:fs/promises";
4114
+ import * as path13 from "node:path";
4115
+ import { createInterface } from "node:readline";
4116
+ var BOUNDARY_TYPES = /* @__PURE__ */ new Set([
4117
+ "session_start",
4118
+ "in_flight_start",
4119
+ "in_flight_end",
4120
+ "session_end"
4121
+ ]);
4122
+ var TYPE_RE = /"type"\s*:\s*"([A-Za-z0-9_:.-]+)"/;
4123
+ var TYPE_PROBE_CHARS = 200;
4124
+ function readEventType(line) {
4125
+ if (line.length === 0 || line[0] !== "{") return null;
4126
+ const fast = TYPE_RE.exec(line.slice(0, TYPE_PROBE_CHARS));
4127
+ if (fast?.[1]) return fast[1];
4128
+ return line.length > TYPE_PROBE_CHARS ? TYPE_RE.exec(line)?.[1] ?? null : null;
4129
+ }
4130
+ function severityRank(diagnosis) {
4131
+ if (diagnosis.findings.some((f) => f.severity === "error")) return 0;
4132
+ if (diagnosis.findings.some((f) => f.severity === "warn")) return 1;
4133
+ return 2;
4134
+ }
4135
+ async function collectJournals(sessionsDir) {
4136
+ const out = [];
4137
+ let days;
4138
+ try {
4139
+ const entries = await fsp7.readdir(sessionsDir, { withFileTypes: true });
4140
+ days = entries.filter((e) => e.isDirectory()).map((e) => e.name);
4141
+ } catch {
4142
+ return out;
4143
+ }
4144
+ for (const day of days) {
4145
+ if (day.startsWith("_")) continue;
4146
+ let names;
4147
+ try {
4148
+ names = await fsp7.readdir(path13.join(sessionsDir, day));
4149
+ } catch {
4150
+ continue;
4151
+ }
4152
+ for (const name of names) {
4153
+ if (!name.endsWith(".jsonl")) continue;
4154
+ out.push({
4155
+ id: `${day}/${name.slice(0, -".jsonl".length)}`,
4156
+ file: path13.join(sessionsDir, day, name)
4157
+ });
4158
+ }
4159
+ }
4160
+ return out.sort((a, b) => a.id.localeCompare(b.id));
4161
+ }
4162
+ async function endsWithNewline(file, bytes) {
4163
+ if (bytes === 0) return true;
4164
+ const handle = await fsp7.open(file, "r");
4165
+ try {
4166
+ const buffer = Buffer.alloc(1);
4167
+ await handle.read(buffer, 0, 1, bytes - 1);
4168
+ return buffer.toString("utf8") === "\n";
4169
+ } finally {
4170
+ await handle.close();
4171
+ }
4172
+ }
4173
+ async function scanJournal(id, file, oversizedBytes, signal) {
4174
+ const stat8 = await fsp7.stat(file);
4175
+ const diagnosis = {
4176
+ id,
4177
+ file,
4178
+ bytes: stat8.size,
4179
+ lines: 0,
4180
+ unparsableLines: 0,
4181
+ snapshotBytes: 0,
4182
+ lastBoundary: null,
4183
+ hasSessionStart: false,
4184
+ hasSummarySidecar: false,
4185
+ summaryStale: false,
4186
+ findings: []
4187
+ };
4188
+ const stream = createReadStream(file, { encoding: "utf8" });
4189
+ const rl = createInterface({ input: stream, crlfDelay: Infinity });
4190
+ try {
4191
+ for await (const line of rl) {
4192
+ signal?.throwIfAborted();
4193
+ diagnosis.lines++;
4194
+ if (line.length === 0) continue;
4195
+ const type = readEventType(line);
4196
+ if (type === null) {
4197
+ diagnosis.unparsableLines++;
4198
+ continue;
4199
+ }
4200
+ if (type === "session_start") diagnosis.hasSessionStart = true;
4201
+ if (BOUNDARY_TYPES.has(type)) {
4202
+ diagnosis.lastBoundary = type;
4203
+ }
4204
+ if (type === "messages_replaced" || type === "context_snapshot") {
4205
+ diagnosis.snapshotBytes += line.length;
4206
+ }
4207
+ }
4208
+ } finally {
4209
+ rl.close();
4210
+ stream.destroy();
4211
+ }
4212
+ const sidecar = `${file.slice(0, -".jsonl".length)}.summary.json`;
4213
+ const sidecarStat = await fsp7.stat(sidecar).catch(() => null);
4214
+ diagnosis.hasSummarySidecar = sidecarStat !== null;
4215
+ diagnosis.summaryStale = sidecarStat !== null && sidecarStat.mtimeMs + 1 < stat8.mtimeMs;
4216
+ const add = (finding) => {
4217
+ diagnosis.findings.push(finding);
4218
+ };
4219
+ if (diagnosis.lines === 0) {
4220
+ add({ code: "empty", severity: "info", detail: "no events recorded" });
4221
+ }
4222
+ if (diagnosis.unparsableLines > 0) {
4223
+ add({
4224
+ code: "unparsable_lines",
4225
+ severity: "error",
4226
+ // The loader skips these without a word, so the only symptom is a
4227
+ // transcript that is quietly missing turns.
4228
+ detail: `${diagnosis.unparsableLines} of ${diagnosis.lines} lines cannot be parsed \u2014 the loader skips them silently`
4229
+ });
4230
+ }
4231
+ if (!await endsWithNewline(file, stat8.size)) {
4232
+ add({
4233
+ code: "truncated_tail",
4234
+ severity: "warn",
4235
+ detail: "last line is incomplete \u2014 the process died mid-write"
4236
+ });
4237
+ }
4238
+ if (diagnosis.lines > 0 && !diagnosis.hasSessionStart) {
4239
+ add({
4240
+ code: "missing_session_start",
4241
+ severity: "warn",
4242
+ detail: "no session_start \u2014 model/provider metadata is unknown"
4243
+ });
4244
+ }
4245
+ if (diagnosis.lastBoundary === "in_flight_start") {
4246
+ add({
4247
+ code: "died_mid_turn",
4248
+ severity: "warn",
4249
+ // Not a defect to fix here: `store.resume()` heals it on open, pairing
4250
+ // the dangling tool_uses with synthesized results.
4251
+ detail: "died mid-turn \u2014 resume repairs this on open"
4252
+ });
4253
+ } else if (diagnosis.lines > 0 && diagnosis.lastBoundary !== "session_end") {
4254
+ add({
4255
+ code: "never_closed",
4256
+ severity: "info",
4257
+ detail: "no session_end \u2014 killed rather than closed"
4258
+ });
4259
+ }
4260
+ if (!diagnosis.hasSummarySidecar && diagnosis.lines > 0) {
4261
+ add({
4262
+ code: "missing_summary",
4263
+ severity: "warn",
4264
+ detail: "no .summary.json \u2014 the picker has no title or counts for it",
4265
+ fix: "rebuild the summary from the journal"
4266
+ });
4267
+ } else if (diagnosis.summaryStale) {
4268
+ add({
4269
+ code: "stale_summary",
4270
+ severity: "info",
4271
+ detail: ".summary.json is older than the transcript",
4272
+ fix: "rebuild the summary from the journal"
4273
+ });
4274
+ }
4275
+ if (stat8.size >= oversizedBytes) {
4276
+ const share = stat8.size > 0 ? Math.round(diagnosis.snapshotBytes / stat8.size * 100) : 0;
4277
+ add({
4278
+ code: "oversized",
4279
+ severity: "info",
4280
+ detail: `${(stat8.size / 1e6).toFixed(0)} MB \u2014 slow to open` + (share >= 50 ? `; ${share}% is superseded conversation snapshots` : "")
4281
+ });
4282
+ }
4283
+ return diagnosis;
4284
+ }
4285
+ async function diagnoseSessions(options) {
4286
+ const { sessionsDir, onProgress, signal } = options;
4287
+ const oversizedBytes = options.oversizedBytes ?? 64 * 1024 * 1024;
4288
+ const journals = await collectJournals(sessionsDir);
4289
+ const sessions = [];
4290
+ const unreadable = [];
4291
+ let scanned = 0;
4292
+ for (const { id, file } of journals) {
4293
+ signal?.throwIfAborted();
4294
+ onProgress?.({ scanned, total: journals.length, id });
4295
+ try {
4296
+ sessions.push(await scanJournal(id, file, oversizedBytes, signal));
4297
+ } catch (error) {
4298
+ if (signal?.aborted) throw error;
4299
+ unreadable.push({ id, reason: error instanceof Error ? error.message : String(error) });
4300
+ }
4301
+ scanned++;
4302
+ }
4303
+ onProgress?.({ scanned, total: journals.length, id: "" });
4304
+ const totals = {
4305
+ sessions: sessions.length,
4306
+ bytes: sessions.reduce((sum, s) => sum + s.bytes, 0),
4307
+ snapshotBytes: sessions.reduce((sum, s) => sum + s.snapshotBytes, 0),
4308
+ unparsableLines: sessions.reduce((sum, s) => sum + s.unparsableLines, 0)
4309
+ };
4310
+ const byCode = {};
4311
+ for (const session of sessions) {
4312
+ for (const finding of session.findings) {
4313
+ byCode[finding.code] = (byCode[finding.code] ?? 0) + 1;
4314
+ }
4315
+ }
4316
+ sessions.sort((a, b) => severityRank(a) - severityRank(b) || b.bytes - a.bytes);
4317
+ return { sessionsDir, totals, byCode, sessions, unreadable };
4318
+ }
4319
+ async function repairSessionSummaries(options) {
4320
+ const { report, onProgress, signal } = options;
4321
+ const scrubber = options.secretScrubber ?? new DefaultSecretScrubber();
4322
+ const targets = report.sessions.filter(
4323
+ (session) => session.findings.some((f) => f.code === "missing_summary" || f.code === "stale_summary")
4324
+ );
4325
+ const result = { repaired: [], failed: [] };
4326
+ for (const session of targets) {
4327
+ signal?.throwIfAborted();
4328
+ onProgress?.({ repaired: result.repaired.length, total: targets.length, id: session.id });
4329
+ try {
4330
+ const stat8 = await fsp7.stat(session.file);
4331
+ const summary = await summarizeSessionFile({
4332
+ id: session.id,
4333
+ file: session.file,
4334
+ mtime: stat8.mtime.toISOString(),
4335
+ secretScrubber: scrubber
4336
+ });
4337
+ const sidecar = `${session.file.slice(0, -".jsonl".length)}.summary.json`;
4338
+ await atomicWrite(sidecar, `${JSON.stringify(summary, null, 2)}
4339
+ `, { mode: 384 });
4340
+ result.repaired.push(session.id);
4341
+ } catch (error) {
4342
+ result.failed.push({
4343
+ id: session.id,
4344
+ reason: error instanceof Error ? error.message : String(error)
4345
+ });
4346
+ }
4347
+ }
4348
+ onProgress?.({ repaired: result.repaired.length, total: targets.length, id: "" });
4349
+ return result;
4350
+ }
4351
+
3824
4352
  // src/storage/session-event-bridge.ts
3825
4353
  var CORE_RECONSTRUCT_EVENTS = /* @__PURE__ */ new Set([
3826
4354
  "session_start",
@@ -3828,6 +4356,7 @@ var CORE_RECONSTRUCT_EVENTS = /* @__PURE__ */ new Set([
3828
4356
  "session_forked",
3829
4357
  "user_input",
3830
4358
  "llm_response",
4359
+ "tool_use",
3831
4360
  "tool_result",
3832
4361
  "message_appended",
3833
4362
  "message_updated",
@@ -3844,7 +4373,6 @@ var CORE_RECONSTRUCT_EVENTS = /* @__PURE__ */ new Set([
3844
4373
  ]);
3845
4374
  var STANDARD_AUDIT_EVENTS = /* @__PURE__ */ new Set([
3846
4375
  "llm_request",
3847
- "tool_use",
3848
4376
  "tool_call_start",
3849
4377
  "tool_call_end",
3850
4378
  "compaction",
@@ -3860,8 +4388,13 @@ var STANDARD_AUDIT_EVENTS = /* @__PURE__ */ new Set([
3860
4388
  // at the DEFAULT level and the resume timeline would lose them silently.
3861
4389
  "mode_changed",
3862
4390
  "agent_spawned",
4391
+ "agent_session_linked",
3863
4392
  "agent_stopped",
3864
4393
  "agent_error",
4394
+ "delegate_started",
4395
+ "delegate_completed",
4396
+ "loop_detected",
4397
+ "model_switched",
3865
4398
  "task_created",
3866
4399
  "task_updated",
3867
4400
  "task_completed",
@@ -4322,10 +4855,10 @@ async function applyRewindToConversation(opts) {
4322
4855
  }
4323
4856
 
4324
4857
  // src/storage/session-rewinder.ts
4325
- import { createReadStream } from "node:fs";
4326
- import * as fsp7 from "node:fs/promises";
4327
- import * as path12 from "node:path";
4328
- import { createInterface } from "node:readline";
4858
+ import { createReadStream as createReadStream2 } from "node:fs";
4859
+ import * as fsp8 from "node:fs/promises";
4860
+ import * as path14 from "node:path";
4861
+ import { createInterface as createInterface2 } from "node:readline";
4329
4862
  var DefaultSessionRewinder = class {
4330
4863
  constructor(sessionsDir, projectRoot) {
4331
4864
  this.sessionsDir = sessionsDir;
@@ -4337,8 +4870,8 @@ var DefaultSessionRewinder = class {
4337
4870
  return sessionScopedPath(this.sessionsDir, sessionId, ".jsonl");
4338
4871
  }
4339
4872
  async *readEvents(file) {
4340
- const stream = createReadStream(file, { encoding: "utf8" });
4341
- const lines = createInterface({ input: stream, crlfDelay: Infinity });
4873
+ const stream = createReadStream2(file, { encoding: "utf8" });
4874
+ const lines = createInterface2({ input: stream, crlfDelay: Infinity });
4342
4875
  try {
4343
4876
  for await (const line of lines) {
4344
4877
  if (!line.trim()) continue;
@@ -4458,10 +4991,10 @@ async function revertSnapshots(snapshots, projectRoot) {
4458
4991
  for (const snapshot of [...snapshots].reverse()) {
4459
4992
  for (const file of [...snapshot.files].reverse()) {
4460
4993
  try {
4461
- const absPath = path12.resolve(file.path);
4462
- const root = path12.resolve(projectRoot);
4463
- const rel = path12.relative(root, absPath);
4464
- if (rel.startsWith("..") || path12.isAbsolute(rel)) {
4994
+ const absPath = path14.resolve(file.path);
4995
+ const root = path14.resolve(projectRoot);
4996
+ const rel = path14.relative(root, absPath);
4997
+ if (rel.startsWith("..") || path14.isAbsolute(rel)) {
4465
4998
  errors.push(`${file.path}: path resolves outside project root \u2014 skipping`);
4466
4999
  continue;
4467
5000
  }
@@ -4471,7 +5004,7 @@ async function revertSnapshots(snapshots, projectRoot) {
4471
5004
  revertedFiles.push(file.path);
4472
5005
  }
4473
5006
  } else if (file.action === "created") {
4474
- await fsp7.unlink(file.path);
5007
+ await fsp8.unlink(file.path);
4475
5008
  revertedFiles.push(file.path);
4476
5009
  } else if (file.action === "modified") {
4477
5010
  if (file.before !== null) {
@@ -4488,7 +5021,7 @@ async function revertSnapshots(snapshots, projectRoot) {
4488
5021
  }
4489
5022
 
4490
5023
  // src/storage/task-store.ts
4491
- import * as fsp8 from "node:fs/promises";
5024
+ import * as fsp9 from "node:fs/promises";
4492
5025
  function assertTaskMutationInvariants(previous, updated) {
4493
5026
  const ids = updated.tasks.map((task) => task.id);
4494
5027
  const uniqueIds = new Set(ids);
@@ -4549,7 +5082,7 @@ async function loadTasks(filePath, events, traceId) {
4549
5082
  const t0 = Date.now();
4550
5083
  let raw;
4551
5084
  try {
4552
- raw = await fsp8.readFile(filePath, "utf8");
5085
+ raw = await fsp9.readFile(filePath, "utf8");
4553
5086
  } catch (err) {
4554
5087
  events?.emit("storage.error", {
4555
5088
  sessionId: traceId ?? "~boot~",
@@ -4658,12 +5191,12 @@ async function mutateTasks(filePath, sessionId, fn, events, traceId) {
4658
5191
  }
4659
5192
 
4660
5193
  // src/storage/todos-checkpoint.ts
4661
- import * as fsp9 from "node:fs/promises";
5194
+ import * as fsp10 from "node:fs/promises";
4662
5195
  async function loadTodosCheckpoint(filePath, events, traceId, sessionId) {
4663
5196
  const t0 = Date.now();
4664
5197
  let raw;
4665
5198
  try {
4666
- raw = await fsp9.readFile(filePath, "utf8");
5199
+ raw = await fsp10.readFile(filePath, "utf8");
4667
5200
  } catch (err) {
4668
5201
  events?.emit("storage.error", {
4669
5202
  sessionId: sessionId ?? "~boot~",
@@ -5186,7 +5719,9 @@ export {
5186
5719
  FileMemoryBackend,
5187
5720
  parseEntries,
5188
5721
  SessionMemoryConsolidator,
5722
+ SessionMemoryCurator,
5189
5723
  GraphMemoryBackend,
5724
+ cleanOrphanLocks,
5190
5725
  loadPlan,
5191
5726
  savePlan,
5192
5727
  emptyPlan,
@@ -5209,9 +5744,12 @@ export {
5209
5744
  retainPersistedQueueItems,
5210
5745
  QueueStore,
5211
5746
  RecoveryLock,
5212
- cleanOrphanLocks,
5213
5747
  ReplayLogStore,
5748
+ stampAgentId,
5749
+ withAgentAttribution,
5214
5750
  SessionAnalyzer,
5751
+ diagnoseSessions,
5752
+ repairSessionSummaries,
5215
5753
  CORE_RECONSTRUCT_EVENTS,
5216
5754
  STANDARD_AUDIT_EVENTS,
5217
5755
  createSessionEventBridge,
@@ -5229,4 +5767,4 @@ export {
5229
5767
  attachTodosCheckpoint,
5230
5768
  ToolAuditLog
5231
5769
  };
5232
- //# sourceMappingURL=chunk-K3G6JBUC.js.map
5770
+ //# sourceMappingURL=chunk-WLYKU45P.js.map