@sanqianx/project-knowledge 5.0.24 → 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 -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 +66 -63
- 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,554 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// P-QA-LOG-INTEGRATION-5025 portability gate (canonical tracked regression
|
|
3
|
+
// entry for the logging acceptance / logging-safety lane).
|
|
4
|
+
//
|
|
5
|
+
// This entry does NOT re-run the acceptance drivers. It proves the
|
|
6
|
+
// PORTABILITY contract that lets those drivers enter the canonical
|
|
7
|
+
// cross-platform `npm test`:
|
|
8
|
+
//
|
|
9
|
+
// 1. No machine-specific absolute path survives in any lane file
|
|
10
|
+
// (comments excluded; string literals are executable and are scanned).
|
|
11
|
+
// 2. The isolation helper installs a complete, own environment before any
|
|
12
|
+
// product module loads: temp root OUTSIDE the source repository, own
|
|
13
|
+
// HOME/USERPROFILE/CODEX_HOME/CLAUDE_CONFIG_DIR/APPDATA/LOCALAPPDATA/
|
|
14
|
+
// TEMP/TMP/TMPDIR, own dual KB data roots, own Bridge / agent-terminal /
|
|
15
|
+
// workbench roots. The developer's real configuration is never used.
|
|
16
|
+
// 3. Every require() target of every lane entry resolves to a file that is
|
|
17
|
+
// either git-tracked or explicitly declared in this lane's manifest, so
|
|
18
|
+
// a clean checkout of tracked source can execute the entries (no
|
|
19
|
+
// dependency on untracked fixtures or local drive letters).
|
|
20
|
+
// 4. The run-all / manual-QA classification matches the runner's own rule
|
|
21
|
+
// (read from run-all-tests.js), and the frozen R1 exploration probes are
|
|
22
|
+
// not submitted as canonical entries.
|
|
23
|
+
// 5. No lane entry performs a real model/provider call; the entries that
|
|
24
|
+
// need an analyzer use the labelled offline stand-in.
|
|
25
|
+
// 6. The default evidence directories are inside a gitignored tree.
|
|
26
|
+
// 7. (P-LOGGING-ISOLATION-R2) The driver environment itself is sanitized:
|
|
27
|
+
// a poisoned environment proves that ambient provider keys, proxies,
|
|
28
|
+
// NODE_OPTIONS, module endpoints and CLI-injected configuration do not
|
|
29
|
+
// survive the install, that the entry's explicit lane values do, that a
|
|
30
|
+
// grandchild process inherits the same clean base, and that the real
|
|
31
|
+
// browser executable is still resolvable after HOME/LOCALAPPDATA moved.
|
|
32
|
+
// 8. (P-LOGGING-PS-BROWSER-R3) The remaining isolation details are proven
|
|
33
|
+
// as well: PSModuleAnalysisCachePath is a FILE path whose parent
|
|
34
|
+
// directory exists (structural contract asserted on EVERY platform;
|
|
35
|
+
// the own-PowerShell-child proof runs on Windows only); the
|
|
36
|
+
// browser default profile Chrome derives from USERPROFILE is scaffolded
|
|
37
|
+
// inside the owned home (never the developer's real profile); and the
|
|
38
|
+
// lane tree is really removed when the entry releases it.
|
|
39
|
+
//
|
|
40
|
+
// Strict mode: set PK_LOGGING_GATE_STRICT_TRACKED=1 to additionally require
|
|
41
|
+
// every manifest file to be committed to Git (the commit step belongs to the
|
|
42
|
+
// Leader, not to this lane).
|
|
43
|
+
|
|
44
|
+
const fs = require('node:fs');
|
|
45
|
+
const os = require('node:os');
|
|
46
|
+
const path = require('node:path');
|
|
47
|
+
const { spawnSync } = require('node:child_process');
|
|
48
|
+
|
|
49
|
+
const {
|
|
50
|
+
installLoggingTestEnv, resolveEvidenceDir, isInsideRepo,
|
|
51
|
+
DEAD_MODULE_URL, MODULE_URL_KEYS, MODULE_FLAG_KEYS, MODULE_COMMAND_KEYS,
|
|
52
|
+
} = require('./helpers/parallel-logging-integration-5025-env');
|
|
53
|
+
|
|
54
|
+
const ROOT = path.resolve(__dirname, '../..');
|
|
55
|
+
const ARTIFACTS = resolveEvidenceDir(path.resolve(ROOT, 'qa-autopilot/artifacts/parallel-20261023/logging-integration-5025/evidence/portability'));
|
|
56
|
+
|
|
57
|
+
// Every file this lane owns and hands to the Leader for the canonical commit.
|
|
58
|
+
const LANE_MANIFEST = [
|
|
59
|
+
'_site/_test/parallel-logging-acceptance-log003-test.js',
|
|
60
|
+
'_site/_test/parallel-logging-acceptance-log004-test.js',
|
|
61
|
+
'_site/_test/parallel-logging-acceptance-log005-test.js',
|
|
62
|
+
'_site/_test/parallel-logging-acceptance-log006-test.js',
|
|
63
|
+
'_site/_test/parallel-logging-acceptance-log007-test.js',
|
|
64
|
+
'_site/_test/parallel-logging-acceptance-log008-test.js',
|
|
65
|
+
'_site/_test/parallel-logging-fix-r2-normalhook-test.js',
|
|
66
|
+
'_site/_test/parallel-logging-fix-r2-gap-test.js',
|
|
67
|
+
'_site/_test/helpers/parallel-logging-acceptance-fixture.js',
|
|
68
|
+
'_site/_test/helpers/parallel-logging-acceptance-proxy.js',
|
|
69
|
+
'_site/_test/helpers/parallel-logging-fix-r2-proxy.js',
|
|
70
|
+
'_site/_test/helpers/parallel-logging-integration-5025-env.js',
|
|
71
|
+
'_site/_test/parallel-logging-integration-5025-portability-test.js',
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
// The R1 exploration probes: frozen history, never canonical entries.
|
|
75
|
+
const FROZEN_EXPLORATION = [
|
|
76
|
+
'_site/_test/parallel-logging-acceptance-log003-probe.js',
|
|
77
|
+
'_site/_test/parallel-logging-acceptance-log004-probe.js',
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
// Manual-QA-only entry (not matched by the runner glob; needs --expect).
|
|
81
|
+
const MANUAL_ONLY = '_site/_test/parallel-logging-fix-r2-crash-probe.js';
|
|
82
|
+
LANE_MANIFEST.push(MANUAL_ONLY);
|
|
83
|
+
|
|
84
|
+
const SCAN_FILES = Array.from(new Set(LANE_MANIFEST));
|
|
85
|
+
|
|
86
|
+
const AUTOMATIC_ENTRIES = LANE_MANIFEST.filter(file => file.endsWith('-test.js') && file.includes('/parallel-logging-'));
|
|
87
|
+
|
|
88
|
+
const REQUIRED_ENV_KEYS = [
|
|
89
|
+
'HOME',
|
|
90
|
+
'USERPROFILE',
|
|
91
|
+
'CODEX_HOME',
|
|
92
|
+
'CLAUDE_CONFIG_DIR',
|
|
93
|
+
'APPDATA',
|
|
94
|
+
'LOCALAPPDATA',
|
|
95
|
+
'TEMP',
|
|
96
|
+
'TMP',
|
|
97
|
+
'TMPDIR',
|
|
98
|
+
'PSModuleAnalysisCachePath',
|
|
99
|
+
'KB_DATA_DIR',
|
|
100
|
+
'KB_KNOWLEDGE_DATA_DIR',
|
|
101
|
+
'AI_CODING_EVENT_BRIDGE_HOME',
|
|
102
|
+
'AGENT_TERMINAL_DATA_DIR',
|
|
103
|
+
'CLAUDE_AI_WORKBENCH_DATA_DIR',
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
// P-LOGGING-ISOLATION-R2: the poisoned environment. Every value here is
|
|
107
|
+
// fabricated - the sentinel never reads a real key and never contacts a real
|
|
108
|
+
// host. The point is to prove what the install REMOVES and what it KEEPS.
|
|
109
|
+
const POISON_ENV = {
|
|
110
|
+
MINIMAX_API_KEY: 'poison-fabricated-key',
|
|
111
|
+
ANTHROPIC_API_KEY: 'poison-fabricated-key',
|
|
112
|
+
OPENAI_API_KEY: 'poison-fabricated-key',
|
|
113
|
+
KB_SITE_AUTH_TOKEN: 'poison-fabricated-token',
|
|
114
|
+
KB_WORKBENCH_RUNTIME_TOKEN: 'poison-fabricated-token',
|
|
115
|
+
HTTP_PROXY: 'http://poison-user:poison-password@proxy.invalid:1',
|
|
116
|
+
HTTPS_PROXY: 'http://poison-user:poison-password@proxy.invalid:1',
|
|
117
|
+
ALL_PROXY: 'http://poison-user:poison-password@proxy.invalid:1',
|
|
118
|
+
NODE_OPTIONS: '--require poison-never-loaded.js',
|
|
119
|
+
ANTHROPIC_BASE_URL: 'http://poison.invalid:1/',
|
|
120
|
+
KB_TERMINAL_URL: 'http://poison.invalid:1/',
|
|
121
|
+
KB_VECTORHUB_URL: 'http://poison.invalid:1/',
|
|
122
|
+
KB_KNOWLEDGE_ENGINE_URL: 'http://poison.invalid:1/',
|
|
123
|
+
KB_EVENTBRIDGE_URL: 'http://poison.invalid:1/',
|
|
124
|
+
KB_MODULES_AUTOSTART: '1',
|
|
125
|
+
KB_MODULES_REGISTER: '1',
|
|
126
|
+
KB_TERMINAL_COMMAND: 'poison-never-executed',
|
|
127
|
+
GIT_CONFIG_GLOBAL: 'poison-git-config',
|
|
128
|
+
GIT_DIR: 'poison-git-dir',
|
|
129
|
+
KB_AUTOMATION_FAKE_CLAUDE: 'ambient-fake-marker',
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// The lane paths that must be redirected away from any ambient value.
|
|
133
|
+
// LOCALAPPDATA is deliberately NOT poisoned: the helper resolves the real
|
|
134
|
+
// browser executable from it BEFORE any path moves, so poisoning it here
|
|
135
|
+
// would hide the per-user Chrome install. Its redirection is proven by the
|
|
136
|
+
// lane-root containment check below.
|
|
137
|
+
const POISON_PATH_KEYS = [
|
|
138
|
+
'HOME', 'USERPROFILE', 'APPDATA', 'TEMP', 'TMP', 'TMPDIR',
|
|
139
|
+
'PSModuleAnalysisCachePath', 'CODEX_HOME', 'CLAUDE_CONFIG_DIR',
|
|
140
|
+
'KB_DATA_DIR', 'KB_KNOWLEDGE_DATA_DIR', 'AI_CODING_EVENT_BRIDGE_HOME',
|
|
141
|
+
'AGENT_TERMINAL_DATA_DIR', 'CLAUDE_AI_WORKBENCH_DATA_DIR',
|
|
142
|
+
];
|
|
143
|
+
|
|
144
|
+
// The explicit lane values the entry owns. They are applied AFTER the
|
|
145
|
+
// sanitization and must survive it.
|
|
146
|
+
const LANE_OVERRIDES = {
|
|
147
|
+
KB_AUTOMATION_FAKE_CLAUDE: '1',
|
|
148
|
+
KB_EMBEDDING_FAKE: '1',
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const stripComments = source => source
|
|
152
|
+
.replace(/\/\*[\s\S]*?\*\//g, ' ')
|
|
153
|
+
.replace(/(^|[^:])\/\/[^\n]*/g, '$1');
|
|
154
|
+
|
|
155
|
+
const git = args => {
|
|
156
|
+
const res = spawnSync('git', ['-C', ROOT, ...args], { encoding: 'utf8' });
|
|
157
|
+
if (res.status !== 0) throw new Error(`git ${args.join(' ')} failed: ${res.stderr || res.stdout}`);
|
|
158
|
+
return res.stdout.trim();
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const isTracked = file => {
|
|
162
|
+
const res = spawnSync('git', ['-C', ROOT, 'ls-files', '--error-unmatch', '--', file], { encoding: 'utf8' });
|
|
163
|
+
return res.status === 0;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const isIgnored = file => {
|
|
167
|
+
const res = spawnSync('git', ['-C', ROOT, 'check-ignore', '-q', '--', file]);
|
|
168
|
+
return res.status === 0;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
function requiresOf(file) {
|
|
172
|
+
const source = fs.readFileSync(path.join(ROOT, file), 'utf8');
|
|
173
|
+
const targets = [];
|
|
174
|
+
const pattern = /require\(\s*'([^']+)'\s*\)/g;
|
|
175
|
+
let match;
|
|
176
|
+
while ((match = pattern.exec(source)) !== null) {
|
|
177
|
+
const target = match[1];
|
|
178
|
+
if (target.startsWith('node:')) continue;
|
|
179
|
+
targets.push(target);
|
|
180
|
+
}
|
|
181
|
+
return targets;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function main() {
|
|
185
|
+
fs.mkdirSync(ARTIFACTS, { recursive: true });
|
|
186
|
+
const evidence = { caseId: 'P-QA-LOG-INTEGRATION-5025-portability', startedAt: new Date().toISOString(), checks: {} };
|
|
187
|
+
const failures = [];
|
|
188
|
+
|
|
189
|
+
git(['rev-parse', '--is-inside-work-tree']);
|
|
190
|
+
|
|
191
|
+
// 1. No machine-specific absolute path in any lane file.
|
|
192
|
+
const absolutePathHits = [];
|
|
193
|
+
// Built from parts so this gate's own source does not contain the needle.
|
|
194
|
+
const OLD_TEMP_BASE_NAME = ['.project-knowledge', 'test-temp'].join('-');
|
|
195
|
+
for (const file of SCAN_FILES) {
|
|
196
|
+
const code = stripComments(fs.readFileSync(path.join(ROOT, file), 'utf8'));
|
|
197
|
+
// A drive letter only counts when it starts a path, not inside a URL
|
|
198
|
+
// scheme such as "http://".
|
|
199
|
+
const matches = code.match(/(?<![A-Za-z0-9_])[A-Za-z]:[\\/][^\s'"`)]*/g) || [];
|
|
200
|
+
const oldTempBase = code.includes(OLD_TEMP_BASE_NAME) ? [OLD_TEMP_BASE_NAME] : [];
|
|
201
|
+
if (matches.length || oldTempBase.length) absolutePathHits.push({ file, matches, oldTempBase });
|
|
202
|
+
}
|
|
203
|
+
evidence.checks.noMachineSpecificPath = { scannedFiles: SCAN_FILES.length, hits: absolutePathHits };
|
|
204
|
+
if (absolutePathHits.length) failures.push(`machine-specific absolute path in: ${absolutePathHits.map(hit => hit.file).join(', ')}`);
|
|
205
|
+
|
|
206
|
+
// 1b. Every manifest file exists.
|
|
207
|
+
const missingManifest = SCAN_FILES.filter(file => !fs.existsSync(path.join(ROOT, file)));
|
|
208
|
+
evidence.checks.manifestExists = { missing: missingManifest };
|
|
209
|
+
if (missingManifest.length) failures.push(`manifest files missing: ${missingManifest.join(', ')}`);
|
|
210
|
+
|
|
211
|
+
// 2. Isolation contract of the helper, proven against a POISONED ambient
|
|
212
|
+
// environment (P-LOGGING-ISOLATION-R2). Redirecting a few directories is
|
|
213
|
+
// not isolation: the driver's own environment still reached every child
|
|
214
|
+
// process. The poison below is fabricated - no real key is read.
|
|
215
|
+
const realHome = process.env.USERPROFILE || process.env.HOME;
|
|
216
|
+
const ambientLocalAppData = process.env.LOCALAPPDATA;
|
|
217
|
+
// The poison/temp base must be OUTSIDE the repository: on the Windows CI
|
|
218
|
+
// job os.tmpdir() is the in-workspace .tmp directory, and a tool root built
|
|
219
|
+
// from it is exactly the in-repo temp shape the helper must refuse. The
|
|
220
|
+
// runner-provided PK_TEST_TEMP_ROOT (runner.temp) is the documented
|
|
221
|
+
// outside-repo root; a normal dev machine's tmpdir is outside as well.
|
|
222
|
+
const ambientTmp = (() => {
|
|
223
|
+
const candidates = [process.env.PK_TEST_TEMP_ROOT, os.tmpdir()];
|
|
224
|
+
for (const candidate of candidates) {
|
|
225
|
+
if (candidate && path.isAbsolute(path.resolve(candidate)) && !isInsideRepo(path.resolve(candidate))) {
|
|
226
|
+
return path.resolve(candidate);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return path.resolve(ROOT, '..');
|
|
230
|
+
})();
|
|
231
|
+
const poisonPaths = {};
|
|
232
|
+
for (const key of POISON_PATH_KEYS) {
|
|
233
|
+
poisonPaths[key] = path.join(ambientTmp, `poison-${key.toLowerCase()}`);
|
|
234
|
+
process.env[key] = poisonPaths[key];
|
|
235
|
+
}
|
|
236
|
+
for (const [key, value] of Object.entries(POISON_ENV)) process.env[key] = value;
|
|
237
|
+
// A tool-controlled knob: it must survive the sanitization and be honored.
|
|
238
|
+
const toolTempRoot = path.join(ambientTmp, 'pk-logging-gate-poison-temp');
|
|
239
|
+
process.env.PK_TEST_TEMP_ROOT = toolTempRoot;
|
|
240
|
+
|
|
241
|
+
// The browser that is resolvable BEFORE the install: after HOME/LOCALAPPDATA
|
|
242
|
+
// move it must still be reachable, otherwise the entries would fall back to
|
|
243
|
+
// the developer's real browser profile.
|
|
244
|
+
let preInstallChrome = null;
|
|
245
|
+
try { preInstallChrome = require('./helpers/find-chrome').findChromeDetailed(); } catch {}
|
|
246
|
+
|
|
247
|
+
const lane = installLoggingTestEnv({
|
|
248
|
+
caseId: 'P-QA-LOG-INTEGRATION-5025-portability',
|
|
249
|
+
prefix: 'logport',
|
|
250
|
+
extraEnv: LANE_OVERRIDES,
|
|
251
|
+
});
|
|
252
|
+
const installed = {};
|
|
253
|
+
for (const key of REQUIRED_ENV_KEYS) installed[key] = process.env[key];
|
|
254
|
+
const envProblems = [];
|
|
255
|
+
for (const key of REQUIRED_ENV_KEYS) {
|
|
256
|
+
const value = installed[key];
|
|
257
|
+
if (!value || !path.isAbsolute(value)) envProblems.push(`${key} is not an absolute path: ${value}`);
|
|
258
|
+
else if (!value.startsWith(lane.laneTmp)) envProblems.push(`${key} escapes the lane temp root: ${value}`);
|
|
259
|
+
}
|
|
260
|
+
if (isInsideRepo(lane.tempRoot)) envProblems.push(`temp root is inside the repository: ${lane.tempRoot}`);
|
|
261
|
+
if (installed.HOME === realHome) envProblems.push('HOME still points at the developer profile');
|
|
262
|
+
const evidenceDir = resolveEvidenceDir(path.join(ROOT, 'qa-autopilot/artifacts/parallel-20261023/logging-integration-5025/evidence/portability'), { PK_TEST_EVIDENCE_ROOT: path.join(lane.laneTmp, 'evidence-root') });
|
|
263
|
+
if (evidenceDir !== path.join(lane.laneTmp, 'evidence-root', 'portability')) envProblems.push(`PK_TEST_EVIDENCE_ROOT override not honoured: ${evidenceDir}`);
|
|
264
|
+
evidence.checks.isolation = {
|
|
265
|
+
tempRoot: lane.tempRoot,
|
|
266
|
+
tempRootOutsideRepo: !isInsideRepo(lane.tempRoot),
|
|
267
|
+
laneTmp: lane.laneTmp,
|
|
268
|
+
installedEnvKeys: installed,
|
|
269
|
+
isolatedEnvKeys: lane.isolatedEnvKeys,
|
|
270
|
+
evidenceOverride: evidenceDir,
|
|
271
|
+
problems: envProblems,
|
|
272
|
+
};
|
|
273
|
+
if (envProblems.length) failures.push(`isolation contract violated: ${envProblems.join('; ')}`);
|
|
274
|
+
|
|
275
|
+
// 2b. Poisoned-environment sentinel: what the install removes, what it
|
|
276
|
+
// keeps, what a grandchild inherits, and what the browser resolves to.
|
|
277
|
+
const sentinelProblems = [];
|
|
278
|
+
const sentinel = { poison: {}, removed: [], overrides: {}, child: null, chrome: {} };
|
|
279
|
+
const laneOwnedKeys = new Set([...MODULE_URL_KEYS, ...MODULE_FLAG_KEYS, ...MODULE_COMMAND_KEYS]);
|
|
280
|
+
|
|
281
|
+
for (const [key, value] of Object.entries(POISON_ENV)) {
|
|
282
|
+
sentinel.poison[key] = value;
|
|
283
|
+
const current = process.env[key];
|
|
284
|
+
if (laneOwnedKeys.has(key)) {
|
|
285
|
+
// Module endpoints / switches are reset to the lane's own values.
|
|
286
|
+
if (current === value) sentinelProblems.push(`${key} kept the poisoned ambient value`);
|
|
287
|
+
sentinel.overrides[key] = current;
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (LANE_OVERRIDES[key]) continue;
|
|
291
|
+
if (current !== undefined) sentinelProblems.push(`${key} survived the sanitization: ${current}`);
|
|
292
|
+
else sentinel.removed.push(key);
|
|
293
|
+
}
|
|
294
|
+
for (const [key, value] of Object.entries(LANE_OVERRIDES)) {
|
|
295
|
+
if (process.env[key] !== value) sentinelProblems.push(`${key} did not keep the explicit lane value ${value}: ${process.env[key]}`);
|
|
296
|
+
else sentinel.overrides[key] = value;
|
|
297
|
+
}
|
|
298
|
+
for (const key of POISON_PATH_KEYS) {
|
|
299
|
+
const value = process.env[key];
|
|
300
|
+
if (value === poisonPaths[key]) sentinelProblems.push(`${key} kept the poisoned path`);
|
|
301
|
+
if (!value || !path.isAbsolute(value)) sentinelProblems.push(`${key} is not an absolute path after the install: ${value}`);
|
|
302
|
+
else if (!value.startsWith(lane.laneTmp)) sentinelProblems.push(`${key} escapes the lane temp root: ${value}`);
|
|
303
|
+
}
|
|
304
|
+
if (process.env.PK_TEST_TEMP_ROOT !== toolTempRoot) sentinelProblems.push('PK_TEST_TEMP_ROOT did not survive the sanitization');
|
|
305
|
+
if (path.resolve(lane.tempRoot) !== path.resolve(toolTempRoot)) sentinelProblems.push(`the tool-controlled temp root was not honored: ${lane.tempRoot}`);
|
|
306
|
+
|
|
307
|
+
// A grandchild process must inherit the same clean base.
|
|
308
|
+
const childKeys = ['PATH', 'HOME', 'KB_DATA_DIR', 'KB_MODULES_AUTOSTART', 'KB_TERMINAL_URL', ...Object.keys(POISON_ENV)];
|
|
309
|
+
const probe = spawnSync(process.execPath, ['-e', `const keys=${JSON.stringify(childKeys)};const out={};for(const k of keys)out[k]=process.env[k]===undefined?null:process.env[k];process.stdout.write(JSON.stringify(out));`], { env: process.env, encoding: 'utf8' });
|
|
310
|
+
if (probe.status !== 0) {
|
|
311
|
+
sentinelProblems.push(`the grandchild environment probe failed: ${probe.stderr}`);
|
|
312
|
+
} else {
|
|
313
|
+
const childEnv = JSON.parse(probe.stdout);
|
|
314
|
+
for (const [key, value] of Object.entries(POISON_ENV)) {
|
|
315
|
+
if (laneOwnedKeys.has(key) || LANE_OVERRIDES[key]) continue;
|
|
316
|
+
if (childEnv[key] !== null) sentinelProblems.push(`the grandchild inherited ${key}`);
|
|
317
|
+
}
|
|
318
|
+
if (!childEnv.PATH) sentinelProblems.push('the grandchild lost PATH');
|
|
319
|
+
else if (childEnv.PATH !== process.env.PATH) sentinelProblems.push('the grandchild PATH differs from the sanitized base');
|
|
320
|
+
if (childEnv.HOME !== lane.dirs.home) sentinelProblems.push(`the grandchild HOME is not the lane home: ${childEnv.HOME}`);
|
|
321
|
+
if (childEnv.KB_MODULES_AUTOSTART !== '0') sentinelProblems.push('the grandchild did not inherit the lane module switch');
|
|
322
|
+
if (childEnv.KB_TERMINAL_URL !== DEAD_MODULE_URL) sentinelProblems.push(`the grandchild module endpoint is not the lane dead address: ${childEnv.KB_TERMINAL_URL}`);
|
|
323
|
+
sentinel.child = {
|
|
324
|
+
status: probe.status,
|
|
325
|
+
// Only key names and verdicts - the machine's own environment values are
|
|
326
|
+
// never written into the evidence.
|
|
327
|
+
inheritedNullKeys: Object.entries(childEnv).filter(([, value]) => value === null).map(([key]) => key),
|
|
328
|
+
pathPresent: Boolean(childEnv.PATH),
|
|
329
|
+
pathMatchesSanitizedBase: childEnv.PATH === process.env.PATH,
|
|
330
|
+
homeIsLaneHome: childEnv.HOME === lane.dirs.home,
|
|
331
|
+
moduleSwitch: childEnv.KB_MODULES_AUTOSTART,
|
|
332
|
+
moduleUrlIsLaneDeadAddress: childEnv.KB_TERMINAL_URL === DEAD_MODULE_URL,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// The real browser must still be resolvable after HOME/LOCALAPPDATA moved,
|
|
337
|
+
// and it must not be the developer's real profile.
|
|
338
|
+
const chromeProblems = [];
|
|
339
|
+
let resolvedChrome = null;
|
|
340
|
+
try {
|
|
341
|
+
resolvedChrome = require('./helpers/find-chrome').findChromeDetailed();
|
|
342
|
+
} catch (error) {
|
|
343
|
+
chromeProblems.push(`find-chrome failed after the install: ${error.code || error.message}`);
|
|
344
|
+
}
|
|
345
|
+
if (lane.chromePath) {
|
|
346
|
+
if (!resolvedChrome || resolvedChrome.path !== lane.chromePath) chromeProblems.push('the captured browser executable differs from the resolved one');
|
|
347
|
+
if (process.env.KB_CHROME_PATH !== lane.chromePath) chromeProblems.push('KB_CHROME_PATH does not carry the captured browser executable');
|
|
348
|
+
if (!resolvedChrome || resolvedChrome.source !== 'env') chromeProblems.push(`the browser was not resolved through the captured KB_CHROME_PATH: ${resolvedChrome && resolvedChrome.source}`);
|
|
349
|
+
if (!fs.existsSync(lane.chromePath)) chromeProblems.push('the captured browser executable does not exist');
|
|
350
|
+
}
|
|
351
|
+
if (preInstallChrome) {
|
|
352
|
+
if (!lane.chromePath) chromeProblems.push('the browser executable that was resolvable before the install was lost');
|
|
353
|
+
else if (lane.chromePath !== preInstallChrome.path) chromeProblems.push('the captured browser executable differs from the pre-install resolution');
|
|
354
|
+
}
|
|
355
|
+
for (const dir of lane.chromeProfileDirs) {
|
|
356
|
+
if (!dir.startsWith(lane.laneTmp)) chromeProblems.push(`the browser profile directory is outside the lane tree: ${dir}`);
|
|
357
|
+
}
|
|
358
|
+
// Chrome >= 136 also derives its default profile from
|
|
359
|
+
// <USERPROFILE>\AppData\Local\Google\Chrome\User Data, independently of
|
|
360
|
+
// LOCALAPPDATA. That derived directory must exist inside the owned home -
|
|
361
|
+
// and the developer's real default profile must never be part of it.
|
|
362
|
+
if (process.platform === 'win32') {
|
|
363
|
+
const ownedDerivedProfile = path.join(lane.dirs.home, 'AppData', 'Local', 'Google', 'Chrome', 'User Data');
|
|
364
|
+
if (!fs.existsSync(ownedDerivedProfile)) chromeProblems.push('the USERPROFILE-derived browser default profile directory is missing under the owned home');
|
|
365
|
+
if (!lane.chromeProfileDirs.includes(ownedDerivedProfile)) chromeProblems.push('the USERPROFILE-derived browser default profile directory is not scaffolded');
|
|
366
|
+
if (!ownedDerivedProfile.startsWith(lane.laneTmp)) chromeProblems.push('the USERPROFILE-derived browser default profile directory escapes the lane tree');
|
|
367
|
+
const realProfiles = [
|
|
368
|
+
ambientLocalAppData && path.join(ambientLocalAppData, 'Google', 'Chrome', 'User Data'),
|
|
369
|
+
realHome && path.join(realHome, 'AppData', 'Local', 'Google', 'Chrome', 'User Data'),
|
|
370
|
+
].filter(Boolean);
|
|
371
|
+
for (const realProfile of realProfiles) {
|
|
372
|
+
if (lane.chromeProfileDirs.includes(realProfile)) chromeProblems.push('the developer default browser profile is part of the scaffold');
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
if (process.env.LOCALAPPDATA === ambientLocalAppData) chromeProblems.push('LOCALAPPDATA still points at the ambient directory');
|
|
376
|
+
|
|
377
|
+
// The PowerShell module analysis cache must be a FILE path whose parent
|
|
378
|
+
// directory exists; a directory target is wrong. The helper installs the
|
|
379
|
+
// same isolated cache FILE inside the owned parent on EVERY platform, so the
|
|
380
|
+
// structural contract (absolute owned parent, file-shaped target, never the
|
|
381
|
+
// poisoned ambient value) is asserted platform-independently; only the
|
|
382
|
+
// powershell.exe child probe is Windows-specific.
|
|
383
|
+
const psProblems = [];
|
|
384
|
+
const psCache = installed.PSModuleAnalysisCachePath;
|
|
385
|
+
const psCacheParent = path.dirname(psCache);
|
|
386
|
+
let psProbe = null;
|
|
387
|
+
if (!psCache || !path.isAbsolute(psCache)) psProblems.push(`the PowerShell cache path is not absolute: ${psCache}`);
|
|
388
|
+
else {
|
|
389
|
+
if (!fs.existsSync(psCacheParent) || !fs.statSync(psCacheParent).isDirectory()) {
|
|
390
|
+
psProblems.push(`the PowerShell cache parent directory is missing: ${psCacheParent}`);
|
|
391
|
+
}
|
|
392
|
+
if (fs.existsSync(psCache) && fs.statSync(psCache).isDirectory()) {
|
|
393
|
+
psProblems.push('the PowerShell cache path is a directory, not a file path');
|
|
394
|
+
}
|
|
395
|
+
if (!psCache.startsWith(lane.laneTmp)) psProblems.push('the PowerShell cache path is outside the lane tree');
|
|
396
|
+
if (psCache === poisonPaths.PSModuleAnalysisCachePath) psProblems.push('the PowerShell cache path kept the poisoned ambient value');
|
|
397
|
+
}
|
|
398
|
+
if (process.platform === 'win32') {
|
|
399
|
+
// The child prints one status word only - no environment values.
|
|
400
|
+
psProbe = spawnSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command',
|
|
401
|
+
"$ErrorActionPreference='Stop'; Get-Module -ListAvailable | Out-Null; Write-Output 'PS-CACHE-OK'"], {
|
|
402
|
+
env: { ...process.env, PSModuleAnalysisCachePath: psCache },
|
|
403
|
+
encoding: 'utf8',
|
|
404
|
+
timeout: 120000,
|
|
405
|
+
windowsHide: true,
|
|
406
|
+
});
|
|
407
|
+
if (psProbe.error) psProblems.push(`the PowerShell child could not be started: ${psProbe.error.code || psProbe.error.message}`);
|
|
408
|
+
else if (psProbe.status !== 0) psProblems.push(`the PowerShell child failed with the lane cache path (exit ${psProbe.status})`);
|
|
409
|
+
else if (!String(psProbe.stdout || '').includes('PS-CACHE-OK')) psProblems.push('the PowerShell child did not complete with the lane cache path');
|
|
410
|
+
if (psProbe.status === 0 && fs.existsSync(psCache) && fs.statSync(psCache).isDirectory()) {
|
|
411
|
+
psProblems.push('PowerShell created a directory at the cache file path');
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
sentinel.powerShell = {
|
|
415
|
+
parentExists: fs.existsSync(psCacheParent),
|
|
416
|
+
cachePathIsFile: !fs.existsSync(psCache) || !fs.statSync(psCache).isDirectory(),
|
|
417
|
+
childExitCode: psProbe ? psProbe.status : null,
|
|
418
|
+
childCompleted: psProbe ? String(psProbe.stdout || '').includes('PS-CACHE-OK') : null,
|
|
419
|
+
problems: psProblems,
|
|
420
|
+
};
|
|
421
|
+
sentinelProblems.push(...psProblems);
|
|
422
|
+
sentinel.chrome = {
|
|
423
|
+
captured: lane.chromePath,
|
|
424
|
+
resolved: resolvedChrome,
|
|
425
|
+
preInstall: preInstallChrome,
|
|
426
|
+
profileDirs: lane.chromeProfileDirs,
|
|
427
|
+
problems: chromeProblems,
|
|
428
|
+
skipped: !lane.chromePath && !preInstallChrome,
|
|
429
|
+
};
|
|
430
|
+
sentinelProblems.push(...chromeProblems);
|
|
431
|
+
|
|
432
|
+
// Own-process cleanup: the lane tree must be gone once the entry releases
|
|
433
|
+
// it, and the probe child must have exited.
|
|
434
|
+
lane.cleanup();
|
|
435
|
+
const laneTreeRemoved = !fs.existsSync(lane.laneTmp);
|
|
436
|
+
if (!laneTreeRemoved) sentinelProblems.push('the lane temp tree survived the cleanup');
|
|
437
|
+
sentinel.cleanup = {
|
|
438
|
+
laneTreeRemoved,
|
|
439
|
+
probeChildExited: probe.status !== null || Boolean(probe.error),
|
|
440
|
+
powerShellChildExited: psProbe ? (psProbe.status !== null || Boolean(psProbe.error)) : null,
|
|
441
|
+
};
|
|
442
|
+
if (!sentinel.cleanup.probeChildExited) sentinelProblems.push('the grandchild probe process did not exit');
|
|
443
|
+
if (psProbe && !sentinel.cleanup.powerShellChildExited) sentinelProblems.push('the PowerShell probe process did not exit');
|
|
444
|
+
|
|
445
|
+
evidence.checks.poisonedEnvSentinel = { ...sentinel, problems: sentinelProblems };
|
|
446
|
+
if (sentinelProblems.length) failures.push(`poisoned environment sentinel failed: ${sentinelProblems.join('; ')}`);
|
|
447
|
+
|
|
448
|
+
try { fs.rmdirSync(toolTempRoot); } catch {}
|
|
449
|
+
|
|
450
|
+
// 3. Dependency contract: every require target is tracked or declared.
|
|
451
|
+
const dependencyProblems = [];
|
|
452
|
+
const dependencyRows = [];
|
|
453
|
+
for (const file of SCAN_FILES) {
|
|
454
|
+
for (const target of requiresOf(file)) {
|
|
455
|
+
const base = path.resolve(path.dirname(path.join(ROOT, file)), target);
|
|
456
|
+
const candidates = [base, `${base}.js`, `${base}.json`, path.join(base, 'index.js')];
|
|
457
|
+
const hit = candidates.find(candidate => fs.existsSync(candidate));
|
|
458
|
+
const relative = path.relative(ROOT, hit || base).split(path.sep).join('/');
|
|
459
|
+
const exists = Boolean(hit);
|
|
460
|
+
const tracked = exists && isTracked(relative);
|
|
461
|
+
const declared = LANE_MANIFEST.includes(relative);
|
|
462
|
+
dependencyRows.push({ file, target, resolved: relative, exists, tracked, declared });
|
|
463
|
+
if (!exists) dependencyProblems.push(`${file} requires missing ${relative}`);
|
|
464
|
+
else if (!tracked && !declared) dependencyProblems.push(`${file} requires untracked, undeclared ${relative}`);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
evidence.checks.dependencies = { rows: dependencyRows, problems: dependencyProblems };
|
|
468
|
+
if (dependencyProblems.length) failures.push(`dependency contract violated: ${dependencyProblems.join('; ')}`);
|
|
469
|
+
|
|
470
|
+
// 4. Classification: automatic vs manual-QA-only, per the runner's own rule.
|
|
471
|
+
const runnerSource = fs.readFileSync(path.join(ROOT, '_site', '_test', 'run-all-tests.js'), 'utf8');
|
|
472
|
+
const runnerUsesTestSuffix = runnerSource.includes("endsWith('-test.js')");
|
|
473
|
+
const classificationProblems = [];
|
|
474
|
+
if (!runnerUsesTestSuffix) classificationProblems.push('run-all-tests.js no longer selects *-test.js; classification must be re-derived');
|
|
475
|
+
for (const file of AUTOMATIC_ENTRIES) {
|
|
476
|
+
if (!file.endsWith('-test.js')) classificationProblems.push(`${file} is declared automatic but is not selected by the runner`);
|
|
477
|
+
}
|
|
478
|
+
if (MANUAL_ONLY.endsWith('-test.js')) classificationProblems.push(`${MANUAL_ONLY} must not match the automatic runner glob`);
|
|
479
|
+
const manualSource = fs.readFileSync(path.join(ROOT, MANUAL_ONLY), 'utf8');
|
|
480
|
+
const manualNeedsExpect = manualSource.includes('--expect');
|
|
481
|
+
if (!manualNeedsExpect) classificationProblems.push(`${MANUAL_ONLY} no longer requires an explicit --expect argument`);
|
|
482
|
+
for (const file of FROZEN_EXPLORATION) {
|
|
483
|
+
if (LANE_MANIFEST.includes(file)) classificationProblems.push(`${file} is frozen exploration history and must not be canonical`);
|
|
484
|
+
if (file.endsWith('-test.js')) classificationProblems.push(`${file} would be picked up by the automatic runner`);
|
|
485
|
+
}
|
|
486
|
+
evidence.checks.classification = {
|
|
487
|
+
runnerUsesTestSuffix,
|
|
488
|
+
automaticEntries: AUTOMATIC_ENTRIES,
|
|
489
|
+
manualOnly: MANUAL_ONLY,
|
|
490
|
+
manualRequiresExpectArgument: manualNeedsExpect,
|
|
491
|
+
frozenExploration: FROZEN_EXPLORATION,
|
|
492
|
+
problems: classificationProblems,
|
|
493
|
+
};
|
|
494
|
+
if (classificationProblems.length) failures.push(`classification contract violated: ${classificationProblems.join('; ')}`);
|
|
495
|
+
|
|
496
|
+
// 5. No real model/provider call in the lane entries.
|
|
497
|
+
const providerProblems = [];
|
|
498
|
+
const providerPattern = /api\.anthropic\.com|api\.openai\.com|api\.minimax|generativelanguage\.googleapis|sk-[A-Za-z0-9]{16,}/;
|
|
499
|
+
for (const file of SCAN_FILES) {
|
|
500
|
+
const code = stripComments(fs.readFileSync(path.join(ROOT, file), 'utf8'));
|
|
501
|
+
if (providerPattern.test(code)) providerProblems.push(`${file} references a provider endpoint or key`);
|
|
502
|
+
}
|
|
503
|
+
const standInUsers = AUTOMATIC_ENTRIES.concat([MANUAL_ONLY]).filter(file => fs.readFileSync(path.join(ROOT, file), 'utf8').includes('KB_AUTOMATION_FAKE_CLAUDE=1'));
|
|
504
|
+
evidence.checks.noRealModelCall = { providerProblems, standInUsers, standInCount: standInUsers.length };
|
|
505
|
+
if (providerProblems.length) failures.push(`provider reference found: ${providerProblems.join('; ')}`);
|
|
506
|
+
if (standInUsers.length === 0) failures.push('no entry declares the labelled offline analyzer stand-in');
|
|
507
|
+
|
|
508
|
+
// 6. Default evidence roots live inside the gitignored artifact tree.
|
|
509
|
+
const evidenceProblems = [];
|
|
510
|
+
const defaultEvidenceDirs = AUTOMATIC_ENTRIES.map(file => {
|
|
511
|
+
const code = fs.readFileSync(path.join(ROOT, file), 'utf8');
|
|
512
|
+
const match = /qa-autopilot\/artifacts\/[^'"]+/.exec(code);
|
|
513
|
+
return match ? match[0] : null;
|
|
514
|
+
}).filter(Boolean);
|
|
515
|
+
for (const dir of defaultEvidenceDirs) {
|
|
516
|
+
if (!isIgnored(dir)) evidenceProblems.push(`${dir} is not gitignored`);
|
|
517
|
+
}
|
|
518
|
+
evidence.checks.evidenceRoots = { defaultEvidenceDirs, problems: evidenceProblems };
|
|
519
|
+
if (evidenceProblems.length) failures.push(`evidence root not ignored: ${evidenceProblems.join('; ')}`);
|
|
520
|
+
|
|
521
|
+
// Manifest state for the Leader's commit step.
|
|
522
|
+
const manifestState = LANE_MANIFEST.map(file => ({ file, tracked: isTracked(file) }));
|
|
523
|
+
const pendingCommit = manifestState.filter(row => !row.tracked).map(row => row.file);
|
|
524
|
+
const strict = process.env.PK_LOGGING_GATE_STRICT_TRACKED === '1';
|
|
525
|
+
evidence.manifest = { files: manifestState, pendingCommit, strictMode: strict };
|
|
526
|
+
if (strict && pendingCommit.length) failures.push(`strict mode: manifest files not committed yet: ${pendingCommit.join(', ')}`);
|
|
527
|
+
|
|
528
|
+
evidence.verdict = failures.length
|
|
529
|
+
? { status: 'FAIL', failures }
|
|
530
|
+
: { status: 'PASS', pendingCommit };
|
|
531
|
+
evidence.finishedAt = new Date().toISOString();
|
|
532
|
+
fs.writeFileSync(path.join(ARTIFACTS, 'portability-evidence.json'), JSON.stringify(evidence, null, 2) + '\n');
|
|
533
|
+
|
|
534
|
+
if (failures.length) {
|
|
535
|
+
console.error(`P-QA-LOG-INTEGRATION-5025 portability FAIL: ${failures.join(' | ')}`);
|
|
536
|
+
process.exitCode = 1;
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
console.log(`P-QA-LOG-INTEGRATION-5025 portability PASS${pendingCommit.length ? ` (pending commit: ${pendingCommit.length} lane files)` : ''}`);
|
|
540
|
+
process.exitCode = 0;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
try {
|
|
544
|
+
main();
|
|
545
|
+
} catch (error) {
|
|
546
|
+
// Fail closed: an unusable environment must never degrade into a PASS.
|
|
547
|
+
fs.mkdirSync(ARTIFACTS, { recursive: true });
|
|
548
|
+
fs.writeFileSync(path.join(ARTIFACTS, 'portability-evidence.json'), JSON.stringify({
|
|
549
|
+
caseId: 'P-QA-LOG-INTEGRATION-5025-portability',
|
|
550
|
+
verdict: { status: 'FAIL', failures: [String((error && error.stack) || error)] },
|
|
551
|
+
}, null, 2) + '\n');
|
|
552
|
+
console.error(`P-QA-LOG-INTEGRATION-5025 portability FAIL: ${error && error.message}`);
|
|
553
|
+
process.exitCode = 1;
|
|
554
|
+
}
|