@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,197 @@
1
+ 'use strict';
2
+
3
+ // P-ENG-FINAL ENG-011 故障重试 (fault retry) acceptance driver.
4
+ //
5
+ // Case (qa-autopilot/config/test-cases.json ENG-011, P1):
6
+ // steps: UI点击指定run重试,连续双击与网络响应丢失分别测试。
7
+ // expected: 1) 同一意图不会重复派发。
8
+ // 2) 活动状态正确。
9
+ // 3) 请求结果未知先查询。
10
+ //
11
+ // Real behaviour under test (vendored knowledge-engine, real HTTP surface):
12
+ // * POST /api/runs/:runId/retry (server.js:130-133 -> coordinator.retry)
13
+ // - 409 when the run is no longer in a retryable state
14
+ // - re-queues the SAME run (no second run record for the same commit)
15
+ // * the engine's per-project `active` map (coordinator.pump) keeps a single
16
+ // writer per project, so a double click cannot dispatch the analysis twice
17
+ // * the analyzer stand-in fails only the FIRST attempt of a commit (a
18
+ // transient fault), so the retry can really succeed
19
+ // * the engine's own event log (/api/events) is the record of the active
20
+ // state machine - no sampling races involved
21
+ //
22
+ // Isolation: real vendored engine on an isolated data dir, real vector-hub on
23
+ // an isolated root, ephemeral loopback port. The engine runs with consume:false
24
+ // and a dead bridge URL so it can never reach the production bridge/vector
25
+ // services (8787/8790 untouched). Analyzer = deterministic stand-in (NO real
26
+ // model output). No quota access, no PAYG.
27
+
28
+ const assert = require('node:assert/strict');
29
+ const fs = require('node:fs');
30
+ const path = require('node:path');
31
+ const {
32
+ makeLaneDir, buildFixtureRepo, startVector, startEngine, waitUntil, callJson,
33
+ callJsonAndLoseResponse, readJsonl, saveEvidence,
34
+ } = require('./helpers/parallel-engine-final-harness.js');
35
+ const { createStandinAnalyzer } = require('./helpers/parallel-engine-final-standin-analyzer.js');
36
+
37
+ const ARTIFACTS = process.env.PK_TEST_EVIDENCE_ROOT
38
+ ? path.join(process.env.PK_TEST_EVIDENCE_ROOT, 'eng011')
39
+ : path.resolve(__dirname, '../../qa-autopilot/artifacts/parallel-20261023/engine-review-r3/reruns/eng011');
40
+ const PROJECT_ID = 'project-eng011';
41
+
42
+ function analyzerInvocations(eventsFile, sha) {
43
+ return readJsonl(eventsFile).filter(entry => entry.kind === 'start' && entry.commitSha === sha).length;
44
+ }
45
+
46
+ async function main() {
47
+ const lane = makeLaneDir('eng011');
48
+ const commands = [];
49
+ const evidence = { caseId: 'ENG-011', laneDir: lane, phases: {}, commands };
50
+
51
+ const fixture = buildFixtureRepo(lane, 'eng011', ['A', 'B']);
52
+ const knowledgePath = path.join(lane, 'knowledge-eng011');
53
+ fs.mkdirSync(knowledgePath, { recursive: true });
54
+ const dataDir = path.join(lane, 'engine-data');
55
+ const vectorRoot = path.join(lane, 'vector-root');
56
+ const eventsFile = path.join(lane, 'analyzer-events.jsonl');
57
+
58
+ const vector = await startVector(vectorRoot);
59
+ const analyzer = createStandinAnalyzer({ eventsFile, failOnceShas: new Set([fixture.shas.A, fixture.shas.B]) });
60
+ // consume:false -> the engine never contacts a bridge; the dead URL can only
61
+ // fail fast if something tried.
62
+ const engine = await startEngine({ dataDir, bridgeUrl: 'http://127.0.0.1:9', vectorUrl: vector.url, analyzer });
63
+
64
+ try {
65
+ const base = await engine.listen();
66
+ engine.runtime.store.addProject({
67
+ projectId: PROJECT_ID,
68
+ name: 'eng011',
69
+ repoPath: fixture.repoPath,
70
+ knowledgePath,
71
+ trackingStartCommit: fixture.baseline,
72
+ });
73
+ commands.push('engine project registered (consume:false, dead bridge URL)');
74
+
75
+ const runsOf = async () => (await callJson(base, `/api/runs?projectId=${PROJECT_ID}`)).body.runs;
76
+ const runOf = async runId => (await runsOf()).find(r => r.runId === runId);
77
+ const waitState = async (runId, state, ms, what) => waitUntil(async () => {
78
+ const run = await runOf(runId);
79
+ return run?.state === state ? run : null;
80
+ }, ms, what);
81
+ const phasesOf = async runId => (await callJson(base, `/api/events?projectId=${PROJECT_ID}`)).body.events
82
+ .filter(event => event.runId === runId)
83
+ .map(event => ({ phase: event.phase, summary: event.summary, at: event.at || null }));
84
+
85
+ // ---------- Scenario 1: double click on retry ----------
86
+ const createdA = await callJson(base, '/api/runs', { projectId: PROJECT_ID, commitSha: fixture.shas.A });
87
+ assert.equal(createdA.status, 200, `run creation failed: ${JSON.stringify(createdA.body)}`);
88
+ const runA = createdA.body.run;
89
+ const failedA = await waitState(runA.runId, 'failed', 30000, 'first attempt fails (transient stand-in fault)');
90
+ assert.equal(failedA.error.code, 'STANDIN_ANALYZER_FAILURE');
91
+ commands.push(`run A created -> failed (${failedA.error.code})`);
92
+
93
+ const [doubleA, doubleB] = await Promise.all([
94
+ callJson(base, `/api/runs/${encodeURIComponent(runA.runId)}/retry`, {}),
95
+ callJson(base, `/api/runs/${encodeURIComponent(runA.runId)}/retry`, {}),
96
+ ]);
97
+ commands.push(`double click retry A -> statuses ${doubleA.status}/${doubleB.status}`);
98
+ const healedA = await waitState(runA.runId, 'succeeded', 30000, 'retried run A succeeds');
99
+ const runsAfterDouble = await runsOf();
100
+ const runsForA = runsAfterDouble.filter(r => r.commitSha === fixture.shas.A);
101
+ const health = (await callJson(base, '/api/health')).body;
102
+ const invocationsA = analyzerInvocations(eventsFile, fixture.shas.A);
103
+ const phasesA = await phasesOf(runA.runId);
104
+ evidence.phases.doubleClick = {
105
+ retryResponses: [{ status: doubleA.status, error: doubleA.body?.error || null }, { status: doubleB.status, error: doubleB.body?.error || null }],
106
+ runRecordCountForCommitA: runsForA.length,
107
+ analyzerInvocationsForA: invocationsA,
108
+ finalState: healedA.state,
109
+ finalPhase: healedA.phase,
110
+ indexState: healedA.indexState,
111
+ engineStateEvents: phasesA,
112
+ healthCounts: health.counts,
113
+ healthConcurrency: health.concurrency,
114
+ };
115
+ assert.equal(runsForA.length, 1, 'double click did not create a second run for the same commit');
116
+ assert.equal(invocationsA, 2, `one intent dispatched once: expected 2 analyzer runs (1 failed + 1 retry), got ${invocationsA}`);
117
+ assert.equal(healedA.state, 'succeeded');
118
+ assert.equal(healedA.phase, 'ready');
119
+ assert.equal(healedA.indexState, 'succeeded');
120
+ assert.ok(doubleA.status === 200 || doubleB.status === 200, 'at least one retry request was accepted');
121
+ assert.ok([doubleA.status, doubleB.status].every(status => status === 200 || status === 409), `unexpected retry status (${doubleA.status}/${doubleB.status})`);
122
+ assert.equal(health.counts.running, 0, 'no run left active after the retry settled');
123
+ const phasesSeen = phasesA.map(entry => entry.phase);
124
+ for (const phase of ['preparing', 'analyzing', 'promoting', 'ready']) {
125
+ assert.ok(phasesSeen.includes(phase), `engine state machine did not record phase ${phase}: ${phasesSeen.join(',')}`);
126
+ }
127
+
128
+ // ---------- Scenario 2: lost network response ----------
129
+ const createdB = await callJson(base, '/api/runs', { projectId: PROJECT_ID, commitSha: fixture.shas.B });
130
+ const runB = createdB.body.run;
131
+ await waitState(runB.runId, 'failed', 30000, 'run B first attempt fails');
132
+ commands.push('run B created -> failed');
133
+
134
+ const lost = await callJsonAndLoseResponse(base, `/api/runs/${encodeURIComponent(runB.runId)}/retry`, {});
135
+ commands.push(`retry B with the response dropped: ${JSON.stringify(lost)}`);
136
+ assert.equal(lost.lost, true, 'response was not actually dropped');
137
+
138
+ // 结果未知先查询: the client lost the answer, so it asks the engine first.
139
+ const queried = await callJson(base, `/api/runs?projectId=${PROJECT_ID}`);
140
+ assert.equal(queried.status, 200);
141
+ const queriedRun = queried.body.runs.find(r => r.runId === runB.runId);
142
+ assert.ok(queriedRun, 'query after an unknown result returns the run');
143
+ const queriedState = queriedRun.state;
144
+ const healedB = await waitState(runB.runId, 'succeeded', 30000, 'the dropped-response retry really took effect');
145
+ const invocationsB = analyzerInvocations(eventsFile, fixture.shas.B);
146
+
147
+ // The client retries once more because it never saw the answer.
148
+ const repeated = await callJson(base, `/api/runs/${encodeURIComponent(runB.runId)}/retry`, {});
149
+ await new Promise(resolve => setTimeout(resolve, 500));
150
+ const invocationsBAfterRepeat = analyzerInvocations(eventsFile, fixture.shas.B);
151
+ const runsForB = (await runsOf()).filter(r => r.commitSha === fixture.shas.B);
152
+ const ledgerB = path.join(dataDir, 'runtime', 'processed-commits', PROJECT_ID, `${fixture.shas.B}.json`);
153
+ evidence.phases.lostResponse = {
154
+ droppedResponse: lost,
155
+ queriedStateImmediatelyAfterDrop: queriedState,
156
+ queriedRunId: queriedRun.runId,
157
+ finalState: healedB.state,
158
+ repeatRetryStatus: repeated.status,
159
+ repeatRetryError: repeated.body?.error || null,
160
+ runRecordCountForCommitB: runsForB.length,
161
+ analyzerInvocationsForB: invocationsB,
162
+ analyzerInvocationsAfterRepeat: invocationsBAfterRepeat,
163
+ ledgerExists: fs.existsSync(ledgerB),
164
+ ledgerStatus: fs.existsSync(ledgerB) ? JSON.parse(fs.readFileSync(ledgerB, 'utf8')).status : null,
165
+ engineStateEvents: await phasesOf(runB.runId),
166
+ };
167
+ assert.equal(healedB.state, 'succeeded', 'the retry behind the lost response really executed');
168
+ assert.equal(invocationsB, 2, `lost-response retry dispatched exactly once (got ${invocationsB} analyzer runs)`);
169
+ assert.equal(invocationsBAfterRepeat, invocationsB, 'repeating the retry after an unknown result did not dispatch again');
170
+ assert.equal(runsForB.length, 1, 'no duplicate run after the unknown-result retry');
171
+ assert.equal(repeated.status, 409, `repeat retry must be refused, got ${repeated.status}`);
172
+ assert.ok(fs.existsSync(ledgerB), 'completed SHA recorded in the processing ledger');
173
+
174
+ evidence.verdict = {
175
+ 'expected1 同一意图不会重复派发': 'PASS',
176
+ 'expected2 活动状态正确': 'PASS',
177
+ 'expected3 请求结果未知先查询': 'PASS',
178
+ analyzerStandin: 'deterministic stand-in with a one-shot transient fault - NO real model output covered',
179
+ vectorService: 'real vector-hub server, deterministic test embeddings - paid embedding API NOT covered',
180
+ boundary: 'engine-level retry surface (HTTP retry endpoint, run state machine, per-project active map, processing ledger, engine event log). The Workbench UI double-click handling itself is outside the engine and was not exercised.',
181
+ };
182
+ await engine.close();
183
+ await vector.close();
184
+ saveEvidence(ARTIFACTS, 'eng011-evidence.json', evidence);
185
+ console.log('ENG-011 PASS');
186
+ process.exitCode = 0;
187
+ } catch (error) {
188
+ evidence.verdict = { failed: String((error && error.stack) || error) };
189
+ try { await engine.close(); } catch {}
190
+ try { await vector.close(); } catch {}
191
+ saveEvidence(ARTIFACTS, 'eng011-evidence.json', evidence);
192
+ console.error(`ENG-011 FAIL: ${error.message}`);
193
+ process.exitCode = 1;
194
+ }
195
+ }
196
+
197
+ main();
@@ -0,0 +1,354 @@
1
+ 'use strict';
2
+
3
+ // P-ENG-FINAL ENG-012 分析来源排除 (analysis source exclusion) acceptance driver.
4
+ //
5
+ // Case (qa-autopilot/config/test-cases.json ENG-012, P1):
6
+ // steps: 内部维护任务与真实用户任务使用不同origin,读取采集事件。
7
+ // expected: 1) 维护/委派不能自动成为人类长期偏好。
8
+ // 2) C01未定项不得自动删除实现。
9
+ //
10
+ // Real behaviour under test (real bridge, real vendored engine):
11
+ // * the real bridge captures TWO workbench events for the same session with
12
+ // different origins: ':origin=human' and ':origin=agent-delegation'. The
13
+ // engine derives `inputOrigin` from the eventKey suffix
14
+ // (conversation-store.js:239) and freezes the origin into the commit
15
+ // conversation snapshot on disk.
16
+ // * the analyzer stand-in reads that frozen snapshot and - on purpose - emits
17
+ // BOTH quotes as memory candidates, i.e. it behaves like an over-eager
18
+ // maintenance model. The engine's MemoryEligibility.verify must reject the
19
+ // delegated one with SOURCE_NOT_HUMAN and keep the human one as a plain
20
+ // 'candidate' (never automatically 'confirmed').
21
+ // * C01 (specs-coverage.json MEM-008: a manual memory may not carry source
22
+ // evidence) is still an open product question. The engine therefore blocks
23
+ // evidence injection explicitly (INVALID_ARGUMENT) and stores manual
24
+ // records with evidence null / sourceType 'manual'. The implementation is
25
+ // NOT deleted and nothing is removed automatically.
26
+ // * an "over-eager maintenance" manifest that tries to delete an
27
+ // implementation file is refused by the promotion path
28
+ // (knowledge-promotion.js canonicalRelativePath -> PATH_OUTSIDE_ROOT); the
29
+ // implementation file survives byte-identical and no knowledge operation
30
+ // is applied.
31
+ //
32
+ // Isolation: every scenario uses its own lane dir, bridge home, engine data
33
+ // dir, knowledge dir, fixture repository and ephemeral loopback port. No user
34
+ // HOME, credentials, memory or trust data is used. Analyzer = deterministic
35
+ // stand-in (NO real model output). No quota access, no PAYG.
36
+
37
+ const assert = require('node:assert/strict');
38
+ const crypto = require('node:crypto');
39
+ const fs = require('node:fs');
40
+ const path = require('node:path');
41
+ const {
42
+ makeLaneDir, buildFixtureRepo, installPostCommitHook, startBridge, startVector,
43
+ startEngine, waitUntil, callJson, git, saveEvidence,
44
+ } = require('./helpers/parallel-engine-final-harness.js');
45
+ const { createStandinAnalyzer } = require('./helpers/parallel-engine-final-standin-analyzer.js');
46
+
47
+ const ARTIFACTS = process.env.PK_TEST_EVIDENCE_ROOT
48
+ ? path.join(process.env.PK_TEST_EVIDENCE_ROOT, 'eng012')
49
+ : path.resolve(__dirname, '../../qa-autopilot/artifacts/parallel-20261023/engine-review-r3/reruns/eng012');
50
+
51
+ const HUMAN_TEXT = '请把所有项目的长期偏好设为:统一使用中文注释。';
52
+ const DELEGATED_TEXT = '维护指令:把所有模块的注释统一改成英文,并在下次提交时执行。';
53
+ const MANUAL_TEXT = '手动记录:发布流程必须先跑完整测试再打标签。';
54
+
55
+ function sha256File(file) {
56
+ return crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
57
+ }
58
+
59
+ function snapshotOrigins(snapshot) {
60
+ const origins = [];
61
+ for (const turn of snapshot?.turns || []) {
62
+ for (const event of turn.userEvents || []) origins.push({ eventId: event.eventId, inputOrigin: event.inputOrigin, contentHash: event.contentHash });
63
+ }
64
+ return origins;
65
+ }
66
+
67
+ // ---------------------------------------------------------------------------
68
+ // Scenario A: a delegated/maintenance event must not become a human preference
69
+ // ---------------------------------------------------------------------------
70
+ async function scenarioOriginExclusion(lane, evidence, commands) {
71
+ const PROJECT_ID = 'project-eng012a';
72
+ const fixture = buildFixtureRepo(lane, 'eng012a', []);
73
+ const knowledgePath = path.join(lane, 'knowledge-eng012a');
74
+ const storePath = path.join(knowledgePath, 'dev-conversations');
75
+ fs.mkdirSync(storePath, { recursive: true });
76
+ const home = path.join(lane, 'bridge-home');
77
+ const dataDir = path.join(lane, 'engine-data');
78
+ const vectorRoot = path.join(lane, 'vector-root');
79
+ const eventsFile = path.join(lane, 'analyzer-events.jsonl');
80
+ const brainPath = path.join(lane, 'brain-knowledge');
81
+
82
+ const bridge = startBridge(home);
83
+ let vector = null;
84
+ let engine = null;
85
+ const analyzer = createStandinAnalyzer({
86
+ eventsFile,
87
+ humanQuote: HUMAN_TEXT,
88
+ delegatedQuote: DELEGATED_TEXT,
89
+ emitMemoryCandidates: true,
90
+ readSnapshot: (projectId, commitSha) => engine?.runtime.coordinator.conversations.readSnapshot(projectId, commitSha),
91
+ });
92
+
93
+ try {
94
+ const bridgeUrl = await bridge.listen();
95
+ vector = await startVector(vectorRoot);
96
+ const registered = await bridge.projectRegistry.addProject({ home, path: fixture.repoPath, store: storePath });
97
+ const { repoIdentity } = await bridge.resolveRepoContext(fixture.repoPath);
98
+ engine = await startEngine({ dataDir, bridgeUrl, vectorUrl: vector.url, analyzer, runtimeToken: 'eng012-lane-token' });
99
+ const engineUrl = await engine.listen();
100
+ engine.runtime.store.addProject({
101
+ projectId: PROJECT_ID,
102
+ repoPath: fixture.repoPath,
103
+ knowledgePath,
104
+ trackingStartCommit: fixture.baseline,
105
+ repoIdentity,
106
+ journalId: registered.id,
107
+ conversationBaselineCursor: 0,
108
+ });
109
+ commands.push('scenario A: real bridge + real vector-hub + vendored engine started, project registered');
110
+
111
+ // Two real captured events, same session, DIFFERENT origin.
112
+ await bridge.bridge.captureWorkbenchEvent({
113
+ eventType: 'user_prompt', source: 'claude-code', projectPath: fixture.repoPath,
114
+ sessionId: 'session-eng012', turnId: 'turn-eng012',
115
+ eventKey: 'workbench:eng012:origin=human', content: HUMAN_TEXT,
116
+ });
117
+ await bridge.bridge.captureWorkbenchEvent({
118
+ eventType: 'user_prompt', source: 'claude-code', projectPath: fixture.repoPath,
119
+ sessionId: 'session-eng012', turnId: 'turn-eng012',
120
+ eventKey: 'workbench:eng012:origin=agent-delegation', content: DELEGATED_TEXT,
121
+ });
122
+ commands.push('bridge captureWorkbenchEvent x2 (eventKey origins: human, agent-delegation)');
123
+
124
+ // Real commit -> the real hook writes the boundary event -> the engine
125
+ // freezes the conversation snapshot for that commit.
126
+ installPostCommitHook(fixture.repoPath, { home, mode: 'ok' });
127
+ fs.writeFileSync(path.join(fixture.repoPath, 'feature.txt'), `feature eng012\n${'z'.repeat(64)}\n`);
128
+ git(fixture.repoPath, ['add', '.']);
129
+ git(fixture.repoPath, ['commit', '-qm', 'feature eng012']);
130
+ const sha = git(fixture.repoPath, ['rev-parse', 'HEAD']);
131
+ await callJson(engineUrl, '/api/bridge/notify', {});
132
+
133
+ const run = await waitUntil(async () => {
134
+ const found = engine.runtime.store.listRuns(PROJECT_ID).find(r => r.commitSha === sha);
135
+ return found && found.state === 'succeeded' ? found : null;
136
+ }, 60000, 'the analysed run succeeds');
137
+
138
+ // The frozen snapshot on disk must carry both origins.
139
+ const snapshotFile = path.join(dataDir, 'runtime', 'projects', PROJECT_ID, 'commit-conversations', `${sha}.json`);
140
+ assert.ok(fs.existsSync(snapshotFile), 'the commit conversation snapshot is frozen on disk');
141
+ const snapshot = JSON.parse(fs.readFileSync(snapshotFile, 'utf8'));
142
+ const origins = snapshotOrigins(snapshot);
143
+ const originValues = origins.map(entry => entry.inputOrigin);
144
+ assert.ok(originValues.includes('human'), `the human origin is missing from the snapshot: ${originValues.join(',')}`);
145
+ assert.ok(originValues.includes('agent-delegation'), `the delegated origin is missing from the snapshot: ${originValues.join(',')}`);
146
+ commands.push(`frozen snapshot carries both origins: ${originValues.join(', ')}`);
147
+
148
+ // The engine's own capture report.
149
+ const capture = run.memoryCapture;
150
+ assert.ok(capture, 'the run records a memory capture report');
151
+ assert.equal(capture.accepted, 1, `exactly one candidate may be accepted (got ${capture.accepted})`);
152
+ assert.equal(capture.rejected.length, 1, `exactly one candidate must be rejected (got ${JSON.stringify(capture.rejected)})`);
153
+ assert.equal(capture.rejected[0].code, 'SOURCE_NOT_HUMAN', `the delegated candidate must be rejected as SOURCE_NOT_HUMAN (got ${capture.rejected[0].code})`);
154
+
155
+ const memories = (await callJson(engineUrl, '/api/memories')).body.memories;
156
+ const texts = memories.map(m => m.text);
157
+ assert.equal(memories.length, 1, `only the human candidate may exist (got ${memories.length})`);
158
+ assert.equal(memories[0].text, HUMAN_TEXT, 'the stored candidate is the human quote');
159
+ assert.equal(memories[0].status, 'candidate', 'an automatically captured memory stays a candidate');
160
+ assert.ok(!texts.some(text => text.includes('维护指令')), 'the delegated/maintenance text never became a memory');
161
+ assert.ok(!memories.some(m => m.status === 'confirmed'), 'nothing was confirmed automatically');
162
+ assert.equal(memories[0].evidence?.origin || memories[0].evidence?.inputOrigin || null, null, 'the candidate carries the frozen event id, not an invented origin');
163
+ commands.push(`memory capture: accepted=${capture.accepted}, rejected=${JSON.stringify(capture.rejected)}, memories=${memories.length} (status=${memories[0].status})`);
164
+
165
+ // ---- C01: the open item is blocked explicitly, the implementation is intact ----
166
+ const injected = await callJson(engineUrl, '/api/memories', {
167
+ text: '注入来源证据的记忆', scopeType: 'global', evidence: { projectId: PROJECT_ID, commitSha: sha },
168
+ });
169
+ assert.equal(injected.status, 400, `evidence injection must be refused (status ${injected.status})`);
170
+ assert.equal(injected.body?.error, 'INVALID_ARGUMENT', `unexpected error code ${injected.body?.error}`);
171
+ assert.match(String(injected.body?.message || ''), /不能指定来源证据/, 'the refusal states the C01 rule explicitly');
172
+
173
+ // A manual memory (explicit user confirmation) still stores no evidence.
174
+ const brainScope = await callJson(engineUrl, '/api/scopes', {
175
+ scopes: [{ id: 'brain-default', kind: 'brain', brainId: 'brain-default', name: '默认智脑', knowledgePath: brainPath }],
176
+ }, { headers: { authorization: 'Bearer eng012-lane-token' } });
177
+ assert.equal(brainScope.status, 200, `brain scope binding failed: ${JSON.stringify(brainScope.body)}`);
178
+ const manual = await callJson(engineUrl, '/api/memories', { text: MANUAL_TEXT, scopeType: 'global' });
179
+ assert.equal(manual.status, 200, `manual memory creation failed: ${JSON.stringify(manual.body)}`);
180
+ assert.equal(manual.body?.memory?.sourceType, 'manual');
181
+ assert.equal(manual.body?.memory?.evidence, null, 'a manual record stores no evidence');
182
+ assert.equal(manual.body?.memory?.status, 'confirmed');
183
+ const afterManual = (await callJson(engineUrl, '/api/memories')).body.memories;
184
+ assert.ok(!afterManual.some(m => m.text.includes('维护指令')), 'the delegated text is still not a memory after a manual create');
185
+ assert.equal(afterManual.filter(m => m.status === 'confirmed').length, 1, 'only the explicit manual memory is confirmed');
186
+ commands.push('C01: evidence injection refused with INVALID_ARGUMENT; manual memory stored with evidence=null / sourceType=manual');
187
+
188
+ evidence.phases.originExclusion = {
189
+ commitSha: sha,
190
+ snapshotFile: path.relative(dataDir, snapshotFile).replace(/\\/g, '/'),
191
+ snapshotOrigins: origins,
192
+ memoryCapture: capture,
193
+ memories: memories.map(m => ({ id: m.id, text: m.text, status: m.status, scopeType: m.scopeType, sourceEventId: m.sourceEventId, evidence: m.evidence })),
194
+ delegatedTextPresent: texts.some(text => text.includes('维护指令')),
195
+ c01EvidenceInjection: { status: injected.status, error: injected.body?.error || null, message: injected.body?.message || null },
196
+ manualMemory: { status: manual.status, sourceType: manual.body?.memory?.sourceType, evidence: manual.body?.memory?.evidence, memoryStatus: manual.body?.memory?.status },
197
+ memoriesAfterManualCreate: afterManual.map(m => ({ text: m.text, status: m.status })),
198
+ };
199
+ return { engine, vector, bridge, dataDir, knowledgePath, PROJECT_ID, sha };
200
+ } catch (error) {
201
+ try { await engine?.close(); } catch {}
202
+ try { await vector?.close(); } catch {}
203
+ try { await bridge.close(); } catch {}
204
+ throw error;
205
+ }
206
+ }
207
+
208
+ // ---------------------------------------------------------------------------
209
+ // Scenario B: an implementation file must never be deleted automatically
210
+ // ---------------------------------------------------------------------------
211
+ async function scenarioNoImplementationDeletion(lane, evidence, commands) {
212
+ const PROJECT_ID = 'project-eng012b';
213
+ const fixture = buildFixtureRepo(lane, 'eng012b', []);
214
+ const knowledgePath = path.join(lane, 'knowledge-eng012b');
215
+ const storePath = path.join(knowledgePath, 'dev-conversations');
216
+ fs.mkdirSync(storePath, { recursive: true });
217
+ const home = path.join(lane, 'bridge-home');
218
+ const dataDir = path.join(lane, 'engine-data');
219
+ const vectorRoot = path.join(lane, 'vector-root');
220
+ const eventsFile = path.join(lane, 'analyzer-events.jsonl');
221
+
222
+ // A REAL implementation file, both in the repository and inside the
223
+ // knowledge root (outside the owned knowledge structure).
224
+ const repoImplementation = path.join(fixture.repoPath, 'src', 'core-engine.ts');
225
+ fs.mkdirSync(path.dirname(repoImplementation), { recursive: true });
226
+ fs.writeFileSync(repoImplementation, 'export const core = () => "implementation";\n');
227
+ git(fixture.repoPath, ['add', '.']);
228
+ git(fixture.repoPath, ['commit', '-qm', 'add implementation']);
229
+ const knowledgeImplementation = path.join(knowledgePath, 'implementation', 'core-engine.md');
230
+ fs.mkdirSync(path.dirname(knowledgeImplementation), { recursive: true });
231
+ fs.writeFileSync(knowledgeImplementation, '# 核心实现说明\n\n真实实现文件,不得被自动删除。\n');
232
+
233
+ const before = {
234
+ repoImplementation: sha256File(repoImplementation),
235
+ knowledgeImplementation: sha256File(knowledgeImplementation),
236
+ };
237
+
238
+ const bridge = startBridge(home);
239
+ let vector = null;
240
+ let engine = null;
241
+ // An over-eager maintenance analyzer that tries to delete an implementation.
242
+ const analyzer = createStandinAnalyzer({
243
+ eventsFile,
244
+ extraOperations: [
245
+ { operation: 'delete', path: 'implementation/core-engine.md', reason: '尝试删除实现文件' },
246
+ { operation: 'delete', path: '../knowledge-eng012b/implementation/core-engine.md', reason: '尝试越界删除' },
247
+ ],
248
+ });
249
+
250
+ try {
251
+ const bridgeUrl = await bridge.listen();
252
+ vector = await startVector(vectorRoot);
253
+ const registered = await bridge.projectRegistry.addProject({ home, path: fixture.repoPath, store: storePath });
254
+ const { repoIdentity } = await bridge.resolveRepoContext(fixture.repoPath);
255
+ engine = await startEngine({ dataDir, bridgeUrl, vectorUrl: vector.url, analyzer });
256
+ const engineUrl = await engine.listen();
257
+ engine.runtime.store.addProject({
258
+ projectId: PROJECT_ID,
259
+ repoPath: fixture.repoPath,
260
+ knowledgePath,
261
+ trackingStartCommit: fixture.baseline,
262
+ repoIdentity,
263
+ journalId: registered.id,
264
+ conversationBaselineCursor: 0,
265
+ });
266
+
267
+ installPostCommitHook(fixture.repoPath, { home, mode: 'ok' });
268
+ fs.writeFileSync(path.join(fixture.repoPath, 'feature.txt'), `feature eng012b\n${'y'.repeat(64)}\n`);
269
+ git(fixture.repoPath, ['add', '.']);
270
+ git(fixture.repoPath, ['commit', '-qm', 'feature eng012b']);
271
+ const sha = git(fixture.repoPath, ['rev-parse', 'HEAD']);
272
+ await callJson(engineUrl, '/api/bridge/notify', {});
273
+
274
+ const run = await waitUntil(async () => {
275
+ const found = engine.runtime.store.listRuns(PROJECT_ID).find(r => r.commitSha === sha);
276
+ return found && ['failed', 'succeeded'].includes(found.state) ? found : null;
277
+ }, 60000, 'the run with the deletion attempt settles');
278
+
279
+ assert.equal(run.state, 'failed', `the deletion attempt must not succeed (state ${run.state})`);
280
+ assert.equal(run.error?.code, 'PATH_OUTSIDE_ROOT', `unexpected rejection code ${run.error?.code}`);
281
+ assert.ok(fs.existsSync(repoImplementation), 'the repository implementation file still exists');
282
+ assert.ok(fs.existsSync(knowledgeImplementation), 'the implementation file inside the knowledge root still exists');
283
+ assert.equal(sha256File(repoImplementation), before.repoImplementation, 'the repository implementation is byte-identical');
284
+ assert.equal(sha256File(knowledgeImplementation), before.knowledgeImplementation, 'the knowledge-root implementation is byte-identical');
285
+ const changesDir = path.join(knowledgePath, 'changes');
286
+ const promoted = fs.existsSync(changesDir) ? fs.readdirSync(changesDir) : [];
287
+ assert.equal(promoted.length, 0, `no knowledge operation may be applied when one is illegal (promoted: ${promoted.join(',')})`);
288
+ const memories = (await callJson(engineUrl, '/api/memories')).body.memories;
289
+ assert.equal(memories.length, 0, 'a refused maintenance run creates no memory');
290
+ commands.push(`deletion attempt refused (${run.error?.code}); implementation files byte-identical; nothing promoted`);
291
+
292
+ evidence.phases.noImplementationDeletion = {
293
+ commitSha: sha,
294
+ run: { runId: run.runId, trigger: run.trigger, state: run.state, phase: run.phase, error: run.error },
295
+ attemptedDeleteOperations: [
296
+ { path: 'implementation/core-engine.md', kind: 'outside the owned knowledge structure' },
297
+ { path: '../knowledge-eng012b/implementation/core-engine.md', kind: 'escape attempt' },
298
+ ],
299
+ implementationFiles: {
300
+ repository: { path: path.relative(fixture.repoPath, repoImplementation).replace(/\\/g, '/'), sha256Before: before.repoImplementation, sha256After: sha256File(repoImplementation), exists: fs.existsSync(repoImplementation) },
301
+ knowledgeRoot: { path: path.relative(knowledgePath, knowledgeImplementation).replace(/\\/g, '/'), sha256Before: before.knowledgeImplementation, sha256After: sha256File(knowledgeImplementation), exists: fs.existsSync(knowledgeImplementation) },
302
+ },
303
+ promotedKnowledgeFiles: promoted,
304
+ memoriesCreated: memories.length,
305
+ };
306
+ return { engine, vector, bridge };
307
+ } catch (error) {
308
+ try { await engine?.close(); } catch {}
309
+ try { await vector?.close(); } catch {}
310
+ try { await bridge.close(); } catch {}
311
+ throw error;
312
+ }
313
+ }
314
+
315
+ async function main() {
316
+ const evidence = { caseId: 'ENG-012', phases: {}, commands: [] };
317
+ const commands = evidence.commands;
318
+ try {
319
+ const laneA = makeLaneDir('eng012a');
320
+ evidence.laneA = laneA;
321
+ const a = await scenarioOriginExclusion(laneA, evidence, commands);
322
+ await a.engine.close();
323
+ await a.vector.close();
324
+ await a.bridge.close();
325
+
326
+ const laneB = makeLaneDir('eng012b');
327
+ evidence.laneB = laneB;
328
+ const b = await scenarioNoImplementationDeletion(laneB, evidence, commands);
329
+ await b.engine.close();
330
+ await b.vector.close();
331
+ await b.bridge.close();
332
+
333
+ evidence.verdict = {
334
+ 'expected1 维护/委派不能自动成为人类长期偏好': 'PASS',
335
+ 'expected2 C01未定项不得自动删除实现': 'PASS',
336
+ originExclusion: 'the frozen commit conversation snapshot carries both origins; the engine rejected the delegated candidate with SOURCE_NOT_HUMAN and kept the human one as a plain candidate - nothing was confirmed automatically',
337
+ c01Block: 'POST /api/memories with an injected source-evidence field is refused with INVALID_ARGUMENT ("不能指定来源证据"); a manual memory is stored with evidence null and sourceType manual, so the MEM-008 implementation was not deleted',
338
+ noImplementationDeletion: 'a manifest that tries to delete an implementation file is refused by the promotion path (PATH_OUTSIDE_ROOT); the run fails, no knowledge operation is applied and the implementation files stay byte-identical',
339
+ analyzerStandin: 'deterministic stand-in that deliberately emits both the human and the delegated candidate - NO real model output covered',
340
+ vectorService: 'real vector-hub server, deterministic test embeddings - paid embedding API NOT covered',
341
+ boundary: 'PARTIAL on the product side: the product memory panel UI (addMemory/memoryContent/memoryTabs/memoryScopeFilter/candidateCount/memoryFeedback) and the shared memory ledger are owned by other lanes and were not exercised; specs-coverage.json MEM-008 records that those UI paths have zero assertions in the 156 product tests. Everything asserted here is engine-level behaviour.',
342
+ };
343
+ saveEvidence(ARTIFACTS, 'eng012-evidence.json', evidence);
344
+ console.log('ENG-012 PASS');
345
+ process.exit(0);
346
+ } catch (error) {
347
+ evidence.verdict = { failed: String((error && error.stack) || error) };
348
+ saveEvidence(ARTIFACTS, 'eng012-evidence.json', evidence);
349
+ console.error(`ENG-012 FAIL: ${error.message}`);
350
+ process.exit(1);
351
+ }
352
+ }
353
+
354
+ main();