@sanqianx/project-knowledge 5.0.24 → 5.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +66 -63
  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,389 @@
1
+ // _site/_test/helpers/parallel-nav-isolation-env.js
2
+ //
3
+ // P-NAV-VECTOR-ISOLATION-R7: the driver-level environment whitelist for the
4
+ // NAV lane harness. The incident this exists for: parallel-nav-shell.js used
5
+ // to create the real engine WITHOUT an explicit vectorUrl, so the engine kept
6
+ // its constructor default (http://127.0.0.1:8787 = the developer's LIVE
7
+ // desktop vector-hub) and NAV-007's core-source-regression run wrote a real
8
+ // collection there (2026-10-23T18:00:54Z; recovered by
9
+ // P-VECTOR-INCIDENT-RECOVERY-R6). Driving full-env directory variables from a
10
+ // test is NOT enough to override constructor defaults, so the harness now
11
+ // (a) passes an explicit vectorUrl (see parallel-nav-shell.js) and (b) puts
12
+ // the whole driver — and every child that inherits process.env — under the
13
+ // explicit whitelist below.
14
+ //
15
+ // Contract (call order matters, enforced by the harness):
16
+ // 1. the harness resolves Chrome under the REAL environment first
17
+ // (read-only discovery);
18
+ // 2. enterNavIsolation() builds the whitelist environment and mutates
19
+ // process.env — BEFORE any engine/product module is loaded or any child
20
+ // is spawned;
21
+ // 3. restore() puts the original values back after cleanup, and the stable
22
+ // parent temp root SURVIVES serial harness runs in one process (only the
23
+ // process-exit hook removes it), so a later os.tmpdir() never points at
24
+ // a deleted directory.
25
+ //
26
+ // The whitelist keeps only OS-critical variables; every directory the product
27
+ // family consults (HOME/USERPROFILE/HOMEDRIVE+HOMEPATH/CODEX_HOME/
28
+ // CLAUDE_CONFIG_DIR/APPDATA/LOCALAPPDATA/TEMP/TMP/TMPDIR/KB_DATA_DIR/
29
+ // KB_KNOWLEDGE_DATA_DIR/AI_CODING_EVENT_BRIDGE_HOME/AGENT_TERMINAL_DATA_DIR/
30
+ // CLAUDE_AI_WORKBENCH_DATA_DIR/PSModuleAnalysisCachePath) points into one
31
+ // short repo-external fixture root, and the Chrome default-profile shape
32
+ // (<isolated USERPROFILE>/AppData/Local/Google/Chrome/User Data) is created
33
+ // so Chrome's own default paths resolve inside isolation. Ambient module
34
+ // URLs, model-provider credentials, proxy variables and CLI-injection
35
+ // variables are deleted; the harness adds its explicit lane endpoints only
36
+ // AFTER the whitelist is in place.
37
+ //
38
+ // P-NAV-POSIX-CI-R9: on POSIX the fixture path length is a hard correctness
39
+ // constraint, not cosmetics. Chrome places its SingletonSocket under TMPDIR
40
+ // (<root>/com.google.Chrome.<rand>/SingletonSocket) and the product's
41
+ // runtime-control channel lives at <dataDir>/runtime-control.sock
42
+ // (_site/lib/runtime-control.js) — both are UNIX domain sockets bound by the
43
+ // 108-byte sun_path limit. The descriptive R7 component names
44
+ // (pk-nav-r7-<pid>-<rand>/<full-tag>-<rand>) blew that budget on GH runners
45
+ // (CI 40011886791: a 120-char SingletonSocket aborted Chrome with SIGABRT
46
+ // and starved product bootstrap). POSIX now uses short components (pkn…/n…/t
47
+ // layout), keeps the full tag in an on-disk owner.json, prefers the external
48
+ // configured temp root when one is available, and fails fast when the
49
+ // worst-case socket path would exceed the budget. The real-home leak scan is
50
+ // also placement-aware: on hosted runners the owned temp root legitimately
51
+ // lives UNDER the real home (/home/runner/work/_temp), so a value is a leak
52
+ // only when it is outside the owned root while still referencing the real
53
+ // home (canonical containment), never merely because of a shared prefix.
54
+
55
+ 'use strict';
56
+
57
+ const fs = require('node:fs');
58
+ const os = require('node:os');
59
+ const path = require('node:path');
60
+
61
+ // Captured at module load, before any isolation changes the environment.
62
+ const REAL_HOME = os.homedir();
63
+ const REAL_USERPROFILE = process.env.USERPROFILE || REAL_HOME;
64
+ const REPO_ROOT = path.resolve(__dirname, '..', '..', '..');
65
+
66
+ /** OS-critical variables a Windows child may keep. Nothing else survives. */
67
+ const OS_WHITELIST = [
68
+ 'SystemRoot', 'SystemDrive', 'windir', 'ComSpec', 'PATHEXT', 'PATH',
69
+ 'OS', 'NUMBER_OF_PROCESSORS',
70
+ 'PROCESSOR_ARCHITECTURE', 'PROCESSOR_IDENTIFIER', 'PROCESSOR_LEVEL', 'PROCESSOR_REVISION',
71
+ 'COMPUTERNAME', 'USERNAME', 'USERDOMAIN',
72
+ 'PROGRAMDATA', 'ProgramFiles', 'ProgramFiles(x86)', 'ProgramW6432',
73
+ 'CommonProgramFiles', 'CommonProgramFiles(x86)', 'CommonProgramW6432',
74
+ 'DriverData',
75
+ ];
76
+
77
+ /** Directory variables the isolation overrides; every one lands inside the fixture root. */
78
+ const ISOLATION_KEYS = [
79
+ 'HOME', 'USERPROFILE', 'HOMEDRIVE', 'HOMEPATH',
80
+ 'CODEX_HOME', 'CLAUDE_CONFIG_DIR', 'APPDATA', 'LOCALAPPDATA',
81
+ 'TEMP', 'TMP', 'TMPDIR',
82
+ 'KB_DATA_DIR', 'KB_KNOWLEDGE_DATA_DIR',
83
+ 'AI_CODING_EVENT_BRIDGE_HOME', 'AGENT_TERMINAL_DATA_DIR', 'CLAUDE_AI_WORKBENCH_DATA_DIR',
84
+ 'PSModuleAnalysisCachePath',
85
+ ];
86
+
87
+ /** Deleted outright: ambient module URLs (incl. the engine's own env var), model-provider credentials, proxies, CLI injection. */
88
+ const AMBIENT_DELETES = [
89
+ 'KB_KNOWLEDGE_ENGINE_URL', 'KB_VECTORHUB_URL', 'KB_TERMINAL_URL', 'KB_EVENTBRIDGE_URL',
90
+ 'KB_EVENT_BRIDGE_URL', 'KB_VECTOR_HUB_URL', 'KB_WORKBENCH_RUNTIME_TOKEN', 'KB_MODULES_REGISTER',
91
+ 'KB_CHROME_PATH',
92
+ 'ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN', 'ANTHROPIC_BASE_URL', 'ANTHROPIC_MODEL',
93
+ 'ANTHROPIC_DEFAULT_THINKING_MODEL', 'ANTHROPIC_DEFAULT_HAIKU_MODEL',
94
+ 'ANTHROPIC_DEFAULT_SONNET_MODEL', 'ANTHROPIC_DEFAULT_OPUS_MODEL', 'API_TIMEOUT_MS',
95
+ 'CLAUDE_CODE_OAUTH_TOKEN', 'CLAUDE_CODE_USE_BEDROCK', 'CLAUDE_CODE_USE_VERTEX', 'CLAUDE_CODE_USE_FOUNDRY',
96
+ 'CLAUDE_CODE_ENTRYPOINT', 'CLAUDE_CODE_SSE_PORT', 'CLAUDECODE',
97
+ 'MINIMAX_API_KEY', 'MINIMAX_BASE_URL', 'MINIMAX_MODEL',
98
+ 'OPENAI_API_KEY', 'OPENAI_BASE_URL',
99
+ 'NODE_OPTIONS', 'NODE_PATH', 'NODE_PRELOAD',
100
+ 'HTTP_PROXY', 'HTTPS_PROXY', 'ALL_PROXY', 'NO_PROXY',
101
+ 'http_proxy', 'https_proxy', 'all_proxy', 'no_proxy',
102
+ 'PSModulePath',
103
+ ];
104
+
105
+ function isInside(candidate, parent) {
106
+ const relative = path.relative(parent, candidate);
107
+ return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
108
+ }
109
+
110
+ // Windows environment names arrive case-preserved (git-bash exports
111
+ // SYSTEMROOT while cmd exports SystemRoot); membership must not depend on
112
+ // the caller's casing.
113
+ const upper = value => String(value).toUpperCase();
114
+ const OS_WHITELIST_UPPER = () => new Set(OS_WHITELIST.map(upper));
115
+ const isOsWhitelisted = key => OS_WHITELIST_UPPER().has(upper(key));
116
+
117
+ /**
118
+ * A short repo-external temp root (same convention as the R5 lane). The
119
+ * fallback chain is resolved from values captured at MODULE LOAD — a poisoned
120
+ * or later-mutated process.env.TEMP must not steer the run root into the real
121
+ * home (the negative case proves exactly this).
122
+ */
123
+ const LOADED_TEMP_ROOT = (process.env.PK_TEST_TEMP_ROOT || process.env.TEMP || process.env.TMP || os.tmpdir());
124
+
125
+ // R9 POSIX socket budget: sun_path is 108 bytes including the NUL terminator,
126
+ // so 107 characters is the hard ceiling. The worst-case consumer is Chrome's
127
+ // SingletonSocket under the isolated TMPDIR; the suffix rand is observed at
128
+ // ~6 chars but budgeted at 12, and the budget counts UTF-8 BYTES, not chars.
129
+ const POSIX_SOCKET_CHAR_LIMIT = 107;
130
+ const CHROME_RAND_MAX_CHARS = 12;
131
+
132
+ /** Worst-case POSIX socket paths the fixture root must be able to host. */
133
+ function worstCasePosixSocketPaths(root) {
134
+ const base = String(root).replaceAll('\\', '/').replace(/\/+$/, '');
135
+ return {
136
+ chromeSingletonSocket: `${base}/t/com.google.Chrome.${'x'.repeat(CHROME_RAND_MAX_CHARS)}/SingletonSocket`,
137
+ productRuntimeControlSock: `${base}/data/runtime-control.sock`,
138
+ };
139
+ }
140
+
141
+ function posixSocketBudgetVerdict(root, limit = POSIX_SOCKET_CHAR_LIMIT) {
142
+ const paths = worstCasePosixSocketPaths(root);
143
+ const chromeSocketBytes = Buffer.byteLength(paths.chromeSingletonSocket, 'utf8');
144
+ const controlSocketBytes = Buffer.byteLength(paths.productRuntimeControlSock, 'utf8');
145
+ return {
146
+ ok: chromeSocketBytes <= limit && controlSocketBytes <= limit,
147
+ limit, chromeSocketBytes, controlSocketBytes, paths,
148
+ };
149
+ }
150
+
151
+ /** Fail fast — with the computed path in the message — when the budget cannot hold. */
152
+ function assertPosixSocketBudget(root, what) {
153
+ const verdict = posixSocketBudgetVerdict(root);
154
+ if (!verdict.ok) {
155
+ throw new Error(
156
+ `POSIX socket path budget exceeded for ${what}: worst-case Chrome SingletonSocket is ${verdict.chromeSocketBytes} UTF-8 bytes, limit is ${verdict.limit} — ${verdict.paths.chromeSingletonSocket}`,
157
+ );
158
+ }
159
+ return verdict;
160
+ }
161
+
162
+ const IS_POSIX = process.platform !== 'win32';
163
+
164
+ function resolveNavTempRoot() {
165
+ const sharedRoot = path.join(path.dirname(REPO_ROOT), '.project-knowledge-test-temp');
166
+ // Windows keeps the R7 order (shared sibling root first). POSIX prefers the
167
+ // external configured temp (PK_TEST_TEMP_ROOT, then the OS temp captured at
168
+ // module load) over the long sibling shared root: every byte of the root is
169
+ // spent by every socket beneath it (R9).
170
+ const candidates = IS_POSIX
171
+ ? [
172
+ LOADED_TEMP_ROOT === process.env.PK_TEST_TEMP_ROOT ? LOADED_TEMP_ROOT : null,
173
+ LOADED_TEMP_ROOT,
174
+ fs.existsSync(sharedRoot) ? sharedRoot : null,
175
+ ]
176
+ : [
177
+ LOADED_TEMP_ROOT === process.env.PK_TEST_TEMP_ROOT ? LOADED_TEMP_ROOT : null,
178
+ fs.existsSync(sharedRoot) ? sharedRoot : null,
179
+ LOADED_TEMP_ROOT,
180
+ ];
181
+ const chosen = candidates.find(value => value && String(value).trim());
182
+ const root = path.resolve(String(chosen).trim());
183
+ if (isInside(root, REPO_ROOT)) throw new Error(`refusing to use a temp root inside the repository: ${root}`);
184
+ return root;
185
+ }
186
+
187
+ let stableRoot = null;
188
+ let exitHookArmed = false;
189
+ /** Per-process parent temp: stable across serial harness runs, removed at process exit. */
190
+ function stableTempRoot() {
191
+ if (!stableRoot) {
192
+ const prefix = IS_POSIX ? `pkn${process.pid.toString(36)}` : `pk-nav-r7-${process.pid}-`;
193
+ stableRoot = fs.mkdtempSync(path.join(resolveNavTempRoot(), prefix));
194
+ if (!exitHookArmed) {
195
+ exitHookArmed = true;
196
+ process.on('exit', () => { try { fs.rmSync(stableRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* best effort */ } });
197
+ }
198
+ }
199
+ return stableRoot;
200
+ }
201
+
202
+ function buildLayout(root) {
203
+ const layout = {
204
+ home: path.join(root, 'home'),
205
+ codexHome: path.join(root, 'codex-home'),
206
+ claudeConfigDir: path.join(root, 'claude-config'),
207
+ appData: path.join(root, 'appdata'),
208
+ localAppData: path.join(root, 'localappdata'),
209
+ // 't' on POSIX: three fewer bytes on every Chrome socket path (R9).
210
+ temp: path.join(root, IS_POSIX ? 't' : 'temp'),
211
+ dataDir: path.join(root, 'kb-data'),
212
+ knowledgeDataDir: path.join(root, 'kb-knowledge-data'),
213
+ bridgeHome: path.join(root, 'bridge-home'),
214
+ agentTerminalDataDir: path.join(root, 'agent-terminal'),
215
+ workbenchDataDir: path.join(root, 'workbench-data'),
216
+ };
217
+ for (const dir of Object.values(layout)) fs.mkdirSync(dir, { recursive: true });
218
+ // Chrome's default-profile shape under the isolated USERPROFILE: Chrome
219
+ // resolves it even when launched with an explicit --user-data-dir, and no
220
+ // Node/GUI child keeps the real USERPROFILE.
221
+ layout.chromeDefaultProfileDir = path.join(layout.home, 'AppData', 'Local', 'Google', 'Chrome', 'User Data');
222
+ fs.mkdirSync(layout.chromeDefaultProfileDir, { recursive: true });
223
+ layout.psCachePath = path.join(root, 'ps-module-analysis-cache.bin');
224
+ return layout;
225
+ }
226
+
227
+ function isolationEnvMap(layout) {
228
+ const parsed = path.parse(layout.home);
229
+ return {
230
+ HOME: layout.home,
231
+ USERPROFILE: layout.home,
232
+ HOMEDRIVE: parsed.root,
233
+ HOMEPATH: layout.home.slice(parsed.root.length),
234
+ CODEX_HOME: layout.codexHome,
235
+ CLAUDE_CONFIG_DIR: layout.claudeConfigDir,
236
+ APPDATA: layout.appData,
237
+ LOCALAPPDATA: layout.localAppData,
238
+ TEMP: layout.temp,
239
+ TMP: layout.temp,
240
+ TMPDIR: layout.temp,
241
+ KB_DATA_DIR: layout.dataDir,
242
+ KB_KNOWLEDGE_DATA_DIR: layout.knowledgeDataDir,
243
+ AI_CODING_EVENT_BRIDGE_HOME: layout.bridgeHome,
244
+ AGENT_TERMINAL_DATA_DIR: layout.agentTerminalDataDir,
245
+ CLAUDE_AI_WORKBENCH_DATA_DIR: layout.workbenchDataDir,
246
+ KB_MODULES_AUTOSTART: '0',
247
+ PSModuleAnalysisCachePath: layout.psCachePath,
248
+ };
249
+ }
250
+
251
+ /**
252
+ * Whitelist the driver environment in place. Returns the per-run isolation
253
+ * context; the caller MUST call restore() after cleanup (serial runs reuse
254
+ * the stable parent temp, which is only removed at process exit).
255
+ */
256
+ function enterNavIsolation({ tag = 'run' } = {}) {
257
+ // POSIX shortens the case component to 'n<rand6>' (R9 socket budget);
258
+ // Windows keeps the descriptive '<tag>-<rand6>' names.
259
+ const casePrefix = IS_POSIX ? 'n' : `${tag}-`;
260
+ const root = fs.mkdtempSync(path.join(stableTempRoot(), casePrefix));
261
+ if (IS_POSIX) {
262
+ try {
263
+ assertPosixSocketBudget(root, `isolation root for tag ${tag}`);
264
+ } catch (error) {
265
+ try { fs.rmSync(root, { recursive: true, force: true }); } catch { /* best effort */ }
266
+ throw error;
267
+ }
268
+ }
269
+ const layout = buildLayout(root);
270
+
271
+ // The shortened POSIX component names must not cost post-mortem ownership
272
+ // binding anything: the full tag, pid and creation time stay on disk.
273
+ fs.writeFileSync(path.join(root, 'owner.json'), JSON.stringify({
274
+ schema: 'qa-autopilot/nav-isolation-owner/v1',
275
+ tag,
276
+ platform: process.platform,
277
+ pid: process.pid,
278
+ createdAt: new Date().toISOString(),
279
+ }, null, 2) + '\n', 'utf8');
280
+
281
+ const previous = {};
282
+ for (const key of Object.keys(process.env)) previous[key] = process.env[key];
283
+
284
+ // R9 redirection evidence (booleans only — original values may carry real
285
+ // secrets): which isolation keys pointed at the real home BEFORE the
286
+ // whitelist, so the report can prove every one was redirected into the
287
+ // owned root rather than merely overwritten with another leak.
288
+ const originalInsideRealHome = {};
289
+ for (const key of ISOLATION_KEYS) {
290
+ const original = previous[key];
291
+ originalInsideRealHome[key] = original !== undefined
292
+ && (isInside(path.resolve(String(original)), REAL_HOME) || isInside(path.resolve(String(original)), REAL_USERPROFILE));
293
+ }
294
+
295
+ for (const key of Object.keys(process.env)) {
296
+ if (!isOsWhitelisted(key)) delete process.env[key];
297
+ }
298
+ Object.assign(process.env, isolationEnvMap(layout));
299
+
300
+ return {
301
+ tag, root, layout,
302
+ posixShortRoot: IS_POSIX,
303
+ originalInsideRealHome,
304
+ envMap: isolationEnvMap(layout),
305
+ realHome: REAL_HOME,
306
+ realUserProfile: REAL_USERPROFILE,
307
+ /** Put the original environment back; keeps the stable parent temp alive. */
308
+ restore() {
309
+ for (const key of Object.keys(process.env)) delete process.env[key];
310
+ Object.assign(process.env, previous);
311
+ },
312
+ };
313
+ }
314
+
315
+ /**
316
+ * Placement-aware real-home scan (R9). A non-OS-whitelisted env value is a
317
+ * leak ONLY when it references the real home while NOT being canonically
318
+ * inside the owned isolation root: on hosted runners the owned temp root
319
+ * legitimately lives UNDER the real home (/home/runner/work/_temp), and that
320
+ * placement must not fail the scan. Canonical containment decides; a raw
321
+ * substring match outside the owned root still flags (values that merely
322
+ * mention the real home are suspect even when not resolvable paths).
323
+ *
324
+ * R7 correction: the canonical-containment arms (both the owned-root pardon
325
+ * and the real-home accusation) apply ONLY to path-shaped values. Resolving a
326
+ * non-path value such as a numeric flag ('0'/'1') anchors it at the process
327
+ * CWD, and on Linux runners the CWD lives under the real home — that turned
328
+ * KB_MODULES_AUTOSTART='0' into a phantom path leak. Non-path values keep the
329
+ * substring mention test only.
330
+ */
331
+ const PATH_SHAPED_RE = /^(?:[A-Za-z]:[\\/]|\\\\|\/|~[\\/\\]|\.{1,2}[\\/\\])/;
332
+ function realHomeReferenceKeys(env, { root = null, realHome = REAL_HOME, realUserProfile = REAL_USERPROFILE } = {}) {
333
+ return Object.entries(env)
334
+ .filter(([key]) => !isOsWhitelisted(key))
335
+ .filter(([, value]) => {
336
+ const text = String(value);
337
+ const pathShaped = PATH_SHAPED_RE.test(text);
338
+ if (pathShaped && root && isInside(path.resolve(text), root)) return false;
339
+ return text.includes(realHome) || text.includes(realUserProfile)
340
+ || (pathShaped && (isInside(path.resolve(text), realHome) || isInside(path.resolve(text), realUserProfile)));
341
+ })
342
+ .map(([key]) => key);
343
+ }
344
+
345
+ /**
346
+ * The isolation invariants, as one assertable record. `env` defaults to the
347
+ * live process environment, so a harness or a negative case can prove the
348
+ * whitelist property at any moment.
349
+ */
350
+ function navIsolationReport(env = process.env, isolation = null) {
351
+ const layout = isolation ? isolation.layout : null;
352
+ const root = isolation ? isolation.root : null;
353
+ const findings = {
354
+ isolationKeys: Object.fromEntries(ISOLATION_KEYS.map(key => [key, env[key] ?? null])),
355
+ allIsolationKeysInsideRoot: layout
356
+ ? ISOLATION_KEYS.filter(key => key !== 'HOMEDRIVE' && key !== 'HOMEPATH').every(key => env[key] && isInside(path.resolve(env[key]), root))
357
+ : null,
358
+ ambientDeleted: Object.fromEntries([...AMBIENT_DELETES, 'KB_MODULES_AUTOSTART'].map(key => [key, Object.keys(env).some(name => upper(name) === upper(key))])),
359
+ noAmbientSurvives: [...AMBIENT_DELETES].every(key => !Object.keys(env).some(name => upper(name) === upper(key))),
360
+ osWhitelistHeld: Object.keys(env).filter(key => !isOsWhitelisted(key) && !ISOLATION_KEYS.includes(key) && key !== 'KB_MODULES_AUTOSTART'),
361
+ // Real-home references are tolerated ONLY inside the OS allowlist (the
362
+ // real PATH names real tool locations) or, since R9, inside the owned
363
+ // isolation root itself (hosted runners place RUNNER_TEMP under the real
364
+ // home — placement, not identity); every other variable must be free of
365
+ // them. See realHomeReferenceKeys for the canonical rule.
366
+ referencesRealHome: realHomeReferenceKeys(env, { root }),
367
+ // Keys that pointed at the real home before the whitelist and have NOT
368
+ // been redirected into the owned root (empty list = redirection proven).
369
+ redirectionFailures: layout && isolation && isolation.originalInsideRealHome
370
+ ? Object.entries(isolation.originalInsideRealHome)
371
+ .filter(([, wasReal]) => wasReal)
372
+ .filter(([key]) => !(env[key] && isInside(path.resolve(String(env[key])), root)))
373
+ .map(([key]) => key)
374
+ : null,
375
+ posixSocketBudget: root ? posixSocketBudgetVerdict(root) : null,
376
+ chromeDefaultProfileDirExists: layout ? fs.existsSync(layout.chromeDefaultProfileDir) : null,
377
+ psCacheParentExists: layout ? fs.existsSync(path.dirname(layout.psCachePath)) : null,
378
+ };
379
+ if (root) findings.stableRootExists = fs.existsSync(path.dirname(root));
380
+ return findings;
381
+ }
382
+
383
+ module.exports = {
384
+ enterNavIsolation, navIsolationReport, isolationEnvMap, realHomeReferenceKeys,
385
+ OS_WHITELIST, ISOLATION_KEYS, AMBIENT_DELETES,
386
+ REAL_HOME, REAL_USERPROFILE, resolveNavTempRoot,
387
+ worstCasePosixSocketPaths, posixSocketBudgetVerdict, assertPosixSocketBudget,
388
+ POSIX_SOCKET_CHAR_LIMIT, CHROME_RAND_MAX_CHARS,
389
+ };
@@ -0,0 +1,186 @@
1
+ // _site/_test/helpers/parallel-nav-module-ui.js
2
+ //
3
+ // Test double for an embedded module UI (the Agent workbench, the knowledge
4
+ // index, the event bridge). The product embeds a module in an iframe and
5
+ // talks to it with the kb:* postMessage protocol; the module answers
6
+ // "kb:ready" and then receives kb:theme, kb:scope, kb:select-project and
7
+ // kb:visibility.
8
+ //
9
+ // This fixture is a real HTTP service: the product proxies the iframe
10
+ // request to it, the page it serves is the one the browser really loads, and
11
+ // the postMessage traffic is really delivered. It is NOT the real module
12
+ // UI — the cases that use it verify the SHELL side of the protocol (the
13
+ // shell must deliver kb:theme, must not re-send kb:select-project after a
14
+ // theme change, and must map the right project to the frame), so the
15
+ // substituted part is stated in the case report.
16
+ //
17
+ // The fixture also answers the module registry API the product calls when it
18
+ // registers a project, so the project→module mapping under test is a real
19
+ // registration round trip.
20
+
21
+ 'use strict';
22
+
23
+ const http = require('node:http');
24
+ const crypto = require('node:crypto');
25
+ const fs = require('node:fs');
26
+ const path = require('node:path');
27
+
28
+ const PAGE = `<!doctype html>
29
+ <html lang="zh-CN"><head><meta charset="utf-8"><title>module ui fixture</title></head>
30
+ <body>
31
+ <p>module ui fixture</p>
32
+ <script>
33
+ // The messages the shell really sent to this frame, in order.
34
+ window.__navMessages = [];
35
+ window.addEventListener('message', function (event) {
36
+ var data = event.data;
37
+ if (!data || typeof data !== 'object') return;
38
+ window.__navMessages.push({ type: String(data.type || ''), payload: data, at: Date.now() });
39
+ });
40
+ // The shell only starts talking to a frame after the frame announced
41
+ // itself; that announcement is the "ready" edge of the protocol.
42
+ window.parent.postMessage({ type: 'kb:ready' }, '*');
43
+ </script>
44
+ </body></html>`;
45
+
46
+ function sendJson(res, status, payload) {
47
+ const body = JSON.stringify(payload);
48
+ res.writeHead(status, { 'Content-Type': 'application/json; charset=utf-8', 'Content-Length': Buffer.byteLength(body) });
49
+ res.end(body);
50
+ }
51
+
52
+ function createModuleUiFixture({ tag = 'module-ui' } = {}) {
53
+ const state = { pageLoads: 0, requests: [], projects: [], nextId: 1 };
54
+ let server;
55
+
56
+ server = http.createServer(async (req, res) => {
57
+ const url = new URL(req.url, 'http://127.0.0.1');
58
+ const chunks = [];
59
+ for await (const chunk of req) chunks.push(chunk);
60
+ const raw = Buffer.concat(chunks);
61
+ let body = null;
62
+ if (raw.length) { try { body = JSON.parse(raw.toString('utf8')); } catch { body = null; } }
63
+ state.requests.push({ method: req.method, path: url.pathname + url.search, body, at: Date.now() });
64
+
65
+ // The health probes the product uses to recognise a module. The same
66
+ // double stands in for the knowledge index and the event bridge, so the
67
+ // body carries both identity markers.
68
+ if (req.method === 'GET' && url.pathname === '/api/claude-workbench/v1/health') {
69
+ sendJson(res, 200, { status: 'ok', apiVersion: 'test-double' });
70
+ return;
71
+ }
72
+ if (req.method === 'GET' && url.pathname === '/api/health') {
73
+ sendJson(res, 200, { ok: true, projects: state.projects.filter(project => project.sourceDir), registeredProjects: state.projects.filter(project => project.id).length });
74
+ return;
75
+ }
76
+
77
+ // Navigation owns no real journals. An enabled engine can safely poll
78
+ // this empty Bridge contract without reaching the production bridge.
79
+ if (req.method === 'GET' && url.pathname === '/api/journals') {
80
+ sendJson(res, 200, { journals: [] });
81
+ return;
82
+ }
83
+
84
+ // The module registry API the product uses when it registers a project.
85
+ if (req.method === 'GET' && url.pathname === '/api/claude-workbench/v1/projects') {
86
+ sendJson(res, 200, { projects: state.projects });
87
+ return;
88
+ }
89
+ if (req.method === 'POST' && url.pathname === '/api/claude-workbench/v1/projects') {
90
+ const id = `terminal-${state.nextId++}`;
91
+ state.projects.push({ id, name: body?.name || id, rootPath: body?.rootPath || '' });
92
+ sendJson(res, 201, { id, name: body?.name || id, rootPath: body?.rootPath || '' });
93
+ return;
94
+ }
95
+ if (req.method === 'DELETE' && url.pathname.startsWith('/api/claude-workbench/v1/projects/')) {
96
+ const id = decodeURIComponent(url.pathname.split('/').pop());
97
+ state.projects = state.projects.filter(project => project.id !== id);
98
+ res.writeHead(204); res.end();
99
+ return;
100
+ }
101
+ // The knowledge-index registry: the product imports a project by name and
102
+ // source directory, and lists the imported ones before importing again.
103
+ if (req.method === 'GET' && url.pathname === '/api/projects') {
104
+ sendJson(res, 200, { projects: state.projects.filter(project => project.sourceDir) });
105
+ return;
106
+ }
107
+ if (req.method === 'POST' && url.pathname === '/api/import') {
108
+ const project = { name: body?.projectName || '', sourceDir: body?.sourceDir || '', hasIndex: true };
109
+ state.projects.push(project);
110
+ sendJson(res, 200, { ok: true, project: project.name });
111
+ return;
112
+ }
113
+ // The vector contract subset the REAL engine's index step calls
114
+ // (coordinator.js requestIndex -> POST /api/sync {project, sourceDir}).
115
+ // The vector module is NOT the subject under test — this double keeps the
116
+ // engine's index step off its built-in default vectorUrl (the LIVE
117
+ // desktop hub on 127.0.0.1:8787); every request body is recorded so the
118
+ // harness can assert project/sourceDir never leave the fixture.
119
+ if (req.method === 'POST' && url.pathname === '/api/sync') {
120
+ if (!body?.project || !body?.sourceDir) { sendJson(res, 400, { error: "Body must include 'project' and 'sourceDir'." }); return; }
121
+ let filesTracked = 0;
122
+ try {
123
+ filesTracked = fs.readdirSync(body.sourceDir, { withFileTypes: true })
124
+ .filter(entry => entry.isFile() && ['.md', '.txt', '.html'].includes(path.extname(entry.name).toLowerCase())).length;
125
+ } catch { filesTracked = 0; }
126
+ state.projects = state.projects.filter(project => project.name !== body.project);
127
+ state.projects.push({ name: body.project, sourceDir: body.sourceDir, hasIndex: true });
128
+ sendJson(res, 200, { ok: true, project: body.project, filesTracked });
129
+ return;
130
+ }
131
+ if (req.method === 'DELETE' && url.pathname === '/api/project') {
132
+ const name = url.searchParams.get('name');
133
+ state.projects = state.projects.filter(project => project.name !== name);
134
+ sendJson(res, 200, { ok: true });
135
+ return;
136
+ }
137
+ // The development-event registry: the product registers a work tree and
138
+ // reads the journal back by the id the registry answered with. The real
139
+ // registry answers with the workspace id, and the engine only accepts
140
+ // that shape as a session baseline key.
141
+ if (req.method === 'POST' && url.pathname === '/api/projects') {
142
+ const id = `sha256:${crypto.createHash('sha256').update(String(body?.path || '')).digest('hex')}`;
143
+ state.projects.push({ id, path: body?.path || '', auto: false, store: body?.store || '' });
144
+ sendJson(res, 201, { project: { id, path: body?.path || '' } });
145
+ return;
146
+ }
147
+ if (req.method === 'DELETE' && url.pathname === '/api/projects') {
148
+ const id = url.searchParams.get('id');
149
+ state.projects = state.projects.filter(project => project.id !== id);
150
+ sendJson(res, 200, { ok: true });
151
+ return;
152
+ }
153
+ if (req.method !== 'GET') {
154
+ res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
155
+ res.end('not found');
156
+ return;
157
+ }
158
+ // Every other GET is an embedded UI document: count it, because a
159
+ // reloaded frame is a rebuilt task for the module.
160
+ state.pageLoads += 1;
161
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'no-store' });
162
+ res.end(PAGE);
163
+ });
164
+
165
+ return {
166
+ tag,
167
+ state,
168
+ /** How many times the embedded UI document was really served. */
169
+ pageLoads: () => state.pageLoads,
170
+ /** Every POST /api/sync body the engine really sent (vector stand-in evidence). */
171
+ vectorSyncs: () => state.requests.filter(request => request.method === 'POST' && request.path === '/api/sync'),
172
+ /** Every POST /api/import body (the engine's scope-registration vector call). */
173
+ vectorImports: () => state.requests.filter(request => request.method === 'POST' && request.path === '/api/import'),
174
+ async start() {
175
+ await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
176
+ this.url = `http://127.0.0.1:${server.address().port}`;
177
+ return this.url;
178
+ },
179
+ async close() {
180
+ server.closeAllConnections();
181
+ await new Promise(resolve => server.close(resolve));
182
+ },
183
+ };
184
+ }
185
+
186
+ module.exports = { createModuleUiFixture };