@sanqianx/project-knowledge 5.0.24 → 5.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/plugins/marketplace.json +20 -20
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +1361 -1353
- package/LICENSE +201 -201
- package/NOTICE +5 -5
- package/README.md +349 -349
- package/_modules/knowledge-engine/package.json +1 -1
- package/_modules/knowledge-engine/src/coordinator.js +48 -3
- package/_modules/knowledge-engine/src/runtime/automation-config.js +140 -140
- package/_modules/knowledge-engine/src/runtime/commit-conversation-binder.js +238 -238
- package/_modules/knowledge-engine/src/runtime/commit-processing-ledger.js +26 -26
- package/_modules/knowledge-engine/src/runtime/commit-prompt.js +193 -193
- package/_modules/knowledge-engine/src/runtime/commit-reconciler.js +394 -394
- package/_modules/knowledge-engine/src/runtime/contracts.js +282 -282
- package/_modules/knowledge-engine/src/runtime/conversation-store.js +389 -389
- package/_modules/knowledge-engine/src/runtime/evidence-bundle.js +228 -228
- package/_modules/knowledge-engine/src/runtime/git-runner.js +62 -62
- package/_modules/knowledge-engine/src/runtime/knowledge-promotion.js +505 -505
- package/_modules/knowledge-engine/src/runtime/knowledge-retrieval-service.js +400 -400
- package/_modules/knowledge-engine/src/runtime/markdown-knowledge-indexer.js +171 -171
- package/_modules/knowledge-engine/src/runtime/scanner.js +298 -298
- package/_modules/knowledge-engine/ui/app.js +23 -2
- package/_site/README.md +30 -30
- package/_site/_test/agent-capture-mcp-ui-test.js +68 -68
- package/_site/_test/agent-capture-ui-test.js +101 -101
- package/_site/_test/ai-profile-resolver-test.js +137 -137
- package/_site/_test/ai-profile-test.js +75 -75
- package/_site/_test/ai-vendor-presets-test.js +91 -91
- package/_site/_test/automatic-context-test.js +70 -70
- package/_site/_test/automation-queue-test.js +14 -14
- package/_site/_test/automation-ui-test.js +40 -40
- package/_site/_test/background-task-registry-test.js +43 -43
- package/_site/_test/baseline-schema-test.js +91 -91
- package/_site/_test/bin-cli-test.js +230 -230
- package/_site/_test/bridge-adapter-test.js +95 -95
- package/_site/_test/bridge-consumer-service-test.js +310 -310
- package/_site/_test/candidate-bin-content-test.js +35 -35
- package/_site/_test/candidate-product-assets-test.js +13 -13
- package/_site/_test/candidate-release-contract-test.js +14 -14
- package/_site/_test/capture-hook-dedup-test.js +158 -158
- package/_site/_test/cdp-browser-failure-test.js +103 -103
- package/_site/_test/chat-claudecodeui-match-test.js +92 -92
- package/_site/_test/claude-executable-discovery-test.js +90 -90
- package/_site/_test/claude-session-lifecycle-sweep-test.js +252 -252
- package/_site/_test/claude-workbench-test.js +174 -174
- package/_site/_test/cli-instance-management-test.js +62 -62
- package/_site/_test/client-capture-restart-e2e-test.js +189 -189
- package/_site/_test/codex-conversation-projection-test.js +60 -60
- package/_site/_test/codex-marketplace-scoped-path-test.js +186 -186
- package/_site/_test/codex-notify-capture-e2e-test.js +101 -101
- package/_site/_test/codex-notify-fanout-test.js +141 -134
- package/_site/_test/codex-notify-upgrade-test.js +253 -253
- package/_site/_test/commit-boundary-freeze-test.js +147 -147
- package/_site/_test/commit-conversation-binding-test.js +99 -99
- package/_site/_test/commit-evidence-test.js +110 -110
- package/_site/_test/configuration-generation-test.js +22 -22
- package/_site/_test/context-pack-test.js +200 -200
- package/_site/_test/conversation-api-test.js +119 -119
- package/_site/_test/conversation-origin-test.js +15 -15
- package/_site/_test/conversation-store-test.js +138 -138
- package/_site/_test/cross-repo-isolation-e2e-test.js +187 -187
- package/_site/_test/desktop-browser-compat-test.js +28 -28
- package/_site/_test/desktop-hook-runtime-regression-test.js +204 -204
- package/_site/_test/embedding-config-test.js +32 -32
- package/_site/_test/explicit-commit-processor-test.js +37 -37
- package/_site/_test/fixtures/fake-browser-exit.js +10 -10
- package/_site/_test/fixtures/fake-browser-hang.js +10 -10
- package/_site/_test/fixtures/integration-busy-worker.cjs +6 -6
- package/_site/_test/fixtures/make-git-repos.js +92 -92
- package/_site/_test/fixtures/retrieval-gold-queries.json +32 -32
- package/_site/_test/folder-picker-output-test.js +19 -19
- package/_site/_test/fresh-hook-reimport-test.js +53 -53
- package/_site/_test/fresh-product-data-test.js +56 -56
- package/_site/_test/full-integration-e2e-test.js +167 -167
- package/_site/_test/git-path-compatibility-test.js +80 -80
- package/_site/_test/git-validation-test.js +81 -81
- package/_site/_test/glm-ui-refresh-review-test.js +313 -404
- package/_site/_test/harness-isolation-test.js +138 -0
- package/_site/_test/helpers/cdp-browser.js +383 -0
- package/_site/_test/helpers/cdp-network-capture.js +66 -0
- package/_site/_test/helpers/find-chrome.js +34 -0
- package/_site/_test/helpers/free-port.js +8 -0
- package/_site/_test/helpers/logging-ui-fixture.js +131 -0
- package/_site/_test/helpers/module-fixture.js +282 -0
- package/_site/_test/helpers/parallel-engine-advanced-engine-child.js +45 -0
- package/_site/_test/helpers/parallel-engine-advanced-fault-writer.js +171 -0
- package/_site/_test/helpers/parallel-engine-advanced-harness.js +245 -0
- package/_site/_test/helpers/parallel-engine-advanced-standin-analyzer.js +80 -0
- package/_site/_test/helpers/parallel-engine-advanced-ui-host.js +177 -0
- package/_site/_test/helpers/parallel-engine-final-harness.js +314 -0
- package/_site/_test/helpers/parallel-engine-final-standin-analyzer.js +159 -0
- package/_site/_test/helpers/parallel-knowledge-fixture.js +255 -0
- package/_site/_test/helpers/parallel-logging-acceptance-fixture.js +111 -0
- package/_site/_test/helpers/parallel-logging-acceptance-proxy.js +106 -0
- package/_site/_test/helpers/parallel-logging-fix-r2-proxy.js +205 -0
- package/_site/_test/helpers/parallel-logging-integration-5025-env.js +432 -0
- package/_site/_test/helpers/parallel-memory-analyzer.js +81 -0
- package/_site/_test/helpers/parallel-memory-event-bridge.js +128 -0
- package/_site/_test/helpers/parallel-memory-shell.js +470 -0
- package/_site/_test/helpers/parallel-nav-isolation-env.js +389 -0
- package/_site/_test/helpers/parallel-nav-module-ui.js +186 -0
- package/_site/_test/helpers/parallel-nav-proxy.js +148 -0
- package/_site/_test/helpers/parallel-nav-shell.js +361 -0
- package/_site/_test/helpers/parallel-qa-engine-endpoint-guard.js +206 -0
- package/_site/_test/helpers/parallel-qa-engine-endpoint-isolate.js +257 -0
- package/_site/_test/helpers/parallel-retrieval-followup-corpus.js +293 -0
- package/_site/_test/helpers/parallel-retrieval-followup-next-session.js +70 -0
- package/_site/_test/helpers/parallel-retrieval-followup-r2-shell.js +737 -0
- package/_site/_test/helpers/parallel-retrieval-followup-r2-wb-host.js +82 -0
- package/_site/_test/helpers/parallel-retrieval-followup-shell.js +279 -0
- package/_site/_test/helpers/parallel-workbench-fixture.js +371 -0
- package/_site/_test/helpers/parallel-workbench-host.js +80 -0
- package/_site/_test/helpers/parallel-workbench-integration-5025-fixture.js +408 -0
- package/_site/_test/helpers/parallel-workbench-integration-5025-harness.js +593 -0
- package/_site/_test/helpers/parallel-workbench-integration-5025-host.js +70 -0
- package/_site/_test/helpers/parallel-workbench-integration-5025-launcher.js +240 -0
- package/_site/_test/helpers/parallel-workbench-integration-5025-runtime-harness.js +630 -0
- package/_site/_test/helpers/parallel-workbench-source-map.js +196 -0
- package/_site/_test/helpers/spawn-server.js +106 -0
- package/_site/_test/helpers/version-visibility-fixture.js +251 -0
- package/_site/_test/hook-runtime-endpoint-test.js +88 -88
- package/_site/_test/hook-status-repair-api-test.js +152 -152
- package/_site/_test/hook-trigger-test.js +85 -85
- package/_site/_test/hook-worktree-test.js +42 -42
- package/_site/_test/import-preflight-api-test.js +234 -234
- package/_site/_test/index-builder-test.js +41 -41
- package/_site/_test/index-error-display-contract-test.js +10 -10
- package/_site/_test/index-writer-concurrency-test.js +135 -135
- package/_site/_test/integration-adapters-test.js +262 -262
- package/_site/_test/integration-auto-repair-test.js +113 -113
- package/_site/_test/integration-capture-setup-test.js +118 -118
- package/_site/_test/integration-intent-test.js +81 -81
- package/_site/_test/integration-runtime-binding-a2-test.js +566 -566
- package/_site/_test/integration-runtime-binding-a3-test.js +227 -227
- package/_site/_test/integration-runtime-binding-test.js +473 -473
- package/_site/_test/integration-status-scan-test.js +29 -29
- package/_site/_test/integration-surface-coverage-test.js +164 -164
- package/_site/_test/kb-framework-test.js +57 -57
- package/_site/_test/kbpath-follow-test.js +63 -63
- package/_site/_test/knowledge-db-test.js +144 -144
- package/_site/_test/knowledge-engine-client-test.js +120 -109
- package/_site/_test/knowledge-language-control-test.js +170 -170
- package/_site/_test/knowledge-maintenance-test.js +40 -40
- package/_site/_test/knowledge-promotion-recovery-test.js +260 -260
- package/_site/_test/knowledge-query-test.js +54 -54
- package/_site/_test/knowledge-retrieval-service-test.js +77 -77
- package/_site/_test/knowledge-scopes-test.js +37 -37
- package/_site/_test/knowledge-storage-location-test.js +28 -28
- package/_site/_test/knowledge-storage-startup-test.js +52 -52
- package/_site/_test/knowledge-store-logs-supervision-test.js +89 -89
- package/_site/_test/launcher-readiness-test.js +80 -80
- package/_site/_test/legacy-claude-session-alias-test.js +106 -106
- package/_site/_test/legacy-routes-removed-test.js +47 -47
- package/_site/_test/legacy-workbench-exclusion-test.js +92 -92
- package/_site/_test/live-gateway-test.js +48 -48
- package/_site/_test/local-marketplace-test.js +16 -16
- package/_site/_test/log-redaction-test.js +58 -58
- package/_site/_test/logging-api-test.js +89 -89
- package/_site/_test/logging-sse-no-gap-test.js +88 -88
- package/_site/_test/logging-ui-test.js +107 -107
- package/_site/_test/markdown-delta-overlay-test.js +85 -85
- package/_site/_test/markdown-maintenance-api-test.js +75 -75
- package/_site/_test/markdown-maintenance-test.js +11 -11
- package/_site/_test/mcp-server-test.js +149 -149
- package/_site/_test/model-context-windows-test.js +89 -89
- package/_site/_test/module-agent-start-proxy-test.js +65 -65
- package/_site/_test/module-artifact-integrity-test.js +27 -27
- package/_site/_test/module-boundary-test.js +30 -30
- package/_site/_test/module-bridge-eventbridge-test.js +202 -202
- package/_site/_test/module-dynamic-port-test.js +118 -118
- package/_site/_test/module-index-proxy-test.js +33 -33
- package/_site/_test/module-model-configuration-test.js +44 -44
- package/_site/_test/module-process-lifecycle-test.js +35 -35
- package/_site/_test/module-stream-proxy-test.js +34 -34
- package/_site/_test/module-terminal-restart-test.js +63 -63
- package/_site/_test/module-wiring-unbind-race-test.js +59 -59
- package/_site/_test/native-context-integrations-test.js +86 -86
- package/_site/_test/non-release-ci-test.js +34 -34
- package/_site/_test/offline-boundary-isolation-test.js +32 -32
- package/_site/_test/orphaned-claim-recovery-test.js +80 -80
- package/_site/_test/package-boundary-test.js +43 -43
- package/_site/_test/package-startup-test.js +56 -56
- package/_site/_test/packaged-ui-smoke-test.js +88 -88
- package/_site/_test/parallel-ci-r9-posix-socket-budget-test.js +156 -0
- package/_site/_test/parallel-engine-advanced-eng005-test.js +136 -0
- package/_site/_test/parallel-engine-advanced-eng006-test.js +171 -0
- package/_site/_test/parallel-engine-advanced-eng007-reconcile-test.js +231 -0
- package/_site/_test/parallel-engine-advanced-eng009-test.js +208 -0
- package/_site/_test/parallel-engine-advanced-eng010-test.js +213 -0
- package/_site/_test/parallel-engine-advanced-eng011-ui-probe.js +459 -0
- package/_site/_test/parallel-engine-final-eng002-test.js +255 -0
- package/_site/_test/parallel-engine-final-eng007-test.js +269 -0
- package/_site/_test/parallel-engine-final-eng011-test.js +197 -0
- package/_site/_test/parallel-engine-final-eng012-test.js +354 -0
- package/_site/_test/parallel-knowledge-client-error-code-test.js +184 -0
- package/_site/_test/parallel-knowledge-engine-test.js +353 -0
- package/_site/_test/parallel-knowledge-retrieval-test.js +292 -0
- package/_site/_test/parallel-knowledge-vector-test.js +168 -0
- package/_site/_test/parallel-linux-ci-r7-log007-day-test.js +110 -0
- package/_site/_test/parallel-logging-acceptance-log003-test.js +224 -0
- package/_site/_test/parallel-logging-acceptance-log004-test.js +231 -0
- package/_site/_test/parallel-logging-acceptance-log005-test.js +208 -0
- package/_site/_test/parallel-logging-acceptance-log006-test.js +214 -0
- package/_site/_test/parallel-logging-acceptance-log007-test.js +223 -0
- package/_site/_test/parallel-logging-acceptance-log008-test.js +180 -0
- package/_site/_test/parallel-logging-fix-r2-crash-probe.js +271 -0
- package/_site/_test/parallel-logging-fix-r2-gap-test.js +294 -0
- package/_site/_test/parallel-logging-fix-r2-normalhook-test.js +330 -0
- package/_site/_test/parallel-logging-integration-5025-portability-test.js +554 -0
- package/_site/_test/parallel-memory-candidate-test.js +301 -0
- package/_site/_test/parallel-memory-manual-test.js +197 -0
- package/_site/_test/parallel-memory-scope-test.js +228 -0
- package/_site/_test/parallel-memory-source-test.js +227 -0
- package/_site/_test/parallel-memory-sync-test.js +238 -0
- package/_site/_test/parallel-memory-view-r8-reload-gate-test.js +123 -0
- package/_site/_test/parallel-nav-failure-test.js +119 -0
- package/_site/_test/parallel-nav-isolation-test.js +308 -0
- package/_site/_test/parallel-nav-isolation-vector-path-test.js +90 -0
- package/_site/_test/parallel-nav-offline-test.js +272 -0
- package/_site/_test/parallel-nav-operability-test.js +257 -0
- package/_site/_test/parallel-nav-switch-test.js +247 -0
- package/_site/_test/parallel-nav-theme-test.js +130 -0
- package/_site/_test/parallel-nav-viewport-test.js +310 -0
- package/_site/_test/parallel-qa-engine-endpoint-guard-test.js +273 -0
- package/_site/_test/parallel-retrieval-followup-citation-test.js +219 -0
- package/_site/_test/parallel-retrieval-followup-corpus-test.js +287 -0
- package/_site/_test/parallel-workbench-independent-host.js +262 -0
- package/_site/_test/parallel-workbench-integration-5025-abort-probe.js +340 -0
- package/_site/_test/parallel-workbench-integration-5025-drafts-probe.js +588 -0
- package/_site/_test/parallel-workbench-integration-5025-env-check.js +317 -0
- package/_site/_test/parallel-workbench-integration-5025-model-probe.js +342 -0
- package/_site/_test/parallel-workbench-integration-5025-ordering-probe.js +326 -0
- package/_site/_test/parallel-workbench-model-probe.js +336 -0
- package/_site/_test/parallel-workbench-offline-test.js +169 -0
- package/_site/_test/parallel-workbench-provenance-trace.js +134 -0
- package/_site/_test/parallel-workbench-source-match.js +206 -0
- package/_site/_test/parallel-workbench-standalone-turn.js +349 -0
- package/_site/_test/path-consistency-test.js +151 -151
- package/_site/_test/pending-sweep-test.js +9 -9
- package/_site/_test/post-commit-automation-test.js +87 -87
- package/_site/_test/pr-consumer-contract-test.js +55 -55
- package/_site/_test/product-brand-contract-test.js +25 -25
- package/_site/_test/product-diagnostics-ui-test.js +93 -93
- package/_site/_test/product-empty-state-test.js +148 -0
- package/_site/_test/product-import-ui-test.js +219 -104
- package/_site/_test/product-navigation-test.js +152 -0
- package/_site/_test/product-progress-status-test.js +84 -84
- package/_site/_test/project-delete-recovery-test.js +64 -64
- package/_site/_test/project-domain-create-test.js +91 -0
- package/_site/_test/project-domain-scope-retrieval-test.js +214 -0
- package/_site/_test/project-git-init-confirm-test.js +115 -0
- package/_site/_test/project-goal-editor-test.js +144 -144
- package/_site/_test/project-import-duplicate-alias-test.js +134 -0
- package/_site/_test/project-import-unicode-restart-test.js +140 -0
- package/_site/_test/project-lifecycle-transaction-test.js +106 -106
- package/_site/_test/project-module-partial-recovery-test.js +222 -0
- package/_site/_test/project-remove-running-guard-test.js +79 -79
- package/_site/_test/project-store-test.js +90 -90
- package/_site/_test/project-unbind-late-read-ui-test.js +250 -0
- package/_site/_test/project-unbind-writer-guard-test.js +231 -0
- package/_site/_test/prompt-settings-test.js +115 -115
- package/_site/_test/protected-architecture-gate-test.js +122 -122
- package/_site/_test/refactor-characterization-test.js +36 -36
- package/_site/_test/registry-events-test.js +38 -38
- package/_site/_test/release-version-sync-test.js +115 -115
- package/_site/_test/requirement-binding-test.js +113 -113
- package/_site/_test/requirement-recorder-test.js +173 -173
- package/_site/_test/run-all-tests.js +173 -161
- package/_site/_test/runtime-endpoint-test.js +64 -64
- package/_site/_test/scanner-test.js +83 -83
- package/_site/_test/server-security-test.js +96 -96
- package/_site/_test/sessions-stream-test.js +93 -93
- package/_site/_test/shared-contracts-test.js +58 -58
- package/_site/_test/shared-scope-root-binding-test.js +74 -67
- package/_site/_test/simple-import-test.js +98 -98
- package/_site/_test/startup-analysis-disabled-test.js +16 -16
- package/_site/_test/storage-foundation-test.js +78 -78
- package/_site/_test/structured-logger-test.js +101 -101
- package/_site/_test/t07b-cln-005-coverage-test.js +212 -0
- package/_site/_test/team-knowledge-store-sparse-checkout-test.js +196 -196
- package/_site/_test/team-knowledge-store-test.js +132 -132
- package/_site/_test/test-server-cleanup-test.js +35 -35
- package/_site/_test/test-server-module-isolation-test.js +37 -37
- package/_site/_test/tracking-start-test.js +144 -144
- package/_site/_test/vector-storage-root-test.js +75 -75
- package/_site/_test/version-visibility-browser-probe.js +249 -0
- package/_site/_test/version-visibility-test.js +92 -0
- package/_site/_test/workbench-context-receipts-test.js +22 -22
- package/_site/_test/workbench-permission-test.js +117 -117
- package/_site/_test/zcode-capture-integration-test.js +112 -112
- package/_site/lib/ai-profile-resolver.js +78 -78
- package/_site/lib/ai-vendor-presets.js +83 -83
- package/_site/lib/ai-workspace.js +104 -104
- package/_site/lib/atomic-file.js +204 -204
- package/_site/lib/automation-config.js +140 -140
- package/_site/lib/bridge-adapter.js +260 -260
- package/_site/lib/bridge-consumer-service.js +402 -402
- package/_site/lib/capture-hook-config.js +108 -108
- package/_site/lib/claude-cli-runner.js +1599 -1599
- package/_site/lib/cli-instances.js +43 -43
- package/_site/lib/codex-context-status.js +17 -17
- package/_site/lib/codex-notify-config.js +193 -193
- package/_site/lib/commit-conversation-binder.js +247 -247
- package/_site/lib/commit-processing-ledger.js +27 -27
- package/_site/lib/commit-prompt.js +202 -202
- package/_site/lib/commit-reconciler.js +444 -444
- package/_site/lib/context-pack-builder.js +299 -299
- package/_site/lib/contracts.js +291 -291
- package/_site/lib/conversation-exclusions.js +204 -204
- package/_site/lib/conversation-query-service.js +161 -161
- package/_site/lib/conversation-store.js +387 -387
- package/_site/lib/data-dir.js +13 -13
- package/_site/lib/embedding-service.js +85 -85
- package/_site/lib/engine-connection.js +93 -93
- package/_site/lib/engine-knowledge-client.js +76 -72
- package/_site/lib/evidence-bundle.js +228 -228
- package/_site/lib/folder-picker-output.js +24 -24
- package/_site/lib/git-path.js +14 -14
- package/_site/lib/git-runner.js +62 -62
- package/_site/lib/github-team-store.js +1175 -1175
- package/_site/lib/hook-manager.js +203 -203
- package/_site/lib/index-builder.js +157 -157
- package/_site/lib/index-service.js +173 -173
- package/_site/lib/integration-auto-repair.js +77 -77
- package/_site/lib/integration-installer.js +1240 -1240
- package/_site/lib/integration-intent.js +88 -88
- package/_site/lib/integration-status-scan.js +99 -99
- package/_site/lib/integration-status-worker.js +14 -14
- package/_site/lib/kb-framework.js +191 -191
- package/_site/lib/kb-validator.js +124 -124
- package/_site/lib/knowledge-db.js +363 -363
- package/_site/lib/knowledge-promotion.js +435 -435
- package/_site/lib/knowledge-retrieval-service.js +401 -401
- package/_site/lib/knowledge-schema.js +121 -121
- package/_site/lib/knowledge-tool-runtime.js +366 -366
- package/_site/lib/live-gateway.js +78 -78
- package/_site/lib/llm-client.js +173 -173
- package/_site/lib/markdown-knowledge-indexer.js +230 -230
- package/_site/lib/model-context-windows.js +82 -82
- package/_site/lib/module-bridge.js +874 -874
- package/_site/lib/module-port-resolver.js +57 -57
- package/_site/lib/post-commit-automation.js +141 -141
- package/_site/lib/product-data.js +35 -35
- package/_site/lib/project-lifecycle-service.js +554 -554
- package/_site/lib/project-registry-store.js +129 -129
- package/_site/lib/project-store.js +268 -268
- package/_site/lib/prompt-registry.js +148 -148
- package/_site/lib/public-version-info.js +37 -0
- package/_site/lib/registry-events.js +16 -16
- package/_site/lib/requirement-adapters.js +10 -10
- package/_site/lib/requirement-binder.js +112 -112
- package/_site/lib/requirement-recorder.js +278 -278
- package/_site/lib/runtime-control.js +89 -89
- package/_site/lib/runtime-endpoint.js +160 -160
- package/_site/lib/scanner.js +298 -298
- package/_site/lib/server-app.js +1672 -1664
- package/_site/lib/settings-store.js +153 -153
- package/_site/lib/storage-layout.js +166 -166
- package/_site/lib/structured-logger.js +574 -574
- package/_site/lib/zcode-context-integration.js +60 -60
- package/_site/scripts/codex-notify-fanout.cjs +95 -95
- package/_site/scripts/folder-picker.ps1 +156 -156
- package/_site/scripts/hook-trigger.js +158 -158
- package/_site/scripts/install-module-candidates.js +69 -69
- package/_site/scripts/pack-module-candidates.js +89 -89
- package/_site/scripts/sync-product-content.js +28 -28
- package/_site/scripts/sync-release-version.js +164 -164
- package/_site/scripts/vendor-modules.js +49 -49
- package/_site/scripts/verify-module-runtime.js +50 -50
- package/_site/scripts/verify-product-runtime.js +36 -36
- package/_site/scripts/verify-retrieval-gold.js +83 -83
- package/_site/server.js +15 -15
- package/_site/start.bat +26 -26
- package/_site/stop.bat +11 -11
- package/bin/project-knowledge-integrations.js +254 -254
- package/bin/project-knowledge-kb.js +67 -67
- package/bin/project-knowledge-mcp.js +201 -201
- package/bin/project-knowledge.js +269 -170
- package/claude-prompts.json +21 -21
- package/docs/README.zh-CN.md +207 -205
- package/docs/assets/architecture.svg +181 -181
- package/docs/assets/logo.svg +49 -49
- package/docs/fresh-v5-start.md +44 -44
- package/docs/leader-glm-workbench-playbook.md +122 -122
- package/docs/project-registry-schema.md +33 -33
- package/docs/release-5.0.16-acceptance.md +176 -176
- package/docs/release-5.0.17-acceptance.md +117 -117
- package/docs/release-5.0.19-acceptance.md +39 -39
- package/docs/team-knowledge-mode-a-plan.md +73 -73
- package/docs/testing-strategy.md +33 -33
- package/module-runtime-manifest.json +68 -65
- package/package.json +113 -110
- package/plugins/project-knowledge/.claude-plugin/plugin.json +1 -1
- package/plugins/project-knowledge/.codex-plugin/plugin.json +1 -1
- package/plugins/project-knowledge/.mcp.json +1 -1
- package/templates/change.md +30 -30
- package/templates/project-readme.md +52 -52
- package/ui/index.html +3 -2
- package/ui/version-info.css +44 -0
- package/ui/version-info.js +24 -0
- package/vendor-manifest.json +55 -55
|
@@ -0,0 +1,737 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// Lane-owned helpers for the P-RETRIEVAL-FOLLOWUP-R2 round (RET-007-R2).
|
|
3
|
+
//
|
|
4
|
+
// PROVENANCE / OWNERSHIP
|
|
5
|
+
// ----------------------
|
|
6
|
+
// This file is a LANE-EXCLUSIVE SNAPSHOT of the P-MEMORY-INJECTION-02 lane's
|
|
7
|
+
// helper. That lane is still writing its file, so this lane COPIES the pieces
|
|
8
|
+
// it needs instead of importing them: the source is read-only here and is
|
|
9
|
+
// never edited, and the SHA-256 of the source is computed at run time so the
|
|
10
|
+
// copy can always be checked against its origin.
|
|
11
|
+
//
|
|
12
|
+
// piece source (read-only) owner
|
|
13
|
+
// -------------------------------------- ----------------------------------------- --------------------------
|
|
14
|
+
// isolation, read-only profile facade, _site/_test/helpers/parallel-memory-injection-shell.js P-MEMORY-INJECTION-02
|
|
15
|
+
// recording proxy, transcript scan,
|
|
16
|
+
// real Workbench turn
|
|
17
|
+
// host child shape _site/_test/helpers/parallel-memory-injection-wb-host.js P-MEMORY-INJECTION-02
|
|
18
|
+
//
|
|
19
|
+
// The chain helpers of THIS lane (real Git, real hook, real engine, real
|
|
20
|
+
// vector hub, real subscription profile) are NOT copied: they already live in
|
|
21
|
+
// the lane-owned _site/_test/helpers/parallel-retrieval-followup-shell.js and
|
|
22
|
+
// are required from there.
|
|
23
|
+
//
|
|
24
|
+
// Isolation contract (batch rules): every artefact lives under the shared
|
|
25
|
+
// external temp root (D:/SanQian.Xu/.project-knowledge-test-temp); the
|
|
26
|
+
// Workbench data dir, Bridge home, HOME/USERPROFILE and CLAUDE_CONFIG_DIR are
|
|
27
|
+
// isolated; the live product ports (5757/5760/5789/5790/8787/8790) are
|
|
28
|
+
// refused; ambient module addresses and every ambient Anthropic credential
|
|
29
|
+
// variable are dropped.
|
|
30
|
+
//
|
|
31
|
+
// Credential contract: the original subscription credential is read from its
|
|
32
|
+
// real location READ-ONLY and stays in memory. It is never written to a file,
|
|
33
|
+
// a log, a report or a clone, and the profile store handed to the host refuses
|
|
34
|
+
// every write method.
|
|
35
|
+
const fs = require('node:fs');
|
|
36
|
+
const os = require('node:os');
|
|
37
|
+
const path = require('node:path');
|
|
38
|
+
const http = require('node:http');
|
|
39
|
+
const net = require('node:net');
|
|
40
|
+
const crypto = require('node:crypto');
|
|
41
|
+
const { spawn, execFileSync } = require('node:child_process');
|
|
42
|
+
|
|
43
|
+
// The chain helpers of THIS lane (own file, not a snapshot).
|
|
44
|
+
const chain = require('./parallel-retrieval-followup-shell');
|
|
45
|
+
|
|
46
|
+
const REPO_ROOT = path.resolve(__dirname, '..', '..', '..');
|
|
47
|
+
const ENGINE_ENTRY = path.join(REPO_ROOT, '_modules', 'knowledge-engine', 'src', 'server.js');
|
|
48
|
+
const BRIDGE_CONSOLE_ENTRY = path.join(REPO_ROOT, 'node_modules', '@sanqianx', 'ai-coding-event-bridge-console', 'src', 'server.js');
|
|
49
|
+
const BRIDGE_REPO_CONTEXT = path.join(REPO_ROOT, 'node_modules', '@sanqianx', 'ai-coding-event-bridge-console', 'src', 'bridge', 'core', 'repo-context.js');
|
|
50
|
+
|
|
51
|
+
// The developer's live surfaces. A lane test may never bind or talk to them.
|
|
52
|
+
const FORBIDDEN_PORTS = new Set([5757, 5760, 5789, 5790, 8787, 8790]);
|
|
53
|
+
|
|
54
|
+
// Ambient module addresses that would point a test at a live instance.
|
|
55
|
+
const AMBIENT_MODULE_URLS = [
|
|
56
|
+
'KB_KNOWLEDGE_ENGINE_URL',
|
|
57
|
+
'KB_VECTORHUB_URL',
|
|
58
|
+
'KB_TERMINAL_URL',
|
|
59
|
+
'KB_EVENTBRIDGE_URL',
|
|
60
|
+
'KB_EVENT_BRIDGE_URL',
|
|
61
|
+
'KB_WORKBENCH_RUNTIME_TOKEN',
|
|
62
|
+
'KB_MODULES_AUTOSTART',
|
|
63
|
+
'KB_ENGINE_RUNTIME_TOKEN',
|
|
64
|
+
'AI_CODING_EVENT_BRIDGE_HOME',
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
// Ambient Anthropic credentials: the lane may only use the credential it
|
|
68
|
+
// injects itself, never one that happens to sit in the shell.
|
|
69
|
+
const AMBIENT_MODEL_ENV = [
|
|
70
|
+
'ANTHROPIC_API_KEY',
|
|
71
|
+
'ANTHROPIC_AUTH_TOKEN',
|
|
72
|
+
'ANTHROPIC_BASE_URL',
|
|
73
|
+
'ANTHROPIC_MODEL',
|
|
74
|
+
'ANTHROPIC_DEFAULT_THINKING_MODEL',
|
|
75
|
+
'ANTHROPIC_DEFAULT_HAIKU_MODEL',
|
|
76
|
+
'ANTHROPIC_DEFAULT_SONNET_MODEL',
|
|
77
|
+
'ANTHROPIC_DEFAULT_OPUS_MODEL',
|
|
78
|
+
'API_TIMEOUT_MS',
|
|
79
|
+
'CLAUDE_CODE_OAUTH_TOKEN',
|
|
80
|
+
'CLAUDE_CODE_USE_BEDROCK',
|
|
81
|
+
'CLAUDE_CODE_USE_VERTEX',
|
|
82
|
+
'CLAUDE_CODE_USE_FOUNDRY',
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
// Captured before any isolation rewrites HOME.
|
|
86
|
+
const REAL_HOME = os.homedir();
|
|
87
|
+
const REAL_USERPROFILE = process.env.USERPROFILE || REAL_HOME;
|
|
88
|
+
|
|
89
|
+
const SNAPSHOT_SOURCES = [
|
|
90
|
+
{ piece: 'isolation, read-only profile facade, recording proxy, transcript scan, real Workbench turn', source: '_site/_test/helpers/parallel-memory-injection-shell.js', owner: 'P-MEMORY-INJECTION-02 lane (untracked, still being written)' },
|
|
91
|
+
{ piece: 'host child shape', source: '_site/_test/helpers/parallel-memory-injection-wb-host.js', owner: 'P-MEMORY-INJECTION-02 lane (untracked, still being written)' },
|
|
92
|
+
{ piece: 'chain helpers (real Git, real engine, real vector hub, real subscription profile)', source: '_site/_test/helpers/parallel-retrieval-followup-shell.js', owner: 'this lane (P-RETRIEVAL-FOLLOWUP)' },
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
function sha256File(file) {
|
|
96
|
+
try { return crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex'); } catch { return null; }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// The provenance of every snapshot, with the source hash computed now.
|
|
100
|
+
function snapshotProvenance() {
|
|
101
|
+
return SNAPSHOT_SOURCES.map(entry => {
|
|
102
|
+
const absolute = path.join(REPO_ROOT, ...entry.source.split('/'));
|
|
103
|
+
return { ...entry, sourceSha256: sha256File(absolute), sourceExists: fs.existsSync(absolute) };
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function isInside(candidate, parent) {
|
|
108
|
+
const relative = path.relative(parent, candidate);
|
|
109
|
+
return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// The batch contract pins an external temp root next to the repositories.
|
|
113
|
+
function resolveTempRoot() {
|
|
114
|
+
const sharedRoot = path.join(path.dirname(REPO_ROOT), '.project-knowledge-test-temp');
|
|
115
|
+
const candidates = [
|
|
116
|
+
process.env.PK_TEST_TEMP_ROOT,
|
|
117
|
+
fs.existsSync(sharedRoot) ? sharedRoot : null,
|
|
118
|
+
process.env.TEMP,
|
|
119
|
+
process.env.TMP,
|
|
120
|
+
process.env.TMPDIR,
|
|
121
|
+
];
|
|
122
|
+
const chosen = candidates.find(value => value && String(value).trim());
|
|
123
|
+
const root = path.resolve(chosen ? String(chosen).trim() : os.tmpdir());
|
|
124
|
+
if (isInside(root, REPO_ROOT)) throw new Error(`refusing to use a temp root inside the repository: ${root}`);
|
|
125
|
+
return root;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function makeTempDir(prefix = 'parallel-memory-injection') {
|
|
129
|
+
const root = resolveTempRoot();
|
|
130
|
+
fs.mkdirSync(root, { recursive: true });
|
|
131
|
+
const dir = fs.mkdtempSync(path.join(root, `${prefix}-`));
|
|
132
|
+
if (isInside(dir, REPO_ROOT)) throw new Error(`refusing to create a fixture inside the repository: ${dir}`);
|
|
133
|
+
return dir;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function removeTree(dir) {
|
|
137
|
+
if (!dir) return;
|
|
138
|
+
fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Windows keeps a directory locked for a short while after the process that
|
|
142
|
+
// used it exits (and the AV scanner may hold it too), so a single rmSync can
|
|
143
|
+
// fail with EPERM even though nothing is still running. Retry with a delay
|
|
144
|
+
// and report the outcome instead of throwing, so a leftover scratch folder
|
|
145
|
+
// never turns a green evidence run into a script error.
|
|
146
|
+
async function removeTreeAsync(dir, { attempts = 12, delayMs = 500 } = {}) {
|
|
147
|
+
if (!dir) return { removed: true, path: dir, error: null };
|
|
148
|
+
let lastError = null;
|
|
149
|
+
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
150
|
+
try {
|
|
151
|
+
fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
152
|
+
return { removed: true, path: dir, error: null, attempts: attempt };
|
|
153
|
+
} catch (error) {
|
|
154
|
+
lastError = error;
|
|
155
|
+
if (!fs.existsSync(dir)) return { removed: true, path: dir, error: null, attempts: attempt };
|
|
156
|
+
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return { removed: false, path: dir, attempts, error: { code: lastError.code, message: lastError.message } };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async function freePort() {
|
|
163
|
+
return new Promise((resolve, reject) => {
|
|
164
|
+
const server = net.createServer();
|
|
165
|
+
server.unref();
|
|
166
|
+
server.on('error', reject);
|
|
167
|
+
server.listen(0, '127.0.0.1', () => {
|
|
168
|
+
const { port } = server.address();
|
|
169
|
+
server.close(() => {
|
|
170
|
+
if (FORBIDDEN_PORTS.has(Number(port))) { reject(new Error(`refusing to use the live port ${port}`)); return; }
|
|
171
|
+
resolve(Number(port));
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function waitForHttp(url, timeoutMs = 30000) {
|
|
178
|
+
const parsed = new URL(url);
|
|
179
|
+
const port = parsed.port ? Number(parsed.port) : (parsed.protocol === 'https:' ? 443 : 80);
|
|
180
|
+
if (FORBIDDEN_PORTS.has(port)) throw new Error(`refusing to contact the live service ${url}`);
|
|
181
|
+
const until = Date.now() + timeoutMs;
|
|
182
|
+
let lastError = null;
|
|
183
|
+
while (Date.now() < until) {
|
|
184
|
+
try {
|
|
185
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(2000) });
|
|
186
|
+
if (response.ok) return true;
|
|
187
|
+
lastError = new Error(`HTTP ${response.status}`);
|
|
188
|
+
} catch (error) { lastError = error; }
|
|
189
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
190
|
+
}
|
|
191
|
+
throw new Error(`Timed out waiting for ${url}: ${lastError && lastError.message}`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function git(cwd, args) {
|
|
195
|
+
const result = execFileSync('git', ['-C', cwd, ...args], { encoding: 'utf8', windowsHide: true, env: { ...process.env, GIT_TERMINAL_PROMPT: '0' } });
|
|
196
|
+
return String(result || '').trim();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// A real Git repository with a real commit: the engine resolves a project by
|
|
200
|
+
// the Git toplevel, and the Bridge derives the repo identity from it.
|
|
201
|
+
function makeGitRepo(root, name) {
|
|
202
|
+
const repo = path.join(root, name);
|
|
203
|
+
fs.mkdirSync(repo, { recursive: true });
|
|
204
|
+
git(repo, ['init', '-q', '-b', 'main']);
|
|
205
|
+
git(repo, ['config', 'user.email', 'parallel-memory-injection@local.invalid']);
|
|
206
|
+
git(repo, ['config', 'user.name', 'Parallel Memory Injection Lane']);
|
|
207
|
+
git(repo, ['config', 'commit.gpgsign', 'false']);
|
|
208
|
+
fs.writeFileSync(path.join(repo, 'README.md'), `# ${name}\n`, 'utf8');
|
|
209
|
+
git(repo, ['add', '.']);
|
|
210
|
+
git(repo, ['commit', '-qm', 'baseline']);
|
|
211
|
+
return { path: repo, headCommit: git(repo, ['rev-parse', 'HEAD']) };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function sanitizedEnv(extra = {}) {
|
|
215
|
+
const env = { ...process.env, ...extra };
|
|
216
|
+
for (const key of AMBIENT_MODULE_URLS) delete env[key];
|
|
217
|
+
for (const key of AMBIENT_MODEL_ENV) delete env[key];
|
|
218
|
+
return env;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function spawnNode(args, env = {}) {
|
|
222
|
+
const child = spawn(process.execPath, args, { env: sanitizedEnv(env), windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
223
|
+
const output = { stdout: '', stderr: '' };
|
|
224
|
+
child.stdout.on('data', chunk => { output.stdout += chunk; });
|
|
225
|
+
child.stderr.on('data', chunk => { output.stderr += chunk; });
|
|
226
|
+
const exited = new Promise(resolve => child.once('close', code => resolve({ code, ...output })));
|
|
227
|
+
return { child, exited, output };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// The isolated directories of one run.
|
|
231
|
+
function createIsolationLayout(prefix = 'parallel-memory-injection') {
|
|
232
|
+
const root = makeTempDir(prefix);
|
|
233
|
+
const layout = {
|
|
234
|
+
root,
|
|
235
|
+
dataDir: path.join(root, 'workbench-data'),
|
|
236
|
+
knowledgeDataDir: path.join(root, 'knowledge-data'),
|
|
237
|
+
bridgeHome: path.join(root, 'bridge-home'),
|
|
238
|
+
engineDataDir: path.join(root, 'engine-data'),
|
|
239
|
+
brainKnowledgeDir: path.join(root, 'brain-knowledge'),
|
|
240
|
+
projectKnowledgeDir: path.join(root, 'project-knowledge'),
|
|
241
|
+
controlKnowledgeDir: path.join(root, 'control-knowledge'),
|
|
242
|
+
home: path.join(root, 'home'),
|
|
243
|
+
claudeConfigDir: path.join(root, 'claude-config'),
|
|
244
|
+
temp: path.join(root, 'temp'),
|
|
245
|
+
repos: path.join(root, 'repos'),
|
|
246
|
+
};
|
|
247
|
+
for (const dir of Object.values(layout)) {
|
|
248
|
+
if (typeof dir === 'string') fs.mkdirSync(dir, { recursive: true });
|
|
249
|
+
}
|
|
250
|
+
return layout;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// The environment a host child may inherit.
|
|
254
|
+
function hostEnv(layout, extra = {}) {
|
|
255
|
+
const parsed = path.parse(layout.home);
|
|
256
|
+
return sanitizedEnv({
|
|
257
|
+
// The real profile directory is passed explicitly: the child's isolated
|
|
258
|
+
// HOME would otherwise hide it from the read-only profile facade.
|
|
259
|
+
PK_WB_REAL_PROFILE_DIR: realWorkbenchProfileDir(),
|
|
260
|
+
HOME: layout.home,
|
|
261
|
+
USERPROFILE: layout.home,
|
|
262
|
+
HOMEDRIVE: parsed.root,
|
|
263
|
+
HOMEPATH: parsed.root === path.sep ? layout.home.slice(1) : layout.home.slice(parsed.root.length),
|
|
264
|
+
CLAUDE_CONFIG_DIR: layout.claudeConfigDir,
|
|
265
|
+
TEMP: layout.temp,
|
|
266
|
+
TMP: layout.temp,
|
|
267
|
+
TMPDIR: layout.temp,
|
|
268
|
+
KB_DATA_DIR: layout.knowledgeDataDir,
|
|
269
|
+
KB_KNOWLEDGE_DATA_DIR: layout.knowledgeDataDir,
|
|
270
|
+
AI_CODING_EVENT_BRIDGE_HOME: layout.bridgeHome,
|
|
271
|
+
AGENT_TERMINAL_DATA_DIR: layout.dataDir,
|
|
272
|
+
CLAUDE_AI_WORKBENCH_DATA_DIR: layout.dataDir,
|
|
273
|
+
KB_MODULES_AUTOSTART: '0',
|
|
274
|
+
...extra,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Where the product keeps its profiles. Resolved from the real home, never
|
|
279
|
+
// from an isolated one.
|
|
280
|
+
function realWorkbenchProfileDir() {
|
|
281
|
+
const override = String(process.env.PK_WB_REAL_PROFILE_DIR || '').trim();
|
|
282
|
+
if (override) return path.resolve(override);
|
|
283
|
+
return path.join(REAL_HOME, '.project-knowledge-v5', 'workbench');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Byte-level snapshot of a flat directory. The SHA-256 digests stay in the
|
|
287
|
+
// process memory: only counts and file NAMES ever leave compareDigests, so a
|
|
288
|
+
// digest of a credential file is never printed, logged or persisted.
|
|
289
|
+
function digestDirectory(dir) {
|
|
290
|
+
if (!dir || !fs.existsSync(dir)) return null;
|
|
291
|
+
const entries = {};
|
|
292
|
+
for (const name of fs.readdirSync(dir)) {
|
|
293
|
+
try {
|
|
294
|
+
const file = path.join(dir, name);
|
|
295
|
+
if (!fs.statSync(file).isFile()) continue;
|
|
296
|
+
entries[name] = crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
|
|
297
|
+
} catch { entries[name] = null; }
|
|
298
|
+
}
|
|
299
|
+
return entries;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function compareDigests(before, after) {
|
|
303
|
+
const names = new Set([...Object.keys(before || {}), ...Object.keys(after || {})]);
|
|
304
|
+
const changed = [], added = [], removed = [], unreadable = [];
|
|
305
|
+
for (const name of names) {
|
|
306
|
+
const a = before ? before[name] : undefined;
|
|
307
|
+
const b = after ? after[name] : undefined;
|
|
308
|
+
if (a === undefined && b !== undefined) added.push(name);
|
|
309
|
+
else if (a !== undefined && b === undefined) removed.push(name);
|
|
310
|
+
else if (a === null || b === null) unreadable.push(name);
|
|
311
|
+
else if (a !== b) changed.push(name);
|
|
312
|
+
}
|
|
313
|
+
return {
|
|
314
|
+
count: names.size,
|
|
315
|
+
byteIdentical: changed.length === 0 && added.length === 0 && removed.length === 0 && unreadable.length === 0,
|
|
316
|
+
changedFiles: changed,
|
|
317
|
+
addedFiles: added,
|
|
318
|
+
removedFiles: removed,
|
|
319
|
+
unreadableFiles: unreadable,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// A profile store that reads the original profiles and credentials but
|
|
324
|
+
// refuses every write. The credential stays in memory: it is never written
|
|
325
|
+
// anywhere by this lane.
|
|
326
|
+
function createReadOnlyProfileStore(moduleRoot, layout, options = {}) {
|
|
327
|
+
const profileDir = options.profileDir || realWorkbenchProfileDir();
|
|
328
|
+
const profileFile = path.join(profileDir, 'profiles.v2.json');
|
|
329
|
+
const credentialFile = path.join(profileDir, 'credentials.v1.json');
|
|
330
|
+
if (!fs.existsSync(profileFile)) throw new Error(`the original profile file is missing: ${profileFile}`);
|
|
331
|
+
const { ProfileStore } = require(path.join(moduleRoot, 'packages', 'server', 'lib', 'profile-store.js'));
|
|
332
|
+
const store = new ProfileStore({ dataDir: layout.dataDir, profileFile, credentialFile });
|
|
333
|
+
const WRITE_METHODS = new Set(['save', 'delete', 'setCredential', 'setEmbeddingConfig', 'setMaintenanceDefault', 'importLegacy', 'importEmbedding']);
|
|
334
|
+
return new Proxy(store, {
|
|
335
|
+
get(target, property) {
|
|
336
|
+
if (WRITE_METHODS.has(property)) {
|
|
337
|
+
return () => { throw Object.assign(new Error('the profile store of this fixture is read-only'), { status: 409 }); };
|
|
338
|
+
}
|
|
339
|
+
const value = target[property];
|
|
340
|
+
return typeof value === 'function' ? value.bind(target) : value;
|
|
341
|
+
},
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// The module that is hosted: the copy the installed product ships, unless the
|
|
346
|
+
// caller pins another one explicitly.
|
|
347
|
+
function resolveWorkbenchModuleRoot(options = {}) {
|
|
348
|
+
const override = String(options.moduleRoot || process.env.PK_WB_MODULE_ROOT || '').trim();
|
|
349
|
+
if (override) return path.resolve(override);
|
|
350
|
+
const appData = String(process.env.APPDATA || '').trim();
|
|
351
|
+
if (appData) {
|
|
352
|
+
const candidate = path.join(appData, 'npm', 'node_modules', '@sanqianx', 'project-knowledge', 'node_modules', 'claude-ai-workbench');
|
|
353
|
+
if (fs.existsSync(path.join(candidate, 'packages', 'server', 'package.json'))) return candidate;
|
|
354
|
+
}
|
|
355
|
+
const repoPin = path.join(REPO_ROOT, 'node_modules', 'claude-ai-workbench');
|
|
356
|
+
if (fs.existsSync(path.join(repoPin, 'packages', 'server', 'package.json'))) return repoPin;
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function packageIdentity(moduleRoot) {
|
|
361
|
+
try {
|
|
362
|
+
const manifest = JSON.parse(fs.readFileSync(path.join(moduleRoot, 'packages', 'server', 'package.json'), 'utf8'));
|
|
363
|
+
return { name: manifest.name, version: manifest.version };
|
|
364
|
+
} catch { return { name: null, version: null }; }
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function safeJson(raw) {
|
|
368
|
+
const text = Buffer.isBuffer(raw) ? raw.toString('utf8') : String(raw || '');
|
|
369
|
+
try { return JSON.parse(text); } catch { return text.length > 200000 ? `${text.slice(0, 200000)}…[truncated]` : text; }
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// An observation-only transparent proxy in front of the real engine: it
|
|
373
|
+
// forwards every request byte-for-byte and records both directions. It never
|
|
374
|
+
// rewrites, filters or synthesises a response, so what the Workbench module
|
|
375
|
+
// received is what the engine produced.
|
|
376
|
+
async function startRecordingProxy({ target, label = 'engine' }) {
|
|
377
|
+
const targetUrl = new URL(target);
|
|
378
|
+
const records = [];
|
|
379
|
+
const server = http.createServer((req, res) => {
|
|
380
|
+
const chunks = [];
|
|
381
|
+
req.on('data', chunk => chunks.push(chunk));
|
|
382
|
+
req.on('end', async () => {
|
|
383
|
+
const body = Buffer.concat(chunks);
|
|
384
|
+
const entry = { label, method: req.method, url: req.url, requestBytes: body.length, requestBody: safeJson(body), at: new Date().toISOString() };
|
|
385
|
+
try {
|
|
386
|
+
const headers = { ...req.headers };
|
|
387
|
+
delete headers.host;
|
|
388
|
+
delete headers['accept-encoding'];
|
|
389
|
+
const response = await fetch(new URL(req.url, targetUrl), {
|
|
390
|
+
method: req.method,
|
|
391
|
+
headers,
|
|
392
|
+
body: body.length ? body : undefined,
|
|
393
|
+
signal: AbortSignal.timeout(15000),
|
|
394
|
+
});
|
|
395
|
+
const text = await response.text();
|
|
396
|
+
entry.responseStatus = response.status;
|
|
397
|
+
entry.responseBody = safeJson(text);
|
|
398
|
+
records.push(entry);
|
|
399
|
+
res.writeHead(response.status, { 'Content-Type': response.headers.get('content-type') || 'application/json' });
|
|
400
|
+
res.end(text);
|
|
401
|
+
} catch (error) {
|
|
402
|
+
entry.error = error.message;
|
|
403
|
+
records.push(entry);
|
|
404
|
+
res.writeHead(502, { 'Content-Type': 'application/json' });
|
|
405
|
+
res.end(JSON.stringify({ ok: false, error: 'PROXY_TARGET_UNAVAILABLE' }));
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
|
|
410
|
+
const port = server.address().port;
|
|
411
|
+
if (FORBIDDEN_PORTS.has(Number(port))) throw new Error(`refusing to use the live port ${port}`);
|
|
412
|
+
return {
|
|
413
|
+
url: `http://127.0.0.1:${port}`,
|
|
414
|
+
records,
|
|
415
|
+
requests: () => records.filter(entry => entry.method === 'POST'),
|
|
416
|
+
close: () => new Promise(done => server.close(() => done())),
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// An ISOLATED stand-in for the vector hub. The engine must never reach the
|
|
421
|
+
// live 8787 instance, and this lane makes no vector claim: the stand-in
|
|
422
|
+
// answers an empty result set, so retrieval stays lexical-only. Vector
|
|
423
|
+
// evidence is explicitly NOT produced here.
|
|
424
|
+
async function startVectorHubStandIn() {
|
|
425
|
+
const requests = [];
|
|
426
|
+
const server = http.createServer((req, res) => {
|
|
427
|
+
requests.push({ url: req.url, at: new Date().toISOString() });
|
|
428
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
429
|
+
res.end(JSON.stringify({ ok: true, results: [], model: 'lane-stand-in-lexical-only', dimensions: 0 }));
|
|
430
|
+
});
|
|
431
|
+
await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
|
|
432
|
+
const port = server.address().port;
|
|
433
|
+
if (FORBIDDEN_PORTS.has(Number(port))) throw new Error(`refusing to use the live port ${port}`);
|
|
434
|
+
return {
|
|
435
|
+
url: `http://127.0.0.1:${port}`,
|
|
436
|
+
requests,
|
|
437
|
+
kind: 'isolated-stand-in (empty result set, lexical-only, NOT vector evidence)',
|
|
438
|
+
close: () => new Promise(done => server.close(() => done())),
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// The REAL knowledge engine, in-process, on its own isolated data dir.
|
|
443
|
+
async function startRealEngine({ dataDir, runtimeToken, debug = true, consume = false, bridgeUrl, vectorUrl }) {
|
|
444
|
+
// Fail-closed endpoint guard: the coordinator ignores env and silently
|
|
445
|
+
// defaults its vector/bridge legs to LIVE 8787/8790, so an engine without
|
|
446
|
+
// explicit OWN endpoints is refused instead of defaulting live.
|
|
447
|
+
const { assertOwnedEndpoint } = require('./parallel-qa-engine-endpoint-guard');
|
|
448
|
+
assertOwnedEndpoint(vectorUrl, { role: 'vectorUrl' });
|
|
449
|
+
assertOwnedEndpoint(bridgeUrl, { role: 'bridgeUrl' });
|
|
450
|
+
const { createEngineServer } = require(ENGINE_ENTRY);
|
|
451
|
+
const engine = createEngineServer({
|
|
452
|
+
dataDir,
|
|
453
|
+
runtimeToken,
|
|
454
|
+
debug: debug === true,
|
|
455
|
+
consume: consume === true,
|
|
456
|
+
bridgeUrl,
|
|
457
|
+
vectorUrl,
|
|
458
|
+
});
|
|
459
|
+
await engine.ready;
|
|
460
|
+
await new Promise(resolve => engine.server.listen(0, '127.0.0.1', resolve));
|
|
461
|
+
const port = engine.server.address().port;
|
|
462
|
+
if (FORBIDDEN_PORTS.has(Number(port))) throw new Error(`refusing to use the live port ${port}`);
|
|
463
|
+
const url = `http://127.0.0.1:${port}`;
|
|
464
|
+
const api = async (method, route, body) => {
|
|
465
|
+
const response = await fetch(url + route, {
|
|
466
|
+
method,
|
|
467
|
+
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${runtimeToken}` },
|
|
468
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
469
|
+
signal: AbortSignal.timeout(20000),
|
|
470
|
+
});
|
|
471
|
+
return { status: response.status, body: await response.json().catch(() => null) };
|
|
472
|
+
};
|
|
473
|
+
return {
|
|
474
|
+
engine,
|
|
475
|
+
url,
|
|
476
|
+
token: runtimeToken,
|
|
477
|
+
api,
|
|
478
|
+
close: () => engine.close().catch(() => {}),
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// The REAL event-bridge console, in-process, on its own isolated home.
|
|
483
|
+
async function startBridgeConsole({ home, runtimeToken }) {
|
|
484
|
+
const { createConsoleServer } = require(BRIDGE_CONSOLE_ENTRY);
|
|
485
|
+
const handler = createConsoleServer({ home, runtimeToken });
|
|
486
|
+
const server = http.createServer(handler);
|
|
487
|
+
await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
|
|
488
|
+
const port = server.address().port;
|
|
489
|
+
if (FORBIDDEN_PORTS.has(Number(port))) throw new Error(`refusing to use the live port ${port}`);
|
|
490
|
+
const url = `http://127.0.0.1:${port}`;
|
|
491
|
+
const api = async (method, route, body) => {
|
|
492
|
+
const response = await fetch(url + route, {
|
|
493
|
+
method,
|
|
494
|
+
headers: { 'Content-Type': 'application/json', ...(route.startsWith('/api/internal/') ? { Authorization: `Bearer ${runtimeToken}` } : {}) },
|
|
495
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
496
|
+
signal: AbortSignal.timeout(20000),
|
|
497
|
+
});
|
|
498
|
+
return { status: response.status, body: await response.json().catch(() => null) };
|
|
499
|
+
};
|
|
500
|
+
return { url, api, close: () => new Promise(done => server.close(() => done())) };
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// The repo identity the real Bridge derives for a directory.
|
|
504
|
+
async function resolveRepoIdentity(dir) {
|
|
505
|
+
const { resolveRepoContext } = require(BRIDGE_REPO_CONTEXT);
|
|
506
|
+
return resolveRepoContext(dir);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function walkFiles(root, visit) {
|
|
510
|
+
let names;
|
|
511
|
+
try { names = fs.readdirSync(root, { withFileTypes: true }); } catch { return; }
|
|
512
|
+
for (const entry of names) {
|
|
513
|
+
const full = path.join(root, entry.name);
|
|
514
|
+
if (entry.isDirectory()) walkFiles(full, visit);
|
|
515
|
+
else if (entry.isFile()) visit(full);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Read the CLI transcript of THIS run and report only what the evidence
|
|
520
|
+
// layers need: whether the request that carried the round token also carried
|
|
521
|
+
// the unique convention, and which model the vendor returned. The transcript
|
|
522
|
+
// itself is never copied anywhere.
|
|
523
|
+
function scanClaudeTranscript(roots, { claudeSessionId, token, marker }) {
|
|
524
|
+
const files = [];
|
|
525
|
+
const userMessages = [];
|
|
526
|
+
const assistantModels = new Set();
|
|
527
|
+
let assistantCount = 0;
|
|
528
|
+
for (const root of roots) {
|
|
529
|
+
walkFiles(root, file => {
|
|
530
|
+
if (!file.endsWith('.jsonl')) return;
|
|
531
|
+
let text;
|
|
532
|
+
try { text = fs.readFileSync(file, 'utf8'); } catch { return; }
|
|
533
|
+
if (claudeSessionId && !text.includes(claudeSessionId)) return;
|
|
534
|
+
files.push(path.basename(file));
|
|
535
|
+
for (const line of text.split(/\r?\n/)) {
|
|
536
|
+
let entry;
|
|
537
|
+
try { entry = JSON.parse(line); } catch { continue; }
|
|
538
|
+
const sessionMatches = !claudeSessionId || entry.sessionId === claudeSessionId;
|
|
539
|
+
if (entry.type === 'user' && entry.message && sessionMatches) {
|
|
540
|
+
const content = Array.isArray(entry.message.content) ? entry.message.content : [];
|
|
541
|
+
const text_ = content.map(block => (block && typeof block.text === 'string' ? block.text : '')).join('\n');
|
|
542
|
+
if (!text_) continue;
|
|
543
|
+
const markerAt = marker ? text_.indexOf(marker) : -1;
|
|
544
|
+
userMessages.push({
|
|
545
|
+
sessionId: entry.sessionId || null,
|
|
546
|
+
hasToken: token ? text_.includes(token) : null,
|
|
547
|
+
hasMarker: marker ? markerAt >= 0 : null,
|
|
548
|
+
hasKnowledgeContext: text_.includes('<knowledge_context>'),
|
|
549
|
+
length: text_.length,
|
|
550
|
+
markerExcerpt: markerAt >= 0 ? text_.slice(Math.max(0, markerAt - 120), markerAt + 260) : null,
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
if (entry.type === 'assistant' && entry.message && sessionMatches) {
|
|
554
|
+
assistantCount += 1;
|
|
555
|
+
if (typeof entry.message.model === 'string' && entry.message.model) assistantModels.add(entry.message.model);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
return {
|
|
561
|
+
transcriptFiles: files,
|
|
562
|
+
userMessages,
|
|
563
|
+
assistantCount,
|
|
564
|
+
assistantModelValues: [...assistantModels],
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
async function getJson(url, options) {
|
|
569
|
+
const response = await fetch(url, { ...options, signal: AbortSignal.timeout(30000) });
|
|
570
|
+
const body = await response.json().catch(() => null);
|
|
571
|
+
return { status: response.status, ok: response.ok, body };
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// Consume the Workbench session event stream until the terminal event arrives.
|
|
575
|
+
async function consumeSessionEvents(url, onEvent, until, timeoutMs) {
|
|
576
|
+
const controller = new AbortController();
|
|
577
|
+
const timer = setTimeout(() => controller.abort(new Error(`event stream timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
578
|
+
let done = null;
|
|
579
|
+
const finished = new Promise(resolve => { done = resolve; });
|
|
580
|
+
(async () => {
|
|
581
|
+
try {
|
|
582
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
583
|
+
if (!response.ok) throw new Error(`event stream HTTP ${response.status}`);
|
|
584
|
+
const reader = response.body.getReader();
|
|
585
|
+
const decoder = new TextDecoder();
|
|
586
|
+
let buffer = '';
|
|
587
|
+
for (;;) {
|
|
588
|
+
const { value, done: streamDone } = await reader.read();
|
|
589
|
+
if (streamDone) break;
|
|
590
|
+
buffer += decoder.decode(value, { stream: true });
|
|
591
|
+
let index;
|
|
592
|
+
while ((index = buffer.indexOf('\n')) >= 0) {
|
|
593
|
+
const line = buffer.slice(0, index).replace(/\r$/, '');
|
|
594
|
+
buffer = buffer.slice(index + 1);
|
|
595
|
+
if (!line.startsWith('data:')) continue;
|
|
596
|
+
const payload = line.slice(5).trim();
|
|
597
|
+
if (!payload) continue;
|
|
598
|
+
let event;
|
|
599
|
+
try { event = JSON.parse(payload); } catch { continue; }
|
|
600
|
+
try { onEvent(event); } catch { /* listener errors never kill the stream */ }
|
|
601
|
+
if (until(event)) { controller.abort(); return; }
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
} catch { /* aborted or ended */ }
|
|
605
|
+
finally { done && done(); }
|
|
606
|
+
})();
|
|
607
|
+
await finished;
|
|
608
|
+
clearTimeout(timer);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// One real turn against the hosted Workbench module.
|
|
612
|
+
//
|
|
613
|
+
// sessionInputOrigin is what the real client sends when it creates a session
|
|
614
|
+
// (packages/client: opts.inputOrigin || 'human'). It is OMITTED when the
|
|
615
|
+
// caller did not declare one, exactly like the module's own dispatcher child.
|
|
616
|
+
// inputOptions is the option object the input endpoint receives; the module's
|
|
617
|
+
// dispatcher passes { inputOrigin: 'agent-delegation', permissionMode, effort }.
|
|
618
|
+
async function runWorkbenchTurn({
|
|
619
|
+
base, profileId, model, effort, workspaceRef, contextId, question,
|
|
620
|
+
sessionInputOrigin, inputOptions, timeoutMs = 420000,
|
|
621
|
+
}) {
|
|
622
|
+
const sessionBody = {
|
|
623
|
+
context: { contextId, workspaceRef },
|
|
624
|
+
aiProfileId: profileId,
|
|
625
|
+
model,
|
|
626
|
+
effort,
|
|
627
|
+
};
|
|
628
|
+
if (sessionInputOrigin !== undefined) sessionBody.inputOrigin = sessionInputOrigin;
|
|
629
|
+
const session = await getJson(`${base}/api/claude-workbench/v1/sessions`, {
|
|
630
|
+
method: 'POST',
|
|
631
|
+
headers: { 'Content-Type': 'application/json' },
|
|
632
|
+
body: JSON.stringify(sessionBody),
|
|
633
|
+
});
|
|
634
|
+
if (session.status !== 201) throw Object.assign(new Error(`the session was not created: HTTP ${session.status} ${JSON.stringify(session.body)}`), { status: session.status });
|
|
635
|
+
const sessionId = session.body.session.sessionId;
|
|
636
|
+
|
|
637
|
+
const events = [];
|
|
638
|
+
// The CLI's own stderr (provider refusals, 429s, crashes) arrives as
|
|
639
|
+
// claude/stderr events. They are collected separately so a failed turn can
|
|
640
|
+
// report the REAL provider error instead of "isError with no diagnostics".
|
|
641
|
+
const stderrEvents = [];
|
|
642
|
+
const isTerminal = event => event.type === 'claude/result';
|
|
643
|
+
const streamUrl = `${base}/api/claude-workbench/v1/sessions/${encodeURIComponent(sessionId)}/events`;
|
|
644
|
+
const consume = consumeSessionEvents(streamUrl, event => {
|
|
645
|
+
if (event.type === 'claude/stderr') { stderrEvents.push(String(event.text || event.message || '')); return; }
|
|
646
|
+
if (['claude/init', 'claude/result', 'claude/error', 'claude/aborted'].includes(event.type)) events.push(event);
|
|
647
|
+
}, isTerminal, timeoutMs + 60000).catch(() => {});
|
|
648
|
+
|
|
649
|
+
const inputBody = { text: question };
|
|
650
|
+
if (inputOptions !== undefined) inputBody.options = inputOptions;
|
|
651
|
+
const send = await getJson(`${base}/api/claude-workbench/v1/sessions/${encodeURIComponent(sessionId)}/input`, {
|
|
652
|
+
method: 'POST',
|
|
653
|
+
headers: { 'Content-Type': 'application/json' },
|
|
654
|
+
body: JSON.stringify(inputBody),
|
|
655
|
+
});
|
|
656
|
+
if (send.status !== 202) {
|
|
657
|
+
await Promise.race([consume, new Promise(resolve => setTimeout(resolve, 2000))]);
|
|
658
|
+
throw Object.assign(new Error(`the input was not accepted: HTTP ${send.status} ${JSON.stringify(send.body)}`), { status: send.status });
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
const deadline = Date.now() + timeoutMs;
|
|
662
|
+
while (Date.now() < deadline && !events.some(isTerminal)) {
|
|
663
|
+
await new Promise(resolve => setTimeout(resolve, 250));
|
|
664
|
+
}
|
|
665
|
+
await Promise.race([consume, new Promise(resolve => setTimeout(resolve, 5000))]);
|
|
666
|
+
|
|
667
|
+
const init = events.find(event => event.type === 'claude/init') || null;
|
|
668
|
+
const result = events.find(event => event.type === 'claude/result') || null;
|
|
669
|
+
const error = events.find(event => event.type === 'claude/error') || null;
|
|
670
|
+
return {
|
|
671
|
+
sessionId,
|
|
672
|
+
events,
|
|
673
|
+
init,
|
|
674
|
+
result,
|
|
675
|
+
error,
|
|
676
|
+
stderrEvents,
|
|
677
|
+
claudeSessionId: init ? init.claudeSessionId : null,
|
|
678
|
+
sdkReportedModel: init ? init.model : null,
|
|
679
|
+
answer: result ? String(result.result || '') : '',
|
|
680
|
+
isError: result ? result.isError === true : true,
|
|
681
|
+
usage: result && result.usage ? { inputTokens: result.usage.input_tokens, outputTokens: result.usage.output_tokens } : null,
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
async function eventually(fn, timeoutMs = 15000, intervalMs = 100) {
|
|
686
|
+
const until = Date.now() + timeoutMs;
|
|
687
|
+
let last;
|
|
688
|
+
while (Date.now() < until) {
|
|
689
|
+
try { last = await fn(); if (last) return last; } catch (error) { last = error.message; }
|
|
690
|
+
await new Promise(resolve => setTimeout(resolve, intervalMs));
|
|
691
|
+
}
|
|
692
|
+
return null;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
module.exports = {
|
|
696
|
+
chain,
|
|
697
|
+
REPO_ROOT,
|
|
698
|
+
ENGINE_ENTRY,
|
|
699
|
+
BRIDGE_CONSOLE_ENTRY,
|
|
700
|
+
FORBIDDEN_PORTS,
|
|
701
|
+
AMBIENT_MODULE_URLS,
|
|
702
|
+
AMBIENT_MODEL_ENV,
|
|
703
|
+
REAL_HOME,
|
|
704
|
+
REAL_USERPROFILE,
|
|
705
|
+
SNAPSHOT_SOURCES,
|
|
706
|
+
snapshotProvenance,
|
|
707
|
+
sha256File,
|
|
708
|
+
isInside,
|
|
709
|
+
resolveTempRoot,
|
|
710
|
+
makeTempDir,
|
|
711
|
+
removeTree,
|
|
712
|
+
removeTreeAsync,
|
|
713
|
+
freePort,
|
|
714
|
+
waitForHttp,
|
|
715
|
+
git,
|
|
716
|
+
makeGitRepo,
|
|
717
|
+
sanitizedEnv,
|
|
718
|
+
spawnNode,
|
|
719
|
+
createIsolationLayout,
|
|
720
|
+
hostEnv,
|
|
721
|
+
realWorkbenchProfileDir,
|
|
722
|
+
digestDirectory,
|
|
723
|
+
compareDigests,
|
|
724
|
+
createReadOnlyProfileStore,
|
|
725
|
+
resolveWorkbenchModuleRoot,
|
|
726
|
+
packageIdentity,
|
|
727
|
+
startRecordingProxy,
|
|
728
|
+
startVectorHubStandIn,
|
|
729
|
+
startRealEngine,
|
|
730
|
+
startBridgeConsole,
|
|
731
|
+
resolveRepoIdentity,
|
|
732
|
+
scanClaudeTranscript,
|
|
733
|
+
getJson,
|
|
734
|
+
consumeSessionEvents,
|
|
735
|
+
runWorkbenchTurn,
|
|
736
|
+
eventually,
|
|
737
|
+
};
|