@modusensus/dsh-mneme 0.13.0 → 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.
- package/LICENSE +21 -21
- package/README.md +830 -828
- package/assets/icon.svg +3 -3
- package/bin/cli.mjs +964 -964
- package/bin/dsh-mneme-choro.mjs +262 -254
- package/bin/dsh-mneme-mcp.mjs +510 -510
- package/bin/dsh-mneme-serve.mjs +151 -151
- package/cordis.patch.yml +21 -21
- package/docs/CONFIGURATION.md +407 -402
- package/docs/CONTINUITY.md +139 -139
- package/docs/DAEMON.md +57 -57
- package/docs/DIRECTORIES.md +114 -114
- package/docs/DISTILL.md +397 -371
- package/docs/DSH-GO.md +97 -97
- package/docs/ENTITIES.md +247 -247
- package/docs/FORGET.md +77 -77
- package/docs/KB.md +110 -110
- package/docs/LOCAL_MODEL.md +222 -222
- package/docs/SEMANTIC.md +256 -256
- package/docs/SHARE.md +552 -552
- package/docs/SLEEP.md +202 -202
- package/docs/STORAGE.md +122 -122
- package/docs/WORKFLOWS.md +366 -366
- package/lib/api-standalone.js +1007 -1007
- package/lib/api.js +3600 -3394
- package/lib/attachment-text.js +122 -122
- package/lib/bootstrap-http.js +105 -105
- package/lib/bootstrap.js +215 -215
- package/lib/candidates.js +454 -454
- package/lib/capabilities.js +819 -819
- package/lib/choro-command.js +111 -111
- package/lib/client.js +14420 -13436
- package/lib/commands.js +95 -95
- package/lib/config-keys.js +144 -144
- package/lib/config.js +1361 -1317
- package/lib/content-hash.js +54 -54
- package/lib/continuity.js +258 -258
- package/lib/date-hint.js +32 -0
- package/lib/diary/auto.js +190 -190
- package/lib/diary/compose.js +440 -440
- package/lib/diary/dir.js +59 -59
- package/lib/diary/export.js +97 -97
- package/lib/diary/index.js +26 -26
- package/lib/diary/library.js +189 -189
- package/lib/diary/qq-inbox.js +142 -142
- package/lib/diary/rollover.js +61 -61
- package/lib/diary/session-provider.js +122 -122
- package/lib/document-index.js +94 -94
- package/lib/document.js +322 -322
- package/lib/dream/clustering.js +123 -123
- package/lib/dream/decisions.js +945 -907
- package/lib/dream/narratives.js +44 -44
- package/lib/dream/sleep.js +2027 -1887
- package/lib/dream/triage.js +139 -0
- package/lib/dream.js +1879 -1764
- package/lib/dsh-go/host.js +162 -162
- package/lib/dsh-go/panel.js +2091 -2091
- package/lib/dsh-go/text.js +342 -342
- package/lib/dsh-go/views/common.js +68 -68
- package/lib/dsh-go/views/entity.js +48 -48
- package/lib/dsh-go/views/memory.js +198 -198
- package/lib/dsh-go/views/root.js +30 -30
- package/lib/dsh-go/views/settings.js +398 -398
- package/lib/dsh-go/views/status.js +51 -51
- package/lib/embedding.js +342 -342
- package/lib/entities/extractor.js +285 -285
- package/lib/fence.js +24 -24
- package/lib/graph/anchoring.js +184 -184
- package/lib/guide.js +74 -74
- package/lib/heat.js +144 -144
- package/lib/hot-memory.js +119 -107
- package/lib/image-describe.js +158 -0
- package/lib/index.js +852 -822
- package/lib/inject.js +656 -639
- package/lib/kb/index.js +309 -309
- package/lib/kb/routes.js +219 -219
- package/lib/kb/tools.js +148 -148
- package/lib/lang.js +607 -584
- package/lib/local-embedder.js +358 -358
- package/lib/maintenance.js +162 -162
- package/lib/memory-source.js +9 -9
- package/lib/mirror.js +330 -330
- package/lib/organize.js +456 -456
- package/lib/peak-hours.js +172 -172
- package/lib/pipeline-activities.js +178 -178
- package/lib/pipeline-attribution.js +165 -165
- package/lib/pipeline-command.js +279 -279
- package/lib/pipeline-confirm.js +142 -142
- package/lib/pipeline-exec.js +174 -174
- package/lib/pipeline-nudge-auto.js +129 -129
- package/lib/pipeline-nudge.js +1623 -1623
- package/lib/pipeline-observations.js +181 -181
- package/lib/pipeline-observe.js +133 -133
- package/lib/pipeline-runner.js +361 -361
- package/lib/pipeline-runs.js +442 -442
- package/lib/pipeline.js +716 -716
- package/lib/placement.js +13 -13
- package/lib/pre-inject-gate.js +354 -354
- package/lib/profile-extract.js +164 -164
- package/lib/profile-facts.js +356 -356
- package/lib/provenance-http.js +251 -251
- package/lib/quality-filter.js +162 -162
- package/lib/recall-stats.js +190 -190
- package/lib/reclaim-http.js +150 -150
- package/lib/reranker.js +269 -269
- package/lib/runtime/adopt.js +176 -176
- package/lib/runtime/closure.js +172 -172
- package/lib/runtime/download.js +247 -247
- package/lib/runtime/layout.js +265 -265
- package/lib/runtime/loader.js +252 -252
- package/lib/runtime/model-fetch.js +361 -361
- package/lib/runtime/provision.js +237 -237
- package/lib/runtime/tarball.js +130 -130
- package/lib/runtime/verify.js +223 -223
- package/lib/safe-slice.js +18 -18
- package/lib/scope-state.js +277 -277
- package/lib/scope.js +187 -187
- package/lib/search/adaptive.js +60 -60
- package/lib/search/bm25.js +96 -96
- package/lib/semantic.js +572 -572
- package/lib/sensitive-scan.js +209 -209
- package/lib/serve.js +228 -228
- package/lib/service.js +3268 -3196
- package/lib/session-gate.js +91 -91
- package/lib/session-usage.js +350 -350
- package/lib/settings.js +827 -802
- package/lib/share-http.js +281 -281
- package/lib/share-import.js +234 -234
- package/lib/share.js +335 -335
- package/lib/store.js +5895 -5662
- package/lib/summarize.js +1388 -1343
- package/lib/tools.js +1370 -1356
- package/lib/user-settings.js +230 -230
- package/lib/vector-index.js +180 -180
- package/lib/version-check.js +122 -122
- package/lib/wiki/claims.js +267 -0
- package/lib/wiki/cli-hint.js +90 -90
- package/lib/wiki/inject.js +164 -164
- package/lib/wiki/partition.js +200 -200
- package/lib/wiki/plan.js +214 -214
- package/lib/wiki/queries.js +640 -474
- package/lib/wiki/render.js +261 -187
- package/lib/wiki/scan.js +371 -371
- package/lib/wiki/t0.js +500 -463
- package/lib/wiki/t1-jobs.js +232 -232
- package/lib/wiki/t1.js +609 -502
- package/lib/write-admission.js +404 -404
- package/locale/en.json +6 -6
- package/locale/zh.json +6 -6
- package/package.json +15 -1
- package/runtime-manifest.json +526 -526
- package/scripts/benchmark-embed.js +201 -201
- package/scripts/benchmark-recall.js +249 -249
- package/scripts/benchmark-rerank.js +166 -166
- package/scripts/build-runtime-manifest.mjs +224 -224
- package/scripts/changelog-prep.mjs +91 -91
- package/scripts/check-sync.js +44 -44
- package/scripts/e2e-dsh.js +220 -220
- package/scripts/mneme-runtime.mjs +277 -277
- package/scripts/publish-gate.mjs +197 -197
- package/scripts/release-docs.mjs +210 -204
- package/scripts/release-notes.mjs +164 -161
- package/scripts/stress-dsh.js +255 -255
- package/scripts/sync-lib.js +47 -47
- package/scripts/sync-test-badge.mjs +69 -69
- package/scripts/test-count-sync.mjs +48 -48
- package/src/api-standalone.js +1007 -1007
- package/src/api.js +3600 -3394
- package/src/attachment-text.js +122 -122
- package/src/bootstrap-http.js +105 -105
- package/src/bootstrap.js +215 -215
- package/src/candidates.js +454 -454
- package/src/capabilities.js +819 -819
- package/src/choro-command.js +111 -111
- package/src/commands.js +95 -95
- package/src/config-keys.js +144 -144
- package/src/config.js +1361 -1317
- package/src/content-hash.js +54 -54
- package/src/continuity.js +258 -258
- package/src/date-hint.js +32 -0
- package/src/diary/auto.js +190 -190
- package/src/diary/compose.js +440 -440
- package/src/diary/dir.js +59 -59
- package/src/diary/export.js +97 -97
- package/src/diary/index.js +26 -26
- package/src/diary/library.js +189 -189
- package/src/diary/qq-inbox.js +142 -142
- package/src/diary/rollover.js +61 -61
- package/src/diary/session-provider.js +122 -122
- package/src/document-index.js +94 -94
- package/src/document.js +322 -322
- package/src/dream/clustering.js +123 -123
- package/src/dream/decisions.js +945 -907
- package/src/dream/narratives.js +44 -44
- package/src/dream/sleep.js +2027 -1887
- package/src/dream/triage.js +139 -0
- package/src/dream.js +1879 -1764
- package/src/dsh-go/host.js +162 -162
- package/src/dsh-go/panel.js +2091 -2091
- package/src/dsh-go/text.js +342 -342
- package/src/dsh-go/views/common.js +68 -68
- package/src/dsh-go/views/entity.js +48 -48
- package/src/dsh-go/views/memory.js +198 -198
- package/src/dsh-go/views/root.js +30 -30
- package/src/dsh-go/views/settings.js +398 -398
- package/src/dsh-go/views/status.js +51 -51
- package/src/embedding.js +342 -342
- package/src/entities/extractor.js +285 -285
- package/src/fence.js +24 -24
- package/src/graph/anchoring.js +184 -184
- package/src/guide.js +74 -74
- package/src/heat.js +144 -144
- package/src/hot-memory.js +119 -107
- package/src/image-describe.js +158 -0
- package/src/index.js +852 -822
- package/src/inject.js +656 -639
- package/src/kb/index.js +309 -309
- package/src/kb/routes.js +219 -219
- package/src/kb/tools.js +148 -148
- package/src/lang.js +607 -584
- package/src/local-embedder.js +358 -358
- package/src/maintenance.js +162 -162
- package/src/memory-source.js +9 -9
- package/src/mirror.js +330 -330
- package/src/organize.js +456 -456
- package/src/peak-hours.js +172 -172
- package/src/pipeline-activities.js +178 -178
- package/src/pipeline-attribution.js +165 -165
- package/src/pipeline-command.js +279 -279
- package/src/pipeline-confirm.js +142 -142
- package/src/pipeline-exec.js +174 -174
- package/src/pipeline-nudge-auto.js +129 -129
- package/src/pipeline-nudge.js +1623 -1623
- package/src/pipeline-observations.js +181 -181
- package/src/pipeline-observe.js +133 -133
- package/src/pipeline-runner.js +361 -361
- package/src/pipeline-runs.js +442 -442
- package/src/pipeline.js +716 -716
- package/src/placement.js +13 -13
- package/src/pre-inject-gate.js +354 -354
- package/src/profile-extract.js +164 -164
- package/src/profile-facts.js +356 -356
- package/src/provenance-http.js +251 -251
- package/src/quality-filter.js +162 -162
- package/src/recall-stats.js +190 -190
- package/src/reclaim-http.js +150 -150
- package/src/reranker.js +269 -269
- package/src/runtime/adopt.js +176 -176
- package/src/runtime/closure.js +172 -172
- package/src/runtime/download.js +247 -247
- package/src/runtime/layout.js +265 -265
- package/src/runtime/loader.js +252 -252
- package/src/runtime/model-fetch.js +361 -361
- package/src/runtime/provision.js +237 -237
- package/src/runtime/tarball.js +130 -130
- package/src/runtime/verify.js +223 -223
- package/src/safe-slice.js +18 -18
- package/src/scope-state.js +277 -277
- package/src/scope.js +187 -187
- package/src/search/adaptive.js +60 -60
- package/src/search/bm25.js +96 -96
- package/src/semantic.js +572 -572
- package/src/sensitive-scan.js +209 -209
- package/src/serve.js +228 -228
- package/src/service.js +3268 -3196
- package/src/session-gate.js +91 -91
- package/src/session-usage.js +350 -350
- package/src/settings.js +827 -802
- package/src/share-http.js +281 -281
- package/src/share-import.js +234 -234
- package/src/share.js +335 -335
- package/src/store.js +5895 -5662
- package/src/summarize.js +1388 -1343
- package/src/tools.js +1370 -1356
- package/src/user-settings.js +230 -230
- package/src/vector-index.js +180 -180
- package/src/version-check.js +122 -122
- package/src/wiki/claims.js +267 -0
- package/src/wiki/cli-hint.js +90 -90
- package/src/wiki/inject.js +164 -164
- package/src/wiki/partition.js +200 -200
- package/src/wiki/plan.js +214 -214
- package/src/wiki/queries.js +640 -474
- package/src/wiki/render.js +261 -187
- package/src/wiki/scan.js +371 -371
- package/src/wiki/t0.js +500 -463
- package/src/wiki/t1-jobs.js +232 -232
- package/src/wiki/t1.js +609 -502
- package/src/write-admission.js +404 -404
- package/test/adaptive-inject-budget.test.js +85 -85
- package/test/api-hardening.test.js +173 -173
- package/test/api-nudge-route.test.js +259 -259
- package/test/api-routes-gaps.test.js +1092 -1092
- package/test/api.test.js +3007 -2988
- package/test/attachment-text.test.js +139 -139
- package/test/audit.test.js +448 -448
- package/test/baseline-persist.test.js +248 -248
- package/test/benchmark.test.js +94 -94
- package/test/bm25-corpus-cache.test.js +145 -145
- package/test/bootstrap.test.js +228 -228
- package/test/candidates.test.js +345 -345
- package/test/capabilities.test.js +577 -577
- package/test/capacity-warning.test.js +262 -262
- package/test/changelog-prep.test.js +125 -125
- package/test/choro-command.test.js +218 -218
- package/test/cli-enums.test.js +37 -37
- package/test/cli-flag-value.test.js +86 -86
- package/test/cli-receive.test.js +390 -390
- package/test/cli-share.test.js +437 -437
- package/test/client-share.test.js +225 -225
- package/test/client.test.js +4595 -4184
- package/test/clustering.test.js +100 -100
- package/test/commands.test.js +106 -106
- package/test/config-keys-routes.test.js +233 -233
- package/test/config.test.js +153 -153
- package/test/conflict-freeze.test.js +344 -344
- package/test/conflict-ledger-enforce.test.js +452 -0
- package/test/conflict-ledger.test.js +242 -0
- package/test/conflict-reviewed.test.js +79 -79
- package/test/content-hash.test.js +204 -204
- package/test/continuity.test.js +452 -452
- package/test/contrast.test.js +432 -320
- package/test/date-hint.test.js +156 -0
- package/test/dedupe-candidate-window.test.js +180 -180
- package/test/dependency-overrides.test.js +78 -78
- package/test/diary-library.test.js +187 -187
- package/test/diary.test.js +576 -576
- package/test/differentiate-feedback.test.js +248 -248
- package/test/distill-tx-embed-gap.test.js +110 -110
- package/test/docs-config-keys.test.js +65 -65
- package/test/document-dir.test.js +233 -233
- package/test/document.test.js +703 -703
- package/test/dream-archive-guardrail.test.js +116 -116
- package/test/dream-baseline-clamp.test.js +174 -0
- package/test/dream-candidate-hybrid.test.js +281 -281
- package/test/dream-coverage-degrade.test.js +86 -86
- package/test/dream-decision-evidence.test.js +314 -314
- package/test/dream-failure-backoff.test.js +173 -173
- package/test/dream-fence.test.js +207 -207
- package/test/dream-maxtokens-fallback.test.js +132 -132
- package/test/dream-merge-guardrail.test.js +219 -219
- package/test/dream-peak-hours.test.js +194 -194
- package/test/dream.test.js +1528 -1528
- package/test/dsh-go-host.test.js +134 -134
- package/test/dsh-go-panel-actions.test.js +854 -854
- package/test/dsh-go-panel.test.js +251 -251
- package/test/embed-ready-poll.test.js +94 -94
- package/test/embed-text-reasons.test.js +112 -112
- package/test/embedding-cache-f32.test.js +276 -276
- package/test/embedding-ready.test.js +226 -226
- package/test/entities.test.js +711 -711
- package/test/entity-recall.test.js +179 -179
- package/test/epistemic.test.js +325 -325
- package/test/failure-query.test.js +147 -147
- package/test/failure-retention.test.js +105 -105
- package/test/fnew-0112.test.js +311 -311
- package/test/fnew-03.test.js +422 -422
- package/test/forget-corrections.test.js +70 -70
- package/test/graph-anchoring.test.js +184 -184
- package/test/graph-api.test.js +333 -209
- package/test/graph-boosted-relations.test.js +189 -189
- package/test/graph-inject-budget.test.js +103 -103
- package/test/graph-multipath.test.js +269 -269
- package/test/graph-passive-confirm.test.js +91 -91
- package/test/graph-weight-evolution.test.js +104 -104
- package/test/heat.test.js +175 -175
- package/test/helpers/dream-mock.js +86 -86
- package/test/helpers/peer-worker.mjs +25 -25
- package/test/helpers/runtime-source.js +60 -60
- package/test/helpers/tar-builder.js +80 -80
- package/test/helpers/write-admission-samples.js +312 -312
- package/test/hot-memory.test.js +259 -211
- package/test/image-description.test.js +271 -0
- package/test/image-memory.test.js +170 -170
- package/test/inject-content-cap.test.js +91 -91
- package/test/inject-first-round-bm25.test.js +89 -89
- package/test/inject-heat.test.js +77 -77
- package/test/inject-parent-gate.test.js +134 -106
- package/test/inject-pin-explicit.test.js +300 -300
- package/test/inject-pin-vector-crowd.test.js +225 -225
- package/test/inject-pools.test.js +195 -195
- package/test/inject-recall.test.js +172 -172
- package/test/inject-rotation.test.js +161 -161
- package/test/inject.test.js +553 -494
- package/test/issue-617-step1-query-and-fusion.test.js +361 -361
- package/test/kb-api-wiring.test.js +128 -128
- package/test/kb-collections.test.js +272 -272
- package/test/kb-routes.test.js +379 -379
- package/test/lang.test.js +98 -98
- package/test/lastrunat-persist.test.js +101 -101
- package/test/lib-smoke.test.js +116 -116
- package/test/llm-audit.test.js +815 -815
- package/test/llm-message-source.test.js +207 -207
- package/test/local-embedder.test.js +292 -292
- package/test/maintenance.test.js +501 -501
- package/test/mcp-stdio.test.js +385 -385
- package/test/mint-source.test.js +311 -311
- package/test/mirror-dirty.test.js +424 -424
- package/test/mirror-edit-digest.test.js +187 -187
- package/test/mirror-generation.test.js +499 -499
- package/test/mirror-types.test.js +208 -208
- package/test/mirror.test.js +249 -249
- package/test/narrative-bars.test.js +162 -162
- package/test/organize-tool.test.js +232 -232
- package/test/organize.test.js +418 -418
- package/test/panel-chart-scale.test.js +90 -0
- package/test/panel-tokens.test.js +245 -0
- package/test/peak-hours-observability.test.js +70 -70
- package/test/peer-blockers.test.js +193 -193
- package/test/persona-addressing.test.js +83 -83
- package/test/persona-api.test.js +172 -172
- package/test/persona-by-session.test.js +568 -568
- package/test/persona-flag.test.js +36 -36
- package/test/persona-inject.test.js +145 -145
- package/test/persona-settings.test.js +198 -198
- package/test/pipeline-activities.test.js +155 -155
- package/test/pipeline-attribution.test.js +175 -175
- package/test/pipeline-command.test.js +243 -243
- package/test/pipeline-confirm.test.js +148 -148
- package/test/pipeline-exec.test.js +172 -172
- package/test/pipeline-nudge-auto.test.js +248 -248
- package/test/pipeline-nudge.test.js +1278 -1278
- package/test/pipeline-observations.test.js +157 -157
- package/test/pipeline-observe.test.js +127 -127
- package/test/pipeline-r1r2.test.js +278 -278
- package/test/pipeline-runner.test.js +468 -468
- package/test/pipeline-runs.test.js +767 -767
- package/test/pipeline.test.js +636 -636
- package/test/placement.test.js +36 -36
- package/test/policy-epoch.test.js +259 -259
- package/test/pre-inject-gate.test.js +444 -444
- package/test/profile-extract.test.js +269 -269
- package/test/profile-facts.test.js +492 -492
- package/test/prompt-stance.test.js +128 -128
- package/test/provenance-http.test.js +367 -367
- package/test/publish-gate.test.js +272 -272
- package/test/quality-backfill.test.js +290 -290
- package/test/quality-filter.test.js +295 -295
- package/test/readme-claims.test.js +113 -113
- package/test/reasoning-effort.test.js +752 -752
- package/test/recall-anti-update.test.js +82 -82
- package/test/recall-evals.test.js +253 -253
- package/test/recall-layer.test.js +326 -326
- package/test/recall-retention.test.js +128 -128
- package/test/recall-stats.test.js +274 -274
- package/test/receipt-chain.test.js +451 -451
- package/test/reclaim-http.test.js +209 -209
- package/test/reflection-update-gate.test.js +129 -129
- package/test/reflection.test.js +226 -226
- package/test/reindex-backfill.test.js +475 -475
- package/test/reindex-scheduler.test.js +369 -369
- package/test/release-docs.test.js +156 -136
- package/test/release-notes.test.js +265 -240
- package/test/release-workflow.test.js +93 -93
- package/test/reranker-single-logit.test.js +73 -73
- package/test/reranker.test.js +197 -197
- package/test/resident-status.test.js +83 -83
- package/test/route-policy.test.js +113 -113
- package/test/runtime-adopt.test.js +206 -206
- package/test/runtime-cli.test.js +89 -89
- package/test/runtime-closure.test.js +193 -193
- package/test/runtime-download.test.js +302 -302
- package/test/runtime-layout.test.js +163 -163
- package/test/runtime-loader.test.js +255 -255
- package/test/runtime-manifest.test.js +159 -159
- package/test/runtime-model-fetch.test.js +348 -348
- package/test/runtime-provision.test.js +101 -101
- package/test/runtime-tarball.test.js +81 -81
- package/test/runtime-verify.test.js +319 -319
- package/test/scope-candidates.test.js +491 -491
- package/test/scope-distill-stamp.test.js +134 -134
- package/test/scope-explicit.test.js +452 -452
- package/test/scope-inject-soft.test.js +106 -106
- package/test/scope-optional-service.test.js +110 -110
- package/test/scope-retrieval.test.js +197 -197
- package/test/scope-state.test.js +610 -610
- package/test/scope-storage.test.js +255 -255
- package/test/scope-strict.test.js +367 -367
- package/test/search-fusion.test.js +90 -90
- package/test/security-doc.test.js +188 -178
- package/test/semantic.test.js +124 -124
- package/test/sensitive-scan.test.js +251 -251
- package/test/serve-bin.test.js +121 -121
- package/test/serve.test.js +258 -258
- package/test/service-search.test.js +174 -174
- package/test/service.test.js +410 -410
- package/test/session-gate.test.js +264 -264
- package/test/session-usage.test.js +317 -317
- package/test/settings.test.js +273 -273
- package/test/share-foreign-rows.test.js +144 -144
- package/test/share-http.test.js +144 -144
- package/test/share-import.test.js +577 -577
- package/test/share-imported-guard.test.js +311 -311
- package/test/share-imported-identity.test.js +111 -111
- package/test/share-pack.test.js +511 -511
- package/test/share-receive-http.test.js +756 -756
- package/test/share-routes.test.js +337 -337
- package/test/share-store.test.js +133 -133
- package/test/share-validate.test.js +101 -101
- package/test/skip-invalid-restore.test.js +262 -262
- package/test/sleep-action-set.test.js +441 -441
- package/test/sleep-catchup.test.js +315 -315
- package/test/sleep-failure-backoff.test.js +156 -156
- package/test/sleep-heat.test.js +174 -174
- package/test/sleep-scheduler-rearm.test.js +89 -89
- package/test/sleep.test.js +1455 -1418
- package/test/standalone-api.test.js +1344 -1344
- package/test/store-vector-cache.test.js +98 -98
- package/test/store-write-path-columns.test.js +191 -191
- package/test/store.test.js +744 -744
- package/test/stress.test.js +209 -209
- package/test/summarize-occurred-at.test.js +127 -127
- package/test/summarize-parse-diagnostics.test.js +75 -75
- package/test/summarize-reasoning-effort.test.js +189 -189
- package/test/summarize.test.js +2251 -2251
- package/test/supersede-state-tracking.test.js +394 -394
- package/test/test-count-sync.test.js +71 -71
- package/test/tool-state-ignore.test.js +65 -65
- package/test/tools-dto-schema-matrix.test.js +398 -398
- package/test/tools-memory-get-schema.test.js +65 -65
- package/test/tools.test.js +585 -585
- package/test/updated-at-semantics.test.js +113 -113
- package/test/user-settings-preview.test.js +127 -127
- package/test/user-settings-segments.test.js +527 -527
- package/test/vector-index.test.js +334 -334
- package/test/version-check.test.js +152 -152
- package/test/webServer-optional.test.js +82 -82
- package/test/wiki-api.test.js +734 -627
- package/test/wiki-claims.test.js +194 -0
- package/test/wiki-cli-hint.test.js +118 -118
- package/test/wiki-inject.test.js +265 -265
- package/test/wiki-partition.test.js +112 -112
- package/test/wiki-plan.test.js +80 -80
- package/test/wiki-provenance.test.js +202 -0
- package/test/wiki-queries.test.js +398 -277
- package/test/wiki-scan.test.js +208 -208
- package/test/wiki-store.test.js +190 -190
- package/test/wiki-t0.test.js +456 -380
- package/test/wiki-t1-jobs.test.js +125 -125
- package/test/wiki-t1.test.js +460 -235
- package/test/wiki-tools.test.js +176 -176
- package/test/workflow-guards.test.js +155 -155
- package/test/write-admission.test.js +668 -668
package/lib/date-hint.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 记忆条目上「模型可见」的日期标注。
|
|
3
|
+
*
|
|
4
|
+
* 背景:注入行与工具回执原来只给 updated_at(memory_get 连 updated_at 都不给),
|
|
5
|
+
* 而模型回答「这条多旧了 / 还作不作数」唯一能用的就是时间。updated_at 又不是年龄
|
|
6
|
+
* ——巩固(dream)合并时会把败者正文加注记并归档、顺带刷新 updated_at,全库
|
|
7
|
+
* updated_at > created_at 的行里真漂移(≥1 天)有 656 行,最长 51 天。所以年龄
|
|
8
|
+
* 必须看 created_at,事件时间有 occurred_at 时优先用它。
|
|
9
|
+
*
|
|
10
|
+
* 为什么只给日期不给时间:模型要判的是「多旧」,秒级精度没有信息量,每行却要多耗
|
|
11
|
+
* 8 个字符的注入预算(MAX_BLOCK 只有 maxContent + 600)。跨年场景 YYYY-MM-DD 本身
|
|
12
|
+
* 就覆盖了。
|
|
13
|
+
*
|
|
14
|
+
* 为什么按 UTC 切而不是宿主本地时区:created_at / occurred_at 落库都是 UTC ISO 串
|
|
15
|
+
* (store 侧 Date.toISOString())。按本地时区格式化会让同一份库在两台机器上渲染出
|
|
16
|
+
* 不同的注入文本,测试也没法钉死。最坏情况是 UTC 16:00 之后的事件被标成前一天,
|
|
17
|
+
* 对「多旧」这个用途无影响,确定性优先。
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** ISO 时间串 → `YYYY-MM-DD`;空值或形状不对返回 ""(调用方据此跳过,不渲染占位符)。 */
|
|
21
|
+
export function hintDate(iso) {
|
|
22
|
+
const s = String(iso ?? "");
|
|
23
|
+
return /^\d{4}-\d{2}-\d{2}/.test(s) ? s.slice(0, 10) : "";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 条目日期:事件发生时间优先(occurred_at 是「这件事什么时候发生的」),缺省回落到
|
|
28
|
+
* 落库时间 created_at(必填列,永远有值)。
|
|
29
|
+
*/
|
|
30
|
+
export function memoryDate(m) {
|
|
31
|
+
return hintDate(m?.occurred_at) || hintDate(m?.created_at);
|
|
32
|
+
}
|
package/lib/diary/auto.js
CHANGED
|
@@ -1,190 +1,190 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 日记的**触发侧**:让「跨天了该写一篇」变成自动发生,而不是等人想起来点按钮。
|
|
3
|
-
*
|
|
4
|
-
* 为什么单独一个文件:compose.js 是纯逻辑(采集/生成/落盘),触发时机、去重、
|
|
5
|
-
* 错误兜底是**宿主接线**问题。混在一起会让那层不再能被测试直接驱动。
|
|
6
|
-
*
|
|
7
|
-
* 三条执行侧边界(与 pipeline-nudge-auto.js 同一套口径):
|
|
8
|
-
* - **不 cron,但可选定时唤醒**:判定发生在三处——turn/end、插件启动、以及
|
|
9
|
-
* diaryWriteEveryMinutes > 0 时的定时器。定时器只负责「醒来问一句今天写了没」,
|
|
10
|
-
* 写不写仍由 compose 按落盘日期去重,所以一天最多一篇;缺省 0 = 关,只有前两处
|
|
11
|
-
* (=此前行为,整日不说话就不写);
|
|
12
|
-
* - **一次只补一篇**:睡得久一点回来了也就补一篇,不许醒来一次补十篇烧配额;
|
|
13
|
-
* - **失败不冒泡**:session/event 那条链上还挂着摘要与续期,日记写砸了只能 warn。
|
|
14
|
-
*/
|
|
15
|
-
import { projectRootOf } from "../pipeline-runner.js";
|
|
16
|
-
import { localDateString } from "./rollover.js";
|
|
17
|
-
import { sessionAgentId } from "./session-provider.js";
|
|
18
|
-
|
|
19
|
-
/** 同一项目两次判定的最短间隔:turn/end 密度很高,而一天只需写一篇。 */
|
|
20
|
-
export const DIARY_MIN_INTERVAL_MS = 60 * 1000;
|
|
21
|
-
|
|
22
|
-
export function createDiaryAutoRun({
|
|
23
|
-
ctx = null,
|
|
24
|
-
composer = null,
|
|
25
|
-
logger = null,
|
|
26
|
-
sessionGate = null,
|
|
27
|
-
now = () => Date.now(),
|
|
28
|
-
minIntervalMs = DIARY_MIN_INTERVAL_MS,
|
|
29
|
-
everyMs = 0,
|
|
30
|
-
listProjects = null
|
|
31
|
-
} = {}) {
|
|
32
|
-
const log = logger || (ctx && ctx.logger) || null;
|
|
33
|
-
let disposed = false;
|
|
34
|
-
let timer = null;
|
|
35
|
-
/** 定时写的钟。与 timer(setTimeout(0) 的派发器)是两回事:那个只把待判项目挪到下一帧。 */
|
|
36
|
-
let ticker = null;
|
|
37
|
-
/** 每个项目最近一次判定时刻。注意是「判定」不是「写过」——写过与否在 compose 里按落盘判断。 */
|
|
38
|
-
const checkedAt = new Map();
|
|
39
|
-
/**
|
|
40
|
-
* 待判项目 → { session, trigger }。带会话是因为素材主来源就是它(见 compose 的
|
|
41
|
-
* session 参数);带 trigger 是因为重扫要如实记账「这篇是谁叫醒的」。
|
|
42
|
-
*/
|
|
43
|
-
const pending = new Map();
|
|
44
|
-
|
|
45
|
-
const normalize = (p) => {
|
|
46
|
-
let s = String(p).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
47
|
-
if (/^[a-zA-Z]:\//.test(s)) s = s.toLowerCase();
|
|
48
|
-
return s;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const runOne = (projectRoot, trigger, session = null) => {
|
|
52
|
-
pending.delete(projectRoot);
|
|
53
|
-
if (disposed || !composer) return null;
|
|
54
|
-
checkedAt.set(normalize(projectRoot), now());
|
|
55
|
-
// session 与 agentId 一起传:素材取会话转录,声音取这个会话的人格卡。
|
|
56
|
-
// 两者必须来自同一个会话,否则会写出「A 的人格 + B 的素材」那种缝合怪。
|
|
57
|
-
const task = composer.compose({ trigger, projectRoot, session, agentId: sessionAgentId(session) });
|
|
58
|
-
// compose 是异步的(要等模型),绝不能返回给 session/event 的派发方去 await——
|
|
59
|
-
// 那会把回合收尾吊在模型延迟上(本机实测 p90 五十秒级)。
|
|
60
|
-
return Promise.resolve(task).catch((error) => {
|
|
61
|
-
log?.warn?.("[dsh-mneme] diary compose failed (" + projectRoot + "): " + String((error && error.message) || error));
|
|
62
|
-
return null;
|
|
63
|
-
});
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const flush = () => {
|
|
67
|
-
timer = null;
|
|
68
|
-
if (disposed) return;
|
|
69
|
-
const first = pending.entries().next();
|
|
70
|
-
if (first.done) return;
|
|
71
|
-
const [projectRoot, queued] = first.value;
|
|
72
|
-
runOne(projectRoot, queued.trigger, queued.session);
|
|
73
|
-
if (pending.size > 0 && !disposed) defer();
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const defer = () => {
|
|
77
|
-
if (disposed || timer) return;
|
|
78
|
-
// 当前这一帧是宿主的 turn/end 处理链。setTimeout(0) 挪到下一个宏任务,
|
|
79
|
-
// 宿主先收尾;unref 让退出不被这根定时器吊住。
|
|
80
|
-
timer = setTimeout(flush, 0);
|
|
81
|
-
if (typeof timer.unref === "function") timer.unref();
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
const schedule = (projectRoot, session = null, trigger = "rollover") => {
|
|
85
|
-
const key = normalize(projectRoot);
|
|
86
|
-
const last = checkedAt.get(key);
|
|
87
|
-
if (last !== undefined && now() - last < minIntervalMs) return;
|
|
88
|
-
if (pending.has(projectRoot)) return;
|
|
89
|
-
pending.set(projectRoot, { session, trigger });
|
|
90
|
-
defer();
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const onSessionEvent = (session, event) => {
|
|
94
|
-
if (disposed) return;
|
|
95
|
-
if (sessionGate?.isOff(session)) return;
|
|
96
|
-
if (!event || event.type !== "turn/end") return;
|
|
97
|
-
const projectRoot = projectRootOf(session);
|
|
98
|
-
if (!projectRoot) return;
|
|
99
|
-
schedule(projectRoot, session);
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const unsubscribe = ctx && typeof ctx.on === "function" ? ctx.on("session/event", onSessionEvent) : null;
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* 定时写:每隔 everyMs 醒来问一次「今天写了没」。
|
|
106
|
-
*
|
|
107
|
-
* 为什么需要它:原来的判定全挂在 turn/end 上,等于「你不说话它就不写」。桉桉
|
|
108
|
-
* 2026-11-09 说的「日记本按理来说应该需要定时写」就是这件事。唤醒后走的是同一条
|
|
109
|
-
* schedule → compose 路径,去重仍在 compose 里按落盘日期做,所以:
|
|
110
|
-
* - 一天最多一篇(跟手点「写一篇」共用那个去重);
|
|
111
|
-
* - 失败只 warn,不打断宿主(session/event 那条链上还挂着摘要与续期);
|
|
112
|
-
* - 醒来时不知道该扫哪个项目就什么都不做——宁可漏一次,不猜别人的项目根。
|
|
113
|
-
*
|
|
114
|
-
* 不用 setInterval 的理由:写完一篇要等模型(本机 p90 五十秒级),固定节拍会在
|
|
115
|
-
* 慢的那次之后立刻再来一次。这里改成「跑完再排下一次」,天然不重叠。
|
|
116
|
-
*/
|
|
117
|
-
const tick = async () => {
|
|
118
|
-
if (disposed) return;
|
|
119
|
-
ticker = null;
|
|
120
|
-
if (!composer || everyMs <= 0) return;
|
|
121
|
-
try {
|
|
122
|
-
const projects = typeof listProjects === "function" ? listProjects() : [];
|
|
123
|
-
const list = Array.isArray(projects) ? projects.filter(Boolean) : [];
|
|
124
|
-
for (const projectRoot of list) {
|
|
125
|
-
if (disposed) break;
|
|
126
|
-
// 同一个项目由 turn/end 刚判过就不必再判(minIntervalMs 已经在 schedule 里
|
|
127
|
-
// 拦了一道,这里只是省掉一次 map 写入)。
|
|
128
|
-
schedule(projectRoot, null, "timer");
|
|
129
|
-
}
|
|
130
|
-
} catch (error) {
|
|
131
|
-
log?.warn?.("[dsh-mneme] diary timer scan failed: " + String((error && error.message) || error));
|
|
132
|
-
}
|
|
133
|
-
arm();
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
const arm = () => {
|
|
137
|
-
if (disposed || everyMs <= 0 || ticker) return;
|
|
138
|
-
ticker = setTimeout(() => {
|
|
139
|
-
Promise.resolve(tick()).catch((error) => {
|
|
140
|
-
log?.warn?.("[dsh-mneme] diary timer tick failed: " + String((error && error.message) || error));
|
|
141
|
-
});
|
|
142
|
-
}, everyMs);
|
|
143
|
-
// unref:不因为一根日记的钟让宿主退不出去。
|
|
144
|
-
if (typeof ticker.unref === "function") ticker.unref();
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
// 只有明确配了间隔才起钟。缺省 0 = 完全不起,行为与 v0.13 之前一致。
|
|
148
|
-
arm();
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* 启动补写:只补上次关宿主那段时间留下的那一篇。
|
|
152
|
-
*
|
|
153
|
-
* 为什么是启动而不是「每隔几小时」:宿主退出期间没有任何东西在跑,唯一能知道
|
|
154
|
-
* 「昨天没写」的时刻就是下次启动或下次说话。两处都判,效果对用户是一样的。
|
|
155
|
-
* 不知道该补哪个项目(启动时没有会话)→ 什么都不做,等第一次 turn/end。
|
|
156
|
-
*/
|
|
157
|
-
const catchUp = (projects = []) => {
|
|
158
|
-
if (disposed || !composer) return Promise.resolve([]);
|
|
159
|
-
const list = Array.isArray(projects) ? projects.filter(Boolean) : [];
|
|
160
|
-
return Promise.all(
|
|
161
|
-
list.map((projectRoot) =>
|
|
162
|
-
Promise.resolve(composer.compose({ trigger: "startup", projectRoot })).catch((error) => {
|
|
163
|
-
log?.warn?.("[dsh-mneme] diary startup catch-up failed (" + projectRoot + "): " + String((error && error.message) || error));
|
|
164
|
-
return null;
|
|
165
|
-
})
|
|
166
|
-
)
|
|
167
|
-
);
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
const dispose = () => {
|
|
171
|
-
disposed = true;
|
|
172
|
-
pending.clear();
|
|
173
|
-
if (timer) {
|
|
174
|
-
clearTimeout(timer);
|
|
175
|
-
timer = null;
|
|
176
|
-
}
|
|
177
|
-
if (ticker) {
|
|
178
|
-
clearTimeout(ticker);
|
|
179
|
-
ticker = null;
|
|
180
|
-
}
|
|
181
|
-
if (typeof unsubscribe === "function") unsubscribe();
|
|
182
|
-
};
|
|
183
|
-
dispose.runNow = (projectRoot, trigger = "manual", session = null) => (disposed || !projectRoot ? null : runOne(projectRoot, trigger, session));
|
|
184
|
-
dispose.pendingCount = () => pending.size;
|
|
185
|
-
dispose.timerArmed = () => ticker !== null;
|
|
186
|
-
dispose.tickNow = () => (disposed ? Promise.resolve() : Promise.resolve(tick()));
|
|
187
|
-
dispose.catchUp = catchUp;
|
|
188
|
-
dispose.today = () => localDateString(new Date(now()));
|
|
189
|
-
return dispose;
|
|
190
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* 日记的**触发侧**:让「跨天了该写一篇」变成自动发生,而不是等人想起来点按钮。
|
|
3
|
+
*
|
|
4
|
+
* 为什么单独一个文件:compose.js 是纯逻辑(采集/生成/落盘),触发时机、去重、
|
|
5
|
+
* 错误兜底是**宿主接线**问题。混在一起会让那层不再能被测试直接驱动。
|
|
6
|
+
*
|
|
7
|
+
* 三条执行侧边界(与 pipeline-nudge-auto.js 同一套口径):
|
|
8
|
+
* - **不 cron,但可选定时唤醒**:判定发生在三处——turn/end、插件启动、以及
|
|
9
|
+
* diaryWriteEveryMinutes > 0 时的定时器。定时器只负责「醒来问一句今天写了没」,
|
|
10
|
+
* 写不写仍由 compose 按落盘日期去重,所以一天最多一篇;缺省 0 = 关,只有前两处
|
|
11
|
+
* (=此前行为,整日不说话就不写);
|
|
12
|
+
* - **一次只补一篇**:睡得久一点回来了也就补一篇,不许醒来一次补十篇烧配额;
|
|
13
|
+
* - **失败不冒泡**:session/event 那条链上还挂着摘要与续期,日记写砸了只能 warn。
|
|
14
|
+
*/
|
|
15
|
+
import { projectRootOf } from "../pipeline-runner.js";
|
|
16
|
+
import { localDateString } from "./rollover.js";
|
|
17
|
+
import { sessionAgentId } from "./session-provider.js";
|
|
18
|
+
|
|
19
|
+
/** 同一项目两次判定的最短间隔:turn/end 密度很高,而一天只需写一篇。 */
|
|
20
|
+
export const DIARY_MIN_INTERVAL_MS = 60 * 1000;
|
|
21
|
+
|
|
22
|
+
export function createDiaryAutoRun({
|
|
23
|
+
ctx = null,
|
|
24
|
+
composer = null,
|
|
25
|
+
logger = null,
|
|
26
|
+
sessionGate = null,
|
|
27
|
+
now = () => Date.now(),
|
|
28
|
+
minIntervalMs = DIARY_MIN_INTERVAL_MS,
|
|
29
|
+
everyMs = 0,
|
|
30
|
+
listProjects = null
|
|
31
|
+
} = {}) {
|
|
32
|
+
const log = logger || (ctx && ctx.logger) || null;
|
|
33
|
+
let disposed = false;
|
|
34
|
+
let timer = null;
|
|
35
|
+
/** 定时写的钟。与 timer(setTimeout(0) 的派发器)是两回事:那个只把待判项目挪到下一帧。 */
|
|
36
|
+
let ticker = null;
|
|
37
|
+
/** 每个项目最近一次判定时刻。注意是「判定」不是「写过」——写过与否在 compose 里按落盘判断。 */
|
|
38
|
+
const checkedAt = new Map();
|
|
39
|
+
/**
|
|
40
|
+
* 待判项目 → { session, trigger }。带会话是因为素材主来源就是它(见 compose 的
|
|
41
|
+
* session 参数);带 trigger 是因为重扫要如实记账「这篇是谁叫醒的」。
|
|
42
|
+
*/
|
|
43
|
+
const pending = new Map();
|
|
44
|
+
|
|
45
|
+
const normalize = (p) => {
|
|
46
|
+
let s = String(p).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
47
|
+
if (/^[a-zA-Z]:\//.test(s)) s = s.toLowerCase();
|
|
48
|
+
return s;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const runOne = (projectRoot, trigger, session = null) => {
|
|
52
|
+
pending.delete(projectRoot);
|
|
53
|
+
if (disposed || !composer) return null;
|
|
54
|
+
checkedAt.set(normalize(projectRoot), now());
|
|
55
|
+
// session 与 agentId 一起传:素材取会话转录,声音取这个会话的人格卡。
|
|
56
|
+
// 两者必须来自同一个会话,否则会写出「A 的人格 + B 的素材」那种缝合怪。
|
|
57
|
+
const task = composer.compose({ trigger, projectRoot, session, agentId: sessionAgentId(session) });
|
|
58
|
+
// compose 是异步的(要等模型),绝不能返回给 session/event 的派发方去 await——
|
|
59
|
+
// 那会把回合收尾吊在模型延迟上(本机实测 p90 五十秒级)。
|
|
60
|
+
return Promise.resolve(task).catch((error) => {
|
|
61
|
+
log?.warn?.("[dsh-mneme] diary compose failed (" + projectRoot + "): " + String((error && error.message) || error));
|
|
62
|
+
return null;
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const flush = () => {
|
|
67
|
+
timer = null;
|
|
68
|
+
if (disposed) return;
|
|
69
|
+
const first = pending.entries().next();
|
|
70
|
+
if (first.done) return;
|
|
71
|
+
const [projectRoot, queued] = first.value;
|
|
72
|
+
runOne(projectRoot, queued.trigger, queued.session);
|
|
73
|
+
if (pending.size > 0 && !disposed) defer();
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const defer = () => {
|
|
77
|
+
if (disposed || timer) return;
|
|
78
|
+
// 当前这一帧是宿主的 turn/end 处理链。setTimeout(0) 挪到下一个宏任务,
|
|
79
|
+
// 宿主先收尾;unref 让退出不被这根定时器吊住。
|
|
80
|
+
timer = setTimeout(flush, 0);
|
|
81
|
+
if (typeof timer.unref === "function") timer.unref();
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const schedule = (projectRoot, session = null, trigger = "rollover") => {
|
|
85
|
+
const key = normalize(projectRoot);
|
|
86
|
+
const last = checkedAt.get(key);
|
|
87
|
+
if (last !== undefined && now() - last < minIntervalMs) return;
|
|
88
|
+
if (pending.has(projectRoot)) return;
|
|
89
|
+
pending.set(projectRoot, { session, trigger });
|
|
90
|
+
defer();
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const onSessionEvent = (session, event) => {
|
|
94
|
+
if (disposed) return;
|
|
95
|
+
if (sessionGate?.isOff(session)) return;
|
|
96
|
+
if (!event || event.type !== "turn/end") return;
|
|
97
|
+
const projectRoot = projectRootOf(session);
|
|
98
|
+
if (!projectRoot) return;
|
|
99
|
+
schedule(projectRoot, session);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const unsubscribe = ctx && typeof ctx.on === "function" ? ctx.on("session/event", onSessionEvent) : null;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 定时写:每隔 everyMs 醒来问一次「今天写了没」。
|
|
106
|
+
*
|
|
107
|
+
* 为什么需要它:原来的判定全挂在 turn/end 上,等于「你不说话它就不写」。桉桉
|
|
108
|
+
* 2026-11-09 说的「日记本按理来说应该需要定时写」就是这件事。唤醒后走的是同一条
|
|
109
|
+
* schedule → compose 路径,去重仍在 compose 里按落盘日期做,所以:
|
|
110
|
+
* - 一天最多一篇(跟手点「写一篇」共用那个去重);
|
|
111
|
+
* - 失败只 warn,不打断宿主(session/event 那条链上还挂着摘要与续期);
|
|
112
|
+
* - 醒来时不知道该扫哪个项目就什么都不做——宁可漏一次,不猜别人的项目根。
|
|
113
|
+
*
|
|
114
|
+
* 不用 setInterval 的理由:写完一篇要等模型(本机 p90 五十秒级),固定节拍会在
|
|
115
|
+
* 慢的那次之后立刻再来一次。这里改成「跑完再排下一次」,天然不重叠。
|
|
116
|
+
*/
|
|
117
|
+
const tick = async () => {
|
|
118
|
+
if (disposed) return;
|
|
119
|
+
ticker = null;
|
|
120
|
+
if (!composer || everyMs <= 0) return;
|
|
121
|
+
try {
|
|
122
|
+
const projects = typeof listProjects === "function" ? listProjects() : [];
|
|
123
|
+
const list = Array.isArray(projects) ? projects.filter(Boolean) : [];
|
|
124
|
+
for (const projectRoot of list) {
|
|
125
|
+
if (disposed) break;
|
|
126
|
+
// 同一个项目由 turn/end 刚判过就不必再判(minIntervalMs 已经在 schedule 里
|
|
127
|
+
// 拦了一道,这里只是省掉一次 map 写入)。
|
|
128
|
+
schedule(projectRoot, null, "timer");
|
|
129
|
+
}
|
|
130
|
+
} catch (error) {
|
|
131
|
+
log?.warn?.("[dsh-mneme] diary timer scan failed: " + String((error && error.message) || error));
|
|
132
|
+
}
|
|
133
|
+
arm();
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const arm = () => {
|
|
137
|
+
if (disposed || everyMs <= 0 || ticker) return;
|
|
138
|
+
ticker = setTimeout(() => {
|
|
139
|
+
Promise.resolve(tick()).catch((error) => {
|
|
140
|
+
log?.warn?.("[dsh-mneme] diary timer tick failed: " + String((error && error.message) || error));
|
|
141
|
+
});
|
|
142
|
+
}, everyMs);
|
|
143
|
+
// unref:不因为一根日记的钟让宿主退不出去。
|
|
144
|
+
if (typeof ticker.unref === "function") ticker.unref();
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// 只有明确配了间隔才起钟。缺省 0 = 完全不起,行为与 v0.13 之前一致。
|
|
148
|
+
arm();
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* 启动补写:只补上次关宿主那段时间留下的那一篇。
|
|
152
|
+
*
|
|
153
|
+
* 为什么是启动而不是「每隔几小时」:宿主退出期间没有任何东西在跑,唯一能知道
|
|
154
|
+
* 「昨天没写」的时刻就是下次启动或下次说话。两处都判,效果对用户是一样的。
|
|
155
|
+
* 不知道该补哪个项目(启动时没有会话)→ 什么都不做,等第一次 turn/end。
|
|
156
|
+
*/
|
|
157
|
+
const catchUp = (projects = []) => {
|
|
158
|
+
if (disposed || !composer) return Promise.resolve([]);
|
|
159
|
+
const list = Array.isArray(projects) ? projects.filter(Boolean) : [];
|
|
160
|
+
return Promise.all(
|
|
161
|
+
list.map((projectRoot) =>
|
|
162
|
+
Promise.resolve(composer.compose({ trigger: "startup", projectRoot })).catch((error) => {
|
|
163
|
+
log?.warn?.("[dsh-mneme] diary startup catch-up failed (" + projectRoot + "): " + String((error && error.message) || error));
|
|
164
|
+
return null;
|
|
165
|
+
})
|
|
166
|
+
)
|
|
167
|
+
);
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const dispose = () => {
|
|
171
|
+
disposed = true;
|
|
172
|
+
pending.clear();
|
|
173
|
+
if (timer) {
|
|
174
|
+
clearTimeout(timer);
|
|
175
|
+
timer = null;
|
|
176
|
+
}
|
|
177
|
+
if (ticker) {
|
|
178
|
+
clearTimeout(ticker);
|
|
179
|
+
ticker = null;
|
|
180
|
+
}
|
|
181
|
+
if (typeof unsubscribe === "function") unsubscribe();
|
|
182
|
+
};
|
|
183
|
+
dispose.runNow = (projectRoot, trigger = "manual", session = null) => (disposed || !projectRoot ? null : runOne(projectRoot, trigger, session));
|
|
184
|
+
dispose.pendingCount = () => pending.size;
|
|
185
|
+
dispose.timerArmed = () => ticker !== null;
|
|
186
|
+
dispose.tickNow = () => (disposed ? Promise.resolve() : Promise.resolve(tick()));
|
|
187
|
+
dispose.catchUp = catchUp;
|
|
188
|
+
dispose.today = () => localDateString(new Date(now()));
|
|
189
|
+
return dispose;
|
|
190
|
+
}
|