@sanqianx/project-knowledge 5.0.23 → 5.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/plugins/marketplace.json +20 -20
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +1361 -1346
- package/LICENSE +201 -201
- package/NOTICE +5 -5
- package/README.md +349 -349
- package/_modules/knowledge-engine/package.json +1 -1
- package/_modules/knowledge-engine/src/coordinator.js +48 -3
- package/_modules/knowledge-engine/src/runtime/automation-config.js +140 -140
- package/_modules/knowledge-engine/src/runtime/commit-conversation-binder.js +238 -238
- package/_modules/knowledge-engine/src/runtime/commit-processing-ledger.js +26 -26
- package/_modules/knowledge-engine/src/runtime/commit-prompt.js +193 -193
- package/_modules/knowledge-engine/src/runtime/commit-reconciler.js +394 -394
- package/_modules/knowledge-engine/src/runtime/contracts.js +282 -282
- package/_modules/knowledge-engine/src/runtime/conversation-store.js +389 -389
- package/_modules/knowledge-engine/src/runtime/evidence-bundle.js +228 -228
- package/_modules/knowledge-engine/src/runtime/git-runner.js +62 -62
- package/_modules/knowledge-engine/src/runtime/knowledge-promotion.js +505 -505
- package/_modules/knowledge-engine/src/runtime/knowledge-retrieval-service.js +400 -400
- package/_modules/knowledge-engine/src/runtime/markdown-knowledge-indexer.js +171 -171
- package/_modules/knowledge-engine/src/runtime/scanner.js +298 -298
- package/_modules/knowledge-engine/ui/app.js +23 -2
- package/_site/README.md +30 -30
- package/_site/_test/agent-capture-mcp-ui-test.js +68 -68
- package/_site/_test/agent-capture-ui-test.js +101 -101
- package/_site/_test/ai-profile-resolver-test.js +137 -137
- package/_site/_test/ai-profile-test.js +75 -75
- package/_site/_test/ai-vendor-presets-test.js +91 -91
- package/_site/_test/automatic-context-test.js +70 -70
- package/_site/_test/automation-queue-test.js +14 -14
- package/_site/_test/automation-ui-test.js +40 -40
- package/_site/_test/background-task-registry-test.js +43 -43
- package/_site/_test/baseline-schema-test.js +91 -91
- package/_site/_test/bin-cli-test.js +230 -230
- package/_site/_test/bridge-adapter-test.js +95 -95
- package/_site/_test/bridge-consumer-service-test.js +310 -310
- package/_site/_test/candidate-bin-content-test.js +35 -35
- package/_site/_test/candidate-product-assets-test.js +13 -13
- package/_site/_test/candidate-release-contract-test.js +14 -14
- package/_site/_test/capture-hook-dedup-test.js +158 -158
- package/_site/_test/cdp-browser-failure-test.js +103 -103
- package/_site/_test/chat-claudecodeui-match-test.js +92 -92
- package/_site/_test/claude-executable-discovery-test.js +90 -90
- package/_site/_test/claude-session-lifecycle-sweep-test.js +252 -252
- package/_site/_test/claude-workbench-test.js +174 -174
- package/_site/_test/cli-instance-management-test.js +62 -62
- package/_site/_test/client-capture-restart-e2e-test.js +189 -189
- package/_site/_test/codex-conversation-projection-test.js +60 -60
- package/_site/_test/codex-marketplace-scoped-path-test.js +186 -186
- package/_site/_test/codex-notify-capture-e2e-test.js +101 -101
- package/_site/_test/codex-notify-fanout-test.js +141 -134
- package/_site/_test/codex-notify-upgrade-test.js +253 -253
- package/_site/_test/commit-boundary-freeze-test.js +147 -147
- package/_site/_test/commit-conversation-binding-test.js +99 -99
- package/_site/_test/commit-evidence-test.js +110 -110
- package/_site/_test/configuration-generation-test.js +22 -22
- package/_site/_test/context-pack-test.js +200 -200
- package/_site/_test/conversation-api-test.js +119 -119
- package/_site/_test/conversation-origin-test.js +15 -15
- package/_site/_test/conversation-store-test.js +138 -138
- package/_site/_test/cross-repo-isolation-e2e-test.js +187 -187
- package/_site/_test/desktop-browser-compat-test.js +28 -28
- package/_site/_test/desktop-hook-runtime-regression-test.js +204 -204
- package/_site/_test/embedding-config-test.js +32 -32
- package/_site/_test/explicit-commit-processor-test.js +37 -37
- package/_site/_test/fixtures/fake-browser-exit.js +10 -10
- package/_site/_test/fixtures/fake-browser-hang.js +10 -10
- package/_site/_test/fixtures/integration-busy-worker.cjs +6 -6
- package/_site/_test/fixtures/make-git-repos.js +92 -92
- package/_site/_test/fixtures/retrieval-gold-queries.json +32 -32
- package/_site/_test/folder-picker-output-test.js +19 -19
- package/_site/_test/fresh-hook-reimport-test.js +53 -53
- package/_site/_test/fresh-product-data-test.js +56 -56
- package/_site/_test/full-integration-e2e-test.js +167 -167
- package/_site/_test/git-path-compatibility-test.js +80 -80
- package/_site/_test/git-validation-test.js +81 -81
- package/_site/_test/glm-ui-refresh-review-test.js +313 -404
- package/_site/_test/harness-isolation-test.js +138 -0
- package/_site/_test/helpers/cdp-browser.js +383 -0
- package/_site/_test/helpers/cdp-network-capture.js +66 -0
- package/_site/_test/helpers/find-chrome.js +34 -0
- package/_site/_test/helpers/free-port.js +8 -0
- package/_site/_test/helpers/logging-ui-fixture.js +131 -0
- package/_site/_test/helpers/module-fixture.js +282 -0
- package/_site/_test/helpers/parallel-engine-advanced-engine-child.js +45 -0
- package/_site/_test/helpers/parallel-engine-advanced-fault-writer.js +171 -0
- package/_site/_test/helpers/parallel-engine-advanced-harness.js +245 -0
- package/_site/_test/helpers/parallel-engine-advanced-standin-analyzer.js +80 -0
- package/_site/_test/helpers/parallel-engine-advanced-ui-host.js +177 -0
- package/_site/_test/helpers/parallel-engine-final-harness.js +314 -0
- package/_site/_test/helpers/parallel-engine-final-standin-analyzer.js +159 -0
- package/_site/_test/helpers/parallel-knowledge-fixture.js +255 -0
- package/_site/_test/helpers/parallel-logging-acceptance-fixture.js +111 -0
- package/_site/_test/helpers/parallel-logging-acceptance-proxy.js +106 -0
- package/_site/_test/helpers/parallel-logging-fix-r2-proxy.js +205 -0
- package/_site/_test/helpers/parallel-logging-integration-5025-env.js +432 -0
- package/_site/_test/helpers/parallel-memory-analyzer.js +81 -0
- package/_site/_test/helpers/parallel-memory-event-bridge.js +128 -0
- package/_site/_test/helpers/parallel-memory-shell.js +470 -0
- package/_site/_test/helpers/parallel-nav-isolation-env.js +389 -0
- package/_site/_test/helpers/parallel-nav-module-ui.js +186 -0
- package/_site/_test/helpers/parallel-nav-proxy.js +148 -0
- package/_site/_test/helpers/parallel-nav-shell.js +361 -0
- package/_site/_test/helpers/parallel-qa-engine-endpoint-guard.js +206 -0
- package/_site/_test/helpers/parallel-qa-engine-endpoint-isolate.js +257 -0
- package/_site/_test/helpers/parallel-retrieval-followup-corpus.js +293 -0
- package/_site/_test/helpers/parallel-retrieval-followup-next-session.js +70 -0
- package/_site/_test/helpers/parallel-retrieval-followup-r2-shell.js +737 -0
- package/_site/_test/helpers/parallel-retrieval-followup-r2-wb-host.js +82 -0
- package/_site/_test/helpers/parallel-retrieval-followup-shell.js +279 -0
- package/_site/_test/helpers/parallel-workbench-fixture.js +371 -0
- package/_site/_test/helpers/parallel-workbench-host.js +80 -0
- package/_site/_test/helpers/parallel-workbench-integration-5025-fixture.js +408 -0
- package/_site/_test/helpers/parallel-workbench-integration-5025-harness.js +593 -0
- package/_site/_test/helpers/parallel-workbench-integration-5025-host.js +70 -0
- package/_site/_test/helpers/parallel-workbench-integration-5025-launcher.js +240 -0
- package/_site/_test/helpers/parallel-workbench-integration-5025-runtime-harness.js +630 -0
- package/_site/_test/helpers/parallel-workbench-source-map.js +196 -0
- package/_site/_test/helpers/spawn-server.js +106 -0
- package/_site/_test/helpers/version-visibility-fixture.js +251 -0
- package/_site/_test/hook-runtime-endpoint-test.js +88 -88
- package/_site/_test/hook-status-repair-api-test.js +152 -152
- package/_site/_test/hook-trigger-test.js +85 -85
- package/_site/_test/hook-worktree-test.js +42 -42
- package/_site/_test/import-preflight-api-test.js +234 -234
- package/_site/_test/index-builder-test.js +41 -41
- package/_site/_test/index-error-display-contract-test.js +10 -10
- package/_site/_test/index-writer-concurrency-test.js +135 -135
- package/_site/_test/integration-adapters-test.js +262 -262
- package/_site/_test/integration-auto-repair-test.js +113 -113
- package/_site/_test/integration-capture-setup-test.js +118 -118
- package/_site/_test/integration-intent-test.js +81 -81
- package/_site/_test/integration-runtime-binding-a2-test.js +566 -566
- package/_site/_test/integration-runtime-binding-a3-test.js +227 -227
- package/_site/_test/integration-runtime-binding-test.js +473 -473
- package/_site/_test/integration-status-scan-test.js +29 -29
- package/_site/_test/integration-surface-coverage-test.js +164 -164
- package/_site/_test/kb-framework-test.js +57 -57
- package/_site/_test/kbpath-follow-test.js +63 -63
- package/_site/_test/knowledge-db-test.js +144 -144
- package/_site/_test/knowledge-engine-client-test.js +120 -109
- package/_site/_test/knowledge-language-control-test.js +170 -170
- package/_site/_test/knowledge-maintenance-test.js +40 -40
- package/_site/_test/knowledge-promotion-recovery-test.js +260 -260
- package/_site/_test/knowledge-query-test.js +54 -54
- package/_site/_test/knowledge-retrieval-service-test.js +77 -77
- package/_site/_test/knowledge-scopes-test.js +37 -37
- package/_site/_test/knowledge-storage-location-test.js +28 -28
- package/_site/_test/knowledge-storage-startup-test.js +52 -52
- package/_site/_test/knowledge-store-logs-supervision-test.js +89 -89
- package/_site/_test/launcher-readiness-test.js +80 -80
- package/_site/_test/legacy-claude-session-alias-test.js +106 -106
- package/_site/_test/legacy-routes-removed-test.js +47 -47
- package/_site/_test/legacy-workbench-exclusion-test.js +92 -92
- package/_site/_test/live-gateway-test.js +48 -48
- package/_site/_test/local-marketplace-test.js +16 -16
- package/_site/_test/log-redaction-test.js +58 -58
- package/_site/_test/logging-api-test.js +89 -89
- package/_site/_test/logging-sse-no-gap-test.js +88 -88
- package/_site/_test/logging-ui-test.js +107 -107
- package/_site/_test/markdown-delta-overlay-test.js +85 -85
- package/_site/_test/markdown-maintenance-api-test.js +75 -75
- package/_site/_test/markdown-maintenance-test.js +11 -11
- package/_site/_test/mcp-server-test.js +149 -149
- package/_site/_test/model-context-windows-test.js +89 -89
- package/_site/_test/module-agent-start-proxy-test.js +65 -65
- package/_site/_test/module-artifact-integrity-test.js +27 -27
- package/_site/_test/module-boundary-test.js +30 -30
- package/_site/_test/module-bridge-eventbridge-test.js +202 -202
- package/_site/_test/module-dynamic-port-test.js +118 -118
- package/_site/_test/module-index-proxy-test.js +33 -33
- package/_site/_test/module-model-configuration-test.js +44 -44
- package/_site/_test/module-process-lifecycle-test.js +35 -35
- package/_site/_test/module-stream-proxy-test.js +34 -34
- package/_site/_test/module-terminal-restart-test.js +63 -63
- package/_site/_test/module-wiring-unbind-race-test.js +59 -59
- package/_site/_test/native-context-integrations-test.js +86 -86
- package/_site/_test/non-release-ci-test.js +34 -34
- package/_site/_test/offline-boundary-isolation-test.js +32 -32
- package/_site/_test/orphaned-claim-recovery-test.js +80 -80
- package/_site/_test/package-boundary-test.js +43 -43
- package/_site/_test/package-startup-test.js +56 -56
- package/_site/_test/packaged-ui-smoke-test.js +88 -88
- package/_site/_test/parallel-ci-r9-posix-socket-budget-test.js +156 -0
- package/_site/_test/parallel-engine-advanced-eng005-test.js +136 -0
- package/_site/_test/parallel-engine-advanced-eng006-test.js +171 -0
- package/_site/_test/parallel-engine-advanced-eng007-reconcile-test.js +231 -0
- package/_site/_test/parallel-engine-advanced-eng009-test.js +208 -0
- package/_site/_test/parallel-engine-advanced-eng010-test.js +213 -0
- package/_site/_test/parallel-engine-advanced-eng011-ui-probe.js +459 -0
- package/_site/_test/parallel-engine-final-eng002-test.js +255 -0
- package/_site/_test/parallel-engine-final-eng007-test.js +269 -0
- package/_site/_test/parallel-engine-final-eng011-test.js +197 -0
- package/_site/_test/parallel-engine-final-eng012-test.js +354 -0
- package/_site/_test/parallel-knowledge-client-error-code-test.js +184 -0
- package/_site/_test/parallel-knowledge-engine-test.js +353 -0
- package/_site/_test/parallel-knowledge-retrieval-test.js +292 -0
- package/_site/_test/parallel-knowledge-vector-test.js +168 -0
- package/_site/_test/parallel-linux-ci-r7-log007-day-test.js +110 -0
- package/_site/_test/parallel-logging-acceptance-log003-test.js +224 -0
- package/_site/_test/parallel-logging-acceptance-log004-test.js +231 -0
- package/_site/_test/parallel-logging-acceptance-log005-test.js +208 -0
- package/_site/_test/parallel-logging-acceptance-log006-test.js +214 -0
- package/_site/_test/parallel-logging-acceptance-log007-test.js +223 -0
- package/_site/_test/parallel-logging-acceptance-log008-test.js +180 -0
- package/_site/_test/parallel-logging-fix-r2-crash-probe.js +271 -0
- package/_site/_test/parallel-logging-fix-r2-gap-test.js +294 -0
- package/_site/_test/parallel-logging-fix-r2-normalhook-test.js +330 -0
- package/_site/_test/parallel-logging-integration-5025-portability-test.js +554 -0
- package/_site/_test/parallel-memory-candidate-test.js +301 -0
- package/_site/_test/parallel-memory-manual-test.js +197 -0
- package/_site/_test/parallel-memory-scope-test.js +228 -0
- package/_site/_test/parallel-memory-source-test.js +227 -0
- package/_site/_test/parallel-memory-sync-test.js +238 -0
- package/_site/_test/parallel-memory-view-r8-reload-gate-test.js +123 -0
- package/_site/_test/parallel-nav-failure-test.js +119 -0
- package/_site/_test/parallel-nav-isolation-test.js +308 -0
- package/_site/_test/parallel-nav-isolation-vector-path-test.js +90 -0
- package/_site/_test/parallel-nav-offline-test.js +272 -0
- package/_site/_test/parallel-nav-operability-test.js +257 -0
- package/_site/_test/parallel-nav-switch-test.js +247 -0
- package/_site/_test/parallel-nav-theme-test.js +130 -0
- package/_site/_test/parallel-nav-viewport-test.js +310 -0
- package/_site/_test/parallel-qa-engine-endpoint-guard-test.js +273 -0
- package/_site/_test/parallel-retrieval-followup-citation-test.js +219 -0
- package/_site/_test/parallel-retrieval-followup-corpus-test.js +287 -0
- package/_site/_test/parallel-workbench-independent-host.js +262 -0
- package/_site/_test/parallel-workbench-integration-5025-abort-probe.js +340 -0
- package/_site/_test/parallel-workbench-integration-5025-drafts-probe.js +588 -0
- package/_site/_test/parallel-workbench-integration-5025-env-check.js +317 -0
- package/_site/_test/parallel-workbench-integration-5025-model-probe.js +342 -0
- package/_site/_test/parallel-workbench-integration-5025-ordering-probe.js +326 -0
- package/_site/_test/parallel-workbench-model-probe.js +336 -0
- package/_site/_test/parallel-workbench-offline-test.js +169 -0
- package/_site/_test/parallel-workbench-provenance-trace.js +134 -0
- package/_site/_test/parallel-workbench-source-match.js +206 -0
- package/_site/_test/parallel-workbench-standalone-turn.js +349 -0
- package/_site/_test/path-consistency-test.js +151 -151
- package/_site/_test/pending-sweep-test.js +9 -9
- package/_site/_test/post-commit-automation-test.js +87 -87
- package/_site/_test/pr-consumer-contract-test.js +55 -55
- package/_site/_test/product-brand-contract-test.js +25 -25
- package/_site/_test/product-diagnostics-ui-test.js +93 -93
- package/_site/_test/product-empty-state-test.js +148 -0
- package/_site/_test/product-import-ui-test.js +219 -104
- package/_site/_test/product-navigation-test.js +152 -0
- package/_site/_test/product-progress-status-test.js +84 -84
- package/_site/_test/project-delete-recovery-test.js +64 -64
- package/_site/_test/project-domain-create-test.js +91 -0
- package/_site/_test/project-domain-scope-retrieval-test.js +214 -0
- package/_site/_test/project-git-init-confirm-test.js +115 -0
- package/_site/_test/project-goal-editor-test.js +144 -144
- package/_site/_test/project-import-duplicate-alias-test.js +134 -0
- package/_site/_test/project-import-unicode-restart-test.js +140 -0
- package/_site/_test/project-lifecycle-transaction-test.js +106 -106
- package/_site/_test/project-module-partial-recovery-test.js +222 -0
- package/_site/_test/project-remove-running-guard-test.js +79 -79
- package/_site/_test/project-store-test.js +90 -90
- package/_site/_test/project-unbind-late-read-ui-test.js +250 -0
- package/_site/_test/project-unbind-writer-guard-test.js +231 -0
- package/_site/_test/prompt-settings-test.js +115 -115
- package/_site/_test/protected-architecture-gate-test.js +122 -122
- package/_site/_test/refactor-characterization-test.js +36 -36
- package/_site/_test/registry-events-test.js +38 -38
- package/_site/_test/release-version-sync-test.js +115 -115
- package/_site/_test/requirement-binding-test.js +113 -113
- package/_site/_test/requirement-recorder-test.js +173 -173
- package/_site/_test/run-all-tests.js +173 -161
- package/_site/_test/runtime-endpoint-test.js +64 -64
- package/_site/_test/scanner-test.js +83 -83
- package/_site/_test/server-security-test.js +96 -96
- package/_site/_test/sessions-stream-test.js +93 -93
- package/_site/_test/shared-contracts-test.js +58 -58
- package/_site/_test/shared-scope-root-binding-test.js +74 -67
- package/_site/_test/simple-import-test.js +98 -98
- package/_site/_test/startup-analysis-disabled-test.js +16 -16
- package/_site/_test/storage-foundation-test.js +78 -78
- package/_site/_test/structured-logger-test.js +101 -101
- package/_site/_test/t07b-cln-005-coverage-test.js +212 -0
- package/_site/_test/team-knowledge-store-sparse-checkout-test.js +196 -196
- package/_site/_test/team-knowledge-store-test.js +132 -132
- package/_site/_test/test-server-cleanup-test.js +35 -35
- package/_site/_test/test-server-module-isolation-test.js +37 -37
- package/_site/_test/tracking-start-test.js +144 -144
- package/_site/_test/vector-storage-root-test.js +75 -75
- package/_site/_test/version-visibility-browser-probe.js +249 -0
- package/_site/_test/version-visibility-test.js +92 -0
- package/_site/_test/workbench-context-receipts-test.js +22 -22
- package/_site/_test/workbench-permission-test.js +117 -117
- package/_site/_test/zcode-capture-integration-test.js +112 -112
- package/_site/lib/ai-profile-resolver.js +78 -78
- package/_site/lib/ai-vendor-presets.js +83 -83
- package/_site/lib/ai-workspace.js +104 -104
- package/_site/lib/atomic-file.js +204 -204
- package/_site/lib/automation-config.js +140 -140
- package/_site/lib/bridge-adapter.js +260 -260
- package/_site/lib/bridge-consumer-service.js +402 -402
- package/_site/lib/capture-hook-config.js +108 -108
- package/_site/lib/claude-cli-runner.js +1599 -1599
- package/_site/lib/cli-instances.js +43 -43
- package/_site/lib/codex-context-status.js +17 -17
- package/_site/lib/codex-notify-config.js +193 -193
- package/_site/lib/commit-conversation-binder.js +247 -247
- package/_site/lib/commit-processing-ledger.js +27 -27
- package/_site/lib/commit-prompt.js +202 -202
- package/_site/lib/commit-reconciler.js +444 -444
- package/_site/lib/context-pack-builder.js +299 -299
- package/_site/lib/contracts.js +291 -291
- package/_site/lib/conversation-exclusions.js +204 -204
- package/_site/lib/conversation-query-service.js +161 -161
- package/_site/lib/conversation-store.js +387 -387
- package/_site/lib/data-dir.js +13 -13
- package/_site/lib/embedding-service.js +85 -85
- package/_site/lib/engine-connection.js +93 -93
- package/_site/lib/engine-knowledge-client.js +76 -72
- package/_site/lib/evidence-bundle.js +228 -228
- package/_site/lib/folder-picker-output.js +24 -24
- package/_site/lib/git-path.js +14 -14
- package/_site/lib/git-runner.js +62 -62
- package/_site/lib/github-team-store.js +1175 -1175
- package/_site/lib/hook-manager.js +203 -203
- package/_site/lib/index-builder.js +157 -157
- package/_site/lib/index-service.js +173 -173
- package/_site/lib/integration-auto-repair.js +77 -77
- package/_site/lib/integration-installer.js +1240 -1240
- package/_site/lib/integration-intent.js +88 -88
- package/_site/lib/integration-status-scan.js +99 -99
- package/_site/lib/integration-status-worker.js +14 -14
- package/_site/lib/kb-framework.js +191 -191
- package/_site/lib/kb-validator.js +124 -124
- package/_site/lib/knowledge-db.js +363 -363
- package/_site/lib/knowledge-promotion.js +435 -435
- package/_site/lib/knowledge-retrieval-service.js +401 -401
- package/_site/lib/knowledge-schema.js +121 -121
- package/_site/lib/knowledge-tool-runtime.js +366 -366
- package/_site/lib/live-gateway.js +78 -78
- package/_site/lib/llm-client.js +173 -173
- package/_site/lib/markdown-knowledge-indexer.js +230 -230
- package/_site/lib/model-context-windows.js +82 -82
- package/_site/lib/module-bridge.js +874 -874
- package/_site/lib/module-port-resolver.js +57 -57
- package/_site/lib/post-commit-automation.js +141 -141
- package/_site/lib/product-data.js +35 -35
- package/_site/lib/project-lifecycle-service.js +554 -554
- package/_site/lib/project-registry-store.js +129 -129
- package/_site/lib/project-store.js +268 -268
- package/_site/lib/prompt-registry.js +148 -148
- package/_site/lib/public-version-info.js +37 -0
- package/_site/lib/registry-events.js +16 -16
- package/_site/lib/requirement-adapters.js +10 -10
- package/_site/lib/requirement-binder.js +112 -112
- package/_site/lib/requirement-recorder.js +278 -278
- package/_site/lib/runtime-control.js +89 -89
- package/_site/lib/runtime-endpoint.js +160 -160
- package/_site/lib/scanner.js +298 -298
- package/_site/lib/server-app.js +1672 -1664
- package/_site/lib/settings-store.js +153 -153
- package/_site/lib/storage-layout.js +166 -166
- package/_site/lib/structured-logger.js +574 -574
- package/_site/lib/zcode-context-integration.js +60 -60
- package/_site/scripts/codex-notify-fanout.cjs +95 -95
- package/_site/scripts/folder-picker.ps1 +156 -156
- package/_site/scripts/hook-trigger.js +158 -158
- package/_site/scripts/install-module-candidates.js +69 -69
- package/_site/scripts/pack-module-candidates.js +89 -89
- package/_site/scripts/sync-product-content.js +28 -28
- package/_site/scripts/sync-release-version.js +164 -164
- package/_site/scripts/vendor-modules.js +49 -49
- package/_site/scripts/verify-module-runtime.js +50 -50
- package/_site/scripts/verify-product-runtime.js +36 -36
- package/_site/scripts/verify-retrieval-gold.js +83 -83
- package/_site/server.js +15 -15
- package/_site/start.bat +26 -26
- package/_site/stop.bat +11 -11
- package/bin/project-knowledge-integrations.js +254 -254
- package/bin/project-knowledge-kb.js +67 -67
- package/bin/project-knowledge-mcp.js +201 -201
- package/bin/project-knowledge.js +269 -170
- package/claude-prompts.json +21 -21
- package/docs/README.zh-CN.md +207 -205
- package/docs/assets/architecture.svg +181 -181
- package/docs/assets/logo.svg +49 -49
- package/docs/fresh-v5-start.md +44 -44
- package/docs/leader-glm-workbench-playbook.md +122 -122
- package/docs/project-registry-schema.md +33 -33
- package/docs/release-5.0.16-acceptance.md +176 -176
- package/docs/release-5.0.17-acceptance.md +117 -117
- package/docs/release-5.0.19-acceptance.md +39 -39
- package/docs/team-knowledge-mode-a-plan.md +73 -73
- package/docs/testing-strategy.md +33 -33
- package/module-runtime-manifest.json +70 -67
- package/package.json +113 -110
- package/plugins/project-knowledge/.claude-plugin/plugin.json +1 -1
- package/plugins/project-knowledge/.codex-plugin/plugin.json +1 -1
- package/plugins/project-knowledge/.mcp.json +1 -1
- package/templates/change.md +30 -30
- package/templates/project-readme.md +52 -52
- package/ui/index.html +3 -2
- package/ui/version-info.css +44 -0
- package/ui/version-info.js +24 -0
- package/vendor-manifest.json +55 -55
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const fs = require('node:fs');
|
|
3
|
-
const path = require('node:path');
|
|
4
|
-
const os = require('node:os');
|
|
5
|
-
const crypto = require('node:crypto');
|
|
6
|
-
const { spawnSync } = require('node:child_process');
|
|
7
|
-
const AtomicFile = require('../lib/atomic-file');
|
|
8
|
-
const hash = bytes => crypto.createHash('sha256').update(bytes).digest('hex');
|
|
9
|
-
const root = path.resolve(__dirname, '../..');
|
|
10
|
-
const npmCli = process.env.npm_execpath || path.join(path.dirname(process.execPath), 'node_modules/npm/bin/npm-cli.js');
|
|
11
|
-
const definitions = {
|
|
12
|
-
terminal: { option: '--terminal-source', name: '@sanqianx/claude-ai-workbench', installName: 'claude-ai-workbench', required: ['apps/agent-terminal/app.js', 'apps/agent-terminal/app.css', 'packages/server/lib/knowledge-context.js'] },
|
|
13
|
-
vectorHub: { option: '--vector-source', name: '@sanqianx/vector-hub', installName: '@sanqianx/vector-hub', required: ['dist/cjs/bin.js', 'dist/cjs/server/manager.js', 'ui/index.html'] },
|
|
14
|
-
eventBridge: { option: '--bridge-source', name: '@sanqianx/ai-coding-event-bridge-console', installName: '@sanqianx/ai-coding-event-bridge-console', required: ['src/server.js', 'src/bridge/core/consumer-registry.js', 'console/index.html'] },
|
|
15
|
-
};
|
|
16
|
-
function run(command, args, cwd) {
|
|
17
|
-
const result = spawnSync(command, args, { cwd, windowsHide: true, encoding: 'utf8', maxBuffer: 16 * 1024 * 1024 });
|
|
18
|
-
if (result.status !== 0) throw new Error(`${path.basename(command)} failed (${result.status}): ${result.error?.message || result.stderr}`);
|
|
19
|
-
return result.stdout;
|
|
20
|
-
}
|
|
21
|
-
function safeRelative(file) { return typeof file === 'string' && !path.isAbsolute(file) && !/[\\\x00-\x1f]/.test(file) && !file.split('/').some(p => p === '..' || p === '.'); }
|
|
22
|
-
function installedFileBytes(pkg, relative, bytes) {
|
|
23
|
-
const bins = typeof pkg.bin === 'string' ? [pkg.bin] : Object.values(pkg.bin || {});
|
|
24
|
-
const isBin = bins.some(file => String(file).replace(/\\/g, '/').replace(/^\.\//, '') === relative);
|
|
25
|
-
// npm bin-links removes CRLF from the shebang only, on every platform.
|
|
26
|
-
// Hash the installed bytes; keep body line endings and ordinary files exact.
|
|
27
|
-
if (isBin && /^#![^\n]+\r\n/.test(bytes.subarray(0, 2048).toString('utf8'))) return Buffer.from(bytes.toString('utf8').replace(/^(#![^\n]+)\r\n/, '$1\n'));
|
|
28
|
-
return bytes;
|
|
29
|
-
}
|
|
30
|
-
function productFiles(directory) {
|
|
31
|
-
const previous = JSON.parse(fs.readFileSync(path.join(directory, 'module-runtime-manifest.json'), 'utf8'));
|
|
32
|
-
const files = new Set(['ui/index.html', 'ui/knowledge-panel.html', 'ui/product.js', 'ui/live-client.js', 'ui/product.css', 'ui/favicon.svg', ...Object.keys(previous.productFiles || {})]);
|
|
33
|
-
return Object.fromEntries([...files].map(file => {
|
|
34
|
-
if (!safeRelative(file)) throw new Error('Unsafe product asset path');
|
|
35
|
-
const target = path.join(directory, file);
|
|
36
|
-
if (fs.lstatSync(target).isSymbolicLink()) throw new Error('Symlink in product assets');
|
|
37
|
-
return [file, hash(fs.readFileSync(target))];
|
|
38
|
-
}));
|
|
39
|
-
}
|
|
40
|
-
function verifyInstalled(manifest, installedRoot) {
|
|
41
|
-
for (const [key, module] of Object.entries(manifest.modules)) {
|
|
42
|
-
const directory = path.join(installedRoot, 'node_modules', module.installName);
|
|
43
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(directory, 'package.json')));
|
|
44
|
-
if (pkg.name !== module.name || pkg.version !== module.version) throw new Error(`Installed module identity mismatch: ${key}`);
|
|
45
|
-
for (const [relative, expected] of Object.entries(module.files)) {
|
|
46
|
-
if (!safeRelative(relative)) throw new Error('Unsafe module manifest path');
|
|
47
|
-
const file = path.join(directory, relative);
|
|
48
|
-
if (fs.lstatSync(file).isSymbolicLink() || hash(fs.readFileSync(file)) !== expected) throw new Error(`Installed module is stale or altered: ${key}/${relative}`);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
function pack(sources) {
|
|
53
|
-
const output = fs.mkdtempSync(path.join(os.tmpdir(), 'kb-module-candidates-'));
|
|
54
|
-
const manifest = { schema: 'project-knowledge/module-candidates/v1', createdAt: new Date().toISOString(), modules: {} };
|
|
55
|
-
for (const [key, definition] of Object.entries(definitions)) {
|
|
56
|
-
const source = path.resolve(sources[key]);
|
|
57
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(source, 'package.json')));
|
|
58
|
-
if (pkg.name !== definition.name) throw new Error(`Unexpected source identity: ${key}`);
|
|
59
|
-
const expectedVersion = JSON.parse(fs.readFileSync(path.join(root, 'package.json'))).dependencies[definition.installName];
|
|
60
|
-
if (expectedVersion !== pkg.version && expectedVersion !== `npm:${pkg.name}@${pkg.version}`) throw new Error(`Source version is not pinned by the shell: ${key}`);
|
|
61
|
-
const result = JSON.parse(run(process.execPath, [npmCli, 'pack', '--ignore-scripts', '--json', '--pack-destination', output], source))[0];
|
|
62
|
-
const files = {};
|
|
63
|
-
for (const entry of result.files) {
|
|
64
|
-
if (!safeRelative(entry.path)) throw new Error('Unsafe npm package path');
|
|
65
|
-
const file = path.join(source, entry.path);
|
|
66
|
-
if (fs.lstatSync(file).isSymbolicLink()) throw new Error(`Symlink in module package: ${key}/${entry.path}`);
|
|
67
|
-
files[entry.path] = hash(installedFileBytes(pkg, entry.path, fs.readFileSync(file)));
|
|
68
|
-
}
|
|
69
|
-
if (definition.required.some(file => !files[file])) throw new Error(`Incomplete module runtime: ${key}`);
|
|
70
|
-
manifest.modules[key] = { name: pkg.name, installName: definition.installName, version: pkg.version, tarball: result.filename, sha256: hash(fs.readFileSync(path.join(output, result.filename))), files };
|
|
71
|
-
process.stdout.write(`Packed ${key} ${pkg.version}: ${result.files.length} files\n`);
|
|
72
|
-
}
|
|
73
|
-
const manifestPath = path.join(output, 'module-candidates.json'); AtomicFile.writeJsonAtomic(manifestPath, manifest);
|
|
74
|
-
AtomicFile.writeJsonAtomic(path.join(root, 'module-runtime-manifest.json'), { schema: 'project-knowledge/module-content/v1', productFiles: productFiles(root), modules: Object.fromEntries(Object.entries(manifest.modules).map(([key, module]) => [key, { name: module.name, installName: module.installName, version: module.version, files: module.files }])) });
|
|
75
|
-
process.stdout.write(`MODULE_CANDIDATES ${manifestPath}\n`);
|
|
76
|
-
return manifestPath;
|
|
77
|
-
}
|
|
78
|
-
if (require.main === module) {
|
|
79
|
-
try {
|
|
80
|
-
const at = process.argv.indexOf('--verify-installed');
|
|
81
|
-
if (at >= 0) { const manifest = JSON.parse(fs.readFileSync(process.argv[at + 1])); verifyInstalled(manifest, path.resolve(process.argv[at + 2])); process.stdout.write('Installed module bytes verified against candidate artifacts.\n'); }
|
|
82
|
-
else {
|
|
83
|
-
const sources = {};
|
|
84
|
-
for (const [key, d] of Object.entries(definitions)) { const i = process.argv.indexOf(d.option); if (i < 0 || !process.argv[i + 1]) throw new Error(`Explicit source required: ${d.option}`); sources[key] = process.argv[i + 1]; }
|
|
85
|
-
pack(sources);
|
|
86
|
-
}
|
|
87
|
-
} catch (error) { process.stderr.write(`${error.message}\n`); process.exitCode = 1; }
|
|
88
|
-
}
|
|
89
|
-
module.exports = { verifyInstalled, safeRelative, productFiles, installedFileBytes };
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('node:fs');
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const os = require('node:os');
|
|
5
|
+
const crypto = require('node:crypto');
|
|
6
|
+
const { spawnSync } = require('node:child_process');
|
|
7
|
+
const AtomicFile = require('../lib/atomic-file');
|
|
8
|
+
const hash = bytes => crypto.createHash('sha256').update(bytes).digest('hex');
|
|
9
|
+
const root = path.resolve(__dirname, '../..');
|
|
10
|
+
const npmCli = process.env.npm_execpath || path.join(path.dirname(process.execPath), 'node_modules/npm/bin/npm-cli.js');
|
|
11
|
+
const definitions = {
|
|
12
|
+
terminal: { option: '--terminal-source', name: '@sanqianx/claude-ai-workbench', installName: 'claude-ai-workbench', required: ['apps/agent-terminal/app.js', 'apps/agent-terminal/app.css', 'packages/server/lib/knowledge-context.js'] },
|
|
13
|
+
vectorHub: { option: '--vector-source', name: '@sanqianx/vector-hub', installName: '@sanqianx/vector-hub', required: ['dist/cjs/bin.js', 'dist/cjs/server/manager.js', 'ui/index.html'] },
|
|
14
|
+
eventBridge: { option: '--bridge-source', name: '@sanqianx/ai-coding-event-bridge-console', installName: '@sanqianx/ai-coding-event-bridge-console', required: ['src/server.js', 'src/bridge/core/consumer-registry.js', 'console/index.html'] },
|
|
15
|
+
};
|
|
16
|
+
function run(command, args, cwd) {
|
|
17
|
+
const result = spawnSync(command, args, { cwd, windowsHide: true, encoding: 'utf8', maxBuffer: 16 * 1024 * 1024 });
|
|
18
|
+
if (result.status !== 0) throw new Error(`${path.basename(command)} failed (${result.status}): ${result.error?.message || result.stderr}`);
|
|
19
|
+
return result.stdout;
|
|
20
|
+
}
|
|
21
|
+
function safeRelative(file) { return typeof file === 'string' && !path.isAbsolute(file) && !/[\\\x00-\x1f]/.test(file) && !file.split('/').some(p => p === '..' || p === '.'); }
|
|
22
|
+
function installedFileBytes(pkg, relative, bytes) {
|
|
23
|
+
const bins = typeof pkg.bin === 'string' ? [pkg.bin] : Object.values(pkg.bin || {});
|
|
24
|
+
const isBin = bins.some(file => String(file).replace(/\\/g, '/').replace(/^\.\//, '') === relative);
|
|
25
|
+
// npm bin-links removes CRLF from the shebang only, on every platform.
|
|
26
|
+
// Hash the installed bytes; keep body line endings and ordinary files exact.
|
|
27
|
+
if (isBin && /^#![^\n]+\r\n/.test(bytes.subarray(0, 2048).toString('utf8'))) return Buffer.from(bytes.toString('utf8').replace(/^(#![^\n]+)\r\n/, '$1\n'));
|
|
28
|
+
return bytes;
|
|
29
|
+
}
|
|
30
|
+
function productFiles(directory) {
|
|
31
|
+
const previous = JSON.parse(fs.readFileSync(path.join(directory, 'module-runtime-manifest.json'), 'utf8'));
|
|
32
|
+
const files = new Set(['ui/index.html', 'ui/knowledge-panel.html', 'ui/product.js', 'ui/live-client.js', 'ui/product.css', 'ui/favicon.svg', ...Object.keys(previous.productFiles || {})]);
|
|
33
|
+
return Object.fromEntries([...files].map(file => {
|
|
34
|
+
if (!safeRelative(file)) throw new Error('Unsafe product asset path');
|
|
35
|
+
const target = path.join(directory, file);
|
|
36
|
+
if (fs.lstatSync(target).isSymbolicLink()) throw new Error('Symlink in product assets');
|
|
37
|
+
return [file, hash(fs.readFileSync(target))];
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
function verifyInstalled(manifest, installedRoot) {
|
|
41
|
+
for (const [key, module] of Object.entries(manifest.modules)) {
|
|
42
|
+
const directory = path.join(installedRoot, 'node_modules', module.installName);
|
|
43
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(directory, 'package.json')));
|
|
44
|
+
if (pkg.name !== module.name || pkg.version !== module.version) throw new Error(`Installed module identity mismatch: ${key}`);
|
|
45
|
+
for (const [relative, expected] of Object.entries(module.files)) {
|
|
46
|
+
if (!safeRelative(relative)) throw new Error('Unsafe module manifest path');
|
|
47
|
+
const file = path.join(directory, relative);
|
|
48
|
+
if (fs.lstatSync(file).isSymbolicLink() || hash(fs.readFileSync(file)) !== expected) throw new Error(`Installed module is stale or altered: ${key}/${relative}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function pack(sources) {
|
|
53
|
+
const output = fs.mkdtempSync(path.join(os.tmpdir(), 'kb-module-candidates-'));
|
|
54
|
+
const manifest = { schema: 'project-knowledge/module-candidates/v1', createdAt: new Date().toISOString(), modules: {} };
|
|
55
|
+
for (const [key, definition] of Object.entries(definitions)) {
|
|
56
|
+
const source = path.resolve(sources[key]);
|
|
57
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(source, 'package.json')));
|
|
58
|
+
if (pkg.name !== definition.name) throw new Error(`Unexpected source identity: ${key}`);
|
|
59
|
+
const expectedVersion = JSON.parse(fs.readFileSync(path.join(root, 'package.json'))).dependencies[definition.installName];
|
|
60
|
+
if (expectedVersion !== pkg.version && expectedVersion !== `npm:${pkg.name}@${pkg.version}`) throw new Error(`Source version is not pinned by the shell: ${key}`);
|
|
61
|
+
const result = JSON.parse(run(process.execPath, [npmCli, 'pack', '--ignore-scripts', '--json', '--pack-destination', output], source))[0];
|
|
62
|
+
const files = {};
|
|
63
|
+
for (const entry of result.files) {
|
|
64
|
+
if (!safeRelative(entry.path)) throw new Error('Unsafe npm package path');
|
|
65
|
+
const file = path.join(source, entry.path);
|
|
66
|
+
if (fs.lstatSync(file).isSymbolicLink()) throw new Error(`Symlink in module package: ${key}/${entry.path}`);
|
|
67
|
+
files[entry.path] = hash(installedFileBytes(pkg, entry.path, fs.readFileSync(file)));
|
|
68
|
+
}
|
|
69
|
+
if (definition.required.some(file => !files[file])) throw new Error(`Incomplete module runtime: ${key}`);
|
|
70
|
+
manifest.modules[key] = { name: pkg.name, installName: definition.installName, version: pkg.version, tarball: result.filename, sha256: hash(fs.readFileSync(path.join(output, result.filename))), files };
|
|
71
|
+
process.stdout.write(`Packed ${key} ${pkg.version}: ${result.files.length} files\n`);
|
|
72
|
+
}
|
|
73
|
+
const manifestPath = path.join(output, 'module-candidates.json'); AtomicFile.writeJsonAtomic(manifestPath, manifest);
|
|
74
|
+
AtomicFile.writeJsonAtomic(path.join(root, 'module-runtime-manifest.json'), { schema: 'project-knowledge/module-content/v1', productFiles: productFiles(root), modules: Object.fromEntries(Object.entries(manifest.modules).map(([key, module]) => [key, { name: module.name, installName: module.installName, version: module.version, files: module.files }])) });
|
|
75
|
+
process.stdout.write(`MODULE_CANDIDATES ${manifestPath}\n`);
|
|
76
|
+
return manifestPath;
|
|
77
|
+
}
|
|
78
|
+
if (require.main === module) {
|
|
79
|
+
try {
|
|
80
|
+
const at = process.argv.indexOf('--verify-installed');
|
|
81
|
+
if (at >= 0) { const manifest = JSON.parse(fs.readFileSync(process.argv[at + 1])); verifyInstalled(manifest, path.resolve(process.argv[at + 2])); process.stdout.write('Installed module bytes verified against candidate artifacts.\n'); }
|
|
82
|
+
else {
|
|
83
|
+
const sources = {};
|
|
84
|
+
for (const [key, d] of Object.entries(definitions)) { const i = process.argv.indexOf(d.option); if (i < 0 || !process.argv[i + 1]) throw new Error(`Explicit source required: ${d.option}`); sources[key] = process.argv[i + 1]; }
|
|
85
|
+
pack(sources);
|
|
86
|
+
}
|
|
87
|
+
} catch (error) { process.stderr.write(`${error.message}\n`); process.exitCode = 1; }
|
|
88
|
+
}
|
|
89
|
+
module.exports = { verifyInstalled, safeRelative, productFiles, installedFileBytes };
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const fs = require('node:fs');
|
|
3
|
-
const path = require('node:path');
|
|
4
|
-
const crypto = require('node:crypto');
|
|
5
|
-
const { createRequire } = require('node:module');
|
|
6
|
-
const { execFileSync } = require('node:child_process');
|
|
7
|
-
const { safeRelative } = require('./pack-module-candidates');
|
|
8
|
-
const AtomicFile = require('../lib/atomic-file');
|
|
9
|
-
const root = path.resolve(__dirname, '../..');
|
|
10
|
-
const file = path.join(root, 'module-runtime-manifest.json');
|
|
11
|
-
const manifest = JSON.parse(fs.readFileSync(file));
|
|
12
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json')));
|
|
13
|
-
const resolve = createRequire(path.join(root, 'package.json'));
|
|
14
|
-
const digest = file => crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
|
|
15
|
-
for (const module of Object.values(manifest.modules)) {
|
|
16
|
-
const directory = path.dirname(resolve.resolve(`${module.installName}/package.json`));
|
|
17
|
-
if (!directory.startsWith(path.join(root, 'node_modules') + path.sep)) throw new Error('Module must resolve inside this installed dependency tree.');
|
|
18
|
-
const installed = JSON.parse(fs.readFileSync(path.join(directory, 'package.json')));
|
|
19
|
-
const expected = pkg.dependencies[module.installName];
|
|
20
|
-
if (installed.name !== module.name || ![installed.version, `npm:${installed.name}@${installed.version}`].includes(expected)) throw new Error('Install the exact registry module version before content synchronization.');
|
|
21
|
-
module.version = installed.version;
|
|
22
|
-
const npmCli = process.env.npm_execpath || path.join(path.dirname(process.execPath), 'node_modules/npm/bin/npm-cli.js');
|
|
23
|
-
const packed = JSON.parse(execFileSync(process.execPath, [npmCli, 'pack', '--dry-run', '--ignore-scripts', '--json'], { cwd: directory, windowsHide: true, encoding: 'utf8', maxBuffer: 16 * 1024 * 1024 }))[0];
|
|
24
|
-
module.files = Object.fromEntries(packed.files.map(entry => { const relative = entry.path; if (!safeRelative(relative)) throw new Error('Unsafe content path'); const target = path.join(directory, relative); if (fs.lstatSync(target).isSymbolicLink()) throw new Error('Unsafe content symlink'); return [relative, digest(target)]; }));
|
|
25
|
-
}
|
|
26
|
-
for (const relative of ['ui/index.html', 'ui/knowledge-panel.html', 'ui/product.js', 'ui/live-client.js', 'ui/product.css', 'ui/favicon.svg', 'plugins/project-knowledge/hooks/claude.json', 'plugins/project-knowledge/hooks/codex.json', 'plugins/project-knowledge/scripts/context-hook.cjs', 'plugins/project-knowledge/scripts/mcp-launcher.cjs', 'plugins/project-knowledge/.claude-plugin/plugin.json', 'plugins/project-knowledge/.codex-plugin/plugin.json', 'plugins/project-knowledge/.mcp.json']) manifest.productFiles[relative] = digest(path.join(root, relative));
|
|
27
|
-
AtomicFile.writeJsonAtomic(file, manifest);
|
|
28
|
-
console.log('Updated content hashes from exact installed modules and reviewed product assets; this is not release acceptance.');
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('node:fs');
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const crypto = require('node:crypto');
|
|
5
|
+
const { createRequire } = require('node:module');
|
|
6
|
+
const { execFileSync } = require('node:child_process');
|
|
7
|
+
const { safeRelative } = require('./pack-module-candidates');
|
|
8
|
+
const AtomicFile = require('../lib/atomic-file');
|
|
9
|
+
const root = path.resolve(__dirname, '../..');
|
|
10
|
+
const file = path.join(root, 'module-runtime-manifest.json');
|
|
11
|
+
const manifest = JSON.parse(fs.readFileSync(file));
|
|
12
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json')));
|
|
13
|
+
const resolve = createRequire(path.join(root, 'package.json'));
|
|
14
|
+
const digest = file => crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
|
|
15
|
+
for (const module of Object.values(manifest.modules)) {
|
|
16
|
+
const directory = path.dirname(resolve.resolve(`${module.installName}/package.json`));
|
|
17
|
+
if (!directory.startsWith(path.join(root, 'node_modules') + path.sep)) throw new Error('Module must resolve inside this installed dependency tree.');
|
|
18
|
+
const installed = JSON.parse(fs.readFileSync(path.join(directory, 'package.json')));
|
|
19
|
+
const expected = pkg.dependencies[module.installName];
|
|
20
|
+
if (installed.name !== module.name || ![installed.version, `npm:${installed.name}@${installed.version}`].includes(expected)) throw new Error('Install the exact registry module version before content synchronization.');
|
|
21
|
+
module.version = installed.version;
|
|
22
|
+
const npmCli = process.env.npm_execpath || path.join(path.dirname(process.execPath), 'node_modules/npm/bin/npm-cli.js');
|
|
23
|
+
const packed = JSON.parse(execFileSync(process.execPath, [npmCli, 'pack', '--dry-run', '--ignore-scripts', '--json'], { cwd: directory, windowsHide: true, encoding: 'utf8', maxBuffer: 16 * 1024 * 1024 }))[0];
|
|
24
|
+
module.files = Object.fromEntries(packed.files.map(entry => { const relative = entry.path; if (!safeRelative(relative)) throw new Error('Unsafe content path'); const target = path.join(directory, relative); if (fs.lstatSync(target).isSymbolicLink()) throw new Error('Unsafe content symlink'); return [relative, digest(target)]; }));
|
|
25
|
+
}
|
|
26
|
+
for (const relative of ['ui/index.html', 'ui/knowledge-panel.html', 'ui/product.js', 'ui/live-client.js', 'ui/product.css', 'ui/favicon.svg', 'plugins/project-knowledge/hooks/claude.json', 'plugins/project-knowledge/hooks/codex.json', 'plugins/project-knowledge/scripts/context-hook.cjs', 'plugins/project-knowledge/scripts/mcp-launcher.cjs', 'plugins/project-knowledge/.claude-plugin/plugin.json', 'plugins/project-knowledge/.codex-plugin/plugin.json', 'plugins/project-knowledge/.mcp.json']) manifest.productFiles[relative] = digest(path.join(root, relative));
|
|
27
|
+
AtomicFile.writeJsonAtomic(file, manifest);
|
|
28
|
+
console.log('Updated content hashes from exact installed modules and reviewed product assets; this is not release acceptance.');
|
|
@@ -1,164 +1,164 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const { spawnSync } = require('child_process');
|
|
6
|
-
|
|
7
|
-
function readJson(filePath) {
|
|
8
|
-
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function writeJson(filePath, value) {
|
|
12
|
-
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function packageVersion(rootDir) {
|
|
16
|
-
const version = String(readJson(path.join(rootDir, 'package.json')).version || '').trim();
|
|
17
|
-
if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(version)) {
|
|
18
|
-
throw new Error(`package.json must contain a SemVer version, received: ${version || '(empty)'}`);
|
|
19
|
-
}
|
|
20
|
-
return version;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function releaseVersionTargets(rootDir, version, { webOnly = false } = {}) {
|
|
24
|
-
return [
|
|
25
|
-
{
|
|
26
|
-
file: 'package-lock.json',
|
|
27
|
-
update(value) {
|
|
28
|
-
value.version = version;
|
|
29
|
-
if (!value.packages || !value.packages['']) throw new Error('package-lock.json has no root package entry');
|
|
30
|
-
value.packages[''].version = version;
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
file: 'desktop/package.json',
|
|
35
|
-
update(value) { value.version = version; },
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
file: 'desktop/package-lock.json',
|
|
39
|
-
update(value) {
|
|
40
|
-
value.version = version;
|
|
41
|
-
if (!value.packages || !value.packages['']) throw new Error('desktop/package-lock.json has no root package entry');
|
|
42
|
-
value.packages[''].version = version;
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
file: 'plugins/project-knowledge/.claude-plugin/plugin.json',
|
|
47
|
-
update(value) { value.version = version; },
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
file: 'plugins/project-knowledge/.codex-plugin/plugin.json',
|
|
51
|
-
update(value) { value.version = version; },
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
file: '.claude-plugin/marketplace.json',
|
|
55
|
-
update(value) {
|
|
56
|
-
if (!Array.isArray(value.plugins) || !value.plugins[0]) throw new Error('Claude marketplace has no project plugin');
|
|
57
|
-
value.plugins[0].version = version;
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
file: 'plugins/project-knowledge/.mcp.json',
|
|
62
|
-
update(value) {
|
|
63
|
-
const server = value && value.mcpServers && value.mcpServers['project-knowledge'];
|
|
64
|
-
const serialized = JSON.stringify(server || {});
|
|
65
|
-
if (/npx/i.test(serialized) || /@sanqianx\/project-knowledge@/.test(serialized)) throw new Error('project-knowledge MCP server must use the bundled launcher; the npx/pinned package form is rejected');
|
|
66
|
-
const args = Array.isArray(server && server.args) ? server.args : [];
|
|
67
|
-
const bootstrap = String(args[1] || '');
|
|
68
|
-
if (!server || server.command !== 'node' || args[0] !== '-e' || !bootstrap.includes('mcp-launcher.cjs')) throw new Error('project-knowledge MCP server must launch the bundled mcp-launcher.cjs via node -e');
|
|
69
|
-
if (server.cwd !== undefined) throw new Error('project-knowledge MCP server must not pin a cwd; the plugin version is carried by env.KB_PLUGIN_VERSION');
|
|
70
|
-
if (bootstrap.includes('process.cwd')) throw new Error('the MCP bootstrap must never consult process.cwd');
|
|
71
|
-
server.env = { ...(server.env || {}), KB_PLUGIN_VERSION: version };
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
].filter(target => !webOnly || !target.file.startsWith('desktop/')).map(target => ({ ...target, path: path.join(rootDir, target.file) }));
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function inspectReleaseVersion(rootDir, options) {
|
|
78
|
-
const version = packageVersion(rootDir);
|
|
79
|
-
const drift = [];
|
|
80
|
-
for (const target of releaseVersionTargets(rootDir, version, options)) {
|
|
81
|
-
const before = fs.readFileSync(target.path, 'utf8');
|
|
82
|
-
const value = JSON.parse(before);
|
|
83
|
-
target.update(value);
|
|
84
|
-
const after = `${JSON.stringify(value, null, 2)}\n`;
|
|
85
|
-
if (before.replace(/\r\n/g, '\n') !== after) drift.push(target.file);
|
|
86
|
-
}
|
|
87
|
-
return { version, drift };
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function syncReleaseVersion(rootDir, options) {
|
|
91
|
-
const version = packageVersion(rootDir);
|
|
92
|
-
const changed = [];
|
|
93
|
-
for (const target of releaseVersionTargets(rootDir, version, options)) {
|
|
94
|
-
const before = fs.readFileSync(target.path, 'utf8');
|
|
95
|
-
const value = JSON.parse(before);
|
|
96
|
-
target.update(value);
|
|
97
|
-
const after = `${JSON.stringify(value, null, 2)}\n`;
|
|
98
|
-
if (before.replace(/\r\n/g, '\n') === after) continue;
|
|
99
|
-
writeJson(target.path, value);
|
|
100
|
-
changed.push(target.file);
|
|
101
|
-
}
|
|
102
|
-
return { version, changed };
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function stageReleaseVersionFiles(rootDir, files) {
|
|
106
|
-
if (!files.length) return;
|
|
107
|
-
const result = spawnSync('git', ['-C', rootDir, 'add', '--', ...files], {
|
|
108
|
-
encoding: 'utf8',
|
|
109
|
-
windowsHide: true,
|
|
110
|
-
});
|
|
111
|
-
if (result.status !== 0) {
|
|
112
|
-
throw new Error(`failed to stage synchronized release files: ${(result.stderr || result.stdout || '').trim()}`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function parseArgs(argv) {
|
|
117
|
-
let rootDir = path.resolve(__dirname, '..', '..');
|
|
118
|
-
let check = false;
|
|
119
|
-
let tag = null;
|
|
120
|
-
let stage = false;
|
|
121
|
-
let webOnly = false;
|
|
122
|
-
for (let index = 0; index < argv.length; index += 1) {
|
|
123
|
-
const arg = argv[index];
|
|
124
|
-
if (arg === '--check') check = true;
|
|
125
|
-
else if (arg === '--stage') stage = true;
|
|
126
|
-
else if (arg === '--web-only') webOnly = true;
|
|
127
|
-
else if (arg === '--root') rootDir = path.resolve(argv[++index] || '');
|
|
128
|
-
else if (arg === '--tag') tag = String(argv[++index] || '').trim();
|
|
129
|
-
else throw new Error(`Unknown argument: ${arg}`);
|
|
130
|
-
}
|
|
131
|
-
return { rootDir, check, tag, stage, webOnly };
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function main(argv = process.argv.slice(2)) {
|
|
135
|
-
const { rootDir, check, tag, stage, webOnly } = parseArgs(argv);
|
|
136
|
-
if (check) {
|
|
137
|
-
const result = inspectReleaseVersion(rootDir, { webOnly });
|
|
138
|
-
if (result.drift.length) {
|
|
139
|
-
throw new Error(`Release version ${result.version} is out of sync: ${result.drift.join(', ')}`);
|
|
140
|
-
}
|
|
141
|
-
if (tag && tag !== `v${result.version}`) {
|
|
142
|
-
throw new Error(`Release tag ${tag} must match package version v${result.version}`);
|
|
143
|
-
}
|
|
144
|
-
console.log(`release version ${result.version} is synchronized`);
|
|
145
|
-
return result;
|
|
146
|
-
}
|
|
147
|
-
const result = syncReleaseVersion(rootDir, { webOnly });
|
|
148
|
-
if (stage) stageReleaseVersionFiles(rootDir, result.changed);
|
|
149
|
-
console.log(result.changed.length
|
|
150
|
-
? `${stage ? 'synchronized and staged' : 'synchronized'} release version ${result.version}: ${result.changed.join(', ')}`
|
|
151
|
-
: `release version ${result.version} is already synchronized`);
|
|
152
|
-
return result;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (require.main === module) {
|
|
156
|
-
try {
|
|
157
|
-
main();
|
|
158
|
-
} catch (error) {
|
|
159
|
-
console.error(`release version synchronization failed: ${error.message}`);
|
|
160
|
-
process.exitCode = 1;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
module.exports = { inspectReleaseVersion, main, releaseVersionTargets, stageReleaseVersionFiles, syncReleaseVersion };
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { spawnSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
function readJson(filePath) {
|
|
8
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function writeJson(filePath, value) {
|
|
12
|
+
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function packageVersion(rootDir) {
|
|
16
|
+
const version = String(readJson(path.join(rootDir, 'package.json')).version || '').trim();
|
|
17
|
+
if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(version)) {
|
|
18
|
+
throw new Error(`package.json must contain a SemVer version, received: ${version || '(empty)'}`);
|
|
19
|
+
}
|
|
20
|
+
return version;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function releaseVersionTargets(rootDir, version, { webOnly = false } = {}) {
|
|
24
|
+
return [
|
|
25
|
+
{
|
|
26
|
+
file: 'package-lock.json',
|
|
27
|
+
update(value) {
|
|
28
|
+
value.version = version;
|
|
29
|
+
if (!value.packages || !value.packages['']) throw new Error('package-lock.json has no root package entry');
|
|
30
|
+
value.packages[''].version = version;
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
file: 'desktop/package.json',
|
|
35
|
+
update(value) { value.version = version; },
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
file: 'desktop/package-lock.json',
|
|
39
|
+
update(value) {
|
|
40
|
+
value.version = version;
|
|
41
|
+
if (!value.packages || !value.packages['']) throw new Error('desktop/package-lock.json has no root package entry');
|
|
42
|
+
value.packages[''].version = version;
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
file: 'plugins/project-knowledge/.claude-plugin/plugin.json',
|
|
47
|
+
update(value) { value.version = version; },
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
file: 'plugins/project-knowledge/.codex-plugin/plugin.json',
|
|
51
|
+
update(value) { value.version = version; },
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
file: '.claude-plugin/marketplace.json',
|
|
55
|
+
update(value) {
|
|
56
|
+
if (!Array.isArray(value.plugins) || !value.plugins[0]) throw new Error('Claude marketplace has no project plugin');
|
|
57
|
+
value.plugins[0].version = version;
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
file: 'plugins/project-knowledge/.mcp.json',
|
|
62
|
+
update(value) {
|
|
63
|
+
const server = value && value.mcpServers && value.mcpServers['project-knowledge'];
|
|
64
|
+
const serialized = JSON.stringify(server || {});
|
|
65
|
+
if (/npx/i.test(serialized) || /@sanqianx\/project-knowledge@/.test(serialized)) throw new Error('project-knowledge MCP server must use the bundled launcher; the npx/pinned package form is rejected');
|
|
66
|
+
const args = Array.isArray(server && server.args) ? server.args : [];
|
|
67
|
+
const bootstrap = String(args[1] || '');
|
|
68
|
+
if (!server || server.command !== 'node' || args[0] !== '-e' || !bootstrap.includes('mcp-launcher.cjs')) throw new Error('project-knowledge MCP server must launch the bundled mcp-launcher.cjs via node -e');
|
|
69
|
+
if (server.cwd !== undefined) throw new Error('project-knowledge MCP server must not pin a cwd; the plugin version is carried by env.KB_PLUGIN_VERSION');
|
|
70
|
+
if (bootstrap.includes('process.cwd')) throw new Error('the MCP bootstrap must never consult process.cwd');
|
|
71
|
+
server.env = { ...(server.env || {}), KB_PLUGIN_VERSION: version };
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
].filter(target => !webOnly || !target.file.startsWith('desktop/')).map(target => ({ ...target, path: path.join(rootDir, target.file) }));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function inspectReleaseVersion(rootDir, options) {
|
|
78
|
+
const version = packageVersion(rootDir);
|
|
79
|
+
const drift = [];
|
|
80
|
+
for (const target of releaseVersionTargets(rootDir, version, options)) {
|
|
81
|
+
const before = fs.readFileSync(target.path, 'utf8');
|
|
82
|
+
const value = JSON.parse(before);
|
|
83
|
+
target.update(value);
|
|
84
|
+
const after = `${JSON.stringify(value, null, 2)}\n`;
|
|
85
|
+
if (before.replace(/\r\n/g, '\n') !== after) drift.push(target.file);
|
|
86
|
+
}
|
|
87
|
+
return { version, drift };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function syncReleaseVersion(rootDir, options) {
|
|
91
|
+
const version = packageVersion(rootDir);
|
|
92
|
+
const changed = [];
|
|
93
|
+
for (const target of releaseVersionTargets(rootDir, version, options)) {
|
|
94
|
+
const before = fs.readFileSync(target.path, 'utf8');
|
|
95
|
+
const value = JSON.parse(before);
|
|
96
|
+
target.update(value);
|
|
97
|
+
const after = `${JSON.stringify(value, null, 2)}\n`;
|
|
98
|
+
if (before.replace(/\r\n/g, '\n') === after) continue;
|
|
99
|
+
writeJson(target.path, value);
|
|
100
|
+
changed.push(target.file);
|
|
101
|
+
}
|
|
102
|
+
return { version, changed };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function stageReleaseVersionFiles(rootDir, files) {
|
|
106
|
+
if (!files.length) return;
|
|
107
|
+
const result = spawnSync('git', ['-C', rootDir, 'add', '--', ...files], {
|
|
108
|
+
encoding: 'utf8',
|
|
109
|
+
windowsHide: true,
|
|
110
|
+
});
|
|
111
|
+
if (result.status !== 0) {
|
|
112
|
+
throw new Error(`failed to stage synchronized release files: ${(result.stderr || result.stdout || '').trim()}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function parseArgs(argv) {
|
|
117
|
+
let rootDir = path.resolve(__dirname, '..', '..');
|
|
118
|
+
let check = false;
|
|
119
|
+
let tag = null;
|
|
120
|
+
let stage = false;
|
|
121
|
+
let webOnly = false;
|
|
122
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
123
|
+
const arg = argv[index];
|
|
124
|
+
if (arg === '--check') check = true;
|
|
125
|
+
else if (arg === '--stage') stage = true;
|
|
126
|
+
else if (arg === '--web-only') webOnly = true;
|
|
127
|
+
else if (arg === '--root') rootDir = path.resolve(argv[++index] || '');
|
|
128
|
+
else if (arg === '--tag') tag = String(argv[++index] || '').trim();
|
|
129
|
+
else throw new Error(`Unknown argument: ${arg}`);
|
|
130
|
+
}
|
|
131
|
+
return { rootDir, check, tag, stage, webOnly };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function main(argv = process.argv.slice(2)) {
|
|
135
|
+
const { rootDir, check, tag, stage, webOnly } = parseArgs(argv);
|
|
136
|
+
if (check) {
|
|
137
|
+
const result = inspectReleaseVersion(rootDir, { webOnly });
|
|
138
|
+
if (result.drift.length) {
|
|
139
|
+
throw new Error(`Release version ${result.version} is out of sync: ${result.drift.join(', ')}`);
|
|
140
|
+
}
|
|
141
|
+
if (tag && tag !== `v${result.version}`) {
|
|
142
|
+
throw new Error(`Release tag ${tag} must match package version v${result.version}`);
|
|
143
|
+
}
|
|
144
|
+
console.log(`release version ${result.version} is synchronized`);
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
const result = syncReleaseVersion(rootDir, { webOnly });
|
|
148
|
+
if (stage) stageReleaseVersionFiles(rootDir, result.changed);
|
|
149
|
+
console.log(result.changed.length
|
|
150
|
+
? `${stage ? 'synchronized and staged' : 'synchronized'} release version ${result.version}: ${result.changed.join(', ')}`
|
|
151
|
+
: `release version ${result.version} is already synchronized`);
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (require.main === module) {
|
|
156
|
+
try {
|
|
157
|
+
main();
|
|
158
|
+
} catch (error) {
|
|
159
|
+
console.error(`release version synchronization failed: ${error.message}`);
|
|
160
|
+
process.exitCode = 1;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
module.exports = { inspectReleaseVersion, main, releaseVersionTargets, stageReleaseVersionFiles, syncReleaseVersion };
|