@sanqianx/project-knowledge 5.0.23 → 5.0.25
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/.agents/plugins/marketplace.json +20 -20
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +1361 -1346
- package/LICENSE +201 -201
- package/NOTICE +5 -5
- package/README.md +349 -349
- package/_modules/knowledge-engine/package.json +1 -1
- package/_modules/knowledge-engine/src/coordinator.js +48 -3
- package/_modules/knowledge-engine/src/runtime/automation-config.js +140 -140
- package/_modules/knowledge-engine/src/runtime/commit-conversation-binder.js +238 -238
- package/_modules/knowledge-engine/src/runtime/commit-processing-ledger.js +26 -26
- package/_modules/knowledge-engine/src/runtime/commit-prompt.js +193 -193
- package/_modules/knowledge-engine/src/runtime/commit-reconciler.js +394 -394
- package/_modules/knowledge-engine/src/runtime/contracts.js +282 -282
- package/_modules/knowledge-engine/src/runtime/conversation-store.js +389 -389
- package/_modules/knowledge-engine/src/runtime/evidence-bundle.js +228 -228
- package/_modules/knowledge-engine/src/runtime/git-runner.js +62 -62
- package/_modules/knowledge-engine/src/runtime/knowledge-promotion.js +505 -505
- package/_modules/knowledge-engine/src/runtime/knowledge-retrieval-service.js +400 -400
- package/_modules/knowledge-engine/src/runtime/markdown-knowledge-indexer.js +171 -171
- package/_modules/knowledge-engine/src/runtime/scanner.js +298 -298
- package/_modules/knowledge-engine/ui/app.js +23 -2
- package/_site/README.md +30 -30
- package/_site/_test/agent-capture-mcp-ui-test.js +68 -68
- package/_site/_test/agent-capture-ui-test.js +101 -101
- package/_site/_test/ai-profile-resolver-test.js +137 -137
- package/_site/_test/ai-profile-test.js +75 -75
- package/_site/_test/ai-vendor-presets-test.js +91 -91
- package/_site/_test/automatic-context-test.js +70 -70
- package/_site/_test/automation-queue-test.js +14 -14
- package/_site/_test/automation-ui-test.js +40 -40
- package/_site/_test/background-task-registry-test.js +43 -43
- package/_site/_test/baseline-schema-test.js +91 -91
- package/_site/_test/bin-cli-test.js +230 -230
- package/_site/_test/bridge-adapter-test.js +95 -95
- package/_site/_test/bridge-consumer-service-test.js +310 -310
- package/_site/_test/candidate-bin-content-test.js +35 -35
- package/_site/_test/candidate-product-assets-test.js +13 -13
- package/_site/_test/candidate-release-contract-test.js +14 -14
- package/_site/_test/capture-hook-dedup-test.js +158 -158
- package/_site/_test/cdp-browser-failure-test.js +103 -103
- package/_site/_test/chat-claudecodeui-match-test.js +92 -92
- package/_site/_test/claude-executable-discovery-test.js +90 -90
- package/_site/_test/claude-session-lifecycle-sweep-test.js +252 -252
- package/_site/_test/claude-workbench-test.js +174 -174
- package/_site/_test/cli-instance-management-test.js +62 -62
- package/_site/_test/client-capture-restart-e2e-test.js +189 -189
- package/_site/_test/codex-conversation-projection-test.js +60 -60
- package/_site/_test/codex-marketplace-scoped-path-test.js +186 -186
- package/_site/_test/codex-notify-capture-e2e-test.js +101 -101
- package/_site/_test/codex-notify-fanout-test.js +141 -134
- package/_site/_test/codex-notify-upgrade-test.js +253 -253
- package/_site/_test/commit-boundary-freeze-test.js +147 -147
- package/_site/_test/commit-conversation-binding-test.js +99 -99
- package/_site/_test/commit-evidence-test.js +110 -110
- package/_site/_test/configuration-generation-test.js +22 -22
- package/_site/_test/context-pack-test.js +200 -200
- package/_site/_test/conversation-api-test.js +119 -119
- package/_site/_test/conversation-origin-test.js +15 -15
- package/_site/_test/conversation-store-test.js +138 -138
- package/_site/_test/cross-repo-isolation-e2e-test.js +187 -187
- package/_site/_test/desktop-browser-compat-test.js +28 -28
- package/_site/_test/desktop-hook-runtime-regression-test.js +204 -204
- package/_site/_test/embedding-config-test.js +32 -32
- package/_site/_test/explicit-commit-processor-test.js +37 -37
- package/_site/_test/fixtures/fake-browser-exit.js +10 -10
- package/_site/_test/fixtures/fake-browser-hang.js +10 -10
- package/_site/_test/fixtures/integration-busy-worker.cjs +6 -6
- package/_site/_test/fixtures/make-git-repos.js +92 -92
- package/_site/_test/fixtures/retrieval-gold-queries.json +32 -32
- package/_site/_test/folder-picker-output-test.js +19 -19
- package/_site/_test/fresh-hook-reimport-test.js +53 -53
- package/_site/_test/fresh-product-data-test.js +56 -56
- package/_site/_test/full-integration-e2e-test.js +167 -167
- package/_site/_test/git-path-compatibility-test.js +80 -80
- package/_site/_test/git-validation-test.js +81 -81
- package/_site/_test/glm-ui-refresh-review-test.js +313 -404
- package/_site/_test/harness-isolation-test.js +138 -0
- package/_site/_test/helpers/cdp-browser.js +383 -0
- package/_site/_test/helpers/cdp-network-capture.js +66 -0
- package/_site/_test/helpers/find-chrome.js +34 -0
- package/_site/_test/helpers/free-port.js +8 -0
- package/_site/_test/helpers/logging-ui-fixture.js +131 -0
- package/_site/_test/helpers/module-fixture.js +282 -0
- package/_site/_test/helpers/parallel-engine-advanced-engine-child.js +45 -0
- package/_site/_test/helpers/parallel-engine-advanced-fault-writer.js +171 -0
- package/_site/_test/helpers/parallel-engine-advanced-harness.js +245 -0
- package/_site/_test/helpers/parallel-engine-advanced-standin-analyzer.js +80 -0
- package/_site/_test/helpers/parallel-engine-advanced-ui-host.js +177 -0
- package/_site/_test/helpers/parallel-engine-final-harness.js +314 -0
- package/_site/_test/helpers/parallel-engine-final-standin-analyzer.js +159 -0
- package/_site/_test/helpers/parallel-knowledge-fixture.js +255 -0
- package/_site/_test/helpers/parallel-logging-acceptance-fixture.js +111 -0
- package/_site/_test/helpers/parallel-logging-acceptance-proxy.js +106 -0
- package/_site/_test/helpers/parallel-logging-fix-r2-proxy.js +205 -0
- package/_site/_test/helpers/parallel-logging-integration-5025-env.js +432 -0
- package/_site/_test/helpers/parallel-memory-analyzer.js +81 -0
- package/_site/_test/helpers/parallel-memory-event-bridge.js +128 -0
- package/_site/_test/helpers/parallel-memory-shell.js +470 -0
- package/_site/_test/helpers/parallel-nav-isolation-env.js +389 -0
- package/_site/_test/helpers/parallel-nav-module-ui.js +186 -0
- package/_site/_test/helpers/parallel-nav-proxy.js +148 -0
- package/_site/_test/helpers/parallel-nav-shell.js +361 -0
- package/_site/_test/helpers/parallel-qa-engine-endpoint-guard.js +206 -0
- package/_site/_test/helpers/parallel-qa-engine-endpoint-isolate.js +257 -0
- package/_site/_test/helpers/parallel-retrieval-followup-corpus.js +293 -0
- package/_site/_test/helpers/parallel-retrieval-followup-next-session.js +70 -0
- package/_site/_test/helpers/parallel-retrieval-followup-r2-shell.js +737 -0
- package/_site/_test/helpers/parallel-retrieval-followup-r2-wb-host.js +82 -0
- package/_site/_test/helpers/parallel-retrieval-followup-shell.js +279 -0
- package/_site/_test/helpers/parallel-workbench-fixture.js +371 -0
- package/_site/_test/helpers/parallel-workbench-host.js +80 -0
- package/_site/_test/helpers/parallel-workbench-integration-5025-fixture.js +408 -0
- package/_site/_test/helpers/parallel-workbench-integration-5025-harness.js +593 -0
- package/_site/_test/helpers/parallel-workbench-integration-5025-host.js +70 -0
- package/_site/_test/helpers/parallel-workbench-integration-5025-launcher.js +240 -0
- package/_site/_test/helpers/parallel-workbench-integration-5025-runtime-harness.js +630 -0
- package/_site/_test/helpers/parallel-workbench-source-map.js +196 -0
- package/_site/_test/helpers/spawn-server.js +106 -0
- package/_site/_test/helpers/version-visibility-fixture.js +251 -0
- package/_site/_test/hook-runtime-endpoint-test.js +88 -88
- package/_site/_test/hook-status-repair-api-test.js +152 -152
- package/_site/_test/hook-trigger-test.js +85 -85
- package/_site/_test/hook-worktree-test.js +42 -42
- package/_site/_test/import-preflight-api-test.js +234 -234
- package/_site/_test/index-builder-test.js +41 -41
- package/_site/_test/index-error-display-contract-test.js +10 -10
- package/_site/_test/index-writer-concurrency-test.js +135 -135
- package/_site/_test/integration-adapters-test.js +262 -262
- package/_site/_test/integration-auto-repair-test.js +113 -113
- package/_site/_test/integration-capture-setup-test.js +118 -118
- package/_site/_test/integration-intent-test.js +81 -81
- package/_site/_test/integration-runtime-binding-a2-test.js +566 -566
- package/_site/_test/integration-runtime-binding-a3-test.js +227 -227
- package/_site/_test/integration-runtime-binding-test.js +473 -473
- package/_site/_test/integration-status-scan-test.js +29 -29
- package/_site/_test/integration-surface-coverage-test.js +164 -164
- package/_site/_test/kb-framework-test.js +57 -57
- package/_site/_test/kbpath-follow-test.js +63 -63
- package/_site/_test/knowledge-db-test.js +144 -144
- package/_site/_test/knowledge-engine-client-test.js +120 -109
- package/_site/_test/knowledge-language-control-test.js +170 -170
- package/_site/_test/knowledge-maintenance-test.js +40 -40
- package/_site/_test/knowledge-promotion-recovery-test.js +260 -260
- package/_site/_test/knowledge-query-test.js +54 -54
- package/_site/_test/knowledge-retrieval-service-test.js +77 -77
- package/_site/_test/knowledge-scopes-test.js +37 -37
- package/_site/_test/knowledge-storage-location-test.js +28 -28
- package/_site/_test/knowledge-storage-startup-test.js +52 -52
- package/_site/_test/knowledge-store-logs-supervision-test.js +89 -89
- package/_site/_test/launcher-readiness-test.js +80 -80
- package/_site/_test/legacy-claude-session-alias-test.js +106 -106
- package/_site/_test/legacy-routes-removed-test.js +47 -47
- package/_site/_test/legacy-workbench-exclusion-test.js +92 -92
- package/_site/_test/live-gateway-test.js +48 -48
- package/_site/_test/local-marketplace-test.js +16 -16
- package/_site/_test/log-redaction-test.js +58 -58
- package/_site/_test/logging-api-test.js +89 -89
- package/_site/_test/logging-sse-no-gap-test.js +88 -88
- package/_site/_test/logging-ui-test.js +107 -107
- package/_site/_test/markdown-delta-overlay-test.js +85 -85
- package/_site/_test/markdown-maintenance-api-test.js +75 -75
- package/_site/_test/markdown-maintenance-test.js +11 -11
- package/_site/_test/mcp-server-test.js +149 -149
- package/_site/_test/model-context-windows-test.js +89 -89
- package/_site/_test/module-agent-start-proxy-test.js +65 -65
- package/_site/_test/module-artifact-integrity-test.js +27 -27
- package/_site/_test/module-boundary-test.js +30 -30
- package/_site/_test/module-bridge-eventbridge-test.js +202 -202
- package/_site/_test/module-dynamic-port-test.js +118 -118
- package/_site/_test/module-index-proxy-test.js +33 -33
- package/_site/_test/module-model-configuration-test.js +44 -44
- package/_site/_test/module-process-lifecycle-test.js +35 -35
- package/_site/_test/module-stream-proxy-test.js +34 -34
- package/_site/_test/module-terminal-restart-test.js +63 -63
- package/_site/_test/module-wiring-unbind-race-test.js +59 -59
- package/_site/_test/native-context-integrations-test.js +86 -86
- package/_site/_test/non-release-ci-test.js +34 -34
- package/_site/_test/offline-boundary-isolation-test.js +32 -32
- package/_site/_test/orphaned-claim-recovery-test.js +80 -80
- package/_site/_test/package-boundary-test.js +43 -43
- package/_site/_test/package-startup-test.js +56 -56
- package/_site/_test/packaged-ui-smoke-test.js +88 -88
- package/_site/_test/parallel-ci-r9-posix-socket-budget-test.js +156 -0
- package/_site/_test/parallel-engine-advanced-eng005-test.js +136 -0
- package/_site/_test/parallel-engine-advanced-eng006-test.js +171 -0
- package/_site/_test/parallel-engine-advanced-eng007-reconcile-test.js +231 -0
- package/_site/_test/parallel-engine-advanced-eng009-test.js +208 -0
- package/_site/_test/parallel-engine-advanced-eng010-test.js +213 -0
- package/_site/_test/parallel-engine-advanced-eng011-ui-probe.js +459 -0
- package/_site/_test/parallel-engine-final-eng002-test.js +255 -0
- package/_site/_test/parallel-engine-final-eng007-test.js +269 -0
- package/_site/_test/parallel-engine-final-eng011-test.js +197 -0
- package/_site/_test/parallel-engine-final-eng012-test.js +354 -0
- package/_site/_test/parallel-knowledge-client-error-code-test.js +184 -0
- package/_site/_test/parallel-knowledge-engine-test.js +353 -0
- package/_site/_test/parallel-knowledge-retrieval-test.js +292 -0
- package/_site/_test/parallel-knowledge-vector-test.js +168 -0
- package/_site/_test/parallel-linux-ci-r7-log007-day-test.js +110 -0
- package/_site/_test/parallel-logging-acceptance-log003-test.js +224 -0
- package/_site/_test/parallel-logging-acceptance-log004-test.js +231 -0
- package/_site/_test/parallel-logging-acceptance-log005-test.js +208 -0
- package/_site/_test/parallel-logging-acceptance-log006-test.js +214 -0
- package/_site/_test/parallel-logging-acceptance-log007-test.js +223 -0
- package/_site/_test/parallel-logging-acceptance-log008-test.js +180 -0
- package/_site/_test/parallel-logging-fix-r2-crash-probe.js +271 -0
- package/_site/_test/parallel-logging-fix-r2-gap-test.js +294 -0
- package/_site/_test/parallel-logging-fix-r2-normalhook-test.js +330 -0
- package/_site/_test/parallel-logging-integration-5025-portability-test.js +554 -0
- package/_site/_test/parallel-memory-candidate-test.js +301 -0
- package/_site/_test/parallel-memory-manual-test.js +197 -0
- package/_site/_test/parallel-memory-scope-test.js +228 -0
- package/_site/_test/parallel-memory-source-test.js +227 -0
- package/_site/_test/parallel-memory-sync-test.js +238 -0
- package/_site/_test/parallel-memory-view-r8-reload-gate-test.js +123 -0
- package/_site/_test/parallel-nav-failure-test.js +119 -0
- package/_site/_test/parallel-nav-isolation-test.js +308 -0
- package/_site/_test/parallel-nav-isolation-vector-path-test.js +90 -0
- package/_site/_test/parallel-nav-offline-test.js +272 -0
- package/_site/_test/parallel-nav-operability-test.js +257 -0
- package/_site/_test/parallel-nav-switch-test.js +247 -0
- package/_site/_test/parallel-nav-theme-test.js +130 -0
- package/_site/_test/parallel-nav-viewport-test.js +310 -0
- package/_site/_test/parallel-qa-engine-endpoint-guard-test.js +273 -0
- package/_site/_test/parallel-retrieval-followup-citation-test.js +219 -0
- package/_site/_test/parallel-retrieval-followup-corpus-test.js +287 -0
- package/_site/_test/parallel-workbench-independent-host.js +262 -0
- package/_site/_test/parallel-workbench-integration-5025-abort-probe.js +340 -0
- package/_site/_test/parallel-workbench-integration-5025-drafts-probe.js +588 -0
- package/_site/_test/parallel-workbench-integration-5025-env-check.js +317 -0
- package/_site/_test/parallel-workbench-integration-5025-model-probe.js +342 -0
- package/_site/_test/parallel-workbench-integration-5025-ordering-probe.js +326 -0
- package/_site/_test/parallel-workbench-model-probe.js +336 -0
- package/_site/_test/parallel-workbench-offline-test.js +169 -0
- package/_site/_test/parallel-workbench-provenance-trace.js +134 -0
- package/_site/_test/parallel-workbench-source-match.js +206 -0
- package/_site/_test/parallel-workbench-standalone-turn.js +349 -0
- package/_site/_test/path-consistency-test.js +151 -151
- package/_site/_test/pending-sweep-test.js +9 -9
- package/_site/_test/post-commit-automation-test.js +87 -87
- package/_site/_test/pr-consumer-contract-test.js +55 -55
- package/_site/_test/product-brand-contract-test.js +25 -25
- package/_site/_test/product-diagnostics-ui-test.js +93 -93
- package/_site/_test/product-empty-state-test.js +148 -0
- package/_site/_test/product-import-ui-test.js +219 -104
- package/_site/_test/product-navigation-test.js +152 -0
- package/_site/_test/product-progress-status-test.js +84 -84
- package/_site/_test/project-delete-recovery-test.js +64 -64
- package/_site/_test/project-domain-create-test.js +91 -0
- package/_site/_test/project-domain-scope-retrieval-test.js +214 -0
- package/_site/_test/project-git-init-confirm-test.js +115 -0
- package/_site/_test/project-goal-editor-test.js +144 -144
- package/_site/_test/project-import-duplicate-alias-test.js +134 -0
- package/_site/_test/project-import-unicode-restart-test.js +140 -0
- package/_site/_test/project-lifecycle-transaction-test.js +106 -106
- package/_site/_test/project-module-partial-recovery-test.js +222 -0
- package/_site/_test/project-remove-running-guard-test.js +79 -79
- package/_site/_test/project-store-test.js +90 -90
- package/_site/_test/project-unbind-late-read-ui-test.js +250 -0
- package/_site/_test/project-unbind-writer-guard-test.js +231 -0
- package/_site/_test/prompt-settings-test.js +115 -115
- package/_site/_test/protected-architecture-gate-test.js +122 -122
- package/_site/_test/refactor-characterization-test.js +36 -36
- package/_site/_test/registry-events-test.js +38 -38
- package/_site/_test/release-version-sync-test.js +115 -115
- package/_site/_test/requirement-binding-test.js +113 -113
- package/_site/_test/requirement-recorder-test.js +173 -173
- package/_site/_test/run-all-tests.js +173 -161
- package/_site/_test/runtime-endpoint-test.js +64 -64
- package/_site/_test/scanner-test.js +83 -83
- package/_site/_test/server-security-test.js +96 -96
- package/_site/_test/sessions-stream-test.js +93 -93
- package/_site/_test/shared-contracts-test.js +58 -58
- package/_site/_test/shared-scope-root-binding-test.js +74 -67
- package/_site/_test/simple-import-test.js +98 -98
- package/_site/_test/startup-analysis-disabled-test.js +16 -16
- package/_site/_test/storage-foundation-test.js +78 -78
- package/_site/_test/structured-logger-test.js +101 -101
- package/_site/_test/t07b-cln-005-coverage-test.js +212 -0
- package/_site/_test/team-knowledge-store-sparse-checkout-test.js +196 -196
- package/_site/_test/team-knowledge-store-test.js +132 -132
- package/_site/_test/test-server-cleanup-test.js +35 -35
- package/_site/_test/test-server-module-isolation-test.js +37 -37
- package/_site/_test/tracking-start-test.js +144 -144
- package/_site/_test/vector-storage-root-test.js +75 -75
- package/_site/_test/version-visibility-browser-probe.js +249 -0
- package/_site/_test/version-visibility-test.js +92 -0
- package/_site/_test/workbench-context-receipts-test.js +22 -22
- package/_site/_test/workbench-permission-test.js +117 -117
- package/_site/_test/zcode-capture-integration-test.js +112 -112
- package/_site/lib/ai-profile-resolver.js +78 -78
- package/_site/lib/ai-vendor-presets.js +83 -83
- package/_site/lib/ai-workspace.js +104 -104
- package/_site/lib/atomic-file.js +204 -204
- package/_site/lib/automation-config.js +140 -140
- package/_site/lib/bridge-adapter.js +260 -260
- package/_site/lib/bridge-consumer-service.js +402 -402
- package/_site/lib/capture-hook-config.js +108 -108
- package/_site/lib/claude-cli-runner.js +1599 -1599
- package/_site/lib/cli-instances.js +43 -43
- package/_site/lib/codex-context-status.js +17 -17
- package/_site/lib/codex-notify-config.js +193 -193
- package/_site/lib/commit-conversation-binder.js +247 -247
- package/_site/lib/commit-processing-ledger.js +27 -27
- package/_site/lib/commit-prompt.js +202 -202
- package/_site/lib/commit-reconciler.js +444 -444
- package/_site/lib/context-pack-builder.js +299 -299
- package/_site/lib/contracts.js +291 -291
- package/_site/lib/conversation-exclusions.js +204 -204
- package/_site/lib/conversation-query-service.js +161 -161
- package/_site/lib/conversation-store.js +387 -387
- package/_site/lib/data-dir.js +13 -13
- package/_site/lib/embedding-service.js +85 -85
- package/_site/lib/engine-connection.js +93 -93
- package/_site/lib/engine-knowledge-client.js +76 -72
- package/_site/lib/evidence-bundle.js +228 -228
- package/_site/lib/folder-picker-output.js +24 -24
- package/_site/lib/git-path.js +14 -14
- package/_site/lib/git-runner.js +62 -62
- package/_site/lib/github-team-store.js +1175 -1175
- package/_site/lib/hook-manager.js +203 -203
- package/_site/lib/index-builder.js +157 -157
- package/_site/lib/index-service.js +173 -173
- package/_site/lib/integration-auto-repair.js +77 -77
- package/_site/lib/integration-installer.js +1240 -1240
- package/_site/lib/integration-intent.js +88 -88
- package/_site/lib/integration-status-scan.js +99 -99
- package/_site/lib/integration-status-worker.js +14 -14
- package/_site/lib/kb-framework.js +191 -191
- package/_site/lib/kb-validator.js +124 -124
- package/_site/lib/knowledge-db.js +363 -363
- package/_site/lib/knowledge-promotion.js +435 -435
- package/_site/lib/knowledge-retrieval-service.js +401 -401
- package/_site/lib/knowledge-schema.js +121 -121
- package/_site/lib/knowledge-tool-runtime.js +366 -366
- package/_site/lib/live-gateway.js +78 -78
- package/_site/lib/llm-client.js +173 -173
- package/_site/lib/markdown-knowledge-indexer.js +230 -230
- package/_site/lib/model-context-windows.js +82 -82
- package/_site/lib/module-bridge.js +874 -874
- package/_site/lib/module-port-resolver.js +57 -57
- package/_site/lib/post-commit-automation.js +141 -141
- package/_site/lib/product-data.js +35 -35
- package/_site/lib/project-lifecycle-service.js +554 -554
- package/_site/lib/project-registry-store.js +129 -129
- package/_site/lib/project-store.js +268 -268
- package/_site/lib/prompt-registry.js +148 -148
- package/_site/lib/public-version-info.js +37 -0
- package/_site/lib/registry-events.js +16 -16
- package/_site/lib/requirement-adapters.js +10 -10
- package/_site/lib/requirement-binder.js +112 -112
- package/_site/lib/requirement-recorder.js +278 -278
- package/_site/lib/runtime-control.js +89 -89
- package/_site/lib/runtime-endpoint.js +160 -160
- package/_site/lib/scanner.js +298 -298
- package/_site/lib/server-app.js +1672 -1664
- package/_site/lib/settings-store.js +153 -153
- package/_site/lib/storage-layout.js +166 -166
- package/_site/lib/structured-logger.js +574 -574
- package/_site/lib/zcode-context-integration.js +60 -60
- package/_site/scripts/codex-notify-fanout.cjs +95 -95
- package/_site/scripts/folder-picker.ps1 +156 -156
- package/_site/scripts/hook-trigger.js +158 -158
- package/_site/scripts/install-module-candidates.js +69 -69
- package/_site/scripts/pack-module-candidates.js +89 -89
- package/_site/scripts/sync-product-content.js +28 -28
- package/_site/scripts/sync-release-version.js +164 -164
- package/_site/scripts/vendor-modules.js +49 -49
- package/_site/scripts/verify-module-runtime.js +50 -50
- package/_site/scripts/verify-product-runtime.js +36 -36
- package/_site/scripts/verify-retrieval-gold.js +83 -83
- package/_site/server.js +15 -15
- package/_site/start.bat +26 -26
- package/_site/stop.bat +11 -11
- package/bin/project-knowledge-integrations.js +254 -254
- package/bin/project-knowledge-kb.js +67 -67
- package/bin/project-knowledge-mcp.js +201 -201
- package/bin/project-knowledge.js +269 -170
- package/claude-prompts.json +21 -21
- package/docs/README.zh-CN.md +207 -205
- package/docs/assets/architecture.svg +181 -181
- package/docs/assets/logo.svg +49 -49
- package/docs/fresh-v5-start.md +44 -44
- package/docs/leader-glm-workbench-playbook.md +122 -122
- package/docs/project-registry-schema.md +33 -33
- package/docs/release-5.0.16-acceptance.md +176 -176
- package/docs/release-5.0.17-acceptance.md +117 -117
- package/docs/release-5.0.19-acceptance.md +39 -39
- package/docs/team-knowledge-mode-a-plan.md +73 -73
- package/docs/testing-strategy.md +33 -33
- package/module-runtime-manifest.json +70 -67
- package/package.json +113 -110
- package/plugins/project-knowledge/.claude-plugin/plugin.json +1 -1
- package/plugins/project-knowledge/.codex-plugin/plugin.json +1 -1
- package/plugins/project-knowledge/.mcp.json +1 -1
- package/templates/change.md +30 -30
- package/templates/project-readme.md +52 -52
- package/ui/index.html +3 -2
- package/ui/version-info.css +44 -0
- package/ui/version-info.js +24 -0
- package/vendor-manifest.json +55 -55
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// _site/_test/parallel-memory-sync-test.js
|
|
3
|
+
//
|
|
4
|
+
// MEM-006 同步失败(sync pending).
|
|
5
|
+
//
|
|
6
|
+
// Real isolated product instance, real browser, real HTTP and real disk.
|
|
7
|
+
//
|
|
8
|
+
// The write really fails: the brain's shared memory file path is occupied by
|
|
9
|
+
// a directory, so the engine's own materialize() cannot write the confirmed
|
|
10
|
+
// memory file. Nothing is faked here — the engine records the real write
|
|
11
|
+
// error, the shell renders the real pending state and the real injection gate
|
|
12
|
+
// refuses to hand the unsynced memory to a task.
|
|
13
|
+
//
|
|
14
|
+
// MEM-006 expected:
|
|
15
|
+
// * sync pending真实显示。 -> the engine really answers syncStatus
|
|
16
|
+
// 'pending' with the write error, the real UI
|
|
17
|
+
// shows 写入待恢复 / 待同步 and the real toast
|
|
18
|
+
// warns that the unsynced memory is not
|
|
19
|
+
// injected;
|
|
20
|
+
// * 未同步内容不注入。 -> the engine injects nothing for the unsynced
|
|
21
|
+
// memory, and it does inject it again once
|
|
22
|
+
// the file can really be written.
|
|
23
|
+
|
|
24
|
+
const fs = require('node:fs');
|
|
25
|
+
const path = require('node:path');
|
|
26
|
+
const assert = require('node:assert/strict');
|
|
27
|
+
|
|
28
|
+
const { startHarness, makeRepo } = require('./helpers/parallel-memory-shell');
|
|
29
|
+
|
|
30
|
+
const EVIDENCE = process.env.PK_TEST_EVIDENCE_DIR ? path.resolve(process.env.PK_TEST_EVIDENCE_DIR) : null;
|
|
31
|
+
const MEMORY_TEXT = '同步失败回归:对外错误信息使用中文表述。';
|
|
32
|
+
|
|
33
|
+
async function openMemoryView(harness) {
|
|
34
|
+
await harness.nativeClick('nav [data-view="memory"]');
|
|
35
|
+
await harness.waitFor(
|
|
36
|
+
() => harness.run("document.getElementById('view-memory').classList.contains('active')"),
|
|
37
|
+
'the memory view is open',
|
|
38
|
+
10000,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function main() {
|
|
43
|
+
const harness = await startHarness({ tag: 'memsync', evidenceDir: EVIDENCE || undefined });
|
|
44
|
+
const evidence = [];
|
|
45
|
+
try {
|
|
46
|
+
const repo = makeRepo(harness.fixture, 'memsync-repo', { 'README.md': '# 同步甲\n' });
|
|
47
|
+
const { projectId } = await harness.importProject(repo, '同步甲');
|
|
48
|
+
await harness.requestRegistryRefresh();
|
|
49
|
+
await harness.waitFor(
|
|
50
|
+
() => harness.run("document.getElementById('homeContent').textContent.includes('同步甲')"),
|
|
51
|
+
'the imported project is listed',
|
|
52
|
+
20000,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
await openMemoryView(harness);
|
|
56
|
+
await harness.waitFor(
|
|
57
|
+
() => harness.run("!document.getElementById('addMemory').disabled"),
|
|
58
|
+
'the engine is reachable and the add button is live',
|
|
59
|
+
20000,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
// Break the real write path: the confirmed memory file path becomes a
|
|
63
|
+
// directory, so the engine cannot write the memory file.
|
|
64
|
+
const brainScope = harness.brainScopePath();
|
|
65
|
+
const memoryFile = path.join(brainScope, 'memories', 'confirmed.md');
|
|
66
|
+
fs.rmSync(memoryFile, { recursive: true, force: true });
|
|
67
|
+
fs.mkdirSync(memoryFile, { recursive: true });
|
|
68
|
+
assert.ok(fs.lstatSync(memoryFile).isDirectory(), 'the confirmed memory file path really is occupied by a directory');
|
|
69
|
+
|
|
70
|
+
// Add the memory through the real UI as a global memory.
|
|
71
|
+
await harness.nativeClick('#addMemory');
|
|
72
|
+
await harness.waitFor(
|
|
73
|
+
() => harness.run("document.getElementById('memoryDialog').open === true"),
|
|
74
|
+
'the add dialog is open',
|
|
75
|
+
10000,
|
|
76
|
+
);
|
|
77
|
+
await harness.typeText(MEMORY_TEXT);
|
|
78
|
+
await harness.selectOption('#memoryScope', 'global');
|
|
79
|
+
const postsBefore = harness.network.find(entry => entry.method === 'POST' && entry.url.includes('/api/engine/memories')).length;
|
|
80
|
+
// Passive DOM observation installed BEFORE the real click. The product's
|
|
81
|
+
// confirm handler closes the dialog BEFORE its post-save refreshSnapshot()
|
|
82
|
+
// and shows the toast only after that refresh resolves (ui/product.js:
|
|
83
|
+
// 'close(); await refreshSnapshot(); toast(...)'), so a one-shot read
|
|
84
|
+
// gated on 'dialog closed' can land inside the refresh gap and see an
|
|
85
|
+
// empty toast (CI 40080404131, line 98: empty text). The observer records
|
|
86
|
+
// every REAL toast mutation the REAL click produces — text, visibility
|
|
87
|
+
// and time — nothing is fabricated or forced.
|
|
88
|
+
await harness.run(`(() => {
|
|
89
|
+
const el = document.getElementById('toast');
|
|
90
|
+
window.__pkToastLog = [{ text: el.textContent, hidden: el.hidden, at: Date.now() }];
|
|
91
|
+
new MutationObserver(() => {
|
|
92
|
+
window.__pkToastLog.push({ text: el.textContent, hidden: el.hidden, at: Date.now() });
|
|
93
|
+
}).observe(el, { childList: true, characterData: true, subtree: true, attributes: true, attributeFilter: ['hidden'] });
|
|
94
|
+
return true;
|
|
95
|
+
})()`);
|
|
96
|
+
await harness.nativeClick('#confirmMemory');
|
|
97
|
+
await harness.waitFor(
|
|
98
|
+
() => harness.run("document.getElementById('memoryDialog').open === false"),
|
|
99
|
+
'the dialog closes after the save',
|
|
100
|
+
15000,
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
const post = harness.network.find(entry => entry.method === 'POST' && entry.url.includes('/api/engine/memories'))[postsBefore];
|
|
104
|
+
assert.ok(post, 'the shell really posted the memory');
|
|
105
|
+
assert.equal(post.status, 200, `the real POST answers 200: ${JSON.stringify(post.body)}`);
|
|
106
|
+
const postBody = await harness.network.body(post);
|
|
107
|
+
const created = postBody.memory;
|
|
108
|
+
assert.equal(created.status, 'confirmed', 'the memory itself is confirmed');
|
|
109
|
+
assert.equal(created.syncStatus, 'pending', `the engine really answers syncStatus pending: ${JSON.stringify(created)}`);
|
|
110
|
+
assert.ok(created.syncError, `the engine reports the real write error: ${JSON.stringify(created.syncError)}`);
|
|
111
|
+
|
|
112
|
+
// The real UI shows the pending state. The wait is on the OBSERVED toast
|
|
113
|
+
// record (installed before the click), so the assertion holds no matter
|
|
114
|
+
// when the shell's post-save refreshSnapshot() finishes — the observed
|
|
115
|
+
// toast is the real one the real click produced. The toast's text also
|
|
116
|
+
// persists after its 4s auto-hide (product toast() flips only `hidden`),
|
|
117
|
+
// so a late match is still the real text; requiring hidden === false in
|
|
118
|
+
// the same record proves it was actually VISIBLE when shown.
|
|
119
|
+
const debugUiFailure = async stage => {
|
|
120
|
+
try {
|
|
121
|
+
const dump = await harness.run(`(() => ({
|
|
122
|
+
toasts: window.__pkToastLog || null,
|
|
123
|
+
feedback: document.getElementById('memoryFeedback').textContent,
|
|
124
|
+
feedbackHidden: document.getElementById('memoryFeedback').hidden,
|
|
125
|
+
dialogOpen: document.getElementById('memoryDialog').open,
|
|
126
|
+
activeView: (document.querySelector('.view.active') || {}).id || null,
|
|
127
|
+
}))()`);
|
|
128
|
+
console.error(`MEM-006 UI failure at ${stage}: ${JSON.stringify(dump)}`);
|
|
129
|
+
if (harness.evidence) await harness.browser.screenshot(path.join(harness.evidence, `mem006-failure-${stage}.png`));
|
|
130
|
+
} catch {}
|
|
131
|
+
};
|
|
132
|
+
let toastRecord;
|
|
133
|
+
try {
|
|
134
|
+
toastRecord = await harness.waitFor(
|
|
135
|
+
() => harness.run(`(window.__pkToastLog || []).find(t => !t.hidden && t.text.includes('记忆文件待恢复')) || null`),
|
|
136
|
+
'the toast warns about the pending file',
|
|
137
|
+
10000,
|
|
138
|
+
);
|
|
139
|
+
} catch (error) { await debugUiFailure('toast-pending'); throw error; }
|
|
140
|
+
assert.equal(toastRecord.hidden, false, `the pending toast was really visible when shown: ${JSON.stringify(toastRecord)}`);
|
|
141
|
+
const toast = toastRecord.text;
|
|
142
|
+
assert.match(String(toast), /记忆文件待恢复/, `the toast warns about the pending file: ${toast}`);
|
|
143
|
+
assert.match(String(toast), /未同步内容不会注入任务。/, 'the toast warns that the unsynced memory is not injected');
|
|
144
|
+
|
|
145
|
+
let card;
|
|
146
|
+
try {
|
|
147
|
+
card = await harness.run(`(() => {
|
|
148
|
+
const el = document.querySelector('[data-memory-card=${JSON.stringify(created.id)}]');
|
|
149
|
+
return el ? el.textContent : null;
|
|
150
|
+
})()`);
|
|
151
|
+
} catch (error) { await debugUiFailure('card-read'); throw error; }
|
|
152
|
+
if (!card) await debugUiFailure('card-listed');
|
|
153
|
+
assert.ok(card, 'the confirmed memory is really listed');
|
|
154
|
+
assert.match(card, /写入待恢复/, `the card shows the pending write: ${card}`);
|
|
155
|
+
assert.match(card, /待同步/, 'the card shows the pending sync state');
|
|
156
|
+
if (harness.evidence) await harness.browser.screenshot(path.join(harness.evidence, 'mem006-sync-pending.png'));
|
|
157
|
+
|
|
158
|
+
// 未同步内容不注入: the real injection gate refuses the unsynced memory.
|
|
159
|
+
const injected = await harness.injectedMemories(projectId);
|
|
160
|
+
assert.ok(
|
|
161
|
+
!injected.some(entry => entry.memoryId === created.id),
|
|
162
|
+
`the unsynced memory is never injected: ${JSON.stringify(injected)}`,
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
const pendingRecord = (await harness.productMemories()).find(memory => memory.id === created.id);
|
|
166
|
+
assert.equal(pendingRecord.syncStatus, 'pending', 'the stored memory still carries the pending sync state');
|
|
167
|
+
|
|
168
|
+
evidence.push({
|
|
169
|
+
case: 'MEM-006',
|
|
170
|
+
request: { method: post.method, url: post.url.replace(harness.base, ''), status: post.status, response: postBody },
|
|
171
|
+
memory: { id: created.id, status: created.status, syncStatus: created.syncStatus, syncError: created.syncError, scopeType: created.scopeType, scopeId: created.scopeId },
|
|
172
|
+
ui: { toast, toastObserved: { visibleWhenShown: toastRecord.hidden === false, at: toastRecord.at }, card },
|
|
173
|
+
injectedWhilePending: injected.map(entry => entry.memoryId),
|
|
174
|
+
blockedPath: memoryFile,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// ---------------------------------------------------------------- recovery
|
|
178
|
+
// The write really works again: the directory is removed and the engine's
|
|
179
|
+
// own recovery writes the file. The memory becomes injectable again.
|
|
180
|
+
fs.rmSync(memoryFile, { recursive: true, force: true });
|
|
181
|
+
await harness.waitFor(
|
|
182
|
+
async () => {
|
|
183
|
+
const memories = await harness.productMemories();
|
|
184
|
+
const memory = memories.find(entry => entry.id === created.id);
|
|
185
|
+
return memory && memory.syncStatus === 'ready' ? memory : null;
|
|
186
|
+
},
|
|
187
|
+
'the engine recovers the pending write',
|
|
188
|
+
30000,
|
|
189
|
+
);
|
|
190
|
+
assert.ok(fs.existsSync(memoryFile), 'the confirmed memory file is really written again');
|
|
191
|
+
const fileText = fs.readFileSync(memoryFile, 'utf8');
|
|
192
|
+
assert.ok(fileText.includes(created.id), 'the recovered file holds the memory');
|
|
193
|
+
assert.ok(fileText.includes(MEMORY_TEXT), 'the recovered file holds the text');
|
|
194
|
+
|
|
195
|
+
const afterRecovery = await harness.injectedMemories(projectId);
|
|
196
|
+
assert.ok(
|
|
197
|
+
afterRecovery.some(entry => entry.memoryId === created.id),
|
|
198
|
+
`the recovered memory is injected again: ${JSON.stringify(afterRecovery)}`,
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
await harness.reload();
|
|
202
|
+
await openMemoryView(harness);
|
|
203
|
+
await harness.nativeClick('[data-memory-tab="confirmed"]');
|
|
204
|
+
await harness.waitFor(
|
|
205
|
+
() => harness.run(`document.getElementById('memoryContent').textContent.includes(${JSON.stringify(MEMORY_TEXT)})`),
|
|
206
|
+
'the recovered memory is listed again',
|
|
207
|
+
15000,
|
|
208
|
+
);
|
|
209
|
+
const recoveredCard = await harness.run(`(() => {
|
|
210
|
+
const el = document.querySelector('[data-memory-card=${JSON.stringify(created.id)}]');
|
|
211
|
+
return el ? el.textContent : null;
|
|
212
|
+
})()`);
|
|
213
|
+
assert.ok(recoveredCard, 'the recovered memory has a card');
|
|
214
|
+
assert.ok(!recoveredCard.includes('写入待恢复'), `the card no longer shows the pending write: ${recoveredCard}`);
|
|
215
|
+
assert.match(recoveredCard, /已确认/, 'the card shows the confirmed state again');
|
|
216
|
+
if (harness.evidence) await harness.browser.screenshot(path.join(harness.evidence, 'mem006-recovered.png'));
|
|
217
|
+
|
|
218
|
+
evidence.push({
|
|
219
|
+
case: 'MEM-006-recovery',
|
|
220
|
+
memoryFile,
|
|
221
|
+
injectedAfterRecovery: afterRecovery.map(entry => entry.memoryId),
|
|
222
|
+
ui: { card: recoveredCard },
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
assert.equal(harness.browser.exceptions.length, 0, `no uncaught product JavaScript exceptions: ${JSON.stringify(harness.browser.exceptions)}`);
|
|
226
|
+
|
|
227
|
+
if (harness.evidence) {
|
|
228
|
+
fs.mkdirSync(harness.evidence, { recursive: true });
|
|
229
|
+
fs.writeFileSync(path.join(harness.evidence, 'mem006-sync.json'), `${JSON.stringify(evidence, null, 2)}\n`, 'utf8');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
console.log('parallel-memory-sync-test PASS (MEM-006 the real write failure shows sync pending, the unsynced memory is not injected, and the recovered memory is injected again)');
|
|
233
|
+
} finally {
|
|
234
|
+
await harness.cleanup();
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
main().catch(error => { console.error(error.stack || error.message); process.exitCode = 1; });
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// _site/_test/parallel-memory-view-r8-reload-gate-test.js
|
|
3
|
+
//
|
|
4
|
+
// P-CI-MEMORY-VIEW-R8 focused case: the reload→navigate contract that CI
|
|
5
|
+
// 40062048045 broke in parallel-memory-source-test ("Timed out waiting for
|
|
6
|
+
// the memory view is open", test line 136).
|
|
7
|
+
//
|
|
8
|
+
// Root cause class (see the R8 probe evidence under
|
|
9
|
+
// qa-autopilot/artifacts/parallel-20261023/ci-memory-view-r8/): the shell's
|
|
10
|
+
// reload() used to gate ONLY on `document.readyState === 'complete'`, which
|
|
11
|
+
// proves neither WHICH document answered (Page.reload is acknowledged before
|
|
12
|
+
// the navigation commits; Runtime.evaluate can answer from the outgoing
|
|
13
|
+
// context on a congested renderer) nor that the product's interactive boot
|
|
14
|
+
// finished. A native nav click dispatched right after such a gate can land
|
|
15
|
+
// in the load/swap settle window and be dropped — reproduced 2/2 against the
|
|
16
|
+
// real page with a forced 600ms commit delay; the memory view then never
|
|
17
|
+
// activates (the exact CI never-true predicate).
|
|
18
|
+
//
|
|
19
|
+
// The fixed gate returns only when the answering document is provably FRESH
|
|
20
|
+
// (a marker set on the outgoing document is gone) AND the product's own boot
|
|
21
|
+
// evidence is present (.view.active — ui/product.js attaches its click
|
|
22
|
+
// delegation before the boot setView that marks the initial view active).
|
|
23
|
+
//
|
|
24
|
+
// This case proves that contract on the real page, offline from MEM-008:
|
|
25
|
+
// 1. reload() returns on the fresh, booted document (identity marker);
|
|
26
|
+
// 2. the golden path the CI failure broke — nativeClick nav memory right
|
|
27
|
+
// after reload() — activates the memory view, and home navigation
|
|
28
|
+
// still works;
|
|
29
|
+
// 3. back-to-back reloads keep the contract (the marker technique marks
|
|
30
|
+
// each outgoing document, so consecutive reloads cannot pass on a
|
|
31
|
+
// stale context);
|
|
32
|
+
// 4. the failure-diagnostics surface exists (navigationState).
|
|
33
|
+
//
|
|
34
|
+
// Real isolated product instance, real browser, real CDP input; the harness
|
|
35
|
+
// owns vector+bridge before the engine constructor and no live
|
|
36
|
+
// 5757/5790/8787/8790 endpoint is touched (parallel-memory-shell.js).
|
|
37
|
+
|
|
38
|
+
const fs = require('node:fs');
|
|
39
|
+
const path = require('node:path');
|
|
40
|
+
const assert = require('node:assert/strict');
|
|
41
|
+
|
|
42
|
+
const { startHarness } = require('./helpers/parallel-memory-shell');
|
|
43
|
+
|
|
44
|
+
const EVIDENCE = process.env.PK_TEST_EVIDENCE_DIR ? path.resolve(process.env.PK_TEST_EVIDENCE_DIR) : null;
|
|
45
|
+
|
|
46
|
+
async function main() {
|
|
47
|
+
const harness = await startHarness({ tag: 'memviewr8', evidenceDir: EVIDENCE || undefined });
|
|
48
|
+
const proof = { startedAt: new Date().toISOString() };
|
|
49
|
+
try {
|
|
50
|
+
await harness.waitFor(
|
|
51
|
+
() => harness.run("document.readyState === 'complete' && document.querySelector('.view.active') !== null"),
|
|
52
|
+
'the initial page is booted',
|
|
53
|
+
20000,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
// ---- 1. reload() returns on the FRESH, booted document ----------------
|
|
57
|
+
await harness.run('window.__pkR8Mark = "outgoing", true');
|
|
58
|
+
await harness.reload();
|
|
59
|
+
const fresh = await harness.run(`(() => ({
|
|
60
|
+
mark: typeof window.__pkR8Mark,
|
|
61
|
+
activeView: (document.querySelector('.view.active') || {}).id || null,
|
|
62
|
+
readyState: document.readyState,
|
|
63
|
+
}))()`);
|
|
64
|
+
assert.equal(fresh.mark, 'undefined', 'reload() must return on the fresh document, never on the outgoing one (the marker exists only in the outgoing context)');
|
|
65
|
+
assert.ok(fresh.activeView, 'the product boot finished before reload() returned (an initial view is active — the delegation-attached proof)');
|
|
66
|
+
assert.equal(fresh.readyState, 'complete');
|
|
67
|
+
assert.ok(harness.reloadLog.length >= 1, 'the reload gate records its small metadata');
|
|
68
|
+
proof.freshDocumentGate = fresh;
|
|
69
|
+
|
|
70
|
+
// ---- 2. the golden path the CI failure broke ---------------------------
|
|
71
|
+
await harness.nativeClick('nav [data-view="memory"]');
|
|
72
|
+
await harness.waitFor(
|
|
73
|
+
() => harness.run("document.getElementById('view-memory').classList.contains('active')"),
|
|
74
|
+
'the memory view is open',
|
|
75
|
+
10000,
|
|
76
|
+
);
|
|
77
|
+
await harness.nativeClick('nav [data-view="home"]');
|
|
78
|
+
await harness.waitFor(
|
|
79
|
+
() => harness.run("document.getElementById('view-home').classList.contains('active')"),
|
|
80
|
+
'the home view is open',
|
|
81
|
+
10000,
|
|
82
|
+
);
|
|
83
|
+
proof.goldenPath = { memoryViewOpened: true, homeViewReopened: true };
|
|
84
|
+
|
|
85
|
+
// ---- 3. back-to-back reloads keep the contract -------------------------
|
|
86
|
+
await harness.run('window.__pkR8Mark = "outgoing-again", true');
|
|
87
|
+
await harness.reload();
|
|
88
|
+
await harness.reload();
|
|
89
|
+
const twice = await harness.run(`(() => ({
|
|
90
|
+
mark: typeof window.__pkR8Mark,
|
|
91
|
+
activeView: (document.querySelector('.view.active') || {}).id || null,
|
|
92
|
+
}))()`);
|
|
93
|
+
assert.equal(twice.mark, 'undefined', 'after two consecutive reloads the gate still returned on the fresh document');
|
|
94
|
+
assert.ok(twice.activeView, 'the boot evidence held through the second reload');
|
|
95
|
+
await harness.nativeClick('nav [data-view="memory"]');
|
|
96
|
+
await harness.waitFor(
|
|
97
|
+
() => harness.run("document.getElementById('view-memory').classList.contains('active')"),
|
|
98
|
+
'the memory view opens after back-to-back reloads',
|
|
99
|
+
10000,
|
|
100
|
+
);
|
|
101
|
+
proof.backToBackReloads = { ...twice, memoryViewOpened: true };
|
|
102
|
+
|
|
103
|
+
// ---- 4. the failure-diagnostics surface exists -------------------------
|
|
104
|
+
const state = await harness.navigationState();
|
|
105
|
+
assert.ok(state && typeof state === 'object' && !state.unreachable, `navigationState() must be reachable: ${JSON.stringify(state)}`);
|
|
106
|
+
assert.equal(typeof state.readyState, 'string');
|
|
107
|
+
assert.ok('activeView' in state && 'openDialogs' in state);
|
|
108
|
+
proof.navigationStateShape = state;
|
|
109
|
+
|
|
110
|
+
assert.equal(harness.browser.exceptions.length, 0, `no uncaught product JavaScript exceptions: ${JSON.stringify(harness.browser.exceptions)}`);
|
|
111
|
+
proof.finishedAt = new Date().toISOString();
|
|
112
|
+
proof.verdict = 'PASS';
|
|
113
|
+
if (harness.evidence) {
|
|
114
|
+
fs.mkdirSync(harness.evidence, { recursive: true });
|
|
115
|
+
fs.writeFileSync(path.join(harness.evidence, 'memviewr8-reload-gate.json'), `${JSON.stringify(proof, null, 2)}\n`, 'utf8');
|
|
116
|
+
}
|
|
117
|
+
console.log('parallel-memory-view-r8-reload-gate-test PASS');
|
|
118
|
+
} finally {
|
|
119
|
+
await harness.cleanup();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
main().catch(error => { console.error(error.stack || error.message); process.exitCode = 1; });
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// NAV-004 — 失败保留旧数据。
|
|
3
|
+
//
|
|
4
|
+
// When the registry read fails the shell must show the failure, must keep the
|
|
5
|
+
// project list it already has, and must pick up the new snapshot once the
|
|
6
|
+
// registry answers again.
|
|
7
|
+
//
|
|
8
|
+
// The failure is a real HTTP 503 injected by a proxy in front of the product:
|
|
9
|
+
// the browser really receives a failed answer, and the shell really reads a
|
|
10
|
+
// broken registry. The regression drives the real product UI in a real
|
|
11
|
+
// browser against an isolated instance (own port, own data dir, own knowledge
|
|
12
|
+
// dir, own Bridge journal, own browser profile, own vendored knowledge
|
|
13
|
+
// engine). Screenshots are written to PK_TEST_EVIDENCE_DIR when the batch
|
|
14
|
+
// sets it, so this tracked file stays free of machine-specific paths.
|
|
15
|
+
|
|
16
|
+
const path = require('node:path');
|
|
17
|
+
const assert = require('node:assert/strict');
|
|
18
|
+
|
|
19
|
+
const { startHarness, makeRepo } = require('./helpers/parallel-nav-shell');
|
|
20
|
+
|
|
21
|
+
const EVIDENCE = process.env.PK_TEST_EVIDENCE_DIR ? path.resolve(process.env.PK_TEST_EVIDENCE_DIR) : null;
|
|
22
|
+
|
|
23
|
+
const PROJECTION = '/api/projects/projection';
|
|
24
|
+
|
|
25
|
+
async function main() {
|
|
26
|
+
const harness = await startHarness({ tag: 'nav004', evidenceDir: EVIDENCE || undefined });
|
|
27
|
+
try {
|
|
28
|
+
const repoA = makeRepo(harness.fixture, 'nav004-a');
|
|
29
|
+
const repoB = makeRepo(harness.fixture, 'nav004-b');
|
|
30
|
+
const repoC = makeRepo(harness.fixture, 'nav004-c');
|
|
31
|
+
await harness.importProject(repoA, 'NAV004 甲');
|
|
32
|
+
await harness.importProject(repoB, 'NAV004 乙');
|
|
33
|
+
await harness.requestRegistryRefresh();
|
|
34
|
+
await harness.waitFor(
|
|
35
|
+
async () => {
|
|
36
|
+
const text = await harness.run("document.getElementById('homeContent').textContent");
|
|
37
|
+
return text.includes('NAV004 甲') && text.includes('NAV004 乙');
|
|
38
|
+
},
|
|
39
|
+
'both imported projects are listed',
|
|
40
|
+
20000,
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const listedProjects = () => harness.run(`(() => {
|
|
44
|
+
const rows = [...document.querySelectorAll('#homeContent [data-select-project]')];
|
|
45
|
+
return rows.map(button => {
|
|
46
|
+
const name = button.parentElement.querySelector('b');
|
|
47
|
+
return name ? name.textContent.trim() : '';
|
|
48
|
+
});
|
|
49
|
+
})()`);
|
|
50
|
+
const failedReads = () => harness.productProxy.requests.filter(entry => entry.path.startsWith(PROJECTION) && entry.status === 503).length;
|
|
51
|
+
|
|
52
|
+
// The registry read now fails at the HTTP level.
|
|
53
|
+
harness.productProxy.fail(entry => entry.method === 'GET' && entry.path.startsWith(PROJECTION), 503, '注入的登记读取故障');
|
|
54
|
+
const failuresBefore = failedReads();
|
|
55
|
+
await harness.refreshRegistryAndWait();
|
|
56
|
+
await harness.waitFor(async () => failedReads() > failuresBefore, 'the registry read really failed with an HTTP 503', 20000);
|
|
57
|
+
|
|
58
|
+
// NAV-004 expected 1: the failure is visible.
|
|
59
|
+
await harness.waitFor(
|
|
60
|
+
() => harness.run("document.getElementById('toast').hidden === false && document.getElementById('toast').textContent.includes('暂未刷新')"),
|
|
61
|
+
'the failed refresh is reported to the user',
|
|
62
|
+
10000,
|
|
63
|
+
);
|
|
64
|
+
const toast = await harness.run("document.getElementById('toast').textContent");
|
|
65
|
+
assert.ok(toast.includes('已有内容已保留'), `the failure message says the content was kept: ${toast}`);
|
|
66
|
+
await harness.browser.screenshot(path.join(harness.evidence, 'nav004-read-failure.png'));
|
|
67
|
+
|
|
68
|
+
// NAV-004 expected 2: the list that was already there is not cleared.
|
|
69
|
+
const listed = (await listedProjects()).sort();
|
|
70
|
+
assert.deepEqual(listed, ['NAV004 乙', 'NAV004 甲'], 'the project list still holds the projects it had before the failure');
|
|
71
|
+
const homeText = await harness.run("document.getElementById('homeContent').textContent");
|
|
72
|
+
assert.ok(homeText.includes('NAV004 甲'), 'the failed read keeps the first project');
|
|
73
|
+
assert.ok(homeText.includes('NAV004 乙'), 'the failed read keeps the second project');
|
|
74
|
+
const selectorText = await harness.run("document.getElementById('projectSelect').textContent");
|
|
75
|
+
assert.ok(selectorText.includes('NAV004 甲') && selectorText.includes('NAV004 乙'), 'the failed read keeps the project selector entries');
|
|
76
|
+
|
|
77
|
+
// A project that appears while the registry is broken must not slip into
|
|
78
|
+
// the list as if it had been read.
|
|
79
|
+
await harness.importProject(repoC, 'NAV004 丙');
|
|
80
|
+
const failuresBeforeSecond = failedReads();
|
|
81
|
+
await harness.refreshRegistryAndWait();
|
|
82
|
+
await harness.waitFor(async () => failedReads() > failuresBeforeSecond, 'the second registry read really failed too', 20000);
|
|
83
|
+
const duringFailure = await harness.run("document.getElementById('homeContent').textContent");
|
|
84
|
+
assert.ok(duringFailure.includes('NAV004 甲') && duringFailure.includes('NAV004 乙'), 'the old projects survive the repeated failure');
|
|
85
|
+
assert.equal(duringFailure.includes('NAV004 丙'), false, 'a project that was never read is not shown while the registry is broken');
|
|
86
|
+
assert.deepEqual((await listedProjects()).sort(), ['NAV004 乙', 'NAV004 甲'], 'the project rows are exactly the projects read before the failure');
|
|
87
|
+
await harness.browser.screenshot(path.join(harness.evidence, 'nav004-old-data-kept.png'));
|
|
88
|
+
|
|
89
|
+
// NAV-004 expected 3: after the registry answers again, the list is
|
|
90
|
+
// updated from the new snapshot.
|
|
91
|
+
harness.productProxy.clearFaults();
|
|
92
|
+
await harness.refreshRegistryAndWait();
|
|
93
|
+
await harness.waitFor(
|
|
94
|
+
() => harness.run("document.getElementById('homeContent').textContent.includes('NAV004 丙')"),
|
|
95
|
+
'the recovered read shows the new project',
|
|
96
|
+
20000,
|
|
97
|
+
);
|
|
98
|
+
const recovered = await harness.run("document.getElementById('homeContent').textContent");
|
|
99
|
+
assert.ok(recovered.includes('NAV004 甲') && recovered.includes('NAV004 乙'), 'the recovered read keeps the earlier projects');
|
|
100
|
+
assert.deepEqual((await listedProjects()).sort(), ['NAV004 丙', 'NAV004 乙', 'NAV004 甲'], 'the recovered list is the new snapshot');
|
|
101
|
+
await harness.browser.screenshot(path.join(harness.evidence, 'nav004-recovered.png'));
|
|
102
|
+
|
|
103
|
+
// The failure was an HTTP failure of a real read, not a shell-side guess.
|
|
104
|
+
const failed = harness.productProxy.requests.filter(entry => entry.path.startsWith(PROJECTION) && entry.status === 503);
|
|
105
|
+
assert.ok(failed.length >= 2, `the registry read failed at the HTTP level ${failed.length} times`);
|
|
106
|
+
// The failure notice is transient: the recovery does not leave a permanent
|
|
107
|
+
// error behind in the shell.
|
|
108
|
+
await harness.wait(4500);
|
|
109
|
+
assert.equal(await harness.run("document.getElementById('toast').hidden"), true, 'the failure message is not left behind after the recovery');
|
|
110
|
+
|
|
111
|
+
assert.equal(harness.browser.exceptions.length, 0, `no uncaught product JavaScript exceptions: ${JSON.stringify(harness.browser.exceptions)}`);
|
|
112
|
+
|
|
113
|
+
console.log('parallel-nav-failure-test PASS (the failure is visible, the old list survives, the recovery updates from the new snapshot)');
|
|
114
|
+
} finally {
|
|
115
|
+
await harness.cleanup();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
main().catch(error => { console.error(error.stack || error.message); process.exitCode = 1; });
|