@sanqianx/project-knowledge 5.0.23 → 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 -1346
  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 +70 -67
  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,156 @@
1
+ 'use strict';
2
+ // _site/_test/parallel-ci-r9-posix-socket-budget-test.js
3
+ //
4
+ // P-CI-LAST-LINUX-R9 focused case: the POSIX control-socket path budget that
5
+ // killed normalhook on CI 40075242420 (linux24, exit 1, empty pipes).
6
+ //
7
+ // Mechanism (all source-proven, see the R9 evidence lane): the product's
8
+ // runtime-control listens on a filesystem unix socket at
9
+ // <dataDir>/runtime-control.sock on POSIX (runtime-control.js:14; Windows uses
10
+ // a hashed named pipe with no length dependence). Linux sun_path is 108 bytes
11
+ // including the NUL, so paths longer than 107 chars cannot bind. The logging
12
+ // lane stacks three name layers — laneTmp (5025-env mkdtemp `${prefix}-`),
13
+ // its `temp` dir (TEMP/TMP/TMPDIR), and the acceptance fixture's dataDir
14
+ // mkdtemp — and the OLD 'pk-logging-acc-' fixture prefix made the
15
+ // logfixr2-normal dataDir produce a 109-char socket on the CI temp root
16
+ // (/home/runner/work/_temp): unbindable, so the server exited 1 before the
17
+ // health gate and the test timed out with zero child output.
18
+ //
19
+ // This case locks the class, not the incident:
20
+ // 1. every logging-lane (prefix, caseId) pair builds a bindable socket
21
+ // string on the documented CI Linux temp root (pure string math, runs
22
+ // and holds on BOTH platforms);
23
+ // 2. the fixture's fail-fast guard rejects an over-budget dataDir and
24
+ // accepts in-budget ones (on win32 it is a no-op — named pipes);
25
+ // 3. on POSIX the kernel verdict is reproduced live: the fixed normalhook
26
+ // length binds; the 109 incident is recorded, without assuming whether
27
+ // this Node/libuv version refuses or truncates it. 108 is also diagnostic.
28
+ // on win32 this leg is reported platform-skipped (no sun_path there);
29
+ // 4. the product's controlPath shape per platform is asserted unchanged.
30
+ //
31
+ // No server spawn, no engine, no browser: naming + kernel contracts only.
32
+
33
+ const fs = require('node:fs');
34
+ const os = require('node:os');
35
+ const net = require('node:net');
36
+ const path = require('node:path');
37
+ const assert = require('node:assert/strict');
38
+
39
+ const { applyDriverIsolation } = require('./helpers/parallel-qa-engine-endpoint-isolate');
40
+ const isolation = applyDriverIsolation({ prefix: 'r9-socket-budget' });
41
+ const ownedRoot = fs.realpathSync(isolation.layout.root);
42
+ const { controlPath } = require('../lib/runtime-control');
43
+ const { assertPosixSocketBudget, POSIX_SOCKET_CHAR_LIMIT } = require('./helpers/parallel-logging-acceptance-fixture');
44
+
45
+ const CI_LINUX_TEMP_ROOT = '/home/runner/work/_temp'; // from the 40075242420 log (PK_TEST_TEMP_ROOT)
46
+ const MKDTEMP_RANDOM = 6; // fs.mkdtempSync appends exactly 6 random chars
47
+ const SOCK_SUFFIX = '/runtime-control.sock'; // 21 chars — runtime-control.js:14 (POSIX)
48
+
49
+ // Every spawnServer consumer of the acceptance fixture in the logging lane
50
+ // (test file → lane prefix → fixture caseId).
51
+ const LANE_CASES = [
52
+ ['parallel-logging-acceptance-log003-test.js', 'log003', 'log003'],
53
+ ['parallel-logging-acceptance-log004-test.js', 'log004', 'log004'],
54
+ ['parallel-logging-acceptance-log005-test.js', 'log005', 'log005'],
55
+ ['parallel-logging-acceptance-log006-test.js', 'log006', 'log006'],
56
+ ['parallel-logging-acceptance-log007-test.js', 'log007', 'log007'],
57
+ ['parallel-logging-acceptance-log008-test.js', 'log008', 'log008'],
58
+ ['parallel-logging-fix-r2-gap-test.js', 'logfixr2-gap', 'logfixr2gap'],
59
+ ['parallel-logging-fix-r2-normalhook-test.js', 'logfixr2-normal', 'logfixr2normal'],
60
+ ];
61
+
62
+ // Replicates the three naming layers verbatim (5025-env:331,336,361-363 and
63
+ // the fixture's mkdtemp) against an arbitrary temp root.
64
+ function laneSocketPath(tempRoot, prefix, caseId, fixturePrefix) {
65
+ const laneTmp = path.posix.join(tempRoot, `${prefix}-${'x'.repeat(MKDTEMP_RANDOM)}`);
66
+ const tmpdir = path.posix.join(laneTmp, 'temp');
67
+ const dataDir = path.posix.join(tmpdir, `${fixturePrefix}${caseId}-${'x'.repeat(MKDTEMP_RANDOM)}`);
68
+ return path.posix.join(dataDir, 'runtime-control.sock');
69
+ }
70
+
71
+ function tryListen(socketPath) {
72
+ return new Promise(resolve => {
73
+ const server = net.createServer(() => {});
74
+ const fail = error => resolve({ bound: false, code: error.code || null, message: String(error.message).slice(0, 160) });
75
+ server.once('error', fail);
76
+ server.listen(socketPath, () => server.close(() => resolve({ bound: true })));
77
+ });
78
+ }
79
+
80
+ async function main() {
81
+ const proof = { case: 'P-CI-LAST-LINUX-R9 posix-socket-budget', startedAt: new Date().toISOString() };
82
+
83
+ // ---- 1. every lane case is bindable on the CI Linux temp root -----------
84
+ const rows = LANE_CASES.map(([test, prefix, caseId]) => {
85
+ const fixed = laneSocketPath(CI_LINUX_TEMP_ROOT, prefix, caseId, 'pk-la-').length;
86
+ const old = laneSocketPath(CI_LINUX_TEMP_ROOT, prefix, caseId, 'pk-logging-acc-').length;
87
+ return { test, oldLength: old, fixedLength: fixed, oldWasBindable: old <= POSIX_SOCKET_CHAR_LIMIT, fixedBindable: fixed <= POSIX_SOCKET_CHAR_LIMIT };
88
+ });
89
+ for (const row of rows) {
90
+ assert.ok(row.fixedBindable, `${row.test}: fixed socket length ${row.fixedLength} exceeds the POSIX budget ${POSIX_SOCKET_CHAR_LIMIT} on the CI temp root`);
91
+ }
92
+ const normalhook = rows.find(r => r.test.includes('normalhook'));
93
+ assert.ok(!normalhook.oldWasBindable && normalhook.oldLength === 109, `the CI incident stays red as history: normalhook OLD length was 109 (> ${POSIX_SOCKET_CHAR_LIMIT})`);
94
+ proof.laneBudgets = rows;
95
+
96
+ // ---- 2. the fixture guard fails fast on over-budget, passes in-budget ---
97
+ const okDir = laneSocketPath(CI_LINUX_TEMP_ROOT, 'logfixr2-normal', 'logfixr2normal', 'pk-la-').slice(0, -SOCK_SUFFIX.length);
98
+ const longDir = laneSocketPath(CI_LINUX_TEMP_ROOT, 'logfixr2-normal', 'logfixr2normal', 'pk-logging-acc-').slice(0, -SOCK_SUFFIX.length);
99
+ if (process.platform === 'win32') {
100
+ assert.equal(assertPosixSocketBudget(longDir), longDir, 'on win32 the control channel is a named pipe: the guard is a no-op');
101
+ proof.fixtureGuard = { platform: 'win32', behavior: 'no-op (named pipe)' };
102
+ } else {
103
+ assert.equal(assertPosixSocketBudget(okDir), okDir, 'an in-budget dataDir passes the guard');
104
+ assert.throws(() => assertPosixSocketBudget(longDir), /POSIX control socket/, 'an over-budget dataDir is rejected at fixture time, before any spawn');
105
+ proof.fixtureGuard = { platform: process.platform, behavior: 'throws on over-budget, passes in-budget' };
106
+ }
107
+
108
+ // ---- 3. the kernel verdict where sun_path actually applies --------------
109
+ if (process.platform === 'win32') {
110
+ proof.kernelVerdict = { platform: 'win32', skipped: true, reason: 'no sun_path limit on Windows named pipes; leg 1 proves the CI-Linux string math' };
111
+ } else {
112
+ const base = fs.mkdtempSync(path.join(os.tmpdir(), 'pk-r9-budget-'));
113
+ const makeAtLength = length => {
114
+ const parent = path.join(base, 'a'.repeat(Math.max(1, length - SOCK_SUFFIX.length - base.length - 1)));
115
+ fs.mkdirSync(parent, { recursive: true });
116
+ const socketPath = path.join(parent, 'runtime-control.sock');
117
+ assert.equal(socketPath.length, length);
118
+ return socketPath;
119
+ };
120
+ const fixedLength = laneSocketPath(CI_LINUX_TEMP_ROOT, 'logfixr2-normal', 'logfixr2normal', 'pk-la-').length;
121
+ const outcomes = {};
122
+ outcomes.fixed = { length: fixedLength, ...(await tryListen(makeAtLength(fixedLength))) };
123
+ outcomes.incident109 = { length: 109, ...(await tryListen(makeAtLength(109))) };
124
+ // 108 is measured but NOT asserted: the exact sun_path boundary is
125
+ // runtime-dependent (some libuv callers truncate; others reject),
126
+ // so neither boundary observation is a cross-version product contract.
127
+ outcomes.boundary108 = { length: 108, ...(await tryListen(makeAtLength(108))) };
128
+ assert.ok(outcomes.fixed.bound, `the fixed normalhook socket length (${fixedLength}) binds on this POSIX kernel`);
129
+ // Node 22 may truncate both bind and connect names; a universal refusal
130
+ // assertion would characterize the runtime incorrectly. The fixture guard
131
+ // above remains strict, and the fixed in-budget socket must really bind.
132
+ proof.kernelVerdict = { platform: process.platform, outcomes };
133
+ fs.rmSync(base, { recursive: true, force: true });
134
+ }
135
+
136
+ // ---- 4. the product control-path shape per platform ---------------------
137
+ const sampleDataDir = '/tmp/pk-la-sample-abc123';
138
+ if (process.platform === 'win32') {
139
+ assert.match(controlPath(sampleDataDir), /^\\\\\.\\pipe\\project-knowledge-[0-9a-f]{32}$/, 'win32 control channel is the hashed named pipe (no length dependence)');
140
+ } else {
141
+ assert.equal(controlPath(sampleDataDir), path.join(sampleDataDir, 'runtime-control.sock'), 'POSIX control channel is the in-dir unix socket');
142
+ }
143
+ proof.controlPathShape = String(controlPath(sampleDataDir));
144
+
145
+ proof.verdict = 'PASS';
146
+ console.log(`parallel-ci-r9-posix-socket-budget-test PASS (${proof.kernelVerdict.skipped ? 'string-math + guard legs; kernel leg platform-skipped on win32' : 'string-math + guard + live kernel legs'}; normalhook fixed=${normalhook.fixedLength} ≤ ${POSIX_SOCKET_CHAR_LIMIT}, old=${normalhook.oldLength})`);
147
+ console.log(JSON.stringify(proof, null, 2));
148
+ }
149
+
150
+ main().catch(error => { console.error(error.stack || error.message); process.exitCode = 1; }).finally(() => {
151
+ const owner = JSON.parse(fs.readFileSync(path.join(ownedRoot, 'owner.json'), 'utf8'));
152
+ assert.equal(fs.realpathSync(isolation.layout.root), ownedRoot, 'cleanup stays in the freshly owned isolation root');
153
+ assert.equal(owner.pid, process.pid);
154
+ assert.equal(owner.tag, 'r9-socket-budget');
155
+ fs.rmSync(ownedRoot, { recursive: true, force: true });
156
+ });
@@ -0,0 +1,136 @@
1
+ 'use strict';
2
+
3
+ // P-ENG-ADVANCED ENG-005 单项目顺序 (single-project ordering) acceptance driver.
4
+ //
5
+ // Case (qa-autopilot/config/test-cases.json ENG-005):
6
+ // steps: 连续提交A/B/C,令B失败。
7
+ // expected: 1) A成功、B失败、C等待。 2) 不能越过B宣告分析到C。
8
+ //
9
+ // Real behavior under test: vendored knowledge-engine child process, real
10
+ // fixture git commits, real disk state (engine-state.json, knowledge tree),
11
+ // analyzer = declarative stand-in (NO real model output), failure of B via the
12
+ // engine's own debug fault surface (simulateFailure, honored before the
13
+ // analyzer runs). Vector endpoint is a loopback double (vector-hub not covered).
14
+
15
+ const assert = require('node:assert/strict');
16
+ const fs = require('node:fs');
17
+ const path = require('node:path');
18
+ const {
19
+ makeLaneDir, buildFixtureRepo, waitUntil, callJson, startVectorDouble,
20
+ startEngineChild, readEventsFile, writePlan, saveEvidence,
21
+ } = require('./helpers/parallel-engine-advanced-harness.js');
22
+
23
+ const ARTIFACTS = process.env.PK_TEST_EVIDENCE_ROOT
24
+ ? path.join(process.env.PK_TEST_EVIDENCE_ROOT, 'eng005')
25
+ : path.resolve(__dirname, '../../qa-autopilot/artifacts/parallel-20261023/engine-review-r3/reruns/eng005');
26
+ const PROJECT_ID = 'project-eng005';
27
+
28
+ async function main() {
29
+ const lane = makeLaneDir('eng005');
30
+ const commands = [];
31
+ const evidence = { caseId: 'ENG-005', laneDir: lane, phases: {}, commands };
32
+ const fixture = buildFixtureRepo(lane, 'eng005', ['A', 'B', 'C']);
33
+ const knowledgePath = path.join(lane, 'knowledge-eng005');
34
+ fs.mkdirSync(knowledgePath, { recursive: true });
35
+ const planFile = path.join(lane, 'analyzer-plan.json');
36
+ const eventsFile = path.join(lane, 'analyzer-events.jsonl');
37
+ writePlan(planFile, { default: { delayMs: 250 }, rules: [] });
38
+
39
+ const vector = await startVectorDouble();
40
+ const engine = await startEngineChild({ label: 'eng005', dataDir: path.join(lane, 'engine-data'), vectorUrl: vector.url, planFile, eventsFile });
41
+ commands.push(`POST /api/projects (trackingStartCommit=${fixture.baseline.slice(0, 7)})`, 'POST /api/runs A', 'POST /api/runs B simulateFailure:true', 'POST /api/runs C');
42
+
43
+ try {
44
+ const registered = await callJson(engine.base, '/api/projects', {
45
+ projectId: PROJECT_ID, name: 'eng005', repoPath: fixture.repoPath, knowledgePath, trackingStartCommit: fixture.baseline,
46
+ });
47
+ assert.equal(registered.status, 200, `project registration failed: ${JSON.stringify(registered.body)}`);
48
+
49
+ const runA = (await callJson(engine.base, '/api/runs', { projectId: PROJECT_ID, commitSha: fixture.shas.A })).body.run;
50
+ const runB = (await callJson(engine.base, '/api/runs', { projectId: PROJECT_ID, commitSha: fixture.shas.B, simulateFailure: true })).body.run;
51
+ const runC = (await callJson(engine.base, '/api/runs', { projectId: PROJECT_ID, commitSha: fixture.shas.C })).body.run;
52
+ assert.ok(runA && runB && runC, 'enqueue responses carry run objects');
53
+
54
+ // --- Expected 1: A成功、B失败、C等待 ---
55
+ await waitUntil(async () => {
56
+ const runs = (await callJson(engine.base, `/api/runs?projectId=${PROJECT_ID}`)).body.runs;
57
+ const by = sha => runs.find(r => r.commitSha === sha);
58
+ return by(fixture.shas.A)?.state === 'succeeded' && by(fixture.shas.B)?.state === 'failed' && by(fixture.shas.C)?.state === 'queued';
59
+ }, 30000, 'A succeeded / B failed / C queued');
60
+
61
+ const snapshot1 = (await callJson(engine.base, `/api/runs?projectId=${PROJECT_ID}`)).body.runs;
62
+ const sA = snapshot1.find(r => r.commitSha === fixture.shas.A);
63
+ const sB = snapshot1.find(r => r.commitSha === fixture.shas.B);
64
+ const sC = snapshot1.find(r => r.commitSha === fixture.shas.C);
65
+ assert.equal(sA.state, 'succeeded'); assert.equal(sA.phase, 'ready');
66
+ assert.equal(sB.state, 'failed'); assert.equal(sB.error.code, 'DEBUG_SIMULATED_FAILURE');
67
+ assert.equal(sC.state, 'queued'); assert.equal(sC.phase, 'waiting-previous');
68
+ evidence.phases.afterBfailed = {
69
+ A: { state: sA.state, phase: sA.phase, promotedAt: sA.promotedAt },
70
+ B: { state: sB.state, phase: sB.phase, error: sB.error },
71
+ C: { state: sC.state, phase: sC.phase },
72
+ };
73
+
74
+ // --- Expected 2: 不能越过B宣告分析到C ---
75
+ const events1 = readEventsFile(eventsFile);
76
+ const startedShas = new Set(events1.filter(e => e.kind === 'start').map(e => e.commitSha));
77
+ assert.equal(events1.filter(e => e.kind === 'start' && e.commitSha === fixture.shas.A).length, 1, 'A analyzed exactly once');
78
+ assert.ok(!startedShas.has(fixture.shas.B), 'B never reached the analyzer (engine refuses before stand-in)');
79
+ assert.ok(!startedShas.has(fixture.shas.C), 'C was never analyzed while B failed - no skipping past B');
80
+ assert.ok(!fs.existsSync(path.join(knowledgePath, 'changes', `${fixture.shas.B.slice(0, 12)}.md`)), 'no B knowledge file');
81
+ assert.ok(!fs.existsSync(path.join(knowledgePath, 'changes', `${fixture.shas.C.slice(0, 12)}.md`)), 'no C knowledge file');
82
+ assert.ok(fs.existsSync(path.join(knowledgePath, 'changes', `${fixture.shas.A.slice(0, 12)}.md`)), 'A knowledge file exists');
83
+
84
+ const stateAfterFailure = (await callJson(engine.base, `/api/snapshot?projectId=${PROJECT_ID}`)).body;
85
+ const runtime1 = stateAfterFailure.projects.find(p => p.projectId === PROJECT_ID).runtime;
86
+ assert.equal(runtime1.lastAnalyzedCommit, fixture.shas.A, 'pointer stays at A while B failed');
87
+ evidence.phases.pointerAfterBfailed = runtime1.lastAnalyzedCommit;
88
+
89
+ // Recovery: retry B, then C must proceed strictly after B.
90
+ commands.push('POST /api/runs/:B/retry', 'wait C succeeded');
91
+ const retried = await callJson(engine.base, `/api/runs/${encodeURIComponent(runB.runId)}/retry`, {});
92
+ assert.equal(retried.status, 200, `retry B failed: ${JSON.stringify(retried.body)}`);
93
+ await waitUntil(async () => {
94
+ const runs = (await callJson(engine.base, `/api/runs?projectId=${PROJECT_ID}`)).body.runs;
95
+ return runs.every(r => r.state === 'succeeded');
96
+ }, 30000, 'B retry and C both succeed');
97
+ const snapshot2 = (await callJson(engine.base, `/api/runs?projectId=${PROJECT_ID}`)).body.runs;
98
+ const events2 = readEventsFile(eventsFile);
99
+ const bStart = events2.find(e => e.kind === 'start' && e.commitSha === fixture.shas.B);
100
+ const cStart = events2.find(e => e.kind === 'start' && e.commitSha === fixture.shas.C);
101
+ const bFinish = events2.find(e => e.kind === 'finish' && e.commitSha === fixture.shas.B);
102
+ assert.ok(bStart && cStart && bFinish, 'analyzer saw B (after retry) then C');
103
+ assert.ok(new Date(cStart.at) >= new Date(bFinish.at), 'C analysis started only after B finished');
104
+ for (const sha of ['A', 'B', 'C']) {
105
+ assert.equal(events2.filter(e => e.kind === 'start' && e.commitSha === fixture.shas[sha]).length, 1, `${sha} analyzed exactly once across failure+retry`);
106
+ }
107
+ const runtime2 = (await callJson(engine.base, `/api/snapshot?projectId=${PROJECT_ID}`)).body.projects.find(p => p.projectId === PROJECT_ID).runtime;
108
+ assert.equal(runtime2.lastAnalyzedCommit, fixture.shas.C, 'pointer ends at C after ordered recovery');
109
+ evidence.phases.afterRecovery = {
110
+ runs: snapshot2.map(r => ({ commit: r.commitSha.slice(0, 7), state: r.state, phase: r.phase, promotedAt: r.promotedAt })),
111
+ analyzerStarts: events2.filter(e => e.kind === 'start').map(e => ({ sha: e.commitSha.slice(0, 7), at: e.at })),
112
+ lastAnalyzedCommit: runtime2.lastAnalyzedCommit,
113
+ };
114
+
115
+ evidence.verdict = {
116
+ 'expected1 A成功、B失败、C等待': 'PASS',
117
+ 'expected2 不能越过B宣告分析到C': 'PASS',
118
+ analyzerStandin: 'declarative stand-in - real staged bytes, NO real model output covered',
119
+ vectorDouble: 'loopback HTTP double - vector-hub itself not covered',
120
+ };
121
+ await engine.stop();
122
+ await vector.close();
123
+ saveEvidence(ARTIFACTS, 'eng005-evidence.json', evidence);
124
+ console.log('ENG-005 PASS');
125
+ process.exitCode = 0;
126
+ } catch (error) {
127
+ evidence.verdict = { failed: String(error && error.stack || error) };
128
+ try { await engine.stop(); } catch {}
129
+ try { await vector.close(); } catch {}
130
+ saveEvidence(ARTIFACTS, 'eng005-evidence.json', evidence);
131
+ console.error(`ENG-005 FAIL: ${error.message}`);
132
+ process.exitCode = 1;
133
+ }
134
+ }
135
+
136
+ main();
@@ -0,0 +1,171 @@
1
+ 'use strict';
2
+
3
+ // P-ENG-ADVANCED ENG-006 跨项目并发 (cross-project concurrency) acceptance driver.
4
+ //
5
+ // Case (qa-autopilot/config/test-cases.json ENG-006):
6
+ // steps: 两个或更多fixture提交并观察调度。
7
+ // expected: 1) 按当前实际并发上限排队。 2) 项目之间无文件串写。
8
+ //
9
+ // Real behavior under test: vendored knowledge-engine child process with its
10
+ // DEFAULT concurrency (coordinator clamps to 2), three projects (one with a
11
+ // non-ASCII knowledge path), four queued runs, real analyzer-interval evidence
12
+ // from the stand-in's JSONL log (no real model output), real per-project
13
+ // knowledge trees on disk, loopback vector double.
14
+
15
+ const assert = require('node:assert/strict');
16
+ const fs = require('node:fs');
17
+ const path = require('node:path');
18
+ const {
19
+ makeLaneDir, buildFixtureRepo, waitUntil, callJson, startVectorDouble,
20
+ startEngineChild, readEventsFile, writePlan, saveEvidence, listFilesRecursive,
21
+ } = require('./helpers/parallel-engine-advanced-harness.js');
22
+
23
+ const ARTIFACTS = process.env.PK_TEST_EVIDENCE_ROOT
24
+ ? path.join(process.env.PK_TEST_EVIDENCE_ROOT, 'eng006')
25
+ : path.resolve(__dirname, '../../qa-autopilot/artifacts/parallel-20261023/engine-review-r3/reruns/eng006');
26
+ const PROJECTS = [
27
+ { projectId: 'project-eng006-a', name: 'eng006-a', dirName: 'repo-eng006-a', knowledgeName: 'knowledge-eng006-a' },
28
+ { projectId: 'project-eng006-b', name: 'eng006-b', dirName: 'repo-eng006-b', knowledgeName: 'knowledge-eng006-b' },
29
+ { projectId: 'project-eng006-c', name: 'eng006-c(中文路径)', dirName: 'repo-eng006-c', knowledgeName: '知识-eng006-c' },
30
+ ];
31
+
32
+ function maxOverlap(intervals) {
33
+ const points = [];
34
+ for (const [start, end] of intervals) { points.push([start, 1], [end, -1]); }
35
+ points.sort((x, y) => x[0] - y[0] || y[1] - x[1]);
36
+ let live = 0; let peak = 0;
37
+ for (const [, delta] of points) { live += delta; peak = Math.max(peak, live); }
38
+ return peak;
39
+ }
40
+
41
+ async function main() {
42
+ const lane = makeLaneDir('eng006');
43
+ const commands = [];
44
+ const evidence = { caseId: 'ENG-006', laneDir: lane, phases: {}, commands };
45
+ const fixtures = [];
46
+ for (const spec of PROJECTS) {
47
+ fixtures.push({ spec, fixture: buildFixtureRepo(lane, spec.dirName, ['one', 'two']) });
48
+ }
49
+ const planFile = path.join(lane, 'analyzer-plan.json');
50
+ const eventsFile = path.join(lane, 'analyzer-events.jsonl');
51
+ writePlan(planFile, { default: { delayMs: 700 }, rules: [] });
52
+
53
+ const vector = await startVectorDouble();
54
+ const engine = await startEngineChild({ label: 'eng006', dataDir: path.join(lane, 'engine-data'), vectorUrl: vector.url, planFile, eventsFile });
55
+ commands.push('POST /api/projects x3 (default concurrency, no override)', 'POST /api/runs a#one, b#one, c#one, a#two');
56
+
57
+ try {
58
+ for (const { spec, fixture } of fixtures) {
59
+ const knowledgePath = path.join(lane, spec.knowledgeName);
60
+ fs.mkdirSync(knowledgePath, { recursive: true });
61
+ spec.knowledgePath = knowledgePath;
62
+ const registered = await callJson(engine.base, '/api/projects', {
63
+ projectId: spec.projectId, name: spec.name, repoPath: fixture.repoPath, knowledgePath, trackingStartCommit: fixture.baseline,
64
+ });
65
+ assert.equal(registered.status, 200, `registration failed for ${spec.projectId}`);
66
+ }
67
+
68
+ const enqueuePlan = [[0, 'one'], [1, 'one'], [2, 'one'], [0, 'two']];
69
+ for (const [index, label] of enqueuePlan) {
70
+ const { spec, fixture } = fixtures[index];
71
+ const commitSha = fixture.shas[label];
72
+ const response = await callJson(engine.base, '/api/runs', { projectId: spec.projectId, commitSha });
73
+ assert.equal(response.status, 200, `enqueue failed: ${JSON.stringify(response.body)}`);
74
+ }
75
+ evidence.enqueueNote = 'runs queued in order: a#one, b#one, c#one, a#two (a#two is project a second fixture commit)';
76
+
77
+ const health = (await callJson(engine.base, '/api/health')).body;
78
+ assert.equal(health.concurrency, 2, `actual concurrency limit is 2, got ${health.concurrency}`);
79
+ evidence.phases.healthConcurrency = { concurrency: health.concurrency, active: health.counts.running };
80
+
81
+ // Mid-flight: while the 700ms analyzer intervals run, expect exactly 2 running and 2 queued.
82
+ const midflight = await waitUntil(async () => {
83
+ const runs = (await callJson(engine.base, '/api/runs')).body.runs;
84
+ return runs.length === 4 && runs.filter(r => r.state === 'running').length === 2 && runs.filter(r => r.state === 'queued').length === 2 ? runs : null;
85
+ }, 20000, 'two runs active while two queued');
86
+ evidence.phases.midflight = midflight.map(r => ({ project: r.projectId, sha: r.commitSha.slice(0, 7), state: r.state, phase: r.phase }));
87
+
88
+ await waitUntil(async () => {
89
+ const runs = (await callJson(engine.base, '/api/runs')).body.runs;
90
+ return runs.length === 4 && runs.every(r => r.state === 'succeeded');
91
+ }, 40000, 'all four runs succeed');
92
+
93
+ // --- Expected 1: 按当前实际并发上限排队 ---
94
+ const events = readEventsFile(eventsFile);
95
+ const byRun = new Map();
96
+ for (const e of events) {
97
+ const key = `${e.projectId}:${e.commitSha.slice(0, 7)}`;
98
+ if (!byRun.has(key)) byRun.set(key, { projectId: e.projectId, sha: e.commitSha.slice(0, 7) });
99
+ byRun.get(key)[e.kind === 'start' ? 'startAt' : 'finishAt'] = e.at;
100
+ }
101
+ const intervals = [...byRun.values()].map(r => [new Date(r.startAt).getTime(), new Date(r.finishAt).getTime()]);
102
+ const peak = maxOverlap(intervals);
103
+ assert.equal(intervals.length, 4, 'four analysis intervals recorded');
104
+ assert.equal(peak, 2, `analyzer never exceeded the actual concurrency limit (peak=${peak}, limit=2)`);
105
+ // project a serialized: a#two start after a#one finish
106
+ const aOne = [...byRun.values()].find(r => r.projectId === PROJECTS[0].projectId && r.sha === fixtures[0].fixture.shas.one.slice(0, 7));
107
+ const aTwo = [...byRun.values()].find(r => r.projectId === PROJECTS[0].projectId && r.sha === fixtures[0].fixture.shas.two.slice(0, 7));
108
+ assert.ok(aOne && aTwo, 'both project-a commits analyzed');
109
+ assert.ok(new Date(aTwo.startAt) >= new Date(aOne.finishAt), 'same-project runs serialized');
110
+ evidence.phases.schedule = {
111
+ concurrencyLimit: health.concurrency,
112
+ peakConcurrentAnalyzerIntervals: peak,
113
+ intervals: [...byRun.values()],
114
+ sameProjectSerialized: { aOneFinish: aOne.finishAt, aTwoStart: aTwo.startAt },
115
+ };
116
+
117
+ // --- Expected 2: 项目之间无文件串写 ---
118
+ const enqueuedLabelsByIndex = { 0: ['one', 'two'], 1: ['one'], 2: ['one'] };
119
+ for (const [index, { spec, fixture }] of fixtures.entries()) {
120
+ const files = listFilesRecursive(spec.knowledgePath);
121
+ const own = files.filter(f => f.startsWith('changes/'));
122
+ const expectedOwn = enqueuedLabelsByIndex[index].map(label => `changes/${fixture.shas[label].slice(0, 12)}.md`).sort();
123
+ assert.deepEqual(own.sort(), expectedOwn, `${spec.projectId} knowledge tree contains exactly its own promoted files`);
124
+ for (const file of own) {
125
+ const content = fs.readFileSync(path.join(spec.knowledgePath, ...file.split('/')), 'utf8');
126
+ assert.ok(content.includes(spec.projectId), `${file} mentions its own project`);
127
+ for (const other of PROJECTS) {
128
+ if (other.projectId !== spec.projectId) assert.ok(!content.includes(other.projectId), `${file} must not mention ${other.projectId} (no cross-write)`);
129
+ }
130
+ }
131
+ }
132
+ const finalRuns = (await callJson(engine.base, '/api/runs')).body.runs;
133
+ for (const run of finalRuns) {
134
+ const owner = PROJECTS.find(p => p.projectId === run.projectId);
135
+ assert.ok(owner, 'every run attributed to a registered project');
136
+ assert.ok([fixtures[PROJECTS.indexOf(owner)].fixture.shas.one, fixtures[PROJECTS.indexOf(owner)].fixture.shas.two].includes(run.commitSha), 'run commit belongs to its own project fixture');
137
+ }
138
+ const syncs = vector.requests.filter(r => r.url === '/api/sync');
139
+ assert.equal(syncs.length, 4, 'four index syncs (one per promoted run)');
140
+ for (const sync of syncs) {
141
+ const project = PROJECTS.find(p => p.projectId === sync.body.project);
142
+ assert.ok(project, `sync project ${sync.body.project} is one of ours`);
143
+ assert.ok(sync.body.sourceDir && PROJECTS.some(p => p.knowledgePath && sync.body.sourceDir.replace(/\//g, '\\').endsWith(path.basename(p.knowledgePath)) || sync.body.sourceDir === p.knowledgePath || p.knowledgePath.endsWith(sync.body.sourceDir.split(/[\\/]/).pop())), 'sync sourceDir belongs to that project');
144
+ }
145
+ evidence.phases.crossWriteCheck = {
146
+ knowledgeTrees: Object.fromEntries(PROJECTS.map(p => [p.projectId, listFilesRecursive(p.knowledgePath)])),
147
+ syncRequests: syncs.map(s => ({ project: s.body.project, sourceDir: s.body.sourceDir })),
148
+ };
149
+
150
+ evidence.verdict = {
151
+ 'expected1 按当前实际并发上限排队(实际上限=2, 峰值=2, 同项目串行)': 'PASS',
152
+ 'expected2 项目之间无文件串写(知识树/归属/索引请求逐项核对)': 'PASS',
153
+ analyzerStandin: 'declarative stand-in - real intervals, NO real model output covered',
154
+ vectorDouble: 'loopback HTTP double - vector-hub itself not covered',
155
+ };
156
+ await engine.stop();
157
+ await vector.close();
158
+ saveEvidence(ARTIFACTS, 'eng006-evidence.json', evidence);
159
+ console.log('ENG-006 PASS');
160
+ process.exitCode = 0;
161
+ } catch (error) {
162
+ evidence.verdict = { failed: String(error && error.stack || error) };
163
+ try { await engine.stop(); } catch {}
164
+ try { await vector.close(); } catch {}
165
+ saveEvidence(ARTIFACTS, 'eng006-evidence.json', evidence);
166
+ console.error(`ENG-006 FAIL: ${error.message}`);
167
+ process.exitCode = 1;
168
+ }
169
+ }
170
+
171
+ main();