@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.
Files changed (401) hide show
  1. package/.agents/plugins/marketplace.json +20 -20
  2. package/.claude-plugin/marketplace.json +1 -1
  3. package/CHANGELOG.md +1361 -1353
  4. package/LICENSE +201 -201
  5. package/NOTICE +5 -5
  6. package/README.md +349 -349
  7. package/_modules/knowledge-engine/package.json +1 -1
  8. package/_modules/knowledge-engine/src/coordinator.js +48 -3
  9. package/_modules/knowledge-engine/src/runtime/automation-config.js +140 -140
  10. package/_modules/knowledge-engine/src/runtime/commit-conversation-binder.js +238 -238
  11. package/_modules/knowledge-engine/src/runtime/commit-processing-ledger.js +26 -26
  12. package/_modules/knowledge-engine/src/runtime/commit-prompt.js +193 -193
  13. package/_modules/knowledge-engine/src/runtime/commit-reconciler.js +394 -394
  14. package/_modules/knowledge-engine/src/runtime/contracts.js +282 -282
  15. package/_modules/knowledge-engine/src/runtime/conversation-store.js +389 -389
  16. package/_modules/knowledge-engine/src/runtime/evidence-bundle.js +228 -228
  17. package/_modules/knowledge-engine/src/runtime/git-runner.js +62 -62
  18. package/_modules/knowledge-engine/src/runtime/knowledge-promotion.js +505 -505
  19. package/_modules/knowledge-engine/src/runtime/knowledge-retrieval-service.js +400 -400
  20. package/_modules/knowledge-engine/src/runtime/markdown-knowledge-indexer.js +171 -171
  21. package/_modules/knowledge-engine/src/runtime/scanner.js +298 -298
  22. package/_modules/knowledge-engine/ui/app.js +23 -2
  23. package/_site/README.md +30 -30
  24. package/_site/_test/agent-capture-mcp-ui-test.js +68 -68
  25. package/_site/_test/agent-capture-ui-test.js +101 -101
  26. package/_site/_test/ai-profile-resolver-test.js +137 -137
  27. package/_site/_test/ai-profile-test.js +75 -75
  28. package/_site/_test/ai-vendor-presets-test.js +91 -91
  29. package/_site/_test/automatic-context-test.js +70 -70
  30. package/_site/_test/automation-queue-test.js +14 -14
  31. package/_site/_test/automation-ui-test.js +40 -40
  32. package/_site/_test/background-task-registry-test.js +43 -43
  33. package/_site/_test/baseline-schema-test.js +91 -91
  34. package/_site/_test/bin-cli-test.js +230 -230
  35. package/_site/_test/bridge-adapter-test.js +95 -95
  36. package/_site/_test/bridge-consumer-service-test.js +310 -310
  37. package/_site/_test/candidate-bin-content-test.js +35 -35
  38. package/_site/_test/candidate-product-assets-test.js +13 -13
  39. package/_site/_test/candidate-release-contract-test.js +14 -14
  40. package/_site/_test/capture-hook-dedup-test.js +158 -158
  41. package/_site/_test/cdp-browser-failure-test.js +103 -103
  42. package/_site/_test/chat-claudecodeui-match-test.js +92 -92
  43. package/_site/_test/claude-executable-discovery-test.js +90 -90
  44. package/_site/_test/claude-session-lifecycle-sweep-test.js +252 -252
  45. package/_site/_test/claude-workbench-test.js +174 -174
  46. package/_site/_test/cli-instance-management-test.js +62 -62
  47. package/_site/_test/client-capture-restart-e2e-test.js +189 -189
  48. package/_site/_test/codex-conversation-projection-test.js +60 -60
  49. package/_site/_test/codex-marketplace-scoped-path-test.js +186 -186
  50. package/_site/_test/codex-notify-capture-e2e-test.js +101 -101
  51. package/_site/_test/codex-notify-fanout-test.js +141 -134
  52. package/_site/_test/codex-notify-upgrade-test.js +253 -253
  53. package/_site/_test/commit-boundary-freeze-test.js +147 -147
  54. package/_site/_test/commit-conversation-binding-test.js +99 -99
  55. package/_site/_test/commit-evidence-test.js +110 -110
  56. package/_site/_test/configuration-generation-test.js +22 -22
  57. package/_site/_test/context-pack-test.js +200 -200
  58. package/_site/_test/conversation-api-test.js +119 -119
  59. package/_site/_test/conversation-origin-test.js +15 -15
  60. package/_site/_test/conversation-store-test.js +138 -138
  61. package/_site/_test/cross-repo-isolation-e2e-test.js +187 -187
  62. package/_site/_test/desktop-browser-compat-test.js +28 -28
  63. package/_site/_test/desktop-hook-runtime-regression-test.js +204 -204
  64. package/_site/_test/embedding-config-test.js +32 -32
  65. package/_site/_test/explicit-commit-processor-test.js +37 -37
  66. package/_site/_test/fixtures/fake-browser-exit.js +10 -10
  67. package/_site/_test/fixtures/fake-browser-hang.js +10 -10
  68. package/_site/_test/fixtures/integration-busy-worker.cjs +6 -6
  69. package/_site/_test/fixtures/make-git-repos.js +92 -92
  70. package/_site/_test/fixtures/retrieval-gold-queries.json +32 -32
  71. package/_site/_test/folder-picker-output-test.js +19 -19
  72. package/_site/_test/fresh-hook-reimport-test.js +53 -53
  73. package/_site/_test/fresh-product-data-test.js +56 -56
  74. package/_site/_test/full-integration-e2e-test.js +167 -167
  75. package/_site/_test/git-path-compatibility-test.js +80 -80
  76. package/_site/_test/git-validation-test.js +81 -81
  77. package/_site/_test/glm-ui-refresh-review-test.js +313 -404
  78. package/_site/_test/harness-isolation-test.js +138 -0
  79. package/_site/_test/helpers/cdp-browser.js +383 -0
  80. package/_site/_test/helpers/cdp-network-capture.js +66 -0
  81. package/_site/_test/helpers/find-chrome.js +34 -0
  82. package/_site/_test/helpers/free-port.js +8 -0
  83. package/_site/_test/helpers/logging-ui-fixture.js +131 -0
  84. package/_site/_test/helpers/module-fixture.js +282 -0
  85. package/_site/_test/helpers/parallel-engine-advanced-engine-child.js +45 -0
  86. package/_site/_test/helpers/parallel-engine-advanced-fault-writer.js +171 -0
  87. package/_site/_test/helpers/parallel-engine-advanced-harness.js +245 -0
  88. package/_site/_test/helpers/parallel-engine-advanced-standin-analyzer.js +80 -0
  89. package/_site/_test/helpers/parallel-engine-advanced-ui-host.js +177 -0
  90. package/_site/_test/helpers/parallel-engine-final-harness.js +314 -0
  91. package/_site/_test/helpers/parallel-engine-final-standin-analyzer.js +159 -0
  92. package/_site/_test/helpers/parallel-knowledge-fixture.js +255 -0
  93. package/_site/_test/helpers/parallel-logging-acceptance-fixture.js +111 -0
  94. package/_site/_test/helpers/parallel-logging-acceptance-proxy.js +106 -0
  95. package/_site/_test/helpers/parallel-logging-fix-r2-proxy.js +205 -0
  96. package/_site/_test/helpers/parallel-logging-integration-5025-env.js +432 -0
  97. package/_site/_test/helpers/parallel-memory-analyzer.js +81 -0
  98. package/_site/_test/helpers/parallel-memory-event-bridge.js +128 -0
  99. package/_site/_test/helpers/parallel-memory-shell.js +470 -0
  100. package/_site/_test/helpers/parallel-nav-isolation-env.js +389 -0
  101. package/_site/_test/helpers/parallel-nav-module-ui.js +186 -0
  102. package/_site/_test/helpers/parallel-nav-proxy.js +148 -0
  103. package/_site/_test/helpers/parallel-nav-shell.js +361 -0
  104. package/_site/_test/helpers/parallel-qa-engine-endpoint-guard.js +206 -0
  105. package/_site/_test/helpers/parallel-qa-engine-endpoint-isolate.js +257 -0
  106. package/_site/_test/helpers/parallel-retrieval-followup-corpus.js +293 -0
  107. package/_site/_test/helpers/parallel-retrieval-followup-next-session.js +70 -0
  108. package/_site/_test/helpers/parallel-retrieval-followup-r2-shell.js +737 -0
  109. package/_site/_test/helpers/parallel-retrieval-followup-r2-wb-host.js +82 -0
  110. package/_site/_test/helpers/parallel-retrieval-followup-shell.js +279 -0
  111. package/_site/_test/helpers/parallel-workbench-fixture.js +371 -0
  112. package/_site/_test/helpers/parallel-workbench-host.js +80 -0
  113. package/_site/_test/helpers/parallel-workbench-integration-5025-fixture.js +408 -0
  114. package/_site/_test/helpers/parallel-workbench-integration-5025-harness.js +593 -0
  115. package/_site/_test/helpers/parallel-workbench-integration-5025-host.js +70 -0
  116. package/_site/_test/helpers/parallel-workbench-integration-5025-launcher.js +240 -0
  117. package/_site/_test/helpers/parallel-workbench-integration-5025-runtime-harness.js +630 -0
  118. package/_site/_test/helpers/parallel-workbench-source-map.js +196 -0
  119. package/_site/_test/helpers/spawn-server.js +106 -0
  120. package/_site/_test/helpers/version-visibility-fixture.js +251 -0
  121. package/_site/_test/hook-runtime-endpoint-test.js +88 -88
  122. package/_site/_test/hook-status-repair-api-test.js +152 -152
  123. package/_site/_test/hook-trigger-test.js +85 -85
  124. package/_site/_test/hook-worktree-test.js +42 -42
  125. package/_site/_test/import-preflight-api-test.js +234 -234
  126. package/_site/_test/index-builder-test.js +41 -41
  127. package/_site/_test/index-error-display-contract-test.js +10 -10
  128. package/_site/_test/index-writer-concurrency-test.js +135 -135
  129. package/_site/_test/integration-adapters-test.js +262 -262
  130. package/_site/_test/integration-auto-repair-test.js +113 -113
  131. package/_site/_test/integration-capture-setup-test.js +118 -118
  132. package/_site/_test/integration-intent-test.js +81 -81
  133. package/_site/_test/integration-runtime-binding-a2-test.js +566 -566
  134. package/_site/_test/integration-runtime-binding-a3-test.js +227 -227
  135. package/_site/_test/integration-runtime-binding-test.js +473 -473
  136. package/_site/_test/integration-status-scan-test.js +29 -29
  137. package/_site/_test/integration-surface-coverage-test.js +164 -164
  138. package/_site/_test/kb-framework-test.js +57 -57
  139. package/_site/_test/kbpath-follow-test.js +63 -63
  140. package/_site/_test/knowledge-db-test.js +144 -144
  141. package/_site/_test/knowledge-engine-client-test.js +120 -109
  142. package/_site/_test/knowledge-language-control-test.js +170 -170
  143. package/_site/_test/knowledge-maintenance-test.js +40 -40
  144. package/_site/_test/knowledge-promotion-recovery-test.js +260 -260
  145. package/_site/_test/knowledge-query-test.js +54 -54
  146. package/_site/_test/knowledge-retrieval-service-test.js +77 -77
  147. package/_site/_test/knowledge-scopes-test.js +37 -37
  148. package/_site/_test/knowledge-storage-location-test.js +28 -28
  149. package/_site/_test/knowledge-storage-startup-test.js +52 -52
  150. package/_site/_test/knowledge-store-logs-supervision-test.js +89 -89
  151. package/_site/_test/launcher-readiness-test.js +80 -80
  152. package/_site/_test/legacy-claude-session-alias-test.js +106 -106
  153. package/_site/_test/legacy-routes-removed-test.js +47 -47
  154. package/_site/_test/legacy-workbench-exclusion-test.js +92 -92
  155. package/_site/_test/live-gateway-test.js +48 -48
  156. package/_site/_test/local-marketplace-test.js +16 -16
  157. package/_site/_test/log-redaction-test.js +58 -58
  158. package/_site/_test/logging-api-test.js +89 -89
  159. package/_site/_test/logging-sse-no-gap-test.js +88 -88
  160. package/_site/_test/logging-ui-test.js +107 -107
  161. package/_site/_test/markdown-delta-overlay-test.js +85 -85
  162. package/_site/_test/markdown-maintenance-api-test.js +75 -75
  163. package/_site/_test/markdown-maintenance-test.js +11 -11
  164. package/_site/_test/mcp-server-test.js +149 -149
  165. package/_site/_test/model-context-windows-test.js +89 -89
  166. package/_site/_test/module-agent-start-proxy-test.js +65 -65
  167. package/_site/_test/module-artifact-integrity-test.js +27 -27
  168. package/_site/_test/module-boundary-test.js +30 -30
  169. package/_site/_test/module-bridge-eventbridge-test.js +202 -202
  170. package/_site/_test/module-dynamic-port-test.js +118 -118
  171. package/_site/_test/module-index-proxy-test.js +33 -33
  172. package/_site/_test/module-model-configuration-test.js +44 -44
  173. package/_site/_test/module-process-lifecycle-test.js +35 -35
  174. package/_site/_test/module-stream-proxy-test.js +34 -34
  175. package/_site/_test/module-terminal-restart-test.js +63 -63
  176. package/_site/_test/module-wiring-unbind-race-test.js +59 -59
  177. package/_site/_test/native-context-integrations-test.js +86 -86
  178. package/_site/_test/non-release-ci-test.js +34 -34
  179. package/_site/_test/offline-boundary-isolation-test.js +32 -32
  180. package/_site/_test/orphaned-claim-recovery-test.js +80 -80
  181. package/_site/_test/package-boundary-test.js +43 -43
  182. package/_site/_test/package-startup-test.js +56 -56
  183. package/_site/_test/packaged-ui-smoke-test.js +88 -88
  184. package/_site/_test/parallel-ci-r9-posix-socket-budget-test.js +156 -0
  185. package/_site/_test/parallel-engine-advanced-eng005-test.js +136 -0
  186. package/_site/_test/parallel-engine-advanced-eng006-test.js +171 -0
  187. package/_site/_test/parallel-engine-advanced-eng007-reconcile-test.js +231 -0
  188. package/_site/_test/parallel-engine-advanced-eng009-test.js +208 -0
  189. package/_site/_test/parallel-engine-advanced-eng010-test.js +213 -0
  190. package/_site/_test/parallel-engine-advanced-eng011-ui-probe.js +459 -0
  191. package/_site/_test/parallel-engine-final-eng002-test.js +255 -0
  192. package/_site/_test/parallel-engine-final-eng007-test.js +269 -0
  193. package/_site/_test/parallel-engine-final-eng011-test.js +197 -0
  194. package/_site/_test/parallel-engine-final-eng012-test.js +354 -0
  195. package/_site/_test/parallel-knowledge-client-error-code-test.js +184 -0
  196. package/_site/_test/parallel-knowledge-engine-test.js +353 -0
  197. package/_site/_test/parallel-knowledge-retrieval-test.js +292 -0
  198. package/_site/_test/parallel-knowledge-vector-test.js +168 -0
  199. package/_site/_test/parallel-linux-ci-r7-log007-day-test.js +110 -0
  200. package/_site/_test/parallel-logging-acceptance-log003-test.js +224 -0
  201. package/_site/_test/parallel-logging-acceptance-log004-test.js +231 -0
  202. package/_site/_test/parallel-logging-acceptance-log005-test.js +208 -0
  203. package/_site/_test/parallel-logging-acceptance-log006-test.js +214 -0
  204. package/_site/_test/parallel-logging-acceptance-log007-test.js +223 -0
  205. package/_site/_test/parallel-logging-acceptance-log008-test.js +180 -0
  206. package/_site/_test/parallel-logging-fix-r2-crash-probe.js +271 -0
  207. package/_site/_test/parallel-logging-fix-r2-gap-test.js +294 -0
  208. package/_site/_test/parallel-logging-fix-r2-normalhook-test.js +330 -0
  209. package/_site/_test/parallel-logging-integration-5025-portability-test.js +554 -0
  210. package/_site/_test/parallel-memory-candidate-test.js +301 -0
  211. package/_site/_test/parallel-memory-manual-test.js +197 -0
  212. package/_site/_test/parallel-memory-scope-test.js +228 -0
  213. package/_site/_test/parallel-memory-source-test.js +227 -0
  214. package/_site/_test/parallel-memory-sync-test.js +238 -0
  215. package/_site/_test/parallel-memory-view-r8-reload-gate-test.js +123 -0
  216. package/_site/_test/parallel-nav-failure-test.js +119 -0
  217. package/_site/_test/parallel-nav-isolation-test.js +308 -0
  218. package/_site/_test/parallel-nav-isolation-vector-path-test.js +90 -0
  219. package/_site/_test/parallel-nav-offline-test.js +272 -0
  220. package/_site/_test/parallel-nav-operability-test.js +257 -0
  221. package/_site/_test/parallel-nav-switch-test.js +247 -0
  222. package/_site/_test/parallel-nav-theme-test.js +130 -0
  223. package/_site/_test/parallel-nav-viewport-test.js +310 -0
  224. package/_site/_test/parallel-qa-engine-endpoint-guard-test.js +273 -0
  225. package/_site/_test/parallel-retrieval-followup-citation-test.js +219 -0
  226. package/_site/_test/parallel-retrieval-followup-corpus-test.js +287 -0
  227. package/_site/_test/parallel-workbench-independent-host.js +262 -0
  228. package/_site/_test/parallel-workbench-integration-5025-abort-probe.js +340 -0
  229. package/_site/_test/parallel-workbench-integration-5025-drafts-probe.js +588 -0
  230. package/_site/_test/parallel-workbench-integration-5025-env-check.js +317 -0
  231. package/_site/_test/parallel-workbench-integration-5025-model-probe.js +342 -0
  232. package/_site/_test/parallel-workbench-integration-5025-ordering-probe.js +326 -0
  233. package/_site/_test/parallel-workbench-model-probe.js +336 -0
  234. package/_site/_test/parallel-workbench-offline-test.js +169 -0
  235. package/_site/_test/parallel-workbench-provenance-trace.js +134 -0
  236. package/_site/_test/parallel-workbench-source-match.js +206 -0
  237. package/_site/_test/parallel-workbench-standalone-turn.js +349 -0
  238. package/_site/_test/path-consistency-test.js +151 -151
  239. package/_site/_test/pending-sweep-test.js +9 -9
  240. package/_site/_test/post-commit-automation-test.js +87 -87
  241. package/_site/_test/pr-consumer-contract-test.js +55 -55
  242. package/_site/_test/product-brand-contract-test.js +25 -25
  243. package/_site/_test/product-diagnostics-ui-test.js +93 -93
  244. package/_site/_test/product-empty-state-test.js +148 -0
  245. package/_site/_test/product-import-ui-test.js +219 -104
  246. package/_site/_test/product-navigation-test.js +152 -0
  247. package/_site/_test/product-progress-status-test.js +84 -84
  248. package/_site/_test/project-delete-recovery-test.js +64 -64
  249. package/_site/_test/project-domain-create-test.js +91 -0
  250. package/_site/_test/project-domain-scope-retrieval-test.js +214 -0
  251. package/_site/_test/project-git-init-confirm-test.js +115 -0
  252. package/_site/_test/project-goal-editor-test.js +144 -144
  253. package/_site/_test/project-import-duplicate-alias-test.js +134 -0
  254. package/_site/_test/project-import-unicode-restart-test.js +140 -0
  255. package/_site/_test/project-lifecycle-transaction-test.js +106 -106
  256. package/_site/_test/project-module-partial-recovery-test.js +222 -0
  257. package/_site/_test/project-remove-running-guard-test.js +79 -79
  258. package/_site/_test/project-store-test.js +90 -90
  259. package/_site/_test/project-unbind-late-read-ui-test.js +250 -0
  260. package/_site/_test/project-unbind-writer-guard-test.js +231 -0
  261. package/_site/_test/prompt-settings-test.js +115 -115
  262. package/_site/_test/protected-architecture-gate-test.js +122 -122
  263. package/_site/_test/refactor-characterization-test.js +36 -36
  264. package/_site/_test/registry-events-test.js +38 -38
  265. package/_site/_test/release-version-sync-test.js +115 -115
  266. package/_site/_test/requirement-binding-test.js +113 -113
  267. package/_site/_test/requirement-recorder-test.js +173 -173
  268. package/_site/_test/run-all-tests.js +173 -161
  269. package/_site/_test/runtime-endpoint-test.js +64 -64
  270. package/_site/_test/scanner-test.js +83 -83
  271. package/_site/_test/server-security-test.js +96 -96
  272. package/_site/_test/sessions-stream-test.js +93 -93
  273. package/_site/_test/shared-contracts-test.js +58 -58
  274. package/_site/_test/shared-scope-root-binding-test.js +74 -67
  275. package/_site/_test/simple-import-test.js +98 -98
  276. package/_site/_test/startup-analysis-disabled-test.js +16 -16
  277. package/_site/_test/storage-foundation-test.js +78 -78
  278. package/_site/_test/structured-logger-test.js +101 -101
  279. package/_site/_test/t07b-cln-005-coverage-test.js +212 -0
  280. package/_site/_test/team-knowledge-store-sparse-checkout-test.js +196 -196
  281. package/_site/_test/team-knowledge-store-test.js +132 -132
  282. package/_site/_test/test-server-cleanup-test.js +35 -35
  283. package/_site/_test/test-server-module-isolation-test.js +37 -37
  284. package/_site/_test/tracking-start-test.js +144 -144
  285. package/_site/_test/vector-storage-root-test.js +75 -75
  286. package/_site/_test/version-visibility-browser-probe.js +249 -0
  287. package/_site/_test/version-visibility-test.js +92 -0
  288. package/_site/_test/workbench-context-receipts-test.js +22 -22
  289. package/_site/_test/workbench-permission-test.js +117 -117
  290. package/_site/_test/zcode-capture-integration-test.js +112 -112
  291. package/_site/lib/ai-profile-resolver.js +78 -78
  292. package/_site/lib/ai-vendor-presets.js +83 -83
  293. package/_site/lib/ai-workspace.js +104 -104
  294. package/_site/lib/atomic-file.js +204 -204
  295. package/_site/lib/automation-config.js +140 -140
  296. package/_site/lib/bridge-adapter.js +260 -260
  297. package/_site/lib/bridge-consumer-service.js +402 -402
  298. package/_site/lib/capture-hook-config.js +108 -108
  299. package/_site/lib/claude-cli-runner.js +1599 -1599
  300. package/_site/lib/cli-instances.js +43 -43
  301. package/_site/lib/codex-context-status.js +17 -17
  302. package/_site/lib/codex-notify-config.js +193 -193
  303. package/_site/lib/commit-conversation-binder.js +247 -247
  304. package/_site/lib/commit-processing-ledger.js +27 -27
  305. package/_site/lib/commit-prompt.js +202 -202
  306. package/_site/lib/commit-reconciler.js +444 -444
  307. package/_site/lib/context-pack-builder.js +299 -299
  308. package/_site/lib/contracts.js +291 -291
  309. package/_site/lib/conversation-exclusions.js +204 -204
  310. package/_site/lib/conversation-query-service.js +161 -161
  311. package/_site/lib/conversation-store.js +387 -387
  312. package/_site/lib/data-dir.js +13 -13
  313. package/_site/lib/embedding-service.js +85 -85
  314. package/_site/lib/engine-connection.js +93 -93
  315. package/_site/lib/engine-knowledge-client.js +76 -72
  316. package/_site/lib/evidence-bundle.js +228 -228
  317. package/_site/lib/folder-picker-output.js +24 -24
  318. package/_site/lib/git-path.js +14 -14
  319. package/_site/lib/git-runner.js +62 -62
  320. package/_site/lib/github-team-store.js +1175 -1175
  321. package/_site/lib/hook-manager.js +203 -203
  322. package/_site/lib/index-builder.js +157 -157
  323. package/_site/lib/index-service.js +173 -173
  324. package/_site/lib/integration-auto-repair.js +77 -77
  325. package/_site/lib/integration-installer.js +1240 -1240
  326. package/_site/lib/integration-intent.js +88 -88
  327. package/_site/lib/integration-status-scan.js +99 -99
  328. package/_site/lib/integration-status-worker.js +14 -14
  329. package/_site/lib/kb-framework.js +191 -191
  330. package/_site/lib/kb-validator.js +124 -124
  331. package/_site/lib/knowledge-db.js +363 -363
  332. package/_site/lib/knowledge-promotion.js +435 -435
  333. package/_site/lib/knowledge-retrieval-service.js +401 -401
  334. package/_site/lib/knowledge-schema.js +121 -121
  335. package/_site/lib/knowledge-tool-runtime.js +366 -366
  336. package/_site/lib/live-gateway.js +78 -78
  337. package/_site/lib/llm-client.js +173 -173
  338. package/_site/lib/markdown-knowledge-indexer.js +230 -230
  339. package/_site/lib/model-context-windows.js +82 -82
  340. package/_site/lib/module-bridge.js +874 -874
  341. package/_site/lib/module-port-resolver.js +57 -57
  342. package/_site/lib/post-commit-automation.js +141 -141
  343. package/_site/lib/product-data.js +35 -35
  344. package/_site/lib/project-lifecycle-service.js +554 -554
  345. package/_site/lib/project-registry-store.js +129 -129
  346. package/_site/lib/project-store.js +268 -268
  347. package/_site/lib/prompt-registry.js +148 -148
  348. package/_site/lib/public-version-info.js +37 -0
  349. package/_site/lib/registry-events.js +16 -16
  350. package/_site/lib/requirement-adapters.js +10 -10
  351. package/_site/lib/requirement-binder.js +112 -112
  352. package/_site/lib/requirement-recorder.js +278 -278
  353. package/_site/lib/runtime-control.js +89 -89
  354. package/_site/lib/runtime-endpoint.js +160 -160
  355. package/_site/lib/scanner.js +298 -298
  356. package/_site/lib/server-app.js +1672 -1664
  357. package/_site/lib/settings-store.js +153 -153
  358. package/_site/lib/storage-layout.js +166 -166
  359. package/_site/lib/structured-logger.js +574 -574
  360. package/_site/lib/zcode-context-integration.js +60 -60
  361. package/_site/scripts/codex-notify-fanout.cjs +95 -95
  362. package/_site/scripts/folder-picker.ps1 +156 -156
  363. package/_site/scripts/hook-trigger.js +158 -158
  364. package/_site/scripts/install-module-candidates.js +69 -69
  365. package/_site/scripts/pack-module-candidates.js +89 -89
  366. package/_site/scripts/sync-product-content.js +28 -28
  367. package/_site/scripts/sync-release-version.js +164 -164
  368. package/_site/scripts/vendor-modules.js +49 -49
  369. package/_site/scripts/verify-module-runtime.js +50 -50
  370. package/_site/scripts/verify-product-runtime.js +36 -36
  371. package/_site/scripts/verify-retrieval-gold.js +83 -83
  372. package/_site/server.js +15 -15
  373. package/_site/start.bat +26 -26
  374. package/_site/stop.bat +11 -11
  375. package/bin/project-knowledge-integrations.js +254 -254
  376. package/bin/project-knowledge-kb.js +67 -67
  377. package/bin/project-knowledge-mcp.js +201 -201
  378. package/bin/project-knowledge.js +269 -170
  379. package/claude-prompts.json +21 -21
  380. package/docs/README.zh-CN.md +207 -205
  381. package/docs/assets/architecture.svg +181 -181
  382. package/docs/assets/logo.svg +49 -49
  383. package/docs/fresh-v5-start.md +44 -44
  384. package/docs/leader-glm-workbench-playbook.md +122 -122
  385. package/docs/project-registry-schema.md +33 -33
  386. package/docs/release-5.0.16-acceptance.md +176 -176
  387. package/docs/release-5.0.17-acceptance.md +117 -117
  388. package/docs/release-5.0.19-acceptance.md +39 -39
  389. package/docs/team-knowledge-mode-a-plan.md +73 -73
  390. package/docs/testing-strategy.md +33 -33
  391. package/module-runtime-manifest.json +68 -65
  392. package/package.json +113 -110
  393. package/plugins/project-knowledge/.claude-plugin/plugin.json +1 -1
  394. package/plugins/project-knowledge/.codex-plugin/plugin.json +1 -1
  395. package/plugins/project-knowledge/.mcp.json +1 -1
  396. package/templates/change.md +30 -30
  397. package/templates/project-readme.md +52 -52
  398. package/ui/index.html +3 -2
  399. package/ui/version-info.css +44 -0
  400. package/ui/version-info.js +24 -0
  401. package/vendor-manifest.json +55 -55
@@ -0,0 +1,196 @@
1
+ 'use strict';
2
+ // Lane-owned helpers for the Workbench provenance batch (WB001).
3
+ //
4
+ // They answer one question with bytes, never with version strings:
5
+ // module-runtime-manifest.json <-> the currently installed package
6
+ // module-runtime-manifest.json <-> the Workbench source checkout
7
+ //
8
+ // A file is compared three ways, in this order:
9
+ // identical the raw sha256 equals the manifest hash
10
+ // eolOnly the sha256 differs but the CRLF-normalised content matches
11
+ // (npm tarballs ship LF, a Windows checkout carries CRLF)
12
+ // different the content really differs
13
+ //
14
+ // Every path is resolved from the repository location or from an explicit
15
+ // environment override, so nothing here depends on a developer directory.
16
+ const fs = require('node:fs');
17
+ const path = require('node:path');
18
+ const crypto = require('node:crypto');
19
+ const { execFileSync } = require('node:child_process');
20
+
21
+ const REPO_ROOT = path.resolve(__dirname, '..', '..', '..');
22
+ const MANIFEST_FILE = path.join(REPO_ROOT, 'module-runtime-manifest.json');
23
+
24
+ function sha256Buffer(value) {
25
+ return crypto.createHash('sha256').update(value).digest('hex');
26
+ }
27
+
28
+ // The same content with the line endings normalised to LF.
29
+ function normalizedSha256(value) {
30
+ return sha256Buffer(Buffer.from(value.toString('utf8').replace(/\r\n/g, '\n'), 'utf8'));
31
+ }
32
+
33
+ function sha256File(filePath) {
34
+ return fs.existsSync(filePath) ? sha256Buffer(fs.readFileSync(filePath)) : null;
35
+ }
36
+
37
+ function loadManifest() {
38
+ if (!fs.existsSync(MANIFEST_FILE)) throw new Error(`module manifest is missing: ${MANIFEST_FILE}`);
39
+ const manifest = JSON.parse(fs.readFileSync(MANIFEST_FILE, 'utf8'));
40
+ const terminal = manifest.modules && manifest.modules.terminal;
41
+ if (!terminal || !terminal.files || typeof terminal.files !== 'object') {
42
+ throw new Error('module manifest has no modules.terminal.files');
43
+ }
44
+ return {
45
+ file: MANIFEST_FILE,
46
+ schema: manifest.schema,
47
+ terminal,
48
+ files: terminal.files,
49
+ count: Object.keys(terminal.files).length,
50
+ };
51
+ }
52
+
53
+ function packageIdentity(root) {
54
+ const packageFile = path.join(root, 'package.json');
55
+ if (!fs.existsSync(packageFile)) return null;
56
+ const pkg = JSON.parse(fs.readFileSync(packageFile, 'utf8'));
57
+ return { root, packageFile, name: pkg.name, version: pkg.version };
58
+ }
59
+
60
+ // Classify every manifest file against a candidate tree.
61
+ function compareTree(manifestFiles, root) {
62
+ const identical = [];
63
+ const eolOnly = [];
64
+ const different = [];
65
+ const missing = [];
66
+ for (const [relative, expected] of Object.entries(manifestFiles)) {
67
+ const target = path.join(root, relative);
68
+ if (!fs.existsSync(target)) { missing.push(relative); continue; }
69
+ const content = fs.readFileSync(target);
70
+ if (sha256Buffer(content) === expected) { identical.push(relative); continue; }
71
+ if (normalizedSha256(content) === expected) { eolOnly.push(relative); continue; }
72
+ different.push(relative);
73
+ }
74
+ return {
75
+ root,
76
+ total: Object.keys(manifestFiles).length,
77
+ identical,
78
+ eolOnly,
79
+ different,
80
+ missing,
81
+ identicalCount: identical.length,
82
+ eolOnlyCount: eolOnly.length,
83
+ differentCount: different.length,
84
+ missingCount: missing.length,
85
+ };
86
+ }
87
+
88
+ // The package the repository pins: node_modules/claude-ai-workbench.
89
+ function resolveRepoTargetPackage() {
90
+ return path.join(REPO_ROOT, 'node_modules', 'claude-ai-workbench');
91
+ }
92
+
93
+ // The package the installed product (5.0.24) actually ships.
94
+ function resolveInstalledProductPackage() {
95
+ const override = String(process.env.PK_WB_INSTALLED_PRODUCT_MODULE || '').trim();
96
+ if (override) return fs.existsSync(override) ? override : null;
97
+ const appData = String(process.env.APPDATA || '').trim();
98
+ if (!appData) return null;
99
+ const candidate = path.join(appData, 'npm', 'node_modules', '@sanqianx', 'project-knowledge', 'node_modules', 'claude-ai-workbench');
100
+ return fs.existsSync(candidate) ? candidate : null;
101
+ }
102
+
103
+ function resolveInstalledProductRoot() {
104
+ const override = String(process.env.PK_WB_INSTALLED_PRODUCT_ROOT || '').trim();
105
+ if (override) return fs.existsSync(override) ? override : null;
106
+ const appData = String(process.env.APPDATA || '').trim();
107
+ if (!appData) return null;
108
+ const candidate = path.join(appData, 'npm', 'node_modules', '@sanqianx', 'project-knowledge');
109
+ return fs.existsSync(path.join(candidate, 'package.json')) ? candidate : null;
110
+ }
111
+
112
+ // The Workbench source checkout: an explicit override, or a sibling of this
113
+ // repository.
114
+ function resolveSourceCheckout() {
115
+ const override = String(process.env.PK_WB_SOURCE_DIR || '').trim();
116
+ const candidates = override ? [override] : [path.join(path.dirname(REPO_ROOT), 'claude-ai-workbench')];
117
+ for (const candidate of candidates) {
118
+ if (fs.existsSync(path.join(candidate, 'packages', 'server', 'package.json'))) return path.resolve(candidate);
119
+ }
120
+ return null;
121
+ }
122
+
123
+ // The commit the checkout currently stands on. This reads the working state
124
+ // of the checkout, never a historical object.
125
+ function sourceCommitId(root) {
126
+ if (!root) return null;
127
+ try {
128
+ const out = execFileSync('git', ['rev-parse', 'HEAD'], { cwd: root, windowsHide: true, encoding: 'utf8' });
129
+ return out.trim();
130
+ } catch {
131
+ return null;
132
+ }
133
+ }
134
+
135
+ function sourceWorkingTreeClean(root) {
136
+ if (!root) return null;
137
+ try {
138
+ const out = execFileSync('git', ['status', '--porcelain'], { cwd: root, windowsHide: true, encoding: 'utf8' });
139
+ return out.trim().length === 0;
140
+ } catch {
141
+ return null;
142
+ }
143
+ }
144
+
145
+ // Provenance trace against a historical commit of the source checkout.
146
+ // This reads Git objects and is therefore NOT part of the canonical test:
147
+ // it is evidence for the report, and it fails loudly when the commit or the
148
+ // Git history is unavailable.
149
+ function traceAgainstCommit(sourceRoot, commit, manifestFiles, packageRoot) {
150
+ if (!sourceRoot) throw new Error('source checkout is required to trace a commit');
151
+ const identical = [];
152
+ const different = [];
153
+ const absent = [];
154
+ for (const relative of Object.keys(manifestFiles)) {
155
+ let committed;
156
+ try {
157
+ committed = execFileSync('git', ['show', `${commit}:${relative}`], { cwd: sourceRoot, windowsHide: true, maxBuffer: 1 << 26 });
158
+ } catch {
159
+ absent.push(relative);
160
+ continue;
161
+ }
162
+ const shipped = fs.readFileSync(path.join(packageRoot, relative));
163
+ if (normalizedSha256(committed) === normalizedSha256(shipped)) identical.push(relative);
164
+ else different.push(relative);
165
+ }
166
+ return { commit, identical, different, absent, identicalCount: identical.length, differentCount: different.length, absentCount: absent.length };
167
+ }
168
+
169
+ // Which commits of the source checkout touch a given file, newest first.
170
+ function commitsTouchingFile(sourceRoot, relative, limit = 8) {
171
+ try {
172
+ const out = execFileSync('git', ['log', `--format=%h %s`, `-${limit}`, '--', relative], { cwd: sourceRoot, windowsHide: true, encoding: 'utf8' });
173
+ return out.split(/\r?\n/).map(line => line.trim()).filter(Boolean);
174
+ } catch {
175
+ return [];
176
+ }
177
+ }
178
+
179
+ module.exports = {
180
+ REPO_ROOT,
181
+ MANIFEST_FILE,
182
+ sha256Buffer,
183
+ normalizedSha256,
184
+ sha256File,
185
+ loadManifest,
186
+ packageIdentity,
187
+ compareTree,
188
+ resolveRepoTargetPackage,
189
+ resolveInstalledProductPackage,
190
+ resolveInstalledProductRoot,
191
+ resolveSourceCheckout,
192
+ sourceCommitId,
193
+ sourceWorkingTreeClean,
194
+ traceAgainstCommit,
195
+ commitsTouchingFile,
196
+ };
@@ -0,0 +1,106 @@
1
+ // _site/_test/helpers/spawn-server.js
2
+ //
3
+ // Test helper: spawn _site/server.js with an isolated KB_DATA_DIR so each
4
+ // regression test runs against a fresh, empty user-data location. Without
5
+ // this, server.js would default to ~/.project-knowledge/ and tests would
6
+ // pollute (or read from) the real user data.
7
+ //
8
+ // Usage:
9
+ // const { server, dataDir, cleanup } = require('./helpers/spawn-server');
10
+ // const { server, dataDir, cleanup } = spawnServer({
11
+ // root: ROOT,
12
+ // port: 7891,
13
+ // extraEnv: { KB_AUTOMATION_FAKE_CLAUDE: '1' },
14
+ // tag: 'hook-trigger',
15
+ // });
16
+ // ...
17
+ // cleanup(); // kills server + removes temp dataDir
18
+
19
+ const fs = require('fs');
20
+ const os = require('os');
21
+ const path = require('path');
22
+ const { spawn } = require('child_process');
23
+ const runtimeControl = require('../../lib/runtime-control');
24
+ const runtimeEndpoint = require('../../lib/runtime-endpoint');
25
+
26
+ function defaultDataDir(tag) {
27
+ return fs.mkdtempSync(path.join(os.tmpdir(), `kb-data-${tag || 'test'}-${process.pid}-`));
28
+ }
29
+
30
+ function spawnServer({ root, port, host = '127.0.0.1', dataDir, extraEnv = {}, tag, analysisOwner = 'legacy', stdio = ['ignore', 'pipe', 'pipe'], cwd }) {
31
+ const dir = dataDir || defaultDataDir(tag);
32
+ // Isolate the Bridge journal home too: the runtime registers a
33
+ // 'project-knowledge' consumer at startup, and without this the test
34
+ // server would write into the developer's real ~/.ai-coding-event-bridge.
35
+ const bridgeHome = fs.mkdtempSync(path.join(os.tmpdir(), `kb-bridge-${tag || 'test'}-${process.pid}-`));
36
+ // The knowledge root is a second product-owned location. A test must never
37
+ // inherit the developer's real knowledge directory through the environment,
38
+ // so give every isolated instance its own one.
39
+ const knowledgeDir = fs.mkdtempSync(path.join(os.tmpdir(), `kb-knowledge-${tag || 'test'}-${process.pid}-`));
40
+ // Legacy behavior tests characterize the retired writer in isolation. The
41
+ // production entry point still defaults to engine ownership; product tests
42
+ // explicitly request it and run the real module services.
43
+ const entry = path.join(root, '_site', 'lib', 'server-app.js');
44
+ // CI 40075242420 (normalhook, linux24): a startup rejection used to vanish —
45
+ // exit 1 with empty stdout/stderr — because this catch swallowed the reason.
46
+ // The failure path below prints the child's stderr tail, so emit one bounded
47
+ // JSON line of own metadata (code / message head / first stack frame's file
48
+ // only; never logs, keys or transcripts) and keep exit 1.
49
+ const bootstrap = `const {startServer,installProcessHandlers}=require(${JSON.stringify(entry)});const instance=startServer({analysisOwner:${JSON.stringify(analysisOwner)}});installProcessHandlers(instance);instance.then(s=>process.stdout.write('Project Knowledge listening on http://'+s.host+':'+s.port+'\\n')).catch(e=>{const frame=String(e&&e.stack||'').split('\\n')[1]||'';const fm=/([^\\\\/]+\\.[a-z]+):/i.exec(frame);process.stderr.write(JSON.stringify({event:'server.startup-fatal',code:e&&e.code||null,message:String(e&&e.message||e).slice(0,300),stackFile:fm?fm[1]:null})+'\\n');process.exitCode=1});`;
50
+ const child = spawn(process.execPath, ['-e', bootstrap], {
51
+ cwd: cwd || root,
52
+ env: {
53
+ ...process.env,
54
+ KB_SITE_PORT: String(port),
55
+ KB_SITE_HOST: host,
56
+ KB_DATA_DIR: dir,
57
+ KB_KNOWLEDGE_DATA_DIR: knowledgeDir,
58
+ KB_CLAUDE_RULES_DIR: dir,
59
+ KB_SKIP_MIGRATION: '1',
60
+ // 测试隔离:禁止测试服务器向真实模块(terminal/vector-hub)登记项目
61
+ KB_MODULES_REGISTER: '0',
62
+ KB_MODULES_AUTOSTART: '0',
63
+ // Disabling registration does not disable status/profile reads. Never
64
+ // let an isolated legacy test consult the developer's live modules.
65
+ // A test needing real modules supplies its own URLs in extraEnv below.
66
+ KB_TERMINAL_URL: 'http://127.0.0.1:0',
67
+ KB_VECTORHUB_URL: 'http://127.0.0.1:0',
68
+ KB_EVENTBRIDGE_URL: 'http://127.0.0.1:0',
69
+ KB_KNOWLEDGE_ENGINE_URL: 'http://127.0.0.1:0',
70
+ AI_CODING_EVENT_BRIDGE_HOME: bridgeHome,
71
+ ...extraEnv,
72
+ },
73
+ stdio,
74
+ windowsHide: true,
75
+ });
76
+ return {
77
+ child,
78
+ dataDir: dir,
79
+ bridgeHome,
80
+ knowledgeDir,
81
+ cleanup: async () => {
82
+ // On Windows SIGTERM is a force kill. Drain owned background work via
83
+ // the verified control channel first, so Git/Agent children release cwd.
84
+ const live = runtimeEndpoint.readEndpoint(dir);
85
+ if (live?.pid === child.pid && child.exitCode === null) {
86
+ try { await runtimeControl.request(dir, { action: 'stop', pid: live.pid, port: live.port, startedAt: live.startedAt }, 10000); } catch {}
87
+ await new Promise(resolve => {
88
+ const timer = setTimeout(resolve, 1500);
89
+ child.once('close', () => { clearTimeout(timer); resolve(); });
90
+ if (child.exitCode !== null) { clearTimeout(timer); resolve(); }
91
+ });
92
+ }
93
+ if (child.exitCode === null) try { child.kill(); } catch {}
94
+ await new Promise(resolve => {
95
+ const timer = setTimeout(resolve, 5000);
96
+ child.once('close', () => { clearTimeout(timer); resolve(); });
97
+ if (child.exitCode !== null) { clearTimeout(timer); resolve(); }
98
+ });
99
+ await fs.promises.rm(dir, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
100
+ await fs.promises.rm(bridgeHome, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
101
+ await fs.promises.rm(knowledgeDir, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
102
+ },
103
+ };
104
+ }
105
+
106
+ module.exports = { spawnServer, defaultDataDir };
@@ -0,0 +1,251 @@
1
+ 'use strict';
2
+ // FEATURE-VERSIONS-01-R2 fixture — the version-visibility lane's own isolation
3
+ // contract, borrowed from the accepted drafts-r5 fixture (read-only reuse of
4
+ // its patterns; that file stays untouched):
5
+ // * every directory lives under a repo-external temp root (PK_TEST_TEMP_ROOT
6
+ // → repo-parent shared root when it exists → TEMP/TMP/TMPDIR → os.tmpdir),
7
+ // never inside the repository, never on a hardcoded drive/user dir;
8
+ // * the full env whitelist (HOME/USERPROFILE/HOMEDRIVE/HOMEPATH/CODEX_HOME/
9
+ // CLAUDE_CONFIG_DIR/APPDATA/LOCALAPPDATA/TEMP/TMP/TMPDIR/双 KB_DATA_DIR/
10
+ // Bridge home/Workbench data) is absolute-pathed into one per-run layout
11
+ // root; ambient module addresses and Anthropic credentials are stripped;
12
+ // * the live product ports 5757/5760/5789/5790/8787/8790 are refused;
13
+ // * Chrome is resolved from the REAL machine before any isolation is applied
14
+ // (find-chrome reads the real environment), then run with an isolated
15
+ // --user-data-dir plus the Chrome>=136 empty-default-dir scaffold under the
16
+ // isolated home so remote debugging is accepted.
17
+ const fs = require('node:fs');
18
+ const os = require('node:os');
19
+ const path = require('node:path');
20
+ const net = require('node:net');
21
+ const { findChromeDetailed } = require('./find-chrome');
22
+
23
+ const REPO_ROOT = path.resolve(__dirname, '..', '..', '..');
24
+ const FORBIDDEN_PORTS = new Set([5757, 5760, 5789, 5790, 8787, 8790]);
25
+
26
+ const AMBIENT_MODULE_URLS = [
27
+ 'KB_KNOWLEDGE_ENGINE_URL', 'KB_VECTORHUB_URL', 'KB_TERMINAL_URL', 'KB_EVENTBRIDGE_URL', 'KB_EVENT_BRIDGE_URL',
28
+ 'KB_WORKBENCH_RUNTIME_TOKEN', 'KB_MODULES_AUTOSTART',
29
+ ];
30
+ const AMBIENT_MODEL_ENV = [
31
+ 'ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN', 'ANTHROPIC_BASE_URL', 'ANTHROPIC_MODEL',
32
+ 'ANTHROPIC_DEFAULT_THINKING_MODEL', 'ANTHROPIC_DEFAULT_HAIKU_MODEL', 'ANTHROPIC_DEFAULT_SONNET_MODEL',
33
+ 'ANTHROPIC_DEFAULT_OP_MODEL', 'API_TIMEOUT_MS', 'CLAUDE_CODE_OAUTH_TOKEN',
34
+ 'CLAUDE_CODE_USE_BEDROCK', 'CLAUDE_CODE_USE_VERTEX', 'CLAUDE_CODE_USE_FOUNDRY',
35
+ ];
36
+
37
+ const ISOLATION_PATH_KEYS = [
38
+ 'HOME', 'USERPROFILE', 'CODEX_HOME', 'CLAUDE_CONFIG_DIR', 'APPDATA', 'LOCALAPPDATA',
39
+ 'TEMP', 'TMP', 'TMPDIR', 'KB_DATA_DIR', 'KB_KNOWLEDGE_DATA_DIR',
40
+ 'AI_CODING_EVENT_BRIDGE_HOME', 'AGENT_TERMINAL_DATA_DIR', 'CLAUDE_AI_WORKBENCH_DATA_DIR',
41
+ ];
42
+
43
+ // Captured at module load, BEFORE any isolation could hide the real machine:
44
+ // the browser binary this lane's UI acceptance will drive.
45
+ const CHROME_PATH = findChromeDetailed().path;
46
+
47
+ function isInside(candidate, parent) {
48
+ const relative = path.relative(parent, candidate);
49
+ return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
50
+ }
51
+
52
+ function resolveTempRoot() {
53
+ const sharedRoot = path.join(path.dirname(REPO_ROOT), '.project-knowledge-test-temp');
54
+ const candidates = [process.env.PK_TEST_TEMP_ROOT, fs.existsSync(sharedRoot) ? sharedRoot : null, process.env.TEMP, process.env.TMP, process.env.TMPDIR];
55
+ const chosen = candidates.find(value => value && String(value).trim());
56
+ const root = path.resolve(chosen ? String(chosen).trim() : os.tmpdir());
57
+ if (isInside(root, REPO_ROOT)) throw new Error(`refusing to use a temp root inside the repository: ${root}`);
58
+ return root;
59
+ }
60
+
61
+ function makeTempDir(prefix = 'version-visibility') {
62
+ const root = resolveTempRoot();
63
+ fs.mkdirSync(root, { recursive: true });
64
+ const dir = fs.mkdtempSync(path.join(root, `${prefix}-`));
65
+ if (isInside(dir, REPO_ROOT)) throw new Error(`refusing to create a fixture inside the repository: ${dir}`);
66
+ return dir;
67
+ }
68
+
69
+ function removeTree(dir) {
70
+ if (!dir) return;
71
+ fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
72
+ }
73
+
74
+ async function freePort() {
75
+ return new Promise((resolve, reject) => {
76
+ const server = net.createServer();
77
+ server.unref();
78
+ server.on('error', reject);
79
+ server.listen(0, '127.0.0.1', () => {
80
+ const { port } = server.address();
81
+ server.close(() => {
82
+ if (FORBIDDEN_PORTS.has(Number(port))) { reject(new Error(`refusing to use the live port ${port}`)); return; }
83
+ resolve(Number(port));
84
+ });
85
+ });
86
+ });
87
+ }
88
+
89
+ function assertAllowedEndpoint(url, what = 'endpoint') {
90
+ const parsed = new URL(String(url));
91
+ const port = parsed.port ? Number(parsed.port) : (parsed.protocol === 'https:' ? 443 : 80);
92
+ if (FORBIDDEN_PORTS.has(port)) throw new Error(`refusing to contact the live ${what} ${url}`);
93
+ return url;
94
+ }
95
+
96
+ async function waitForHttp(url, timeoutMs = 45000) {
97
+ assertAllowedEndpoint(url, 'service');
98
+ const until = Date.now() + timeoutMs;
99
+ let lastError = null;
100
+ while (Date.now() < until) {
101
+ try {
102
+ const response = await fetch(url, { signal: AbortSignal.timeout(2000) });
103
+ if (response.ok) return true;
104
+ lastError = new Error(`HTTP ${response.status}`);
105
+ } catch (error) { lastError = error; }
106
+ await new Promise(resolve => setTimeout(resolve, 120));
107
+ }
108
+ throw new Error(`Timed out waiting for ${url}: ${lastError && lastError.message}`);
109
+ }
110
+
111
+ function sanitizedEnv(extra = {}, source = process.env) {
112
+ const env = {};
113
+ const systemKey = /^(?:PATH|PATHEXT|SYSTEMROOT|WINDIR|SYSTEMDRIVE|COMSPEC|OS|PROCESSOR_ARCHITECTURE|PROCESSOR_IDENTIFIER|PROCESSOR_LEVEL|PROCESSOR_REVISION|NUMBER_OF_PROCESSORS|PROGRAMFILES(?:\(X86\))?|PROGRAMW6432|PROGRAMDATA|LANG|LC_ALL|LC_CTYPE|TERM)$/i;
114
+ for (const [key, value] of Object.entries(source)) {
115
+ if (systemKey.test(key)) env[key] = value;
116
+ }
117
+ // Only the inherited environment is filtered. Explicit lane URLs and the
118
+ // disabled autostart flag must survive, or the server uses live defaults.
119
+ return { ...env, ...extra };
120
+ }
121
+
122
+ function spawnNode(args, env = {}) {
123
+ const { spawn } = require('node:child_process');
124
+ const child = spawn(process.execPath, args, { env: sanitizedEnv(env), windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'] });
125
+ const output = { stdout: '', stderr: '' };
126
+ child.stdout.on('data', chunk => { output.stdout += chunk; });
127
+ child.stderr.on('data', chunk => { output.stderr += chunk; });
128
+ const exited = new Promise(resolve => child.once('close', code => resolve({ code, ...output })));
129
+ return { child, exited, output };
130
+ }
131
+
132
+ function createIsolationLayout(prefix = 'version-visibility') {
133
+ const root = makeTempDir(prefix);
134
+ const layout = {
135
+ root,
136
+ dataDir: path.join(root, 'kb-data'),
137
+ knowledgeDataDir: path.join(root, 'knowledge-data'),
138
+ bridgeHome: path.join(root, 'bridge-home'),
139
+ workbenchDataDir: path.join(root, 'workbench-data'),
140
+ home: path.join(root, 'home'),
141
+ claudeConfigDir: path.join(root, 'claude-config'),
142
+ codexHome: path.join(root, 'codex-home'),
143
+ appData: path.join(root, 'appdata'),
144
+ localAppData: path.join(root, 'localappdata'),
145
+ temp: path.join(root, 'temp'),
146
+ };
147
+ for (const dir of Object.values(layout)) fs.mkdirSync(dir, { recursive: true });
148
+ // Chrome >= 136 gate: an empty default-shaped "User Data" scaffold under the
149
+ // ISOLATED home lets the default-dir resolution succeed, so the separate
150
+ // --user-data-dir browser profile below this layout is accepted. Nothing of
151
+ // the real machine is touched.
152
+ fs.mkdirSync(path.join(layout.home, 'AppData', 'Local', 'Google', 'Chrome', 'User Data'), { recursive: true });
153
+ fs.mkdirSync(path.join(layout.home, 'AppData', 'Roaming'), { recursive: true });
154
+ return layout;
155
+ }
156
+
157
+ function isolationEnvMap(layout, extraPaths = {}) {
158
+ const parsed = path.parse(layout.home);
159
+ return {
160
+ HOME: layout.home,
161
+ USERPROFILE: layout.home,
162
+ HOMEDRIVE: parsed.root,
163
+ HOMEPATH: parsed.root === path.sep ? layout.home.slice(1) : layout.home.slice(parsed.root.length),
164
+ CODEX_HOME: layout.codexHome,
165
+ CLAUDE_CONFIG_DIR: layout.claudeConfigDir,
166
+ APPDATA: layout.appData,
167
+ LOCALAPPDATA: layout.localAppData,
168
+ TEMP: layout.temp,
169
+ TMP: layout.temp,
170
+ TMPDIR: layout.temp,
171
+ PSModuleAnalysisCachePath: path.join(layout.temp, 'powershell-module-cache'),
172
+ KB_DATA_DIR: layout.dataDir,
173
+ KB_KNOWLEDGE_DATA_DIR: layout.knowledgeDataDir,
174
+ AI_CODING_EVENT_BRIDGE_HOME: layout.bridgeHome,
175
+ AGENT_TERMINAL_DATA_DIR: layout.workbenchDataDir,
176
+ CLAUDE_AI_WORKBENCH_DATA_DIR: layout.workbenchDataDir,
177
+ KB_MODULES_AUTOSTART: '0',
178
+ ...extraPaths,
179
+ };
180
+ }
181
+
182
+ function hostEnv(layout, extra = {}) {
183
+ return sanitizedEnv(isolationEnvMap(layout, extra));
184
+ }
185
+
186
+ function applyIsolationEnv(layout) {
187
+ const env = hostEnv(layout);
188
+ for (const key of Object.keys(process.env)) delete process.env[key];
189
+ Object.assign(process.env, env);
190
+ }
191
+
192
+ // The product server under test: real _site/server.js, fully isolated, with
193
+ // every module address explicitly held on this run's own free ports (so the
194
+ // process can never reach for the live defaults 5760/8787/8790/5790).
195
+ async function startRootServer(layout, options = {}) {
196
+ const port = options.port || await freePort();
197
+ const [terminalPort, vectorHubPort, eventBridgePort, enginePort] = await Promise.all([freePort(), freePort(), freePort(), freePort()]);
198
+ const env = hostEnv(layout, {
199
+ KB_SITE_PORT: String(port),
200
+ KB_SITE_HOST: '127.0.0.1',
201
+ KB_TERMINAL_URL: `http://127.0.0.1:${terminalPort}`,
202
+ KB_VECTORHUB_URL: `http://127.0.0.1:${vectorHubPort}`,
203
+ KB_EVENTBRIDGE_URL: `http://127.0.0.1:${eventBridgePort}`,
204
+ KB_KNOWLEDGE_ENGINE_URL: `http://127.0.0.1:${enginePort}`,
205
+ });
206
+ const runner = spawnNode([path.join(REPO_ROOT, '_site', 'server.js')], env);
207
+ const base = `http://127.0.0.1:${port}`;
208
+ await waitForHttp(`${base}/api/system/version`);
209
+ return { layout, port, base, runner, modulePorts: { terminalPort, vectorHubPort, eventBridgePort, enginePort } };
210
+ }
211
+
212
+ async function stopRootServer(server) {
213
+ if (!server || !server.runner) return;
214
+ server.runner.child.kill();
215
+ await server.runner.exited;
216
+ }
217
+
218
+ // The honest-unknown branch: serve the REAL ui/ assets from disk, but fail the
219
+ // version GET — the tooltip must then say 版本未知 instead of inventing one.
220
+ async function startVersionBrokenUiServer(layout, options = {}) {
221
+ const port = options.port || await freePort();
222
+ const uiRoot = path.join(REPO_ROOT, 'ui');
223
+ const types = { '.html': 'text/html; charset=utf-8', '.js': 'text/javascript; charset=utf-8', '.css': 'text/css; charset=utf-8', '.svg': 'image/svg+xml' };
224
+ const http = require('node:http');
225
+ const server = http.createServer((req, res) => {
226
+ const pathname = new URL(req.url, 'http://127.0.0.1').pathname;
227
+ if (pathname === '/api/system/version') {
228
+ res.writeHead(503, { 'Content-Type': 'application/json' });
229
+ res.end(JSON.stringify({ ok: false }));
230
+ return;
231
+ }
232
+ const rel = pathname === '/' ? 'index.html' : pathname.replace(/^\//, '');
233
+ const file = path.join(uiRoot, rel);
234
+ if (!isInside(path.resolve(file), uiRoot) || !fs.existsSync(file) || !fs.statSync(file).isFile()) {
235
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
236
+ res.end('Not found');
237
+ return;
238
+ }
239
+ res.writeHead(200, { 'Content-Type': types[path.extname(file)] || 'application/octet-stream' });
240
+ res.end(fs.readFileSync(file));
241
+ });
242
+ await new Promise(resolve => server.listen(port, '127.0.0.1', resolve));
243
+ return { layout, port, base: `http://127.0.0.1:${port}`, server };
244
+ }
245
+
246
+ module.exports = {
247
+ REPO_ROOT, FORBIDDEN_PORTS, AMBIENT_MODULE_URLS, AMBIENT_MODEL_ENV, ISOLATION_PATH_KEYS,
248
+ CHROME_PATH, resolveTempRoot, makeTempDir, removeTree, freePort, assertAllowedEndpoint,
249
+ waitForHttp, sanitizedEnv, spawnNode, createIsolationLayout, isolationEnvMap, hostEnv, applyIsolationEnv,
250
+ startRootServer, stopRootServer, startVersionBrokenUiServer,
251
+ };