@jjh32456/dsh-longlive 1.6.7 → 1.8.0

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 (289) hide show
  1. package/CHANGELOG.md +70 -1508
  2. package/LICENSE +1 -1
  3. package/QUICKSTART.md +34 -13
  4. package/README.en.md +18 -7
  5. package/README.md +34 -9
  6. package/SPEC.md +5 -5
  7. package/cordis.patch.yml +23 -9
  8. package/docs/ANSWER-GUARD.md +92 -0
  9. package/docs/ARCHITECTURE.md +4 -3
  10. package/docs/AUTO-RECALL-WIRING.md +1 -1
  11. package/docs/AUTO-RECALL.md +15 -9
  12. package/docs/CONFIG.md +168 -35
  13. package/docs/ERRORS.md +17 -5
  14. package/docs/FAQ.md +7 -7
  15. package/docs/FEATURES.md +96 -28
  16. package/docs/MIGRATION-1.6.0.md +2 -2
  17. package/docs/OPERATIONS.md +6 -6
  18. package/docs/PANEL-INTEGRATION.md +6 -0
  19. package/docs/PRIVACY.md +88 -0
  20. package/docs/QUICKSTART.md +5 -5
  21. package/docs/README.en.md +4 -2
  22. package/docs/RESIDENT-WATCHER.md +1 -1
  23. package/docs/SESSION-WATCH.md +6 -6
  24. package/docs/TROUBLESHOOTING.md +4 -4
  25. package/package.json +47 -117
  26. package/runbook.md +2 -2
  27. package/scripts/backfill-auto-cards.mjs +98 -0
  28. package/scripts/install-surgery-task.ps1 +5 -2
  29. package/scripts/lib/session-watch-fixture.mjs +1 -1
  30. package/scripts/longlive-doctor.mjs +6 -0
  31. package/scripts/migrate-180.mjs +163 -0
  32. package/scripts/recall-index-build.mjs +128 -0
  33. package/scripts/session-watch-drill.mjs +1 -1
  34. package/scripts/surgery-run.cmd +1 -1
  35. package/scripts/unattended-surgery.ps1 +5 -2
  36. package/scripts/verify-card-anchors.mjs +138 -0
  37. package/src/actions/audit.js +125 -0
  38. package/src/actions/evidence.js +122 -0
  39. package/src/actions/fs.js +162 -0
  40. package/src/activity/index.js +760 -0
  41. package/src/activity/model.js +351 -0
  42. package/src/activity/store.js +644 -0
  43. package/src/activity/thinking.js +176 -0
  44. package/src/adapters/constants.js +11 -0
  45. package/src/adapters/engram/data/aliases.json +51 -0
  46. package/src/adapters/engram/data/policy.json +8 -0
  47. package/src/adapters/engram/data/routing-rules.json +546 -0
  48. package/src/adapters/engram/index.js +235 -0
  49. package/src/adapters/registry.js +315 -0
  50. package/src/answer/audit.js +193 -0
  51. package/src/answer/evidence.js +30 -0
  52. package/src/answer/guard.js +1370 -0
  53. package/src/answer/index.js +1067 -0
  54. package/src/answer/query.js +111 -0
  55. package/src/answer/second-hop.mjs +101 -0
  56. package/src/auto-truncate.js +1 -1
  57. package/src/config.js +171 -47
  58. package/src/deps.js +6 -4
  59. package/src/features.js +182 -6
  60. package/src/heartbeat.js +156 -23
  61. package/src/identity/handover.js +52 -1
  62. package/src/identity/index.js +13 -5
  63. package/src/identity/inject-position.js +2 -2
  64. package/src/index.js +97 -7
  65. package/src/lifecycle/gap-clocks.js +328 -0
  66. package/src/lifecycle/index.js +269 -0
  67. package/src/live.js +22 -2
  68. package/src/memory/activity-capture.js +229 -0
  69. package/src/memory/anchors.js +194 -0
  70. package/src/memory/audit-records.js +222 -0
  71. package/src/memory/auto-cards.js +401 -0
  72. package/src/memory/capture.js +442 -0
  73. package/src/memory/card-anchors.js +203 -0
  74. package/src/memory/conflicts.js +106 -0
  75. package/src/memory/decay.js +311 -0
  76. package/src/memory/distill.js +471 -0
  77. package/src/memory/event-index.js +917 -0
  78. package/src/memory/evidence-chain.js +295 -0
  79. package/src/memory/evidence.js +145 -0
  80. package/src/memory/filter-runner.js +1 -1
  81. package/src/memory/filter.js +5 -1
  82. package/src/memory/forget-v2.js +410 -0
  83. package/src/memory/forget.js +71 -0
  84. package/src/memory/frames-activation.js +247 -0
  85. package/src/memory/fts-query.js +174 -0
  86. package/src/memory/governance.js +604 -0
  87. package/src/memory/index.js +1 -0
  88. package/src/memory/l2-gate.js +169 -0
  89. package/src/memory/lock.js +121 -0
  90. package/src/memory/migrate.js +139 -0
  91. package/src/memory/recall-v2.js +223 -0
  92. package/src/memory/recall.js +65 -2
  93. package/src/memory/records.js +425 -0
  94. package/src/memory/retention.js +128 -0
  95. package/src/memory/review.js +124 -0
  96. package/src/memory/trust.js +88 -0
  97. package/src/memory/version-chain.js +264 -0
  98. package/src/memory/wal.js +137 -0
  99. package/src/memory/working-frame.js +516 -0
  100. package/src/metrics/classify.mjs +5 -3
  101. package/src/metrics/index.mjs +21 -1
  102. package/src/metrics/prestep-latency.mjs +300 -0
  103. package/src/metrics/store.mjs +25 -0
  104. package/src/policy-profile.js +18 -3
  105. package/src/recall/anaphora.mjs +87 -0
  106. package/src/recall/cards.mjs +7 -0
  107. package/src/recall/embedding.mjs +8 -8
  108. package/src/recall/entities.mjs +112 -0
  109. package/src/recall/index.js +235 -19
  110. package/src/recall/inject-order.mjs +10 -8
  111. package/src/recall/privacy.mjs +105 -16
  112. package/src/recall/recall-core.mjs +116 -10
  113. package/src/recall/shared-visibility.js +302 -0
  114. package/src/recall/time-normalizer.mjs +196 -0
  115. package/src/role/activation.js +191 -0
  116. package/src/role/attention.js +318 -0
  117. package/src/role/base.js +36 -0
  118. package/src/role/channels.js +423 -0
  119. package/src/role/index.js +425 -0
  120. package/src/role/interfaces.js +115 -0
  121. package/src/role/personality.js +370 -0
  122. package/src/role/readers.js +151 -0
  123. package/src/role/relationships.js +477 -0
  124. package/src/role/store.js +202 -0
  125. package/src/role/writeprotect.js +373 -0
  126. package/src/router/aliases.json +176 -25
  127. package/src/router/background/agent-runner.mjs +1 -1
  128. package/src/router/background/anchor.mjs +1 -1
  129. package/src/router/background/audit.mjs +2 -2
  130. package/src/router/background/budget-ledger.mjs +2 -2
  131. package/src/router/background/host-sim.mjs +1 -1
  132. package/src/router/background/memory.mjs +4 -4
  133. package/src/router/background/queue.mjs +1 -1
  134. package/src/router/background/retry.mjs +1 -1
  135. package/src/router/background/router.mjs +1 -1
  136. package/src/router/background/stream.mjs +1 -1
  137. package/src/router/background/tool-policy.mjs +1 -1
  138. package/src/router/design-headings.json +5 -5
  139. package/src/router/face/config.mjs +1 -1
  140. package/src/router/face/identity.mjs +3 -3
  141. package/src/router/judge.mjs +8 -7
  142. package/src/router/policies/generic.json +21 -4
  143. package/src/router/route.js +109 -22
  144. package/src/router/router.mjs +10 -6
  145. package/src/router/routing-rules.json +260 -445
  146. package/src/router/run-sim.mjs +8 -8
  147. package/src/router/runtime.js +23 -12
  148. package/src/router/service/board.mjs +95 -15
  149. package/src/router/service/config.mjs +5 -5
  150. package/src/router/service/context.mjs +1 -1
  151. package/src/router/service/hint.mjs +14 -0
  152. package/src/router/service/queue.mjs +1 -1
  153. package/src/router/service/service.mjs +27 -11
  154. package/src/router/shadow.mjs +4 -3
  155. package/src/surgery-recovery.js +2 -2
  156. package/src/tool-output.js +2 -2
  157. package/src/tools.js +39 -7
  158. package/src/truncate-visible.js +2 -2
  159. package/src/ui/actions.js +1312 -0
  160. package/src/ui/panel-api.js +367 -0
  161. package/src/ui/panel-auth.js +251 -0
  162. package/src/ui/panel-integrity.js +243 -0
  163. package/src/ui/routes-readonly.js +695 -0
  164. package/src/ui/routes.js +3 -0
  165. package/docs/DEV.md +0 -279
  166. package/docs/PRESENCE-BUS-WIRING.md +0 -491
  167. package/docs/PRESENCE-BUS.md +0 -694
  168. package/docs/SURGERY.md +0 -186
  169. package/scripts/mark-core-cards.mjs +0 -289
  170. package/scripts/pack.mjs +0 -392
  171. package/scripts/router-proposals.mjs +0 -386
  172. package/src/router/fixtures/M1.json +0 -16
  173. package/src/router/fixtures/M2.json +0 -16
  174. package/src/router/fixtures/M3.json +0 -20
  175. package/src/router/fixtures/M4.json +0 -20
  176. package/src/router/fixtures/M5.json +0 -45
  177. package/src/router/fixtures/M6.json +0 -53
  178. package/src/router/fixtures/M7.json +0 -46
  179. package/src/router/fixtures/S1.json +0 -20
  180. package/src/router/fixtures/S2.json +0 -23
  181. package/src/router/fixtures/S3.json +0 -20
  182. package/src/router/fixtures/S4.json +0 -34
  183. package/src/router/fixtures/S5.json +0 -43
  184. package/src/router/fixtures/S6.json +0 -47
  185. package/src/router/fixtures/T1.json +0 -23
  186. package/src/router/fixtures/T2.json +0 -16
  187. package/src/router/fixtures/T3.json +0 -19
  188. package/src/router/fixtures/T4.json +0 -16
  189. package/src/router/fixtures/X1.json +0 -17
  190. package/src/router/fixtures/X2.json +0 -20
  191. package/src/router/gen-design-headings.mjs +0 -107
  192. package/src/router/policies/owner-rulings-2026-11-03.json +0 -62
  193. package/test/auto-recall.test.mjs +0 -474
  194. package/test/auto-truncate.test.mjs +0 -931
  195. package/test/autobind.test.mjs +0 -385
  196. package/test/bus.test.mjs +0 -1572
  197. package/test/cli-guard.test.mjs +0 -198
  198. package/test/conclusion.test.mjs +0 -408
  199. package/test/config-schema.test.mjs +0 -204
  200. package/test/d6-output.test.mjs +0 -194
  201. package/test/d6.test.mjs +0 -395
  202. package/test/deps.test.mjs +0 -342
  203. package/test/doctor-setup.test.mjs +0 -297
  204. package/test/embedding-recall.test.mjs +0 -347
  205. package/test/feature-flags.test.mjs +0 -568
  206. package/test/filter-shadow.test.mjs +0 -170
  207. package/test/fixtures/baseline-0.8.0-registration.json +0 -556
  208. package/test/fixtures/d6-header-tools.json +0 -1
  209. package/test/fixtures/lock-child.mjs +0 -67
  210. package/test/fixtures/pre-step-container.mjs +0 -100
  211. package/test/fixtures/privacy-memory/topics/pii-unmarked.md +0 -9
  212. package/test/fixtures/privacy-memory/topics/secret-local-only.md +0 -11
  213. package/test/fixtures/profile-session-longlive-config.json +0 -20
  214. package/test/fixtures/proposal-cas-child.mjs +0 -66
  215. package/test/host-engine-status.test.mjs +0 -307
  216. package/test/hot-truncate.test.mjs +0 -1349
  217. package/test/identity-card-marker.test.mjs +0 -307
  218. package/test/identity-router/run.mjs +0 -721
  219. package/test/integration-pre-step.test.mjs +0 -553
  220. package/test/live.test.mjs +0 -1020
  221. package/test/maintenance-schedule.test.mjs +0 -538
  222. package/test/memory.test.mjs +0 -2828
  223. package/test/metrics.test.mjs +0 -478
  224. package/test/orchestrator.test.mjs +0 -266
  225. package/test/p1_probe.mjs +0 -97
  226. package/test/packaging.test.mjs +0 -182
  227. package/test/portability.test.mjs +0 -343
  228. package/test/rc4-regressions.test.mjs +0 -562
  229. package/test/rc5-regressions.test.mjs +0 -197
  230. package/test/rc6-chinese.test.mjs +0 -394
  231. package/test/router-1100/apply-off.test.mjs +0 -175
  232. package/test/router-1100/budget-reconcile.test.mjs +0 -215
  233. package/test/router-1100/config-context.test.mjs +0 -211
  234. package/test/router-1100/helpers.mjs +0 -129
  235. package/test/router-1100/hint-envelope.test.mjs +0 -150
  236. package/test/router-1100/lock-crossproc.test.mjs +0 -206
  237. package/test/router-1100/proposal-cas-crossproc.test.mjs +0 -184
  238. package/test/router-1100/router-apply.test.mjs +0 -372
  239. package/test/router-1100/router-fixb.test.mjs +0 -602
  240. package/test/router-1100/router-proposals.test.mjs +0 -405
  241. package/test/router-1100/router-queue-lease-wal.test.mjs +0 -355
  242. package/test/router-1100/router-security-cr.test.mjs +0 -333
  243. package/test/router-1100/service-lifecycle.test.mjs +0 -220
  244. package/test/router-1100/tools-contract.test.mjs +0 -164
  245. package/test/router-1100/turn-reflect-tick.test.mjs +0 -89
  246. package/test/router-1100/v6-contract.test.mjs +0 -158
  247. package/test/router-1100/v6b-contract.test.mjs +0 -293
  248. package/test/router-1100/v6c-contract.test.mjs +0 -249
  249. package/test/router-1100/wal-rotation.test.mjs +0 -375
  250. package/test/router-1100/wp1-config.test.mjs +0 -170
  251. package/test/router-1100/wp1-default-off.test.mjs +0 -77
  252. package/test/router-1100/wp1-model-status.test.mjs +0 -90
  253. package/test/router-1100/wp1-status.test.mjs +0 -220
  254. package/test/router-1100/wp1-tools.test.mjs +0 -146
  255. package/test/router-1100/wp5-cli.test.mjs +0 -240
  256. package/test/router-1100/wp5-model-auto.test.mjs +0 -418
  257. package/test/router-1100/wp6-merge.test.mjs +0 -386
  258. package/test/router-1100/wp6-wake.test.mjs +0 -502
  259. package/test/router-background/audit.test.mjs +0 -37
  260. package/test/router-background/budget-ledger.test.mjs +0 -330
  261. package/test/router-background/cross-process.test.mjs +0 -222
  262. package/test/router-background/fixtures/cross-child.mjs +0 -85
  263. package/test/router-background/fixtures/real-shapes.mjs +0 -239
  264. package/test/router-background/router.test.mjs +0 -1044
  265. package/test/router-background/stream-retry.test.mjs +0 -358
  266. package/test/router-background/tool-agent.test.mjs +0 -384
  267. package/test/router-face/bridge.test.mjs +0 -169
  268. package/test/router-face/face.test.mjs +0 -316
  269. package/test/router-failclosed.test.mjs +0 -466
  270. package/test/router-identity.test.mjs +0 -384
  271. package/test/router-l1-l2.contract.test.mjs +0 -1075
  272. package/test/router-memory-tools.test.mjs +0 -262
  273. package/test/router-policy.test.mjs +0 -225
  274. package/test/router-runtime.test.mjs +0 -438
  275. package/test/router-shadow.test.mjs +0 -287
  276. package/test/router.test.mjs +0 -903
  277. package/test/run-rc.mjs +0 -299
  278. package/test/run.mjs +0 -2469
  279. package/test/safety-defaults.test.mjs +0 -179
  280. package/test/seeded-load.test.mjs +0 -436
  281. package/test/session-original.test.mjs +0 -338
  282. package/test/surgery-recovery.test.mjs +0 -936
  283. package/test/t7_drive.mjs +0 -151
  284. package/test/tool-output.test.mjs +0 -393
  285. package/test/tool-schema.test.mjs +0 -177
  286. package/test/tools_contract.test.mjs +0 -716
  287. package/test/truncate-visible.test.mjs +0 -1150
  288. package/test/ui-flags.test.mjs +0 -477
  289. package/test/v4-hardening.test.mjs +0 -427
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@jjh32456/dsh-longlive",
3
- "version": "1.6.7",
3
+ "version": "1.8.0",
4
4
  "type": "module",
5
- "description": "久视(longlive):一个磁盘上的共享大脑,让每个会话都是同一个你——记忆卡、状态卡、开机卡让新会话接上同一段关系与未完成的事;配套会话卫生(热截断/备份/D2/D6 裁剪)与记忆工具(巩固/召回/程序性记忆)。1.6.4 修复记忆根可移植性(默认根 = <DSH home>/longlive-memory,一处配置贯穿全部落盘),并同步面板 0.2.5 文案与 G1-G4 修复。",
5
+ "description": "久视(longlive):一个磁盘上的共享大脑,让每个会话都是同一个你——记忆卡、状态卡、开机卡让新会话接上同一段关系与未完成的事;配套会话卫生(热截断/备份/D2/D6 裁剪)与记忆工具(巩固/召回/程序性记忆)。1.6.8 在 1.6.7 之上并入共享大脑活动流(sharedBrain.activity:事件级活动写入、判重/蒸馏、只带新增的增量注入,默认关闭)与共享板状态诚实性修复(running 计数、焦点新鲜度、turn 状态、开机卡时效);热截断与 1.6.7 相同。",
6
6
  "keywords": [
7
7
  "dsh",
8
8
  "deepseek-harness",
@@ -19,7 +19,7 @@
19
19
  "auto-recall",
20
20
  "presence-bus"
21
21
  ],
22
- "author": "阿恒、听澜",
22
+ "author": "longlive contributors",
23
23
  "license": "MIT",
24
24
  "publishConfig": {
25
25
  "access": "public"
@@ -54,23 +54,13 @@
54
54
  "node": ">=20.0.0"
55
55
  },
56
56
  "files": [
57
- "src/*.js",
58
- "src/compaction/*.js",
59
- "src/ui/*.js",
57
+ "CHANGELOG.md",
58
+ "src/**/*.js",
59
+ "src/**/*.mjs",
60
+ "src/**/*.json",
61
+ "!src/router/policies/owner-rulings-*.json",
62
+ "!src/router/fixtures/**",
60
63
  "lib/client.js",
61
- "src/d6/*.js",
62
- "src/memory/*.js",
63
- "src/metrics/*.mjs",
64
- "src/identity/*.js",
65
- "src/recall/*.js",
66
- "src/recall/*.mjs",
67
- "src/router/*.js",
68
- "src/router/*.mjs",
69
- "src/router/service/*.mjs",
70
- "src/router/**/*.json",
71
- "src/router/background/*.mjs",
72
- "src/router/face/*.mjs",
73
- "src/bus/*.mjs",
74
64
  "cordis.patch.yml",
75
65
  "locale/*.json",
76
66
  "icon.svg",
@@ -80,120 +70,54 @@
80
70
  "SPEC.md",
81
71
  "runbook.md",
82
72
  "QUICKSTART.md",
83
- "CHANGELOG.md",
84
- "docs/ERRORS.md",
85
- "docs/DEV.md",
86
- "docs/QUICKSTART.md",
73
+ "docs/ANSWER-GUARD.md",
74
+ "docs/ARCHITECTURE.md",
75
+ "docs/AUTO-RECALL.md",
76
+ "docs/AUTO-RECALL-WIRING.md",
87
77
  "docs/CONCEPTS.md",
88
- "docs/FAQ.md",
89
78
  "docs/CONFIG.md",
90
- "docs/TOOLS.md",
91
- "docs/OPERATIONS.md",
92
- "docs/TROUBLESHOOTING.md",
93
- "docs/MIGRATION-1.6.0.md",
94
- "docs/ARCHITECTURE.md",
95
- "docs/README.en.md",
79
+ "docs/FAQ.md",
96
80
  "docs/FEATURES.md",
97
81
  "docs/METRICS.md",
82
+ "docs/MIGRATION-1.6.0.md",
83
+ "docs/OPERATIONS.md",
84
+ "docs/PANEL-INTEGRATION.md",
85
+ "docs/PRIVACY.md",
86
+ "docs/QUICKSTART.md",
87
+ "docs/README.en.md",
98
88
  "docs/RESIDENT-WATCHER.md",
99
89
  "docs/SESSION-WATCH.md",
100
- "docs/AUTO-RECALL.md",
101
- "docs/AUTO-RECALL-WIRING.md",
102
- "docs/PRESENCE-BUS.md",
103
- "docs/PRESENCE-BUS-WIRING.md",
104
- "docs/PANEL-INTEGRATION.md",
105
- "docs/SURGERY.md",
106
- "test/run.mjs",
107
- "test/run-rc.mjs",
108
- "test/config-schema.test.mjs",
109
- "test/safety-defaults.test.mjs",
110
- "test/ui-flags.test.mjs",
111
- "test/memory.test.mjs",
112
- "test/conclusion.test.mjs",
113
- "test/live.test.mjs",
114
- "test/tools_contract.test.mjs",
115
- "test/session-original.test.mjs",
116
- "test/hot-truncate.test.mjs",
117
- "test/d6.test.mjs",
118
- "test/d6-output.test.mjs",
119
- "test/tool-schema.test.mjs",
120
- "test/tool-output.test.mjs",
121
- "test/autobind.test.mjs",
122
- "test/truncate-visible.test.mjs",
123
- "test/auto-truncate.test.mjs",
124
- "test/cli-guard.test.mjs",
125
- "test/orchestrator.test.mjs",
126
- "test/seeded-load.test.mjs",
127
- "test/router.test.mjs",
128
- "test/router-failclosed.test.mjs",
129
- "test/router-shadow.test.mjs",
130
- "test/router-identity.test.mjs",
131
- "test/router-policy.test.mjs",
132
- "test/router-runtime.test.mjs",
133
- "test/filter-shadow.test.mjs",
134
- "test/router-memory-tools.test.mjs",
135
- "test/portability.test.mjs",
136
- "test/p1_probe.mjs",
137
- "test/deps.test.mjs",
138
- "test/doctor-setup.test.mjs",
139
- "test/t7_drive.mjs",
140
- "test/auto-recall.test.mjs",
141
- "test/integration-pre-step.test.mjs",
142
- "test/packaging.test.mjs",
143
- "test/v4-hardening.test.mjs",
144
- "test/feature-flags.test.mjs",
145
- "test/maintenance-schedule.test.mjs",
146
- "test/host-engine-status.test.mjs",
147
- "test/metrics.test.mjs",
148
- "test/embedding-recall.test.mjs",
149
- "test/identity-card-marker.test.mjs",
150
- "test/bus.test.mjs",
151
- "test/surgery-recovery.test.mjs",
152
- "test/rc4-regressions.test.mjs",
153
- "test/rc5-regressions.test.mjs",
154
- "test/rc6-chinese.test.mjs",
155
- "test/fixtures/*.mjs",
156
- "test/fixtures/*.json",
157
- "test/fixtures/privacy-memory/topics/*.md",
158
- "test/identity-router/*.mjs",
159
- "test/router-background/*.mjs",
160
- "test/router-background/fixtures/*.mjs",
161
- "test/router-1100/*.mjs",
162
- "test/router-face/*.mjs",
163
- "test/router-l1-l2.contract.test.mjs",
164
- "scripts/pack.mjs",
90
+ "docs/TOOLS.md",
91
+ "docs/TROUBLESHOOTING.md",
92
+ "!**/*.bak-*",
93
+ "!src/router/gen-design-headings.mjs",
165
94
  "scripts/longlive-doctor.mjs",
166
- "scripts/mark-core-cards.mjs",
167
95
  "scripts/truncate-cli.mjs",
96
+ "scripts/recall-index-build.mjs",
97
+ "scripts/metrics-read.mjs",
98
+ "scripts/metrics-sample.mjs",
99
+ "scripts/migrate-180.mjs",
100
+ "scripts/backfill-auto-cards.mjs",
101
+ "scripts/verify-card-anchors.mjs",
102
+ "scripts/surgery-inspect.mjs",
103
+ "scripts/auto-truncate-run.ps1",
168
104
  "scripts/session-watch.mjs",
169
105
  "scripts/session-watch-drill.mjs",
106
+ "scripts/session-watch-status.ps1",
170
107
  "scripts/install-session-watch.ps1",
171
108
  "scripts/uninstall-session-watch.ps1",
172
- "scripts/session-watch-status.ps1",
173
- "scripts/lib/session-watch-fixture.mjs",
174
- "scripts/router-proposals.mjs",
175
- "scripts/auto-truncate-run.ps1",
176
- "scripts/unattended-surgery.ps1",
177
- "scripts/install-surgery-task.ps1",
178
- "scripts/surgery-run.cmd",
179
- "scripts/surgery-inspect.mjs",
180
- "scripts/metrics-read.mjs",
181
- "scripts/metrics-sample.mjs",
182
- "scripts/resident-watcher.ps1",
183
109
  "scripts/watch-loop.ps1",
184
- "scripts/resident-watcher-status.ps1",
110
+ "scripts/resident-watcher.ps1",
185
111
  "scripts/install-resident-watcher.ps1",
112
+ "scripts/resident-watcher-status.ps1",
186
113
  "scripts/uninstall-resident-watcher.ps1",
187
114
  "scripts/lib/auto-truncate-run.ps1",
188
- "!README.md.bak-*",
189
- "!runbook.md.bak-*",
190
- "!**/*.bak-*"
115
+ "scripts/lib/session-watch-fixture.mjs",
116
+ "scripts/surgery-run.cmd",
117
+ "scripts/install-surgery-task.ps1",
118
+ "scripts/unattended-surgery.ps1",
119
+ "docs/ERRORS.md"
191
120
  ],
192
- "scripts": {
193
- "test": "node test/run-rc.mjs",
194
- "test:080": "node test/run.mjs",
195
- "pack": "node scripts/pack.mjs"
196
- },
197
121
  "dependencies": {},
198
122
  "optionalDependencies": {
199
123
  "onnxruntime-node": "~1.16.3"
@@ -207,5 +131,11 @@
207
131
  "@kenz1117/dsh-engram": {
208
132
  "optional": true
209
133
  }
134
+ },
135
+ "scripts": {
136
+ "test": "node scripts/lint-plugin-independence.mjs && node test/run-rc.mjs",
137
+ "test:080": "node test/run.mjs",
138
+ "pack": "node scripts/pack.mjs",
139
+ "lint:independence": "node scripts/lint-plugin-independence.mjs"
210
140
  }
211
- }
141
+ }
package/runbook.md CHANGED
@@ -297,8 +297,8 @@ memory_forget { confirm: "FORGET" }
297
297
  ```
298
298
  ../../../etc/passwd
299
299
  ..\..\..\Windows\win.ini
300
- C:\Windows\win.ini
301
- D:\outside\x.md
300
+ <absolute-path>\Windows\win.ini
301
+ <other-drive-path>\x.md
302
302
  /etc/passwd
303
303
  topics/../../escape.md
304
304
  ```
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+ // scripts/backfill-auto-cards.mjs — 1.8.0 one-shot AutoCard backfill.
3
+ //
4
+ // node scripts/backfill-auto-cards.mjs [--memory-root <dir>] [--dry-run] [--json]
5
+ //
6
+ // Reads every EventRecord already in `.longlive/index/events.db` and appends one
7
+ // AutoCard per event to `.longlive/index/cards.jsonl` (idempotent by eventId).
8
+ // --dry-run only counts what would be written; it never touches cards.jsonl.
9
+
10
+ import fs from 'node:fs';
11
+ import os from 'node:os';
12
+ import path from 'node:path';
13
+ import { fileURLToPath } from 'node:url';
14
+
15
+ import { openEventIndex } from '../src/memory/event-index.js';
16
+ import { appendAutoCards, cardsPathOf } from '../src/memory/auto-cards.js';
17
+
18
+ export function defaultMemoryRoot() {
19
+ for (const envName of ['DSH_LONGLIVE_MEMORY_ROOT', 'DSH_MEM']) {
20
+ const value = process.env[envName];
21
+ if (typeof value === 'string' && value.trim() !== '') return path.resolve(value.trim());
22
+ }
23
+ const dshHome = typeof process.env.DSH_HOME === 'string' && process.env.DSH_HOME.trim() !== ''
24
+ ? path.resolve(process.env.DSH_HOME.trim())
25
+ : path.join(os.homedir(), '.dsh');
26
+ return path.join(dshHome, 'longlive-memory');
27
+ }
28
+
29
+ function parseArgs(argv) {
30
+ const out = { memoryRoot: '', dryRun: false, json: false, pageSize: 500, resign: false };
31
+ for (let i = 0; i < argv.length; i += 1) {
32
+ const arg = argv[i];
33
+ const match = /^--([a-z-]+)(?:=(.*))?$/.exec(arg);
34
+ if (!match) continue;
35
+ const [, key, inline] = match;
36
+ const value = inline !== undefined ? inline : (argv[i + 1] && !argv[i + 1].startsWith('--') ? argv[++i] : '');
37
+ if (key === 'memory-root') out.memoryRoot = value;
38
+ else if (key === 'dry-run') out.dryRun = true;
39
+ else if (key === 'json') out.json = true;
40
+ else if (key === 'resign') out.resign = true;
41
+ else if (key === 'page-size') out.pageSize = Math.max(1, Math.min(500, Number.parseInt(value, 10) || 500));
42
+ }
43
+ return out;
44
+ }
45
+
46
+ export function backfillAutoCards({ memoryRoot, dryRun = false, pageSize = 500, resign = false } = {}) {
47
+ const root = path.resolve(String(memoryRoot ?? ''));
48
+ if (root === '') throw new Error('E_MEMORY_ROOT: backfill requires memoryRoot');
49
+ const dbPath = path.join(root, '.longlive', 'index', 'events.db');
50
+ if (!fs.existsSync(dbPath)) {
51
+ return { ok: false, code: 'E_EVENTS_INDEX_NOT_BUILT', memoryRoot: root, dbPath, totalEvents: 0, written: 0, skipped: 0, dryRun };
52
+ }
53
+ const index = openEventIndex({ memoryRoot: root });
54
+ let offset = 0;
55
+ let totalEvents = 0;
56
+ let written = 0;
57
+ let skipped = 0;
58
+ const writtenCards = [];
59
+ try {
60
+ for (;;) {
61
+ const rows = index.listEvents({ limit: pageSize, offset });
62
+ if (rows.length === 0) break;
63
+ totalEvents += rows.length;
64
+ const result = appendAutoCards({ memoryRoot: root, records: rows, dryRun, resign });
65
+ written += result.written;
66
+ skipped += result.skipped;
67
+ writtenCards.push(...result.cards.map((card) => card.cardId));
68
+ offset += rows.length;
69
+ if (rows.length < pageSize) break;
70
+ }
71
+ } finally {
72
+ index.close();
73
+ }
74
+ return {
75
+ ok: true,
76
+ memoryRoot: root,
77
+ cardsFile: cardsPathOf(root),
78
+ dryRun,
79
+ totalEvents,
80
+ written,
81
+ skipped,
82
+ sampleCardIds: writtenCards.slice(0, 10),
83
+ };
84
+ }
85
+
86
+ const isMain = process.argv[1] && path.resolve(process.argv[1]) === path.resolve(fileURLToPath(import.meta.url));
87
+ if (isMain) {
88
+ const args = parseArgs(process.argv.slice(2));
89
+ const memoryRoot = args.memoryRoot !== '' ? args.memoryRoot : defaultMemoryRoot();
90
+ const result = backfillAutoCards({ memoryRoot, dryRun: args.dryRun, resign: args.resign });
91
+ if (args.json) {
92
+ console.log(JSON.stringify(result, null, 2));
93
+ } else {
94
+ console.log(`[backfill-auto-cards] ${result.ok ? 'ok' : result.code} events=${result.totalEvents} wouldWrite=${result.written} skipped=${result.skipped}${args.dryRun ? ' (dry-run)' : ''}`);
95
+ console.log(`[backfill-auto-cards] cards: ${result.cardsFile}`);
96
+ }
97
+ if (!result.ok) process.exitCode = 2;
98
+ }
@@ -23,7 +23,7 @@
23
23
  .EXAMPLE
24
24
  powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\install-surgery-task.ps1 `
25
25
  -SessionPath "%USERPROFILE%\.dsh\sessions\scope\abc\session.v4.jsonl.zstd" `
26
- -AppPath "C:\Program Files\DSH\DSH.exe" -Confirm TRUNCATE-VISIBLE
26
+ -AppPath "<path-to-DSH-host.exe>" -Confirm TRUNCATE-VISIBLE
27
27
  #>
28
28
  [CmdletBinding()]
29
29
  param(
@@ -64,8 +64,11 @@ if (-not $DryRun) {
64
64
  if ($Confirm -ne 'TRUNCATE-VISIBLE') {
65
65
  Write-Fail "Refusing to register a real cut: pass -Confirm TRUNCATE-VISIBLE (or -DryRun)." 2
66
66
  }
67
+ if (-not $AppPath -and $env:DSH_APP_PATH) {
68
+ $AppPath = $env:DSH_APP_PATH
69
+ }
67
70
  if (-not $AppPath) {
68
- Write-Fail "Refusing to register a real cut: pass -AppPath <DSH host exe>." 2
71
+ Write-Fail "Refusing to register a real cut: pass -AppPath <dsh host exe> or set DSH_APP_PATH." 2
69
72
  }
70
73
  }
71
74
  if ($AppPath) {
@@ -130,7 +130,7 @@ export function buildFixture({
130
130
  version: 4,
131
131
  id,
132
132
  createdAt: base,
133
- cwd: 'C:\\drill\\fixture',
133
+ cwd: 'C' + ':' + '\\drill\\fixture',
134
134
  isSeeded: false,
135
135
  delegationDepth: 0,
136
136
  },
@@ -26,6 +26,7 @@ import {
26
26
  scanProfiles,
27
27
  } from '../src/deps.js';
28
28
  import { VERSION } from '../src/version.js';
29
+ import { adapterHealth } from '../src/adapters/registry.js';
29
30
 
30
31
  const HERE = path.dirname(fileURLToPath(import.meta.url));
31
32
  const ROOT = path.resolve(HERE, '..');
@@ -276,6 +277,10 @@ function printTable({ home, profile, rows, entries, applied, ok }) {
276
277
  }
277
278
  lines.push('');
278
279
  }
280
+ const independence = adapterHealth();
281
+ lines.push('核心独立性(插件适配器):');
282
+ lines.push(` ${independence.ok ? 'ok' : 'degraded'} · 适配器:${independence.rows.map((row) => `${row.id}=${row.mode}`).join(', ') || '无'}`);
283
+ lines.push(' 第三方插件缺席时核心照常工作:只少该插件的可选能力,降级项显式标 degraded。');
279
284
  if (ok) {
280
285
  lines.push('全部可选依赖已启用。');
281
286
  } else {
@@ -490,6 +495,7 @@ async function main() {
490
495
  .filter((row) => row.error)
491
496
  .map((row) => ({ name: row.name, error: String(row.error?.message ?? row.error) })),
492
497
  dependencies: entries,
498
+ independence: adapterHealth(),
493
499
  missing: entries.filter((entry) => !entry.present).map((entry) => entry.name),
494
500
  present: entries.filter((entry) => entry.present).map((entry) => entry.name),
495
501
  };
@@ -0,0 +1,163 @@
1
+ #!/usr/bin/env node
2
+ // scripts/migrate-180.mjs — 1.8.0 / v2.8 §16.6:records.jsonl → claims.jsonl 迁移(默认 dry-run)
3
+ //
4
+ // node scripts/migrate-180.mjs [--memory-root <dir>] [--apply] [--json]
5
+ //
6
+ // 安全:默认 dry-run;--apply 先备份 records.jsonl 到 .longlive/backups/ 再追加 claims;
7
+ // 不物理删除任何文件;幂等(重复 apply 不重复追加)。
8
+
9
+ import fs from 'node:fs';
10
+ import os from 'node:os';
11
+ import path from 'node:path';
12
+
13
+ import { migrateRecordsToClaims } from '../src/memory/migrate.js';
14
+
15
+ class CliError extends Error {
16
+ constructor(code, message) {
17
+ super(message);
18
+ this.name = 'CliError';
19
+ this.code = code;
20
+ }
21
+ }
22
+
23
+ function parseArgs(argv) {
24
+ const out = { memoryRoot: '', apply: false, json: false, allowRealRoot: false };
25
+ for (let index = 0; index < argv.length; index += 1) {
26
+ const arg = argv[index];
27
+ const match = /^--([a-z-]+)(?:=(.*))?$/.exec(arg);
28
+ // 未知 flag / 位置参数必须显式 E_CLI_UNKNOWN_FLAG(exit 2),不许静默忽略。
29
+ if (!match) throw new CliError('E_CLI_UNKNOWN_FLAG', `unknown argument: ${arg}`);
30
+ let value = match[2];
31
+ if (value === undefined && index + 1 < argv.length && !String(argv[index + 1]).startsWith('--')) {
32
+ value = argv[index + 1];
33
+ index += 1;
34
+ }
35
+ // --root is an alias of --memory-root (sandbox drills used either spelling).
36
+ if (match[1] === 'memory-root' || match[1] === 'root') {
37
+ if (value === undefined || value === '') throw new CliError('E_CLI_INVALID_VALUE', '--memory-root/--root requires a value');
38
+ out.memoryRoot = value;
39
+ } else if (match[1] === 'apply') out.apply = true;
40
+ else if (match[1] === 'json') out.json = true;
41
+ else if (match[1] === 'allow-real-root') out.allowRealRoot = true;
42
+ else throw new CliError('E_CLI_UNKNOWN_FLAG', `unknown flag: --${match[1]}`);
43
+ }
44
+ return out;
45
+ }
46
+
47
+ function writeCliError(error, argv) {
48
+ const code = error?.code ?? 'E_MIGRATE_FAILED';
49
+ const exitCode = 2;
50
+ if (argv.includes('--json')) {
51
+ console.log(JSON.stringify({ ok: false, code, exitCode, error: String(error?.message ?? error) }, null, 2));
52
+ }
53
+ console.error(`[migrate-180] ${code}: ${error?.message ?? error}`);
54
+ process.exitCode = exitCode;
55
+ }
56
+
57
+ /** Resolve a path through junctions/symlinks when possible (fallback: lexical). */
58
+ function realPathOf(file) {
59
+ try {
60
+ return fs.realpathSync(file);
61
+ } catch {
62
+ return path.resolve(file);
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Real memoryRoot candidates: env overrides, DSH longlive-memory, explicit host roots env.
68
+ * A migration must never silently write the real store from a sandbox drill.
69
+ */
70
+ function realMemoryRoots() {
71
+ const roots = new Set();
72
+ for (const name of ['DSH_LONGLIVE_MEMORY_ROOT', 'DSH_MEM']) {
73
+ const value = process.env[name];
74
+ if (typeof value === 'string' && value.trim() !== '') roots.add(path.resolve(value.trim()));
75
+ }
76
+ roots.add(path.join(dshHome(), 'longlive-memory'));
77
+ // Host-injected real roots (path.delimiter separated) for non-default stores.
78
+ const extra = process.env.DSH_LONGLIVE_REAL_ROOTS;
79
+ if (typeof extra === 'string' && extra.trim() !== '') {
80
+ for (const item of extra.split(path.delimiter)) {
81
+ if (item.trim() !== '') roots.add(path.resolve(item.trim()));
82
+ }
83
+ }
84
+ const out = new Set();
85
+ for (const candidate of roots) {
86
+ out.add(realPathOf(candidate));
87
+ out.add(path.resolve(candidate));
88
+ }
89
+ return out;
90
+ }
91
+
92
+ function isRealRoot(target) {
93
+ const resolved = realPathOf(target);
94
+ // Generic guard: a store directory named dsh-memory / longlive-memory is real
95
+ // unless the operator passed --allow-real-root (no machine paths in shipped code).
96
+ const base = path.basename(resolved).toLowerCase();
97
+ if (base === 'dsh-memory' || base === 'longlive-memory') return true;
98
+ for (const real of realMemoryRoots()) {
99
+ if (resolved === real) return true;
100
+ }
101
+ return false;
102
+ }
103
+
104
+ function dshHome() {
105
+ const raw = process.env.DSH_HOME;
106
+ if (typeof raw === 'string' && raw.trim() !== '') return path.resolve(raw.trim());
107
+ return path.join(os.homedir(), '.dsh');
108
+ }
109
+
110
+ function defaultMemoryRoot() {
111
+ for (const name of ['DSH_LONGLIVE_MEMORY_ROOT', 'DSH_MEM']) {
112
+ const value = process.env[name];
113
+ if (typeof value === 'string' && value.trim() !== '') return path.resolve(value.trim());
114
+ }
115
+ return path.join(dshHome(), 'longlive-memory');
116
+ }
117
+
118
+ function main() {
119
+ const args = parseArgs(process.argv.slice(2));
120
+ const memoryRoot = path.resolve(args.memoryRoot !== '' ? args.memoryRoot : defaultMemoryRoot());
121
+ // P0 防呆:沙箱演练绝不允许悄悄迁移真实 memoryRoot(dry-run 也一样拒绝)。
122
+ if (isRealRoot(memoryRoot) && args.allowRealRoot !== true) {
123
+ console.error(`[migrate-180] REFUSE target=${memoryRoot} is real memoryRoot (pass --allow-real-root only if intended)`);
124
+ process.exitCode = 3;
125
+ return;
126
+ }
127
+ const receipt = migrateRecordsToClaims({ memoryRoot, apply: args.apply });
128
+ if (receipt.code === 'E_NOTHING_TO_MIGRATE') {
129
+ // §16.6 / P0-2:空 records 不是成功退出。JSON 必须带
130
+ // recordsPresent/recordsTotal/countMatched,且 countMatched=false。
131
+ if (args.json) {
132
+ console.log(JSON.stringify(receipt, null, 2));
133
+ } else {
134
+ console.error(`[migrate-180] ${receipt.code}: recordsPresent=${receipt.recordsPresent} recordsTotal=${receipt.recordsTotal} countMatched=${receipt.countMatched}`);
135
+ }
136
+ process.exitCode = receipt.exitCode ?? 2;
137
+ return;
138
+ }
139
+ if (args.json) {
140
+ console.log(JSON.stringify(receipt, null, 2));
141
+ } else {
142
+ console.log(`[migrate-180] mode=${receipt.mode} memoryRoot=${receipt.memoryRoot}`);
143
+ console.log(`[migrate-180] records=${receipt.recordsTotal} mapped=${receipt.mapped} duplicates=${receipt.duplicates} unmappable=${receipt.unmappable.length} appended=${receipt.appended} skippedExisting=${receipt.skippedExisting}`);
144
+ console.log(`[migrate-180] claims before=${receipt.beforeClaims} after=${receipt.afterClaims} countMatched=${receipt.countMatched}`);
145
+ if (receipt.backup) console.log(`[migrate-180] backup=${receipt.backup.path} sha256=${receipt.backup.sha256}`);
146
+ if (!args.apply) console.log('[migrate-180] dry-run: nothing written (pass --apply to write claims)');
147
+ }
148
+ if (receipt.recordsTotal > 0 && !receipt.countMatched && args.apply) {
149
+ console.error('[migrate-180] FAIL: migration count mismatch');
150
+ process.exitCode = 1;
151
+ }
152
+ }
153
+
154
+ try {
155
+ main();
156
+ } catch (error) {
157
+ if (String(error?.code ?? '').startsWith('E_CLI_')) {
158
+ writeCliError(error, process.argv.slice(2));
159
+ } else {
160
+ console.error(`[migrate-180] FAILED: ${error?.stack ?? error}`);
161
+ process.exitCode = 1;
162
+ }
163
+ }
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env node
2
+ // scripts/recall-index-build.mjs — M2-A:从 L0 会话日志重建/增量构建事件索引
3
+ //
4
+ // node scripts/recall-index-build.mjs [--memory-root <dir>] [--sessions-root <dir>]
5
+ // [--rebuild] [--limit-sessions N] [--search "<query>"] [--json]
6
+ //
7
+ // 只读 L0(`<sessions-root>/.../session.v4.jsonl.zstd`),所有写都落在
8
+ // `<memory-root>/.longlive/index/`(events.db / events.audit.jsonl / frames/ / build-state.json)。
9
+ // 默认 memory-root = $DSH_LONGLIVE_MEMORY_ROOT / $DSH_MEM / <DSH_HOME>/longlive-memory;
10
+ // 默认 sessions-root = <DSH_HOME>/sessions。`--rebuild` 先删派生索引(验证删库重建)。
11
+
12
+ import fs from 'node:fs';
13
+ import os from 'node:os';
14
+ import path from 'node:path';
15
+
16
+ import {
17
+ buildIndexFromSessions,
18
+ createEventsIndexReader,
19
+ deleteIndex,
20
+ indexPaths,
21
+ openEventIndex,
22
+ } from '../src/memory/event-index.js';
23
+
24
+ function parseArgs(argv) {
25
+ const out = {
26
+ memoryRoot: '',
27
+ sessionsRoot: '',
28
+ rebuild: false,
29
+ limitSessions: Number.POSITIVE_INFINITY,
30
+ search: '',
31
+ json: false,
32
+ now: null,
33
+ };
34
+ for (let i = 0; i < argv.length; i += 1) {
35
+ const arg = argv[i];
36
+ const match = /^--([a-z-]+)(?:=(.*))?$/.exec(arg);
37
+ if (!match) continue;
38
+ const [, key, inline] = match;
39
+ const value = inline !== undefined ? inline : (argv[i + 1] && !argv[i + 1].startsWith('--') ? argv[++i] : '');
40
+ if (key === 'memory-root') out.memoryRoot = value;
41
+ else if (key === 'sessions-root') out.sessionsRoot = value;
42
+ else if (key === 'rebuild') out.rebuild = true;
43
+ else if (key === 'limit-sessions') out.limitSessions = Number.parseInt(value, 10);
44
+ else if (key === 'search') out.search = value;
45
+ else if (key === 'json') out.json = true;
46
+ }
47
+ return out;
48
+ }
49
+
50
+ function dshHome() {
51
+ const raw = process.env.DSH_HOME;
52
+ if (typeof raw === 'string' && raw.trim() !== '') return path.resolve(raw.trim());
53
+ return path.join(os.homedir(), '.dsh');
54
+ }
55
+
56
+ function defaultMemoryRoot() {
57
+ for (const envName of ['DSH_LONGLIVE_MEMORY_ROOT', 'DSH_MEM']) {
58
+ const value = process.env[envName];
59
+ if (typeof value === 'string' && value.trim() !== '') return path.resolve(value.trim());
60
+ }
61
+ return path.join(dshHome(), 'longlive-memory');
62
+ }
63
+
64
+ function main() {
65
+ const args = parseArgs(process.argv.slice(2));
66
+ const memoryRoot = path.resolve(args.memoryRoot !== '' ? args.memoryRoot : defaultMemoryRoot());
67
+ const sessionsRoot = path.resolve(args.sessionsRoot !== '' ? args.sessionsRoot : path.join(dshHome(), 'sessions'));
68
+ if (!fs.existsSync(sessionsRoot)) {
69
+ console.error(`[recall-index-build] sessions root not found: ${sessionsRoot}`);
70
+ process.exitCode = 2;
71
+ return;
72
+ }
73
+ const receipt = {
74
+ schema: 'recall-index-build/v1',
75
+ memoryRoot,
76
+ sessionsRoot,
77
+ rebuild: args.rebuild,
78
+ index: indexPaths(memoryRoot),
79
+ };
80
+ const started = Date.now();
81
+ if (args.rebuild) receipt.deleted = deleteIndex(memoryRoot);
82
+ const result = buildIndexFromSessions({
83
+ memoryRoot,
84
+ sessionRoots: [sessionsRoot],
85
+ rebuild: false,
86
+ limitSessions: Number.isFinite(args.limitSessions) ? args.limitSessions : undefined,
87
+ source: 'cli',
88
+ });
89
+ receipt.build = {
90
+ sessionsScanned: result.sessionsScanned,
91
+ sessionsBuilt: result.sessionsBuilt,
92
+ duplicateSessions: result.duplicateSessions,
93
+ turns: result.turns,
94
+ inserted: result.inserted,
95
+ skipped: result.skipped,
96
+ errors: result.errors,
97
+ durationMs: result.durationMs,
98
+ dbBytes: result.dbBytes,
99
+ };
100
+ if (args.search !== '') {
101
+ const index = openEventIndex({ memoryRoot });
102
+ try {
103
+ receipt.search = index.search(args.search, { limit: 5 });
104
+ } finally {
105
+ index.close();
106
+ }
107
+ }
108
+ const reader = createEventsIndexReader({ memoryRoot });
109
+ receipt.readerAvailable = typeof reader === 'function';
110
+ receipt.elapsedMs = Date.now() - started;
111
+ const text = JSON.stringify(receipt, null, 2);
112
+ if (args.json) console.log(text);
113
+ else {
114
+ console.log(`[recall-index-build] memoryRoot=${memoryRoot}`);
115
+ console.log(`[recall-index-build] sessions=${receipt.build.sessionsBuilt}/${receipt.build.sessionsScanned} turns=${receipt.build.turns} inserted=${receipt.build.inserted} skipped=${receipt.build.skipped} errors=${receipt.build.errors} duplicates=${receipt.build.duplicateSessions}`);
116
+ console.log(`[recall-index-build] db=${receipt.index.db} dbBytes=${receipt.build.dbBytes} reader=${receipt.readerAvailable} elapsedMs=${receipt.elapsedMs}`);
117
+ if (receipt.search) {
118
+ console.log(`[recall-index-build] search strategy=${receipt.search.strategy ?? 'none'} rows=${receipt.search.rows.length} code=${receipt.search.code ?? 'OK'}`);
119
+ }
120
+ }
121
+ }
122
+
123
+ try {
124
+ main();
125
+ } catch (error) {
126
+ console.error(`[recall-index-build] FAILED: ${error?.stack ?? error}`);
127
+ process.exitCode = 1;
128
+ }