@sanqianx/project-knowledge 5.0.24 → 5.0.26
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 -1353
- 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 +68 -65
- 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
|
@@ -1,101 +1,101 @@
|
|
|
1
|
-
const assert = require('assert');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const os = require('os');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const { StorageLayout } = require('../lib/storage-layout');
|
|
6
|
-
const { Logger, LogRepository, localDay } = require('../lib/structured-logger');
|
|
7
|
-
|
|
8
|
-
(async () => {
|
|
9
|
-
const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pk-logger-v3-'));
|
|
10
|
-
const layout = new StorageLayout({ dataDir });
|
|
11
|
-
const config = { levels: ['trace', 'debug', 'info', 'warn', 'error', 'fatal'] };
|
|
12
|
-
let stderr = '';
|
|
13
|
-
const logger = new Logger({
|
|
14
|
-
layout,
|
|
15
|
-
settingsProvider: () => config,
|
|
16
|
-
secrets: ['known-secret-value'],
|
|
17
|
-
stderr: { write(value) { stderr += String(value); } },
|
|
18
|
-
});
|
|
19
|
-
const published = [];
|
|
20
|
-
logger.subscribe(record => published.push(record));
|
|
21
|
-
logger.subscribe(() => { throw new Error('subscriber failure must be isolated'); });
|
|
22
|
-
const child = logger.child({ component: 'commit-reconciler', projectId: 'project-a', operationId: 'op-1', runId: 'run-1', commitSha: 'abc' });
|
|
23
|
-
const cause = new Error('cause known-secret-value');
|
|
24
|
-
cause.code = 'ECAUSE';
|
|
25
|
-
const failure = new Error('Bearer top-secret-token');
|
|
26
|
-
failure.code = 'ETEST';
|
|
27
|
-
failure.cause = cause;
|
|
28
|
-
for (const level of ['trace', 'debug', 'info', 'warn', 'error', 'fatal']) {
|
|
29
|
-
await child[level](`test.${level}`, `${level} message`, {
|
|
30
|
-
phase: 'test',
|
|
31
|
-
error: level === 'error' ? failure : null,
|
|
32
|
-
context: { apiKey: 'known-secret-value', nested: { authorization: 'Bearer nested-token', safe: 'kept' } },
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
await logger.close();
|
|
36
|
-
|
|
37
|
-
const projectDirectory = layout.getLogPath('project', 'project-a');
|
|
38
|
-
const files = fs.readdirSync(projectDirectory).filter(file => file.endsWith('.jsonl'));
|
|
39
|
-
assert.deepStrictEqual(files, [`${localDay()}.jsonl`], 'one project/day must use exactly one file');
|
|
40
|
-
assert(!files.some(file => /\.\d{3}\.jsonl$/.test(file)), 'v13 writer must never create size segments');
|
|
41
|
-
const allText = fs.readFileSync(path.join(projectDirectory, files[0]), 'utf8');
|
|
42
|
-
assert(!allText.includes('known-secret-value'));
|
|
43
|
-
assert(!allText.includes('top-secret-token'));
|
|
44
|
-
assert(!allText.includes('nested-token'));
|
|
45
|
-
assert(allText.includes('[REDACTED]'));
|
|
46
|
-
assert.strictEqual(published.length, 6, 'each durable append must publish exactly once');
|
|
47
|
-
assert.deepStrictEqual(published.map(record => record.level), ['trace', 'debug', 'info', 'warn', 'error', 'fatal']);
|
|
48
|
-
for (const line of allText.trim().split(/\r?\n/)) {
|
|
49
|
-
const record = JSON.parse(line);
|
|
50
|
-
assert.strictEqual(record.schema, 'log/v2');
|
|
51
|
-
assert.strictEqual(record.projectId, 'project-a');
|
|
52
|
-
assert.strictEqual(record.operationId, 'op-1');
|
|
53
|
-
assert(record.id && record.ts && record.event);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
await logger.info('system.completed', 'System record', { component: 'server', operationId: 'op-system' });
|
|
57
|
-
await logger.close();
|
|
58
|
-
assert(fs.existsSync(path.join(layout.getLogPath('system'), `${localDay()}.jsonl`)), 'unscoped logs belong to system/day');
|
|
59
|
-
|
|
60
|
-
const repository = new LogRepository({ layout, secrets: ['known-secret-value'] });
|
|
61
|
-
const first = repository.query({ pageSize: 2, projectId: 'project-a' });
|
|
62
|
-
assert.strictEqual(first.entries.length, 2);
|
|
63
|
-
assert(first.nextCursor);
|
|
64
|
-
const second = repository.query({ pageSize: 2, projectId: 'project-a', cursor: first.nextCursor });
|
|
65
|
-
assert.strictEqual(second.entries.length, 2);
|
|
66
|
-
assert.notStrictEqual(first.entries[0].id, second.entries[0].id);
|
|
67
|
-
assert.throws(
|
|
68
|
-
() => repository.query({ pageSize: 3, projectId: 'project-a', cursor: first.nextCursor }),
|
|
69
|
-
error => error.code === 'LOG_CURSOR_EXPIRED',
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
const exportPath = path.join(dataDir, 'exports', 'diagnostics.jsonl');
|
|
73
|
-
const exported = repository.exportToFile(exportPath, { projectId: 'project-a' });
|
|
74
|
-
assert.strictEqual(exported.count, 6);
|
|
75
|
-
assert(!fs.readFileSync(exportPath, 'utf8').includes('known-secret-value'));
|
|
76
|
-
assert.strictEqual(stderr, '');
|
|
77
|
-
assert.strictEqual(typeof repository.cleanup, 'undefined', 'production log cleanup API must not exist');
|
|
78
|
-
|
|
79
|
-
const blocker = path.join(dataDir, 'not-a-directory');
|
|
80
|
-
fs.writeFileSync(blocker, 'blocker');
|
|
81
|
-
const failingLayout = {
|
|
82
|
-
getDataDir() { return dataDir; },
|
|
83
|
-
getLogPath() { return path.join(blocker, 'logs'); },
|
|
84
|
-
};
|
|
85
|
-
const failing = new Logger({
|
|
86
|
-
layout: failingLayout,
|
|
87
|
-
settingsProvider: () => config,
|
|
88
|
-
secrets: ['known-secret-value'],
|
|
89
|
-
stderr: { write(value) { stderr += String(value); } },
|
|
90
|
-
});
|
|
91
|
-
const failingChild = failing.child({ component: 'failure-test' });
|
|
92
|
-
await failingChild.error('logger.failure.test', 'known-secret-value', { error: new Error('known-secret-value') });
|
|
93
|
-
assert.strictEqual(failing.getHealth().status, 'degraded', 'parent and child must share logger health');
|
|
94
|
-
assert.strictEqual(failingChild.getHealth().status, 'degraded');
|
|
95
|
-
assert(stderr.includes('logger fallback'));
|
|
96
|
-
assert(!stderr.includes('known-secret-value'));
|
|
97
|
-
console.log('structured-logger-test PASS');
|
|
98
|
-
})().catch(error => {
|
|
99
|
-
console.error(error.stack || error.message);
|
|
100
|
-
process.exitCode = 1;
|
|
101
|
-
});
|
|
1
|
+
const assert = require('assert');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { StorageLayout } = require('../lib/storage-layout');
|
|
6
|
+
const { Logger, LogRepository, localDay } = require('../lib/structured-logger');
|
|
7
|
+
|
|
8
|
+
(async () => {
|
|
9
|
+
const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pk-logger-v3-'));
|
|
10
|
+
const layout = new StorageLayout({ dataDir });
|
|
11
|
+
const config = { levels: ['trace', 'debug', 'info', 'warn', 'error', 'fatal'] };
|
|
12
|
+
let stderr = '';
|
|
13
|
+
const logger = new Logger({
|
|
14
|
+
layout,
|
|
15
|
+
settingsProvider: () => config,
|
|
16
|
+
secrets: ['known-secret-value'],
|
|
17
|
+
stderr: { write(value) { stderr += String(value); } },
|
|
18
|
+
});
|
|
19
|
+
const published = [];
|
|
20
|
+
logger.subscribe(record => published.push(record));
|
|
21
|
+
logger.subscribe(() => { throw new Error('subscriber failure must be isolated'); });
|
|
22
|
+
const child = logger.child({ component: 'commit-reconciler', projectId: 'project-a', operationId: 'op-1', runId: 'run-1', commitSha: 'abc' });
|
|
23
|
+
const cause = new Error('cause known-secret-value');
|
|
24
|
+
cause.code = 'ECAUSE';
|
|
25
|
+
const failure = new Error('Bearer top-secret-token');
|
|
26
|
+
failure.code = 'ETEST';
|
|
27
|
+
failure.cause = cause;
|
|
28
|
+
for (const level of ['trace', 'debug', 'info', 'warn', 'error', 'fatal']) {
|
|
29
|
+
await child[level](`test.${level}`, `${level} message`, {
|
|
30
|
+
phase: 'test',
|
|
31
|
+
error: level === 'error' ? failure : null,
|
|
32
|
+
context: { apiKey: 'known-secret-value', nested: { authorization: 'Bearer nested-token', safe: 'kept' } },
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
await logger.close();
|
|
36
|
+
|
|
37
|
+
const projectDirectory = layout.getLogPath('project', 'project-a');
|
|
38
|
+
const files = fs.readdirSync(projectDirectory).filter(file => file.endsWith('.jsonl'));
|
|
39
|
+
assert.deepStrictEqual(files, [`${localDay()}.jsonl`], 'one project/day must use exactly one file');
|
|
40
|
+
assert(!files.some(file => /\.\d{3}\.jsonl$/.test(file)), 'v13 writer must never create size segments');
|
|
41
|
+
const allText = fs.readFileSync(path.join(projectDirectory, files[0]), 'utf8');
|
|
42
|
+
assert(!allText.includes('known-secret-value'));
|
|
43
|
+
assert(!allText.includes('top-secret-token'));
|
|
44
|
+
assert(!allText.includes('nested-token'));
|
|
45
|
+
assert(allText.includes('[REDACTED]'));
|
|
46
|
+
assert.strictEqual(published.length, 6, 'each durable append must publish exactly once');
|
|
47
|
+
assert.deepStrictEqual(published.map(record => record.level), ['trace', 'debug', 'info', 'warn', 'error', 'fatal']);
|
|
48
|
+
for (const line of allText.trim().split(/\r?\n/)) {
|
|
49
|
+
const record = JSON.parse(line);
|
|
50
|
+
assert.strictEqual(record.schema, 'log/v2');
|
|
51
|
+
assert.strictEqual(record.projectId, 'project-a');
|
|
52
|
+
assert.strictEqual(record.operationId, 'op-1');
|
|
53
|
+
assert(record.id && record.ts && record.event);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
await logger.info('system.completed', 'System record', { component: 'server', operationId: 'op-system' });
|
|
57
|
+
await logger.close();
|
|
58
|
+
assert(fs.existsSync(path.join(layout.getLogPath('system'), `${localDay()}.jsonl`)), 'unscoped logs belong to system/day');
|
|
59
|
+
|
|
60
|
+
const repository = new LogRepository({ layout, secrets: ['known-secret-value'] });
|
|
61
|
+
const first = repository.query({ pageSize: 2, projectId: 'project-a' });
|
|
62
|
+
assert.strictEqual(first.entries.length, 2);
|
|
63
|
+
assert(first.nextCursor);
|
|
64
|
+
const second = repository.query({ pageSize: 2, projectId: 'project-a', cursor: first.nextCursor });
|
|
65
|
+
assert.strictEqual(second.entries.length, 2);
|
|
66
|
+
assert.notStrictEqual(first.entries[0].id, second.entries[0].id);
|
|
67
|
+
assert.throws(
|
|
68
|
+
() => repository.query({ pageSize: 3, projectId: 'project-a', cursor: first.nextCursor }),
|
|
69
|
+
error => error.code === 'LOG_CURSOR_EXPIRED',
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const exportPath = path.join(dataDir, 'exports', 'diagnostics.jsonl');
|
|
73
|
+
const exported = repository.exportToFile(exportPath, { projectId: 'project-a' });
|
|
74
|
+
assert.strictEqual(exported.count, 6);
|
|
75
|
+
assert(!fs.readFileSync(exportPath, 'utf8').includes('known-secret-value'));
|
|
76
|
+
assert.strictEqual(stderr, '');
|
|
77
|
+
assert.strictEqual(typeof repository.cleanup, 'undefined', 'production log cleanup API must not exist');
|
|
78
|
+
|
|
79
|
+
const blocker = path.join(dataDir, 'not-a-directory');
|
|
80
|
+
fs.writeFileSync(blocker, 'blocker');
|
|
81
|
+
const failingLayout = {
|
|
82
|
+
getDataDir() { return dataDir; },
|
|
83
|
+
getLogPath() { return path.join(blocker, 'logs'); },
|
|
84
|
+
};
|
|
85
|
+
const failing = new Logger({
|
|
86
|
+
layout: failingLayout,
|
|
87
|
+
settingsProvider: () => config,
|
|
88
|
+
secrets: ['known-secret-value'],
|
|
89
|
+
stderr: { write(value) { stderr += String(value); } },
|
|
90
|
+
});
|
|
91
|
+
const failingChild = failing.child({ component: 'failure-test' });
|
|
92
|
+
await failingChild.error('logger.failure.test', 'known-secret-value', { error: new Error('known-secret-value') });
|
|
93
|
+
assert.strictEqual(failing.getHealth().status, 'degraded', 'parent and child must share logger health');
|
|
94
|
+
assert.strictEqual(failingChild.getHealth().status, 'degraded');
|
|
95
|
+
assert(stderr.includes('logger fallback'));
|
|
96
|
+
assert(!stderr.includes('known-secret-value'));
|
|
97
|
+
console.log('structured-logger-test PASS');
|
|
98
|
+
})().catch(error => {
|
|
99
|
+
console.error(error.stack || error.message);
|
|
100
|
+
process.exitCode = 1;
|
|
101
|
+
});
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// _site/_test/t07b-cln-005-coverage-test.js
|
|
2
|
+
//
|
|
3
|
+
// T07B ledger coverage for spec CLN-005 "活跃数据保留"
|
|
4
|
+
// (qa-autopilot/config/test-cases.json).
|
|
5
|
+
//
|
|
6
|
+
// steps : "ACTIVE/FAILED/RETAIN与旧PASSED目录混合。"
|
|
7
|
+
// expected : "仅PASSED且到期进入清单;首失败/检查点/基线永不自动删。"
|
|
8
|
+
//
|
|
9
|
+
// The behaviour under test is the real cleanup planner of the QA control
|
|
10
|
+
// package (qa-autopilot/lib/safety.cjs -> cleanupPlan / applyCleanup) together
|
|
11
|
+
// with the real checkpoint store (qa-autopilot/lib/state.cjs -> Store). The
|
|
12
|
+
// fixture is an isolated QA root that mixes every run status, so the plan is
|
|
13
|
+
// checked against the spec itself and not against a hand-written expectation.
|
|
14
|
+
//
|
|
15
|
+
// Every assertion message starts with "QA-SPEC-CLN-005" so the controller can
|
|
16
|
+
// confirm on its own that this expectation is guarded.
|
|
17
|
+
|
|
18
|
+
'use strict';
|
|
19
|
+
|
|
20
|
+
const assert = require('node:assert/strict');
|
|
21
|
+
const fs = require('node:fs');
|
|
22
|
+
const os = require('node:os');
|
|
23
|
+
const path = require('node:path');
|
|
24
|
+
|
|
25
|
+
const CONTROL_ROOT = path.resolve(__dirname, '..', '..', 'qa-autopilot');
|
|
26
|
+
const SAFETY_LIB = path.join(CONTROL_ROOT, 'lib', 'safety.cjs');
|
|
27
|
+
const STATE_LIB = path.join(CONTROL_ROOT, 'lib', 'state.cjs');
|
|
28
|
+
|
|
29
|
+
if (!fs.existsSync(SAFETY_LIB) || !fs.existsSync(STATE_LIB)) {
|
|
30
|
+
console.error('t07b-cln-005-coverage-test FAILED: QA control library is missing at ' + CONTROL_ROOT);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const { cleanupPlan, applyCleanup, ownedRun, setRunStatus, readJSON, atomicJSON, hash } = require(SAFETY_LIB);
|
|
35
|
+
const { Store } = require(STATE_LIB);
|
|
36
|
+
|
|
37
|
+
const EPOCH = new Date(0).toISOString();
|
|
38
|
+
const RETENTION_HOURS = 1;
|
|
39
|
+
const FIRST_FAILURE_LOG = 'first failure stdout (redacted)\n';
|
|
40
|
+
const FIRST_FAILURE_SHOT = Buffer.from('89504e470d0a1a0a0000000d49484452', 'hex');
|
|
41
|
+
|
|
42
|
+
function writeFile(file, content) {
|
|
43
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
44
|
+
fs.writeFileSync(file, content);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Creates a real owned run directory through the control library, then pins the
|
|
48
|
+
// finished timestamp so "expired" and "not expired" are decided by the fixture
|
|
49
|
+
// and not by wall-clock luck.
|
|
50
|
+
function ownedRunWithStatus(qa, id, status, finishedAt) {
|
|
51
|
+
const dir = ownedRun(qa, id);
|
|
52
|
+
setRunStatus(dir, status);
|
|
53
|
+
const marker = path.join(dir, '.qa-owner.json');
|
|
54
|
+
const state = readJSON(marker);
|
|
55
|
+
state.finishedAt = finishedAt;
|
|
56
|
+
atomicJSON(marker, state);
|
|
57
|
+
return dir;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function readBytes(file) {
|
|
61
|
+
return fs.readFileSync(file);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const qa = fs.mkdtempSync(path.join(os.tmpdir(), 'qa-cln005-'));
|
|
65
|
+
try {
|
|
66
|
+
const runsRoot = path.join(qa, '.runtime', 'runs');
|
|
67
|
+
|
|
68
|
+
// --- mixed run fixture: only one of these may ever reach the cleanup list ---
|
|
69
|
+
const expired = ownedRunWithStatus(qa, 'expired-passed', 'PASSED', EPOCH);
|
|
70
|
+
writeFile(path.join(expired, 'temp.txt'), 'expired run payload');
|
|
71
|
+
writeFile(path.join(expired, 'logs', 'stdout.log'), 'expired run log');
|
|
72
|
+
|
|
73
|
+
const fresh = ownedRunWithStatus(qa, 'fresh-passed', 'PASSED', new Date().toISOString());
|
|
74
|
+
writeFile(path.join(fresh, 'temp.txt'), 'fresh run payload');
|
|
75
|
+
|
|
76
|
+
// An ACTIVE run is protected by its status alone, even when it looks ancient.
|
|
77
|
+
const active = ownedRunWithStatus(qa, 'active-run', 'ACTIVE', EPOCH);
|
|
78
|
+
writeFile(path.join(active, 'temp.txt'), 'active run payload');
|
|
79
|
+
|
|
80
|
+
const failed = ownedRunWithStatus(qa, 'failed-run', 'FAILED', EPOCH);
|
|
81
|
+
writeFile(path.join(failed, 'first-failure', 'stdout.log'), FIRST_FAILURE_LOG);
|
|
82
|
+
writeFile(path.join(failed, 'first-failure', 'screenshot.png'), FIRST_FAILURE_SHOT);
|
|
83
|
+
|
|
84
|
+
const retained = ownedRunWithStatus(qa, 'retained-run', 'RETAIN', EPOCH);
|
|
85
|
+
writeFile(path.join(retained, 'evidence.json'), '{"retained":true}');
|
|
86
|
+
|
|
87
|
+
// A PASSED run without a usable finishedAt has no proven expiry.
|
|
88
|
+
const brokenFinished = ownedRunWithStatus(qa, 'broken-finished-run', 'PASSED', 'not-a-date');
|
|
89
|
+
writeFile(path.join(brokenFinished, 'temp.txt'), 'broken finished payload');
|
|
90
|
+
|
|
91
|
+
// Runs this controller does not own: no marker, a foreign id, a foreign root.
|
|
92
|
+
const unowned = path.join(runsRoot, 'unowned-run');
|
|
93
|
+
writeFile(path.join(unowned, 'data.txt'), 'unowned payload');
|
|
94
|
+
|
|
95
|
+
const foreignId = path.join(runsRoot, 'foreign-id-run');
|
|
96
|
+
writeFile(path.join(foreignId, 'data.txt'), 'foreign id payload');
|
|
97
|
+
atomicJSON(path.join(foreignId, '.qa-owner.json'), {
|
|
98
|
+
schema: 1, id: 'another-id', root: fs.realpathSync(runsRoot), createdAt: EPOCH, status: 'PASSED', finishedAt: EPOCH,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const foreignRoot = path.join(runsRoot, 'foreign-root-run');
|
|
102
|
+
writeFile(path.join(foreignRoot, 'data.txt'), 'foreign root payload');
|
|
103
|
+
atomicJSON(path.join(foreignRoot, '.qa-owner.json'), {
|
|
104
|
+
schema: 1, id: 'foreign-root-run', root: path.join(qa, 'elsewhere'), createdAt: EPOCH, status: 'PASSED', finishedAt: EPOCH,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// --- checkpoint, baseline and work clone live outside the run area ---
|
|
108
|
+
const store = new Store(path.join(qa, 'state'));
|
|
109
|
+
const checkpoint = store.transition('BASELINE_VERIFYING');
|
|
110
|
+
const checkpointFile = path.join(qa, 'state', 'checkpoint.json');
|
|
111
|
+
const journalFile = path.join(qa, 'state', 'journal', '00000001.json');
|
|
112
|
+
|
|
113
|
+
const baselineRecord = {
|
|
114
|
+
baseSha: 'b'.repeat(40), tag: 'qa-baseline-20261020', branch: 'qa/test-20261020', status: 'REMOTE_BASELINE_CONFIRMED',
|
|
115
|
+
};
|
|
116
|
+
const baselineFile = path.join(qa, 'state', 'baseline.json');
|
|
117
|
+
atomicJSON(baselineFile, baselineRecord);
|
|
118
|
+
|
|
119
|
+
const workspaceFile = path.join(qa, '.runtime', 'workspaces', 'repair', 'src', 'app.js');
|
|
120
|
+
writeFile(workspaceFile, 'console.log("work clone");\n');
|
|
121
|
+
|
|
122
|
+
// --- dry run ---
|
|
123
|
+
const plan = cleanupPlan(qa, RETENTION_HOURS);
|
|
124
|
+
const planFile = path.join(qa, 'state', 'cleanup-plan.json');
|
|
125
|
+
atomicJSON(planFile, { olderThanHours: RETENTION_HOURS, plan, planHash: hash(JSON.stringify(plan)) });
|
|
126
|
+
|
|
127
|
+
// Only the expired, owned, PASSED run may enter the list.
|
|
128
|
+
assert.deepEqual(
|
|
129
|
+
plan.map(item => item.id),
|
|
130
|
+
['expired-passed'],
|
|
131
|
+
'QA-SPEC-CLN-005 仅PASSED且到期进入清单:混合目录中只有已到期的自有PASSED运行进入清单',
|
|
132
|
+
);
|
|
133
|
+
assert.equal(plan[0].id, 'expired-passed', 'QA-SPEC-CLN-005 仅PASSED且到期进入清单:进入清单的运行必须是已到期的PASSED运行');
|
|
134
|
+
|
|
135
|
+
const plannedFiles = plan.flatMap(item => item.entries.map(entry => entry.relative));
|
|
136
|
+
assert.ok(
|
|
137
|
+
plannedFiles.includes(path.join('expired-passed', 'temp.txt')),
|
|
138
|
+
'QA-SPEC-CLN-005 仅PASSED且到期进入清单:清单逐文件列出到期运行的内容',
|
|
139
|
+
);
|
|
140
|
+
assert.ok(
|
|
141
|
+
plannedFiles.includes(path.join('expired-passed', 'logs', 'stdout.log')),
|
|
142
|
+
'QA-SPEC-CLN-005 仅PASSED且到期进入清单:清单逐文件列出到期运行的子目录内容',
|
|
143
|
+
);
|
|
144
|
+
assert.ok(
|
|
145
|
+
plan[0].entries.every(entry => /^[0-9a-f]{64}$/.test(entry.sha256)),
|
|
146
|
+
'QA-SPEC-CLN-005 仅PASSED且到期进入清单:每个被列入的文件都带可核对的哈希',
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
// Every other run status and every foreign directory stays out of the list.
|
|
150
|
+
for (const id of ['fresh-passed', 'active-run', 'failed-run', 'retained-run', 'broken-finished-run', 'unowned-run', 'foreign-id-run', 'foreign-root-run']) {
|
|
151
|
+
assert.ok(
|
|
152
|
+
!plannedFiles.some(relative => relative.startsWith(id + path.sep)),
|
|
153
|
+
'QA-SPEC-CLN-005 仅PASSED且到期进入清单:' + id + ' 不得进入清理清单',
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// The retention floor keeps a just finished run out of reach.
|
|
158
|
+
assert.throws(
|
|
159
|
+
() => cleanupPlan(qa, 0),
|
|
160
|
+
{ code: 'RETENTION' },
|
|
161
|
+
'QA-SPEC-CLN-005 仅PASSED且到期进入清单:保留期低于一小时时拒绝出清单',
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
// --- apply the reviewed plan ---
|
|
165
|
+
const deleted = applyCleanup(qa, { olderThanHours: RETENTION_HOURS, planHash: hash(JSON.stringify(plan)) });
|
|
166
|
+
assert.deepEqual(
|
|
167
|
+
deleted,
|
|
168
|
+
['expired-passed'],
|
|
169
|
+
'QA-SPEC-CLN-005 仅PASSED且到期进入清单:执行时只删除清单里的到期PASSED运行',
|
|
170
|
+
);
|
|
171
|
+
assert.equal(fs.existsSync(expired), false, 'QA-SPEC-CLN-005 仅PASSED且到期进入清单:到期PASSED运行被真正删除');
|
|
172
|
+
assert.equal(fs.existsSync(path.join(expired, 'temp.txt')), false, 'QA-SPEC-CLN-005 仅PASSED且到期进入清单:到期运行的文件被逐个删除');
|
|
173
|
+
|
|
174
|
+
// Active / failed / retained / fresh runs and their payloads stay untouched.
|
|
175
|
+
assert.equal(fs.existsSync(active), true, 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:ACTIVE运行目录被保留');
|
|
176
|
+
assert.equal(fs.readFileSync(path.join(active, 'temp.txt'), 'utf8'), 'active run payload', 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:ACTIVE运行内容被保留');
|
|
177
|
+
|
|
178
|
+
assert.equal(fs.existsSync(failed), true, 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:FAILED运行目录被保留');
|
|
179
|
+
assert.equal(fs.readFileSync(path.join(failed, 'first-failure', 'stdout.log'), 'utf8'), FIRST_FAILURE_LOG, 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:首失败日志被保留');
|
|
180
|
+
assert.ok(readBytes(path.join(failed, 'first-failure', 'screenshot.png')).equals(FIRST_FAILURE_SHOT), 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:首失败截图被保留');
|
|
181
|
+
|
|
182
|
+
assert.equal(fs.existsSync(retained), true, 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:RETAIN运行目录被保留');
|
|
183
|
+
assert.equal(fs.readFileSync(path.join(retained, 'evidence.json'), 'utf8'), '{"retained":true}', 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:RETAIN运行证据被保留');
|
|
184
|
+
|
|
185
|
+
assert.equal(fs.existsSync(fresh), true, 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:未到期的PASSED运行被保留');
|
|
186
|
+
assert.equal(fs.readFileSync(path.join(fresh, 'temp.txt'), 'utf8'), 'fresh run payload', 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:未到期运行内容被保留');
|
|
187
|
+
|
|
188
|
+
for (const id of ['unowned-run', 'foreign-id-run', 'foreign-root-run', 'broken-finished-run']) {
|
|
189
|
+
assert.equal(fs.existsSync(path.join(runsRoot, id)), true, 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:非自有运行目录 ' + id + ' 被保留');
|
|
190
|
+
}
|
|
191
|
+
assert.equal(fs.readFileSync(path.join(unowned, 'data.txt'), 'utf8'), 'unowned payload', 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:无归属标记的目录内容被保留');
|
|
192
|
+
|
|
193
|
+
// Checkpoint, baseline and the work clone are outside the cleanup scope.
|
|
194
|
+
assert.equal(fs.existsSync(checkpointFile), true, 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:检查点文件被保留');
|
|
195
|
+
assert.deepEqual(readJSON(checkpointFile), checkpoint, 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:检查点内容未被改动');
|
|
196
|
+
assert.equal(fs.existsSync(journalFile), true, 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:检查点日志被保留');
|
|
197
|
+
assert.equal(fs.existsSync(baselineFile), true, 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:基线记录被保留');
|
|
198
|
+
assert.deepEqual(readJSON(baselineFile), baselineRecord, 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:基线记录内容未被改动');
|
|
199
|
+
assert.equal(fs.existsSync(workspaceFile), true, 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:工作clone不在清理范围');
|
|
200
|
+
assert.equal(fs.existsSync(planFile), true, 'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:已审计的清理计划记录被保留');
|
|
201
|
+
|
|
202
|
+
// A survivor never silently turns into a deletion candidate.
|
|
203
|
+
assert.deepEqual(
|
|
204
|
+
cleanupPlan(qa, RETENTION_HOURS),
|
|
205
|
+
[],
|
|
206
|
+
'QA-SPEC-CLN-005 首失败/检查点/基线永不自动删:清理后重新出清单仍为空,保留数据不会自动变成可删数据',
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
console.log('t07b-cln-005-coverage-test PASS (QA-SPEC-CLN-005: only expired owned PASSED runs are listed and deleted; first failure, checkpoint and baseline are never auto-deleted)');
|
|
210
|
+
} finally {
|
|
211
|
+
fs.rmSync(qa, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
212
|
+
}
|