@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
package/lib/wiki/render.js
CHANGED
|
@@ -1,261 +1,261 @@
|
|
|
1
|
-
// dsh-mneme/src/wiki/render.js
|
|
2
|
-
// T0 骨架页与 index.md 的确定性渲染(spec §6 步 6),以及混合所有权的保留区机制
|
|
3
|
-
// (spec §4:`<!-- CHORO:HUMAN -->` 标记块重生成时逐字节保留)。
|
|
4
|
-
//
|
|
5
|
-
// 确定性纪律(spec §9 可重建不变量):正文零时间戳、零随机——所有列表先排序再拼;
|
|
6
|
-
// 页面唯一的时刻 frontmatter.generatedAt 由 t0.js 从 state.json 沿用(实现计划
|
|
7
|
-
// P3:时刻收进 state.json,失败不推进,页面字节才可能跨 run 稳定)。
|
|
8
|
-
//
|
|
9
|
-
// 保留区规则(写死、可测):
|
|
10
|
-
// 1. 抽取:START…END 之间连同两行标记整体抽出,一个字节不动;
|
|
11
|
-
// 2. 回填:新正文之后按原相对顺序接回全部块;
|
|
12
|
-
// 3. 重生成永不删块、永不改写块内内容(包括缩进与格式)——红线 6;
|
|
13
|
-
// 4. 没有块时整页覆盖(spec:人在块外的手改不保证存活,是明说语义不是事故)。
|
|
14
|
-
|
|
15
|
-
export const TEMPLATE_VERSION = "1";
|
|
16
|
-
|
|
17
|
-
export const HUMAN_START = "<!-- CHORO:HUMAN:START -->";
|
|
18
|
-
export const HUMAN_END = "<!-- CHORO:HUMAN:END -->";
|
|
19
|
-
|
|
20
|
-
// T1 语义段的包装标记。写的人是 t1.js,读的人还有 t0.js——重跑 T0 时它要能认出
|
|
21
|
-
// 「这页已经被富化过」,否则 enriched → skeleton 的退回是静默的。标记随页面格式
|
|
22
|
-
// 走,所以与 HUMAN 标记同住这里,t1.js 转出给调用方。
|
|
23
|
-
export const T1_SECTION_START = "<!-- CHORO:T1:START -->";
|
|
24
|
-
export const T1_SECTION_END = "<!-- CHORO:T1:END -->";
|
|
25
|
-
|
|
26
|
-
// 验证溯源的两个 frontmatter 键(issue #615 之后的 ①:语义段带上「对着哪次提交验证的」)。
|
|
27
|
-
// 只有 T1 写它们,T0 渲染时一个字节都不产出——骨架页没有语义段,也就没有「哪次验证的」
|
|
28
|
-
// 这回事;反过来说,T0 重建整页时这两个键随 T1 正文一起消失,与「T0 丢弃语义段」是
|
|
29
|
-
// 同一件事,不新增语义。放在这里而不是 t1.js:frontmatter 的形状属于页面格式。
|
|
30
|
-
export const FM_VERIFIED_BASELINE = "verifiedBaseline";
|
|
31
|
-
export const FM_VERIFIED_AT = "verifiedAt";
|
|
32
|
-
|
|
33
|
-
/** frontmatter 边界:首行 --- 与下一个 --- 的行号;不存在返回 null。 */
|
|
34
|
-
function frontmatterBounds(lines) {
|
|
35
|
-
if (String(lines[0] ?? "").trim() !== "---") return null;
|
|
36
|
-
for (let i = 1; i < lines.length; i++) {
|
|
37
|
-
if (String(lines[i]).trim() === "---") return { open: 0, close: i };
|
|
38
|
-
}
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* 取 frontmatter 里某个顶层键的字符串值。
|
|
44
|
-
*
|
|
45
|
-
* 只认顶层键(`key: value`),缩进的列表项(` - x`)不会误命中;值两侧的引号剥掉
|
|
46
|
-
* (yamlScalar 会给含特殊字符的值加引号,读回来要还原成原文)。
|
|
47
|
-
* 没有 frontmatter、键不存在、值为空 → 一律 null:调用方据此说「没记下」,
|
|
48
|
-
* 而不是把空串当成一个合法的提交号。
|
|
49
|
-
*/
|
|
50
|
-
export function readFrontmatterKey(pageText, key) {
|
|
51
|
-
const lines = String(pageText ?? "").split("\n");
|
|
52
|
-
const bounds = frontmatterBounds(lines);
|
|
53
|
-
if (!bounds) return null;
|
|
54
|
-
const re = new RegExp(`^${escapeRegExp(key)}\\s*:\\s*(.*)$`);
|
|
55
|
-
for (let i = bounds.open + 1; i < bounds.close; i++) {
|
|
56
|
-
const m = re.exec(lines[i]);
|
|
57
|
-
if (!m) continue;
|
|
58
|
-
let v = m[1].trim();
|
|
59
|
-
if (v.length >= 2 && v.startsWith('"') && v.endsWith('"')) {
|
|
60
|
-
try { v = JSON.parse(v); } catch { v = v.slice(1, -1); }
|
|
61
|
-
}
|
|
62
|
-
return v === "" ? null : v;
|
|
63
|
-
}
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* 就地设置 frontmatter 顶层键:有则覆盖、无则追加在收尾 --- 之前(按传入顺序)。
|
|
69
|
-
*
|
|
70
|
-
* value 为 null / undefined / 空串 = **删掉**这个键,不留 `key:` 空行——「这一页是哪次
|
|
71
|
-
* 提交验证的,T1 没记下来」本身要能在文件里查得出来,而不是显示成一片空白。
|
|
72
|
-
* 没有 frontmatter 的正文原样返回:绝不给人写的坏文件凭空造一个块。
|
|
73
|
-
*
|
|
74
|
-
* @param {string} pageText
|
|
75
|
-
* @param {Array<[string, string|null]>} entries
|
|
76
|
-
*/
|
|
77
|
-
export function setFrontmatterKeys(pageText, entries) {
|
|
78
|
-
const lines = String(pageText ?? "").split("\n");
|
|
79
|
-
const bounds = frontmatterBounds(lines);
|
|
80
|
-
if (!bounds) return String(pageText ?? "");
|
|
81
|
-
const pending = new Map(entries.map(([k, v]) => [k, v === undefined || v === null || String(v).trim() === "" ? null : String(v)]));
|
|
82
|
-
const out = lines.slice(0, bounds.open + 1);
|
|
83
|
-
for (let i = bounds.open + 1; i < bounds.close; i++) {
|
|
84
|
-
const m = /^([A-Za-z_][\w-]*)\s*:/.exec(lines[i]);
|
|
85
|
-
if (m && pending.has(m[1])) {
|
|
86
|
-
const v = pending.get(m[1]);
|
|
87
|
-
pending.delete(m[1]);
|
|
88
|
-
if (v !== null) out.push(`${m[1]}: ${v}`);
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
out.push(lines[i]);
|
|
92
|
-
}
|
|
93
|
-
for (const [k, v] of pending) {
|
|
94
|
-
if (v !== null) out.push(`${k}: ${v}`);
|
|
95
|
-
}
|
|
96
|
-
out.push(...lines.slice(bounds.close));
|
|
97
|
-
return out.join("\n");
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/** 抽出全部保留区。返回 { blocks: string[](含标记本身,原样), count }。 */
|
|
101
|
-
export function extractHumanBlocks(pageText) {
|
|
102
|
-
if (typeof pageText !== "string") return { blocks: [], count: 0 };
|
|
103
|
-
const blocks = [];
|
|
104
|
-
const re = new RegExp(`${escapeRegExp(HUMAN_START)}[\\s\\S]*?${escapeRegExp(HUMAN_END)}`, "g");
|
|
105
|
-
let m;
|
|
106
|
-
while ((m = re.exec(pageText)) !== null) blocks.push(m[0]);
|
|
107
|
-
return { blocks, count: blocks.length };
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/** 新正文 + 保留区(按原顺序接在页尾,各隔一个空行)。 */
|
|
111
|
-
export function injectHumanBlocks(newContent, blocks) {
|
|
112
|
-
if (!blocks || blocks.length === 0) return newContent;
|
|
113
|
-
return `${newContent.replace(/\n*$/, "\n")}\n${blocks.join("\n\n")}\n`;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* 渲染一页骨架。meta: { slug, title, parents[], sourceFiles[], gitBaseline,
|
|
118
|
-
* generatedAt, status };mod 是 partition 的产物。
|
|
119
|
-
*/
|
|
120
|
-
export function renderSkeletonPage(mod, meta) {
|
|
121
|
-
const lines = [];
|
|
122
|
-
lines.push("---");
|
|
123
|
-
lines.push("choro: v1");
|
|
124
|
-
lines.push(`slug: ${meta.slug}`);
|
|
125
|
-
lines.push(`title: ${yamlScalar(meta.title)}`);
|
|
126
|
-
if (meta.parents && meta.parents.length > 0) {
|
|
127
|
-
lines.push("parents:");
|
|
128
|
-
for (const p of meta.parents) lines.push(` - ${p}`);
|
|
129
|
-
} else {
|
|
130
|
-
lines.push("parents: []");
|
|
131
|
-
}
|
|
132
|
-
lines.push("sourceFiles:");
|
|
133
|
-
for (const f of meta.sourceFiles) lines.push(` - ${f}`);
|
|
134
|
-
lines.push(`gitBaseline: ${meta.gitBaseline}`);
|
|
135
|
-
lines.push(`templateVersion: ${TEMPLATE_VERSION}`);
|
|
136
|
-
lines.push(`language: ${meta.language ?? "zh"}`);
|
|
137
|
-
lines.push(`status: ${meta.status}`);
|
|
138
|
-
lines.push(`generatedAt: ${meta.generatedAt}`);
|
|
139
|
-
lines.push("---");
|
|
140
|
-
lines.push("");
|
|
141
|
-
lines.push(`# ${meta.title}`);
|
|
142
|
-
lines.push("");
|
|
143
|
-
// 注意:这行说明里**不得出现成对的标记字面量**——抽取用的是全局正则,说明行
|
|
144
|
-
// 里一旦同时含 START 与 END,下一轮重生成就会把它当成一块保留区接在页尾
|
|
145
|
-
// (实测:第二轮页面凭空多两行)。所以说标记时用名字,不用原文。
|
|
146
|
-
lines.push(
|
|
147
|
-
`> 确定性骨架(T0,零模型):由文件树与 import 图生成。` +
|
|
148
|
-
`CHORO:HUMAN 标记对(START/END 两个 HTML 注释)包住的内容在重生成时逐字节保留;` +
|
|
149
|
-
`标记对之外的手改不保留(想保住一段就把它挪进标记对里)。`
|
|
150
|
-
);
|
|
151
|
-
lines.push("");
|
|
152
|
-
lines.push(`## 文件清单(${mod.fileCount} 个)`);
|
|
153
|
-
lines.push("");
|
|
154
|
-
lines.push("| 文件 | 行数 |");
|
|
155
|
-
lines.push("| --- | ---: |");
|
|
156
|
-
for (const [file, lines2] of mod.fileLines) lines.push(`| ${file} | ${lines2} |`);
|
|
157
|
-
lines.push("");
|
|
158
|
-
lines.push("## 入口");
|
|
159
|
-
lines.push("");
|
|
160
|
-
if (mod.entries.length > 0) {
|
|
161
|
-
for (const e of mod.entries) lines.push(`- \`${e}\``);
|
|
162
|
-
} else {
|
|
163
|
-
lines.push("- 无(没有 index/main 命名的文件,也不是包入口)");
|
|
164
|
-
}
|
|
165
|
-
lines.push("");
|
|
166
|
-
lines.push("## 内部依赖");
|
|
167
|
-
lines.push("");
|
|
168
|
-
if (mod.upstream.length > 0) {
|
|
169
|
-
lines.push(`- 上游依赖(本模块引用的模块):${mod.upstream.map((s) => `\`${s}\``).join("、")}`);
|
|
170
|
-
}
|
|
171
|
-
if (mod.downstream.length > 0) {
|
|
172
|
-
lines.push(`- 下游(引用本模块的模块):${mod.downstream.map((s) => `\`${s}\``).join("、")}`);
|
|
173
|
-
}
|
|
174
|
-
if (mod.upstream.length === 0 && mod.downstream.length === 0) {
|
|
175
|
-
lines.push("- 无内部依赖边(孤立模块)");
|
|
176
|
-
}
|
|
177
|
-
lines.push("");
|
|
178
|
-
lines.push("## 外部依赖");
|
|
179
|
-
lines.push("");
|
|
180
|
-
if (mod.externalDeps.length > 0) {
|
|
181
|
-
for (const d of mod.externalDeps) lines.push(`- \`${d.pkg}\` ×${d.count}`);
|
|
182
|
-
} else {
|
|
183
|
-
lines.push("- 无外部 npm 依赖");
|
|
184
|
-
}
|
|
185
|
-
lines.push("");
|
|
186
|
-
lines.push("## 生成说明");
|
|
187
|
-
lines.push("");
|
|
188
|
-
lines.push(
|
|
189
|
-
`- 模块划分:目录初稿 + 兄弟组内聚合并(内部边 ≥3),超上限逐级下切;` +
|
|
190
|
-
`本组 ${mod.fileCount} 个文件。`
|
|
191
|
-
);
|
|
192
|
-
if (mod.unresolvedCount > 0) {
|
|
193
|
-
lines.push(`- ${mod.unresolvedCount} 条相对引用没有解析到仓库内文件(别名/动态路径),未计入依赖图。`);
|
|
194
|
-
}
|
|
195
|
-
lines.push("");
|
|
196
|
-
return lines.join("\n");
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/** index.md:模块目录 + 仓库级信息。同样零时间戳(时刻在 state.json)。 */
|
|
200
|
-
export function renderIndex(modules, repoMeta) {
|
|
201
|
-
const lines = [];
|
|
202
|
-
lines.push("---");
|
|
203
|
-
lines.push("choro: v1");
|
|
204
|
-
lines.push(`repo: ${yamlScalar(repoMeta.name)}`);
|
|
205
|
-
lines.push(`gitBaseline: ${repoMeta.gitBaseline}`);
|
|
206
|
-
lines.push(`templateVersion: ${TEMPLATE_VERSION}`);
|
|
207
|
-
lines.push(`generatedAt: ${repoMeta.generatedAt}`);
|
|
208
|
-
lines.push("language: zh");
|
|
209
|
-
lines.push("---");
|
|
210
|
-
lines.push("");
|
|
211
|
-
lines.push(`# ${repoMeta.name} · 仓库地志`);
|
|
212
|
-
lines.push("");
|
|
213
|
-
lines.push(
|
|
214
|
-
`T0 确定性骨架(零模型)。页面在 \`modules/\` 下,真源是本目录的 Markdown;` +
|
|
215
|
-
`本文件整页机器所有、可随时重算(spec §4)。`
|
|
216
|
-
);
|
|
217
|
-
lines.push("");
|
|
218
|
-
lines.push(`- 扫描 ${repoMeta.fileCount} 个文件,划出 ${modules.length} 个模块。`);
|
|
219
|
-
if (repoMeta.skipped > 0) lines.push(`- ${repoMeta.skipped} 个文件读取失败,已跳过(页脚与 receipt 都有记)。`);
|
|
220
|
-
if (repoMeta.unresolved > 0) lines.push(`- ${repoMeta.unresolved} 条相对引用未解析(别名/动态路径),未计入依赖图。`);
|
|
221
|
-
lines.push("");
|
|
222
|
-
lines.push("## 模块目录");
|
|
223
|
-
lines.push("");
|
|
224
|
-
lines.push("| 模块 | 页面 | 文件数 | 内部边 | 外部依赖 |");
|
|
225
|
-
lines.push("| --- | --- | ---: | ---: | ---: |");
|
|
226
|
-
for (const mod of modules) {
|
|
227
|
-
const pageRel = `modules/${mod.slug}.md`;
|
|
228
|
-
lines.push(
|
|
229
|
-
`| ${mod.title} | [${mod.slug}](${pageRel}) | ${mod.fileCount} | ` +
|
|
230
|
-
`${mod.internalEdges.length} | ${mod.externalDeps.length} |`
|
|
231
|
-
);
|
|
232
|
-
}
|
|
233
|
-
lines.push("");
|
|
234
|
-
lines.push("## 脚本命令(根 package.json)");
|
|
235
|
-
lines.push("");
|
|
236
|
-
const scriptNames = Object.keys(repoMeta.scripts ?? {}).sort();
|
|
237
|
-
if (scriptNames.length > 0) {
|
|
238
|
-
lines.push("| 命令 | 内容 |");
|
|
239
|
-
lines.push("| --- | --- |");
|
|
240
|
-
for (const name of scriptNames) lines.push(`| \`${name}\` | ${escapeCell(String(repoMeta.scripts[name]))} |`);
|
|
241
|
-
} else {
|
|
242
|
-
lines.push("- 无 scripts 字段或没有根 package.json。");
|
|
243
|
-
}
|
|
244
|
-
lines.push("");
|
|
245
|
-
return lines.join("\n");
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// YAML 标量:含冒号/引号等特殊字符时加引号(frontmatter 里的 title/repo 是人名或
|
|
249
|
-
// 目录名,通常无害,但这层便宜且省掉转义 bug)。
|
|
250
|
-
function yamlScalar(text) {
|
|
251
|
-
const s = String(text ?? "");
|
|
252
|
-
return /[:#'\"[\]{},&*?|>%@`]/.test(s) || s.trim() !== s ? JSON.stringify(s) : s;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
function escapeCell(text) {
|
|
256
|
-
return text.replace(/\|/g, "\\|").replace(/\n/g, " ");
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
function escapeRegExp(text) {
|
|
260
|
-
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
261
|
-
}
|
|
1
|
+
// dsh-mneme/src/wiki/render.js
|
|
2
|
+
// T0 骨架页与 index.md 的确定性渲染(spec §6 步 6),以及混合所有权的保留区机制
|
|
3
|
+
// (spec §4:`<!-- CHORO:HUMAN -->` 标记块重生成时逐字节保留)。
|
|
4
|
+
//
|
|
5
|
+
// 确定性纪律(spec §9 可重建不变量):正文零时间戳、零随机——所有列表先排序再拼;
|
|
6
|
+
// 页面唯一的时刻 frontmatter.generatedAt 由 t0.js 从 state.json 沿用(实现计划
|
|
7
|
+
// P3:时刻收进 state.json,失败不推进,页面字节才可能跨 run 稳定)。
|
|
8
|
+
//
|
|
9
|
+
// 保留区规则(写死、可测):
|
|
10
|
+
// 1. 抽取:START…END 之间连同两行标记整体抽出,一个字节不动;
|
|
11
|
+
// 2. 回填:新正文之后按原相对顺序接回全部块;
|
|
12
|
+
// 3. 重生成永不删块、永不改写块内内容(包括缩进与格式)——红线 6;
|
|
13
|
+
// 4. 没有块时整页覆盖(spec:人在块外的手改不保证存活,是明说语义不是事故)。
|
|
14
|
+
|
|
15
|
+
export const TEMPLATE_VERSION = "1";
|
|
16
|
+
|
|
17
|
+
export const HUMAN_START = "<!-- CHORO:HUMAN:START -->";
|
|
18
|
+
export const HUMAN_END = "<!-- CHORO:HUMAN:END -->";
|
|
19
|
+
|
|
20
|
+
// T1 语义段的包装标记。写的人是 t1.js,读的人还有 t0.js——重跑 T0 时它要能认出
|
|
21
|
+
// 「这页已经被富化过」,否则 enriched → skeleton 的退回是静默的。标记随页面格式
|
|
22
|
+
// 走,所以与 HUMAN 标记同住这里,t1.js 转出给调用方。
|
|
23
|
+
export const T1_SECTION_START = "<!-- CHORO:T1:START -->";
|
|
24
|
+
export const T1_SECTION_END = "<!-- CHORO:T1:END -->";
|
|
25
|
+
|
|
26
|
+
// 验证溯源的两个 frontmatter 键(issue #615 之后的 ①:语义段带上「对着哪次提交验证的」)。
|
|
27
|
+
// 只有 T1 写它们,T0 渲染时一个字节都不产出——骨架页没有语义段,也就没有「哪次验证的」
|
|
28
|
+
// 这回事;反过来说,T0 重建整页时这两个键随 T1 正文一起消失,与「T0 丢弃语义段」是
|
|
29
|
+
// 同一件事,不新增语义。放在这里而不是 t1.js:frontmatter 的形状属于页面格式。
|
|
30
|
+
export const FM_VERIFIED_BASELINE = "verifiedBaseline";
|
|
31
|
+
export const FM_VERIFIED_AT = "verifiedAt";
|
|
32
|
+
|
|
33
|
+
/** frontmatter 边界:首行 --- 与下一个 --- 的行号;不存在返回 null。 */
|
|
34
|
+
function frontmatterBounds(lines) {
|
|
35
|
+
if (String(lines[0] ?? "").trim() !== "---") return null;
|
|
36
|
+
for (let i = 1; i < lines.length; i++) {
|
|
37
|
+
if (String(lines[i]).trim() === "---") return { open: 0, close: i };
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 取 frontmatter 里某个顶层键的字符串值。
|
|
44
|
+
*
|
|
45
|
+
* 只认顶层键(`key: value`),缩进的列表项(` - x`)不会误命中;值两侧的引号剥掉
|
|
46
|
+
* (yamlScalar 会给含特殊字符的值加引号,读回来要还原成原文)。
|
|
47
|
+
* 没有 frontmatter、键不存在、值为空 → 一律 null:调用方据此说「没记下」,
|
|
48
|
+
* 而不是把空串当成一个合法的提交号。
|
|
49
|
+
*/
|
|
50
|
+
export function readFrontmatterKey(pageText, key) {
|
|
51
|
+
const lines = String(pageText ?? "").split("\n");
|
|
52
|
+
const bounds = frontmatterBounds(lines);
|
|
53
|
+
if (!bounds) return null;
|
|
54
|
+
const re = new RegExp(`^${escapeRegExp(key)}\\s*:\\s*(.*)$`);
|
|
55
|
+
for (let i = bounds.open + 1; i < bounds.close; i++) {
|
|
56
|
+
const m = re.exec(lines[i]);
|
|
57
|
+
if (!m) continue;
|
|
58
|
+
let v = m[1].trim();
|
|
59
|
+
if (v.length >= 2 && v.startsWith('"') && v.endsWith('"')) {
|
|
60
|
+
try { v = JSON.parse(v); } catch { v = v.slice(1, -1); }
|
|
61
|
+
}
|
|
62
|
+
return v === "" ? null : v;
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 就地设置 frontmatter 顶层键:有则覆盖、无则追加在收尾 --- 之前(按传入顺序)。
|
|
69
|
+
*
|
|
70
|
+
* value 为 null / undefined / 空串 = **删掉**这个键,不留 `key:` 空行——「这一页是哪次
|
|
71
|
+
* 提交验证的,T1 没记下来」本身要能在文件里查得出来,而不是显示成一片空白。
|
|
72
|
+
* 没有 frontmatter 的正文原样返回:绝不给人写的坏文件凭空造一个块。
|
|
73
|
+
*
|
|
74
|
+
* @param {string} pageText
|
|
75
|
+
* @param {Array<[string, string|null]>} entries
|
|
76
|
+
*/
|
|
77
|
+
export function setFrontmatterKeys(pageText, entries) {
|
|
78
|
+
const lines = String(pageText ?? "").split("\n");
|
|
79
|
+
const bounds = frontmatterBounds(lines);
|
|
80
|
+
if (!bounds) return String(pageText ?? "");
|
|
81
|
+
const pending = new Map(entries.map(([k, v]) => [k, v === undefined || v === null || String(v).trim() === "" ? null : String(v)]));
|
|
82
|
+
const out = lines.slice(0, bounds.open + 1);
|
|
83
|
+
for (let i = bounds.open + 1; i < bounds.close; i++) {
|
|
84
|
+
const m = /^([A-Za-z_][\w-]*)\s*:/.exec(lines[i]);
|
|
85
|
+
if (m && pending.has(m[1])) {
|
|
86
|
+
const v = pending.get(m[1]);
|
|
87
|
+
pending.delete(m[1]);
|
|
88
|
+
if (v !== null) out.push(`${m[1]}: ${v}`);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
out.push(lines[i]);
|
|
92
|
+
}
|
|
93
|
+
for (const [k, v] of pending) {
|
|
94
|
+
if (v !== null) out.push(`${k}: ${v}`);
|
|
95
|
+
}
|
|
96
|
+
out.push(...lines.slice(bounds.close));
|
|
97
|
+
return out.join("\n");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** 抽出全部保留区。返回 { blocks: string[](含标记本身,原样), count }。 */
|
|
101
|
+
export function extractHumanBlocks(pageText) {
|
|
102
|
+
if (typeof pageText !== "string") return { blocks: [], count: 0 };
|
|
103
|
+
const blocks = [];
|
|
104
|
+
const re = new RegExp(`${escapeRegExp(HUMAN_START)}[\\s\\S]*?${escapeRegExp(HUMAN_END)}`, "g");
|
|
105
|
+
let m;
|
|
106
|
+
while ((m = re.exec(pageText)) !== null) blocks.push(m[0]);
|
|
107
|
+
return { blocks, count: blocks.length };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** 新正文 + 保留区(按原顺序接在页尾,各隔一个空行)。 */
|
|
111
|
+
export function injectHumanBlocks(newContent, blocks) {
|
|
112
|
+
if (!blocks || blocks.length === 0) return newContent;
|
|
113
|
+
return `${newContent.replace(/\n*$/, "\n")}\n${blocks.join("\n\n")}\n`;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 渲染一页骨架。meta: { slug, title, parents[], sourceFiles[], gitBaseline,
|
|
118
|
+
* generatedAt, status };mod 是 partition 的产物。
|
|
119
|
+
*/
|
|
120
|
+
export function renderSkeletonPage(mod, meta) {
|
|
121
|
+
const lines = [];
|
|
122
|
+
lines.push("---");
|
|
123
|
+
lines.push("choro: v1");
|
|
124
|
+
lines.push(`slug: ${meta.slug}`);
|
|
125
|
+
lines.push(`title: ${yamlScalar(meta.title)}`);
|
|
126
|
+
if (meta.parents && meta.parents.length > 0) {
|
|
127
|
+
lines.push("parents:");
|
|
128
|
+
for (const p of meta.parents) lines.push(` - ${p}`);
|
|
129
|
+
} else {
|
|
130
|
+
lines.push("parents: []");
|
|
131
|
+
}
|
|
132
|
+
lines.push("sourceFiles:");
|
|
133
|
+
for (const f of meta.sourceFiles) lines.push(` - ${f}`);
|
|
134
|
+
lines.push(`gitBaseline: ${meta.gitBaseline}`);
|
|
135
|
+
lines.push(`templateVersion: ${TEMPLATE_VERSION}`);
|
|
136
|
+
lines.push(`language: ${meta.language ?? "zh"}`);
|
|
137
|
+
lines.push(`status: ${meta.status}`);
|
|
138
|
+
lines.push(`generatedAt: ${meta.generatedAt}`);
|
|
139
|
+
lines.push("---");
|
|
140
|
+
lines.push("");
|
|
141
|
+
lines.push(`# ${meta.title}`);
|
|
142
|
+
lines.push("");
|
|
143
|
+
// 注意:这行说明里**不得出现成对的标记字面量**——抽取用的是全局正则,说明行
|
|
144
|
+
// 里一旦同时含 START 与 END,下一轮重生成就会把它当成一块保留区接在页尾
|
|
145
|
+
// (实测:第二轮页面凭空多两行)。所以说标记时用名字,不用原文。
|
|
146
|
+
lines.push(
|
|
147
|
+
`> 确定性骨架(T0,零模型):由文件树与 import 图生成。` +
|
|
148
|
+
`CHORO:HUMAN 标记对(START/END 两个 HTML 注释)包住的内容在重生成时逐字节保留;` +
|
|
149
|
+
`标记对之外的手改不保留(想保住一段就把它挪进标记对里)。`
|
|
150
|
+
);
|
|
151
|
+
lines.push("");
|
|
152
|
+
lines.push(`## 文件清单(${mod.fileCount} 个)`);
|
|
153
|
+
lines.push("");
|
|
154
|
+
lines.push("| 文件 | 行数 |");
|
|
155
|
+
lines.push("| --- | ---: |");
|
|
156
|
+
for (const [file, lines2] of mod.fileLines) lines.push(`| ${file} | ${lines2} |`);
|
|
157
|
+
lines.push("");
|
|
158
|
+
lines.push("## 入口");
|
|
159
|
+
lines.push("");
|
|
160
|
+
if (mod.entries.length > 0) {
|
|
161
|
+
for (const e of mod.entries) lines.push(`- \`${e}\``);
|
|
162
|
+
} else {
|
|
163
|
+
lines.push("- 无(没有 index/main 命名的文件,也不是包入口)");
|
|
164
|
+
}
|
|
165
|
+
lines.push("");
|
|
166
|
+
lines.push("## 内部依赖");
|
|
167
|
+
lines.push("");
|
|
168
|
+
if (mod.upstream.length > 0) {
|
|
169
|
+
lines.push(`- 上游依赖(本模块引用的模块):${mod.upstream.map((s) => `\`${s}\``).join("、")}`);
|
|
170
|
+
}
|
|
171
|
+
if (mod.downstream.length > 0) {
|
|
172
|
+
lines.push(`- 下游(引用本模块的模块):${mod.downstream.map((s) => `\`${s}\``).join("、")}`);
|
|
173
|
+
}
|
|
174
|
+
if (mod.upstream.length === 0 && mod.downstream.length === 0) {
|
|
175
|
+
lines.push("- 无内部依赖边(孤立模块)");
|
|
176
|
+
}
|
|
177
|
+
lines.push("");
|
|
178
|
+
lines.push("## 外部依赖");
|
|
179
|
+
lines.push("");
|
|
180
|
+
if (mod.externalDeps.length > 0) {
|
|
181
|
+
for (const d of mod.externalDeps) lines.push(`- \`${d.pkg}\` ×${d.count}`);
|
|
182
|
+
} else {
|
|
183
|
+
lines.push("- 无外部 npm 依赖");
|
|
184
|
+
}
|
|
185
|
+
lines.push("");
|
|
186
|
+
lines.push("## 生成说明");
|
|
187
|
+
lines.push("");
|
|
188
|
+
lines.push(
|
|
189
|
+
`- 模块划分:目录初稿 + 兄弟组内聚合并(内部边 ≥3),超上限逐级下切;` +
|
|
190
|
+
`本组 ${mod.fileCount} 个文件。`
|
|
191
|
+
);
|
|
192
|
+
if (mod.unresolvedCount > 0) {
|
|
193
|
+
lines.push(`- ${mod.unresolvedCount} 条相对引用没有解析到仓库内文件(别名/动态路径),未计入依赖图。`);
|
|
194
|
+
}
|
|
195
|
+
lines.push("");
|
|
196
|
+
return lines.join("\n");
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** index.md:模块目录 + 仓库级信息。同样零时间戳(时刻在 state.json)。 */
|
|
200
|
+
export function renderIndex(modules, repoMeta) {
|
|
201
|
+
const lines = [];
|
|
202
|
+
lines.push("---");
|
|
203
|
+
lines.push("choro: v1");
|
|
204
|
+
lines.push(`repo: ${yamlScalar(repoMeta.name)}`);
|
|
205
|
+
lines.push(`gitBaseline: ${repoMeta.gitBaseline}`);
|
|
206
|
+
lines.push(`templateVersion: ${TEMPLATE_VERSION}`);
|
|
207
|
+
lines.push(`generatedAt: ${repoMeta.generatedAt}`);
|
|
208
|
+
lines.push("language: zh");
|
|
209
|
+
lines.push("---");
|
|
210
|
+
lines.push("");
|
|
211
|
+
lines.push(`# ${repoMeta.name} · 仓库地志`);
|
|
212
|
+
lines.push("");
|
|
213
|
+
lines.push(
|
|
214
|
+
`T0 确定性骨架(零模型)。页面在 \`modules/\` 下,真源是本目录的 Markdown;` +
|
|
215
|
+
`本文件整页机器所有、可随时重算(spec §4)。`
|
|
216
|
+
);
|
|
217
|
+
lines.push("");
|
|
218
|
+
lines.push(`- 扫描 ${repoMeta.fileCount} 个文件,划出 ${modules.length} 个模块。`);
|
|
219
|
+
if (repoMeta.skipped > 0) lines.push(`- ${repoMeta.skipped} 个文件读取失败,已跳过(页脚与 receipt 都有记)。`);
|
|
220
|
+
if (repoMeta.unresolved > 0) lines.push(`- ${repoMeta.unresolved} 条相对引用未解析(别名/动态路径),未计入依赖图。`);
|
|
221
|
+
lines.push("");
|
|
222
|
+
lines.push("## 模块目录");
|
|
223
|
+
lines.push("");
|
|
224
|
+
lines.push("| 模块 | 页面 | 文件数 | 内部边 | 外部依赖 |");
|
|
225
|
+
lines.push("| --- | --- | ---: | ---: | ---: |");
|
|
226
|
+
for (const mod of modules) {
|
|
227
|
+
const pageRel = `modules/${mod.slug}.md`;
|
|
228
|
+
lines.push(
|
|
229
|
+
`| ${mod.title} | [${mod.slug}](${pageRel}) | ${mod.fileCount} | ` +
|
|
230
|
+
`${mod.internalEdges.length} | ${mod.externalDeps.length} |`
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
lines.push("");
|
|
234
|
+
lines.push("## 脚本命令(根 package.json)");
|
|
235
|
+
lines.push("");
|
|
236
|
+
const scriptNames = Object.keys(repoMeta.scripts ?? {}).sort();
|
|
237
|
+
if (scriptNames.length > 0) {
|
|
238
|
+
lines.push("| 命令 | 内容 |");
|
|
239
|
+
lines.push("| --- | --- |");
|
|
240
|
+
for (const name of scriptNames) lines.push(`| \`${name}\` | ${escapeCell(String(repoMeta.scripts[name]))} |`);
|
|
241
|
+
} else {
|
|
242
|
+
lines.push("- 无 scripts 字段或没有根 package.json。");
|
|
243
|
+
}
|
|
244
|
+
lines.push("");
|
|
245
|
+
return lines.join("\n");
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// YAML 标量:含冒号/引号等特殊字符时加引号(frontmatter 里的 title/repo 是人名或
|
|
249
|
+
// 目录名,通常无害,但这层便宜且省掉转义 bug)。
|
|
250
|
+
function yamlScalar(text) {
|
|
251
|
+
const s = String(text ?? "");
|
|
252
|
+
return /[:#'\"[\]{},&*?|>%@`]/.test(s) || s.trim() !== s ? JSON.stringify(s) : s;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function escapeCell(text) {
|
|
256
|
+
return text.replace(/\|/g, "\\|").replace(/\n/g, " ");
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function escapeRegExp(text) {
|
|
260
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
261
|
+
}
|