@modusensus/dsh-mneme 0.13.0 → 0.14.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +830 -828
- package/assets/icon.svg +3 -3
- package/bin/cli.mjs +964 -964
- package/bin/dsh-mneme-choro.mjs +262 -254
- package/bin/dsh-mneme-mcp.mjs +510 -510
- package/bin/dsh-mneme-serve.mjs +151 -151
- package/cordis.patch.yml +21 -21
- package/docs/CONFIGURATION.md +407 -402
- package/docs/CONTINUITY.md +139 -139
- package/docs/DAEMON.md +57 -57
- package/docs/DIRECTORIES.md +114 -114
- package/docs/DISTILL.md +397 -371
- package/docs/DSH-GO.md +97 -97
- package/docs/ENTITIES.md +247 -247
- package/docs/FORGET.md +77 -77
- package/docs/KB.md +110 -110
- package/docs/LOCAL_MODEL.md +222 -222
- package/docs/SEMANTIC.md +256 -256
- package/docs/SHARE.md +552 -552
- package/docs/SLEEP.md +202 -202
- package/docs/STORAGE.md +122 -122
- package/docs/WORKFLOWS.md +366 -366
- package/lib/api-standalone.js +1007 -1007
- package/lib/api.js +3600 -3394
- package/lib/attachment-text.js +122 -122
- package/lib/bootstrap-http.js +105 -105
- package/lib/bootstrap.js +215 -215
- package/lib/candidates.js +454 -454
- package/lib/capabilities.js +819 -819
- package/lib/choro-command.js +111 -111
- package/lib/client.js +14420 -13436
- package/lib/commands.js +95 -95
- package/lib/config-keys.js +144 -144
- package/lib/config.js +1361 -1317
- package/lib/content-hash.js +54 -54
- package/lib/continuity.js +258 -258
- package/lib/date-hint.js +32 -0
- package/lib/diary/auto.js +190 -190
- package/lib/diary/compose.js +440 -440
- package/lib/diary/dir.js +59 -59
- package/lib/diary/export.js +97 -97
- package/lib/diary/index.js +26 -26
- package/lib/diary/library.js +189 -189
- package/lib/diary/qq-inbox.js +142 -142
- package/lib/diary/rollover.js +61 -61
- package/lib/diary/session-provider.js +122 -122
- package/lib/document-index.js +94 -94
- package/lib/document.js +322 -322
- package/lib/dream/clustering.js +123 -123
- package/lib/dream/decisions.js +945 -907
- package/lib/dream/narratives.js +44 -44
- package/lib/dream/sleep.js +2027 -1887
- package/lib/dream/triage.js +139 -0
- package/lib/dream.js +1879 -1764
- package/lib/dsh-go/host.js +162 -162
- package/lib/dsh-go/panel.js +2091 -2091
- package/lib/dsh-go/text.js +342 -342
- package/lib/dsh-go/views/common.js +68 -68
- package/lib/dsh-go/views/entity.js +48 -48
- package/lib/dsh-go/views/memory.js +198 -198
- package/lib/dsh-go/views/root.js +30 -30
- package/lib/dsh-go/views/settings.js +398 -398
- package/lib/dsh-go/views/status.js +51 -51
- package/lib/embedding.js +342 -342
- package/lib/entities/extractor.js +285 -285
- package/lib/fence.js +24 -24
- package/lib/graph/anchoring.js +184 -184
- package/lib/guide.js +74 -74
- package/lib/heat.js +144 -144
- package/lib/hot-memory.js +119 -107
- package/lib/image-describe.js +158 -0
- package/lib/index.js +852 -822
- package/lib/inject.js +656 -639
- package/lib/kb/index.js +309 -309
- package/lib/kb/routes.js +219 -219
- package/lib/kb/tools.js +148 -148
- package/lib/lang.js +607 -584
- package/lib/local-embedder.js +358 -358
- package/lib/maintenance.js +162 -162
- package/lib/memory-source.js +9 -9
- package/lib/mirror.js +330 -330
- package/lib/organize.js +456 -456
- package/lib/peak-hours.js +172 -172
- package/lib/pipeline-activities.js +178 -178
- package/lib/pipeline-attribution.js +165 -165
- package/lib/pipeline-command.js +279 -279
- package/lib/pipeline-confirm.js +142 -142
- package/lib/pipeline-exec.js +174 -174
- package/lib/pipeline-nudge-auto.js +129 -129
- package/lib/pipeline-nudge.js +1623 -1623
- package/lib/pipeline-observations.js +181 -181
- package/lib/pipeline-observe.js +133 -133
- package/lib/pipeline-runner.js +361 -361
- package/lib/pipeline-runs.js +442 -442
- package/lib/pipeline.js +716 -716
- package/lib/placement.js +13 -13
- package/lib/pre-inject-gate.js +354 -354
- package/lib/profile-extract.js +164 -164
- package/lib/profile-facts.js +356 -356
- package/lib/provenance-http.js +251 -251
- package/lib/quality-filter.js +162 -162
- package/lib/recall-stats.js +190 -190
- package/lib/reclaim-http.js +150 -150
- package/lib/reranker.js +269 -269
- package/lib/runtime/adopt.js +176 -176
- package/lib/runtime/closure.js +172 -172
- package/lib/runtime/download.js +247 -247
- package/lib/runtime/layout.js +265 -265
- package/lib/runtime/loader.js +252 -252
- package/lib/runtime/model-fetch.js +361 -361
- package/lib/runtime/provision.js +237 -237
- package/lib/runtime/tarball.js +130 -130
- package/lib/runtime/verify.js +223 -223
- package/lib/safe-slice.js +18 -18
- package/lib/scope-state.js +277 -277
- package/lib/scope.js +187 -187
- package/lib/search/adaptive.js +60 -60
- package/lib/search/bm25.js +96 -96
- package/lib/semantic.js +572 -572
- package/lib/sensitive-scan.js +209 -209
- package/lib/serve.js +228 -228
- package/lib/service.js +3268 -3196
- package/lib/session-gate.js +91 -91
- package/lib/session-usage.js +350 -350
- package/lib/settings.js +827 -802
- package/lib/share-http.js +281 -281
- package/lib/share-import.js +234 -234
- package/lib/share.js +335 -335
- package/lib/store.js +5895 -5662
- package/lib/summarize.js +1388 -1343
- package/lib/tools.js +1370 -1356
- package/lib/user-settings.js +230 -230
- package/lib/vector-index.js +180 -180
- package/lib/version-check.js +122 -122
- package/lib/wiki/claims.js +267 -0
- package/lib/wiki/cli-hint.js +90 -90
- package/lib/wiki/inject.js +164 -164
- package/lib/wiki/partition.js +200 -200
- package/lib/wiki/plan.js +214 -214
- package/lib/wiki/queries.js +640 -474
- package/lib/wiki/render.js +261 -187
- package/lib/wiki/scan.js +371 -371
- package/lib/wiki/t0.js +500 -463
- package/lib/wiki/t1-jobs.js +232 -232
- package/lib/wiki/t1.js +609 -502
- package/lib/write-admission.js +404 -404
- package/locale/en.json +6 -6
- package/locale/zh.json +6 -6
- package/package.json +15 -1
- package/runtime-manifest.json +526 -526
- package/scripts/benchmark-embed.js +201 -201
- package/scripts/benchmark-recall.js +249 -249
- package/scripts/benchmark-rerank.js +166 -166
- package/scripts/build-runtime-manifest.mjs +224 -224
- package/scripts/changelog-prep.mjs +91 -91
- package/scripts/check-sync.js +44 -44
- package/scripts/e2e-dsh.js +220 -220
- package/scripts/mneme-runtime.mjs +277 -277
- package/scripts/publish-gate.mjs +197 -197
- package/scripts/release-docs.mjs +210 -204
- package/scripts/release-notes.mjs +164 -161
- package/scripts/stress-dsh.js +255 -255
- package/scripts/sync-lib.js +47 -47
- package/scripts/sync-test-badge.mjs +69 -69
- package/scripts/test-count-sync.mjs +48 -48
- package/src/api-standalone.js +1007 -1007
- package/src/api.js +3600 -3394
- package/src/attachment-text.js +122 -122
- package/src/bootstrap-http.js +105 -105
- package/src/bootstrap.js +215 -215
- package/src/candidates.js +454 -454
- package/src/capabilities.js +819 -819
- package/src/choro-command.js +111 -111
- package/src/commands.js +95 -95
- package/src/config-keys.js +144 -144
- package/src/config.js +1361 -1317
- package/src/content-hash.js +54 -54
- package/src/continuity.js +258 -258
- package/src/date-hint.js +32 -0
- package/src/diary/auto.js +190 -190
- package/src/diary/compose.js +440 -440
- package/src/diary/dir.js +59 -59
- package/src/diary/export.js +97 -97
- package/src/diary/index.js +26 -26
- package/src/diary/library.js +189 -189
- package/src/diary/qq-inbox.js +142 -142
- package/src/diary/rollover.js +61 -61
- package/src/diary/session-provider.js +122 -122
- package/src/document-index.js +94 -94
- package/src/document.js +322 -322
- package/src/dream/clustering.js +123 -123
- package/src/dream/decisions.js +945 -907
- package/src/dream/narratives.js +44 -44
- package/src/dream/sleep.js +2027 -1887
- package/src/dream/triage.js +139 -0
- package/src/dream.js +1879 -1764
- package/src/dsh-go/host.js +162 -162
- package/src/dsh-go/panel.js +2091 -2091
- package/src/dsh-go/text.js +342 -342
- package/src/dsh-go/views/common.js +68 -68
- package/src/dsh-go/views/entity.js +48 -48
- package/src/dsh-go/views/memory.js +198 -198
- package/src/dsh-go/views/root.js +30 -30
- package/src/dsh-go/views/settings.js +398 -398
- package/src/dsh-go/views/status.js +51 -51
- package/src/embedding.js +342 -342
- package/src/entities/extractor.js +285 -285
- package/src/fence.js +24 -24
- package/src/graph/anchoring.js +184 -184
- package/src/guide.js +74 -74
- package/src/heat.js +144 -144
- package/src/hot-memory.js +119 -107
- package/src/image-describe.js +158 -0
- package/src/index.js +852 -822
- package/src/inject.js +656 -639
- package/src/kb/index.js +309 -309
- package/src/kb/routes.js +219 -219
- package/src/kb/tools.js +148 -148
- package/src/lang.js +607 -584
- package/src/local-embedder.js +358 -358
- package/src/maintenance.js +162 -162
- package/src/memory-source.js +9 -9
- package/src/mirror.js +330 -330
- package/src/organize.js +456 -456
- package/src/peak-hours.js +172 -172
- package/src/pipeline-activities.js +178 -178
- package/src/pipeline-attribution.js +165 -165
- package/src/pipeline-command.js +279 -279
- package/src/pipeline-confirm.js +142 -142
- package/src/pipeline-exec.js +174 -174
- package/src/pipeline-nudge-auto.js +129 -129
- package/src/pipeline-nudge.js +1623 -1623
- package/src/pipeline-observations.js +181 -181
- package/src/pipeline-observe.js +133 -133
- package/src/pipeline-runner.js +361 -361
- package/src/pipeline-runs.js +442 -442
- package/src/pipeline.js +716 -716
- package/src/placement.js +13 -13
- package/src/pre-inject-gate.js +354 -354
- package/src/profile-extract.js +164 -164
- package/src/profile-facts.js +356 -356
- package/src/provenance-http.js +251 -251
- package/src/quality-filter.js +162 -162
- package/src/recall-stats.js +190 -190
- package/src/reclaim-http.js +150 -150
- package/src/reranker.js +269 -269
- package/src/runtime/adopt.js +176 -176
- package/src/runtime/closure.js +172 -172
- package/src/runtime/download.js +247 -247
- package/src/runtime/layout.js +265 -265
- package/src/runtime/loader.js +252 -252
- package/src/runtime/model-fetch.js +361 -361
- package/src/runtime/provision.js +237 -237
- package/src/runtime/tarball.js +130 -130
- package/src/runtime/verify.js +223 -223
- package/src/safe-slice.js +18 -18
- package/src/scope-state.js +277 -277
- package/src/scope.js +187 -187
- package/src/search/adaptive.js +60 -60
- package/src/search/bm25.js +96 -96
- package/src/semantic.js +572 -572
- package/src/sensitive-scan.js +209 -209
- package/src/serve.js +228 -228
- package/src/service.js +3268 -3196
- package/src/session-gate.js +91 -91
- package/src/session-usage.js +350 -350
- package/src/settings.js +827 -802
- package/src/share-http.js +281 -281
- package/src/share-import.js +234 -234
- package/src/share.js +335 -335
- package/src/store.js +5895 -5662
- package/src/summarize.js +1388 -1343
- package/src/tools.js +1370 -1356
- package/src/user-settings.js +230 -230
- package/src/vector-index.js +180 -180
- package/src/version-check.js +122 -122
- package/src/wiki/claims.js +267 -0
- package/src/wiki/cli-hint.js +90 -90
- package/src/wiki/inject.js +164 -164
- package/src/wiki/partition.js +200 -200
- package/src/wiki/plan.js +214 -214
- package/src/wiki/queries.js +640 -474
- package/src/wiki/render.js +261 -187
- package/src/wiki/scan.js +371 -371
- package/src/wiki/t0.js +500 -463
- package/src/wiki/t1-jobs.js +232 -232
- package/src/wiki/t1.js +609 -502
- package/src/write-admission.js +404 -404
- package/test/adaptive-inject-budget.test.js +85 -85
- package/test/api-hardening.test.js +173 -173
- package/test/api-nudge-route.test.js +259 -259
- package/test/api-routes-gaps.test.js +1092 -1092
- package/test/api.test.js +3007 -2988
- package/test/attachment-text.test.js +139 -139
- package/test/audit.test.js +448 -448
- package/test/baseline-persist.test.js +248 -248
- package/test/benchmark.test.js +94 -94
- package/test/bm25-corpus-cache.test.js +145 -145
- package/test/bootstrap.test.js +228 -228
- package/test/candidates.test.js +345 -345
- package/test/capabilities.test.js +577 -577
- package/test/capacity-warning.test.js +262 -262
- package/test/changelog-prep.test.js +125 -125
- package/test/choro-command.test.js +218 -218
- package/test/cli-enums.test.js +37 -37
- package/test/cli-flag-value.test.js +86 -86
- package/test/cli-receive.test.js +390 -390
- package/test/cli-share.test.js +437 -437
- package/test/client-share.test.js +225 -225
- package/test/client.test.js +4595 -4184
- package/test/clustering.test.js +100 -100
- package/test/commands.test.js +106 -106
- package/test/config-keys-routes.test.js +233 -233
- package/test/config.test.js +153 -153
- package/test/conflict-freeze.test.js +344 -344
- package/test/conflict-ledger-enforce.test.js +452 -0
- package/test/conflict-ledger.test.js +242 -0
- package/test/conflict-reviewed.test.js +79 -79
- package/test/content-hash.test.js +204 -204
- package/test/continuity.test.js +452 -452
- package/test/contrast.test.js +432 -320
- package/test/date-hint.test.js +156 -0
- package/test/dedupe-candidate-window.test.js +180 -180
- package/test/dependency-overrides.test.js +78 -78
- package/test/diary-library.test.js +187 -187
- package/test/diary.test.js +576 -576
- package/test/differentiate-feedback.test.js +248 -248
- package/test/distill-tx-embed-gap.test.js +110 -110
- package/test/docs-config-keys.test.js +65 -65
- package/test/document-dir.test.js +233 -233
- package/test/document.test.js +703 -703
- package/test/dream-archive-guardrail.test.js +116 -116
- package/test/dream-baseline-clamp.test.js +174 -0
- package/test/dream-candidate-hybrid.test.js +281 -281
- package/test/dream-coverage-degrade.test.js +86 -86
- package/test/dream-decision-evidence.test.js +314 -314
- package/test/dream-failure-backoff.test.js +173 -173
- package/test/dream-fence.test.js +207 -207
- package/test/dream-maxtokens-fallback.test.js +132 -132
- package/test/dream-merge-guardrail.test.js +219 -219
- package/test/dream-peak-hours.test.js +194 -194
- package/test/dream.test.js +1528 -1528
- package/test/dsh-go-host.test.js +134 -134
- package/test/dsh-go-panel-actions.test.js +854 -854
- package/test/dsh-go-panel.test.js +251 -251
- package/test/embed-ready-poll.test.js +94 -94
- package/test/embed-text-reasons.test.js +112 -112
- package/test/embedding-cache-f32.test.js +276 -276
- package/test/embedding-ready.test.js +226 -226
- package/test/entities.test.js +711 -711
- package/test/entity-recall.test.js +179 -179
- package/test/epistemic.test.js +325 -325
- package/test/failure-query.test.js +147 -147
- package/test/failure-retention.test.js +105 -105
- package/test/fnew-0112.test.js +311 -311
- package/test/fnew-03.test.js +422 -422
- package/test/forget-corrections.test.js +70 -70
- package/test/graph-anchoring.test.js +184 -184
- package/test/graph-api.test.js +333 -209
- package/test/graph-boosted-relations.test.js +189 -189
- package/test/graph-inject-budget.test.js +103 -103
- package/test/graph-multipath.test.js +269 -269
- package/test/graph-passive-confirm.test.js +91 -91
- package/test/graph-weight-evolution.test.js +104 -104
- package/test/heat.test.js +175 -175
- package/test/helpers/dream-mock.js +86 -86
- package/test/helpers/peer-worker.mjs +25 -25
- package/test/helpers/runtime-source.js +60 -60
- package/test/helpers/tar-builder.js +80 -80
- package/test/helpers/write-admission-samples.js +312 -312
- package/test/hot-memory.test.js +259 -211
- package/test/image-description.test.js +271 -0
- package/test/image-memory.test.js +170 -170
- package/test/inject-content-cap.test.js +91 -91
- package/test/inject-first-round-bm25.test.js +89 -89
- package/test/inject-heat.test.js +77 -77
- package/test/inject-parent-gate.test.js +134 -106
- package/test/inject-pin-explicit.test.js +300 -300
- package/test/inject-pin-vector-crowd.test.js +225 -225
- package/test/inject-pools.test.js +195 -195
- package/test/inject-recall.test.js +172 -172
- package/test/inject-rotation.test.js +161 -161
- package/test/inject.test.js +553 -494
- package/test/issue-617-step1-query-and-fusion.test.js +361 -361
- package/test/kb-api-wiring.test.js +128 -128
- package/test/kb-collections.test.js +272 -272
- package/test/kb-routes.test.js +379 -379
- package/test/lang.test.js +98 -98
- package/test/lastrunat-persist.test.js +101 -101
- package/test/lib-smoke.test.js +116 -116
- package/test/llm-audit.test.js +815 -815
- package/test/llm-message-source.test.js +207 -207
- package/test/local-embedder.test.js +292 -292
- package/test/maintenance.test.js +501 -501
- package/test/mcp-stdio.test.js +385 -385
- package/test/mint-source.test.js +311 -311
- package/test/mirror-dirty.test.js +424 -424
- package/test/mirror-edit-digest.test.js +187 -187
- package/test/mirror-generation.test.js +499 -499
- package/test/mirror-types.test.js +208 -208
- package/test/mirror.test.js +249 -249
- package/test/narrative-bars.test.js +162 -162
- package/test/organize-tool.test.js +232 -232
- package/test/organize.test.js +418 -418
- package/test/panel-chart-scale.test.js +90 -0
- package/test/panel-tokens.test.js +245 -0
- package/test/peak-hours-observability.test.js +70 -70
- package/test/peer-blockers.test.js +193 -193
- package/test/persona-addressing.test.js +83 -83
- package/test/persona-api.test.js +172 -172
- package/test/persona-by-session.test.js +568 -568
- package/test/persona-flag.test.js +36 -36
- package/test/persona-inject.test.js +145 -145
- package/test/persona-settings.test.js +198 -198
- package/test/pipeline-activities.test.js +155 -155
- package/test/pipeline-attribution.test.js +175 -175
- package/test/pipeline-command.test.js +243 -243
- package/test/pipeline-confirm.test.js +148 -148
- package/test/pipeline-exec.test.js +172 -172
- package/test/pipeline-nudge-auto.test.js +248 -248
- package/test/pipeline-nudge.test.js +1278 -1278
- package/test/pipeline-observations.test.js +157 -157
- package/test/pipeline-observe.test.js +127 -127
- package/test/pipeline-r1r2.test.js +278 -278
- package/test/pipeline-runner.test.js +468 -468
- package/test/pipeline-runs.test.js +767 -767
- package/test/pipeline.test.js +636 -636
- package/test/placement.test.js +36 -36
- package/test/policy-epoch.test.js +259 -259
- package/test/pre-inject-gate.test.js +444 -444
- package/test/profile-extract.test.js +269 -269
- package/test/profile-facts.test.js +492 -492
- package/test/prompt-stance.test.js +128 -128
- package/test/provenance-http.test.js +367 -367
- package/test/publish-gate.test.js +272 -272
- package/test/quality-backfill.test.js +290 -290
- package/test/quality-filter.test.js +295 -295
- package/test/readme-claims.test.js +113 -113
- package/test/reasoning-effort.test.js +752 -752
- package/test/recall-anti-update.test.js +82 -82
- package/test/recall-evals.test.js +253 -253
- package/test/recall-layer.test.js +326 -326
- package/test/recall-retention.test.js +128 -128
- package/test/recall-stats.test.js +274 -274
- package/test/receipt-chain.test.js +451 -451
- package/test/reclaim-http.test.js +209 -209
- package/test/reflection-update-gate.test.js +129 -129
- package/test/reflection.test.js +226 -226
- package/test/reindex-backfill.test.js +475 -475
- package/test/reindex-scheduler.test.js +369 -369
- package/test/release-docs.test.js +156 -136
- package/test/release-notes.test.js +265 -240
- package/test/release-workflow.test.js +93 -93
- package/test/reranker-single-logit.test.js +73 -73
- package/test/reranker.test.js +197 -197
- package/test/resident-status.test.js +83 -83
- package/test/route-policy.test.js +113 -113
- package/test/runtime-adopt.test.js +206 -206
- package/test/runtime-cli.test.js +89 -89
- package/test/runtime-closure.test.js +193 -193
- package/test/runtime-download.test.js +302 -302
- package/test/runtime-layout.test.js +163 -163
- package/test/runtime-loader.test.js +255 -255
- package/test/runtime-manifest.test.js +159 -159
- package/test/runtime-model-fetch.test.js +348 -348
- package/test/runtime-provision.test.js +101 -101
- package/test/runtime-tarball.test.js +81 -81
- package/test/runtime-verify.test.js +319 -319
- package/test/scope-candidates.test.js +491 -491
- package/test/scope-distill-stamp.test.js +134 -134
- package/test/scope-explicit.test.js +452 -452
- package/test/scope-inject-soft.test.js +106 -106
- package/test/scope-optional-service.test.js +110 -110
- package/test/scope-retrieval.test.js +197 -197
- package/test/scope-state.test.js +610 -610
- package/test/scope-storage.test.js +255 -255
- package/test/scope-strict.test.js +367 -367
- package/test/search-fusion.test.js +90 -90
- package/test/security-doc.test.js +188 -178
- package/test/semantic.test.js +124 -124
- package/test/sensitive-scan.test.js +251 -251
- package/test/serve-bin.test.js +121 -121
- package/test/serve.test.js +258 -258
- package/test/service-search.test.js +174 -174
- package/test/service.test.js +410 -410
- package/test/session-gate.test.js +264 -264
- package/test/session-usage.test.js +317 -317
- package/test/settings.test.js +273 -273
- package/test/share-foreign-rows.test.js +144 -144
- package/test/share-http.test.js +144 -144
- package/test/share-import.test.js +577 -577
- package/test/share-imported-guard.test.js +311 -311
- package/test/share-imported-identity.test.js +111 -111
- package/test/share-pack.test.js +511 -511
- package/test/share-receive-http.test.js +756 -756
- package/test/share-routes.test.js +337 -337
- package/test/share-store.test.js +133 -133
- package/test/share-validate.test.js +101 -101
- package/test/skip-invalid-restore.test.js +262 -262
- package/test/sleep-action-set.test.js +441 -441
- package/test/sleep-catchup.test.js +315 -315
- package/test/sleep-failure-backoff.test.js +156 -156
- package/test/sleep-heat.test.js +174 -174
- package/test/sleep-scheduler-rearm.test.js +89 -89
- package/test/sleep.test.js +1455 -1418
- package/test/standalone-api.test.js +1344 -1344
- package/test/store-vector-cache.test.js +98 -98
- package/test/store-write-path-columns.test.js +191 -191
- package/test/store.test.js +744 -744
- package/test/stress.test.js +209 -209
- package/test/summarize-occurred-at.test.js +127 -127
- package/test/summarize-parse-diagnostics.test.js +75 -75
- package/test/summarize-reasoning-effort.test.js +189 -189
- package/test/summarize.test.js +2251 -2251
- package/test/supersede-state-tracking.test.js +394 -394
- package/test/test-count-sync.test.js +71 -71
- package/test/tool-state-ignore.test.js +65 -65
- package/test/tools-dto-schema-matrix.test.js +398 -398
- package/test/tools-memory-get-schema.test.js +65 -65
- package/test/tools.test.js +585 -585
- package/test/updated-at-semantics.test.js +113 -113
- package/test/user-settings-preview.test.js +127 -127
- package/test/user-settings-segments.test.js +527 -527
- package/test/vector-index.test.js +334 -334
- package/test/version-check.test.js +152 -152
- package/test/webServer-optional.test.js +82 -82
- package/test/wiki-api.test.js +734 -627
- package/test/wiki-claims.test.js +194 -0
- package/test/wiki-cli-hint.test.js +118 -118
- package/test/wiki-inject.test.js +265 -265
- package/test/wiki-partition.test.js +112 -112
- package/test/wiki-plan.test.js +80 -80
- package/test/wiki-provenance.test.js +202 -0
- package/test/wiki-queries.test.js +398 -277
- package/test/wiki-scan.test.js +208 -208
- package/test/wiki-store.test.js +190 -190
- package/test/wiki-t0.test.js +456 -380
- package/test/wiki-t1-jobs.test.js +125 -125
- package/test/wiki-t1.test.js +460 -235
- package/test/wiki-tools.test.js +176 -176
- package/test/workflow-guards.test.js +155 -155
- package/test/write-admission.test.js +668 -668
|
@@ -1,156 +1,156 @@
|
|
|
1
|
-
// 工作流配置的回归锁:安全扫描、发布权限、发版准备的注入面不能悄悄退回。
|
|
2
|
-
// 锁的都是「配置漂移」——CI 配置没有类型检查,改错了照样绿。
|
|
3
|
-
import test from "node:test";
|
|
4
|
-
import assert from "node:assert/strict";
|
|
5
|
-
import { readFileSync } from "node:fs";
|
|
6
|
-
import { fileURLToPath } from "node:url";
|
|
7
|
-
import path from "node:path";
|
|
8
|
-
|
|
9
|
-
const repoRoot = path.dirname(path.dirname(path.dirname(fileURLToPath(import.meta.url))));
|
|
10
|
-
|
|
11
|
-
test("security.yml 的 osv-scanner 保持 fail-on-vuln: true", () => {
|
|
12
|
-
// 2026-10 审计:这里原本是 false(纯提醒,PR 上永远是绿的)。改回 false 就等于
|
|
13
|
-
// 「有已知漏洞也不红」,而测试目录原本没有任何东西会察觉这件事。
|
|
14
|
-
const yml = readFileSync(path.join(repoRoot, ".github", "workflows", "security.yml"), "utf8");
|
|
15
|
-
assert.match(yml, /fail-on-vuln:\s*true/, "osv-scanner 必须保持 fail-on-vuln: true");
|
|
16
|
-
assert.doesNotMatch(yml, /fail-on-vuln:\s*false/, "不得退回只上传 SARIF 不拦的档位");
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
// 剥掉整行注释再断言:注释里会**描述**「id-token: write 该发给谁」,
|
|
20
|
-
// 直接对全文 grep 会被自己写的说明文字骗过(第一版就栽在这里)。
|
|
21
|
-
function codeOnly(yml) {
|
|
22
|
-
return yml.split(/\r?\n/).filter((l) => !/^\s*#/.test(l)).join("\n");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// 按缩进切出单个 job 的文本块:工作流顶层是 0 缩进,job 名是 2 缩进。
|
|
26
|
-
// 只做文本切片不做完整 YAML 解析——仓库零依赖,为一条断言引 yaml 解析器不划算。
|
|
27
|
-
function jobBlock(yml, name) {
|
|
28
|
-
const lines = codeOnly(yml).split(/\r?\n/);
|
|
29
|
-
const start = lines.findIndex((l) => l === " " + name + ":");
|
|
30
|
-
assert.ok(start >= 0, "找不到 job: " + name);
|
|
31
|
-
let end = lines.length;
|
|
32
|
-
for (let i = start + 1; i < lines.length; i++) {
|
|
33
|
-
if (/^ [A-Za-z0-9_-]+:$/.test(lines[i])) { end = i; break; }
|
|
34
|
-
}
|
|
35
|
-
return lines.slice(start, end).join("\n");
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
test("release.yml 的 provenance 权限只发给 publish,不发给工作流顶层", () => {
|
|
39
|
-
// 三件事分开断言,因为「全文件 grep id-token: write」会被两种错误都骗过:
|
|
40
|
-
// ①有人把 id-token 提到工作流顶层(verify/test 也拿到 OIDC 能力)
|
|
41
|
-
// ②有人把 publish 的权限删了但别的 job 还有(provenance 会失败)
|
|
42
|
-
const yml = readFileSync(path.join(repoRoot, ".github", "workflows", "release.yml"), "utf8");
|
|
43
|
-
assert.match(yml, /npm publish[^\n]*--provenance/, "publish 必须带 --provenance");
|
|
44
|
-
|
|
45
|
-
// YAML 允许把顶层键写成 "jobs": 或 'jobs':,那也是合法的工作流。
|
|
46
|
-
// 只匹配裸 jobs: 会在那种写法下把整个文件当成 head,于是 publish 里合法的
|
|
47
|
-
// id-token 被误判成「顶层声明」——失败方向是误红不是漏检,但假红会磨损这条锁。
|
|
48
|
-
const head = codeOnly(yml).split(/\r?\n(?=["']?jobs["']?:\s*$)/m)[0];
|
|
49
|
-
assert.doesNotMatch(head, /id-token:/, "工作流顶层不得声明 id-token(会泄漏给所有 job)");
|
|
50
|
-
|
|
51
|
-
const publish = jobBlock(yml, "publish");
|
|
52
|
-
assert.match(publish, /id-token:\s*write/, "publish job 需要 id-token: write");
|
|
53
|
-
assert.doesNotMatch(publish, /contents:\s*write/, "publish 只读代码,不需要 contents: write");
|
|
54
|
-
|
|
55
|
-
const release = jobBlock(yml, "release");
|
|
56
|
-
assert.match(release, /contents:\s*write/, "release job 建 Release 需要 contents: write");
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
// 把每个 `run: |` 块的正文切出来。要断言的是「脚本正文里没有模板展开」,
|
|
60
|
-
// 而 run 块之外(env、with、name)出现 ${{ }} 是正常且必需的。
|
|
61
|
-
function runBlocks(yml) {
|
|
62
|
-
const lines = codeOnly(yml).split(/\r?\n/);
|
|
63
|
-
const blocks = [];
|
|
64
|
-
for (let i = 0; i < lines.length; i++) {
|
|
65
|
-
const m = /^(\s*)run:\s*\|\s*$/.exec(lines[i]);
|
|
66
|
-
if (!m) continue;
|
|
67
|
-
const indent = m[1].length;
|
|
68
|
-
let j = i + 1;
|
|
69
|
-
for (; j < lines.length; j++) {
|
|
70
|
-
const line = lines[j];
|
|
71
|
-
if (!line.trim()) continue;
|
|
72
|
-
if (line.match(/^\s*/)[0].length <= indent) break;
|
|
73
|
-
}
|
|
74
|
-
blocks.push(lines.slice(i + 1, j).join("\n"));
|
|
75
|
-
i = j - 1;
|
|
76
|
-
}
|
|
77
|
-
return blocks;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
test("release-prep.yml 的版本号走 env 注入,不内插进 run 脚本", () => {
|
|
81
|
-
// 2026-10 审计:zizmor 对 `--head "release-prep/${{ inputs.version }}"` 报 template-injection
|
|
82
|
-
// (模板展开可能带进攻击者可控的代码)。虽然上游 Validate 已用 ^[0-9]+\.[0-9]+\.[0-9]+$ 卡过格式,
|
|
83
|
-
// 但这里让扫描器看清「值不经过 shell 重解析」比让它推理上游校验够不够严便宜得多。
|
|
84
|
-
// 退回内插不会有任何测试变红,所以在这里锁住。
|
|
85
|
-
const yml = readFileSync(path.join(repoRoot, ".github", "workflows", "release-prep.yml"), "utf8");
|
|
86
|
-
assert.match(yml, /VERSION:\s*\$\{\{\s*inputs\.version\s*\}\}/, "版本号必须先进 env 再进脚本");
|
|
87
|
-
const blocks = runBlocks(yml);
|
|
88
|
-
assert.ok(blocks.length >= 3, "至少应切出 Validate / Count tests / Create PR 三个 run 块,实际 " + blocks.length);
|
|
89
|
-
for (const block of blocks) {
|
|
90
|
-
assert.doesNotMatch(block, /\$\{\{/, "run 脚本正文里不得出现模板展开:" + block.slice(0, 120));
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test("release-prep.yml 与 badge:sync 用同一个记账口径(套件总数,不是通过数)", () => {
|
|
95
|
-
// v0.8.11 徽章漂移的同类失效:两条路径各有一套口径时,谁都不知道该信哪个数。
|
|
96
|
-
// 徽章报的是 CI(ubuntu)口径——平台条件跳过的用例在 pass 里不计、在 tests 里计入,
|
|
97
|
-
// 于是从一台有跳过条件的机器上跑发版准备,会写进一个比 badge:sync 小 1 的徽章,
|
|
98
|
-
// 而且它进 PR 时 CI 是绿的(徽章只出现在文档里,没有测试会去比对它)。
|
|
99
|
-
const yml = readFileSync(path.join(repoRoot, ".github", "workflows", "release-prep.yml"), "utf8");
|
|
100
|
-
const blocks = runBlocks(yml);
|
|
101
|
-
const countBlock = blocks.find((b) => /node --test/.test(b));
|
|
102
|
-
assert.ok(countBlock, "应当能切出跑测试的那个 run 块");
|
|
103
|
-
assert.ok(countBlock.includes("tests [0-9]+"), "计数必须取 tests N(与 sync-test-badge.mjs 同口径)");
|
|
104
|
-
assert.ok(!countBlock.includes("pass [0-9]+"), "不得退回 pass N:那是另一套记账口径");
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test("发版准备的两份人写清单都点出跨 minor 要挪 SECURITY.md 支持版本表", () => {
|
|
108
|
-
// 跨 minor 时 security-doc.test.js 会红,而那时人往往已经忘了这张表——工作流开的 PR
|
|
109
|
-
// 就是最后一道能把话说清楚的时机。commit-msg 与 pr-body 是两份独立的文本,
|
|
110
|
-
// 少一份就等于一半的路径上没有提示(reviewer 只看 PR 正文,git log 只看提交信息)。
|
|
111
|
-
const yml = readFileSync(path.join(repoRoot, ".github", "workflows", "release-prep.yml"), "utf8");
|
|
112
|
-
const hits = yml.match(/SECURITY\.md 中英两张支持版本表/g) || [];
|
|
113
|
-
assert.equal(hits.length, 2, "commit message 与 PR 正文各要有一条,实际 " + hits.length);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
test("release-prep.yml 的重跑守卫:已有 PR 不动分支,只覆盖机器产出", () => {
|
|
117
|
-
// 2026-10-18 实测:工作流 8 步里前 7 步全成功,最后一步 git push 被
|
|
118
|
-
// "! [rejected] release-prep/0.9.1 -> release-prep/0.9.1 (fetch first)" 打回——
|
|
119
|
-
// 上一次运行已经把同名分支推上去了。不可重入的代价不是「重跑失败」这么轻:
|
|
120
|
-
// 人会以为流程坏了,转去手工发版,整套自动化就此被绕开。
|
|
121
|
-
//
|
|
122
|
-
// 但「能重跑」不能退化成「无条件 force push」:分支上可能已经有人补过 CHANGELOG
|
|
123
|
-
// 条目,那正是这套流程留给人的那部分工作,覆盖掉比不能重跑更糟。所以守卫分三档:
|
|
124
|
-
// 有进行中的 PR → 什么都不动;顶端是机器产出且没有 PR → 按重跑覆盖;其他 → 停下要人看。
|
|
125
|
-
const yml = readFileSync(path.join(repoRoot, ".github", "workflows", "release-prep.yml"), "utf8");
|
|
126
|
-
const blocks = runBlocks(yml);
|
|
127
|
-
const pushBlock = blocks.find((b) => /git push/.test(b));
|
|
128
|
-
assert.ok(pushBlock, "应当能切出含 git push 的那个 run 块");
|
|
129
|
-
|
|
130
|
-
const prLookup = pushBlock.indexOf('--state open');
|
|
131
|
-
const pushAt = pushBlock.indexOf("git push");
|
|
132
|
-
assert.ok(prLookup > 0, "重跑前必须查有没有进行中的 PR(gh pr list --state open)");
|
|
133
|
-
assert.ok(prLookup < pushAt, "查 PR 必须发生在 push 之前");
|
|
134
|
-
|
|
135
|
-
// 三档判定:没有 PR 才继续;继续时顶端提交必须是本工作流生成的。
|
|
136
|
-
assert.ok(pushBlock.includes("--force-with-lease="), "重跑覆盖必须用 --force-with-lease(锁住 fetch 到的 SHA)");
|
|
137
|
-
assert.ok(!/git push[^\n]*--force(?!-with-lease)/.test(pushBlock), "不得退回无条件 --force");
|
|
138
|
-
// 断言的是那个 if 本身,不是变量名:变量名留在 case 里、判定被删掉,
|
|
139
|
-
// 只查 includes("MACHINE_TAIL") 照样绿(第一版就是这么漏的)。
|
|
140
|
-
assert.match(pushBlock, /if \[ "\$MACHINE_TAIL" != "yes" \]; then/, "必须有「顶端不是机器产出就停下」的那道判定");
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
test("release-prep.yml 开 PR 失败时给的是可行动的报错,不是裸 GraphQL 报错", () => {
|
|
144
|
-
// 第二个真因(2026-10-18 实测):仓库级开关 can_approve_pull_request_reviews=false,
|
|
145
|
-
// job 里写 pull-requests: write 覆盖不了它,最后一步报
|
|
146
|
-
// "GitHub Actions is not permitted to create or approve pull requests"。
|
|
147
|
-
// 这个开关在**组织层**默认关着时仓库层根本改不动(gh api 返回 409 Conflict),
|
|
148
|
-
// 所以要让人一眼看出该去哪里开、开完能不能直接重跑。
|
|
149
|
-
const yml = readFileSync(path.join(repoRoot, ".github", "workflows", "release-prep.yml"), "utf8");
|
|
150
|
-
// 只在**可执行部分**里找:这几句话在注释里也出现过(注释是在解释为什么),
|
|
151
|
-
// 对全文 grep 会被自己写的说明文字骗过——报错文案被删干净了照样绿。
|
|
152
|
-
const code = codeOnly(yml);
|
|
153
|
-
assert.match(code, /not permitted to create or approve pull requests/, "报错文案要点名这个具体的 GitHub 报错,人才搜得到");
|
|
154
|
-
assert.match(code, /Settings → Actions → General/, "必须写清去哪个设置页开");
|
|
155
|
-
assert.match(code, /Allow GitHub Actions to create and approve pull requests/, "必须写清要打开的那个开关叫什么");
|
|
1
|
+
// 工作流配置的回归锁:安全扫描、发布权限、发版准备的注入面不能悄悄退回。
|
|
2
|
+
// 锁的都是「配置漂移」——CI 配置没有类型检查,改错了照样绿。
|
|
3
|
+
import test from "node:test";
|
|
4
|
+
import assert from "node:assert/strict";
|
|
5
|
+
import { readFileSync } from "node:fs";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
|
|
9
|
+
const repoRoot = path.dirname(path.dirname(path.dirname(fileURLToPath(import.meta.url))));
|
|
10
|
+
|
|
11
|
+
test("security.yml 的 osv-scanner 保持 fail-on-vuln: true", () => {
|
|
12
|
+
// 2026-10 审计:这里原本是 false(纯提醒,PR 上永远是绿的)。改回 false 就等于
|
|
13
|
+
// 「有已知漏洞也不红」,而测试目录原本没有任何东西会察觉这件事。
|
|
14
|
+
const yml = readFileSync(path.join(repoRoot, ".github", "workflows", "security.yml"), "utf8");
|
|
15
|
+
assert.match(yml, /fail-on-vuln:\s*true/, "osv-scanner 必须保持 fail-on-vuln: true");
|
|
16
|
+
assert.doesNotMatch(yml, /fail-on-vuln:\s*false/, "不得退回只上传 SARIF 不拦的档位");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// 剥掉整行注释再断言:注释里会**描述**「id-token: write 该发给谁」,
|
|
20
|
+
// 直接对全文 grep 会被自己写的说明文字骗过(第一版就栽在这里)。
|
|
21
|
+
function codeOnly(yml) {
|
|
22
|
+
return yml.split(/\r?\n/).filter((l) => !/^\s*#/.test(l)).join("\n");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 按缩进切出单个 job 的文本块:工作流顶层是 0 缩进,job 名是 2 缩进。
|
|
26
|
+
// 只做文本切片不做完整 YAML 解析——仓库零依赖,为一条断言引 yaml 解析器不划算。
|
|
27
|
+
function jobBlock(yml, name) {
|
|
28
|
+
const lines = codeOnly(yml).split(/\r?\n/);
|
|
29
|
+
const start = lines.findIndex((l) => l === " " + name + ":");
|
|
30
|
+
assert.ok(start >= 0, "找不到 job: " + name);
|
|
31
|
+
let end = lines.length;
|
|
32
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
33
|
+
if (/^ [A-Za-z0-9_-]+:$/.test(lines[i])) { end = i; break; }
|
|
34
|
+
}
|
|
35
|
+
return lines.slice(start, end).join("\n");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
test("release.yml 的 provenance 权限只发给 publish,不发给工作流顶层", () => {
|
|
39
|
+
// 三件事分开断言,因为「全文件 grep id-token: write」会被两种错误都骗过:
|
|
40
|
+
// ①有人把 id-token 提到工作流顶层(verify/test 也拿到 OIDC 能力)
|
|
41
|
+
// ②有人把 publish 的权限删了但别的 job 还有(provenance 会失败)
|
|
42
|
+
const yml = readFileSync(path.join(repoRoot, ".github", "workflows", "release.yml"), "utf8");
|
|
43
|
+
assert.match(yml, /npm publish[^\n]*--provenance/, "publish 必须带 --provenance");
|
|
44
|
+
|
|
45
|
+
// YAML 允许把顶层键写成 "jobs": 或 'jobs':,那也是合法的工作流。
|
|
46
|
+
// 只匹配裸 jobs: 会在那种写法下把整个文件当成 head,于是 publish 里合法的
|
|
47
|
+
// id-token 被误判成「顶层声明」——失败方向是误红不是漏检,但假红会磨损这条锁。
|
|
48
|
+
const head = codeOnly(yml).split(/\r?\n(?=["']?jobs["']?:\s*$)/m)[0];
|
|
49
|
+
assert.doesNotMatch(head, /id-token:/, "工作流顶层不得声明 id-token(会泄漏给所有 job)");
|
|
50
|
+
|
|
51
|
+
const publish = jobBlock(yml, "publish");
|
|
52
|
+
assert.match(publish, /id-token:\s*write/, "publish job 需要 id-token: write");
|
|
53
|
+
assert.doesNotMatch(publish, /contents:\s*write/, "publish 只读代码,不需要 contents: write");
|
|
54
|
+
|
|
55
|
+
const release = jobBlock(yml, "release");
|
|
56
|
+
assert.match(release, /contents:\s*write/, "release job 建 Release 需要 contents: write");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// 把每个 `run: |` 块的正文切出来。要断言的是「脚本正文里没有模板展开」,
|
|
60
|
+
// 而 run 块之外(env、with、name)出现 ${{ }} 是正常且必需的。
|
|
61
|
+
function runBlocks(yml) {
|
|
62
|
+
const lines = codeOnly(yml).split(/\r?\n/);
|
|
63
|
+
const blocks = [];
|
|
64
|
+
for (let i = 0; i < lines.length; i++) {
|
|
65
|
+
const m = /^(\s*)run:\s*\|\s*$/.exec(lines[i]);
|
|
66
|
+
if (!m) continue;
|
|
67
|
+
const indent = m[1].length;
|
|
68
|
+
let j = i + 1;
|
|
69
|
+
for (; j < lines.length; j++) {
|
|
70
|
+
const line = lines[j];
|
|
71
|
+
if (!line.trim()) continue;
|
|
72
|
+
if (line.match(/^\s*/)[0].length <= indent) break;
|
|
73
|
+
}
|
|
74
|
+
blocks.push(lines.slice(i + 1, j).join("\n"));
|
|
75
|
+
i = j - 1;
|
|
76
|
+
}
|
|
77
|
+
return blocks;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
test("release-prep.yml 的版本号走 env 注入,不内插进 run 脚本", () => {
|
|
81
|
+
// 2026-10 审计:zizmor 对 `--head "release-prep/${{ inputs.version }}"` 报 template-injection
|
|
82
|
+
// (模板展开可能带进攻击者可控的代码)。虽然上游 Validate 已用 ^[0-9]+\.[0-9]+\.[0-9]+$ 卡过格式,
|
|
83
|
+
// 但这里让扫描器看清「值不经过 shell 重解析」比让它推理上游校验够不够严便宜得多。
|
|
84
|
+
// 退回内插不会有任何测试变红,所以在这里锁住。
|
|
85
|
+
const yml = readFileSync(path.join(repoRoot, ".github", "workflows", "release-prep.yml"), "utf8");
|
|
86
|
+
assert.match(yml, /VERSION:\s*\$\{\{\s*inputs\.version\s*\}\}/, "版本号必须先进 env 再进脚本");
|
|
87
|
+
const blocks = runBlocks(yml);
|
|
88
|
+
assert.ok(blocks.length >= 3, "至少应切出 Validate / Count tests / Create PR 三个 run 块,实际 " + blocks.length);
|
|
89
|
+
for (const block of blocks) {
|
|
90
|
+
assert.doesNotMatch(block, /\$\{\{/, "run 脚本正文里不得出现模板展开:" + block.slice(0, 120));
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("release-prep.yml 与 badge:sync 用同一个记账口径(套件总数,不是通过数)", () => {
|
|
95
|
+
// v0.8.11 徽章漂移的同类失效:两条路径各有一套口径时,谁都不知道该信哪个数。
|
|
96
|
+
// 徽章报的是 CI(ubuntu)口径——平台条件跳过的用例在 pass 里不计、在 tests 里计入,
|
|
97
|
+
// 于是从一台有跳过条件的机器上跑发版准备,会写进一个比 badge:sync 小 1 的徽章,
|
|
98
|
+
// 而且它进 PR 时 CI 是绿的(徽章只出现在文档里,没有测试会去比对它)。
|
|
99
|
+
const yml = readFileSync(path.join(repoRoot, ".github", "workflows", "release-prep.yml"), "utf8");
|
|
100
|
+
const blocks = runBlocks(yml);
|
|
101
|
+
const countBlock = blocks.find((b) => /node --test/.test(b));
|
|
102
|
+
assert.ok(countBlock, "应当能切出跑测试的那个 run 块");
|
|
103
|
+
assert.ok(countBlock.includes("tests [0-9]+"), "计数必须取 tests N(与 sync-test-badge.mjs 同口径)");
|
|
104
|
+
assert.ok(!countBlock.includes("pass [0-9]+"), "不得退回 pass N:那是另一套记账口径");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("发版准备的两份人写清单都点出跨 minor 要挪 SECURITY.md 支持版本表", () => {
|
|
108
|
+
// 跨 minor 时 security-doc.test.js 会红,而那时人往往已经忘了这张表——工作流开的 PR
|
|
109
|
+
// 就是最后一道能把话说清楚的时机。commit-msg 与 pr-body 是两份独立的文本,
|
|
110
|
+
// 少一份就等于一半的路径上没有提示(reviewer 只看 PR 正文,git log 只看提交信息)。
|
|
111
|
+
const yml = readFileSync(path.join(repoRoot, ".github", "workflows", "release-prep.yml"), "utf8");
|
|
112
|
+
const hits = yml.match(/SECURITY\.md 中英两张支持版本表/g) || [];
|
|
113
|
+
assert.equal(hits.length, 2, "commit message 与 PR 正文各要有一条,实际 " + hits.length);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test("release-prep.yml 的重跑守卫:已有 PR 不动分支,只覆盖机器产出", () => {
|
|
117
|
+
// 2026-10-18 实测:工作流 8 步里前 7 步全成功,最后一步 git push 被
|
|
118
|
+
// "! [rejected] release-prep/0.9.1 -> release-prep/0.9.1 (fetch first)" 打回——
|
|
119
|
+
// 上一次运行已经把同名分支推上去了。不可重入的代价不是「重跑失败」这么轻:
|
|
120
|
+
// 人会以为流程坏了,转去手工发版,整套自动化就此被绕开。
|
|
121
|
+
//
|
|
122
|
+
// 但「能重跑」不能退化成「无条件 force push」:分支上可能已经有人补过 CHANGELOG
|
|
123
|
+
// 条目,那正是这套流程留给人的那部分工作,覆盖掉比不能重跑更糟。所以守卫分三档:
|
|
124
|
+
// 有进行中的 PR → 什么都不动;顶端是机器产出且没有 PR → 按重跑覆盖;其他 → 停下要人看。
|
|
125
|
+
const yml = readFileSync(path.join(repoRoot, ".github", "workflows", "release-prep.yml"), "utf8");
|
|
126
|
+
const blocks = runBlocks(yml);
|
|
127
|
+
const pushBlock = blocks.find((b) => /git push/.test(b));
|
|
128
|
+
assert.ok(pushBlock, "应当能切出含 git push 的那个 run 块");
|
|
129
|
+
|
|
130
|
+
const prLookup = pushBlock.indexOf('--state open');
|
|
131
|
+
const pushAt = pushBlock.indexOf("git push");
|
|
132
|
+
assert.ok(prLookup > 0, "重跑前必须查有没有进行中的 PR(gh pr list --state open)");
|
|
133
|
+
assert.ok(prLookup < pushAt, "查 PR 必须发生在 push 之前");
|
|
134
|
+
|
|
135
|
+
// 三档判定:没有 PR 才继续;继续时顶端提交必须是本工作流生成的。
|
|
136
|
+
assert.ok(pushBlock.includes("--force-with-lease="), "重跑覆盖必须用 --force-with-lease(锁住 fetch 到的 SHA)");
|
|
137
|
+
assert.ok(!/git push[^\n]*--force(?!-with-lease)/.test(pushBlock), "不得退回无条件 --force");
|
|
138
|
+
// 断言的是那个 if 本身,不是变量名:变量名留在 case 里、判定被删掉,
|
|
139
|
+
// 只查 includes("MACHINE_TAIL") 照样绿(第一版就是这么漏的)。
|
|
140
|
+
assert.match(pushBlock, /if \[ "\$MACHINE_TAIL" != "yes" \]; then/, "必须有「顶端不是机器产出就停下」的那道判定");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("release-prep.yml 开 PR 失败时给的是可行动的报错,不是裸 GraphQL 报错", () => {
|
|
144
|
+
// 第二个真因(2026-10-18 实测):仓库级开关 can_approve_pull_request_reviews=false,
|
|
145
|
+
// job 里写 pull-requests: write 覆盖不了它,最后一步报
|
|
146
|
+
// "GitHub Actions is not permitted to create or approve pull requests"。
|
|
147
|
+
// 这个开关在**组织层**默认关着时仓库层根本改不动(gh api 返回 409 Conflict),
|
|
148
|
+
// 所以要让人一眼看出该去哪里开、开完能不能直接重跑。
|
|
149
|
+
const yml = readFileSync(path.join(repoRoot, ".github", "workflows", "release-prep.yml"), "utf8");
|
|
150
|
+
// 只在**可执行部分**里找:这几句话在注释里也出现过(注释是在解释为什么),
|
|
151
|
+
// 对全文 grep 会被自己写的说明文字骗过——报错文案被删干净了照样绿。
|
|
152
|
+
const code = codeOnly(yml);
|
|
153
|
+
assert.match(code, /not permitted to create or approve pull requests/, "报错文案要点名这个具体的 GitHub 报错,人才搜得到");
|
|
154
|
+
assert.match(code, /Settings → Actions → General/, "必须写清去哪个设置页开");
|
|
155
|
+
assert.match(code, /Allow GitHub Actions to create and approve pull requests/, "必须写清要打开的那个开关叫什么");
|
|
156
156
|
});
|