@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,301 @@
1
+ 'use strict';
2
+ // _site/_test/parallel-memory-candidate-test.js
3
+ //
4
+ // MEM-003 候选记忆 / MEM-005 忽略候选.
5
+ //
6
+ // Both cases run against a real isolated product instance with the REAL
7
+ // vendored knowledge engine behind a pass-through proxy: its own port, data
8
+ // dir, knowledge root, Bridge journal home and browser profile.
9
+ //
10
+ // The candidate is produced by the REAL pipeline: a real follow-up commit in a
11
+ // real Git fixture, a real frozen user event, the real promotion of a staged
12
+ // Markdown file and the engine's own MemoryService.capture() with its own
13
+ // provenance gate. The review happens in the real UI in a real Chrome.
14
+ //
15
+ // HONEST SCOPE LABEL: the analysis step is this lane's declared stand-in
16
+ // analyzer (helpers/parallel-memory-analyzer.js). It replaces the model, so
17
+ // these cases are evidence about the engine's admission, review, scope and
18
+ // injection machinery, never about the model's judgement.
19
+ //
20
+ // MEM-003 expected:
21
+ // * 保存为candidate。 -> the memory the engine really stored has status
22
+ // 'candidate', no manual source and a frozen
23
+ // source record;
24
+ // * 未确认不注入。 -> before the user confirms it the engine injects
25
+ // nothing for that memory, and the real UI lists
26
+ // it in 候选箱 with 审核确认 / 忽略.
27
+ // MEM-005 expected:
28
+ // * 状态ignored。 -> the real PATCH answers with status 'ignored';
29
+ // * 来源保持记录(冻结)。 -> the ignored record keeps the same commit, entry,
30
+ // quote, source event and eligibility, and injects
31
+ // nothing.
32
+
33
+ const fs = require('node:fs');
34
+ const path = require('node:path');
35
+ const assert = require('node:assert/strict');
36
+
37
+ const { startHarness, makeRepo } = require('./helpers/parallel-memory-shell');
38
+
39
+ const EVIDENCE = process.env.PK_TEST_EVIDENCE_DIR ? path.resolve(process.env.PK_TEST_EVIDENCE_DIR) : null;
40
+ const CANDIDATE_TEXT = '对外错误信息使用中文表述,并优先复用已有模块。';
41
+ const IGNORED_TEXT = '新增对外接口必须补充中文字段说明文档。';
42
+
43
+ async function openMemoryView(harness) {
44
+ await harness.nativeClick('nav [data-view="memory"]');
45
+ await harness.waitFor(
46
+ () => harness.run("document.getElementById('view-memory').classList.contains('active')"),
47
+ 'the memory view is open',
48
+ 10000,
49
+ );
50
+ }
51
+
52
+ async function openCandidateBox(harness) {
53
+ await openMemoryView(harness);
54
+ await harness.nativeClick('[data-memory-tab="candidate"]');
55
+ }
56
+
57
+ async function cardText(harness, memoryId) {
58
+ return harness.run(`(() => {
59
+ const el = document.querySelector('[data-memory-card=${JSON.stringify(memoryId)}]');
60
+ return el ? el.textContent : null;
61
+ })()`);
62
+ }
63
+
64
+ async function main() {
65
+ const harness = await startHarness({ tag: 'memcand', evidenceDir: EVIDENCE || undefined });
66
+ const evidence = [];
67
+ try {
68
+ const repo = makeRepo(harness.fixture, 'memcand-repo', { 'README.md': '# 候选甲\n' });
69
+ const { projectId } = await harness.importProject(repo, '候选甲');
70
+ await harness.requestRegistryRefresh();
71
+ await harness.waitFor(
72
+ () => harness.run("document.getElementById('homeContent').textContent.includes('候选甲')"),
73
+ 'the imported project is listed',
74
+ 20000,
75
+ );
76
+
77
+ // ---------------------------------------------------------------- MEM-003
78
+ const produced = await harness.produceCandidate({ repo, projectId, text: CANDIDATE_TEXT, scopeType: 'global' });
79
+ assert.equal(produced.capture.accepted, 1, `the real run admitted one candidate: ${JSON.stringify(produced.capture)}`);
80
+ assert.deepEqual(produced.capture.rejected, [], 'the real gate rejected nothing for a human source');
81
+
82
+ const stored = (await harness.productMemories()).find(memory => memory.text === CANDIDATE_TEXT);
83
+ assert.ok(stored, 'the candidate really exists in the engine');
84
+ assert.equal(stored.status, 'candidate', 'the automatic memory is saved as a candidate');
85
+ assert.notEqual(stored.sourceType, 'manual', 'an automatic candidate is not a manual memory');
86
+ assert.equal(stored.scopeType, 'global', 'a global candidate keeps the global scope');
87
+ assert.equal(stored.scopeId, stored.brainId, 'a global candidate targets the brain itself');
88
+ assert.equal(stored.evidence.projectId, projectId, 'the frozen source names the source project');
89
+ assert.equal(stored.evidence.commitSha, produced.commitSha, 'the frozen source names the real commit');
90
+ assert.ok(stored.evidence.entryId, 'the frozen source names the promoted entry');
91
+ assert.ok(stored.evidence.quote, 'the frozen source keeps the quoted text');
92
+ assert.equal(stored.sourceEventId, produced.event.eventId, 'the frozen source names the human event');
93
+ assert.equal(stored.sourceHash, produced.event.contentHash, 'the frozen source keeps the event hash');
94
+ assert.equal(stored.eligibility.durable, true, 'the candidate records why it is durable');
95
+ assert.equal(stored.eligibility.crossProject, true, 'the candidate records why it crosses projects');
96
+
97
+ // The candidate is really injected nowhere before the user confirms it.
98
+ const beforeReview = await harness.injectedMemories(projectId);
99
+ assert.ok(
100
+ !beforeReview.some(entry => entry.memoryId === stored.id),
101
+ `an unconfirmed candidate is never injected: ${JSON.stringify(beforeReview)}`,
102
+ );
103
+
104
+ // The real UI lists it in 候选箱 with the review actions.
105
+ await harness.reload();
106
+ await openCandidateBox(harness);
107
+ await harness.waitFor(
108
+ () => harness.run(`document.getElementById('memoryContent').textContent.includes(${JSON.stringify(CANDIDATE_TEXT)})`),
109
+ 'the candidate is listed in the candidate box',
110
+ 15000,
111
+ );
112
+ const listed = await cardText(harness, stored.id);
113
+ assert.ok(listed, 'the candidate really has a card in the candidate box');
114
+ assert.match(listed, /来源/, 'the card names the source of the candidate');
115
+ assert.ok(listed.includes(produced.commitSha.slice(0, 8)), 'the card shows the frozen commit');
116
+ assert.ok(
117
+ await harness.run(`Boolean(document.querySelector('[data-memory-action="confirm"][data-memory-id=${JSON.stringify(stored.id)}]'))`),
118
+ 'the candidate offers 审核确认',
119
+ );
120
+ assert.ok(
121
+ await harness.run(`Boolean(document.querySelector('[data-memory-action="ignore"][data-memory-id=${JSON.stringify(stored.id)}]'))`),
122
+ 'the candidate offers 忽略',
123
+ );
124
+ if (harness.evidence) await harness.browser.screenshot(path.join(harness.evidence, 'mem003-candidate-box.png'));
125
+
126
+ // The step's own path first: edit the candidate and click 保存候选 WITHOUT
127
+ // confirming — the memory has to stay a candidate and stay un-injected.
128
+ const EDIT_SUFFIX = '(修订)';
129
+ await harness.nativeClick(`[data-memory-action="confirm"][data-memory-id="${stored.id}"]`);
130
+ await harness.waitFor(
131
+ () => harness.run("document.getElementById('memoryDialog').open === true"),
132
+ 'the review dialog is open',
133
+ 10000,
134
+ );
135
+ await harness.nativeClick('#memoryText');
136
+ await harness.pressKey('End', { code: 'End', keyCode: 35 });
137
+ await harness.typeText(EDIT_SUFFIX);
138
+ const editedBody = await harness.run("document.getElementById('memoryText').value");
139
+ assert.equal(editedBody, CANDIDATE_TEXT + EDIT_SUFFIX, 'the real edit reached the textarea');
140
+
141
+ await harness.nativeClick('#saveMemoryCandidate');
142
+ await harness.waitFor(
143
+ () => harness.run("document.getElementById('memoryDialog').open === false"),
144
+ 'the dialog closes after saving the candidate',
145
+ 15000,
146
+ );
147
+ const saveCandidatePatch = harness.network.find(entry => entry.method === 'PATCH' && entry.url.includes(`/api/engine/memories/${stored.id}`)).pop();
148
+ assert.ok(saveCandidatePatch, 'the shell really patched the candidate');
149
+ assert.deepEqual(Object.keys(saveCandidatePatch.body).sort(), ['scopeId', 'scopeType', 'text'], '保存候选 sends no status at all');
150
+ const saveCandidateBody = await harness.network.body(saveCandidatePatch);
151
+ assert.equal(saveCandidatePatch.status, 200, `保存候选 answers 200: ${JSON.stringify(saveCandidatePatch.body)}`);
152
+ assert.equal(saveCandidateBody.memory.status, 'candidate', '保存候选 keeps the memory a candidate');
153
+ assert.equal(saveCandidateBody.memory.text, CANDIDATE_TEXT + EDIT_SUFFIX, '保存候选 keeps the edited text');
154
+ assert.equal(saveCandidateBody.memory.originalText, CANDIDATE_TEXT, '保存候选 keeps the frozen original summary');
155
+ const saveToast = await harness.run("document.getElementById('toast').textContent");
156
+ assert.match(String(saveToast), /候选已保存,尚未生效。/, `the toast says the candidate is not yet effective: ${saveToast}`);
157
+
158
+ const afterSaveCandidate = await harness.injectedMemories(projectId);
159
+ assert.ok(
160
+ !afterSaveCandidate.some(entry => entry.memoryId === stored.id),
161
+ `a saved-but-unconfirmed candidate is never injected: ${JSON.stringify(afterSaveCandidate)}`,
162
+ );
163
+ const stillCandidate = (await harness.productMemories()).find(memory => memory.id === stored.id);
164
+ assert.equal(stillCandidate.status, 'candidate', 'the stored memory is still a candidate after 保存候选');
165
+ await harness.waitFor(
166
+ () => harness.run(`document.getElementById('memoryContent').textContent.includes(${JSON.stringify(CANDIDATE_TEXT + EDIT_SUFFIX)})`),
167
+ 'the edited candidate is listed in the candidate box',
168
+ 15000,
169
+ );
170
+ if (harness.evidence) await harness.browser.screenshot(path.join(harness.evidence, 'mem003-saved-candidate.png'));
171
+
172
+ // 审核确认: the dialog shows the frozen source, and confirming confirms it.
173
+ await harness.nativeClick(`[data-memory-action="confirm"][data-memory-id="${stored.id}"]`);
174
+ await harness.waitFor(
175
+ () => harness.run("document.getElementById('memoryDialog').open === true"),
176
+ 'the review dialog is open',
177
+ 10000,
178
+ );
179
+ const shownEvidence = await harness.run("document.getElementById('memoryEvidence').textContent");
180
+ assert.ok(shownEvidence.includes(produced.commitSha), `the dialog shows the frozen commit: ${shownEvidence}`);
181
+ assert.ok(shownEvidence.includes(stored.evidence.entryId), 'the dialog shows the frozen entry');
182
+ const shownQuote = await harness.run("document.getElementById('memoryQuote').textContent");
183
+ assert.ok(shownQuote.includes(stored.evidence.quote), 'the dialog shows the frozen quote');
184
+ assert.ok(
185
+ await harness.run("document.getElementById('memoryEvidenceDetails').hidden === false"),
186
+ 'the frozen source is really visible for a candidate',
187
+ );
188
+ if (harness.evidence) await harness.browser.screenshot(path.join(harness.evidence, 'mem003-review-dialog.png'));
189
+
190
+ await harness.nativeClick('#confirmMemory');
191
+ await harness.waitFor(
192
+ () => harness.run("document.getElementById('memoryDialog').open === false"),
193
+ 'the dialog closes after the confirmation',
194
+ 15000,
195
+ );
196
+ const patch = harness.network.find(entry => entry.method === 'PATCH' && entry.url.includes('/api/engine/memories/')).pop();
197
+ assert.ok(patch, 'the shell really patched the candidate');
198
+ assert.equal(patch.status, 200, `the confirmation answers 200: ${JSON.stringify(patch.body)}`);
199
+ const patchBody = await harness.network.body(patch);
200
+ assert.ok(patchBody && patchBody.memory, `the confirmation answers with the memory: ${JSON.stringify(patchBody)}`);
201
+ assert.equal(patchBody.memory.status, 'confirmed', 'the confirmed memory is confirmed');
202
+ assert.equal(patchBody.memory.evidence.commitSha, produced.commitSha, 'the confirmation keeps the frozen source');
203
+
204
+ const afterConfirm = await harness.injectedMemories(projectId);
205
+ assert.ok(
206
+ afterConfirm.some(entry => entry.memoryId === stored.id),
207
+ `the confirmed memory is injected: ${JSON.stringify(afterConfirm)}`,
208
+ );
209
+
210
+ // The confirmed memory is listed in the confirmed tab of the real UI.
211
+ await harness.nativeClick('[data-memory-tab="confirmed"]');
212
+ await harness.waitFor(
213
+ () => harness.run(`document.getElementById('memoryContent').textContent.includes(${JSON.stringify(CANDIDATE_TEXT)})`),
214
+ 'the confirmed memory is listed',
215
+ 15000,
216
+ );
217
+ if (harness.evidence) await harness.browser.screenshot(path.join(harness.evidence, 'mem003-confirmed.png'));
218
+
219
+ evidence.push({
220
+ case: 'MEM-003',
221
+ run: { commitSha: produced.commitSha, memoryCapture: produced.capture },
222
+ candidate: { id: stored.id, status: stored.status, scopeType: stored.scopeType, scopeId: stored.scopeId, evidence: stored.evidence, sourceEventId: stored.sourceEventId, sourceHash: stored.sourceHash, eligibility: stored.eligibility },
223
+ saveCandidateWithoutConfirm: { method: saveCandidatePatch.method, url: saveCandidatePatch.url.replace(harness.base, ''), status: saveCandidatePatch.status, request: saveCandidatePatch.body, response: saveCandidateBody },
224
+ injectedBeforeReview: beforeReview.map(entry => entry.memoryId),
225
+ confirmation: { method: patch.method, url: patch.url.replace(harness.base, ''), status: patch.status, request: patch.body, response: patchBody },
226
+ injectedAfterReview: afterConfirm.map(entry => entry.memoryId),
227
+ scopeLabel: 'honest: the analysis step is the lane stand-in analyzer, not a model',
228
+ });
229
+
230
+ // ---------------------------------------------------------------- MEM-005
231
+ const second = await harness.produceCandidate({ repo, projectId, text: IGNORED_TEXT, scopeType: 'global', file: 'src/ignored.js' });
232
+ assert.equal(second.capture.accepted, 1, `the second real run admitted one candidate: ${JSON.stringify(second.capture)}`);
233
+ const toIgnore = (await harness.productMemories()).find(memory => memory.text === IGNORED_TEXT);
234
+ assert.ok(toIgnore, 'the second candidate really exists in the engine');
235
+ assert.equal(toIgnore.status, 'candidate', 'the second candidate starts as a candidate');
236
+
237
+ await harness.reload();
238
+ await openCandidateBox(harness);
239
+ await harness.waitFor(
240
+ () => harness.run(`document.getElementById('memoryContent').textContent.includes(${JSON.stringify(IGNORED_TEXT)})`),
241
+ 'the second candidate is listed in the candidate box',
242
+ 15000,
243
+ );
244
+ if (harness.evidence) await harness.browser.screenshot(path.join(harness.evidence, 'mem005-candidate-before-ignore.png'));
245
+
246
+ await harness.nativeClick(`[data-memory-action="ignore"][data-memory-id="${toIgnore.id}"]`);
247
+ await harness.waitFor(
248
+ () => harness.run(`!document.getElementById('memoryContent').textContent.includes(${JSON.stringify(IGNORED_TEXT)})`),
249
+ 'the ignored candidate leaves the candidate box',
250
+ 15000,
251
+ );
252
+ const ignorePatch = harness.network.find(entry => entry.method === 'PATCH' && entry.url.includes(`/api/engine/memories/${toIgnore.id}`)).pop();
253
+ assert.ok(ignorePatch, 'the shell really ignored the candidate');
254
+ assert.equal(ignorePatch.status, 200, `the ignore answers 200: ${JSON.stringify(ignorePatch.body)}`);
255
+ assert.deepEqual(ignorePatch.body, { status: 'ignored' }, 'the ignore only changes the status');
256
+ const ignoreBody = await harness.network.body(ignorePatch);
257
+ assert.equal(ignoreBody.memory.status, 'ignored', 'the ignored memory is ignored');
258
+
259
+ const ignored = (await harness.productMemories()).find(memory => memory.id === toIgnore.id);
260
+ assert.ok(ignored, 'the ignored memory is still stored');
261
+ assert.equal(ignored.status, 'ignored', 'the stored memory carries the ignored status');
262
+ assert.equal(ignored.evidence.commitSha, second.commitSha, 'the ignored memory keeps the frozen commit');
263
+ assert.equal(ignored.evidence.entryId, toIgnore.evidence.entryId, 'the ignored memory keeps the frozen entry');
264
+ assert.equal(ignored.evidence.quote, toIgnore.evidence.quote, 'the ignored memory keeps the frozen quote');
265
+ assert.equal(ignored.sourceEventId, toIgnore.sourceEventId, 'the ignored memory keeps the frozen source event');
266
+ assert.equal(ignored.sourceHash, toIgnore.sourceHash, 'the ignored memory keeps the frozen source hash');
267
+ assert.equal(ignored.eligibility.reason, toIgnore.eligibility.reason, 'the ignored memory keeps the recorded reason');
268
+
269
+ const afterIgnore = await harness.injectedMemories(projectId);
270
+ assert.ok(
271
+ !afterIgnore.some(entry => entry.memoryId === toIgnore.id),
272
+ `an ignored memory is never injected: ${JSON.stringify(afterIgnore)}`,
273
+ );
274
+
275
+ // The confirmed memory is untouched by the ignore of another candidate.
276
+ const stillConfirmed = (await harness.productMemories()).find(memory => memory.id === stored.id);
277
+ assert.equal(stillConfirmed.status, 'confirmed', 'ignoring one candidate does not change the confirmed memory');
278
+ if (harness.evidence) await harness.browser.screenshot(path.join(harness.evidence, 'mem005-candidate-after-ignore.png'));
279
+
280
+ evidence.push({
281
+ case: 'MEM-005',
282
+ run: { commitSha: second.commitSha, memoryCapture: second.capture },
283
+ ignored: { id: ignored.id, status: ignored.status, evidence: ignored.evidence, sourceEventId: ignored.sourceEventId, sourceHash: ignored.sourceHash, eligibility: ignored.eligibility },
284
+ ignoreRequest: { method: ignorePatch.method, url: ignorePatch.url.replace(harness.base, ''), status: ignorePatch.status, request: ignorePatch.body, response: ignoreBody },
285
+ injectedAfterIgnore: afterIgnore.map(entry => entry.memoryId),
286
+ });
287
+
288
+ assert.equal(harness.browser.exceptions.length, 0, `no uncaught product JavaScript exceptions: ${JSON.stringify(harness.browser.exceptions)}`);
289
+
290
+ if (harness.evidence) {
291
+ fs.mkdirSync(harness.evidence, { recursive: true });
292
+ fs.writeFileSync(path.join(harness.evidence, 'mem003-mem005-candidate.json'), `${JSON.stringify(evidence, null, 2)}\n`, 'utf8');
293
+ }
294
+
295
+ console.log('parallel-memory-candidate-test PASS (MEM-003 candidate saved and not injected before the review; MEM-005 ignored keeps the frozen source and injects nothing)');
296
+ } finally {
297
+ await harness.cleanup();
298
+ }
299
+ }
300
+
301
+ main().catch(error => { console.error(error.stack || error.message); process.exitCode = 1; });
@@ -0,0 +1,197 @@
1
+ 'use strict';
2
+ // _site/_test/parallel-memory-manual-test.js
3
+ //
4
+ // MEM-001 手动添加 / MEM-002 空白拒绝.
5
+ //
6
+ // Every step runs against a real isolated product instance: its own port,
7
+ // data dir, knowledge root, Bridge journal home and browser profile, with the
8
+ // REAL vendored knowledge engine in-process behind a pass-through proxy. The
9
+ // memory is added through the real UI in a real Chrome: a real pointer click
10
+ // opens the dialog, real key events type the content, a real pointer click
11
+ // submits it.
12
+ //
13
+ // MEM-001 expected:
14
+ // * POST真实保存为confirmed。 -> the captured POST really answers
15
+ // status 'confirmed', sourceType
16
+ // 'manual', evidence null;
17
+ // * 刷新后保留。 -> after a real page reload the memory
18
+ // is still listed, still confirmed, and
19
+ // the memory file on disk still holds
20
+ // it.
21
+ // MEM-002 expected:
22
+ // * 前后端均拒绝。 -> the UI refuses a blank body without
23
+ // sending a request, and the engine
24
+ // itself rejects a blank body;
25
+ // * 不出现空记忆。 -> no memory exists anywhere afterwards.
26
+
27
+ const fs = require('node:fs');
28
+ const path = require('node:path');
29
+ const assert = require('node:assert/strict');
30
+
31
+ const { startHarness, makeRepo } = require('./helpers/parallel-memory-shell');
32
+
33
+ const EVIDENCE = process.env.PK_TEST_EVIDENCE_DIR ? path.resolve(process.env.PK_TEST_EVIDENCE_DIR) : null;
34
+ const MEMORY_TEXT = '对外错误信息使用中文表述,并优先复用已有模块。';
35
+
36
+ async function openMemoryView(harness) {
37
+ await harness.nativeClick('nav [data-view="memory"]');
38
+ await harness.waitFor(
39
+ () => harness.run("document.getElementById('view-memory').classList.contains('active')"),
40
+ 'the memory view is open',
41
+ 10000,
42
+ );
43
+ }
44
+
45
+ async function main() {
46
+ const harness = await startHarness({ tag: 'mem001', evidenceDir: EVIDENCE || undefined });
47
+ const evidence = [];
48
+ try {
49
+ const repo = makeRepo(harness.fixture, 'mem001-repo', { 'README.md': '# 记忆甲\n' });
50
+ const { projectId } = await harness.importProject(repo, '记忆甲');
51
+
52
+ // The shell has to know the project before it can bind a project scope.
53
+ await harness.requestRegistryRefresh();
54
+ await harness.waitFor(
55
+ () => harness.run("document.getElementById('homeContent').textContent.includes('记忆甲')"),
56
+ 'the imported project is listed',
57
+ 20000,
58
+ );
59
+
60
+ await openMemoryView(harness);
61
+ await harness.waitFor(
62
+ () => harness.run("!document.getElementById('addMemory').disabled"),
63
+ 'the engine is reachable and the add button is live',
64
+ 20000,
65
+ );
66
+
67
+ // ---------------------------------------------------------------- MEM-002
68
+ await harness.nativeClick('#addMemory');
69
+ await harness.waitFor(
70
+ () => harness.run("document.getElementById('memoryDialog').open === true"),
71
+ 'the add dialog is open',
72
+ 10000,
73
+ );
74
+ // Real key events into the really focused textarea.
75
+ await harness.typeText(' ');
76
+ const typed = await harness.run("document.getElementById('memoryText').value");
77
+ assert.equal(typed, ' ', 'the blank body really reached the textarea');
78
+
79
+ const postsBefore = harness.network.find(entry => entry.method === 'POST' && entry.url.includes('/api/engine/memories')).length;
80
+ await harness.nativeClick('#confirmMemory');
81
+ await harness.waitFor(
82
+ () => harness.run("document.getElementById('memoryFeedback').hidden === false"),
83
+ 'the shell refuses the blank body in the dialog',
84
+ 10000,
85
+ );
86
+ const feedback = await harness.run("document.getElementById('memoryFeedback').textContent");
87
+ assert.match(String(feedback), /请填写记忆内容。/, 'the shell names the missing content');
88
+ const postsAfter = harness.network.find(entry => entry.method === 'POST' && entry.url.includes('/api/engine/memories')).length;
89
+ assert.equal(postsAfter, postsBefore, 'the shell must not send a request for a blank body');
90
+
91
+ // The backend refuses the same blank body on its own.
92
+ const backendBlank = await harness.productApi('POST', '/api/engine/memories', { text: ' ', scopeType: 'global', scopeId: 'brain-default', brainId: 'brain-default' });
93
+ assert.equal(backendBlank.status, 400, `the engine refuses a blank body: ${JSON.stringify(backendBlank.body)}`);
94
+ assert.equal(backendBlank.body.error, 'INVALID_ARGUMENT', 'the engine reports an invalid argument');
95
+ assert.match(String(backendBlank.body.message), /记忆内容必须为 1–2000 个字符。/, 'the engine names the length rule');
96
+
97
+ const afterBlank = await harness.productMemories();
98
+ assert.deepEqual(afterBlank, [], 'a refused blank body creates no memory at all');
99
+ if (harness.evidence) await harness.browser.screenshot(path.join(harness.evidence, 'mem002-blank-refused.png'));
100
+
101
+ evidence.push({
102
+ case: 'MEM-002',
103
+ frontEnd: { feedback, requestsSent: postsAfter - postsBefore },
104
+ backEnd: { status: backendBlank.status, body: backendBlank.body },
105
+ memoriesAfter: afterBlank.length,
106
+ });
107
+
108
+ // ---------------------------------------------------------------- MEM-001
109
+ // The same dialog now carries a real body. The rejected submit left the
110
+ // focus on the confirm button, so the real user clicks back into the field.
111
+ await harness.nativeClick('#memoryText');
112
+ await harness.pressBackspace(3);
113
+ await harness.typeText(MEMORY_TEXT);
114
+ const body = await harness.run("document.getElementById('memoryText').value");
115
+ assert.equal(body, MEMORY_TEXT, 'the real body reached the textarea');
116
+
117
+ await harness.nativeClick('#confirmMemory');
118
+ await harness.waitFor(
119
+ () => harness.run("document.getElementById('memoryDialog').open === false"),
120
+ 'the dialog closes after a confirmed save',
121
+ 15000,
122
+ );
123
+
124
+ const post = harness.network.find(entry => entry.method === 'POST' && entry.url.includes('/api/engine/memories')).pop();
125
+ assert.ok(post, 'the shell really posted a memory');
126
+ assert.equal(post.status, 200, `the real POST answers 200: ${JSON.stringify(post.body)}`);
127
+ const postBody = await harness.network.body(post);
128
+ assert.ok(postBody && postBody.memory, `the real POST answers with the memory: ${JSON.stringify(postBody)}`);
129
+ const created = postBody.memory;
130
+ assert.equal(created.status, 'confirmed', 'the memory is saved as confirmed');
131
+ assert.equal(created.sourceType, 'manual', 'a manual memory has no model source');
132
+ assert.equal(created.evidence, null, 'a manual memory invents no evidence');
133
+ assert.equal(created.text, MEMORY_TEXT, 'the saved text is the text that was typed');
134
+ assert.equal(created.scopeType, 'project', 'the default scope of an active project is the project itself');
135
+ assert.equal(created.scopeId, projectId, 'the scope target is the active project');
136
+ assert.ok(created.id, 'the memory has an id');
137
+
138
+ // The memory is listed in the real UI.
139
+ await harness.waitFor(
140
+ () => harness.run(`document.getElementById('memoryContent').textContent.includes(${JSON.stringify(MEMORY_TEXT)})`),
141
+ 'the new memory is listed',
142
+ 15000,
143
+ );
144
+ if (harness.evidence) await harness.browser.screenshot(path.join(harness.evidence, 'mem001-confirmed.png'));
145
+
146
+ // The memory file really holds the memory.
147
+ const brainScope = harness.brainScopePath();
148
+ const memoryFile = path.join(brainScope, 'memories', 'projects', `${projectId}.md`);
149
+ assert.ok(fs.existsSync(memoryFile), `the memory file exists: ${memoryFile}`);
150
+ const fileText = fs.readFileSync(memoryFile, 'utf8');
151
+ assert.ok(fileText.includes(created.id), 'the memory file names the memory');
152
+ assert.ok(fileText.includes(MEMORY_TEXT), 'the memory file holds the text');
153
+ assert.match(fileText, /来源:手动添加(用户确认)/, 'the memory file records the manual source');
154
+
155
+ // A confirmed, applicable memory is injected into the task.
156
+ const injected = await harness.injectedMemories(projectId);
157
+ assert.ok(injected.some(memory => memory.memoryId === created.id), `the confirmed memory is injected: ${JSON.stringify(injected)}`);
158
+
159
+ // 刷新后保留: a real reload of the real page.
160
+ await harness.reload();
161
+ await harness.waitFor(
162
+ () => harness.run(`document.getElementById('memoryContent').textContent.includes(${JSON.stringify(MEMORY_TEXT)})`),
163
+ 'the memory is still listed after a real reload',
164
+ 25000,
165
+ );
166
+ if (harness.evidence) await harness.browser.screenshot(path.join(harness.evidence, 'mem001-after-reload.png'));
167
+ const afterReload = await harness.productMemories();
168
+ const kept = afterReload.find(memory => memory.id === created.id);
169
+ assert.ok(kept, 'the memory survives the reload');
170
+ assert.equal(kept.status, 'confirmed', 'the memory is still confirmed after the reload');
171
+ assert.equal(kept.text, MEMORY_TEXT, 'the memory text survives the reload');
172
+ assert.equal(kept.scopeType, 'project', 'the scope survives the reload');
173
+ assert.equal(kept.scopeId, projectId, 'the scope target survives the reload');
174
+ assert.equal(kept.syncStatus, 'ready', 'the memory file is in sync');
175
+
176
+ evidence.push({
177
+ case: 'MEM-001',
178
+ request: { method: post.method, url: post.url.replace(harness.base, ''), status: post.status, request: post.body, response: postBody },
179
+ memoryFile: { path: memoryFile, sha256: require('node:crypto').createHash('sha256').update(fileText).digest('hex') },
180
+ afterReload: kept,
181
+ injected: injected.map(memory => memory.memoryId),
182
+ });
183
+
184
+ assert.equal(harness.browser.exceptions.length, 0, `no uncaught product JavaScript exceptions: ${JSON.stringify(harness.browser.exceptions)}`);
185
+
186
+ if (harness.evidence) {
187
+ fs.mkdirSync(harness.evidence, { recursive: true });
188
+ fs.writeFileSync(path.join(harness.evidence, 'mem001-manual.json'), `${JSON.stringify(evidence, null, 2)}\n`, 'utf8');
189
+ }
190
+
191
+ console.log(`parallel-memory-manual-test PASS (MEM-001 confirmed + survives a real reload; MEM-002 refused by the shell without a request and by the engine with 400)`);
192
+ } finally {
193
+ await harness.cleanup();
194
+ }
195
+ }
196
+
197
+ main().catch(error => { console.error(error.stack || error.message); process.exitCode = 1; });