@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,238 @@
1
+ 'use strict';
2
+ // _site/_test/parallel-memory-sync-test.js
3
+ //
4
+ // MEM-006 同步失败(sync pending).
5
+ //
6
+ // Real isolated product instance, real browser, real HTTP and real disk.
7
+ //
8
+ // The write really fails: the brain's shared memory file path is occupied by
9
+ // a directory, so the engine's own materialize() cannot write the confirmed
10
+ // memory file. Nothing is faked here — the engine records the real write
11
+ // error, the shell renders the real pending state and the real injection gate
12
+ // refuses to hand the unsynced memory to a task.
13
+ //
14
+ // MEM-006 expected:
15
+ // * sync pending真实显示。 -> the engine really answers syncStatus
16
+ // 'pending' with the write error, the real UI
17
+ // shows 写入待恢复 / 待同步 and the real toast
18
+ // warns that the unsynced memory is not
19
+ // injected;
20
+ // * 未同步内容不注入。 -> the engine injects nothing for the unsynced
21
+ // memory, and it does inject it again once
22
+ // the file can really be written.
23
+
24
+ const fs = require('node:fs');
25
+ const path = require('node:path');
26
+ const assert = require('node:assert/strict');
27
+
28
+ const { startHarness, makeRepo } = require('./helpers/parallel-memory-shell');
29
+
30
+ const EVIDENCE = process.env.PK_TEST_EVIDENCE_DIR ? path.resolve(process.env.PK_TEST_EVIDENCE_DIR) : null;
31
+ const MEMORY_TEXT = '同步失败回归:对外错误信息使用中文表述。';
32
+
33
+ async function openMemoryView(harness) {
34
+ await harness.nativeClick('nav [data-view="memory"]');
35
+ await harness.waitFor(
36
+ () => harness.run("document.getElementById('view-memory').classList.contains('active')"),
37
+ 'the memory view is open',
38
+ 10000,
39
+ );
40
+ }
41
+
42
+ async function main() {
43
+ const harness = await startHarness({ tag: 'memsync', evidenceDir: EVIDENCE || undefined });
44
+ const evidence = [];
45
+ try {
46
+ const repo = makeRepo(harness.fixture, 'memsync-repo', { 'README.md': '# 同步甲\n' });
47
+ const { projectId } = await harness.importProject(repo, '同步甲');
48
+ await harness.requestRegistryRefresh();
49
+ await harness.waitFor(
50
+ () => harness.run("document.getElementById('homeContent').textContent.includes('同步甲')"),
51
+ 'the imported project is listed',
52
+ 20000,
53
+ );
54
+
55
+ await openMemoryView(harness);
56
+ await harness.waitFor(
57
+ () => harness.run("!document.getElementById('addMemory').disabled"),
58
+ 'the engine is reachable and the add button is live',
59
+ 20000,
60
+ );
61
+
62
+ // Break the real write path: the confirmed memory file path becomes a
63
+ // directory, so the engine cannot write the memory file.
64
+ const brainScope = harness.brainScopePath();
65
+ const memoryFile = path.join(brainScope, 'memories', 'confirmed.md');
66
+ fs.rmSync(memoryFile, { recursive: true, force: true });
67
+ fs.mkdirSync(memoryFile, { recursive: true });
68
+ assert.ok(fs.lstatSync(memoryFile).isDirectory(), 'the confirmed memory file path really is occupied by a directory');
69
+
70
+ // Add the memory through the real UI as a global memory.
71
+ await harness.nativeClick('#addMemory');
72
+ await harness.waitFor(
73
+ () => harness.run("document.getElementById('memoryDialog').open === true"),
74
+ 'the add dialog is open',
75
+ 10000,
76
+ );
77
+ await harness.typeText(MEMORY_TEXT);
78
+ await harness.selectOption('#memoryScope', 'global');
79
+ const postsBefore = harness.network.find(entry => entry.method === 'POST' && entry.url.includes('/api/engine/memories')).length;
80
+ // Passive DOM observation installed BEFORE the real click. The product's
81
+ // confirm handler closes the dialog BEFORE its post-save refreshSnapshot()
82
+ // and shows the toast only after that refresh resolves (ui/product.js:
83
+ // 'close(); await refreshSnapshot(); toast(...)'), so a one-shot read
84
+ // gated on 'dialog closed' can land inside the refresh gap and see an
85
+ // empty toast (CI 40080404131, line 98: empty text). The observer records
86
+ // every REAL toast mutation the REAL click produces — text, visibility
87
+ // and time — nothing is fabricated or forced.
88
+ await harness.run(`(() => {
89
+ const el = document.getElementById('toast');
90
+ window.__pkToastLog = [{ text: el.textContent, hidden: el.hidden, at: Date.now() }];
91
+ new MutationObserver(() => {
92
+ window.__pkToastLog.push({ text: el.textContent, hidden: el.hidden, at: Date.now() });
93
+ }).observe(el, { childList: true, characterData: true, subtree: true, attributes: true, attributeFilter: ['hidden'] });
94
+ return true;
95
+ })()`);
96
+ await harness.nativeClick('#confirmMemory');
97
+ await harness.waitFor(
98
+ () => harness.run("document.getElementById('memoryDialog').open === false"),
99
+ 'the dialog closes after the save',
100
+ 15000,
101
+ );
102
+
103
+ const post = harness.network.find(entry => entry.method === 'POST' && entry.url.includes('/api/engine/memories'))[postsBefore];
104
+ assert.ok(post, 'the shell really posted the memory');
105
+ assert.equal(post.status, 200, `the real POST answers 200: ${JSON.stringify(post.body)}`);
106
+ const postBody = await harness.network.body(post);
107
+ const created = postBody.memory;
108
+ assert.equal(created.status, 'confirmed', 'the memory itself is confirmed');
109
+ assert.equal(created.syncStatus, 'pending', `the engine really answers syncStatus pending: ${JSON.stringify(created)}`);
110
+ assert.ok(created.syncError, `the engine reports the real write error: ${JSON.stringify(created.syncError)}`);
111
+
112
+ // The real UI shows the pending state. The wait is on the OBSERVED toast
113
+ // record (installed before the click), so the assertion holds no matter
114
+ // when the shell's post-save refreshSnapshot() finishes — the observed
115
+ // toast is the real one the real click produced. The toast's text also
116
+ // persists after its 4s auto-hide (product toast() flips only `hidden`),
117
+ // so a late match is still the real text; requiring hidden === false in
118
+ // the same record proves it was actually VISIBLE when shown.
119
+ const debugUiFailure = async stage => {
120
+ try {
121
+ const dump = await harness.run(`(() => ({
122
+ toasts: window.__pkToastLog || null,
123
+ feedback: document.getElementById('memoryFeedback').textContent,
124
+ feedbackHidden: document.getElementById('memoryFeedback').hidden,
125
+ dialogOpen: document.getElementById('memoryDialog').open,
126
+ activeView: (document.querySelector('.view.active') || {}).id || null,
127
+ }))()`);
128
+ console.error(`MEM-006 UI failure at ${stage}: ${JSON.stringify(dump)}`);
129
+ if (harness.evidence) await harness.browser.screenshot(path.join(harness.evidence, `mem006-failure-${stage}.png`));
130
+ } catch {}
131
+ };
132
+ let toastRecord;
133
+ try {
134
+ toastRecord = await harness.waitFor(
135
+ () => harness.run(`(window.__pkToastLog || []).find(t => !t.hidden && t.text.includes('记忆文件待恢复')) || null`),
136
+ 'the toast warns about the pending file',
137
+ 10000,
138
+ );
139
+ } catch (error) { await debugUiFailure('toast-pending'); throw error; }
140
+ assert.equal(toastRecord.hidden, false, `the pending toast was really visible when shown: ${JSON.stringify(toastRecord)}`);
141
+ const toast = toastRecord.text;
142
+ assert.match(String(toast), /记忆文件待恢复/, `the toast warns about the pending file: ${toast}`);
143
+ assert.match(String(toast), /未同步内容不会注入任务。/, 'the toast warns that the unsynced memory is not injected');
144
+
145
+ let card;
146
+ try {
147
+ card = await harness.run(`(() => {
148
+ const el = document.querySelector('[data-memory-card=${JSON.stringify(created.id)}]');
149
+ return el ? el.textContent : null;
150
+ })()`);
151
+ } catch (error) { await debugUiFailure('card-read'); throw error; }
152
+ if (!card) await debugUiFailure('card-listed');
153
+ assert.ok(card, 'the confirmed memory is really listed');
154
+ assert.match(card, /写入待恢复/, `the card shows the pending write: ${card}`);
155
+ assert.match(card, /待同步/, 'the card shows the pending sync state');
156
+ if (harness.evidence) await harness.browser.screenshot(path.join(harness.evidence, 'mem006-sync-pending.png'));
157
+
158
+ // 未同步内容不注入: the real injection gate refuses the unsynced memory.
159
+ const injected = await harness.injectedMemories(projectId);
160
+ assert.ok(
161
+ !injected.some(entry => entry.memoryId === created.id),
162
+ `the unsynced memory is never injected: ${JSON.stringify(injected)}`,
163
+ );
164
+
165
+ const pendingRecord = (await harness.productMemories()).find(memory => memory.id === created.id);
166
+ assert.equal(pendingRecord.syncStatus, 'pending', 'the stored memory still carries the pending sync state');
167
+
168
+ evidence.push({
169
+ case: 'MEM-006',
170
+ request: { method: post.method, url: post.url.replace(harness.base, ''), status: post.status, response: postBody },
171
+ memory: { id: created.id, status: created.status, syncStatus: created.syncStatus, syncError: created.syncError, scopeType: created.scopeType, scopeId: created.scopeId },
172
+ ui: { toast, toastObserved: { visibleWhenShown: toastRecord.hidden === false, at: toastRecord.at }, card },
173
+ injectedWhilePending: injected.map(entry => entry.memoryId),
174
+ blockedPath: memoryFile,
175
+ });
176
+
177
+ // ---------------------------------------------------------------- recovery
178
+ // The write really works again: the directory is removed and the engine's
179
+ // own recovery writes the file. The memory becomes injectable again.
180
+ fs.rmSync(memoryFile, { recursive: true, force: true });
181
+ await harness.waitFor(
182
+ async () => {
183
+ const memories = await harness.productMemories();
184
+ const memory = memories.find(entry => entry.id === created.id);
185
+ return memory && memory.syncStatus === 'ready' ? memory : null;
186
+ },
187
+ 'the engine recovers the pending write',
188
+ 30000,
189
+ );
190
+ assert.ok(fs.existsSync(memoryFile), 'the confirmed memory file is really written again');
191
+ const fileText = fs.readFileSync(memoryFile, 'utf8');
192
+ assert.ok(fileText.includes(created.id), 'the recovered file holds the memory');
193
+ assert.ok(fileText.includes(MEMORY_TEXT), 'the recovered file holds the text');
194
+
195
+ const afterRecovery = await harness.injectedMemories(projectId);
196
+ assert.ok(
197
+ afterRecovery.some(entry => entry.memoryId === created.id),
198
+ `the recovered memory is injected again: ${JSON.stringify(afterRecovery)}`,
199
+ );
200
+
201
+ await harness.reload();
202
+ await openMemoryView(harness);
203
+ await harness.nativeClick('[data-memory-tab="confirmed"]');
204
+ await harness.waitFor(
205
+ () => harness.run(`document.getElementById('memoryContent').textContent.includes(${JSON.stringify(MEMORY_TEXT)})`),
206
+ 'the recovered memory is listed again',
207
+ 15000,
208
+ );
209
+ const recoveredCard = await harness.run(`(() => {
210
+ const el = document.querySelector('[data-memory-card=${JSON.stringify(created.id)}]');
211
+ return el ? el.textContent : null;
212
+ })()`);
213
+ assert.ok(recoveredCard, 'the recovered memory has a card');
214
+ assert.ok(!recoveredCard.includes('写入待恢复'), `the card no longer shows the pending write: ${recoveredCard}`);
215
+ assert.match(recoveredCard, /已确认/, 'the card shows the confirmed state again');
216
+ if (harness.evidence) await harness.browser.screenshot(path.join(harness.evidence, 'mem006-recovered.png'));
217
+
218
+ evidence.push({
219
+ case: 'MEM-006-recovery',
220
+ memoryFile,
221
+ injectedAfterRecovery: afterRecovery.map(entry => entry.memoryId),
222
+ ui: { card: recoveredCard },
223
+ });
224
+
225
+ assert.equal(harness.browser.exceptions.length, 0, `no uncaught product JavaScript exceptions: ${JSON.stringify(harness.browser.exceptions)}`);
226
+
227
+ if (harness.evidence) {
228
+ fs.mkdirSync(harness.evidence, { recursive: true });
229
+ fs.writeFileSync(path.join(harness.evidence, 'mem006-sync.json'), `${JSON.stringify(evidence, null, 2)}\n`, 'utf8');
230
+ }
231
+
232
+ console.log('parallel-memory-sync-test PASS (MEM-006 the real write failure shows sync pending, the unsynced memory is not injected, and the recovered memory is injected again)');
233
+ } finally {
234
+ await harness.cleanup();
235
+ }
236
+ }
237
+
238
+ main().catch(error => { console.error(error.stack || error.message); process.exitCode = 1; });
@@ -0,0 +1,123 @@
1
+ 'use strict';
2
+ // _site/_test/parallel-memory-view-r8-reload-gate-test.js
3
+ //
4
+ // P-CI-MEMORY-VIEW-R8 focused case: the reload→navigate contract that CI
5
+ // 40062048045 broke in parallel-memory-source-test ("Timed out waiting for
6
+ // the memory view is open", test line 136).
7
+ //
8
+ // Root cause class (see the R8 probe evidence under
9
+ // qa-autopilot/artifacts/parallel-20261023/ci-memory-view-r8/): the shell's
10
+ // reload() used to gate ONLY on `document.readyState === 'complete'`, which
11
+ // proves neither WHICH document answered (Page.reload is acknowledged before
12
+ // the navigation commits; Runtime.evaluate can answer from the outgoing
13
+ // context on a congested renderer) nor that the product's interactive boot
14
+ // finished. A native nav click dispatched right after such a gate can land
15
+ // in the load/swap settle window and be dropped — reproduced 2/2 against the
16
+ // real page with a forced 600ms commit delay; the memory view then never
17
+ // activates (the exact CI never-true predicate).
18
+ //
19
+ // The fixed gate returns only when the answering document is provably FRESH
20
+ // (a marker set on the outgoing document is gone) AND the product's own boot
21
+ // evidence is present (.view.active — ui/product.js attaches its click
22
+ // delegation before the boot setView that marks the initial view active).
23
+ //
24
+ // This case proves that contract on the real page, offline from MEM-008:
25
+ // 1. reload() returns on the fresh, booted document (identity marker);
26
+ // 2. the golden path the CI failure broke — nativeClick nav memory right
27
+ // after reload() — activates the memory view, and home navigation
28
+ // still works;
29
+ // 3. back-to-back reloads keep the contract (the marker technique marks
30
+ // each outgoing document, so consecutive reloads cannot pass on a
31
+ // stale context);
32
+ // 4. the failure-diagnostics surface exists (navigationState).
33
+ //
34
+ // Real isolated product instance, real browser, real CDP input; the harness
35
+ // owns vector+bridge before the engine constructor and no live
36
+ // 5757/5790/8787/8790 endpoint is touched (parallel-memory-shell.js).
37
+
38
+ const fs = require('node:fs');
39
+ const path = require('node:path');
40
+ const assert = require('node:assert/strict');
41
+
42
+ const { startHarness } = require('./helpers/parallel-memory-shell');
43
+
44
+ const EVIDENCE = process.env.PK_TEST_EVIDENCE_DIR ? path.resolve(process.env.PK_TEST_EVIDENCE_DIR) : null;
45
+
46
+ async function main() {
47
+ const harness = await startHarness({ tag: 'memviewr8', evidenceDir: EVIDENCE || undefined });
48
+ const proof = { startedAt: new Date().toISOString() };
49
+ try {
50
+ await harness.waitFor(
51
+ () => harness.run("document.readyState === 'complete' && document.querySelector('.view.active') !== null"),
52
+ 'the initial page is booted',
53
+ 20000,
54
+ );
55
+
56
+ // ---- 1. reload() returns on the FRESH, booted document ----------------
57
+ await harness.run('window.__pkR8Mark = "outgoing", true');
58
+ await harness.reload();
59
+ const fresh = await harness.run(`(() => ({
60
+ mark: typeof window.__pkR8Mark,
61
+ activeView: (document.querySelector('.view.active') || {}).id || null,
62
+ readyState: document.readyState,
63
+ }))()`);
64
+ assert.equal(fresh.mark, 'undefined', 'reload() must return on the fresh document, never on the outgoing one (the marker exists only in the outgoing context)');
65
+ assert.ok(fresh.activeView, 'the product boot finished before reload() returned (an initial view is active — the delegation-attached proof)');
66
+ assert.equal(fresh.readyState, 'complete');
67
+ assert.ok(harness.reloadLog.length >= 1, 'the reload gate records its small metadata');
68
+ proof.freshDocumentGate = fresh;
69
+
70
+ // ---- 2. the golden path the CI failure broke ---------------------------
71
+ await harness.nativeClick('nav [data-view="memory"]');
72
+ await harness.waitFor(
73
+ () => harness.run("document.getElementById('view-memory').classList.contains('active')"),
74
+ 'the memory view is open',
75
+ 10000,
76
+ );
77
+ await harness.nativeClick('nav [data-view="home"]');
78
+ await harness.waitFor(
79
+ () => harness.run("document.getElementById('view-home').classList.contains('active')"),
80
+ 'the home view is open',
81
+ 10000,
82
+ );
83
+ proof.goldenPath = { memoryViewOpened: true, homeViewReopened: true };
84
+
85
+ // ---- 3. back-to-back reloads keep the contract -------------------------
86
+ await harness.run('window.__pkR8Mark = "outgoing-again", true');
87
+ await harness.reload();
88
+ await harness.reload();
89
+ const twice = await harness.run(`(() => ({
90
+ mark: typeof window.__pkR8Mark,
91
+ activeView: (document.querySelector('.view.active') || {}).id || null,
92
+ }))()`);
93
+ assert.equal(twice.mark, 'undefined', 'after two consecutive reloads the gate still returned on the fresh document');
94
+ assert.ok(twice.activeView, 'the boot evidence held through the second reload');
95
+ await harness.nativeClick('nav [data-view="memory"]');
96
+ await harness.waitFor(
97
+ () => harness.run("document.getElementById('view-memory').classList.contains('active')"),
98
+ 'the memory view opens after back-to-back reloads',
99
+ 10000,
100
+ );
101
+ proof.backToBackReloads = { ...twice, memoryViewOpened: true };
102
+
103
+ // ---- 4. the failure-diagnostics surface exists -------------------------
104
+ const state = await harness.navigationState();
105
+ assert.ok(state && typeof state === 'object' && !state.unreachable, `navigationState() must be reachable: ${JSON.stringify(state)}`);
106
+ assert.equal(typeof state.readyState, 'string');
107
+ assert.ok('activeView' in state && 'openDialogs' in state);
108
+ proof.navigationStateShape = state;
109
+
110
+ assert.equal(harness.browser.exceptions.length, 0, `no uncaught product JavaScript exceptions: ${JSON.stringify(harness.browser.exceptions)}`);
111
+ proof.finishedAt = new Date().toISOString();
112
+ proof.verdict = 'PASS';
113
+ if (harness.evidence) {
114
+ fs.mkdirSync(harness.evidence, { recursive: true });
115
+ fs.writeFileSync(path.join(harness.evidence, 'memviewr8-reload-gate.json'), `${JSON.stringify(proof, null, 2)}\n`, 'utf8');
116
+ }
117
+ console.log('parallel-memory-view-r8-reload-gate-test PASS');
118
+ } finally {
119
+ await harness.cleanup();
120
+ }
121
+ }
122
+
123
+ main().catch(error => { console.error(error.stack || error.message); process.exitCode = 1; });
@@ -0,0 +1,119 @@
1
+ 'use strict';
2
+ // NAV-004 — 失败保留旧数据。
3
+ //
4
+ // When the registry read fails the shell must show the failure, must keep the
5
+ // project list it already has, and must pick up the new snapshot once the
6
+ // registry answers again.
7
+ //
8
+ // The failure is a real HTTP 503 injected by a proxy in front of the product:
9
+ // the browser really receives a failed answer, and the shell really reads a
10
+ // broken registry. The regression drives the real product UI in a real
11
+ // browser against an isolated instance (own port, own data dir, own knowledge
12
+ // dir, own Bridge journal, own browser profile, own vendored knowledge
13
+ // engine). Screenshots are written to PK_TEST_EVIDENCE_DIR when the batch
14
+ // sets it, so this tracked file stays free of machine-specific paths.
15
+
16
+ const path = require('node:path');
17
+ const assert = require('node:assert/strict');
18
+
19
+ const { startHarness, makeRepo } = require('./helpers/parallel-nav-shell');
20
+
21
+ const EVIDENCE = process.env.PK_TEST_EVIDENCE_DIR ? path.resolve(process.env.PK_TEST_EVIDENCE_DIR) : null;
22
+
23
+ const PROJECTION = '/api/projects/projection';
24
+
25
+ async function main() {
26
+ const harness = await startHarness({ tag: 'nav004', evidenceDir: EVIDENCE || undefined });
27
+ try {
28
+ const repoA = makeRepo(harness.fixture, 'nav004-a');
29
+ const repoB = makeRepo(harness.fixture, 'nav004-b');
30
+ const repoC = makeRepo(harness.fixture, 'nav004-c');
31
+ await harness.importProject(repoA, 'NAV004 甲');
32
+ await harness.importProject(repoB, 'NAV004 乙');
33
+ await harness.requestRegistryRefresh();
34
+ await harness.waitFor(
35
+ async () => {
36
+ const text = await harness.run("document.getElementById('homeContent').textContent");
37
+ return text.includes('NAV004 甲') && text.includes('NAV004 乙');
38
+ },
39
+ 'both imported projects are listed',
40
+ 20000,
41
+ );
42
+
43
+ const listedProjects = () => harness.run(`(() => {
44
+ const rows = [...document.querySelectorAll('#homeContent [data-select-project]')];
45
+ return rows.map(button => {
46
+ const name = button.parentElement.querySelector('b');
47
+ return name ? name.textContent.trim() : '';
48
+ });
49
+ })()`);
50
+ const failedReads = () => harness.productProxy.requests.filter(entry => entry.path.startsWith(PROJECTION) && entry.status === 503).length;
51
+
52
+ // The registry read now fails at the HTTP level.
53
+ harness.productProxy.fail(entry => entry.method === 'GET' && entry.path.startsWith(PROJECTION), 503, '注入的登记读取故障');
54
+ const failuresBefore = failedReads();
55
+ await harness.refreshRegistryAndWait();
56
+ await harness.waitFor(async () => failedReads() > failuresBefore, 'the registry read really failed with an HTTP 503', 20000);
57
+
58
+ // NAV-004 expected 1: the failure is visible.
59
+ await harness.waitFor(
60
+ () => harness.run("document.getElementById('toast').hidden === false && document.getElementById('toast').textContent.includes('暂未刷新')"),
61
+ 'the failed refresh is reported to the user',
62
+ 10000,
63
+ );
64
+ const toast = await harness.run("document.getElementById('toast').textContent");
65
+ assert.ok(toast.includes('已有内容已保留'), `the failure message says the content was kept: ${toast}`);
66
+ await harness.browser.screenshot(path.join(harness.evidence, 'nav004-read-failure.png'));
67
+
68
+ // NAV-004 expected 2: the list that was already there is not cleared.
69
+ const listed = (await listedProjects()).sort();
70
+ assert.deepEqual(listed, ['NAV004 乙', 'NAV004 甲'], 'the project list still holds the projects it had before the failure');
71
+ const homeText = await harness.run("document.getElementById('homeContent').textContent");
72
+ assert.ok(homeText.includes('NAV004 甲'), 'the failed read keeps the first project');
73
+ assert.ok(homeText.includes('NAV004 乙'), 'the failed read keeps the second project');
74
+ const selectorText = await harness.run("document.getElementById('projectSelect').textContent");
75
+ assert.ok(selectorText.includes('NAV004 甲') && selectorText.includes('NAV004 乙'), 'the failed read keeps the project selector entries');
76
+
77
+ // A project that appears while the registry is broken must not slip into
78
+ // the list as if it had been read.
79
+ await harness.importProject(repoC, 'NAV004 丙');
80
+ const failuresBeforeSecond = failedReads();
81
+ await harness.refreshRegistryAndWait();
82
+ await harness.waitFor(async () => failedReads() > failuresBeforeSecond, 'the second registry read really failed too', 20000);
83
+ const duringFailure = await harness.run("document.getElementById('homeContent').textContent");
84
+ assert.ok(duringFailure.includes('NAV004 甲') && duringFailure.includes('NAV004 乙'), 'the old projects survive the repeated failure');
85
+ assert.equal(duringFailure.includes('NAV004 丙'), false, 'a project that was never read is not shown while the registry is broken');
86
+ assert.deepEqual((await listedProjects()).sort(), ['NAV004 乙', 'NAV004 甲'], 'the project rows are exactly the projects read before the failure');
87
+ await harness.browser.screenshot(path.join(harness.evidence, 'nav004-old-data-kept.png'));
88
+
89
+ // NAV-004 expected 3: after the registry answers again, the list is
90
+ // updated from the new snapshot.
91
+ harness.productProxy.clearFaults();
92
+ await harness.refreshRegistryAndWait();
93
+ await harness.waitFor(
94
+ () => harness.run("document.getElementById('homeContent').textContent.includes('NAV004 丙')"),
95
+ 'the recovered read shows the new project',
96
+ 20000,
97
+ );
98
+ const recovered = await harness.run("document.getElementById('homeContent').textContent");
99
+ assert.ok(recovered.includes('NAV004 甲') && recovered.includes('NAV004 乙'), 'the recovered read keeps the earlier projects');
100
+ assert.deepEqual((await listedProjects()).sort(), ['NAV004 丙', 'NAV004 乙', 'NAV004 甲'], 'the recovered list is the new snapshot');
101
+ await harness.browser.screenshot(path.join(harness.evidence, 'nav004-recovered.png'));
102
+
103
+ // The failure was an HTTP failure of a real read, not a shell-side guess.
104
+ const failed = harness.productProxy.requests.filter(entry => entry.path.startsWith(PROJECTION) && entry.status === 503);
105
+ assert.ok(failed.length >= 2, `the registry read failed at the HTTP level ${failed.length} times`);
106
+ // The failure notice is transient: the recovery does not leave a permanent
107
+ // error behind in the shell.
108
+ await harness.wait(4500);
109
+ assert.equal(await harness.run("document.getElementById('toast').hidden"), true, 'the failure message is not left behind after the recovery');
110
+
111
+ assert.equal(harness.browser.exceptions.length, 0, `no uncaught product JavaScript exceptions: ${JSON.stringify(harness.browser.exceptions)}`);
112
+
113
+ console.log('parallel-nav-failure-test PASS (the failure is visible, the old list survives, the recovery updates from the new snapshot)');
114
+ } finally {
115
+ await harness.cleanup();
116
+ }
117
+ }
118
+
119
+ main().catch(error => { console.error(error.stack || error.message); process.exitCode = 1; });