@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.
- package/LICENSE +21 -21
- package/README.md +830 -830
- package/assets/icon.svg +3 -3
- package/bin/cli.mjs +964 -964
- package/bin/dsh-mneme-choro.mjs +262 -262
- 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 -404
- 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 -3600
- 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 -14322
- package/lib/commands.js +95 -95
- package/lib/config-keys.js +144 -144
- package/lib/config.js +1361 -1344
- 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 -945
- package/lib/dream/narratives.js +44 -44
- package/lib/dream/sleep.js +2027 -2027
- package/lib/dream/triage.js +139 -139
- package/lib/dream.js +1879 -1879
- 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 -119
- package/lib/image-describe.js +158 -0
- package/lib/index.js +852 -852
- package/lib/inject.js +656 -651
- 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 -595
- 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 -3268
- package/lib/session-gate.js +91 -91
- package/lib/session-usage.js +350 -350
- package/lib/settings.js +827 -817
- 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 -5895
- 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 -267
- 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 -640
- package/lib/wiki/render.js +261 -261
- package/lib/wiki/scan.js +371 -371
- package/lib/wiki/t0.js +500 -500
- package/lib/wiki/t1-jobs.js +232 -232
- package/lib/wiki/t1.js +609 -609
- package/lib/write-admission.js +404 -404
- package/locale/en.json +6 -6
- package/locale/zh.json +6 -6
- package/package.json +1 -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 -210
- package/scripts/release-notes.mjs +164 -164
- 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 -3600
- 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 -1344
- 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 -945
- package/src/dream/narratives.js +44 -44
- package/src/dream/sleep.js +2027 -2027
- package/src/dream/triage.js +139 -139
- package/src/dream.js +1879 -1879
- 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 -119
- package/src/image-describe.js +158 -0
- package/src/index.js +852 -852
- package/src/inject.js +656 -651
- 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 -595
- 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 -3268
- package/src/session-gate.js +91 -91
- package/src/session-usage.js +350 -350
- package/src/settings.js +827 -817
- 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 -5895
- 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 -267
- 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 -640
- package/src/wiki/render.js +261 -261
- package/src/wiki/scan.js +371 -371
- package/src/wiki/t0.js +500 -500
- package/src/wiki/t1-jobs.js +232 -232
- package/src/wiki/t1.js +609 -609
- 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 -2998
- 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 -4425
- 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 -452
- package/test/conflict-ledger.test.js +242 -242
- 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 -432
- 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 -174
- 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 -333
- 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 -259
- 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 -109
- 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 -553
- 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 -90
- package/test/panel-tokens.test.js +245 -245
- 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 -156
- package/test/release-notes.test.js +265 -265
- 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 -188
- 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 -1455
- 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 -734
- package/test/wiki-claims.test.js +194 -194
- 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 -202
- package/test/wiki-queries.test.js +398 -398
- package/test/wiki-scan.test.js +208 -208
- package/test/wiki-store.test.js +190 -190
- package/test/wiki-t0.test.js +456 -456
- package/test/wiki-t1-jobs.test.js +125 -125
- package/test/wiki-t1.test.js +460 -460
- package/test/wiki-tools.test.js +176 -176
- package/test/workflow-guards.test.js +155 -155
- package/test/write-admission.test.js +668 -668
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
import test from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { createStore } from "../src/store.js";
|
|
4
|
-
import { createService } from "../src/service.js";
|
|
5
|
-
|
|
6
|
-
// issue #339 / E7 考卷补齐:A2 软加权(foreign ×0.5 / 命中 ×1.25)此前只作用于
|
|
7
|
-
// searchMemories——E7 实测「explicit 标注 + 软档」的注入集与无标注逐条相同
|
|
8
|
-
// (80/80),主泄露面上软档形同虚设。本文件锁注入通道的软加权语义:
|
|
9
|
-
// - softScope 激活(scopeEnabled + scope 至少一维可解析)→ foreign 行在层内
|
|
10
|
-
// 数值积上 ×0.5,压不过同档自己行;未标注行同列吃 BOOST 不被压制;
|
|
11
|
-
// - flag 关 / scope 两维全空 → 注入序与改动前逐字节一致(锁平价);
|
|
12
|
-
// - strictScope 硬过滤先行,被滤行不会被二次降权;
|
|
13
|
-
// - 加权后的序流入 pin 池选取(pin 拿到的是加权后次序)。
|
|
14
|
-
|
|
15
|
-
function setup(config) {
|
|
16
|
-
const store = createStore(":memory:");
|
|
17
|
-
const service = createService({ store, mirror: null, config });
|
|
18
|
-
return { store, service };
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const SCOPE_ME = { agent_scope: "me", workspace_scope: null };
|
|
22
|
-
|
|
23
|
-
test("injectCandidates soft weight demotes explicit foreign rows below same-importance own rows", () => {
|
|
24
|
-
const { store, service } = setup({ scopeEnabled: true, strictScope: false });
|
|
25
|
-
// 同 importance 档(E7 的同档设计):无软加权时全靠插入序,foreign 在前。
|
|
26
|
-
store.save({ type: "decision", title: "foreign-a", content: "x", importance: 4, agent_scope: "other", agent_scope_source: "explicit" });
|
|
27
|
-
store.save({ type: "decision", title: "mine-a", content: "x", importance: 4, agent_scope: "me", agent_scope_source: "explicit" });
|
|
28
|
-
store.save({ type: "decision", title: "foreign-b", content: "x", importance: 4, agent_scope: "other", agent_scope_source: "explicit" });
|
|
29
|
-
|
|
30
|
-
const injected = service.injectCandidates({ maxItems: 5, threshold: 3, scope: SCOPE_ME });
|
|
31
|
-
const titles = injected.map((m) => m.title);
|
|
32
|
-
// foreign ×0.5 = 2.0 < 自己 ×1.25 = 5.0:自己行第一;两条 foreign 同分,
|
|
33
|
-
// 相对序随 store.list 的同分序(updated_at),不锁。
|
|
34
|
-
assert.equal(titles[0], "mine-a");
|
|
35
|
-
assert.deepEqual(titles.slice(1).sort(), ["foreign-a", "foreign-b"]);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test("injectCandidates soft tier keeps unlabeled rows ranked with matches, not suppressed", () => {
|
|
39
|
-
const { store, service } = setup({ scopeEnabled: true, strictScope: false });
|
|
40
|
-
store.save({ type: "decision", title: "global", content: "x", importance: 4 });
|
|
41
|
-
store.save({ type: "decision", title: "foreign", content: "x", importance: 4, agent_scope: "other", agent_scope_source: "explicit" });
|
|
42
|
-
|
|
43
|
-
const injected = service.injectCandidates({ maxItems: 5, threshold: 3, scope: SCOPE_ME });
|
|
44
|
-
// 未标注 = 全局可见,与命中行同列(×1.25)而非被压到 foreign 之后。
|
|
45
|
-
assert.deepEqual(injected.map((m) => m.title), ["global", "foreign"]);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test("injectCandidates order is byte-identical when scopeEnabled is off or scope is anonymous", () => {
|
|
49
|
-
const seed = (store) => {
|
|
50
|
-
store.save({ type: "decision", title: "foreign-a", content: "x", importance: 4, agent_scope: "other", agent_scope_source: "explicit" });
|
|
51
|
-
store.save({ type: "decision", title: "mine-a", content: "x", importance: 4, agent_scope: "me", agent_scope_source: "explicit" });
|
|
52
|
-
store.save({ type: "decision", title: "global", content: "x", importance: 3 });
|
|
53
|
-
};
|
|
54
|
-
// flag 关:不传 scope(改动前后必须同序——锁平价)。
|
|
55
|
-
const off = setup({ scopeEnabled: false, strictScope: false });
|
|
56
|
-
seed(off.store);
|
|
57
|
-
// flag 开但身份两维全空:软加权门不激活,也不得改序。
|
|
58
|
-
const anon = setup({ scopeEnabled: true, strictScope: false });
|
|
59
|
-
seed(anon.store);
|
|
60
|
-
|
|
61
|
-
// 平价锁:两种情况的注入序必须一致(比较器与改动前逐字节相同)。
|
|
62
|
-
const baseline = off.service.injectCandidates({ maxItems: 5, threshold: 3 }).map((m) => m.title);
|
|
63
|
-
assert.deepEqual(
|
|
64
|
-
anon.service.injectCandidates({ maxItems: 5, threshold: 3, scope: { agent_scope: null, workspace_scope: null } }).map((m) => m.title),
|
|
65
|
-
baseline
|
|
66
|
-
);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
test("strictScope hard filter runs before soft weighting: filtered rows are not double-demoted", () => {
|
|
70
|
-
const { store, service } = setup({ scopeEnabled: true, strictScope: true });
|
|
71
|
-
store.save({ type: "decision", title: "foreign", content: "x", importance: 4, agent_scope: "other", agent_scope_source: "explicit" });
|
|
72
|
-
store.save({ type: "decision", title: "global", content: "x", importance: 3 });
|
|
73
|
-
|
|
74
|
-
const injected = service.injectCandidates({ maxItems: 5, threshold: 3, scope: SCOPE_ME });
|
|
75
|
-
// 硬墙先删 foreign;剩下的 global(未标注)吃 BOOST 保留——若软加权先跑会把
|
|
76
|
-
// foreign 压到后面再被删,成员虽同但语义不同;此处锁成员与顺序。
|
|
77
|
-
assert.deepEqual(injected.map((m) => m.title), ["global"]);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
test("soft-weighted order feeds the pin pool (pin picks the weighted-first candidates)", () => {
|
|
81
|
-
const { store, service } = setup({ scopeEnabled: true, strictScope: false, pinnedInjectBudget: 1 });
|
|
82
|
-
// pin 池只收 constraint/preference——两条都用 preference,同档靠软加权分序。
|
|
83
|
-
store.save({ type: "preference", title: "foreign-pin", content: "x", importance: 4, agent_scope: "other", agent_scope_source: "explicit" });
|
|
84
|
-
store.save({ type: "preference", title: "mine", content: "x", importance: 4, agent_scope: "me", agent_scope_source: "explicit" });
|
|
85
|
-
|
|
86
|
-
const pinnedStats = {};
|
|
87
|
-
const injected = service.injectCandidates({
|
|
88
|
-
maxItems: 5, threshold: 3, scope: SCOPE_ME, pinnedStats,
|
|
89
|
-
});
|
|
90
|
-
// 加权后 mine 在前:pin 池取的是加权后次序的第一条。
|
|
91
|
-
assert.equal(pinnedStats.shown, 1);
|
|
92
|
-
assert.equal(injected[0].title, "mine");
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
test("first-round BM25 fallback applies the soft weight (no query vector yet)", () => {
|
|
96
|
-
const { store, service } = setup({ scopeEnabled: true, strictScope: false });
|
|
97
|
-
// 同内容同长度(标题各 1 token 且不在查询词表)→ BM25 原始分相同;
|
|
98
|
-
// 未加权时同分序随 store.list(updated desc,foreign 后存先出)。
|
|
99
|
-
store.save({ type: "decision", title: "alpha", content: "plan the dinner party menu with care", importance: 4, agent_scope: "me", agent_scope_source: "explicit" });
|
|
100
|
-
store.save({ type: "decision", title: "bravo", content: "plan the dinner party menu with care", importance: 4, agent_scope: "other", agent_scope_source: "explicit" });
|
|
101
|
-
|
|
102
|
-
const injected = service.injectCandidates({
|
|
103
|
-
query: "dinner party menu", maxItems: 5, threshold: 3, scope: SCOPE_ME,
|
|
104
|
-
});
|
|
105
|
-
assert.equal(injected[0].title, "alpha", "BM25 hits are soft-weighted before the semantic-first merge");
|
|
106
|
-
});
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { createStore } from "../src/store.js";
|
|
4
|
+
import { createService } from "../src/service.js";
|
|
5
|
+
|
|
6
|
+
// issue #339 / E7 考卷补齐:A2 软加权(foreign ×0.5 / 命中 ×1.25)此前只作用于
|
|
7
|
+
// searchMemories——E7 实测「explicit 标注 + 软档」的注入集与无标注逐条相同
|
|
8
|
+
// (80/80),主泄露面上软档形同虚设。本文件锁注入通道的软加权语义:
|
|
9
|
+
// - softScope 激活(scopeEnabled + scope 至少一维可解析)→ foreign 行在层内
|
|
10
|
+
// 数值积上 ×0.5,压不过同档自己行;未标注行同列吃 BOOST 不被压制;
|
|
11
|
+
// - flag 关 / scope 两维全空 → 注入序与改动前逐字节一致(锁平价);
|
|
12
|
+
// - strictScope 硬过滤先行,被滤行不会被二次降权;
|
|
13
|
+
// - 加权后的序流入 pin 池选取(pin 拿到的是加权后次序)。
|
|
14
|
+
|
|
15
|
+
function setup(config) {
|
|
16
|
+
const store = createStore(":memory:");
|
|
17
|
+
const service = createService({ store, mirror: null, config });
|
|
18
|
+
return { store, service };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const SCOPE_ME = { agent_scope: "me", workspace_scope: null };
|
|
22
|
+
|
|
23
|
+
test("injectCandidates soft weight demotes explicit foreign rows below same-importance own rows", () => {
|
|
24
|
+
const { store, service } = setup({ scopeEnabled: true, strictScope: false });
|
|
25
|
+
// 同 importance 档(E7 的同档设计):无软加权时全靠插入序,foreign 在前。
|
|
26
|
+
store.save({ type: "decision", title: "foreign-a", content: "x", importance: 4, agent_scope: "other", agent_scope_source: "explicit" });
|
|
27
|
+
store.save({ type: "decision", title: "mine-a", content: "x", importance: 4, agent_scope: "me", agent_scope_source: "explicit" });
|
|
28
|
+
store.save({ type: "decision", title: "foreign-b", content: "x", importance: 4, agent_scope: "other", agent_scope_source: "explicit" });
|
|
29
|
+
|
|
30
|
+
const injected = service.injectCandidates({ maxItems: 5, threshold: 3, scope: SCOPE_ME });
|
|
31
|
+
const titles = injected.map((m) => m.title);
|
|
32
|
+
// foreign ×0.5 = 2.0 < 自己 ×1.25 = 5.0:自己行第一;两条 foreign 同分,
|
|
33
|
+
// 相对序随 store.list 的同分序(updated_at),不锁。
|
|
34
|
+
assert.equal(titles[0], "mine-a");
|
|
35
|
+
assert.deepEqual(titles.slice(1).sort(), ["foreign-a", "foreign-b"]);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("injectCandidates soft tier keeps unlabeled rows ranked with matches, not suppressed", () => {
|
|
39
|
+
const { store, service } = setup({ scopeEnabled: true, strictScope: false });
|
|
40
|
+
store.save({ type: "decision", title: "global", content: "x", importance: 4 });
|
|
41
|
+
store.save({ type: "decision", title: "foreign", content: "x", importance: 4, agent_scope: "other", agent_scope_source: "explicit" });
|
|
42
|
+
|
|
43
|
+
const injected = service.injectCandidates({ maxItems: 5, threshold: 3, scope: SCOPE_ME });
|
|
44
|
+
// 未标注 = 全局可见,与命中行同列(×1.25)而非被压到 foreign 之后。
|
|
45
|
+
assert.deepEqual(injected.map((m) => m.title), ["global", "foreign"]);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("injectCandidates order is byte-identical when scopeEnabled is off or scope is anonymous", () => {
|
|
49
|
+
const seed = (store) => {
|
|
50
|
+
store.save({ type: "decision", title: "foreign-a", content: "x", importance: 4, agent_scope: "other", agent_scope_source: "explicit" });
|
|
51
|
+
store.save({ type: "decision", title: "mine-a", content: "x", importance: 4, agent_scope: "me", agent_scope_source: "explicit" });
|
|
52
|
+
store.save({ type: "decision", title: "global", content: "x", importance: 3 });
|
|
53
|
+
};
|
|
54
|
+
// flag 关:不传 scope(改动前后必须同序——锁平价)。
|
|
55
|
+
const off = setup({ scopeEnabled: false, strictScope: false });
|
|
56
|
+
seed(off.store);
|
|
57
|
+
// flag 开但身份两维全空:软加权门不激活,也不得改序。
|
|
58
|
+
const anon = setup({ scopeEnabled: true, strictScope: false });
|
|
59
|
+
seed(anon.store);
|
|
60
|
+
|
|
61
|
+
// 平价锁:两种情况的注入序必须一致(比较器与改动前逐字节相同)。
|
|
62
|
+
const baseline = off.service.injectCandidates({ maxItems: 5, threshold: 3 }).map((m) => m.title);
|
|
63
|
+
assert.deepEqual(
|
|
64
|
+
anon.service.injectCandidates({ maxItems: 5, threshold: 3, scope: { agent_scope: null, workspace_scope: null } }).map((m) => m.title),
|
|
65
|
+
baseline
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("strictScope hard filter runs before soft weighting: filtered rows are not double-demoted", () => {
|
|
70
|
+
const { store, service } = setup({ scopeEnabled: true, strictScope: true });
|
|
71
|
+
store.save({ type: "decision", title: "foreign", content: "x", importance: 4, agent_scope: "other", agent_scope_source: "explicit" });
|
|
72
|
+
store.save({ type: "decision", title: "global", content: "x", importance: 3 });
|
|
73
|
+
|
|
74
|
+
const injected = service.injectCandidates({ maxItems: 5, threshold: 3, scope: SCOPE_ME });
|
|
75
|
+
// 硬墙先删 foreign;剩下的 global(未标注)吃 BOOST 保留——若软加权先跑会把
|
|
76
|
+
// foreign 压到后面再被删,成员虽同但语义不同;此处锁成员与顺序。
|
|
77
|
+
assert.deepEqual(injected.map((m) => m.title), ["global"]);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("soft-weighted order feeds the pin pool (pin picks the weighted-first candidates)", () => {
|
|
81
|
+
const { store, service } = setup({ scopeEnabled: true, strictScope: false, pinnedInjectBudget: 1 });
|
|
82
|
+
// pin 池只收 constraint/preference——两条都用 preference,同档靠软加权分序。
|
|
83
|
+
store.save({ type: "preference", title: "foreign-pin", content: "x", importance: 4, agent_scope: "other", agent_scope_source: "explicit" });
|
|
84
|
+
store.save({ type: "preference", title: "mine", content: "x", importance: 4, agent_scope: "me", agent_scope_source: "explicit" });
|
|
85
|
+
|
|
86
|
+
const pinnedStats = {};
|
|
87
|
+
const injected = service.injectCandidates({
|
|
88
|
+
maxItems: 5, threshold: 3, scope: SCOPE_ME, pinnedStats,
|
|
89
|
+
});
|
|
90
|
+
// 加权后 mine 在前:pin 池取的是加权后次序的第一条。
|
|
91
|
+
assert.equal(pinnedStats.shown, 1);
|
|
92
|
+
assert.equal(injected[0].title, "mine");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("first-round BM25 fallback applies the soft weight (no query vector yet)", () => {
|
|
96
|
+
const { store, service } = setup({ scopeEnabled: true, strictScope: false });
|
|
97
|
+
// 同内容同长度(标题各 1 token 且不在查询词表)→ BM25 原始分相同;
|
|
98
|
+
// 未加权时同分序随 store.list(updated desc,foreign 后存先出)。
|
|
99
|
+
store.save({ type: "decision", title: "alpha", content: "plan the dinner party menu with care", importance: 4, agent_scope: "me", agent_scope_source: "explicit" });
|
|
100
|
+
store.save({ type: "decision", title: "bravo", content: "plan the dinner party menu with care", importance: 4, agent_scope: "other", agent_scope_source: "explicit" });
|
|
101
|
+
|
|
102
|
+
const injected = service.injectCandidates({
|
|
103
|
+
query: "dinner party menu", maxItems: 5, threshold: 3, scope: SCOPE_ME,
|
|
104
|
+
});
|
|
105
|
+
assert.equal(injected[0].title, "alpha", "BM25 hits are soft-weighted before the semantic-first merge");
|
|
106
|
+
});
|
|
@@ -1,110 +1,110 @@
|
|
|
1
|
-
import test from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { createScopeResolver } from "../src/scope.js";
|
|
4
|
-
|
|
5
|
-
// issue #487:workspaceRegistry 不在 inject 声明里(src/index.js:45),而 cordis 4
|
|
6
|
-
// 的 ctx 是 Proxy——裸读未注入属性会抛 "cannot get property ... without inject",
|
|
7
|
-
// 不返回 undefined。于是 scope.js 曾经那行 `ctx?.workspaceRegistry?.list?.()` 从
|
|
8
|
-
// v0.8.0 起必然抛错走降级:canonical path 归一与成员资格校验静默失效,只剩
|
|
9
|
-
// header.cwd。
|
|
10
|
-
//
|
|
11
|
-
// 为什么既有测试没拦住:scope-storage.test.js 里三处 registry 测试都用普通对象
|
|
12
|
-
// 伪造 ctx({ workspaceRegistry: {...} }),普通对象裸读不抛错。本文件改用
|
|
13
|
-
// 「读未声明属性即抛」的 Proxy 复刻真实宿主形状,把两侧行为都钉死。
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* cordis 4 形状的 ctx:只有显式提供的属性可读,其余一律抛错(不是 undefined)。
|
|
17
|
-
* @param {object} provided 已提供的属性(reflect / logger …)
|
|
18
|
-
*/
|
|
19
|
-
function proxyCtx(provided) {
|
|
20
|
-
return new Proxy(provided, {
|
|
21
|
-
get(target, prop) {
|
|
22
|
-
if (typeof prop === "symbol" || prop === "then" || String(prop).startsWith("_")) {
|
|
23
|
-
return target[prop];
|
|
24
|
-
}
|
|
25
|
-
if (prop in target) return target[prop];
|
|
26
|
-
throw new Error(`cannot get property "${String(prop)}" without inject`);
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** 带 workspaceRegistry 服务的 reflect(免 inject 读取出口)。 */
|
|
32
|
-
function reflectWith(services, seen = []) {
|
|
33
|
-
return {
|
|
34
|
-
get(name) {
|
|
35
|
-
seen.push(name);
|
|
36
|
-
return services[name];
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const EXEC = { agent: { session: { id: "s1", header: { agentPreset: "coder", cwd: "D:\\raw" } } } };
|
|
42
|
-
|
|
43
|
-
function loggerSpy() {
|
|
44
|
-
const warnings = [];
|
|
45
|
-
return { warnings, logger: { warn: (m) => warnings.push(String(m)) } };
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
test("#487: unregistered ctx property never throws out of the resolver (Proxy shape)", () => {
|
|
49
|
-
// 没有任何服务:裸读 workspaceRegistry 在真宿主里会抛。解析器必须吞掉并降级。
|
|
50
|
-
const { warnings, logger } = loggerSpy();
|
|
51
|
-
const ctx = proxyCtx({ reflect: reflectWith({}), logger });
|
|
52
|
-
const resolve = createScopeResolver({ ctx, config: { scopeEnabled: true }, logger });
|
|
53
|
-
// 不会抛;agentPreset 照常解析,workspace 落到 header.cwd。
|
|
54
|
-
assert.deepEqual(resolve(EXEC), { agent_scope: "coder", workspace_scope: "D:\\raw" });
|
|
55
|
-
// 服务缺失是合法状态(headless / 旧宿主),不是故障——不许刷 warn。
|
|
56
|
-
assert.deepEqual(warnings, [], "missing optional service must stay silent");
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
test("#487: registry reached through reflect.get restores the canonical path", () => {
|
|
60
|
-
// 修复的收益不只是消 warning:宿主确实提供 workspaceRegistry(@deepseek-ai/
|
|
61
|
-
// dsh-workspace),走免 inject 读取能取回 realpath 归一后的 canonical path,
|
|
62
|
-
// 而不是退化成原始 cwd 字符串。
|
|
63
|
-
const registry = { list: () => [{ path: "C:\\canon", sessionIds: ["s1"] }] };
|
|
64
|
-
const seen = [];
|
|
65
|
-
const ctx = proxyCtx({ reflect: reflectWith({ workspaceRegistry: registry }, seen) });
|
|
66
|
-
const resolve = createScopeResolver({ ctx, config: { scopeEnabled: true } });
|
|
67
|
-
|
|
68
|
-
assert.deepEqual(resolve(EXEC), { agent_scope: "coder", workspace_scope: "C:\\canon" });
|
|
69
|
-
assert.ok(seen.includes("workspaceRegistry"), "registry must be read via reflect.get");
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test("#487: membership miss still falls back to header cwd (registry hit is id-scoped)", () => {
|
|
73
|
-
const registry = { list: () => [{ path: "C:\\canon", sessionIds: ["other"] }] };
|
|
74
|
-
const ctx = proxyCtx({ reflect: reflectWith({ workspaceRegistry: registry }) });
|
|
75
|
-
const resolve = createScopeResolver({ ctx, config: { scopeEnabled: true } });
|
|
76
|
-
|
|
77
|
-
assert.deepEqual(resolve(EXEC), { agent_scope: "coder", workspace_scope: "D:\\raw" });
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
test("#487: hosts without ctx.reflect keep working through the plain-object shape", () => {
|
|
81
|
-
// 旧宿主:ctx 是普通对象、没有 reflect.get。普通对象裸读安全,行为必须和修复前一致。
|
|
82
|
-
const ctx = { workspaceRegistry: { list: () => [{ path: "C:\\canon", sessionIds: ["s1"] }] } };
|
|
83
|
-
const resolve = createScopeResolver({ ctx, config: { scopeEnabled: true } });
|
|
84
|
-
assert.deepEqual(resolve(EXEC), { agent_scope: "coder", workspace_scope: "C:\\canon" });
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test("#487: registry explosion still degrades to header cwd and warns exactly once", () => {
|
|
88
|
-
// 既有语义(scope-storage.test.js 已有同款普通对象版):服务确实炸了要出声,
|
|
89
|
-
// 但每次写一个解析器实例只警告一次、绝不影响写入。
|
|
90
|
-
const { warnings, logger } = loggerSpy();
|
|
91
|
-
const registry = { list: () => { throw new Error("boom"); } };
|
|
92
|
-
const ctx = proxyCtx({ reflect: reflectWith({ workspaceRegistry: registry }), logger });
|
|
93
|
-
const resolve = createScopeResolver({ ctx, config: { scopeEnabled: true }, logger });
|
|
94
|
-
|
|
95
|
-
assert.deepEqual(resolve(EXEC), { agent_scope: "coder", workspace_scope: "D:\\raw" });
|
|
96
|
-
assert.deepEqual(resolve(EXEC), { agent_scope: "coder", workspace_scope: "D:\\raw" });
|
|
97
|
-
assert.equal(warnings.length, 1, "warn once per resolver instance, never on every write");
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
test("#487: resolver never throws even when reflect.get itself explodes", () => {
|
|
101
|
-
const { logger } = loggerSpy();
|
|
102
|
-
const ctx = proxyCtx({
|
|
103
|
-
reflect: { get() { throw new Error("reflect boom"); } },
|
|
104
|
-
logger
|
|
105
|
-
});
|
|
106
|
-
const resolve = createScopeResolver({ ctx, config: { scopeEnabled: true }, logger });
|
|
107
|
-
assert.deepEqual(resolve(EXEC), { agent_scope: "coder", workspace_scope: "D:\\raw" });
|
|
108
|
-
// 无会话时照旧全 NULL(fail-closed 读取侧依赖这个契约)。
|
|
109
|
-
assert.deepEqual(resolve(undefined), { agent_scope: null, workspace_scope: null });
|
|
110
|
-
});
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { createScopeResolver } from "../src/scope.js";
|
|
4
|
+
|
|
5
|
+
// issue #487:workspaceRegistry 不在 inject 声明里(src/index.js:45),而 cordis 4
|
|
6
|
+
// 的 ctx 是 Proxy——裸读未注入属性会抛 "cannot get property ... without inject",
|
|
7
|
+
// 不返回 undefined。于是 scope.js 曾经那行 `ctx?.workspaceRegistry?.list?.()` 从
|
|
8
|
+
// v0.8.0 起必然抛错走降级:canonical path 归一与成员资格校验静默失效,只剩
|
|
9
|
+
// header.cwd。
|
|
10
|
+
//
|
|
11
|
+
// 为什么既有测试没拦住:scope-storage.test.js 里三处 registry 测试都用普通对象
|
|
12
|
+
// 伪造 ctx({ workspaceRegistry: {...} }),普通对象裸读不抛错。本文件改用
|
|
13
|
+
// 「读未声明属性即抛」的 Proxy 复刻真实宿主形状,把两侧行为都钉死。
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* cordis 4 形状的 ctx:只有显式提供的属性可读,其余一律抛错(不是 undefined)。
|
|
17
|
+
* @param {object} provided 已提供的属性(reflect / logger …)
|
|
18
|
+
*/
|
|
19
|
+
function proxyCtx(provided) {
|
|
20
|
+
return new Proxy(provided, {
|
|
21
|
+
get(target, prop) {
|
|
22
|
+
if (typeof prop === "symbol" || prop === "then" || String(prop).startsWith("_")) {
|
|
23
|
+
return target[prop];
|
|
24
|
+
}
|
|
25
|
+
if (prop in target) return target[prop];
|
|
26
|
+
throw new Error(`cannot get property "${String(prop)}" without inject`);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** 带 workspaceRegistry 服务的 reflect(免 inject 读取出口)。 */
|
|
32
|
+
function reflectWith(services, seen = []) {
|
|
33
|
+
return {
|
|
34
|
+
get(name) {
|
|
35
|
+
seen.push(name);
|
|
36
|
+
return services[name];
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const EXEC = { agent: { session: { id: "s1", header: { agentPreset: "coder", cwd: "D:\\raw" } } } };
|
|
42
|
+
|
|
43
|
+
function loggerSpy() {
|
|
44
|
+
const warnings = [];
|
|
45
|
+
return { warnings, logger: { warn: (m) => warnings.push(String(m)) } };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
test("#487: unregistered ctx property never throws out of the resolver (Proxy shape)", () => {
|
|
49
|
+
// 没有任何服务:裸读 workspaceRegistry 在真宿主里会抛。解析器必须吞掉并降级。
|
|
50
|
+
const { warnings, logger } = loggerSpy();
|
|
51
|
+
const ctx = proxyCtx({ reflect: reflectWith({}), logger });
|
|
52
|
+
const resolve = createScopeResolver({ ctx, config: { scopeEnabled: true }, logger });
|
|
53
|
+
// 不会抛;agentPreset 照常解析,workspace 落到 header.cwd。
|
|
54
|
+
assert.deepEqual(resolve(EXEC), { agent_scope: "coder", workspace_scope: "D:\\raw" });
|
|
55
|
+
// 服务缺失是合法状态(headless / 旧宿主),不是故障——不许刷 warn。
|
|
56
|
+
assert.deepEqual(warnings, [], "missing optional service must stay silent");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("#487: registry reached through reflect.get restores the canonical path", () => {
|
|
60
|
+
// 修复的收益不只是消 warning:宿主确实提供 workspaceRegistry(@deepseek-ai/
|
|
61
|
+
// dsh-workspace),走免 inject 读取能取回 realpath 归一后的 canonical path,
|
|
62
|
+
// 而不是退化成原始 cwd 字符串。
|
|
63
|
+
const registry = { list: () => [{ path: "C:\\canon", sessionIds: ["s1"] }] };
|
|
64
|
+
const seen = [];
|
|
65
|
+
const ctx = proxyCtx({ reflect: reflectWith({ workspaceRegistry: registry }, seen) });
|
|
66
|
+
const resolve = createScopeResolver({ ctx, config: { scopeEnabled: true } });
|
|
67
|
+
|
|
68
|
+
assert.deepEqual(resolve(EXEC), { agent_scope: "coder", workspace_scope: "C:\\canon" });
|
|
69
|
+
assert.ok(seen.includes("workspaceRegistry"), "registry must be read via reflect.get");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test("#487: membership miss still falls back to header cwd (registry hit is id-scoped)", () => {
|
|
73
|
+
const registry = { list: () => [{ path: "C:\\canon", sessionIds: ["other"] }] };
|
|
74
|
+
const ctx = proxyCtx({ reflect: reflectWith({ workspaceRegistry: registry }) });
|
|
75
|
+
const resolve = createScopeResolver({ ctx, config: { scopeEnabled: true } });
|
|
76
|
+
|
|
77
|
+
assert.deepEqual(resolve(EXEC), { agent_scope: "coder", workspace_scope: "D:\\raw" });
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("#487: hosts without ctx.reflect keep working through the plain-object shape", () => {
|
|
81
|
+
// 旧宿主:ctx 是普通对象、没有 reflect.get。普通对象裸读安全,行为必须和修复前一致。
|
|
82
|
+
const ctx = { workspaceRegistry: { list: () => [{ path: "C:\\canon", sessionIds: ["s1"] }] } };
|
|
83
|
+
const resolve = createScopeResolver({ ctx, config: { scopeEnabled: true } });
|
|
84
|
+
assert.deepEqual(resolve(EXEC), { agent_scope: "coder", workspace_scope: "C:\\canon" });
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("#487: registry explosion still degrades to header cwd and warns exactly once", () => {
|
|
88
|
+
// 既有语义(scope-storage.test.js 已有同款普通对象版):服务确实炸了要出声,
|
|
89
|
+
// 但每次写一个解析器实例只警告一次、绝不影响写入。
|
|
90
|
+
const { warnings, logger } = loggerSpy();
|
|
91
|
+
const registry = { list: () => { throw new Error("boom"); } };
|
|
92
|
+
const ctx = proxyCtx({ reflect: reflectWith({ workspaceRegistry: registry }), logger });
|
|
93
|
+
const resolve = createScopeResolver({ ctx, config: { scopeEnabled: true }, logger });
|
|
94
|
+
|
|
95
|
+
assert.deepEqual(resolve(EXEC), { agent_scope: "coder", workspace_scope: "D:\\raw" });
|
|
96
|
+
assert.deepEqual(resolve(EXEC), { agent_scope: "coder", workspace_scope: "D:\\raw" });
|
|
97
|
+
assert.equal(warnings.length, 1, "warn once per resolver instance, never on every write");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("#487: resolver never throws even when reflect.get itself explodes", () => {
|
|
101
|
+
const { logger } = loggerSpy();
|
|
102
|
+
const ctx = proxyCtx({
|
|
103
|
+
reflect: { get() { throw new Error("reflect boom"); } },
|
|
104
|
+
logger
|
|
105
|
+
});
|
|
106
|
+
const resolve = createScopeResolver({ ctx, config: { scopeEnabled: true }, logger });
|
|
107
|
+
assert.deepEqual(resolve(EXEC), { agent_scope: "coder", workspace_scope: "D:\\raw" });
|
|
108
|
+
// 无会话时照旧全 NULL(fail-closed 读取侧依赖这个契约)。
|
|
109
|
+
assert.deepEqual(resolve(undefined), { agent_scope: null, workspace_scope: null });
|
|
110
|
+
});
|