@joekytc/dsh-swarm 0.1.2 → 0.2.0

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 (567) hide show
  1. package/README.md +3 -3
  2. package/README.zh-CN.md +3 -3
  3. package/client/BoardCard.tsx +24 -2
  4. package/client/ConfigSection.tsx +71 -0
  5. package/client/ConfigSelect.tsx +69 -0
  6. package/client/KanbanBoard.tsx +3 -0
  7. package/client/KanbanTab.tsx +4 -3
  8. package/client/TaskDrawer.tsx +2 -26
  9. package/client/WorkflowRail.tsx +3 -1
  10. package/client/config-store.ts +51 -0
  11. package/client/config.css +110 -0
  12. package/client/index.ts +39 -4
  13. package/client/kanban.css +19 -2
  14. package/client/session-bridge.ts +39 -0
  15. package/client/timeline-model.ts +10 -1
  16. package/client/workflow-model.ts +3 -1
  17. package/lib/client.js +358 -53
  18. package/lib/config.d.ts +8 -1
  19. package/lib/config.js +6 -1
  20. package/lib/dispatcher/agent-runner.d.ts +28 -6
  21. package/lib/dispatcher/agent-runner.js +175 -62
  22. package/lib/dispatcher/chain-auditor.js +4 -1
  23. package/lib/dispatcher/dispatcher.d.ts +62 -3
  24. package/lib/dispatcher/dispatcher.js +243 -20
  25. package/lib/dispatcher/session-events.d.ts +11 -15
  26. package/lib/dispatcher/session-events.js +17 -5
  27. package/lib/dispatcher/v-orchestrator.d.ts +42 -9
  28. package/lib/dispatcher/v-orchestrator.js +236 -28
  29. package/lib/domain/config-override.d.ts +38 -0
  30. package/lib/domain/config-override.js +101 -0
  31. package/lib/domain/delivery-contract.d.ts +3 -2
  32. package/lib/domain/delivery-contract.js +28 -16
  33. package/lib/domain/gate-policy.d.ts +26 -0
  34. package/lib/domain/gate-policy.js +44 -0
  35. package/lib/domain/kanban-service.d.ts +16 -3
  36. package/lib/domain/kanban-service.js +41 -6
  37. package/lib/domain/permissions.js +1 -1
  38. package/lib/domain/planning-checklist.d.ts +5 -0
  39. package/lib/domain/planning-checklist.js +80 -6
  40. package/lib/domain/projection.js +2 -1
  41. package/lib/domain/review-evidence.js +1 -1
  42. package/lib/domain/state-machine.js +2 -1
  43. package/lib/domain/types.d.ts +2 -2
  44. package/lib/index.js +19 -21
  45. package/lib/roles/clean-fs-tools.d.ts +22 -0
  46. package/lib/roles/clean-fs-tools.js +118 -0
  47. package/lib/roles/skill-installer.d.ts +6 -0
  48. package/lib/roles/skill-installer.js +32 -0
  49. package/lib/roles/toolsets.d.ts +13 -1
  50. package/lib/roles/toolsets.js +163 -31
  51. package/lib/roles/wiki-worker.d.ts +1 -0
  52. package/lib/roles/wiki-worker.js +10 -2
  53. package/lib/routes/kanban-http.d.ts +5 -2
  54. package/lib/routes/kanban-http.js +36 -3
  55. package/lib/routes/planning-driver.d.ts +3 -1
  56. package/lib/routes/planning-driver.js +10 -6
  57. package/lib/routes/prefix-router.d.ts +16 -0
  58. package/lib/routes/prefix-router.js +37 -2
  59. package/lib/services/config-provider.d.ts +42 -0
  60. package/lib/services/config-provider.js +94 -0
  61. package/lib/services/gate-runner.d.ts +24 -0
  62. package/lib/services/gate-runner.js +87 -0
  63. package/lib/services/kanban-provider.d.ts +5 -1
  64. package/lib/services/kanban-provider.js +40 -2
  65. package/lib/services/llm-catalog.d.ts +35 -0
  66. package/lib/services/llm-catalog.js +19 -0
  67. package/lib/tools/kanban-tools.js +1 -0
  68. package/lib/tools/main-session-tools.d.ts +17 -2
  69. package/lib/tools/main-session-tools.js +88 -21
  70. package/lib/tools/planning-tools.d.ts +4 -0
  71. package/lib/tools/planning-tools.js +39 -12
  72. package/lib/tools/prefetch-tools.js +1 -0
  73. package/lib/tools/spec-card-tools.js +1 -0
  74. package/lib/tools/wiki-tools.js +5 -4
  75. package/lib/wiki/kb-linkage.d.ts +9 -2
  76. package/lib/wiki/kb-linkage.js +3 -3
  77. package/lib/wiki/local-kb-client.d.ts +14 -0
  78. package/lib/wiki/local-kb-client.js +101 -0
  79. package/lib/wiki/local-kb.d.ts +6 -0
  80. package/lib/wiki/local-kb.js +25 -0
  81. package/lib/wiki/memory-recall.d.ts +14 -6
  82. package/lib/wiki/memory-recall.js +17 -13
  83. package/lib/wiki/page-path.d.ts +9 -3
  84. package/lib/wiki/page-path.js +29 -11
  85. package/lib/wiki/wiki-vault-client.d.ts +3 -3
  86. package/lib/wiki/wiki-vault-client.js +6 -6
  87. package/package.json +16 -11
  88. package/personas/kanban-d/preset.yml +1 -1
  89. package/personas/kanban-dt/agent.cordis.yml +2 -2
  90. package/personas/kanban-dt/preset.yml +1 -1
  91. package/personas/kanban-p/agent.cordis.yml +16 -0
  92. package/personas/kanban-p/preset.yml +1 -1
  93. package/personas/kanban-pt/agent.cordis.yml +38 -8
  94. package/personas/kanban-pt/preset.yml +1 -1
  95. package/personas/kanban-w/agent.cordis.yml +35 -16
  96. package/personas/kanban-w/preset.yml +1 -1
  97. package/personas/persona-dt.md +1 -1
  98. package/personas/persona-p.md +4 -1
  99. package/personas/persona-pt.md +13 -6
  100. package/personas/persona-w.md +11 -9
  101. package/skills/grill-me/SKILL.md +71 -0
  102. package/skills/llm-wiki-skill/.mise.toml +2 -0
  103. package/skills/llm-wiki-skill/.nvmrc +1 -0
  104. package/skills/llm-wiki-skill/AGENTS.md +173 -0
  105. package/skills/llm-wiki-skill/CHANGELOG.md +548 -0
  106. package/skills/llm-wiki-skill/CLAUDE.md +152 -0
  107. package/skills/llm-wiki-skill/HERMES.md +44 -0
  108. package/skills/llm-wiki-skill/README.en.md +261 -0
  109. package/skills/llm-wiki-skill/README.md +291 -0
  110. package/skills/llm-wiki-skill/SKILL.md +1133 -0
  111. package/skills/llm-wiki-skill/assets/graph-demo.gif +0 -0
  112. package/skills/llm-wiki-skill/assets/graph-preview.png +0 -0
  113. package/skills/llm-wiki-skill/deps/LICENSE-d3.txt +13 -0
  114. package/skills/llm-wiki-skill/deps/LICENSE-marked.txt +44 -0
  115. package/skills/llm-wiki-skill/deps/LICENSE-purify.txt +568 -0
  116. package/skills/llm-wiki-skill/deps/LICENSE-roughjs.txt +21 -0
  117. package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/SKILL.md +261 -0
  118. package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/references/config/first-time-setup.md +106 -0
  119. package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/cdp.ts +179 -0
  120. package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/constants.ts +13 -0
  121. package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/defuddle-converter.ts +58 -0
  122. package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/html-to-markdown.ts +135 -0
  123. package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/legacy-converter.ts +629 -0
  124. package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/main.ts +314 -0
  125. package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/markdown-conversion-shared.ts +305 -0
  126. package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/media-localizer.ts +317 -0
  127. package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/package.json +14 -0
  128. package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/paths.ts +29 -0
  129. package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/vendor/baoyu-chrome-cdp/package.json +9 -0
  130. package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/vendor/baoyu-chrome-cdp/src/index.test.ts +307 -0
  131. package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/vendor/baoyu-chrome-cdp/src/index.ts +523 -0
  132. package/skills/llm-wiki-skill/deps/d3.min.js +2 -0
  133. package/skills/llm-wiki-skill/deps/marked.min.js +6 -0
  134. package/skills/llm-wiki-skill/deps/purify.min.js +3 -0
  135. package/skills/llm-wiki-skill/deps/rough.min.js +7 -0
  136. package/skills/llm-wiki-skill/deps/youtube-transcript/SKILL.md +47 -0
  137. package/skills/llm-wiki-skill/deps/youtube-transcript/scripts/get_transcript.py +72 -0
  138. package/skills/llm-wiki-skill/designs/graph-edge-legibility/graph-edge-treatments.html +480 -0
  139. package/skills/llm-wiki-skill/docs/design/oriental-atlas/DESIGN.md +183 -0
  140. package/skills/llm-wiki-skill/docs/design/oriental-atlas/README.md +10 -0
  141. package/skills/llm-wiki-skill/docs/design/oriental-atlas/design-brief.md +170 -0
  142. package/skills/llm-wiki-skill/docs/design/oriental-atlas/oriental-editorial-atlas.html +1908 -0
  143. package/skills/llm-wiki-skill/docs/design/oriental-atlas/reviews/result-review.md +68 -0
  144. package/skills/llm-wiki-skill/docs/graph/2026-06-16-interaction-risk-audit.md +88 -0
  145. package/skills/llm-wiki-skill/docs/graph/2026-06-16-interaction-test-coverage-map.md +212 -0
  146. package/skills/llm-wiki-skill/docs/graph/performance/2026-06-18-phase-0-2-baseline.md +86 -0
  147. package/skills/llm-wiki-skill/docs/graph/performance/2026-06-18-phase-1-3-dom-svg-large-baseline.md +85 -0
  148. package/skills/llm-wiki-skill/docs/graph/performance/2026-06-18-phase-1-4-disposable-validation-gate.md +97 -0
  149. package/skills/llm-wiki-skill/docs/graph/performance/2026-06-18-phase-2-4-global-renderer-trial-matrix.md +168 -0
  150. package/skills/llm-wiki-skill/docs/graph/performance/2026-06-19-phase-6-1-sigma-graphology-trial.md +71 -0
  151. package/skills/llm-wiki-skill/docs/graph/performance/2026-06-19-phase-6-2-vis-network-trial.md +78 -0
  152. package/skills/llm-wiki-skill/docs/graph/performance/2026-06-19-phase-6-3-aggregation-fallback-trial.md +72 -0
  153. package/skills/llm-wiki-skill/docs/graph/performance/2026-06-19-phase-6-4-global-renderer-route-decision.md +94 -0
  154. package/skills/llm-wiki-skill/docs/graph/performance/2026-06-19-sigma-global-production-integration-result.md +102 -0
  155. package/skills/llm-wiki-skill/docs/graph/performance/artifacts/2026-06-18-phase-0-2/stage-4.5-offline-dense-wheel.json +9 -0
  156. package/skills/llm-wiki-skill/docs/graph/performance/artifacts/2026-06-18-phase-0-2/stage-4.5-offline-dense-wheel.png +0 -0
  157. package/skills/llm-wiki-skill/docs/graph/performance/artifacts/2026-06-18-phase-0-2/stage-4.5-offline-navigation.png +0 -0
  158. package/skills/llm-wiki-skill/docs/spark/2026-06-15-omp-tool-status-events-design.md +174 -0
  159. package/skills/llm-wiki-skill/docs/spark/2026-06-16-graph-interaction-geometry-design.md +832 -0
  160. package/skills/llm-wiki-skill/docs/spark/2026-06-16-graph-six-layer-architecture-design.md +577 -0
  161. package/skills/llm-wiki-skill/docs/spark/2026-06-17-static-renderer-coordination-split-design.md +172 -0
  162. package/skills/llm-wiki-skill/docs/spark/2026-06-18-large-graph-global-community-design.md +909 -0
  163. package/skills/llm-wiki-skill/docs/spark/2026-06-19-sigma-global-graph-renderer-design.md +360 -0
  164. package/skills/llm-wiki-skill/docs/spark/2026-06-20-paper-ui-port-design.md +162 -0
  165. package/skills/llm-wiki-skill/docs/spark/2026-06-20-paper-ui-v2-shell-alignment-design.md +384 -0
  166. package/skills/llm-wiki-skill/docs/spark/2026-06-21-graph-experience-completion-design.md +534 -0
  167. package/skills/llm-wiki-skill/docs/spark/2026-06-22-chat-auto-scroll-design.md +185 -0
  168. package/skills/llm-wiki-skill/docs/spark/2026-06-22-graph-community-node-visual-design.md +266 -0
  169. package/skills/llm-wiki-skill/docs/spark/2026-06-25-sigma-overlay-refactor-perf-design.md +170 -0
  170. package/skills/llm-wiki-skill/docs/spark/2026-06-26-global-sigma-community-spotlight-design.md +393 -0
  171. package/skills/llm-wiki-skill/docs/spark/mockups/2026-06-18-large-graph-global-community-flow.html +746 -0
  172. package/skills/llm-wiki-skill/install.ps1 +87 -0
  173. package/skills/llm-wiki-skill/install.sh +722 -0
  174. package/skills/llm-wiki-skill/package-lock.json +11171 -0
  175. package/skills/llm-wiki-skill/package.json +24 -0
  176. package/skills/llm-wiki-skill/packages/graph-engine/package.json +37 -0
  177. package/skills/llm-wiki-skill/packages/graph-engine/src/anim/.gitkeep +1 -0
  178. package/skills/llm-wiki-skill/packages/graph-engine/src/anim/index.ts +179 -0
  179. package/skills/llm-wiki-skill/packages/graph-engine/src/architecture.ts +79 -0
  180. package/skills/llm-wiki-skill/packages/graph-engine/src/diff.ts +121 -0
  181. package/skills/llm-wiki-skill/packages/graph-engine/src/facade.ts +1406 -0
  182. package/skills/llm-wiki-skill/packages/graph-engine/src/graph-node.ts +37 -0
  183. package/skills/llm-wiki-skill/packages/graph-engine/src/index.ts +25 -0
  184. package/skills/llm-wiki-skill/packages/graph-engine/src/layout/edge-geometry.ts +17 -0
  185. package/skills/llm-wiki-skill/packages/graph-engine/src/layout/index.ts +16 -0
  186. package/skills/llm-wiki-skill/packages/graph-engine/src/layout/spatial-index.ts +509 -0
  187. package/skills/llm-wiki-skill/packages/graph-engine/src/model/atlas.ts +18 -0
  188. package/skills/llm-wiki-skill/packages/graph-engine/src/model/index.ts +10 -0
  189. package/skills/llm-wiki-skill/packages/graph-engine/src/model/labels.ts +11 -0
  190. package/skills/llm-wiki-skill/packages/graph-engine/src/model/layout.ts +81 -0
  191. package/skills/llm-wiki-skill/packages/graph-engine/src/model/learning.ts +8 -0
  192. package/skills/llm-wiki-skill/packages/graph-engine/src/model/legacy-helpers.ts +1379 -0
  193. package/skills/llm-wiki-skill/packages/graph-engine/src/model/queue.ts +7 -0
  194. package/skills/llm-wiki-skill/packages/graph-engine/src/model/storage.ts +4 -0
  195. package/skills/llm-wiki-skill/packages/graph-engine/src/model/visibility.ts +9 -0
  196. package/skills/llm-wiki-skill/packages/graph-engine/src/render/.gitkeep +1 -0
  197. package/skills/llm-wiki-skill/packages/graph-engine/src/render/adapter.ts +443 -0
  198. package/skills/llm-wiki-skill/packages/graph-engine/src/render/aggregation-containers.ts +64 -0
  199. package/skills/llm-wiki-skill/packages/graph-engine/src/render/community-cloud-geometry.ts +178 -0
  200. package/skills/llm-wiki-skill/packages/graph-engine/src/render/community-wash.ts +238 -0
  201. package/skills/llm-wiki-skill/packages/graph-engine/src/render/community-washes.ts +19 -0
  202. package/skills/llm-wiki-skill/packages/graph-engine/src/render/compat-contract.ts +14 -0
  203. package/skills/llm-wiki-skill/packages/graph-engine/src/render/controller.ts +705 -0
  204. package/skills/llm-wiki-skill/packages/graph-engine/src/render/controls.ts +288 -0
  205. package/skills/llm-wiki-skill/packages/graph-engine/src/render/dom-svg-renderer.ts +180 -0
  206. package/skills/llm-wiki-skill/packages/graph-engine/src/render/edges.ts +51 -0
  207. package/skills/llm-wiki-skill/packages/graph-engine/src/render/geometry.ts +380 -0
  208. package/skills/llm-wiki-skill/packages/graph-engine/src/render/gestures.ts +673 -0
  209. package/skills/llm-wiki-skill/packages/graph-engine/src/render/graph-renderer-root.ts +387 -0
  210. package/skills/llm-wiki-skill/packages/graph-engine/src/render/hit-testing.ts +56 -0
  211. package/skills/llm-wiki-skill/packages/graph-engine/src/render/host-dom.ts +14 -0
  212. package/skills/llm-wiki-skill/packages/graph-engine/src/render/hover-card.ts +37 -0
  213. package/skills/llm-wiki-skill/packages/graph-engine/src/render/index.ts +213 -0
  214. package/skills/llm-wiki-skill/packages/graph-engine/src/render/keyboard.ts +48 -0
  215. package/skills/llm-wiki-skill/packages/graph-engine/src/render/legend.ts +25 -0
  216. package/skills/llm-wiki-skill/packages/graph-engine/src/render/minimap.ts +45 -0
  217. package/skills/llm-wiki-skill/packages/graph-engine/src/render/model.ts +1339 -0
  218. package/skills/llm-wiki-skill/packages/graph-engine/src/render/node-drag-lifecycle.ts +94 -0
  219. package/skills/llm-wiki-skill/packages/graph-engine/src/render/nodes.ts +103 -0
  220. package/skills/llm-wiki-skill/packages/graph-engine/src/render/offline-reader.ts +209 -0
  221. package/skills/llm-wiki-skill/packages/graph-engine/src/render/overlays-presenter.ts +192 -0
  222. package/skills/llm-wiki-skill/packages/graph-engine/src/render/overlays.ts +73 -0
  223. package/skills/llm-wiki-skill/packages/graph-engine/src/render/pin-position.ts +51 -0
  224. package/skills/llm-wiki-skill/packages/graph-engine/src/render/preview.ts +65 -0
  225. package/skills/llm-wiki-skill/packages/graph-engine/src/render/relation-focus.ts +91 -0
  226. package/skills/llm-wiki-skill/packages/graph-engine/src/render/render-context.ts +85 -0
  227. package/skills/llm-wiki-skill/packages/graph-engine/src/render/render-pipeline.ts +871 -0
  228. package/skills/llm-wiki-skill/packages/graph-engine/src/render/render-styles.ts +1405 -0
  229. package/skills/llm-wiki-skill/packages/graph-engine/src/render/renderer-surface.ts +75 -0
  230. package/skills/llm-wiki-skill/packages/graph-engine/src/render/search.ts +57 -0
  231. package/skills/llm-wiki-skill/packages/graph-engine/src/render/sigma-coordinates.ts +44 -0
  232. package/skills/llm-wiki-skill/packages/graph-engine/src/render/sigma-global-drag.ts +246 -0
  233. package/skills/llm-wiki-skill/packages/graph-engine/src/render/sigma-global-renderer.ts +1425 -0
  234. package/skills/llm-wiki-skill/packages/graph-engine/src/render/sigma-overlay-svg.ts +121 -0
  235. package/skills/llm-wiki-skill/packages/graph-engine/src/render/simulation-bridge.ts +59 -0
  236. package/skills/llm-wiki-skill/packages/graph-engine/src/render/state.ts +262 -0
  237. package/skills/llm-wiki-skill/packages/graph-engine/src/render/toolbar.ts +40 -0
  238. package/skills/llm-wiki-skill/packages/graph-engine/src/render/viewport.ts +336 -0
  239. package/skills/llm-wiki-skill/packages/graph-engine/src/select/.gitkeep +1 -0
  240. package/skills/llm-wiki-skill/packages/graph-engine/src/select/index.ts +189 -0
  241. package/skills/llm-wiki-skill/packages/graph-engine/src/sim/index.ts +372 -0
  242. package/skills/llm-wiki-skill/packages/graph-engine/src/sim/pins.ts +84 -0
  243. package/skills/llm-wiki-skill/packages/graph-engine/src/summary/index.ts +447 -0
  244. package/skills/llm-wiki-skill/packages/graph-engine/src/themes/.gitkeep +1 -0
  245. package/skills/llm-wiki-skill/packages/graph-engine/src/themes/index.ts +8 -0
  246. package/skills/llm-wiki-skill/packages/graph-engine/src/themes/tokens.ts +117 -0
  247. package/skills/llm-wiki-skill/packages/graph-engine/src/types/d3-quadtree.d.ts +22 -0
  248. package/skills/llm-wiki-skill/packages/graph-engine/src/types.ts +531 -0
  249. package/skills/llm-wiki-skill/packages/graph-engine/test/aggregation-fallback-trial-adapter.test.ts +115 -0
  250. package/skills/llm-wiki-skill/packages/graph-engine/test/aggregation-fallback-trial-adapter.ts +222 -0
  251. package/skills/llm-wiki-skill/packages/graph-engine/test/anim.test.ts +121 -0
  252. package/skills/llm-wiki-skill/packages/graph-engine/test/architecture.test.ts +63 -0
  253. package/skills/llm-wiki-skill/packages/graph-engine/test/community-cloud-geometry.test.ts +86 -0
  254. package/skills/llm-wiki-skill/packages/graph-engine/test/community-wash.test.ts +97 -0
  255. package/skills/llm-wiki-skill/packages/graph-engine/test/diff.test.ts +133 -0
  256. package/skills/llm-wiki-skill/packages/graph-engine/test/facade.test.ts +1369 -0
  257. package/skills/llm-wiki-skill/packages/graph-engine/test/geometry.test.ts +147 -0
  258. package/skills/llm-wiki-skill/packages/graph-engine/test/gestures.test.ts +768 -0
  259. package/skills/llm-wiki-skill/packages/graph-engine/test/graph-layout.test.ts +110 -0
  260. package/skills/llm-wiki-skill/packages/graph-engine/test/helpers.test.ts +287 -0
  261. package/skills/llm-wiki-skill/packages/graph-engine/test/interaction-contract.test.ts +106 -0
  262. package/skills/llm-wiki-skill/packages/graph-engine/test/keyboard.test.ts +59 -0
  263. package/skills/llm-wiki-skill/packages/graph-engine/test/large-fixtures.test.ts +47 -0
  264. package/skills/llm-wiki-skill/packages/graph-engine/test/large-graph-fixtures.ts +420 -0
  265. package/skills/llm-wiki-skill/packages/graph-engine/test/learning.test.ts +259 -0
  266. package/skills/llm-wiki-skill/packages/graph-engine/test/node-drag-lifecycle.test.ts +166 -0
  267. package/skills/llm-wiki-skill/packages/graph-engine/test/overlays.test.ts +115 -0
  268. package/skills/llm-wiki-skill/packages/graph-engine/test/preview.test.ts +56 -0
  269. package/skills/llm-wiki-skill/packages/graph-engine/test/queue.test.ts +114 -0
  270. package/skills/llm-wiki-skill/packages/graph-engine/test/relation-focus.test.ts +115 -0
  271. package/skills/llm-wiki-skill/packages/graph-engine/test/render-model.test.ts +1030 -0
  272. package/skills/llm-wiki-skill/packages/graph-engine/test/renderer-adapter-contract.test.ts +271 -0
  273. package/skills/llm-wiki-skill/packages/graph-engine/test/renderer-boundary.test.ts +618 -0
  274. package/skills/llm-wiki-skill/packages/graph-engine/test/renderer-lifecycle.test.ts +1711 -0
  275. package/skills/llm-wiki-skill/packages/graph-engine/test/route-continuity.test.ts +284 -0
  276. package/skills/llm-wiki-skill/packages/graph-engine/test/runtime-state.test.ts +281 -0
  277. package/skills/llm-wiki-skill/packages/graph-engine/test/search-and-legend.test.ts +124 -0
  278. package/skills/llm-wiki-skill/packages/graph-engine/test/select.test.ts +168 -0
  279. package/skills/llm-wiki-skill/packages/graph-engine/test/sigma-coordinates.test.ts +50 -0
  280. package/skills/llm-wiki-skill/packages/graph-engine/test/sigma-global-renderer.test.ts +2210 -0
  281. package/skills/llm-wiki-skill/packages/graph-engine/test/sigma-trial-adapter.test.ts +82 -0
  282. package/skills/llm-wiki-skill/packages/graph-engine/test/sigma-trial-adapter.ts +271 -0
  283. package/skills/llm-wiki-skill/packages/graph-engine/test/sim.test.ts +207 -0
  284. package/skills/llm-wiki-skill/packages/graph-engine/test/simulation-bridge.test.ts +96 -0
  285. package/skills/llm-wiki-skill/packages/graph-engine/test/spatial-index.test.ts +222 -0
  286. package/skills/llm-wiki-skill/packages/graph-engine/test/state.test.ts +189 -0
  287. package/skills/llm-wiki-skill/packages/graph-engine/test/summary-contract.test.ts +422 -0
  288. package/skills/llm-wiki-skill/packages/graph-engine/test/themes.test.ts +62 -0
  289. package/skills/llm-wiki-skill/packages/graph-engine/test/toolbar.test.ts +64 -0
  290. package/skills/llm-wiki-skill/packages/graph-engine/test/viewport.test.ts +213 -0
  291. package/skills/llm-wiki-skill/packages/graph-engine/test/vis-network-trial-adapter.test.ts +82 -0
  292. package/skills/llm-wiki-skill/packages/graph-engine/test/vis-network-trial-adapter.ts +186 -0
  293. package/skills/llm-wiki-skill/packages/graph-engine/tsconfig.json +17 -0
  294. package/skills/llm-wiki-skill/packages/graph-engine/vite.config.ts +15 -0
  295. package/skills/llm-wiki-skill/platforms/claude/CLAUDE.md +37 -0
  296. package/skills/llm-wiki-skill/platforms/claude/companions/llm-wiki-upgrade/SKILL.md +95 -0
  297. package/skills/llm-wiki-skill/platforms/codex/AGENTS.md +23 -0
  298. package/skills/llm-wiki-skill/platforms/hermes/README.md +31 -0
  299. package/skills/llm-wiki-skill/platforms/openclaw/README.md +31 -0
  300. package/skills/llm-wiki-skill/scripts/adapter-state.sh +424 -0
  301. package/skills/llm-wiki-skill/scripts/build-graph-data.sh +395 -0
  302. package/skills/llm-wiki-skill/scripts/build-graph-html.sh +459 -0
  303. package/skills/llm-wiki-skill/scripts/cache.sh +352 -0
  304. package/skills/llm-wiki-skill/scripts/create-source-page.sh +100 -0
  305. package/skills/llm-wiki-skill/scripts/delete-helper.sh +68 -0
  306. package/skills/llm-wiki-skill/scripts/graph-analysis.js +732 -0
  307. package/skills/llm-wiki-skill/scripts/hook-session-start.sh +46 -0
  308. package/skills/llm-wiki-skill/scripts/init-wiki.sh +95 -0
  309. package/skills/llm-wiki-skill/scripts/lib/source-signal-eligibility.js +158 -0
  310. package/skills/llm-wiki-skill/scripts/lint-fix.sh +114 -0
  311. package/skills/llm-wiki-skill/scripts/lint-runner.sh +217 -0
  312. package/skills/llm-wiki-skill/scripts/runtime-context.sh +77 -0
  313. package/skills/llm-wiki-skill/scripts/shared-config.sh +83 -0
  314. package/skills/llm-wiki-skill/scripts/source-record-contract.tsv +10 -0
  315. package/skills/llm-wiki-skill/scripts/source-registry.sh +349 -0
  316. package/skills/llm-wiki-skill/scripts/source-registry.tsv +10 -0
  317. package/skills/llm-wiki-skill/scripts/source-signal-coverage.js +83 -0
  318. package/skills/llm-wiki-skill/scripts/validate-step1.sh +144 -0
  319. package/skills/llm-wiki-skill/scripts/wiki-compat.sh +267 -0
  320. package/skills/llm-wiki-skill/setup.sh +8 -0
  321. package/skills/llm-wiki-skill/templates/entity-template.md +30 -0
  322. package/skills/llm-wiki-skill/templates/graph-styles/wash/footer.html +27 -0
  323. package/skills/llm-wiki-skill/templates/graph-styles/wash/graph-wash-helpers.js +1326 -0
  324. package/skills/llm-wiki-skill/templates/graph-styles/wash/graph-wash.js +1009 -0
  325. package/skills/llm-wiki-skill/templates/graph-styles/wash/header.html +2002 -0
  326. package/skills/llm-wiki-skill/templates/index-en-template.md +51 -0
  327. package/skills/llm-wiki-skill/templates/index-template.md +51 -0
  328. package/skills/llm-wiki-skill/templates/log-en-template.md +11 -0
  329. package/skills/llm-wiki-skill/templates/log-template.md +11 -0
  330. package/skills/llm-wiki-skill/templates/overview-en-template.md +41 -0
  331. package/skills/llm-wiki-skill/templates/overview-template.md +41 -0
  332. package/skills/llm-wiki-skill/templates/purpose-en-template.md +16 -0
  333. package/skills/llm-wiki-skill/templates/purpose-template.md +16 -0
  334. package/skills/llm-wiki-skill/templates/query-template.md +19 -0
  335. package/skills/llm-wiki-skill/templates/schema-template.md +185 -0
  336. package/skills/llm-wiki-skill/templates/source-template.md +51 -0
  337. package/skills/llm-wiki-skill/templates/synthesis-template.md +25 -0
  338. package/skills/llm-wiki-skill/templates/topic-template.md +35 -0
  339. package/skills/llm-wiki-skill/tests/adapter-state.sh +338 -0
  340. package/skills/llm-wiki-skill/tests/browser/graph-aggregation-fallback-trial.ts +737 -0
  341. package/skills/llm-wiki-skill/tests/browser/graph-community-node-map.mjs +255 -0
  342. package/skills/llm-wiki-skill/tests/browser/graph-community-wash-interactions.mjs +170 -0
  343. package/skills/llm-wiki-skill/tests/browser/graph-default-behavior.mjs +630 -0
  344. package/skills/llm-wiki-skill/tests/browser/graph-density-preview.mjs +53 -0
  345. package/skills/llm-wiki-skill/tests/browser/graph-html-insights.mjs +41 -0
  346. package/skills/llm-wiki-skill/tests/browser/graph-large-performance.ts +689 -0
  347. package/skills/llm-wiki-skill/tests/browser/graph-node-slim.mjs +75 -0
  348. package/skills/llm-wiki-skill/tests/browser/graph-offline-phase-6.mjs +660 -0
  349. package/skills/llm-wiki-skill/tests/browser/graph-renderer-trial-shared.ts +291 -0
  350. package/skills/llm-wiki-skill/tests/browser/graph-sigma-global-production.ts +1437 -0
  351. package/skills/llm-wiki-skill/tests/browser/graph-sigma-graphology-trial.ts +949 -0
  352. package/skills/llm-wiki-skill/tests/browser/graph-stage-4-5.mjs +815 -0
  353. package/skills/llm-wiki-skill/tests/browser/graph-vis-network-trial.ts +762 -0
  354. package/skills/llm-wiki-skill/tests/browser/graph-workbench-interactions.mjs +730 -0
  355. package/skills/llm-wiki-skill/tests/browser/validate-graph-trial-result.mjs +149 -0
  356. package/skills/llm-wiki-skill/tests/expected/graph-data-empty.json +60 -0
  357. package/skills/llm-wiki-skill/tests/expected/graph-data-sample.json +396 -0
  358. package/skills/llm-wiki-skill/tests/expected/graph-interactive-basic.html +1736 -0
  359. package/skills/llm-wiki-skill/tests/expected/lint-output.txt +44 -0
  360. package/skills/llm-wiki-skill/tests/fixtures/coverage-sample-wiki/index.md +1 -0
  361. package/skills/llm-wiki-skill/tests/fixtures/coverage-sample-wiki/wiki/entities/Alpha.md +10 -0
  362. package/skills/llm-wiki-skill/tests/fixtures/coverage-sample-wiki/wiki/entities/Beta.md +7 -0
  363. package/skills/llm-wiki-skill/tests/fixtures/coverage-sample-wiki/wiki/entities/Delta.md +8 -0
  364. package/skills/llm-wiki-skill/tests/fixtures/coverage-sample-wiki/wiki/entities/Gamma.md +8 -0
  365. package/skills/llm-wiki-skill/tests/fixtures/coverage-sample-wiki/wiki/queries/20260422-abc.md +10 -0
  366. package/skills/llm-wiki-skill/tests/fixtures/coverage-sample-wiki/wiki/synthesis/Crystal.md +8 -0
  367. package/skills/llm-wiki-skill/tests/fixtures/coverage-sample-wiki/wiki/topics/Overview.md +9 -0
  368. package/skills/llm-wiki-skill/tests/fixtures/graph-data-empty-wiki/wiki/entities/.gitkeep +0 -0
  369. package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/purpose.md +3 -0
  370. package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/wiki/entities/Attention.md +7 -0
  371. package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/wiki/entities/Decoder.md +7 -0
  372. package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/wiki/entities/Encoder.md +7 -0
  373. package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/wiki/entities/GPT.md +7 -0
  374. package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/wiki/entities/Transformer.md +13 -0
  375. package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/wiki/sources/paper.md +9 -0
  376. package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/wiki/topics/arch.md +12 -0
  377. package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/wiki/topics/finetune.md +9 -0
  378. package/skills/llm-wiki-skill/tests/fixtures/graph-interactive-basic/wiki/graph-data.json +40 -0
  379. package/skills/llm-wiki-skill/tests/fixtures/graph-interactive-dense/wiki/graph-data.json +3965 -0
  380. package/skills/llm-wiki-skill/tests/fixtures/graph-interactive-multicomm/wiki/graph-data.json +212 -0
  381. package/skills/llm-wiki-skill/tests/fixtures/lint-sample-wiki/index.md +14 -0
  382. package/skills/llm-wiki-skill/tests/fixtures/lint-sample-wiki/wiki/entities/C++.md +6 -0
  383. package/skills/llm-wiki-skill/tests/fixtures/lint-sample-wiki/wiki/entities/Lonely.md +4 -0
  384. package/skills/llm-wiki-skill/tests/fixtures/lint-sample-wiki/wiki/entities/Other.md +8 -0
  385. package/skills/llm-wiki-skill/tests/fixtures/lint-sample-wiki/wiki/entities/Real.md +7 -0
  386. package/skills/llm-wiki-skill/tests/fixtures/lint-sample-wiki/wiki/sources/2026-01-01-test-source.md +15 -0
  387. package/skills/llm-wiki-skill/tests/fixtures/lint-sample-wiki/wiki/sources/2026-02-01-inline-img.md +12 -0
  388. package/skills/llm-wiki-skill/tests/fixtures/lint-sample-wiki/wiki/topics/AIbasic.md +3 -0
  389. package/skills/llm-wiki-skill/tests/graph-aggregation-fallback-trial.regression-1.sh +46 -0
  390. package/skills/llm-wiki-skill/tests/graph-analysis-helper.regression-1.sh +237 -0
  391. package/skills/llm-wiki-skill/tests/graph-browser-large-performance.regression-1.sh +39 -0
  392. package/skills/llm-wiki-skill/tests/graph-browser-stage-4-5.regression-1.sh +163 -0
  393. package/skills/llm-wiki-skill/tests/graph-build-failures.regression-1.sh +91 -0
  394. package/skills/llm-wiki-skill/tests/graph-community-node-map.regression-1.sh +107 -0
  395. package/skills/llm-wiki-skill/tests/graph-community-wash-interactions.regression-1.sh +35 -0
  396. package/skills/llm-wiki-skill/tests/graph-data-confidence-merge.regression-1.sh +309 -0
  397. package/skills/llm-wiki-skill/tests/graph-data-source-paths.regression-1.sh +49 -0
  398. package/skills/llm-wiki-skill/tests/graph-default-behavior.regression-1.sh +35 -0
  399. package/skills/llm-wiki-skill/tests/graph-html-a11y.regression-1.sh +50 -0
  400. package/skills/llm-wiki-skill/tests/graph-html-brand-link.regression-1.sh +47 -0
  401. package/skills/llm-wiki-skill/tests/graph-html-density.regression-1.sh +228 -0
  402. package/skills/llm-wiki-skill/tests/graph-html-drawer-neighbors.regression-1.sh +47 -0
  403. package/skills/llm-wiki-skill/tests/graph-html-insights.regression-1.sh +80 -0
  404. package/skills/llm-wiki-skill/tests/graph-html-long-label.regression-1.sh +92 -0
  405. package/skills/llm-wiki-skill/tests/graph-html-minimap.regression-1.sh +51 -0
  406. package/skills/llm-wiki-skill/tests/graph-html-mobile.regression-1.sh +48 -0
  407. package/skills/llm-wiki-skill/tests/graph-html-oriental-atlas-contract.regression-1.sh +94 -0
  408. package/skills/llm-wiki-skill/tests/graph-html-oriental-design-contract.regression-1.sh +82 -0
  409. package/skills/llm-wiki-skill/tests/graph-html-search.regression-1.sh +52 -0
  410. package/skills/llm-wiki-skill/tests/graph-html-styles.regression-1.sh +66 -0
  411. package/skills/llm-wiki-skill/tests/graph-html-toolbar.regression-1.sh +62 -0
  412. package/skills/llm-wiki-skill/tests/graph-offline-phase-6.regression-1.sh +51 -0
  413. package/skills/llm-wiki-skill/tests/graph-sigma-global-production.regression-1.sh +64 -0
  414. package/skills/llm-wiki-skill/tests/graph-sigma-graphology-trial.regression-1.sh +46 -0
  415. package/skills/llm-wiki-skill/tests/graph-vis-network-trial.regression-1.sh +46 -0
  416. package/skills/llm-wiki-skill/tests/graph-workbench-interactions.regression-1.sh +151 -0
  417. package/skills/llm-wiki-skill/tests/js/graph-wash-bootstrap.test.js +110 -0
  418. package/skills/llm-wiki-skill/tests/js/graph-wash-helpers.test.js +296 -0
  419. package/skills/llm-wiki-skill/tests/js/graph-wash-learning.test.js +260 -0
  420. package/skills/llm-wiki-skill/tests/js/graph-wash-queue.test.js +115 -0
  421. package/skills/llm-wiki-skill/tests/js/graph-wash-runtime-state.test.js +282 -0
  422. package/skills/llm-wiki-skill/tests/js/source-signal-coverage.test.js +48 -0
  423. package/skills/llm-wiki-skill/tests/js/source-signal-eligibility.test.js +202 -0
  424. package/skills/llm-wiki-skill/tests/lib/graph-html-engine-helpers.sh +110 -0
  425. package/skills/llm-wiki-skill/tests/lint-output.regression-1.sh +32 -0
  426. package/skills/llm-wiki-skill/tests/regression.sh +1754 -0
  427. package/skills/llm-wiki-skill/workbench/AGENTS.md +110 -0
  428. package/skills/llm-wiki-skill/workbench/CLAUDE.md +55 -0
  429. package/skills/llm-wiki-skill/workbench/LICENSE +21 -0
  430. package/skills/llm-wiki-skill/workbench/PRODUCT.md +1353 -0
  431. package/skills/llm-wiki-skill/workbench/README.md +30 -0
  432. package/skills/llm-wiki-skill/workbench/docs/current-kb-retrieval-design.md +587 -0
  433. package/skills/llm-wiki-skill/workbench/docs/graph-evolution-1-design.md +210 -0
  434. package/skills/llm-wiki-skill/workbench/docs/stage-2-design.md +1139 -0
  435. package/skills/llm-wiki-skill/workbench/docs/stage-3-design.md +1269 -0
  436. package/skills/llm-wiki-skill/workbench/docs/stage-3.5-design.md +1164 -0
  437. package/skills/llm-wiki-skill/workbench/docs/stage-4-design.md +504 -0
  438. package/skills/llm-wiki-skill/workbench/docs/stage-4.5-design.md +195 -0
  439. package/skills/llm-wiki-skill/workbench/docs/superpowers/specs/2026-05-28-resizable-preview-layout-design.md +165 -0
  440. package/skills/llm-wiki-skill/workbench/docs/superpowers/specs/2026-05-28-settings-panel-scroll-fix.md +50 -0
  441. package/skills/llm-wiki-skill/workbench/server/package.json +31 -0
  442. package/skills/llm-wiki-skill/workbench/server/src/agent.ts +457 -0
  443. package/skills/llm-wiki-skill/workbench/server/src/artifacts.ts +248 -0
  444. package/skills/llm-wiki-skill/workbench/server/src/auth.ts +164 -0
  445. package/skills/llm-wiki-skill/workbench/server/src/config.ts +130 -0
  446. package/skills/llm-wiki-skill/workbench/server/src/conversations.test.ts +159 -0
  447. package/skills/llm-wiki-skill/workbench/server/src/conversations.ts +270 -0
  448. package/skills/llm-wiki-skill/workbench/server/src/digest/batch.ts +189 -0
  449. package/skills/llm-wiki-skill/workbench/server/src/digest/concurrency.test.ts +36 -0
  450. package/skills/llm-wiki-skill/workbench/server/src/digest/concurrency.ts +31 -0
  451. package/skills/llm-wiki-skill/workbench/server/src/digest/subagent.ts +91 -0
  452. package/skills/llm-wiki-skill/workbench/server/src/extensions/artifacts.ts +81 -0
  453. package/skills/llm-wiki-skill/workbench/server/src/extensions/knowledge-base.ts +263 -0
  454. package/skills/llm-wiki-skill/workbench/server/src/extensions/new-wiki.ts +42 -0
  455. package/skills/llm-wiki-skill/workbench/server/src/extensions/synthesis.ts +172 -0
  456. package/skills/llm-wiki-skill/workbench/server/src/graph-watcher.test.ts +196 -0
  457. package/skills/llm-wiki-skill/workbench/server/src/graph.test.ts +113 -0
  458. package/skills/llm-wiki-skill/workbench/server/src/graph.ts +351 -0
  459. package/skills/llm-wiki-skill/workbench/server/src/index.ts +1148 -0
  460. package/skills/llm-wiki-skill/workbench/server/src/knowledge-bases.test.ts +30 -0
  461. package/skills/llm-wiki-skill/workbench/server/src/knowledge-bases.ts +321 -0
  462. package/skills/llm-wiki-skill/workbench/server/src/pages.test.ts +41 -0
  463. package/skills/llm-wiki-skill/workbench/server/src/pages.ts +160 -0
  464. package/skills/llm-wiki-skill/workbench/server/src/retrieval.test.ts +151 -0
  465. package/skills/llm-wiki-skill/workbench/server/src/retrieval.ts +427 -0
  466. package/skills/llm-wiki-skill/workbench/server/src/tool-status-events.test.ts +363 -0
  467. package/skills/llm-wiki-skill/workbench/server/src/tool-status-events.ts +616 -0
  468. package/skills/llm-wiki-skill/workbench/server/src/wiki-init.test.ts +19 -0
  469. package/skills/llm-wiki-skill/workbench/server/src/wiki-init.ts +188 -0
  470. package/skills/llm-wiki-skill/workbench/server/tsconfig.json +10 -0
  471. package/skills/llm-wiki-skill/workbench/tsconfig.json +20 -0
  472. package/skills/llm-wiki-skill/workbench/web/README.md +73 -0
  473. package/skills/llm-wiki-skill/workbench/web/components.json +21 -0
  474. package/skills/llm-wiki-skill/workbench/web/eslint.config.js +22 -0
  475. package/skills/llm-wiki-skill/workbench/web/index.html +16 -0
  476. package/skills/llm-wiki-skill/workbench/web/package.json +54 -0
  477. package/skills/llm-wiki-skill/workbench/web/src/App.tsx +1195 -0
  478. package/skills/llm-wiki-skill/workbench/web/src/components/AddExternalDialog.tsx +375 -0
  479. package/skills/llm-wiki-skill/workbench/web/src/components/AppearancePanel.tsx +158 -0
  480. package/skills/llm-wiki-skill/workbench/web/src/components/ArtifactView.tsx +15 -0
  481. package/skills/llm-wiki-skill/workbench/web/src/components/BatchDigestPanel.tsx +117 -0
  482. package/skills/llm-wiki-skill/workbench/web/src/components/ChatPanel.tsx +890 -0
  483. package/skills/llm-wiki-skill/workbench/web/src/components/CommandMenu.tsx +75 -0
  484. package/skills/llm-wiki-skill/workbench/web/src/components/ExportButtons.tsx +58 -0
  485. package/skills/llm-wiki-skill/workbench/web/src/components/GraphPanel.tsx +800 -0
  486. package/skills/llm-wiki-skill/workbench/web/src/components/GraphReader.tsx +52 -0
  487. package/skills/llm-wiki-skill/workbench/web/src/components/GraphSelection.tsx +100 -0
  488. package/skills/llm-wiki-skill/workbench/web/src/components/GraphSummaryDrawer.tsx +269 -0
  489. package/skills/llm-wiki-skill/workbench/web/src/components/MainViewTabs.tsx +69 -0
  490. package/skills/llm-wiki-skill/workbench/web/src/components/MarkdownView.tsx +106 -0
  491. package/skills/llm-wiki-skill/workbench/web/src/components/NewWikiDialog.tsx +103 -0
  492. package/skills/llm-wiki-skill/workbench/web/src/components/RefMenu.tsx +44 -0
  493. package/skills/llm-wiki-skill/workbench/web/src/components/RightDrawer.tsx +298 -0
  494. package/skills/llm-wiki-skill/workbench/web/src/components/SearchPanel.tsx +165 -0
  495. package/skills/llm-wiki-skill/workbench/web/src/components/SettingsPanel.tsx +320 -0
  496. package/skills/llm-wiki-skill/workbench/web/src/components/Sidebar.tsx +354 -0
  497. package/skills/llm-wiki-skill/workbench/web/src/components/ToolHistorySummary.tsx +111 -0
  498. package/skills/llm-wiki-skill/workbench/web/src/components/ToolStatusRunway.tsx +70 -0
  499. package/skills/llm-wiki-skill/workbench/web/src/components/TopBar.tsx +348 -0
  500. package/skills/llm-wiki-skill/workbench/web/src/components/renderers/DownloadOnlyRenderer.tsx +88 -0
  501. package/skills/llm-wiki-skill/workbench/web/src/components/renderers/HtmlRenderer.tsx +92 -0
  502. package/skills/llm-wiki-skill/workbench/web/src/components/ui/button.tsx +52 -0
  503. package/skills/llm-wiki-skill/workbench/web/src/components/ui/command.tsx +50 -0
  504. package/skills/llm-wiki-skill/workbench/web/src/components/ui/dialog.tsx +156 -0
  505. package/skills/llm-wiki-skill/workbench/web/src/components/ui/input.tsx +21 -0
  506. package/skills/llm-wiki-skill/workbench/web/src/components/ui/tooltip.tsx +57 -0
  507. package/skills/llm-wiki-skill/workbench/web/src/index.css +4204 -0
  508. package/skills/llm-wiki-skill/workbench/web/src/lib/api.ts +648 -0
  509. package/skills/llm-wiki-skill/workbench/web/src/lib/appearance.ts +114 -0
  510. package/skills/llm-wiki-skill/workbench/web/src/lib/drawer-layout.ts +41 -0
  511. package/skills/llm-wiki-skill/workbench/web/src/lib/drawer-state.ts +168 -0
  512. package/skills/llm-wiki-skill/workbench/web/src/lib/graph-reader.ts +25 -0
  513. package/skills/llm-wiki-skill/workbench/web/src/lib/graph-selection-drawer.ts +35 -0
  514. package/skills/llm-wiki-skill/workbench/web/src/lib/graph-selection.ts +96 -0
  515. package/skills/llm-wiki-skill/workbench/web/src/lib/graph-summary-actions.ts +184 -0
  516. package/skills/llm-wiki-skill/workbench/web/src/lib/legacy-tool-status.ts +113 -0
  517. package/skills/llm-wiki-skill/workbench/web/src/lib/model-roles.ts +20 -0
  518. package/skills/llm-wiki-skill/workbench/web/src/lib/search-filter.ts +104 -0
  519. package/skills/llm-wiki-skill/workbench/web/src/lib/sse.ts +72 -0
  520. package/skills/llm-wiki-skill/workbench/web/src/lib/tool-status-format.ts +170 -0
  521. package/skills/llm-wiki-skill/workbench/web/src/lib/tool-status-model.ts +392 -0
  522. package/skills/llm-wiki-skill/workbench/web/src/lib/utils.ts +10 -0
  523. package/skills/llm-wiki-skill/workbench/web/src/lib/view-status.ts +16 -0
  524. package/skills/llm-wiki-skill/workbench/web/src/lib/wiki-links.ts +32 -0
  525. package/skills/llm-wiki-skill/workbench/web/src/main.tsx +10 -0
  526. package/skills/llm-wiki-skill/workbench/web/test/api.test.ts +61 -0
  527. package/skills/llm-wiki-skill/workbench/web/test/app-shell-drawer-layout.test.tsx +48 -0
  528. package/skills/llm-wiki-skill/workbench/web/test/appearance-panel.test.tsx +121 -0
  529. package/skills/llm-wiki-skill/workbench/web/test/appearance.test.ts +262 -0
  530. package/skills/llm-wiki-skill/workbench/web/test/chat-host-source.test.tsx +22 -0
  531. package/skills/llm-wiki-skill/workbench/web/test/chat-panel-auto-scroll.test.tsx +311 -0
  532. package/skills/llm-wiki-skill/workbench/web/test/chat-panel-bubbles.test.tsx +48 -0
  533. package/skills/llm-wiki-skill/workbench/web/test/chat-panel-composer.test.tsx +86 -0
  534. package/skills/llm-wiki-skill/workbench/web/test/chat-panel-tool-status.test.tsx +26 -0
  535. package/skills/llm-wiki-skill/workbench/web/test/export-batch-paper.test.tsx +101 -0
  536. package/skills/llm-wiki-skill/workbench/web/test/graph-drawer-state.test.ts +257 -0
  537. package/skills/llm-wiki-skill/workbench/web/test/graph-panel-paper.test.tsx +200 -0
  538. package/skills/llm-wiki-skill/workbench/web/test/graph-reader-request.test.ts +32 -0
  539. package/skills/llm-wiki-skill/workbench/web/test/graph-reader.test.ts +62 -0
  540. package/skills/llm-wiki-skill/workbench/web/test/graph-selection-drawer.test.ts +56 -0
  541. package/skills/llm-wiki-skill/workbench/web/test/graph-selection.test.ts +83 -0
  542. package/skills/llm-wiki-skill/workbench/web/test/graph-summary-actions.test.ts +188 -0
  543. package/skills/llm-wiki-skill/workbench/web/test/main-view-tabs.test.tsx +34 -0
  544. package/skills/llm-wiki-skill/workbench/web/test/markdown-view.test.tsx +34 -0
  545. package/skills/llm-wiki-skill/workbench/web/test/popup-menus.test.tsx +85 -0
  546. package/skills/llm-wiki-skill/workbench/web/test/render.test.tsx +30 -0
  547. package/skills/llm-wiki-skill/workbench/web/test/render.tsx +38 -0
  548. package/skills/llm-wiki-skill/workbench/web/test/right-drawer-graph-summary.test.tsx +287 -0
  549. package/skills/llm-wiki-skill/workbench/web/test/right-drawer-interactions.test.tsx +182 -0
  550. package/skills/llm-wiki-skill/workbench/web/test/search-filter.test.ts +65 -0
  551. package/skills/llm-wiki-skill/workbench/web/test/search-panel.test.tsx +155 -0
  552. package/skills/llm-wiki-skill/workbench/web/test/setup-dom.ts +66 -0
  553. package/skills/llm-wiki-skill/workbench/web/test/sidebar-v2-source.test.ts +17 -0
  554. package/skills/llm-wiki-skill/workbench/web/test/sidebar.test.tsx +110 -0
  555. package/skills/llm-wiki-skill/workbench/web/test/tool-history-summary.test.tsx +150 -0
  556. package/skills/llm-wiki-skill/workbench/web/test/tool-status-format.test.ts +107 -0
  557. package/skills/llm-wiki-skill/workbench/web/test/tool-status-model.test.ts +324 -0
  558. package/skills/llm-wiki-skill/workbench/web/test/tool-status-runway.test.ts +159 -0
  559. package/skills/llm-wiki-skill/workbench/web/test/topbar.test.tsx +248 -0
  560. package/skills/llm-wiki-skill/workbench/web/test/visual/paper-ui.ts +898 -0
  561. package/skills/llm-wiki-skill/workbench/web/test/wiki-links.test.ts +23 -0
  562. package/skills/llm-wiki-skill/workbench/web/test-results/paper-ui/actual/.gitkeep +1 -0
  563. package/skills/llm-wiki-skill/workbench/web/test-results/paper-ui/baseline/.gitkeep +1 -0
  564. package/skills/llm-wiki-skill/workbench/web/tsconfig.app.json +30 -0
  565. package/skills/llm-wiki-skill/workbench/web/tsconfig.json +7 -0
  566. package/skills/llm-wiki-skill/workbench/web/tsconfig.node.json +24 -0
  567. package/skills/llm-wiki-skill/workbench/web/vite.config.ts +28 -0
@@ -1,4 +1,5 @@
1
1
  import { defineTool } from '@deepseek-ai/dsh-tools';
2
+ import {} from '@deepseek-ai/dsh-util-values';
2
3
  import { tmpdir } from 'node:os';
3
4
  import { KanbanProvider } from '../services/kanban-provider.js';
4
5
  import { buildKanbanTools } from './kanban-tools.js';
@@ -10,8 +11,11 @@ import { buildPlanningGuidance } from '../routes/planning-driver.js';
10
11
  import { attachSessionToWorkspace, resolveOrCreateWorkspace } from '../dispatcher/workspace-attach.js';
11
12
  import { PREFETCH_MANIFEST_SCHEMA } from '../domain/prefetch-manifest.js';
12
13
  import { WikiVaultClient } from '../wiki/wiki-vault-client.js';
14
+ import { LocalWikiClient } from '../wiki/local-kb-client.js';
15
+ import { ensureLocalKbRoot } from '../wiki/local-kb.js';
16
+ import { LOCAL_CHECKLIST_PREFIX } from '../wiki/page-path.js';
13
17
  export const planningBySession = new Map();
14
- const KANBAN_HANDOFF_RULE = (routes) => `
18
+ export const KANBAN_HANDOFF_RULE = (routes) => `
15
19
  ## 主 agent 铁律(看板工作流 v2)
16
20
  - 你是计划者:只做需求澄清(grill-me)与最终收尾汇报;绝不执行任务本身。
17
21
  - 最高护栏:只读仓库——禁止 git 操作、禁止 write/edit 任何仓库源码;只允许写 KB(planning_checklist_save)与临时目录兜底。
@@ -19,7 +23,25 @@ const KANBAN_HANDOFF_RULE = (routes) => `
19
23
  - ${routes.openspec} 后链路进入 executing,V 自动串行建卡 p→(pt)→w2→d→dt→w3;你不要自己执行。
20
24
  - 用 kanban_show / kanban_list / spec_card_view 观察进度,链完成后向用户汇报产物链接与轨迹入口。
21
25
  - 经验沉淀:链路完成后,用户可发 ${routes.learning}(或 ${routes.learning} <chainId>)沉淀本链经验;主 agent 消化机械证据包后调 planning_learning_save 入库。
26
+ - 叙述铁律:回复中的链号/卡号(ch_/sc_/t_ 编号)只能逐字复制自工具结果;建链成败以工具结果字段为准,禁止编造或沿用旧对话里的编号。
22
27
  `;
28
+ /** 防线③:/openspec: 成功后的逐链确定性叙述规则(2026-09-04 mtmgp81q:模型口播 ch_1_mtjrhkrf
29
+ * 与工具结果 ch_1_mtmgp81q 脱节)。逐字引用锚点 + firstCard 成败结论;整包缓存回放仍可能
30
+ * 绕过 prompt 层——最终防线是链级看门狗(防线①)。 */
31
+ export function buildOpenspecNarrationRule(r) {
32
+ const firstCardLine = !r.firstCard
33
+ ? '- 首卡结果未采集(旧返回体)。汇报前先调 kanban_show 复核链状态,以 kanban_show 复核后再汇报,禁止臆断建卡成功。'
34
+ : 'pending' in r.firstCard
35
+ ? `- 首卡尚未创建(等待超时,看门狗接管)。回复必须写明「首卡尚未创建,看门狗接管」,禁止声称建卡成功。`
36
+ : `- 首卡已创建:taskId=${r.firstCard.taskId}(status=${r.firstCard.status})。回复必须写明「首卡已创建」。`;
37
+ return [
38
+ '## 本次建链结果(回复必须逐字引用,禁止改写编号)',
39
+ `- chainId=${r.chainId}`,
40
+ `- specCardId=${r.specCardId}`,
41
+ firstCardLine,
42
+ '- 铁律:回复中的 ch_/sc_/t_ 编号只能逐字复制自本结果;禁止出现本结果之外的任何编号;禁止声称与本结果矛盾的建卡状态。',
43
+ ].join('\n');
44
+ }
23
45
  // 清单获取只有两条路:内存(路由1)> KB 候选页(路由2,LLM 读页重建)。禁止编造其他原因
24
46
  // ("先重试 / 查服务进程是否重启"类诊断是噪声:内存丢失唯一成因是插件重启,重启后按两条路恢复即可)。
25
47
  const RECOVERY_KB_GUIDANCE = (routes, candidates) => `
@@ -28,7 +50,7 @@ const RECOVERY_KB_GUIDANCE = (routes, candidates) => `
28
50
  ${candidates.map((c) => '- ' + c).join('\n')}
29
51
  恢复步骤(严格顺序):
30
52
  1. 读取候选页内容,对照当前需求判定哪一页是本次需求的需求澄清清单(页首行标题为「# 【需求】<需求名>」);
31
- 2. 消化该页内容,重建结构化 PlanningChecklist(spec 六段 + manifest + clarifications + doubtsrequirementName 取页标题中【需求】后的名称);
53
+ 2. 消化该页内容,重建结构化 PlanningChecklist(spec 六段 + manifest + clarifications + doubts + risks(风险点,若有),requirementName 取页标题中【需求】后的名称;恢复重建时 clarifications 允许登记单条无澄清说明,如 {"q": "本轮无澄清(恢复重建)", "a": "<来源页或原因>"},其余场景 clarifications 禁止为空);
32
54
  3. 调 planning_checklist_save(checklist, restoreRef=<该候选页路径>) 回存(覆盖原页,勿产生重复页);
33
55
  4. 回存成功后提示用户重新发送 ${routes.openspec} 确认。
34
56
  禁止:跳过恢复直接建链建卡;猜测清单内容;把恢复失败归因于"重试/进程检查"之外的任何原因。
@@ -89,7 +111,7 @@ export function buildSpawnPrefetch(ctx) {
89
111
  /** v2 主会话工具面:/plan: 捕获规划上下文(零副作用)→ planning_checklist_save 回写 → /openspec: 用清单建链。
90
112
  * 工具面 = kanban_route + 只读 kanban 子集 + spec_card_view + planning 工具;
91
113
  * 无 spec_card_edit/approve、无 kanban_create/complete/block(主会话越权写由工具面裁剪 + prefetch 子代理只读护栏双保险)。 */
92
- export function registerMainSessionTools(ctx, config) {
114
+ export function registerMainSessionTools(ctx, configProvider) {
93
115
  const registry = ctx.get('tools');
94
116
  if (!registry)
95
117
  return; // 测试裸 Context 无 tools 服务(P1-9 无 inject 依赖),跳过注册
@@ -97,9 +119,13 @@ export function registerMainSessionTools(ctx, config) {
97
119
  if (!provider)
98
120
  return;
99
121
  const service = provider.service;
100
- // 生产 wiring(src/index.ts:44)仅保证 tools+kanban 可用,无 wiki 服务 → config.wikiVault 自建
101
- //(与 dispatcher 构造同源);测试经 ctx.get('wiki') 注入 mock 客户端。
102
- const wiki = ctx.get('wiki') ?? new WikiVaultClient(config.wikiVault);
122
+ // 生产 wiring(src/index.ts)仅保证 tools+kanban 可用,无 wiki 服务 → configProvider 自建
123
+ //(与 dispatcher 构造同源,getEffective() 调用时热读取 baseUrl/pagePrefix);测试经 ctx.get('wiki') 注入 mock 客户端。
124
+ // D3 双模式:local 模式走 LocalWikiClient 本地检索(不发 HTTP),remote 用配置的 WikiVaultClient
125
+ const kbMode = configProvider.mode;
126
+ const wiki = kbMode === 'local'
127
+ ? new LocalWikiClient(ensureLocalKbRoot())
128
+ : (ctx.get('wiki') ?? new WikiVaultClient(() => configProvider.getEffective().wikiVault));
103
129
  const caller = () => ({ actor: 'human' });
104
130
  // 只读 kanban 子集(无 create/complete/block)
105
131
  const readOnly = new Set(['kanban_show', 'kanban_chain', 'kanban_list', 'kanban_comment']);
@@ -115,13 +141,15 @@ export function registerMainSessionTools(ctx, config) {
115
141
  }
116
142
  // planning 工具(清单落库 + 只读预取)——spawnPrefetch 由模块级 buildSpawnPrefetch 提供(可单测)
117
143
  for (const tool of buildPlanningTools({
118
- service, wiki,
144
+ service, wiki: wiki, // local 模式为 LocalWikiClient(write/read/search 同面,D3 双模式客户端)
119
145
  getCaller: caller,
120
146
  spawnPrefetch: buildSpawnPrefetch(ctx),
121
147
  tempDir: () => `${tmpdir()}/dsh-swarm-checklists`, // KB 不可达时的临时兜底,放系统临时目录(不落插件源码/核心存储目录)
122
- pagePrefix: config.wikiVault?.pagePrefix ?? 'projects/', // 生成的清单页路径保持在该客户端配置的命名空间内(避免 kb-rejected)
123
- prefixRoutes: config.prefixRoutes,
124
- memoryEnabled: config.memory?.enabled ?? true,
148
+ pagePrefix: configProvider.getEffective().wikiVault?.pagePrefix ?? 'projects/', // 生成的清单页路径保持在该客户端配置的命名空间内(避免 kb-rejected)
149
+ kbMode: configProvider.mode, // D3 双模式:local 时 checklist/learning 落本地库命名空间(wiki/queries/checklists/、wiki/synthesis/learnings/)
150
+ prefixRoutes: configProvider.getEffective().prefixRoutes,
151
+ memoryEnabled: configProvider.getEffective().memory?.enabled ?? true,
152
+ resolveWorkspaceDir: () => planningBySession.get('session_main')?.workspaceDir ?? null,
125
153
  ownerSessionId: 'session_main',
126
154
  onChecklistSaved({ ref, source, checklist }) {
127
155
  const cur = planningBySession.get('session_main') ?? { workspaceDir: null, sessionId: 'session_main', checklist: null, checklistRef: null, checklistSource: null, requirementName: null };
@@ -129,8 +157,8 @@ export function registerMainSessionTools(ctx, config) {
129
157
  },
130
158
  }))
131
159
  registry.register(tool);
132
- // kanban_route:/plan: 捕获规划上下文;/openspec: 用清单建链
133
- const { plan, openspec, learning } = config.prefixRoutes;
160
+ // kanban_route:/plan: 捕获规划上下文;/openspec: 用清单建链(前缀路由注册时快照,用于工具描述)
161
+ const { plan, openspec, learning } = configProvider.getEffective().prefixRoutes;
134
162
  registry.register(defineTool({
135
163
  name: 'kanban_route',
136
164
  description: `MUST be called when the human message starts with ${plan}, ${openspec}, or ${learning}. This is dsh-swarm planning, NOT the built-in /plan plan mode. ${plan} = zero side-effect + start grill-me (+ auto KB memory index); ${openspec} = create chain from saved checklist; ${learning} = distill experience from a chain (evidence pack + planning_learning_save).`,
@@ -140,17 +168,18 @@ export function registerMainSessionTools(ctx, config) {
140
168
  // M2(Q5)+归组:仅 /plan: 分支捕获主 agent 工作空间并可能询问注册——/openspec:/none 不触发,
141
169
  // 避免死代码副作用多弹一次 ask(/openspec: 实际用的是 planningBySession 已存的 workspaceDir)。
142
170
  // header.cwd 缺失或未注册时询问用户注册工作区;仍不可得保持 null(链任务随后 block 'workspace-unknown')。
143
- const plan = await handlePlanRoute(args.message, service, config.prefixRoutes, 'session_main');
171
+ const plan = await handlePlanRoute(args.message, service, configProvider.getEffective().prefixRoutes, 'session_main');
144
172
  if (plan.kind === 'plan') {
145
173
  const headerCwd = exec?.agent?.session?.header?.cwd ?? null;
146
174
  const workspaceDir = await resolveOrCreateWorkspace(ctx, headerCwd, '主 agent 会话');
147
175
  planningBySession.set('session_main', { workspaceDir, sessionId: 'session_main', checklist: null, checklistRef: null, checklistSource: null, requirementName: plan.rest });
148
- let guidance = buildPlanningGuidance(config.prefixRoutes) + KANBAN_HANDOFF_RULE(config.prefixRoutes);
149
- if ((config.memory?.enabled ?? true) && workspaceDir) {
176
+ let guidance = buildPlanningGuidance(configProvider.getEffective().prefixRoutes) + KANBAN_HANDOFF_RULE(configProvider.getEffective().prefixRoutes);
177
+ if ((configProvider.getEffective().memory?.enabled ?? true) && workspaceDir) {
150
178
  const idx = await recallMemoryIndex(wiki, {
151
179
  requirementName: plan.rest || null,
152
180
  workspaceDir,
153
- maxEntries: config.memory?.maxIndexEntries ?? 8,
181
+ maxEntries: configProvider.getEffective().memory?.maxIndexEntries ?? 8,
182
+ kbMode,
154
183
  });
155
184
  if (idx)
156
185
  guidance += '\n' + idx;
@@ -158,7 +187,7 @@ export function registerMainSessionTools(ctx, config) {
158
187
  return { kind: 'plan', guidance };
159
188
  }
160
189
  if (plan.kind === 'learning') {
161
- const r = await handleLearningRoute(args.message, service, config.prefixRoutes, 'session_main');
190
+ const r = await handleLearningRoute(args.message, service, configProvider.getEffective().prefixRoutes, 'session_main');
162
191
  if (r.error)
163
192
  return { kind: 'learning', error: r.error, guidance: r.guidance };
164
193
  return { kind: 'learning', chainId: r.chainId, brief: r.brief, guidance: r.guidance };
@@ -168,21 +197,59 @@ export function registerMainSessionTools(ctx, config) {
168
197
  // 路由1(内存):planningBySession 命中 → 直接建链
169
198
  const pctx = planningBySession.get('session_main');
170
199
  if (pctx?.checklist && pctx.checklistRef) {
200
+ // 恢复补捕①:内存有清单但 workspaceDir=null(主 agent 重启后清单经 KB 恢复、异常态)→
201
+ // 从 exec.agent.session.header.cwd 捡回工作区,路由1 继续正常建链。已有值绝不重解析
202
+ // (不重复弹 ask,对齐下方 /plan: 分支注释顾虑);解析 null(无 cwd/无通道/用户跳过)保持
203
+ // 现状 → 走 handleOpenspecRoute 的 workspace-unknown fail-fast(不吞错、不猜测路径)。
204
+ if (!pctx.workspaceDir) {
205
+ const headerCwd = exec?.agent?.session?.header?.cwd ?? null;
206
+ const workspaceDir = await resolveOrCreateWorkspace(ctx, headerCwd, '主 agent 会话(/openspec: 恢复)');
207
+ if (workspaceDir) {
208
+ pctx.workspaceDir = workspaceDir;
209
+ planningBySession.set('session_main', pctx);
210
+ }
211
+ }
212
+ // 闸2:清单落库的仓库与当前工作区不一致 → 硬拦不建链(KB 页路径带 repoSlug 维度的前提是链与工作区同源)
213
+ const localPath = pctx.checklist.manifest.repo.localPath;
214
+ if (pctx.workspaceDir && localPath !== pctx.workspaceDir) {
215
+ return {
216
+ kind: 'openspec', approved: false, reason: 'workspace-mismatch',
217
+ error: `[workspace-mismatch] 清单 manifest.repo.localPath (${localPath}) 与当前工作区 (${pctx.workspaceDir}) 不一致。请在目标仓库工作区内重新执行 ${configProvider.getEffective().prefixRoutes.plan} 重新澄清落库后再 ${configProvider.getEffective().prefixRoutes.openspec}(不可跳过)。`,
218
+ };
219
+ }
171
220
  const input = { workspaceDir: pctx.workspaceDir, checklist: pctx.checklist, checklistRef: pctx.checklistRef, requirementName: pctx.requirementName };
172
- const r = await handleOpenspecRoute(args.message, service, config.prefixRoutes, input, 'session_main');
173
- return { kind: 'openspec', chainId: r.chainId, specCardId: r.specCardId, approved: true, guidance: KANBAN_HANDOFF_RULE(config.prefixRoutes) };
221
+ const r = await handleOpenspecRoute(args.message, service, configProvider.getEffective().prefixRoutes, input, 'session_main');
222
+ // 护栏拦截(如 workspace-unknown):透传失败原因与恢复指引,不得伪装成建链成功
223
+ if (r.approved === false || !r.chainId || !r.specCardId) {
224
+ return { kind: 'openspec', approved: false, reason: r.reason ?? 'unknown', guidance: r.guidance };
225
+ }
226
+ return {
227
+ kind: 'openspec', chainId: r.chainId, specCardId: r.specCardId, approved: true, firstCard: r.firstCard,
228
+ guidance: KANBAN_HANDOFF_RULE(configProvider.getEffective().prefixRoutes) + '\n\n' + buildOpenspecNarrationRule({ chainId: r.chainId, specCardId: r.specCardId, firstCard: r.firstCard }),
229
+ };
174
230
  }
175
231
  // 路由2(知识库):内存丢失(插件重启)→ 搜 KB 候选清单页供 LLM 读页重建;搜不到/不可达 → 两条路皆空
232
+ // 恢复补捕②:无内存条目或工作区未捕获 → 从 header.cwd 捡回,写入 planningBySession(checklist 等
233
+ // 字段保持 cur 或空缺省),后续 planning_checklist_save 触发 onChecklistSaved 的 { ...cur } 展开自然
234
+ // 带上 workspaceDir。解析失败不阻塞恢复 guidance 返回(行为同现状,只是少捕一次)。
235
+ if (!planningBySession.get('session_main')?.workspaceDir) {
236
+ const headerCwd = exec?.agent?.session?.header?.cwd ?? null;
237
+ const workspaceDir = await resolveOrCreateWorkspace(ctx, headerCwd, '主 agent 会话(/openspec: 恢复)');
238
+ if (workspaceDir) {
239
+ const cur = planningBySession.get('session_main') ?? { workspaceDir: null, sessionId: 'session_main', checklist: null, checklistRef: null, checklistSource: null, requirementName: null };
240
+ planningBySession.set('session_main', { ...cur, workspaceDir });
241
+ }
242
+ }
176
243
  let candidates = [];
177
244
  try {
178
- candidates = await searchChecklists(wiki, config.wikiVault?.pagePrefix ?? 'projects/');
245
+ candidates = await searchChecklists(wiki, kbMode === 'local' ? LOCAL_CHECKLIST_PREFIX : (configProvider.getEffective().wikiVault?.pagePrefix ?? 'projects/'));
179
246
  }
180
247
  catch { /* KB 不可达/搜索失败 → 候选为空,走两条路皆空分支 */ }
181
248
  return {
182
249
  kind: 'openspec', approved: false, reason: 'no-checklist',
183
250
  recovery: candidates.length > 0 ? 'kb' : 'none',
184
251
  checklistCandidates: candidates,
185
- guidance: candidates.length > 0 ? RECOVERY_KB_GUIDANCE(config.prefixRoutes, candidates) : RECOVERY_NONE_GUIDANCE(config.prefixRoutes),
252
+ guidance: candidates.length > 0 ? RECOVERY_KB_GUIDANCE(configProvider.getEffective().prefixRoutes, candidates) : RECOVERY_NONE_GUIDANCE(configProvider.getEffective().prefixRoutes),
186
253
  };
187
254
  },
188
255
  }));
@@ -20,6 +20,8 @@ export interface PlanningToolDeps {
20
20
  spawnPrefetch?(prompt: string, workspaceDir: string, parentAgent?: Agent, signal?: AbortSignal): Promise<string>;
21
21
  tempDir(): string;
22
22
  pagePrefix?: string;
23
+ /** KB 双模式(D3):local 时 checklist/learning 落本地库命名空间(wiki/queries/checklists/、wiki/synthesis/learnings/),缺省 remote。 */
24
+ kbMode?: 'remote' | 'local';
23
25
  ownerSessionId?: string;
24
26
  /** 斜杠命令前缀路由(决策12 单一事实源),用于 description 文案派生。 */
25
27
  prefixRoutes: PrefixRoutes;
@@ -32,6 +34,8 @@ export interface PlanningToolDeps {
32
34
  }): void;
33
35
  /** memory.enabled;false 时 planning_memory_recall 返回 disabled 提示(planning_learning_save 不受影响)。 */
34
36
  memoryEnabled?: boolean;
37
+ /** 闸1:/plan: 捕获的当前工作区(main-session-tools 注入);非 null 且与清单 localPath 不一致 → 阻断落库。 */
38
+ resolveWorkspaceDir?: () => string | null;
35
39
  }
36
40
  /** 主 agent 规划期工具:需求澄清清单落库(KB 优先/临时目录兜底)+ 只读仓库预取(子代理)。 */
37
41
  export declare function buildPlanningTools(deps: PlanningToolDeps): import("@deepseek-ai/dsh-tools").ToolDefinition[];
@@ -1,19 +1,24 @@
1
1
  // src/tools/planning-tools.ts
2
2
  import { defineTool } from '@deepseek-ai/dsh-tools';
3
+ import {} from '@deepseek-ai/dsh-util-values';
3
4
  import { validatePlanningChecklist, formatChecklistBody } from '../domain/planning-checklist.js';
4
5
  import { validatePrefetchManifest } from '../domain/prefetch-manifest.js';
5
- import { buildChecklistSlug, CHECKLIST_PAGE_PREFIX, assertAllowedWikiPagePath } from '../wiki/page-path.js';
6
+ import { buildChecklistSlug, KB_PAGE_NAMESPACES_HINT, LOCAL_CHECKLIST_PREFIX, LOCAL_LEARNING_BASE, assertAllowedWikiPagePath, assertLocalKbPagePath } from '../wiki/page-path.js';
6
7
  import { validateLearning, formatLearningBody, buildRepoSlug } from '../domain/memory.js';
7
8
  const isWikiError = (e) => e instanceof Error && e.code === 'kb-unreachable';
8
9
  /** 主 agent 规划期工具:需求澄清清单落库(KB 优先/临时目录兜底)+ 只读仓库预取(子代理)。 */
9
10
  export function buildPlanningTools(deps) {
11
+ const local = deps.kbMode === 'local';
12
+ // checklist 前缀双模式(D3/D5):remote → projects/<repoSlug>/checklists/(repoSlug 段在 pagePath 拼接,workspace 计划 T3);
13
+ // local → wiki/queries/checklists/(local 时 LocalWikiClient.write 仅接受 wiki/** 相对路径,projects/ 会被 kb-rejected——I1 修复)
10
14
  const pagePrefix = deps.pagePrefix ?? 'projects/';
15
+ const checklistPrefix = local ? LOCAL_CHECKLIST_PREFIX : pagePrefix;
11
16
  const session = deps.ownerSessionId ?? 'session_main';
12
17
  return [
13
18
  defineTool({
14
19
  name: 'planning_checklist_save',
15
20
  description: 'Save the converged requirement-clarification checklist (structured schema) to KB, falling back to a temp dir if KB is unreachable. Returns ref/path + authoritative repo path. restoreRef (optional) = existing KB page path to overwrite in place (recovery path when in-memory context was lost); omit for first-time save (creates a new timestamped page).',
16
- parameters: { checklist: { type: 'json', required: true, description: 'Structured PlanningChecklist: spec six sections + manifest(repo.files) + clarifications + doubts. checklist.requirementName (optional) = ' + deps.prefixRoutes.plan + ' rest first sentence, used for the checklist page title 【需求】, same source as the task-card title' }, restoreRef: { type: 'string', description: 'Optional KB page path to overwrite in place (recovery path); omit for new save' } },
21
+ parameters: { checklist: { type: 'json', required: true, description: 'Structured PlanningChecklist: {requirementName?, spec: {problem, solution, user_stories, impl_decisions, testing, out_of_scope}, manifest, clarifications, doubts: Array<{"q": string, "resolved": boolean, "answer"?: string}>, risks?}. spec.user_stories: array of plain strings — each element ONE sentence "As a <role>, I want <capability>, so that <benefit>"; NEVER objects/nested. spec.impl_decisions: array of plain strings — one decision per element; NEVER objects. clarifications: non-empty required — record every Q&A asked during this planning round; Array<{"q": string, "a": string}> with keys exactly "q"/"a" (NOT "question"/"answer"). risks (optional): Array<{"description": string, "source": string, "mitigation": string}> — register real risks/non-blocking concerns surfaced during clarification; omit or [] when none. checklist.requirementName (optional) = ' + deps.prefixRoutes.plan + ' rest first sentence, used for the checklist page title 【需求】, same source as the task-card title' }, restoreRef: { type: 'string', description: 'Optional KB page path to overwrite in place (recovery path); omit for new save' } },
17
22
  output: { schema: { type: 'json' }, render: (_a, v) => [{ type: 'text', text: JSON.stringify(v) }] },
18
23
  async execute(args) {
19
24
  const caller = deps.getCaller();
@@ -23,9 +28,13 @@ export function buildPlanningTools(deps) {
23
28
  if (errors.length > 0)
24
29
  throw new Error('invalid planning checklist: ' + errors.join('; '));
25
30
  const checklist = args.checklist;
31
+ const wsDir = deps.resolveWorkspaceDir?.() ?? null;
32
+ if (wsDir && checklist.manifest.repo.localPath !== wsDir) {
33
+ throw new Error(`[workspace-mismatch] 清单 manifest.repo.localPath (${checklist.manifest.repo.localPath}) 与当前工作区 (${wsDir}) 不一致。请在目标仓库工作区内重新执行 ${deps.prefixRoutes.plan} 重新澄清落库(不可跳过)。`);
34
+ }
26
35
  const body = formatChecklistBody(checklist);
27
36
  // 恢复路径(内存丢失后重建):传 restoreRef 则覆盖原页,不产生重复页
28
- if (args.restoreRef && args.restoreRef.startsWith(pagePrefix)) {
37
+ if (args.restoreRef && args.restoreRef.startsWith(checklistPrefix)) {
29
38
  try {
30
39
  await deps.wiki.write(args.restoreRef, body);
31
40
  deps.onChecklistSaved?.({ ref: args.restoreRef, source: 'kb', checklist });
@@ -37,7 +46,10 @@ export function buildPlanningTools(deps) {
37
46
  // KB 不可达 → 落临时目录兜底(不覆盖原页),回调仍回填内存
38
47
  }
39
48
  }
40
- const pagePath = `${CHECKLIST_PAGE_PREFIX}${buildChecklistSlug(checklist.requirementName ?? checklist.spec.problem)}-${Date.now().toString(36)}.md`;
49
+ const slug = buildChecklistSlug(checklist.requirementName ?? checklist.spec.problem);
50
+ const pagePath = local
51
+ ? `${checklistPrefix}${slug}-${Date.now().toString(36)}.md`
52
+ : `${pagePrefix}${buildRepoSlug(checklist.manifest.repo.localPath)}/checklists/${slug}-${Date.now().toString(36)}.md`;
41
53
  try {
42
54
  await deps.wiki.write(pagePath, body);
43
55
  deps.onChecklistSaved?.({ ref: pagePath, source: 'kb', checklist });
@@ -86,7 +98,7 @@ export function buildPlanningTools(deps) {
86
98
  }),
87
99
  defineTool({
88
100
  name: 'planning_learning_save',
89
- description: 'Save a distilled learning (experience) to the knowledge base. scope=chain → projects/<chainId>/learnings/ (requirement-level); scope=project → projects/<repoSlug>/learnings/ (repo-level, repoSlug derived from the chain workspaceDir). Returns ref. Soft-fails {ok:false,reason:"kb-unreachable"} when KB is unreachable (no temp fallback).',
101
+ description: 'Save a distilled learning (experience) to the knowledge base. Remote KB: scope=chain → projects/<repoSlug>/<chainId>/learnings/ (requirement-level); scope=project → projects/<repoSlug>/learnings/ (repo-level). repoSlug is derived from the chain workspaceDir; both scopes require chain.workspaceDir. Local KB: both scopes → wiki/synthesis/learnings/<chainId|repoSlug>/. Returns ref. Soft-fails {ok:false,reason:"kb-unreachable"} when KB is unreachable (no temp fallback).',
90
102
  parameters: {
91
103
  learning: { type: 'json', required: true, description: 'LearningEntry: { title (≤80 chars), lesson, evidence (mechanical chain/task id — required), tags: string[] }' },
92
104
  scope: { type: 'string', enum: ['chain', 'project'], required: true, description: '"chain" (requirement-level) | "project" (repo-level)' },
@@ -110,13 +122,23 @@ export function buildPlanningTools(deps) {
110
122
  throw new Error('unknown chain: ' + args.chainId);
111
123
  const entry = args.learning;
112
124
  let prefix;
113
- if (args.scope === 'chain') {
114
- prefix = `projects/${args.chainId}/learnings/`;
125
+ if (local) {
126
+ // local(D5):scope=chain 直接挂 chainId;scope=project 挂 repoSlug(需 workspaceDir)
127
+ if (args.scope === 'chain') {
128
+ prefix = `${LOCAL_LEARNING_BASE}${args.chainId}/`;
129
+ }
130
+ else {
131
+ if (!chain.workspaceDir)
132
+ throw new Error('scope=project requires chain.workspaceDir (target repo) — chain has none');
133
+ prefix = `${LOCAL_LEARNING_BASE}${buildRepoSlug(chain.workspaceDir)}/`;
134
+ }
115
135
  }
116
136
  else {
137
+ // remote(workspace 计划 T3):两 scope 均要求 chain.workspaceDir,统一挂 projects/<repoSlug>/
117
138
  if (!chain.workspaceDir)
118
- throw new Error('scope=project requires chain.workspaceDir (target repo) — chain has none');
119
- prefix = `projects/${buildRepoSlug(chain.workspaceDir)}/learnings/`;
139
+ throw new Error('learning save requires chain.workspaceDir (target repo) — chain has none');
140
+ const wsRoot = `${pagePrefix}${buildRepoSlug(chain.workspaceDir)}/`;
141
+ prefix = args.scope === 'chain' ? `${wsRoot}${args.chainId}/learnings/` : `${wsRoot}learnings/`;
120
142
  }
121
143
  const pagePath = `${prefix}${buildChecklistSlug(entry.title)}-${Date.now().toString(36)}.md`;
122
144
  try {
@@ -132,9 +154,9 @@ export function buildPlanningTools(deps) {
132
154
  }),
133
155
  defineTool({
134
156
  name: 'planning_memory_recall',
135
- description: 'Recall KB memory for planning. path mode: read a full page (whitelist: projects/checklists/, projects/learnings/, projects/<slug>/learnings/, projects/ch_*/learnings/, projects/ch_*/t_*.md, projects/ch_*/review/) truncated to 8000 chars. query mode: full-text search returning top 5 {path,title,score}. Returns {ok:false,reason:"kb-unreachable"} on KB failure; {ok:false,reason:"disabled"} when memory is disabled.',
157
+ description: 'Recall KB memory for planning. path mode: read a full page truncated to 8000 chars. path mode whitelist: remote = ' + KB_PAGE_NAMESPACES_HINT + '; local = any wiki/** relative path inside the local KB root. query mode: full-text search returning top 5 {path,title,score}. Returns {ok:false,reason:"kb-unreachable"} on KB failure; {ok:false,reason:"disabled"} when memory is disabled.',
136
158
  parameters: {
137
- path: { type: 'string', description: 'KB page path to read in full (mutually exclusive with query)' },
159
+ path: { type: 'string', description: 'KB page path to read in full (mutually exclusive with query). remote mode: projects/ namespace path; local mode: wiki/** relative path inside the local KB root.' },
138
160
  query: { type: 'string', description: 'Full-text query; returns top 5 result paths (mutually exclusive with path)' },
139
161
  },
140
162
  output: { schema: { type: 'json' }, render: (_a, v) => [{ type: 'text', text: JSON.stringify(v) }] },
@@ -149,7 +171,12 @@ export function buildPlanningTools(deps) {
149
171
  if (hasPath === hasQuery)
150
172
  throw new Error('provide exactly one of path|query');
151
173
  if (hasPath) {
152
- assertAllowedWikiPagePath(args.path);
174
+ // path 白名单按 KB 双模式分支(D3/D9):remote → projects/** 命名空间;local → wiki/**(
175
+ // Task 11 后 local 的 checklist/learning 全落 wiki/ 前缀,用 projects/ 白名单会把 local 读腿全拒)
176
+ if (local)
177
+ assertLocalKbPagePath(args.path);
178
+ else
179
+ assertAllowedWikiPagePath(args.path);
153
180
  try {
154
181
  const d = await deps.wiki.read(args.path);
155
182
  const content = d.rawMd.length > 8000 ? d.rawMd.slice(0, 8000) + '…' : d.rawMd;
@@ -1,4 +1,5 @@
1
1
  import { defineTool } from '@deepseek-ai/dsh-tools';
2
+ import {} from '@deepseek-ai/dsh-util-values';
2
3
  import { can } from '../domain/permissions.js';
3
4
  function guard(action, caller) {
4
5
  if (!can(action, caller.actor, null))
@@ -1,4 +1,5 @@
1
1
  import { defineTool } from '@deepseek-ai/dsh-tools';
2
+ import {} from '@deepseek-ai/dsh-util-values';
2
3
  import { KanbanService } from '../domain/kanban-service.js';
3
4
  import { can } from '../domain/permissions.js';
4
5
  function guard(action, caller) {
@@ -1,6 +1,7 @@
1
1
  import { defineTool } from '@deepseek-ai/dsh-tools';
2
+ import {} from '@deepseek-ai/dsh-util-values';
2
3
  import { can } from '../domain/permissions.js';
3
- import { assertAllowedWikiPagePath } from '../wiki/page-path.js';
4
+ import { assertAllowedWikiPagePath, KB_PAGE_NAMESPACES_HINT } from '../wiki/page-path.js';
4
5
  function guard(action, caller) {
5
6
  if (!can(action, caller.actor, null))
6
7
  throw new Error('permission denied: ' + action);
@@ -34,7 +35,7 @@ export function buildWikiTools(wiki, getCaller) {
34
35
  }),
35
36
  defineTool({
36
37
  name: 'wiki_write',
37
- description: 'Write a wiki-vault page under the configured pagePrefix (W only).',
38
+ description: 'Write a wiki-vault page under projects/<repoSlug>/ namespaces (W only). pagePath must match: ' + KB_PAGE_NAMESPACES_HINT,
38
39
  parameters: {
39
40
  pagePath: { type: 'string', required: true },
40
41
  content: { type: 'string', required: true },
@@ -43,8 +44,8 @@ export function buildWikiTools(wiki, getCaller) {
43
44
  async execute(args) {
44
45
  const caller = getCaller();
45
46
  guard('wiki-write', caller);
46
- // Q3&5:工具边界强校验——只允许 projects/checklists/、projects/ch_*/t_*.md、projects/ch_*/review/
47
- // 三类命名空间(page-path.ts 白名单),杜绝 LLM 自造路径/拼错层级导致 kb_url 无法跳转。
47
+ // Q3&5:工具边界强校验——只允许 projects/<repoSlug>/ 白名单命名空间(KB_PAGE_NAMESPACES_HINT 五类,
48
+ // page-path.ts),杜绝 LLM 自造路径/拼错层级导致 kb_url 无法跳转。
48
49
  assertAllowedWikiPagePath(args.pagePath);
49
50
  const out = await wiki.write(args.pagePath, args.content);
50
51
  // Q4:工具直接拼完整 kb_url(host 用 config.wikiVault.baseUrl,杜绝 LLM 手写错域名)。
@@ -1,9 +1,16 @@
1
- import type { WikiVaultClient } from './wiki-vault-client.js';
2
1
  import type { BoardState } from '../domain/types.js';
2
+ /** kb-linkage 所需最小 wiki 面(WikiVaultClient / LocalWikiClient 均满足,D2 双模式客户端注入)。 */
3
+ type KbWikiClient = {
4
+ read(pagePath: string): Promise<{
5
+ rawMd: string;
6
+ }>;
7
+ write(pagePath: string, content: string): Promise<unknown>;
8
+ };
3
9
  /**
4
10
  * 机械互链登记:链上 w:kb 任务完成时调用。
5
11
  * - 清单页:追加/更新「关联文档」区块,列出链上全部已 done 的 W2/W3 页。
6
12
  * - 当前页:写回清单页链接(清单 ref 来自规格卡 kind:'kb' 附件)。
7
13
  * 幂等(containsLine / 区块就地替换);任何 wiki 读/写失败均静默跳过,不抛错。
8
14
  */
9
- export declare function syncKbLinks(wiki: WikiVaultClient, state: BoardState, taskId: string): Promise<void>;
15
+ export declare function syncKbLinks(wiki: KbWikiClient, state: BoardState, taskId: string): Promise<void>;
16
+ export {};
@@ -49,9 +49,9 @@ export async function syncKbLinks(wiki, state, taskId) {
49
49
  if (!chain?.specCardId)
50
50
  return;
51
51
  const spec = state.specCards.get(chain.specCardId);
52
- // 清单页 ref:kind:'kb' 附件;仅接受 projects/ 命名空间(临时目录兜底路径不是 KB 页,跳过)
52
+ // 清单页 ref:kind:'kb' 附件;接受 projects/(remote)或 wiki/(local)命名空间(临时目录兜底路径不是 KB 页,跳过)
53
53
  const checklistRef = spec?.attachments.find((a) => a.kind === 'kb')?.ref ?? null;
54
- const checklistPath = checklistRef && checklistRef.startsWith('projects/') ? checklistRef : null;
54
+ const checklistPath = checklistRef && (checklistRef.startsWith('projects/') || checklistRef.startsWith('wiki/')) ? checklistRef : null;
55
55
  // 链上已 done 的 W2/W3 页(含当前任务所属页)
56
56
  const pages = [...state.tasks.values()]
57
57
  .filter((t) => t.chainId === task.chainId && t.assignee === 'w' && t.mode === 'kb' && t.status === 'done')
@@ -61,7 +61,7 @@ export async function syncKbLinks(wiki, state, taskId) {
61
61
  ? state.handoffs.get(t.id).metadata.page_path
62
62
  : null,
63
63
  }))
64
- .filter((p) => p.pagePath !== null && p.pagePath.startsWith('projects/'));
64
+ .filter((p) => p.pagePath !== null && (p.pagePath.startsWith('projects/') || p.pagePath.startsWith('wiki/')));
65
65
  if (pages.length === 0)
66
66
  return;
67
67
  // 1) 清单页:登记全部 W2/W3 页链接
@@ -0,0 +1,14 @@
1
+ import { type WikiSearchResult } from './wiki-vault-client.js';
2
+ export declare class LocalWikiClient {
3
+ readonly baseUrl = "";
4
+ readonly root: string;
5
+ constructor(root: string);
6
+ private abs;
7
+ write(pagePath: string, content: string): Promise<{
8
+ path: string;
9
+ }>;
10
+ read(pagePath: string): Promise<{
11
+ rawMd: string;
12
+ }>;
13
+ search(q: string): Promise<WikiSearchResult[]>;
14
+ }
@@ -0,0 +1,101 @@
1
+ // src/wiki/local-kb-client.ts
2
+ // 本地 KB 客户端(llm-wiki 目录结构):与 WikiVaultClient 同构的 search/read/write 面,
3
+ // local 模式下替换注入(planning 工具 / kb-linkage / memory-recall 复用既有逻辑,零分支扩散)。
4
+ // 排序原则 D12:相关性优先 7 : 新鲜度 3(0.7*scoreNorm + 0.3*mtimeNorm)。
5
+ import { readdirSync, readFileSync, writeFileSync, mkdirSync, statSync, existsSync } from 'node:fs';
6
+ import { join, dirname, resolve, sep } from 'node:path';
7
+ import { WikiError } from './wiki-vault-client.js';
8
+ import { isInsideKbRoot } from './local-kb.js';
9
+ import { assertLocalKbPagePath } from './page-path.js';
10
+ export class LocalWikiClient {
11
+ baseUrl = '';
12
+ root;
13
+ constructor(root) { this.root = root; }
14
+ abs(pagePath) {
15
+ assertLocalKbPagePath(pagePath); // Task 1 白名单单一来源(wiki/**、拒 .. 与绝对路径),勿内联重复
16
+ const t = resolve(this.root, pagePath);
17
+ if (!isInsideKbRoot(this.root, t))
18
+ throw new WikiError('kb-rejected', undefined, `kb-rejected: path escapes local KB root: ${pagePath}`);
19
+ return t;
20
+ }
21
+ async write(pagePath, content) {
22
+ const t = this.abs(pagePath);
23
+ try {
24
+ mkdirSync(dirname(t), { recursive: true });
25
+ writeFileSync(t, content, 'utf8');
26
+ }
27
+ catch (err) {
28
+ // §9 降级链依赖:fs 失败归一 kb-unreachable(planning 工具按 code 判定 temp 兜底/软失败,审查 M5)
29
+ throw new WikiError('kb-unreachable', undefined, `kb-unreachable: local KB write failed: ${String(err)}`);
30
+ }
31
+ return { path: pagePath };
32
+ }
33
+ async read(pagePath) {
34
+ const t = this.abs(pagePath);
35
+ if (!existsSync(t))
36
+ throw new WikiError('kb-rejected', undefined, `kb-rejected: page not found: ${pagePath}`);
37
+ try {
38
+ return { rawMd: readFileSync(t, 'utf8') };
39
+ }
40
+ catch (err) {
41
+ throw new WikiError('kb-unreachable', undefined, `kb-unreachable: local KB read failed: ${String(err)}`);
42
+ }
43
+ }
44
+ async search(q) {
45
+ const needle = String(q ?? '').toLowerCase().trim();
46
+ if (!needle)
47
+ return [];
48
+ const hits = [];
49
+ const walk = (dir) => {
50
+ let entries = [];
51
+ try {
52
+ entries = readdirSync(dir);
53
+ }
54
+ catch {
55
+ return;
56
+ }
57
+ for (const e of entries) {
58
+ const p = join(dir, e);
59
+ const st = statSync(p);
60
+ if (st.isDirectory()) {
61
+ walk(p);
62
+ continue;
63
+ }
64
+ if (!e.endsWith('.md'))
65
+ continue;
66
+ let text = '';
67
+ try {
68
+ text = readFileSync(p, 'utf8');
69
+ }
70
+ catch {
71
+ continue;
72
+ }
73
+ const lower = text.toLowerCase();
74
+ const n = lower.split(needle).length - 1;
75
+ if (n === 0)
76
+ continue;
77
+ hits.push({
78
+ path: p.slice(this.root.length + 1).split(sep).join('/'),
79
+ title: text.split('\n')[0]?.replace(/^#\s*/, '').trim() || e,
80
+ score: n,
81
+ mtime: Math.floor(st.mtimeMs / 1000),
82
+ hits: n,
83
+ });
84
+ }
85
+ };
86
+ walk(this.root);
87
+ if (hits.length === 0)
88
+ return [];
89
+ const maxHits = Math.max(...hits.map((h) => h.hits));
90
+ const times = hits.map((h) => h.mtime);
91
+ const minT = Math.min(...times);
92
+ const maxT = Math.max(...times);
93
+ const span = maxT - minT || 1;
94
+ return hits
95
+ .map((h) => ({
96
+ ...h,
97
+ score: Number((0.7 * (h.hits / maxHits) + 0.3 * ((h.mtime - minT) / span)).toFixed(4)),
98
+ }))
99
+ .sort((a, b) => b.score - a.score);
100
+ }
101
+ }
@@ -0,0 +1,6 @@
1
+ export declare function localKbRoot(): string;
2
+ /** 尽力创建库根(幂等);失败由调用方告警 + block(kb-unreachable)(设计 §9)。 */
3
+ export declare function ensureLocalKbRoot(root?: string): string;
4
+ /** target 须为绝对路径且解析后落在 root 内(resolve 折叠重复斜杠;相对路径 fail-closed,
5
+ * 因为 bash/fs 里的相对目标语义属会话 cwd 而非库根,护栏不可猜测)。 */
6
+ export declare function isInsideKbRoot(root: string, target: string): boolean;
@@ -0,0 +1,25 @@
1
+ // src/wiki/local-kb.ts
2
+ // 本地 KB(llm-wiki)库根工具(设计 D4:独立 <DSH_HOME>/storages/kanban/wiki/,隔离用户个人 ~/.llm-wiki-path)。
3
+ import { homedir } from 'node:os';
4
+ import { join, resolve, sep } from 'node:path';
5
+ import { mkdirSync } from 'node:fs';
6
+ export function localKbRoot() {
7
+ const dshHome = process.env.DSH_HOME ?? join(homedir(), '.dsh');
8
+ return join(dshHome, 'storages', 'kanban', 'wiki');
9
+ }
10
+ /** 尽力创建库根(幂等);失败由调用方告警 + block(kb-unreachable)(设计 §9)。 */
11
+ export function ensureLocalKbRoot(root = localKbRoot()) {
12
+ mkdirSync(root, { recursive: true });
13
+ return root;
14
+ }
15
+ /** target 须为绝对路径且解析后落在 root 内(resolve 折叠重复斜杠;相对路径 fail-closed,
16
+ * 因为 bash/fs 里的相对目标语义属会话 cwd 而非库根,护栏不可猜测)。 */
17
+ export function isInsideKbRoot(root, target) {
18
+ if (!target)
19
+ return false;
20
+ // 相对路径 fail-closed:不与 root 拼接猜测(相对目标语义属会话 cwd)
21
+ if (resolve(target) !== target)
22
+ return false;
23
+ const r = resolve(root).replace(/\/+$/, '');
24
+ return resolve(target) === r || resolve(target).startsWith(r + sep);
25
+ }
@@ -1,16 +1,24 @@
1
- import type { WikiVaultClient, WikiSearchResult } from './wiki-vault-client.js';
2
- export declare function recallLearningIndex(wiki: WikiVaultClient, opts: {
1
+ import type { WikiSearchResult } from './wiki-vault-client.js';
2
+ /** KB 客户端最小检索面(WikiVaultClient / LocalWikiClient 均满足)。 */
3
+ type WikiSearchClient = {
4
+ search(q: string): Promise<WikiSearchResult[]>;
5
+ };
6
+ export declare function recallLearningIndex(wiki: WikiSearchClient, opts: {
3
7
  requirementName: string | null;
4
8
  workspaceDir: string | null;
9
+ kbMode?: 'remote' | 'local';
5
10
  }): Promise<WikiSearchResult[]>;
6
- export declare function recallDocIndex(wiki: WikiVaultClient, opts: {
11
+ export declare function recallDocIndex(wiki: WikiSearchClient, opts: {
7
12
  requirementName: string | null;
8
13
  workspaceDir: string | null;
14
+ kbMode?: 'remote' | 'local';
9
15
  }): Promise<WikiSearchResult[]>;
10
- export declare function recallMemoryIndex(wiki: WikiVaultClient, opts: {
16
+ export declare function recallMemoryIndex(wiki: WikiSearchClient, opts: {
11
17
  requirementName: string | null;
12
18
  workspaceDir: string | null;
13
19
  maxEntries: number;
20
+ kbMode?: 'remote' | 'local';
14
21
  }): Promise<string | null>;
15
- /** /openspec: 恢复路径复用:搜【需求】候选清单页(projects/ 前缀 top5)。 */
16
- export declare function searchChecklists(wiki: WikiVaultClient, pagePrefix?: string): Promise<string[]>;
22
+ /** /openspec: 恢复路径复用:搜【需求】候选清单页(pagePrefix 前缀 top5;local 调用方传 wiki/queries/checklists/)。 */
23
+ export declare function searchChecklists(wiki: WikiSearchClient, pagePrefix?: string): Promise<string[]>;
24
+ export {};