@modusensus/dsh-mneme 0.14.0-beta.1 → 0.14.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (543) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +830 -830
  3. package/assets/icon.svg +3 -3
  4. package/bin/cli.mjs +964 -964
  5. package/bin/dsh-mneme-choro.mjs +262 -262
  6. package/bin/dsh-mneme-mcp.mjs +510 -510
  7. package/bin/dsh-mneme-serve.mjs +151 -151
  8. package/cordis.patch.yml +21 -21
  9. package/docs/CONFIGURATION.md +407 -404
  10. package/docs/CONTINUITY.md +139 -139
  11. package/docs/DAEMON.md +57 -57
  12. package/docs/DIRECTORIES.md +114 -114
  13. package/docs/DISTILL.md +397 -371
  14. package/docs/DSH-GO.md +97 -97
  15. package/docs/ENTITIES.md +247 -247
  16. package/docs/FORGET.md +77 -77
  17. package/docs/KB.md +110 -110
  18. package/docs/LOCAL_MODEL.md +222 -222
  19. package/docs/SEMANTIC.md +256 -256
  20. package/docs/SHARE.md +552 -552
  21. package/docs/SLEEP.md +202 -202
  22. package/docs/STORAGE.md +122 -122
  23. package/docs/WORKFLOWS.md +366 -366
  24. package/lib/api-standalone.js +1007 -1007
  25. package/lib/api.js +3600 -3600
  26. package/lib/attachment-text.js +122 -122
  27. package/lib/bootstrap-http.js +105 -105
  28. package/lib/bootstrap.js +215 -215
  29. package/lib/candidates.js +454 -454
  30. package/lib/capabilities.js +819 -819
  31. package/lib/choro-command.js +111 -111
  32. package/lib/client.js +14420 -14322
  33. package/lib/commands.js +95 -95
  34. package/lib/config-keys.js +144 -144
  35. package/lib/config.js +1361 -1344
  36. package/lib/content-hash.js +54 -54
  37. package/lib/continuity.js +258 -258
  38. package/lib/date-hint.js +32 -0
  39. package/lib/diary/auto.js +190 -190
  40. package/lib/diary/compose.js +440 -440
  41. package/lib/diary/dir.js +59 -59
  42. package/lib/diary/export.js +97 -97
  43. package/lib/diary/index.js +26 -26
  44. package/lib/diary/library.js +189 -189
  45. package/lib/diary/qq-inbox.js +142 -142
  46. package/lib/diary/rollover.js +61 -61
  47. package/lib/diary/session-provider.js +122 -122
  48. package/lib/document-index.js +94 -94
  49. package/lib/document.js +322 -322
  50. package/lib/dream/clustering.js +123 -123
  51. package/lib/dream/decisions.js +945 -945
  52. package/lib/dream/narratives.js +44 -44
  53. package/lib/dream/sleep.js +2027 -2027
  54. package/lib/dream/triage.js +139 -139
  55. package/lib/dream.js +1879 -1879
  56. package/lib/dsh-go/host.js +162 -162
  57. package/lib/dsh-go/panel.js +2091 -2091
  58. package/lib/dsh-go/text.js +342 -342
  59. package/lib/dsh-go/views/common.js +68 -68
  60. package/lib/dsh-go/views/entity.js +48 -48
  61. package/lib/dsh-go/views/memory.js +198 -198
  62. package/lib/dsh-go/views/root.js +30 -30
  63. package/lib/dsh-go/views/settings.js +398 -398
  64. package/lib/dsh-go/views/status.js +51 -51
  65. package/lib/embedding.js +342 -342
  66. package/lib/entities/extractor.js +285 -285
  67. package/lib/fence.js +24 -24
  68. package/lib/graph/anchoring.js +184 -184
  69. package/lib/guide.js +74 -74
  70. package/lib/heat.js +144 -144
  71. package/lib/hot-memory.js +119 -119
  72. package/lib/image-describe.js +158 -0
  73. package/lib/index.js +852 -852
  74. package/lib/inject.js +656 -651
  75. package/lib/kb/index.js +309 -309
  76. package/lib/kb/routes.js +219 -219
  77. package/lib/kb/tools.js +148 -148
  78. package/lib/lang.js +607 -595
  79. package/lib/local-embedder.js +358 -358
  80. package/lib/maintenance.js +162 -162
  81. package/lib/memory-source.js +9 -9
  82. package/lib/mirror.js +330 -330
  83. package/lib/organize.js +456 -456
  84. package/lib/peak-hours.js +172 -172
  85. package/lib/pipeline-activities.js +178 -178
  86. package/lib/pipeline-attribution.js +165 -165
  87. package/lib/pipeline-command.js +279 -279
  88. package/lib/pipeline-confirm.js +142 -142
  89. package/lib/pipeline-exec.js +174 -174
  90. package/lib/pipeline-nudge-auto.js +129 -129
  91. package/lib/pipeline-nudge.js +1623 -1623
  92. package/lib/pipeline-observations.js +181 -181
  93. package/lib/pipeline-observe.js +133 -133
  94. package/lib/pipeline-runner.js +361 -361
  95. package/lib/pipeline-runs.js +442 -442
  96. package/lib/pipeline.js +716 -716
  97. package/lib/placement.js +13 -13
  98. package/lib/pre-inject-gate.js +354 -354
  99. package/lib/profile-extract.js +164 -164
  100. package/lib/profile-facts.js +356 -356
  101. package/lib/provenance-http.js +251 -251
  102. package/lib/quality-filter.js +162 -162
  103. package/lib/recall-stats.js +190 -190
  104. package/lib/reclaim-http.js +150 -150
  105. package/lib/reranker.js +269 -269
  106. package/lib/runtime/adopt.js +176 -176
  107. package/lib/runtime/closure.js +172 -172
  108. package/lib/runtime/download.js +247 -247
  109. package/lib/runtime/layout.js +265 -265
  110. package/lib/runtime/loader.js +252 -252
  111. package/lib/runtime/model-fetch.js +361 -361
  112. package/lib/runtime/provision.js +237 -237
  113. package/lib/runtime/tarball.js +130 -130
  114. package/lib/runtime/verify.js +223 -223
  115. package/lib/safe-slice.js +18 -18
  116. package/lib/scope-state.js +277 -277
  117. package/lib/scope.js +187 -187
  118. package/lib/search/adaptive.js +60 -60
  119. package/lib/search/bm25.js +96 -96
  120. package/lib/semantic.js +572 -572
  121. package/lib/sensitive-scan.js +209 -209
  122. package/lib/serve.js +228 -228
  123. package/lib/service.js +3268 -3268
  124. package/lib/session-gate.js +91 -91
  125. package/lib/session-usage.js +350 -350
  126. package/lib/settings.js +827 -817
  127. package/lib/share-http.js +281 -281
  128. package/lib/share-import.js +234 -234
  129. package/lib/share.js +335 -335
  130. package/lib/store.js +5895 -5895
  131. package/lib/summarize.js +1388 -1343
  132. package/lib/tools.js +1370 -1356
  133. package/lib/user-settings.js +230 -230
  134. package/lib/vector-index.js +180 -180
  135. package/lib/version-check.js +122 -122
  136. package/lib/wiki/claims.js +267 -267
  137. package/lib/wiki/cli-hint.js +90 -90
  138. package/lib/wiki/inject.js +164 -164
  139. package/lib/wiki/partition.js +200 -200
  140. package/lib/wiki/plan.js +214 -214
  141. package/lib/wiki/queries.js +640 -640
  142. package/lib/wiki/render.js +261 -261
  143. package/lib/wiki/scan.js +371 -371
  144. package/lib/wiki/t0.js +500 -500
  145. package/lib/wiki/t1-jobs.js +232 -232
  146. package/lib/wiki/t1.js +609 -609
  147. package/lib/write-admission.js +404 -404
  148. package/locale/en.json +6 -6
  149. package/locale/zh.json +6 -6
  150. package/package.json +1 -1
  151. package/runtime-manifest.json +526 -526
  152. package/scripts/benchmark-embed.js +201 -201
  153. package/scripts/benchmark-recall.js +249 -249
  154. package/scripts/benchmark-rerank.js +166 -166
  155. package/scripts/build-runtime-manifest.mjs +224 -224
  156. package/scripts/changelog-prep.mjs +91 -91
  157. package/scripts/check-sync.js +44 -44
  158. package/scripts/e2e-dsh.js +220 -220
  159. package/scripts/mneme-runtime.mjs +277 -277
  160. package/scripts/publish-gate.mjs +197 -197
  161. package/scripts/release-docs.mjs +210 -210
  162. package/scripts/release-notes.mjs +164 -164
  163. package/scripts/stress-dsh.js +255 -255
  164. package/scripts/sync-lib.js +47 -47
  165. package/scripts/sync-test-badge.mjs +69 -69
  166. package/scripts/test-count-sync.mjs +48 -48
  167. package/src/api-standalone.js +1007 -1007
  168. package/src/api.js +3600 -3600
  169. package/src/attachment-text.js +122 -122
  170. package/src/bootstrap-http.js +105 -105
  171. package/src/bootstrap.js +215 -215
  172. package/src/candidates.js +454 -454
  173. package/src/capabilities.js +819 -819
  174. package/src/choro-command.js +111 -111
  175. package/src/commands.js +95 -95
  176. package/src/config-keys.js +144 -144
  177. package/src/config.js +1361 -1344
  178. package/src/content-hash.js +54 -54
  179. package/src/continuity.js +258 -258
  180. package/src/date-hint.js +32 -0
  181. package/src/diary/auto.js +190 -190
  182. package/src/diary/compose.js +440 -440
  183. package/src/diary/dir.js +59 -59
  184. package/src/diary/export.js +97 -97
  185. package/src/diary/index.js +26 -26
  186. package/src/diary/library.js +189 -189
  187. package/src/diary/qq-inbox.js +142 -142
  188. package/src/diary/rollover.js +61 -61
  189. package/src/diary/session-provider.js +122 -122
  190. package/src/document-index.js +94 -94
  191. package/src/document.js +322 -322
  192. package/src/dream/clustering.js +123 -123
  193. package/src/dream/decisions.js +945 -945
  194. package/src/dream/narratives.js +44 -44
  195. package/src/dream/sleep.js +2027 -2027
  196. package/src/dream/triage.js +139 -139
  197. package/src/dream.js +1879 -1879
  198. package/src/dsh-go/host.js +162 -162
  199. package/src/dsh-go/panel.js +2091 -2091
  200. package/src/dsh-go/text.js +342 -342
  201. package/src/dsh-go/views/common.js +68 -68
  202. package/src/dsh-go/views/entity.js +48 -48
  203. package/src/dsh-go/views/memory.js +198 -198
  204. package/src/dsh-go/views/root.js +30 -30
  205. package/src/dsh-go/views/settings.js +398 -398
  206. package/src/dsh-go/views/status.js +51 -51
  207. package/src/embedding.js +342 -342
  208. package/src/entities/extractor.js +285 -285
  209. package/src/fence.js +24 -24
  210. package/src/graph/anchoring.js +184 -184
  211. package/src/guide.js +74 -74
  212. package/src/heat.js +144 -144
  213. package/src/hot-memory.js +119 -119
  214. package/src/image-describe.js +158 -0
  215. package/src/index.js +852 -852
  216. package/src/inject.js +656 -651
  217. package/src/kb/index.js +309 -309
  218. package/src/kb/routes.js +219 -219
  219. package/src/kb/tools.js +148 -148
  220. package/src/lang.js +607 -595
  221. package/src/local-embedder.js +358 -358
  222. package/src/maintenance.js +162 -162
  223. package/src/memory-source.js +9 -9
  224. package/src/mirror.js +330 -330
  225. package/src/organize.js +456 -456
  226. package/src/peak-hours.js +172 -172
  227. package/src/pipeline-activities.js +178 -178
  228. package/src/pipeline-attribution.js +165 -165
  229. package/src/pipeline-command.js +279 -279
  230. package/src/pipeline-confirm.js +142 -142
  231. package/src/pipeline-exec.js +174 -174
  232. package/src/pipeline-nudge-auto.js +129 -129
  233. package/src/pipeline-nudge.js +1623 -1623
  234. package/src/pipeline-observations.js +181 -181
  235. package/src/pipeline-observe.js +133 -133
  236. package/src/pipeline-runner.js +361 -361
  237. package/src/pipeline-runs.js +442 -442
  238. package/src/pipeline.js +716 -716
  239. package/src/placement.js +13 -13
  240. package/src/pre-inject-gate.js +354 -354
  241. package/src/profile-extract.js +164 -164
  242. package/src/profile-facts.js +356 -356
  243. package/src/provenance-http.js +251 -251
  244. package/src/quality-filter.js +162 -162
  245. package/src/recall-stats.js +190 -190
  246. package/src/reclaim-http.js +150 -150
  247. package/src/reranker.js +269 -269
  248. package/src/runtime/adopt.js +176 -176
  249. package/src/runtime/closure.js +172 -172
  250. package/src/runtime/download.js +247 -247
  251. package/src/runtime/layout.js +265 -265
  252. package/src/runtime/loader.js +252 -252
  253. package/src/runtime/model-fetch.js +361 -361
  254. package/src/runtime/provision.js +237 -237
  255. package/src/runtime/tarball.js +130 -130
  256. package/src/runtime/verify.js +223 -223
  257. package/src/safe-slice.js +18 -18
  258. package/src/scope-state.js +277 -277
  259. package/src/scope.js +187 -187
  260. package/src/search/adaptive.js +60 -60
  261. package/src/search/bm25.js +96 -96
  262. package/src/semantic.js +572 -572
  263. package/src/sensitive-scan.js +209 -209
  264. package/src/serve.js +228 -228
  265. package/src/service.js +3268 -3268
  266. package/src/session-gate.js +91 -91
  267. package/src/session-usage.js +350 -350
  268. package/src/settings.js +827 -817
  269. package/src/share-http.js +281 -281
  270. package/src/share-import.js +234 -234
  271. package/src/share.js +335 -335
  272. package/src/store.js +5895 -5895
  273. package/src/summarize.js +1388 -1343
  274. package/src/tools.js +1370 -1356
  275. package/src/user-settings.js +230 -230
  276. package/src/vector-index.js +180 -180
  277. package/src/version-check.js +122 -122
  278. package/src/wiki/claims.js +267 -267
  279. package/src/wiki/cli-hint.js +90 -90
  280. package/src/wiki/inject.js +164 -164
  281. package/src/wiki/partition.js +200 -200
  282. package/src/wiki/plan.js +214 -214
  283. package/src/wiki/queries.js +640 -640
  284. package/src/wiki/render.js +261 -261
  285. package/src/wiki/scan.js +371 -371
  286. package/src/wiki/t0.js +500 -500
  287. package/src/wiki/t1-jobs.js +232 -232
  288. package/src/wiki/t1.js +609 -609
  289. package/src/write-admission.js +404 -404
  290. package/test/adaptive-inject-budget.test.js +85 -85
  291. package/test/api-hardening.test.js +173 -173
  292. package/test/api-nudge-route.test.js +259 -259
  293. package/test/api-routes-gaps.test.js +1092 -1092
  294. package/test/api.test.js +3007 -2998
  295. package/test/attachment-text.test.js +139 -139
  296. package/test/audit.test.js +448 -448
  297. package/test/baseline-persist.test.js +248 -248
  298. package/test/benchmark.test.js +94 -94
  299. package/test/bm25-corpus-cache.test.js +145 -145
  300. package/test/bootstrap.test.js +228 -228
  301. package/test/candidates.test.js +345 -345
  302. package/test/capabilities.test.js +577 -577
  303. package/test/capacity-warning.test.js +262 -262
  304. package/test/changelog-prep.test.js +125 -125
  305. package/test/choro-command.test.js +218 -218
  306. package/test/cli-enums.test.js +37 -37
  307. package/test/cli-flag-value.test.js +86 -86
  308. package/test/cli-receive.test.js +390 -390
  309. package/test/cli-share.test.js +437 -437
  310. package/test/client-share.test.js +225 -225
  311. package/test/client.test.js +4595 -4425
  312. package/test/clustering.test.js +100 -100
  313. package/test/commands.test.js +106 -106
  314. package/test/config-keys-routes.test.js +233 -233
  315. package/test/config.test.js +153 -153
  316. package/test/conflict-freeze.test.js +344 -344
  317. package/test/conflict-ledger-enforce.test.js +452 -452
  318. package/test/conflict-ledger.test.js +242 -242
  319. package/test/conflict-reviewed.test.js +79 -79
  320. package/test/content-hash.test.js +204 -204
  321. package/test/continuity.test.js +452 -452
  322. package/test/contrast.test.js +432 -432
  323. package/test/date-hint.test.js +156 -0
  324. package/test/dedupe-candidate-window.test.js +180 -180
  325. package/test/dependency-overrides.test.js +78 -78
  326. package/test/diary-library.test.js +187 -187
  327. package/test/diary.test.js +576 -576
  328. package/test/differentiate-feedback.test.js +248 -248
  329. package/test/distill-tx-embed-gap.test.js +110 -110
  330. package/test/docs-config-keys.test.js +65 -65
  331. package/test/document-dir.test.js +233 -233
  332. package/test/document.test.js +703 -703
  333. package/test/dream-archive-guardrail.test.js +116 -116
  334. package/test/dream-baseline-clamp.test.js +174 -174
  335. package/test/dream-candidate-hybrid.test.js +281 -281
  336. package/test/dream-coverage-degrade.test.js +86 -86
  337. package/test/dream-decision-evidence.test.js +314 -314
  338. package/test/dream-failure-backoff.test.js +173 -173
  339. package/test/dream-fence.test.js +207 -207
  340. package/test/dream-maxtokens-fallback.test.js +132 -132
  341. package/test/dream-merge-guardrail.test.js +219 -219
  342. package/test/dream-peak-hours.test.js +194 -194
  343. package/test/dream.test.js +1528 -1528
  344. package/test/dsh-go-host.test.js +134 -134
  345. package/test/dsh-go-panel-actions.test.js +854 -854
  346. package/test/dsh-go-panel.test.js +251 -251
  347. package/test/embed-ready-poll.test.js +94 -94
  348. package/test/embed-text-reasons.test.js +112 -112
  349. package/test/embedding-cache-f32.test.js +276 -276
  350. package/test/embedding-ready.test.js +226 -226
  351. package/test/entities.test.js +711 -711
  352. package/test/entity-recall.test.js +179 -179
  353. package/test/epistemic.test.js +325 -325
  354. package/test/failure-query.test.js +147 -147
  355. package/test/failure-retention.test.js +105 -105
  356. package/test/fnew-0112.test.js +311 -311
  357. package/test/fnew-03.test.js +422 -422
  358. package/test/forget-corrections.test.js +70 -70
  359. package/test/graph-anchoring.test.js +184 -184
  360. package/test/graph-api.test.js +333 -333
  361. package/test/graph-boosted-relations.test.js +189 -189
  362. package/test/graph-inject-budget.test.js +103 -103
  363. package/test/graph-multipath.test.js +269 -269
  364. package/test/graph-passive-confirm.test.js +91 -91
  365. package/test/graph-weight-evolution.test.js +104 -104
  366. package/test/heat.test.js +175 -175
  367. package/test/helpers/dream-mock.js +86 -86
  368. package/test/helpers/peer-worker.mjs +25 -25
  369. package/test/helpers/runtime-source.js +60 -60
  370. package/test/helpers/tar-builder.js +80 -80
  371. package/test/helpers/write-admission-samples.js +312 -312
  372. package/test/hot-memory.test.js +259 -259
  373. package/test/image-description.test.js +271 -0
  374. package/test/image-memory.test.js +170 -170
  375. package/test/inject-content-cap.test.js +91 -91
  376. package/test/inject-first-round-bm25.test.js +89 -89
  377. package/test/inject-heat.test.js +77 -77
  378. package/test/inject-parent-gate.test.js +134 -109
  379. package/test/inject-pin-explicit.test.js +300 -300
  380. package/test/inject-pin-vector-crowd.test.js +225 -225
  381. package/test/inject-pools.test.js +195 -195
  382. package/test/inject-recall.test.js +172 -172
  383. package/test/inject-rotation.test.js +161 -161
  384. package/test/inject.test.js +553 -553
  385. package/test/issue-617-step1-query-and-fusion.test.js +361 -361
  386. package/test/kb-api-wiring.test.js +128 -128
  387. package/test/kb-collections.test.js +272 -272
  388. package/test/kb-routes.test.js +379 -379
  389. package/test/lang.test.js +98 -98
  390. package/test/lastrunat-persist.test.js +101 -101
  391. package/test/lib-smoke.test.js +116 -116
  392. package/test/llm-audit.test.js +815 -815
  393. package/test/llm-message-source.test.js +207 -207
  394. package/test/local-embedder.test.js +292 -292
  395. package/test/maintenance.test.js +501 -501
  396. package/test/mcp-stdio.test.js +385 -385
  397. package/test/mint-source.test.js +311 -311
  398. package/test/mirror-dirty.test.js +424 -424
  399. package/test/mirror-edit-digest.test.js +187 -187
  400. package/test/mirror-generation.test.js +499 -499
  401. package/test/mirror-types.test.js +208 -208
  402. package/test/mirror.test.js +249 -249
  403. package/test/narrative-bars.test.js +162 -162
  404. package/test/organize-tool.test.js +232 -232
  405. package/test/organize.test.js +418 -418
  406. package/test/panel-chart-scale.test.js +90 -90
  407. package/test/panel-tokens.test.js +245 -245
  408. package/test/peak-hours-observability.test.js +70 -70
  409. package/test/peer-blockers.test.js +193 -193
  410. package/test/persona-addressing.test.js +83 -83
  411. package/test/persona-api.test.js +172 -172
  412. package/test/persona-by-session.test.js +568 -568
  413. package/test/persona-flag.test.js +36 -36
  414. package/test/persona-inject.test.js +145 -145
  415. package/test/persona-settings.test.js +198 -198
  416. package/test/pipeline-activities.test.js +155 -155
  417. package/test/pipeline-attribution.test.js +175 -175
  418. package/test/pipeline-command.test.js +243 -243
  419. package/test/pipeline-confirm.test.js +148 -148
  420. package/test/pipeline-exec.test.js +172 -172
  421. package/test/pipeline-nudge-auto.test.js +248 -248
  422. package/test/pipeline-nudge.test.js +1278 -1278
  423. package/test/pipeline-observations.test.js +157 -157
  424. package/test/pipeline-observe.test.js +127 -127
  425. package/test/pipeline-r1r2.test.js +278 -278
  426. package/test/pipeline-runner.test.js +468 -468
  427. package/test/pipeline-runs.test.js +767 -767
  428. package/test/pipeline.test.js +636 -636
  429. package/test/placement.test.js +36 -36
  430. package/test/policy-epoch.test.js +259 -259
  431. package/test/pre-inject-gate.test.js +444 -444
  432. package/test/profile-extract.test.js +269 -269
  433. package/test/profile-facts.test.js +492 -492
  434. package/test/prompt-stance.test.js +128 -128
  435. package/test/provenance-http.test.js +367 -367
  436. package/test/publish-gate.test.js +272 -272
  437. package/test/quality-backfill.test.js +290 -290
  438. package/test/quality-filter.test.js +295 -295
  439. package/test/readme-claims.test.js +113 -113
  440. package/test/reasoning-effort.test.js +752 -752
  441. package/test/recall-anti-update.test.js +82 -82
  442. package/test/recall-evals.test.js +253 -253
  443. package/test/recall-layer.test.js +326 -326
  444. package/test/recall-retention.test.js +128 -128
  445. package/test/recall-stats.test.js +274 -274
  446. package/test/receipt-chain.test.js +451 -451
  447. package/test/reclaim-http.test.js +209 -209
  448. package/test/reflection-update-gate.test.js +129 -129
  449. package/test/reflection.test.js +226 -226
  450. package/test/reindex-backfill.test.js +475 -475
  451. package/test/reindex-scheduler.test.js +369 -369
  452. package/test/release-docs.test.js +156 -156
  453. package/test/release-notes.test.js +265 -265
  454. package/test/release-workflow.test.js +93 -93
  455. package/test/reranker-single-logit.test.js +73 -73
  456. package/test/reranker.test.js +197 -197
  457. package/test/resident-status.test.js +83 -83
  458. package/test/route-policy.test.js +113 -113
  459. package/test/runtime-adopt.test.js +206 -206
  460. package/test/runtime-cli.test.js +89 -89
  461. package/test/runtime-closure.test.js +193 -193
  462. package/test/runtime-download.test.js +302 -302
  463. package/test/runtime-layout.test.js +163 -163
  464. package/test/runtime-loader.test.js +255 -255
  465. package/test/runtime-manifest.test.js +159 -159
  466. package/test/runtime-model-fetch.test.js +348 -348
  467. package/test/runtime-provision.test.js +101 -101
  468. package/test/runtime-tarball.test.js +81 -81
  469. package/test/runtime-verify.test.js +319 -319
  470. package/test/scope-candidates.test.js +491 -491
  471. package/test/scope-distill-stamp.test.js +134 -134
  472. package/test/scope-explicit.test.js +452 -452
  473. package/test/scope-inject-soft.test.js +106 -106
  474. package/test/scope-optional-service.test.js +110 -110
  475. package/test/scope-retrieval.test.js +197 -197
  476. package/test/scope-state.test.js +610 -610
  477. package/test/scope-storage.test.js +255 -255
  478. package/test/scope-strict.test.js +367 -367
  479. package/test/search-fusion.test.js +90 -90
  480. package/test/security-doc.test.js +188 -188
  481. package/test/semantic.test.js +124 -124
  482. package/test/sensitive-scan.test.js +251 -251
  483. package/test/serve-bin.test.js +121 -121
  484. package/test/serve.test.js +258 -258
  485. package/test/service-search.test.js +174 -174
  486. package/test/service.test.js +410 -410
  487. package/test/session-gate.test.js +264 -264
  488. package/test/session-usage.test.js +317 -317
  489. package/test/settings.test.js +273 -273
  490. package/test/share-foreign-rows.test.js +144 -144
  491. package/test/share-http.test.js +144 -144
  492. package/test/share-import.test.js +577 -577
  493. package/test/share-imported-guard.test.js +311 -311
  494. package/test/share-imported-identity.test.js +111 -111
  495. package/test/share-pack.test.js +511 -511
  496. package/test/share-receive-http.test.js +756 -756
  497. package/test/share-routes.test.js +337 -337
  498. package/test/share-store.test.js +133 -133
  499. package/test/share-validate.test.js +101 -101
  500. package/test/skip-invalid-restore.test.js +262 -262
  501. package/test/sleep-action-set.test.js +441 -441
  502. package/test/sleep-catchup.test.js +315 -315
  503. package/test/sleep-failure-backoff.test.js +156 -156
  504. package/test/sleep-heat.test.js +174 -174
  505. package/test/sleep-scheduler-rearm.test.js +89 -89
  506. package/test/sleep.test.js +1455 -1455
  507. package/test/standalone-api.test.js +1344 -1344
  508. package/test/store-vector-cache.test.js +98 -98
  509. package/test/store-write-path-columns.test.js +191 -191
  510. package/test/store.test.js +744 -744
  511. package/test/stress.test.js +209 -209
  512. package/test/summarize-occurred-at.test.js +127 -127
  513. package/test/summarize-parse-diagnostics.test.js +75 -75
  514. package/test/summarize-reasoning-effort.test.js +189 -189
  515. package/test/summarize.test.js +2251 -2251
  516. package/test/supersede-state-tracking.test.js +394 -394
  517. package/test/test-count-sync.test.js +71 -71
  518. package/test/tool-state-ignore.test.js +65 -65
  519. package/test/tools-dto-schema-matrix.test.js +398 -398
  520. package/test/tools-memory-get-schema.test.js +65 -65
  521. package/test/tools.test.js +585 -585
  522. package/test/updated-at-semantics.test.js +113 -113
  523. package/test/user-settings-preview.test.js +127 -127
  524. package/test/user-settings-segments.test.js +527 -527
  525. package/test/vector-index.test.js +334 -334
  526. package/test/version-check.test.js +152 -152
  527. package/test/webServer-optional.test.js +82 -82
  528. package/test/wiki-api.test.js +734 -734
  529. package/test/wiki-claims.test.js +194 -194
  530. package/test/wiki-cli-hint.test.js +118 -118
  531. package/test/wiki-inject.test.js +265 -265
  532. package/test/wiki-partition.test.js +112 -112
  533. package/test/wiki-plan.test.js +80 -80
  534. package/test/wiki-provenance.test.js +202 -202
  535. package/test/wiki-queries.test.js +398 -398
  536. package/test/wiki-scan.test.js +208 -208
  537. package/test/wiki-store.test.js +190 -190
  538. package/test/wiki-t0.test.js +456 -456
  539. package/test/wiki-t1-jobs.test.js +125 -125
  540. package/test/wiki-t1.test.js +460 -460
  541. package/test/wiki-tools.test.js +176 -176
  542. package/test/workflow-guards.test.js +155 -155
  543. package/test/write-admission.test.js +668 -668
package/src/share-http.js CHANGED
@@ -1,281 +1,281 @@
1
- // 分享包在两张皮上共用的解析与答复(形状照 src/reclaim-http.js,#411)。
2
- // 只返回 {status, body},绝不自己写 res —— 两侧的 sendJson 签名不同(api.js 有
3
- // headers 第四参、api-standalone.js 没有),把写 res 留在各侧 handler 里是唯一
4
- // 能让一份实现喂两张脸的做法。
5
- //
6
- // 哪些行进包、以什么原因不进,一条判据都不在这里重复:那是 src/share.js 的事。本模块
7
- // 只做协议层的事——读 body、把结果包成答复、给一个能落盘的文件名。
8
- import { buildSharePack } from "./share.js";
9
-
10
- /** 拒发时的下一步动作。它是给调用方看的,出口只许有一处措辞(同 RECLAIM_CONFIRM_HINT)。 */
11
- const SHARE_ERROR_HINT = "包体超过分享水位:用 --type 或 --tag 分批,别整库外发。";
12
-
13
- /**
14
- * 记日志这一手,只许经这里。
15
- *
16
- * 「这一层从不抛」是**层的契约**,不是每个调用面的运气(C5 评审裁定):warn 裸调时,宿主
17
- * logger 自己坏掉就会从 catch 块里再抛出去,而两侧 handler 那个外层 try 在 .then 的回调里
18
- * 早已退栈——现场就是「一个字节都没回」(#410)。守卫住在面上一处一个,等于每接一张新脸
19
- * 都要记得再兜一次;住在层里,两侧、以及后面的 CLI(C7)拿到的都是同一个脾气。
20
- *
21
- * 三个构造器(shareReply / receiveReply / undoReply)都走这里,**对称本身就是要点**:
22
- * 只给新加的两个上守卫、出包那侧留一处裸调,下一个读者就会照那处裸的抄。
23
- * 日志环坏掉时答复照旧送出——对面拿到的仍是那一个状态码,只是少了一条日志迹。
24
- */
25
- function warnSafely(warn, message) {
26
- try {
27
- warn?.(message);
28
- } catch { /* 记日志是自己的事,坏了的日志不许把已经算好的答复一起带走 */ }
29
- }
30
-
31
- /**
32
- * 解析 POST body(已由调用方读成文本)→ buildSharePack 的入参集合。
33
- *
34
- * 空 body 等价于 `{}`:分享的主用法就是「一个字节都不发,按整库口径打」。坏 JSON 与
35
- * 发成数组/null 是两个不同的错码(前者是调用方发坏了,后者是发错了顶层形状),
36
- * 与 reclaim 侧同款,出口要能分支。
37
- *
38
- * 只认这三个键,多余的键丢掉:面板与 CLI 各写各的选项时,静默接受一个拼错的键等于
39
- * 让她以为筛过了。
40
- *
41
- * 这里**没有** dryRun:share 是纯读、不改库,spec §4 明确它不套 reclaim 的
42
- * dry-run/confirm 纪律,干跑由 CLI 侧的 `--dry-run` 决定(它压根不发这个键)。上一版
43
- * 把它「登记但不参与答复构造」留着,等于凭空多出一个没人消费的公开字段:今天发
44
- * `dryRun: true` 的人拿到的是真包,而哪天要给它真语义、或把它删掉,两侧都是破坏性改动。
45
- * 删掉后它和别的多余键走同一条规则——丢掉,不再是一个特例。
46
- *
47
- * @returns {{ok: true, options: {alias?: string, type?: unknown, tag?: unknown}}
48
- * | {ok: false, error: string}}
49
- */
50
- export function parseShareBody(text) {
51
- if (text === undefined || text === null || String(text).trim() === "") return { ok: true, options: {} };
52
- let body;
53
- try {
54
- body = JSON.parse(String(text));
55
- } catch {
56
- return { ok: false, error: "invalid-json" };
57
- }
58
- if (!body || typeof body !== "object" || Array.isArray(body)) return { ok: false, error: "invalid-body" };
59
- const options = {};
60
- if (typeof body.alias === "string") options.alias = body.alias;
61
- // type / tag 在这里只判「填没填」,不判形状。收窄口径是 share.js 的 shareFilterSet,
62
- // 它钉死的是「读不懂的形状只许收窄到 0 条,不许当没填」(错的方向是少发,当场看得见)。
63
- // 本层若再校验一次形状、把裸字符串或混进非字符串条目的数组丢成「没填」,就等于在 HTTP
64
- // 面上把那条洞反着挖开——她以为只发了一类,实际整库进包,而 report 看不出异样。
65
- if (body.type !== undefined && body.type !== null) options.type = body.type;
66
- if (body.tag !== undefined && body.tag !== null) options.tag = body.tag;
67
- return { ok: true, options };
68
- }
69
-
70
- /** 包文件名:日期 + pack_id 前 8 位。Content-Disposition 与 CLI 落盘共用这一个拼法。 */
71
- export function shareFilename(packId, now = () => new Date()) {
72
- const stamp = now().toISOString().slice(0, 10).replace(/-/g, "");
73
- return `dsh-mneme-share-${stamp}-${String(packId).slice(0, 8)}.json`;
74
- }
75
-
76
- /**
77
- * 组包并给出答复。`service.all()` 是「全库含归档/已遗忘」的现成通道(store.js 的 all()
78
- * 不带 WHERE),口径判据全在 share.js 里判,本模块不重复任何一条。
79
- *
80
- * filters 两个键只在填了时才挂上去:buildSharePack 的默认值兜的是 `filters` 整个参数为
81
- * undefined,构造一个 `filters: null` 会直接在对端解引用时抛——没填的键就让它不存在。
82
- *
83
- * 413 那条绝不回 pack:这条答复存在的原因恰恰是包太大,把 memories 序列化回去等于把
84
- * 刚拒绝掉的那几 MB 再发一遍。report + 量到的字节 + 水位 + 提示够出口说清「大了多少、
85
- * 怎么分批」(share.js 超限时也把完整 pack 交回,本层只用它的 report)。
86
- *
87
- * 抛错在这里兜住并回 500,不留给调用方的 try:面板侧 handler 的形状是
88
- * `try { return readBody(...).then(...) } catch`,外层 try 在 .then 的回调里已经退栈,
89
- * 从这里抛出去就是一个没人接的 rejection,客户端拿到的不是 500 而是「一个字节都没回」
90
- * (#410,reclaim-http.js 里 reclaimReply 那段注释记的就是这一次)。共用层兜一次,两张
91
- * 皮才不会因为各自接线不同而有一种会漏。warn 可选:数据面的 logger 未必接得上,少一个
92
- * 回调也不许把异常漏出去。
93
- *
94
- * @param {{service: {all: () => object[]}, packageVersion: string, homeDir: string,
95
- * now?: () => Date, options?: object, warn?: ((msg: string) => void)|null}} input
96
- * @returns {{status: number, body: object}}
97
- */
98
- export function shareReply({ service, packageVersion, homeDir, now = () => new Date(), options = {}, warn = null }) {
99
- try {
100
- const rows = typeof service?.all === "function" ? service.all() : [];
101
- const filters = {};
102
- if (options.type !== undefined) filters.type = options.type;
103
- if (options.tag !== undefined) filters.tag = options.tag;
104
- const out = buildSharePack({
105
- rows, alias: options.alias, homeDir, packageVersion,
106
- filters,
107
- generatedAt: now().toISOString()
108
- });
109
- if (!out.ok) {
110
- return {
111
- status: 413,
112
- body: { error: out.error, bytes: out.bytes, limitBytes: out.limitBytes, hint: SHARE_ERROR_HINT, report: out.pack.report }
113
- };
114
- }
115
- return { status: 200, body: out.pack };
116
- } catch (error) {
117
- // 日志里留住原始文本(现场最难下手的就是「只回了 internal」那一类),对外只有一个码。
118
- warnSafely(warn, `[dsh-mneme] share pack failed: ${String(error)}`);
119
- return { status: 500, body: { error: "internal" } };
120
- }
121
- }
122
-
123
- // --- 接收侧(车道 C,spec §5)--------------------------------------------------
124
- // 入库与整包退出同属「两张皮只许差在鉴权与路径」那条纪律(#411),所以这两组解析/答复
125
- // 也住在本模块,与出包侧同一个形状:只回 {status, body},绝不写 res。
126
- //
127
- // 这里刻意**不**重跑 validateSharePack:整包闸门住在 share.js、由 service 的
128
- // importSharePack 自己调(src/share-import.js)。本层再判一次就是第二套口径——两份实现
129
- // 各自演进时最坏情况是「路由放行、service 拒」或反过来,而一个包有没有合格从此没有准信。
130
- // 失败靠 err.code 鸭子类型映射成状态码:ShareImportError 是刻意不从 service 再导出的
131
- // (类跨模块之后,instanceof 就退化成「只在同一个实例内成立」),码才是契约。
132
-
133
- /**
134
- * 导入错误码 → HTTP 状态。一张表喂两张皮(数据面那半也从这儿取),码集由 share.js 的
135
- * validateSharePack 定:闸门新增一格必须在这里登记。认不出的码走「500 + 日志」那一条,
136
- * 绝不静默降级成 400 冒充「你的包不合格」——那会把存储故障报成对方的错。
137
- */
138
- export const SHARE_IMPORT_ERRORS = Object.freeze({
139
- "invalid-kind": 400,
140
- "invalid-pack-id": 400,
141
- "invalid-memories": 400,
142
- "empty-pack": 400,
143
- "invalid-type": 400,
144
- "invalid-entry": 400,
145
- "external-id-mismatch": 400,
146
- "duplicate-external-id": 400
147
- });
148
-
149
- /**
150
- * 「收侧没接线」的码(headless 或旧装配里没有那两个方法)。与 RECLAIM_UNAVAILABLE 同一
151
- * 处置:字面量只许住在本模块,两张皮都从这一个导出取,否则各写一种拼法就没法按码分支。
152
- */
153
- export const SHARE_IMPORT_UNAVAILABLE = "share-import-unavailable";
154
-
155
- /**
156
- * 缺省即干跑:没有 confirm 就是预览。脾气照 readReclaimFields 的 confirm(只认真布尔),
157
- * 但这一面的方向更硬——写的是**收件人的库**,所以唯一的入口就是 confirm,`dryRun` 之类
158
- * 的第二个旋钮一概不认(reclaim 的 body 形状里就带 dryRun,手熟的人会顺手发来,把它读成
159
- * 「要写」等于替她点头)。
160
- */
161
- function readDryRun(body) {
162
- return body?.confirm !== true;
163
- }
164
-
165
- /**
166
- * 答复壳里唯一由本层加的一格。service 那一侧收的是 opts.dryRun、不认识 dry_run,对面读的
167
- * 却是这一格,所以放在本层加:两张皮拿到的键才完全相同。
168
- *
169
- * `dryRun !== false` 而不是 `=== true`:认不出的值(字符串、对象、undefined)一律落回**干跑**,
170
- * 与解析侧同一个失败方向;而传下去的那个布尔值与写进答复的那一格永远同一个数——「其实没写、
171
- * 却说写了」和「其实写了、却说没写」都是说谎,这一格不许和实参分家。
172
- */
173
- function withDryRun(reply, dryRun) {
174
- return { ...reply, dry_run: dryRun !== false };
175
- }
176
-
177
- /**
178
- * 解析 POST /receive 的 body(已读成文本)→ { pack, dryRun }。
179
- *
180
- * 三个码分开是有原因的:invalid-json(发坏了)、invalid-body(顶层就不是对象)、
181
- * missing-pack(对象里没有包)——对面据此知道改哪一头,而它们全是 400。空 body 是
182
- * **错**的,与出包侧相反:那边「一个字节都不发」是整库口径,这边压根没东西可写。
183
- *
184
- * pack 那一格只判「是不是个对象」,不判包:数组或 `{kind:"nope"}` 都往下交,由闸门整包拒
185
- * (invalid-kind)。判据只许有一处。
186
- *
187
- * @returns {{ok: true, pack: object, dryRun: boolean} | {ok: false, error: string}}
188
- */
189
- export function parseReceiveBody(text) {
190
- if (text === undefined || text === null || String(text).trim() === "") return { ok: false, error: "invalid-body" };
191
- let body;
192
- try {
193
- body = JSON.parse(String(text));
194
- } catch {
195
- return { ok: false, error: "invalid-json" };
196
- }
197
- if (!body || typeof body !== "object" || Array.isArray(body)) return { ok: false, error: "invalid-body" };
198
- if (!body.pack || typeof body.pack !== "object") return { ok: false, error: "missing-pack" };
199
- return { ok: true, pack: body.pack, dryRun: readDryRun(body) };
200
- }
201
-
202
- /**
203
- * 解析 POST /receive/undo 的 body → { packId, dryRun }。顶层形状与「有没有 id」是两个错,
204
- * 与 receive 侧同一口径(发坏了 / 发错了形状 / 没填)。
205
- *
206
- * id 在这里 trim,与 deleteSharePack 首行同一把尺;非字符串与空白一律不进删除那条路——
207
- * 让空白去 service 那儿换回一个 `pack_id: ""` 的 0 删除,读数上看不出是「没填」还是
208
- * 「那个包本来就没导入过」,而这两种在出口是完全不同的事。
209
- *
210
- * @returns {{ok: true, packId: string, dryRun: boolean} | {ok: false, error: string}}
211
- */
212
- export function parseUndoBody(text) {
213
- if (text === undefined || text === null || String(text).trim() === "") return { ok: false, error: "invalid-body" };
214
- let body;
215
- try {
216
- body = JSON.parse(String(text));
217
- } catch {
218
- return { ok: false, error: "invalid-json" };
219
- }
220
- if (!body || typeof body !== "object" || Array.isArray(body)) return { ok: false, error: "invalid-body" };
221
- const packId = typeof body.packId === "string" ? body.packId.trim() : "";
222
- if (!packId) return { ok: false, error: "missing-pack-id" };
223
- return { ok: true, packId, dryRun: readDryRun(body) };
224
- }
225
-
226
- /**
227
- * 入库的答复。`pack` 原样交给 service,校验在那儿跑(见本段开头那句「判据只许有一处」)。
228
- *
229
- * 抛错在这儿兜住并回 500,不留给调用方的 try:两侧 handler 的形状都是
230
- * `try { return readBody(...).then(...) } catch`,外层 try 在 .then 的回调里已经退栈,
231
- * 从这里抛出去就是一个没人接的 rejection(#410)。warn 可选——数据面的 logger 未必接得上,
232
- * 少一个回调不许把异常漏出去。
233
- *
234
- * @param {{service: {importSharePack?: Function}, pack: object, dryRun?: boolean,
235
- * warn?: ((msg: string) => void)|null}} input
236
- * @returns {{status: number, body: object}}
237
- */
238
- export function receiveReply({ service, pack, dryRun, warn = null }) {
239
- if (typeof service?.importSharePack !== "function") {
240
- return { status: 503, body: { error: SHARE_IMPORT_UNAVAILABLE } };
241
- }
242
- const dry = dryRun !== false;
243
- try {
244
- return { status: 200, body: withDryRun(service.importSharePack(pack, { dryRun: dry }), dry) };
245
- } catch (error) {
246
- const code = typeof error?.code === "string" ? error.code : null;
247
- const status = code === null ? undefined : SHARE_IMPORT_ERRORS[code];
248
- if (status) {
249
- // detail 是闸门给的那一格(哪个字段、哪个坏类型),只转发不加工;没有就不造这一格。
250
- const detail = typeof error.detail === "string" && error.detail ? { detail: error.detail } : {};
251
- return { status, body: { error: code, ...detail } };
252
- }
253
- warnSafely(warn, `[dsh-mneme] share import failed: ${String(error)}`);
254
- return { status: 500, body: { error: "internal" } };
255
- }
256
- }
257
-
258
- /**
259
- * 整包退出的答复。这一面**不查** SHARE_IMPORT_ERRORS:packId 的形状闸门在 parseUndoBody,
260
- * service 那侧不抛带码的错(非字符串/空白它回一个 0 删除,不是异常),所以真抛出来就是
261
- * 存储故障。别在这儿补第二张表——那张表只会成为 SHARE_IMPORT_ERRORS 的影子。
262
- *
263
- * 答复里的 pack_id 是 service 的读数而不是请求的回显(非字符串/空白那一支它回 ""),
264
- * 本层不改写、不兜底;dry_run 由 withDryRun 加,与入库那侧同一格键。
265
- *
266
- * @param {{service: {deleteSharePack?: Function}, packId: string, dryRun?: boolean,
267
- * warn?: ((msg: string) => void)|null}} input
268
- * @returns {{status: number, body: object}}
269
- */
270
- export function undoReply({ service, packId, dryRun, warn = null }) {
271
- if (typeof service?.deleteSharePack !== "function") {
272
- return { status: 503, body: { error: SHARE_IMPORT_UNAVAILABLE } };
273
- }
274
- const dry = dryRun !== false;
275
- try {
276
- return { status: 200, body: withDryRun(service.deleteSharePack(packId, { dryRun: dry }), dry) };
277
- } catch (error) {
278
- warnSafely(warn, `[dsh-mneme] share undo failed: ${String(error)}`);
279
- return { status: 500, body: { error: "internal" } };
280
- }
281
- }
1
+ // 分享包在两张皮上共用的解析与答复(形状照 src/reclaim-http.js,#411)。
2
+ // 只返回 {status, body},绝不自己写 res —— 两侧的 sendJson 签名不同(api.js 有
3
+ // headers 第四参、api-standalone.js 没有),把写 res 留在各侧 handler 里是唯一
4
+ // 能让一份实现喂两张脸的做法。
5
+ //
6
+ // 哪些行进包、以什么原因不进,一条判据都不在这里重复:那是 src/share.js 的事。本模块
7
+ // 只做协议层的事——读 body、把结果包成答复、给一个能落盘的文件名。
8
+ import { buildSharePack } from "./share.js";
9
+
10
+ /** 拒发时的下一步动作。它是给调用方看的,出口只许有一处措辞(同 RECLAIM_CONFIRM_HINT)。 */
11
+ const SHARE_ERROR_HINT = "包体超过分享水位:用 --type 或 --tag 分批,别整库外发。";
12
+
13
+ /**
14
+ * 记日志这一手,只许经这里。
15
+ *
16
+ * 「这一层从不抛」是**层的契约**,不是每个调用面的运气(C5 评审裁定):warn 裸调时,宿主
17
+ * logger 自己坏掉就会从 catch 块里再抛出去,而两侧 handler 那个外层 try 在 .then 的回调里
18
+ * 早已退栈——现场就是「一个字节都没回」(#410)。守卫住在面上一处一个,等于每接一张新脸
19
+ * 都要记得再兜一次;住在层里,两侧、以及后面的 CLI(C7)拿到的都是同一个脾气。
20
+ *
21
+ * 三个构造器(shareReply / receiveReply / undoReply)都走这里,**对称本身就是要点**:
22
+ * 只给新加的两个上守卫、出包那侧留一处裸调,下一个读者就会照那处裸的抄。
23
+ * 日志环坏掉时答复照旧送出——对面拿到的仍是那一个状态码,只是少了一条日志迹。
24
+ */
25
+ function warnSafely(warn, message) {
26
+ try {
27
+ warn?.(message);
28
+ } catch { /* 记日志是自己的事,坏了的日志不许把已经算好的答复一起带走 */ }
29
+ }
30
+
31
+ /**
32
+ * 解析 POST body(已由调用方读成文本)→ buildSharePack 的入参集合。
33
+ *
34
+ * 空 body 等价于 `{}`:分享的主用法就是「一个字节都不发,按整库口径打」。坏 JSON 与
35
+ * 发成数组/null 是两个不同的错码(前者是调用方发坏了,后者是发错了顶层形状),
36
+ * 与 reclaim 侧同款,出口要能分支。
37
+ *
38
+ * 只认这三个键,多余的键丢掉:面板与 CLI 各写各的选项时,静默接受一个拼错的键等于
39
+ * 让她以为筛过了。
40
+ *
41
+ * 这里**没有** dryRun:share 是纯读、不改库,spec §4 明确它不套 reclaim 的
42
+ * dry-run/confirm 纪律,干跑由 CLI 侧的 `--dry-run` 决定(它压根不发这个键)。上一版
43
+ * 把它「登记但不参与答复构造」留着,等于凭空多出一个没人消费的公开字段:今天发
44
+ * `dryRun: true` 的人拿到的是真包,而哪天要给它真语义、或把它删掉,两侧都是破坏性改动。
45
+ * 删掉后它和别的多余键走同一条规则——丢掉,不再是一个特例。
46
+ *
47
+ * @returns {{ok: true, options: {alias?: string, type?: unknown, tag?: unknown}}
48
+ * | {ok: false, error: string}}
49
+ */
50
+ export function parseShareBody(text) {
51
+ if (text === undefined || text === null || String(text).trim() === "") return { ok: true, options: {} };
52
+ let body;
53
+ try {
54
+ body = JSON.parse(String(text));
55
+ } catch {
56
+ return { ok: false, error: "invalid-json" };
57
+ }
58
+ if (!body || typeof body !== "object" || Array.isArray(body)) return { ok: false, error: "invalid-body" };
59
+ const options = {};
60
+ if (typeof body.alias === "string") options.alias = body.alias;
61
+ // type / tag 在这里只判「填没填」,不判形状。收窄口径是 share.js 的 shareFilterSet,
62
+ // 它钉死的是「读不懂的形状只许收窄到 0 条,不许当没填」(错的方向是少发,当场看得见)。
63
+ // 本层若再校验一次形状、把裸字符串或混进非字符串条目的数组丢成「没填」,就等于在 HTTP
64
+ // 面上把那条洞反着挖开——她以为只发了一类,实际整库进包,而 report 看不出异样。
65
+ if (body.type !== undefined && body.type !== null) options.type = body.type;
66
+ if (body.tag !== undefined && body.tag !== null) options.tag = body.tag;
67
+ return { ok: true, options };
68
+ }
69
+
70
+ /** 包文件名:日期 + pack_id 前 8 位。Content-Disposition 与 CLI 落盘共用这一个拼法。 */
71
+ export function shareFilename(packId, now = () => new Date()) {
72
+ const stamp = now().toISOString().slice(0, 10).replace(/-/g, "");
73
+ return `dsh-mneme-share-${stamp}-${String(packId).slice(0, 8)}.json`;
74
+ }
75
+
76
+ /**
77
+ * 组包并给出答复。`service.all()` 是「全库含归档/已遗忘」的现成通道(store.js 的 all()
78
+ * 不带 WHERE),口径判据全在 share.js 里判,本模块不重复任何一条。
79
+ *
80
+ * filters 两个键只在填了时才挂上去:buildSharePack 的默认值兜的是 `filters` 整个参数为
81
+ * undefined,构造一个 `filters: null` 会直接在对端解引用时抛——没填的键就让它不存在。
82
+ *
83
+ * 413 那条绝不回 pack:这条答复存在的原因恰恰是包太大,把 memories 序列化回去等于把
84
+ * 刚拒绝掉的那几 MB 再发一遍。report + 量到的字节 + 水位 + 提示够出口说清「大了多少、
85
+ * 怎么分批」(share.js 超限时也把完整 pack 交回,本层只用它的 report)。
86
+ *
87
+ * 抛错在这里兜住并回 500,不留给调用方的 try:面板侧 handler 的形状是
88
+ * `try { return readBody(...).then(...) } catch`,外层 try 在 .then 的回调里已经退栈,
89
+ * 从这里抛出去就是一个没人接的 rejection,客户端拿到的不是 500 而是「一个字节都没回」
90
+ * (#410,reclaim-http.js 里 reclaimReply 那段注释记的就是这一次)。共用层兜一次,两张
91
+ * 皮才不会因为各自接线不同而有一种会漏。warn 可选:数据面的 logger 未必接得上,少一个
92
+ * 回调也不许把异常漏出去。
93
+ *
94
+ * @param {{service: {all: () => object[]}, packageVersion: string, homeDir: string,
95
+ * now?: () => Date, options?: object, warn?: ((msg: string) => void)|null}} input
96
+ * @returns {{status: number, body: object}}
97
+ */
98
+ export function shareReply({ service, packageVersion, homeDir, now = () => new Date(), options = {}, warn = null }) {
99
+ try {
100
+ const rows = typeof service?.all === "function" ? service.all() : [];
101
+ const filters = {};
102
+ if (options.type !== undefined) filters.type = options.type;
103
+ if (options.tag !== undefined) filters.tag = options.tag;
104
+ const out = buildSharePack({
105
+ rows, alias: options.alias, homeDir, packageVersion,
106
+ filters,
107
+ generatedAt: now().toISOString()
108
+ });
109
+ if (!out.ok) {
110
+ return {
111
+ status: 413,
112
+ body: { error: out.error, bytes: out.bytes, limitBytes: out.limitBytes, hint: SHARE_ERROR_HINT, report: out.pack.report }
113
+ };
114
+ }
115
+ return { status: 200, body: out.pack };
116
+ } catch (error) {
117
+ // 日志里留住原始文本(现场最难下手的就是「只回了 internal」那一类),对外只有一个码。
118
+ warnSafely(warn, `[dsh-mneme] share pack failed: ${String(error)}`);
119
+ return { status: 500, body: { error: "internal" } };
120
+ }
121
+ }
122
+
123
+ // --- 接收侧(车道 C,spec §5)--------------------------------------------------
124
+ // 入库与整包退出同属「两张皮只许差在鉴权与路径」那条纪律(#411),所以这两组解析/答复
125
+ // 也住在本模块,与出包侧同一个形状:只回 {status, body},绝不写 res。
126
+ //
127
+ // 这里刻意**不**重跑 validateSharePack:整包闸门住在 share.js、由 service 的
128
+ // importSharePack 自己调(src/share-import.js)。本层再判一次就是第二套口径——两份实现
129
+ // 各自演进时最坏情况是「路由放行、service 拒」或反过来,而一个包有没有合格从此没有准信。
130
+ // 失败靠 err.code 鸭子类型映射成状态码:ShareImportError 是刻意不从 service 再导出的
131
+ // (类跨模块之后,instanceof 就退化成「只在同一个实例内成立」),码才是契约。
132
+
133
+ /**
134
+ * 导入错误码 → HTTP 状态。一张表喂两张皮(数据面那半也从这儿取),码集由 share.js 的
135
+ * validateSharePack 定:闸门新增一格必须在这里登记。认不出的码走「500 + 日志」那一条,
136
+ * 绝不静默降级成 400 冒充「你的包不合格」——那会把存储故障报成对方的错。
137
+ */
138
+ export const SHARE_IMPORT_ERRORS = Object.freeze({
139
+ "invalid-kind": 400,
140
+ "invalid-pack-id": 400,
141
+ "invalid-memories": 400,
142
+ "empty-pack": 400,
143
+ "invalid-type": 400,
144
+ "invalid-entry": 400,
145
+ "external-id-mismatch": 400,
146
+ "duplicate-external-id": 400
147
+ });
148
+
149
+ /**
150
+ * 「收侧没接线」的码(headless 或旧装配里没有那两个方法)。与 RECLAIM_UNAVAILABLE 同一
151
+ * 处置:字面量只许住在本模块,两张皮都从这一个导出取,否则各写一种拼法就没法按码分支。
152
+ */
153
+ export const SHARE_IMPORT_UNAVAILABLE = "share-import-unavailable";
154
+
155
+ /**
156
+ * 缺省即干跑:没有 confirm 就是预览。脾气照 readReclaimFields 的 confirm(只认真布尔),
157
+ * 但这一面的方向更硬——写的是**收件人的库**,所以唯一的入口就是 confirm,`dryRun` 之类
158
+ * 的第二个旋钮一概不认(reclaim 的 body 形状里就带 dryRun,手熟的人会顺手发来,把它读成
159
+ * 「要写」等于替她点头)。
160
+ */
161
+ function readDryRun(body) {
162
+ return body?.confirm !== true;
163
+ }
164
+
165
+ /**
166
+ * 答复壳里唯一由本层加的一格。service 那一侧收的是 opts.dryRun、不认识 dry_run,对面读的
167
+ * 却是这一格,所以放在本层加:两张皮拿到的键才完全相同。
168
+ *
169
+ * `dryRun !== false` 而不是 `=== true`:认不出的值(字符串、对象、undefined)一律落回**干跑**,
170
+ * 与解析侧同一个失败方向;而传下去的那个布尔值与写进答复的那一格永远同一个数——「其实没写、
171
+ * 却说写了」和「其实写了、却说没写」都是说谎,这一格不许和实参分家。
172
+ */
173
+ function withDryRun(reply, dryRun) {
174
+ return { ...reply, dry_run: dryRun !== false };
175
+ }
176
+
177
+ /**
178
+ * 解析 POST /receive 的 body(已读成文本)→ { pack, dryRun }。
179
+ *
180
+ * 三个码分开是有原因的:invalid-json(发坏了)、invalid-body(顶层就不是对象)、
181
+ * missing-pack(对象里没有包)——对面据此知道改哪一头,而它们全是 400。空 body 是
182
+ * **错**的,与出包侧相反:那边「一个字节都不发」是整库口径,这边压根没东西可写。
183
+ *
184
+ * pack 那一格只判「是不是个对象」,不判包:数组或 `{kind:"nope"}` 都往下交,由闸门整包拒
185
+ * (invalid-kind)。判据只许有一处。
186
+ *
187
+ * @returns {{ok: true, pack: object, dryRun: boolean} | {ok: false, error: string}}
188
+ */
189
+ export function parseReceiveBody(text) {
190
+ if (text === undefined || text === null || String(text).trim() === "") return { ok: false, error: "invalid-body" };
191
+ let body;
192
+ try {
193
+ body = JSON.parse(String(text));
194
+ } catch {
195
+ return { ok: false, error: "invalid-json" };
196
+ }
197
+ if (!body || typeof body !== "object" || Array.isArray(body)) return { ok: false, error: "invalid-body" };
198
+ if (!body.pack || typeof body.pack !== "object") return { ok: false, error: "missing-pack" };
199
+ return { ok: true, pack: body.pack, dryRun: readDryRun(body) };
200
+ }
201
+
202
+ /**
203
+ * 解析 POST /receive/undo 的 body → { packId, dryRun }。顶层形状与「有没有 id」是两个错,
204
+ * 与 receive 侧同一口径(发坏了 / 发错了形状 / 没填)。
205
+ *
206
+ * id 在这里 trim,与 deleteSharePack 首行同一把尺;非字符串与空白一律不进删除那条路——
207
+ * 让空白去 service 那儿换回一个 `pack_id: ""` 的 0 删除,读数上看不出是「没填」还是
208
+ * 「那个包本来就没导入过」,而这两种在出口是完全不同的事。
209
+ *
210
+ * @returns {{ok: true, packId: string, dryRun: boolean} | {ok: false, error: string}}
211
+ */
212
+ export function parseUndoBody(text) {
213
+ if (text === undefined || text === null || String(text).trim() === "") return { ok: false, error: "invalid-body" };
214
+ let body;
215
+ try {
216
+ body = JSON.parse(String(text));
217
+ } catch {
218
+ return { ok: false, error: "invalid-json" };
219
+ }
220
+ if (!body || typeof body !== "object" || Array.isArray(body)) return { ok: false, error: "invalid-body" };
221
+ const packId = typeof body.packId === "string" ? body.packId.trim() : "";
222
+ if (!packId) return { ok: false, error: "missing-pack-id" };
223
+ return { ok: true, packId, dryRun: readDryRun(body) };
224
+ }
225
+
226
+ /**
227
+ * 入库的答复。`pack` 原样交给 service,校验在那儿跑(见本段开头那句「判据只许有一处」)。
228
+ *
229
+ * 抛错在这儿兜住并回 500,不留给调用方的 try:两侧 handler 的形状都是
230
+ * `try { return readBody(...).then(...) } catch`,外层 try 在 .then 的回调里已经退栈,
231
+ * 从这里抛出去就是一个没人接的 rejection(#410)。warn 可选——数据面的 logger 未必接得上,
232
+ * 少一个回调不许把异常漏出去。
233
+ *
234
+ * @param {{service: {importSharePack?: Function}, pack: object, dryRun?: boolean,
235
+ * warn?: ((msg: string) => void)|null}} input
236
+ * @returns {{status: number, body: object}}
237
+ */
238
+ export function receiveReply({ service, pack, dryRun, warn = null }) {
239
+ if (typeof service?.importSharePack !== "function") {
240
+ return { status: 503, body: { error: SHARE_IMPORT_UNAVAILABLE } };
241
+ }
242
+ const dry = dryRun !== false;
243
+ try {
244
+ return { status: 200, body: withDryRun(service.importSharePack(pack, { dryRun: dry }), dry) };
245
+ } catch (error) {
246
+ const code = typeof error?.code === "string" ? error.code : null;
247
+ const status = code === null ? undefined : SHARE_IMPORT_ERRORS[code];
248
+ if (status) {
249
+ // detail 是闸门给的那一格(哪个字段、哪个坏类型),只转发不加工;没有就不造这一格。
250
+ const detail = typeof error.detail === "string" && error.detail ? { detail: error.detail } : {};
251
+ return { status, body: { error: code, ...detail } };
252
+ }
253
+ warnSafely(warn, `[dsh-mneme] share import failed: ${String(error)}`);
254
+ return { status: 500, body: { error: "internal" } };
255
+ }
256
+ }
257
+
258
+ /**
259
+ * 整包退出的答复。这一面**不查** SHARE_IMPORT_ERRORS:packId 的形状闸门在 parseUndoBody,
260
+ * service 那侧不抛带码的错(非字符串/空白它回一个 0 删除,不是异常),所以真抛出来就是
261
+ * 存储故障。别在这儿补第二张表——那张表只会成为 SHARE_IMPORT_ERRORS 的影子。
262
+ *
263
+ * 答复里的 pack_id 是 service 的读数而不是请求的回显(非字符串/空白那一支它回 ""),
264
+ * 本层不改写、不兜底;dry_run 由 withDryRun 加,与入库那侧同一格键。
265
+ *
266
+ * @param {{service: {deleteSharePack?: Function}, packId: string, dryRun?: boolean,
267
+ * warn?: ((msg: string) => void)|null}} input
268
+ * @returns {{status: number, body: object}}
269
+ */
270
+ export function undoReply({ service, packId, dryRun, warn = null }) {
271
+ if (typeof service?.deleteSharePack !== "function") {
272
+ return { status: 503, body: { error: SHARE_IMPORT_UNAVAILABLE } };
273
+ }
274
+ const dry = dryRun !== false;
275
+ try {
276
+ return { status: 200, body: withDryRun(service.deleteSharePack(packId, { dryRun: dry }), dry) };
277
+ } catch (error) {
278
+ warnSafely(warn, `[dsh-mneme] share undo failed: ${String(error)}`);
279
+ return { status: 500, body: { error: "internal" } };
280
+ }
281
+ }