@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,470 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// _site/_test/helpers/parallel-memory-shell.js
|
|
3
|
+
//
|
|
4
|
+
// Lane harness for the P-MEMORY-01 memory lane.
|
|
5
|
+
//
|
|
6
|
+
// Every case runs against a real, isolated product instance:
|
|
7
|
+
// * its own port, data dir, knowledge root and Bridge journal home (the
|
|
8
|
+
// shared spawn-server helper already isolates those);
|
|
9
|
+
// * the REAL vendored knowledge engine, in-process, with a declared
|
|
10
|
+
// stand-in analyzer (helpers/parallel-memory-analyzer.js) that only
|
|
11
|
+
// replaces the model step;
|
|
12
|
+
// * a pass-through proxy in front of the engine, so the product's own
|
|
13
|
+
// runtime token reaches the engine the way it does in production;
|
|
14
|
+
// * real HTTP module services for terminal / vector-hub / event-bridge;
|
|
15
|
+
// * a real Chrome (CDP) in its own profile.
|
|
16
|
+
//
|
|
17
|
+
// Nothing here reaches the developer's live 5757/5790/8787/8790 endpoints,
|
|
18
|
+
// the real HOME, the real knowledge directories or the real memories.
|
|
19
|
+
|
|
20
|
+
const assert = require('node:assert/strict');
|
|
21
|
+
const crypto = require('node:crypto');
|
|
22
|
+
const fs = require('node:fs');
|
|
23
|
+
const path = require('node:path');
|
|
24
|
+
const { spawnSync } = require('node:child_process');
|
|
25
|
+
|
|
26
|
+
const { spawnServer } = require('../helpers/spawn-server');
|
|
27
|
+
const { findChrome } = require('../helpers/find-chrome');
|
|
28
|
+
const { launchCdpBrowser, waitFor } = require('../helpers/cdp-browser');
|
|
29
|
+
const { attachNetworkCapture } = require('../helpers/cdp-network-capture');
|
|
30
|
+
const { createModuleFixture, createUpstreamProxy } = require('../helpers/module-fixture');
|
|
31
|
+
const freePort = require('../helpers/free-port');
|
|
32
|
+
const { createMemoryStandinAnalyzer } = require('./parallel-memory-analyzer');
|
|
33
|
+
const { createEventBridgeStandin } = require('./parallel-memory-event-bridge');
|
|
34
|
+
const { applyDriverIsolation } = require('./parallel-qa-engine-endpoint-isolate');
|
|
35
|
+
const { guardedCreateEngineServer, createEngineVectorStandin } = require('./parallel-qa-engine-endpoint-guard');
|
|
36
|
+
|
|
37
|
+
const ROOT = path.resolve(__dirname, '../../..');
|
|
38
|
+
const LIVE_PORTS = new Set([5757, 5790, 8787, 8790]);
|
|
39
|
+
|
|
40
|
+
function git(cwd, args) {
|
|
41
|
+
const result = spawnSync('git', ['-C', cwd, ...args], { encoding: 'utf8', windowsHide: true, env: { ...process.env, GIT_TERMINAL_PROMPT: '0' } });
|
|
42
|
+
assert.equal(result.status, 0, `git ${args.join(' ')} failed: ${result.stderr}`);
|
|
43
|
+
return String(result.stdout || '').trim();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** A real Git repository with real commits: the product imports it for real. */
|
|
47
|
+
function makeRepo(root, name, files = { 'README.md': `# ${name}\n` }) {
|
|
48
|
+
const repo = path.join(root, name);
|
|
49
|
+
fs.mkdirSync(repo, { recursive: true });
|
|
50
|
+
git(repo, ['init', '-q', '-b', 'main']);
|
|
51
|
+
git(repo, ['config', 'user.email', 'parallel-memory@local.invalid']);
|
|
52
|
+
git(repo, ['config', 'user.name', 'Parallel Memory Regression']);
|
|
53
|
+
git(repo, ['config', 'commit.gpgsign', 'false']);
|
|
54
|
+
for (const [file, content] of Object.entries(files)) fs.writeFileSync(path.join(repo, file), content, 'utf8');
|
|
55
|
+
git(repo, ['add', '.']);
|
|
56
|
+
git(repo, ['commit', '-qm', 'baseline']);
|
|
57
|
+
return { path: repo, headCommit: git(repo, ['rev-parse', 'HEAD']) };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* A real follow-up commit in an existing repository.
|
|
62
|
+
*
|
|
63
|
+
* The engine registers a project with `trackingStartCommit` set to the commit
|
|
64
|
+
* that was HEAD at import time, and it treats a run for that very commit as
|
|
65
|
+
* already analysed. A maintenance run therefore has to target a commit that
|
|
66
|
+
* was made after the import — exactly the production flow.
|
|
67
|
+
*/
|
|
68
|
+
function commitFile(repo, file, content, message = 'follow-up') {
|
|
69
|
+
const full = path.join(repo.path, file);
|
|
70
|
+
fs.mkdirSync(path.dirname(full), { recursive: true });
|
|
71
|
+
fs.writeFileSync(full, content, 'utf8');
|
|
72
|
+
git(repo.path, ['add', '.']);
|
|
73
|
+
git(repo.path, ['commit', '-qm', message]);
|
|
74
|
+
repo.headCommit = git(repo.path, ['rev-parse', 'HEAD']);
|
|
75
|
+
return repo.headCommit;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function startHarness({ tag, evidenceDir, viewport = { width: 1600, height: 900 } } = {}) {
|
|
79
|
+
// Full driver isolation FIRST, before any product module load or fixture
|
|
80
|
+
// directory: the environment is rebuilt from a system whitelist with every
|
|
81
|
+
// product surface pointed at a per-run layout. Chrome is captured from the
|
|
82
|
+
// REAL environment before the wipe and carried through as KB_CHROME_PATH.
|
|
83
|
+
const applied = applyDriverIsolation({ prefix: `pk-qa-memory-${tag}`, captureChrome: true });
|
|
84
|
+
const tempRoot = applied.layout.temp;
|
|
85
|
+
|
|
86
|
+
const fixture = fs.mkdtempSync(path.join(tempRoot, `pk-parallel-memory-${tag}-`));
|
|
87
|
+
const evidence = evidenceDir || path.join(fixture, 'evidence');
|
|
88
|
+
fs.mkdirSync(evidence, { recursive: true });
|
|
89
|
+
const dataDir = path.join(fixture, 'data');
|
|
90
|
+
const knowledgeRoot = path.join(fixture, 'knowledge');
|
|
91
|
+
fs.mkdirSync(knowledgeRoot, { recursive: true });
|
|
92
|
+
|
|
93
|
+
const plan = { document: '', memoryCandidates: [] };
|
|
94
|
+
const engineToken = crypto.randomBytes(24).toString('hex');
|
|
95
|
+
// OWN fixtures exist BEFORE the engine. The coordinator ignores env and its
|
|
96
|
+
// defaults are LIVE 8787/8790, so the engine must be constructed with an
|
|
97
|
+
// explicit OWN vector endpoint (the full-contract stand-in, because run
|
|
98
|
+
// maintenance ends in POST /api/sync which the module fixture lacks) and the
|
|
99
|
+
// lane's own event bridge.
|
|
100
|
+
const engineVector = createEngineVectorStandin({ label: 'memory-shell-engine-vector' });
|
|
101
|
+
await engineVector.ready;
|
|
102
|
+
const terminal = createModuleFixture({ kind: 'terminal', tag: `${tag}-terminal` });
|
|
103
|
+
const vectorHub = createModuleFixture({ kind: 'vectorHub', tag: `${tag}-vectorhub` });
|
|
104
|
+
// The shared event-bridge fixture answers with `bridge-1`, a journal id the
|
|
105
|
+
// engine rejects, so the project never reaches the engine. This lane uses
|
|
106
|
+
// its own stand-in that derives the real `sha256:` workspace id.
|
|
107
|
+
const eventBridge = await createEventBridgeStandin({ tag: `${tag}-eventbridge` });
|
|
108
|
+
await terminal.start();
|
|
109
|
+
await vectorHub.start();
|
|
110
|
+
await eventBridge.start();
|
|
111
|
+
|
|
112
|
+
const engine = guardedCreateEngineServer({
|
|
113
|
+
dataDir: path.join(fixture, 'engine'),
|
|
114
|
+
runtimeToken: engineToken,
|
|
115
|
+
debug: true,
|
|
116
|
+
consume: false,
|
|
117
|
+
analyzer: createMemoryStandinAnalyzer({ plan }),
|
|
118
|
+
vectorUrl: engineVector.url,
|
|
119
|
+
bridgeUrl: eventBridge.url,
|
|
120
|
+
});
|
|
121
|
+
await engine.ready;
|
|
122
|
+
await new Promise(resolve => engine.server.listen(0, '127.0.0.1', resolve));
|
|
123
|
+
const engineUrl = `http://127.0.0.1:${engine.server.address().port}`;
|
|
124
|
+
assert.equal(LIVE_PORTS.has(engine.server.address().port), false, 'the lane engine must never use a live port');
|
|
125
|
+
const engineProxy = createUpstreamProxy({ target: engineUrl, token: engineToken, tag: 'engine' });
|
|
126
|
+
await engineProxy.start();
|
|
127
|
+
|
|
128
|
+
const port = await freePort();
|
|
129
|
+
const base = `http://127.0.0.1:${port}`;
|
|
130
|
+
const server = spawnServer({
|
|
131
|
+
root: ROOT,
|
|
132
|
+
port,
|
|
133
|
+
dataDir,
|
|
134
|
+
tag: `parallel-memory-${tag}`,
|
|
135
|
+
analysisOwner: 'engine',
|
|
136
|
+
extraEnv: {
|
|
137
|
+
KB_MODULES_REGISTER: '1',
|
|
138
|
+
KB_MODULES_AUTOSTART: '0',
|
|
139
|
+
KB_TERMINAL_URL: terminal.url,
|
|
140
|
+
KB_VECTORHUB_URL: vectorHub.url,
|
|
141
|
+
KB_EVENTBRIDGE_URL: eventBridge.url,
|
|
142
|
+
KB_KNOWLEDGE_ENGINE_URL: engineProxy.url,
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const productApi = async (method, route, body) => {
|
|
147
|
+
const response = await fetch(base + route, {
|
|
148
|
+
method,
|
|
149
|
+
headers: body === undefined ? undefined : { 'Content-Type': 'application/json' },
|
|
150
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
151
|
+
signal: AbortSignal.timeout(20000),
|
|
152
|
+
});
|
|
153
|
+
return { status: response.status, body: await response.json().catch(() => null) };
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const engineApi = async (method, route, body) => {
|
|
157
|
+
const response = await fetch(engineUrl + route, {
|
|
158
|
+
method,
|
|
159
|
+
headers: {
|
|
160
|
+
'Content-Type': 'application/json',
|
|
161
|
+
...(engineToken ? { Authorization: `Bearer ${engineToken}` } : {}),
|
|
162
|
+
},
|
|
163
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
164
|
+
signal: AbortSignal.timeout(20000),
|
|
165
|
+
});
|
|
166
|
+
return { status: response.status, body: await response.json().catch(() => null) };
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
await waitFor(async () => {
|
|
170
|
+
try { return (await productApi('GET', '/api/health')).status === 200; } catch { return false; }
|
|
171
|
+
}, 'the isolated product instance', 30000);
|
|
172
|
+
const settings = await productApi('PATCH', '/api/settings', { knowledge: { rootPath: knowledgeRoot } });
|
|
173
|
+
assert.equal(settings.status, 200, `the isolated instance accepts its own knowledge root: ${JSON.stringify(settings.body)}`);
|
|
174
|
+
|
|
175
|
+
let browser = null;
|
|
176
|
+
let network = null;
|
|
177
|
+
try {
|
|
178
|
+
browser = await launchCdpBrowser({
|
|
179
|
+
chrome: findChrome(),
|
|
180
|
+
profileDir: path.join(fixture, 'browser'),
|
|
181
|
+
url: `${base}/`,
|
|
182
|
+
width: viewport.width,
|
|
183
|
+
height: viewport.height,
|
|
184
|
+
});
|
|
185
|
+
await browser.setViewport(viewport.width, viewport.height);
|
|
186
|
+
await browser.send('Network.enable');
|
|
187
|
+
network = attachNetworkCapture(browser);
|
|
188
|
+
} catch (error) {
|
|
189
|
+
await server.cleanup();
|
|
190
|
+
await engineProxy.close();
|
|
191
|
+
await terminal.close();
|
|
192
|
+
await vectorHub.close();
|
|
193
|
+
await eventBridge.close();
|
|
194
|
+
await engine.close().catch(() => {});
|
|
195
|
+
fs.rmSync(fixture, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
196
|
+
throw error;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const run = expression => browser.evaluate(expression);
|
|
200
|
+
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
201
|
+
const reloadLog = [];
|
|
202
|
+
|
|
203
|
+
/** Ask the shell to read the project registry again. */
|
|
204
|
+
const requestRegistryRefresh = () => run("document.dispatchEvent(new Event('visibilitychange'))");
|
|
205
|
+
|
|
206
|
+
/** A real page reload, so "it survives a refresh" is proven by the browser. */
|
|
207
|
+
const reload = async () => {
|
|
208
|
+
// Mark the OUTGOING document first. Page.reload is acknowledged before the
|
|
209
|
+
// navigation commits, and Runtime.evaluate keeps answering in the old
|
|
210
|
+
// context while it stays attached — so a bare readyState gate is satisfied
|
|
211
|
+
// by the outgoing page (CI 40062048045: the nav click right after
|
|
212
|
+
// reload() was dispatched into the commit gap and lost, and the memory
|
|
213
|
+
// view never activated). The marker exists only in the old context, so
|
|
214
|
+
// the gate below can only pass on the FRESH document; the active-view
|
|
215
|
+
// clause additionally proves the product's synchronous boot finished
|
|
216
|
+
// (ui/product.js attaches its click delegation before the boot setView
|
|
217
|
+
// that marks the initial view active).
|
|
218
|
+
const startedAt = Date.now();
|
|
219
|
+
await run('window.__pkShellReloadMark = Date.now(), true');
|
|
220
|
+
await browser.send('Page.reload', {});
|
|
221
|
+
await waitFor(
|
|
222
|
+
() => run("document.readyState === 'complete' && typeof window.__pkShellReloadMark === 'undefined' && document.querySelector('.view.active') !== null"),
|
|
223
|
+
'the reloaded page is the fresh document and its boot finished',
|
|
224
|
+
20000,
|
|
225
|
+
);
|
|
226
|
+
reloadLog.push({ at: new Date().toISOString(), freshBootGateMs: Date.now() - startedAt });
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Readiness snapshot for failure diagnostics: what the page really looks
|
|
231
|
+
* like when a navigation assertion is about to fail (small metadata).
|
|
232
|
+
*/
|
|
233
|
+
const navigationState = async () => {
|
|
234
|
+
try {
|
|
235
|
+
return await run(`(() => ({
|
|
236
|
+
readyState: document.readyState,
|
|
237
|
+
href: location.href,
|
|
238
|
+
activeView: (document.querySelector('.view.active') || {}).id || null,
|
|
239
|
+
activeNav: document.querySelector('nav [data-view].active') ? document.querySelector('nav [data-view].active').dataset.view : null,
|
|
240
|
+
reloadMark: typeof window.__pkShellReloadMark,
|
|
241
|
+
openDialogs: [...document.querySelectorAll('dialog[open]')].map(dialog => dialog.id),
|
|
242
|
+
toastHidden: document.getElementById('toast') ? document.getElementById('toast').hidden : null,
|
|
243
|
+
toastText: document.getElementById('toast') ? document.getElementById('toast').textContent.trim().slice(0, 80) : null,
|
|
244
|
+
}))()`);
|
|
245
|
+
} catch (error) {
|
|
246
|
+
return { unreachable: String(error && error.message || error) };
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const pressBackspace = async (count = 1) => {
|
|
251
|
+
for (let index = 0; index < count; index += 1) await pressKey('Backspace', { code: 'Backspace', keyCode: 8 });
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
/** Set a select's value and fire the real change event the shell listens to. */
|
|
255
|
+
const selectOption = async (selector, value) => {
|
|
256
|
+
const changed = await run(`(() => {
|
|
257
|
+
const el = document.querySelector(${JSON.stringify(selector)});
|
|
258
|
+
if (!el) return { missing: true };
|
|
259
|
+
el.value = ${JSON.stringify(value)};
|
|
260
|
+
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
261
|
+
return { value: el.value };
|
|
262
|
+
})()`);
|
|
263
|
+
assert.ok(changed && !changed.missing, `the select ${selector} must exist`);
|
|
264
|
+
assert.equal(changed.value, value, `the select ${selector} must accept the value ${value}`);
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
/** A native pointer click: the hit test runs first and must resolve to the target. */
|
|
268
|
+
const nativeClick = async selector => {
|
|
269
|
+
const probe = await run(`(() => {
|
|
270
|
+
const el = document.querySelector(${JSON.stringify(selector)});
|
|
271
|
+
if (!el) return { missing: true };
|
|
272
|
+
const rect = el.getBoundingClientRect();
|
|
273
|
+
if (rect.width <= 0 || rect.height <= 0) return { invisible: true };
|
|
274
|
+
const x = rect.left + rect.width / 2;
|
|
275
|
+
const y = rect.top + rect.height / 2;
|
|
276
|
+
const hit = document.elementFromPoint(x, y);
|
|
277
|
+
return { x, y, hitIsTarget: Boolean(hit && (hit === el || el.contains(hit))), label: (el.textContent || '').trim().slice(0, 40) };
|
|
278
|
+
})()`);
|
|
279
|
+
assert.ok(probe && !probe.missing, `the control ${selector} must exist in the page`);
|
|
280
|
+
assert.ok(!probe.invisible, `the control ${selector} must be visible`);
|
|
281
|
+
assert.ok(probe.hitIsTarget, `the control ${selector} must be the hit target; something else is on top`);
|
|
282
|
+
const common = { x: probe.x, y: probe.y, button: 'left', clickCount: 1 };
|
|
283
|
+
await browser.send('Input.dispatchMouseEvent', { type: 'mouseMoved', x: probe.x, y: probe.y, button: 'none', clickCount: 0 });
|
|
284
|
+
await browser.send('Input.dispatchMouseEvent', { type: 'mousePressed', ...common });
|
|
285
|
+
await browser.send('Input.dispatchMouseEvent', { type: 'mouseReleased', ...common });
|
|
286
|
+
return probe;
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const pressKey = async (key, { code, keyCode, text } = {}) => {
|
|
290
|
+
const base = { key, code: code || key, windowsVirtualKeyCode: keyCode, nativeVirtualKeyCode: keyCode };
|
|
291
|
+
await browser.send('Input.dispatchKeyEvent', { type: text ? 'keyDown' : 'rawKeyDown', ...base, text });
|
|
292
|
+
await browser.send('Input.dispatchKeyEvent', { type: 'keyUp', ...base });
|
|
293
|
+
};
|
|
294
|
+
const pressTab = () => pressKey('Tab', { code: 'Tab', keyCode: 9 });
|
|
295
|
+
const pressEnter = () => pressKey('Enter', { code: 'Enter', keyCode: 13, text: '\r' });
|
|
296
|
+
|
|
297
|
+
/** Type into a focused field with real key events. */
|
|
298
|
+
const typeText = async text => {
|
|
299
|
+
for (const character of String(text)) {
|
|
300
|
+
const upper = character.toUpperCase();
|
|
301
|
+
const isLower = character >= 'a' && character <= 'z';
|
|
302
|
+
const isUpper = character >= 'A' && character <= 'Z';
|
|
303
|
+
const isDigit = character >= '0' && character <= '9';
|
|
304
|
+
const code = isLower ? `Key${upper}` : isUpper ? `Key${character}` : isDigit ? `Digit${character}` : '';
|
|
305
|
+
const keyCode = isLower ? upper.charCodeAt(0) : isUpper || isDigit ? character.charCodeAt(0) : 0;
|
|
306
|
+
const base = { key: character, code, windowsVirtualKeyCode: keyCode, nativeVirtualKeyCode: keyCode };
|
|
307
|
+
await browser.send('Input.dispatchKeyEvent', { type: 'keyDown', ...base, text: character, unmodifiedText: character });
|
|
308
|
+
await browser.send('Input.dispatchKeyEvent', { type: 'keyUp', ...base });
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
/** Import a real project through the real product API. */
|
|
313
|
+
const importProject = async (repo, displayName, { domainId } = {}) => {
|
|
314
|
+
const knowledgePath = path.join(knowledgeRoot, displayName);
|
|
315
|
+
fs.mkdirSync(knowledgePath, { recursive: true });
|
|
316
|
+
const result = await productApi('POST', '/api/projects/import', { localPath: repo.path, knowledgePath, displayName });
|
|
317
|
+
assert.equal(result.status, 201, `the project import must succeed: ${JSON.stringify(result.body)}`);
|
|
318
|
+
const projectId = result.body.projectId;
|
|
319
|
+
if (domainId) {
|
|
320
|
+
const patched = await productApi('PATCH', `/api/projects/${encodeURIComponent(projectId)}`, { domainId });
|
|
321
|
+
assert.equal(patched.status, 200, `the domain binding must succeed: ${JSON.stringify(patched.body)}`);
|
|
322
|
+
}
|
|
323
|
+
return { projectId, project: result.body.project, knowledgePath, modules: result.body.modules };
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
/** Add a real domain to the brain of the isolated instance. */
|
|
327
|
+
const addDomain = async name => {
|
|
328
|
+
const result = await productApi('POST', '/api/domains', { name });
|
|
329
|
+
assert.equal(result.status, 201, `the brain domain must be accepted: ${JSON.stringify(result.body)}`);
|
|
330
|
+
return result.body.domain;
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
/** The knowledge directory the engine uses for the brain scope. */
|
|
334
|
+
const brainScopePath = () => {
|
|
335
|
+
const scope = engine.store.state.sharedScopes.find(entry => entry.kind === 'brain');
|
|
336
|
+
assert.ok(scope, 'the engine must know the brain scope');
|
|
337
|
+
return scope.knowledgePath;
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
/** The knowledge directory the engine uses for one domain scope. */
|
|
341
|
+
const domainScopePath = domainId => {
|
|
342
|
+
const scope = engine.store.state.sharedScopes.find(entry => entry.kind === 'domain' && entry.id === domainId);
|
|
343
|
+
assert.ok(scope, `the engine must know the domain scope ${domainId}`);
|
|
344
|
+
return scope.knowledgePath;
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
/** Every memory the product's own snapshot endpoint serves. */
|
|
348
|
+
const productMemories = async () => {
|
|
349
|
+
const snapshot = await productApi('GET', '/api/engine/snapshot?summary=1&limit=50');
|
|
350
|
+
assert.equal(snapshot.status, 200, `the product snapshot must be readable: ${JSON.stringify(snapshot.body)}`);
|
|
351
|
+
return snapshot.body.memories || [];
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
/** The memories the engine would inject into a task for one project. */
|
|
355
|
+
const injectedMemories = async projectId => {
|
|
356
|
+
const context = await engineApi('POST', '/api/context', { projectId, query: '长期记忆', task: 'memory-lane' });
|
|
357
|
+
assert.equal(context.status, 200, `the engine context must be readable: ${JSON.stringify(context.body)}`);
|
|
358
|
+
return context.body.memories || [];
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* A memory candidate that satisfies the engine's own provenance gate: it
|
|
363
|
+
* quotes the real human event, the quote contains the memory text, and it
|
|
364
|
+
* declares why the text is a durable, cross-project owner preference.
|
|
365
|
+
*/
|
|
366
|
+
const memoryCandidate = ({ text, event, scopeType = 'global' }) => ({
|
|
367
|
+
text,
|
|
368
|
+
quote: text,
|
|
369
|
+
scopeType,
|
|
370
|
+
sourceEventId: event.eventId,
|
|
371
|
+
sourceHash: event.contentHash,
|
|
372
|
+
eligibility: {
|
|
373
|
+
durable: true,
|
|
374
|
+
crossProject: true,
|
|
375
|
+
reason: '人工明确表达的长期偏好',
|
|
376
|
+
scopeReason: scopeType === 'global' ? '适用于所有领域与项目' : '适用于指定领域',
|
|
377
|
+
},
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Drive the real pipeline to a candidate: a real follow-up commit, a real
|
|
382
|
+
* conversation event bound to it, the stand-in analyzer's manifest and the
|
|
383
|
+
* engine's own promotion and capture.
|
|
384
|
+
*/
|
|
385
|
+
const produceCandidate = async ({ repo, projectId, text, scopeType = 'global', inputOrigin = 'human', file = 'src/candidate.js' }) => {
|
|
386
|
+
const head = commitFile(repo, file, `// ${text}\n`, 'candidate commit');
|
|
387
|
+
const event = await ingestUserEvent({
|
|
388
|
+
projectId,
|
|
389
|
+
commitSha: head,
|
|
390
|
+
content: `人工要求:${text}`,
|
|
391
|
+
inputOrigin,
|
|
392
|
+
});
|
|
393
|
+
plan.document = `# 冻结证据\n\n${text}\n`;
|
|
394
|
+
plan.memoryCandidates = [memoryCandidate({ text, event, scopeType })];
|
|
395
|
+
const run = await triggerRun(projectId, head);
|
|
396
|
+
return { run, event, commitSha: head, capture: run.memoryCapture };
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Append a real conversation event to the engine's own conversation store.
|
|
401
|
+
* The engine's own binder freezes it into the commit snapshot, and the
|
|
402
|
+
* engine's own eligibility gate reads its inputOrigin.
|
|
403
|
+
*/
|
|
404
|
+
const ingestUserEvent = async ({ projectId, commitSha, content, inputOrigin = 'human', turnId, eventId }) => {
|
|
405
|
+
const id = eventId || `event-${crypto.randomUUID()}`;
|
|
406
|
+
const turn = turnId || `turn-${crypto.randomUUID()}`;
|
|
407
|
+
const result = await engine.coordinator.conversations.appendEvent(projectId, {
|
|
408
|
+
eventId: id,
|
|
409
|
+
sequence: 1,
|
|
410
|
+
source: 'claude-code',
|
|
411
|
+
eventType: 'user_prompt',
|
|
412
|
+
role: 'user',
|
|
413
|
+
inputOrigin,
|
|
414
|
+
content,
|
|
415
|
+
sessionId: `session-${projectId}`,
|
|
416
|
+
turnId: turn,
|
|
417
|
+
capturedAt: new Date().toISOString(),
|
|
418
|
+
identityConfidence: 'exact',
|
|
419
|
+
explicitCommitSha: commitSha,
|
|
420
|
+
});
|
|
421
|
+
return { eventId: id, turnId: turn, contentHash: result.event.contentHash, inputOrigin: result.event.inputOrigin };
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
/** Run the real maintenance pipeline for a commit and wait for the run. */
|
|
425
|
+
const triggerRun = async (projectId, commitSha, timeoutMs = 60000) => {
|
|
426
|
+
const started = await engineApi('POST', '/api/runs', { projectId, commitSha });
|
|
427
|
+
assert.equal(started.status, 200, `the run must be accepted: ${JSON.stringify(started.body)}`);
|
|
428
|
+
const runId = started.body.run.runId;
|
|
429
|
+
const deadline = Date.now() + timeoutMs;
|
|
430
|
+
let last = null;
|
|
431
|
+
while (Date.now() < deadline) {
|
|
432
|
+
const current = await engineApi('GET', `/api/runs/${encodeURIComponent(runId)}`);
|
|
433
|
+
last = current.body && current.body.run;
|
|
434
|
+
if (last && ['succeeded', 'failed'].includes(last.state)) {
|
|
435
|
+
if (last.state === 'failed') throw new Error(`the run failed: ${JSON.stringify(last.error)}`);
|
|
436
|
+
return last;
|
|
437
|
+
}
|
|
438
|
+
if (last && last.promotedAt && last.memoryCapture) return last;
|
|
439
|
+
await wait(150);
|
|
440
|
+
}
|
|
441
|
+
throw new Error(`the run did not finish in time: ${JSON.stringify(last)}`);
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
const cleanup = async () => {
|
|
445
|
+
await browser?.close();
|
|
446
|
+
await server.cleanup();
|
|
447
|
+
await engineProxy.close();
|
|
448
|
+
await terminal.close();
|
|
449
|
+
await vectorHub.close();
|
|
450
|
+
await eventBridge.close();
|
|
451
|
+
await engine.close().catch(() => {});
|
|
452
|
+
await engineVector.close().catch(() => {});
|
|
453
|
+
fs.rmSync(fixture, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
return {
|
|
457
|
+
fixture, evidence, dataDir, knowledgeRoot, tempRoot, plan,
|
|
458
|
+
base, server, productApi, engineApi, engine, engineUrl, engineProxy,
|
|
459
|
+
terminal, vectorHub, eventBridge, engineVector,
|
|
460
|
+
browser, run, wait, waitFor, network, reloadLog, navigationState,
|
|
461
|
+
requestRegistryRefresh, reload, pressBackspace, selectOption,
|
|
462
|
+
nativeClick, pressKey, pressTab, pressEnter, typeText,
|
|
463
|
+
importProject, addDomain, ingestUserEvent, triggerRun,
|
|
464
|
+
brainScopePath, domainScopePath, productMemories, injectedMemories,
|
|
465
|
+
memoryCandidate, produceCandidate,
|
|
466
|
+
cleanup,
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
module.exports = { startHarness, makeRepo, commitFile, ROOT };
|