maestro-flow 0.5.42 → 0.5.44

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 (412) hide show
  1. package/.agents/skills/domain-add/SKILL.md +3 -0
  2. package/.agents/skills/learn-decompose/SKILL.md +7 -4
  3. package/.agents/skills/learn-follow/SKILL.md +4 -2
  4. package/.agents/skills/learn-investigate/SKILL.md +8 -6
  5. package/.agents/skills/learn-second-opinion/SKILL.md +6 -3
  6. package/.agents/skills/maestro/SKILL.md +1 -1
  7. package/.agents/skills/maestro-amend/SKILL.md +1 -1
  8. package/.agents/skills/maestro-analyze/SKILL.md +1 -1
  9. package/.agents/skills/maestro-blueprint/SKILL.md +1 -1
  10. package/.agents/skills/maestro-brainstorm/SKILL.md +4 -1
  11. package/.agents/skills/maestro-collab/SKILL.md +6 -2
  12. package/.agents/skills/maestro-companion/SKILL.md +4 -1
  13. package/.agents/skills/maestro-composer/SKILL.md +4 -2
  14. package/.agents/skills/maestro-execute/SKILL.md +26 -8
  15. package/.agents/skills/maestro-fork/SKILL.md +4 -3
  16. package/.agents/skills/maestro-grill/SKILL.md +1 -1
  17. package/.agents/skills/maestro-guard/SKILL.md +2 -2
  18. package/.agents/skills/maestro-impeccable/SKILL.md +2 -1
  19. package/.agents/skills/maestro-init/SKILL.md +1 -1
  20. package/.agents/skills/maestro-merge/SKILL.md +12 -1
  21. package/.agents/skills/maestro-milestone-audit/SKILL.md +1 -0
  22. package/.agents/skills/maestro-milestone-complete/SKILL.md +8 -3
  23. package/.agents/skills/maestro-milestone-release/SKILL.md +8 -4
  24. package/.agents/skills/maestro-overlay/SKILL.md +9 -0
  25. package/.agents/skills/maestro-plan/SKILL.md +1 -0
  26. package/.agents/skills/maestro-player/SKILL.md +2 -2
  27. package/.agents/skills/maestro-quick/SKILL.md +5 -3
  28. package/.agents/skills/maestro-ralph/SKILL.md +8 -8
  29. package/.agents/skills/maestro-ralph-agent/SKILL.md +697 -0
  30. package/.agents/skills/maestro-ralph-agent-execute/SKILL.md +461 -0
  31. package/.agents/skills/maestro-ralph-cli/SKILL.md +665 -0
  32. package/.agents/skills/maestro-ralph-cli-execute/SKILL.md +239 -0
  33. package/.agents/skills/maestro-ralph-execute/SKILL.md +127 -11
  34. package/.agents/skills/maestro-roadmap/SKILL.md +1 -1
  35. package/.agents/skills/maestro-swarm-workflow/SKILL.md +16 -14
  36. package/.agents/skills/maestro-tools-register/SKILL.md +16 -1
  37. package/.agents/skills/maestro-ui-codify/SKILL.md +11 -1
  38. package/.agents/skills/maestro-universal-workflow/SKILL.md +28 -5
  39. package/.agents/skills/maestro-update/SKILL.md +10 -7
  40. package/.agents/skills/manage-codebase-rebuild/SKILL.md +5 -1
  41. package/.agents/skills/manage-drift-realign/SKILL.md +6 -2
  42. package/.agents/skills/manage-harvest/SKILL.md +4 -1
  43. package/.agents/skills/manage-issue-discover/SKILL.md +1 -0
  44. package/.agents/skills/manage-kg-extractors/SKILL.md +5 -1
  45. package/.agents/skills/manage-knowhow-capture/SKILL.md +1 -0
  46. package/.agents/skills/manage-knowledge-audit/SKILL.md +3 -0
  47. package/.agents/skills/manage-wiki/SKILL.md +1 -0
  48. package/.agents/skills/odyssey-debug/SKILL.md +2 -1
  49. package/.agents/skills/odyssey-improve/SKILL.md +2 -2
  50. package/.agents/skills/odyssey-planex/SKILL.md +8 -7
  51. package/.agents/skills/odyssey-review-test-fix/SKILL.md +4 -1
  52. package/.agents/skills/odyssey-ui/SKILL.md +4 -4
  53. package/.agents/skills/quality-auto-test/SKILL.md +11 -1
  54. package/.agents/skills/quality-debug/SKILL.md +16 -2
  55. package/.agents/skills/quality-retrospective/SKILL.md +9 -1
  56. package/.agents/skills/quality-review/SKILL.md +8 -0
  57. package/.agents/skills/quality-sync/SKILL.md +2 -2
  58. package/.agents/skills/quality-test/SKILL.md +9 -1
  59. package/.agents/skills/security-audit/SKILL.md +14 -4
  60. package/.agents/skills/spec-add/SKILL.md +5 -2
  61. package/.agents/skills/spec-load/SKILL.md +1 -1
  62. package/.agents/skills/spec-remove/SKILL.md +1 -1
  63. package/.agents/skills/spec-setup/SKILL.md +3 -0
  64. package/.agy/skills/domain-add/SKILL.md +3 -0
  65. package/.agy/skills/learn-decompose/SKILL.md +7 -4
  66. package/.agy/skills/learn-follow/SKILL.md +4 -2
  67. package/.agy/skills/learn-investigate/SKILL.md +8 -6
  68. package/.agy/skills/learn-second-opinion/SKILL.md +6 -3
  69. package/.agy/skills/maestro/SKILL.md +1 -1
  70. package/.agy/skills/maestro-amend/SKILL.md +1 -1
  71. package/.agy/skills/maestro-analyze/SKILL.md +1 -1
  72. package/.agy/skills/maestro-blueprint/SKILL.md +1 -1
  73. package/.agy/skills/maestro-brainstorm/SKILL.md +4 -1
  74. package/.agy/skills/maestro-collab/SKILL.md +6 -2
  75. package/.agy/skills/maestro-companion/SKILL.md +4 -1
  76. package/.agy/skills/maestro-composer/SKILL.md +4 -2
  77. package/.agy/skills/maestro-execute/SKILL.md +26 -8
  78. package/.agy/skills/maestro-fork/SKILL.md +4 -3
  79. package/.agy/skills/maestro-grill/SKILL.md +1 -1
  80. package/.agy/skills/maestro-guard/SKILL.md +2 -2
  81. package/.agy/skills/maestro-impeccable/SKILL.md +2 -1
  82. package/.agy/skills/maestro-init/SKILL.md +1 -1
  83. package/.agy/skills/maestro-merge/SKILL.md +12 -1
  84. package/.agy/skills/maestro-milestone-audit/SKILL.md +1 -0
  85. package/.agy/skills/maestro-milestone-complete/SKILL.md +8 -3
  86. package/.agy/skills/maestro-milestone-release/SKILL.md +8 -4
  87. package/.agy/skills/maestro-overlay/SKILL.md +9 -0
  88. package/.agy/skills/maestro-plan/SKILL.md +1 -0
  89. package/.agy/skills/maestro-player/SKILL.md +2 -2
  90. package/.agy/skills/maestro-quick/SKILL.md +5 -3
  91. package/.agy/skills/maestro-ralph/SKILL.md +8 -8
  92. package/.agy/skills/maestro-ralph-agent/SKILL.md +696 -0
  93. package/.agy/skills/maestro-ralph-agent-execute/SKILL.md +457 -0
  94. package/.agy/skills/maestro-ralph-cli/SKILL.md +661 -0
  95. package/.agy/skills/maestro-ralph-cli-execute/SKILL.md +235 -0
  96. package/.agy/skills/maestro-ralph-execute/SKILL.md +127 -11
  97. package/.agy/skills/maestro-roadmap/SKILL.md +1 -1
  98. package/.agy/skills/maestro-swarm-workflow/SKILL.md +16 -14
  99. package/.agy/skills/maestro-tools-register/SKILL.md +16 -1
  100. package/.agy/skills/maestro-ui-codify/SKILL.md +11 -1
  101. package/.agy/skills/maestro-universal-workflow/SKILL.md +28 -5
  102. package/.agy/skills/maestro-update/SKILL.md +10 -7
  103. package/.agy/skills/manage-codebase-rebuild/SKILL.md +5 -1
  104. package/.agy/skills/manage-drift-realign/SKILL.md +6 -2
  105. package/.agy/skills/manage-harvest/SKILL.md +4 -1
  106. package/.agy/skills/manage-issue-discover/SKILL.md +1 -0
  107. package/.agy/skills/manage-kg-extractors/SKILL.md +5 -1
  108. package/.agy/skills/manage-knowhow-capture/SKILL.md +1 -0
  109. package/.agy/skills/manage-knowledge-audit/SKILL.md +3 -0
  110. package/.agy/skills/manage-wiki/SKILL.md +1 -0
  111. package/.agy/skills/odyssey-debug/SKILL.md +2 -1
  112. package/.agy/skills/odyssey-improve/SKILL.md +2 -2
  113. package/.agy/skills/odyssey-planex/SKILL.md +8 -7
  114. package/.agy/skills/odyssey-review-test-fix/SKILL.md +4 -1
  115. package/.agy/skills/odyssey-ui/SKILL.md +4 -4
  116. package/.agy/skills/quality-auto-test/SKILL.md +11 -1
  117. package/.agy/skills/quality-debug/SKILL.md +16 -2
  118. package/.agy/skills/quality-retrospective/SKILL.md +9 -1
  119. package/.agy/skills/quality-review/SKILL.md +8 -0
  120. package/.agy/skills/quality-sync/SKILL.md +2 -2
  121. package/.agy/skills/quality-test/SKILL.md +9 -1
  122. package/.agy/skills/security-audit/SKILL.md +14 -4
  123. package/.agy/skills/spec-add/SKILL.md +5 -2
  124. package/.agy/skills/spec-load/SKILL.md +1 -1
  125. package/.agy/skills/spec-remove/SKILL.md +1 -1
  126. package/.agy/skills/spec-setup/SKILL.md +3 -0
  127. package/.claude/commands/domain-add.md +3 -0
  128. package/.claude/commands/learn-decompose.md +7 -4
  129. package/.claude/commands/learn-follow.md +4 -2
  130. package/.claude/commands/learn-investigate.md +8 -6
  131. package/.claude/commands/learn-second-opinion.md +6 -3
  132. package/.claude/commands/maestro-amend.md +1 -1
  133. package/.claude/commands/maestro-analyze.md +1 -1
  134. package/.claude/commands/maestro-blueprint.md +1 -1
  135. package/.claude/commands/maestro-brainstorm.md +4 -1
  136. package/.claude/commands/maestro-collab.md +6 -2
  137. package/.claude/commands/maestro-companion.md +4 -1
  138. package/.claude/commands/maestro-composer.md +4 -2
  139. package/.claude/commands/maestro-execute.md +26 -8
  140. package/.claude/commands/maestro-fork.md +4 -3
  141. package/.claude/commands/maestro-grill.md +1 -1
  142. package/.claude/commands/maestro-guard.md +2 -2
  143. package/.claude/commands/maestro-impeccable.md +2 -1
  144. package/.claude/commands/maestro-init.md +1 -1
  145. package/.claude/commands/maestro-merge.md +12 -1
  146. package/.claude/commands/maestro-milestone-audit.md +1 -0
  147. package/.claude/commands/maestro-milestone-complete.md +8 -3
  148. package/.claude/commands/maestro-milestone-release.md +8 -4
  149. package/.claude/commands/maestro-overlay.md +9 -0
  150. package/.claude/commands/maestro-plan.md +1 -0
  151. package/.claude/commands/maestro-player.md +2 -2
  152. package/.claude/commands/maestro-quick.md +5 -3
  153. package/.claude/commands/maestro-ralph-agent-execute.md +459 -0
  154. package/.claude/commands/maestro-ralph-agent.md +695 -0
  155. package/.claude/commands/maestro-ralph-cli-execute.md +237 -0
  156. package/.claude/commands/maestro-ralph-cli.md +663 -0
  157. package/.claude/commands/maestro-ralph-execute.md +127 -11
  158. package/.claude/commands/maestro-ralph.md +8 -8
  159. package/.claude/commands/maestro-roadmap.md +1 -1
  160. package/.claude/commands/maestro-swarm-workflow.md +16 -14
  161. package/.claude/commands/maestro-tools-register.md +16 -1
  162. package/.claude/commands/maestro-ui-codify.md +11 -1
  163. package/.claude/commands/maestro-universal-workflow.md +28 -5
  164. package/.claude/commands/maestro-update.md +10 -7
  165. package/.claude/commands/maestro.md +1 -1
  166. package/.claude/commands/manage-codebase-rebuild.md +5 -1
  167. package/.claude/commands/manage-drift-realign.md +6 -2
  168. package/.claude/commands/manage-harvest.md +4 -1
  169. package/.claude/commands/manage-issue-discover.md +1 -0
  170. package/.claude/commands/manage-kg-extractors.md +5 -1
  171. package/.claude/commands/manage-knowhow-capture.md +1 -0
  172. package/.claude/commands/manage-knowledge-audit.md +3 -0
  173. package/.claude/commands/manage-wiki.md +1 -0
  174. package/.claude/commands/odyssey-debug.md +2 -1
  175. package/.claude/commands/odyssey-improve.md +2 -2
  176. package/.claude/commands/odyssey-planex.md +8 -7
  177. package/.claude/commands/odyssey-review-test-fix.md +4 -1
  178. package/.claude/commands/odyssey-ui.md +4 -4
  179. package/.claude/commands/quality-auto-test.md +11 -1
  180. package/.claude/commands/quality-debug.md +16 -2
  181. package/.claude/commands/quality-retrospective.md +9 -1
  182. package/.claude/commands/quality-review.md +8 -0
  183. package/.claude/commands/quality-sync.md +2 -2
  184. package/.claude/commands/quality-test.md +9 -1
  185. package/.claude/commands/security-audit.md +14 -4
  186. package/.claude/commands/spec-add.md +5 -2
  187. package/.claude/commands/spec-load.md +1 -1
  188. package/.claude/commands/spec-remove.md +1 -1
  189. package/.claude/commands/spec-setup.md +3 -0
  190. package/.codex/skills/codify-to-knowhow/SKILL.md +27 -15
  191. package/.codex/skills/domain-add/SKILL.md +5 -3
  192. package/.codex/skills/learn-decompose/SKILL.md +22 -4
  193. package/.codex/skills/learn-follow/SKILL.md +12 -6
  194. package/.codex/skills/learn-investigate/SKILL.md +11 -6
  195. package/.codex/skills/learn-retro/SKILL.md +12 -6
  196. package/.codex/skills/learn-second-opinion/SKILL.md +11 -3
  197. package/.codex/skills/maestro/SKILL.md +19 -13
  198. package/.codex/skills/maestro-amend/SKILL.md +10 -2
  199. package/.codex/skills/maestro-analyze/SKILL.md +7 -1
  200. package/.codex/skills/maestro-blueprint/SKILL.md +1 -1
  201. package/.codex/skills/maestro-brainstorm/SKILL.md +11 -8
  202. package/.codex/skills/maestro-collab/SKILL.md +5 -5
  203. package/.codex/skills/maestro-companion/SKILL.md +4 -1
  204. package/.codex/skills/maestro-composer/SKILL.md +6 -3
  205. package/.codex/skills/maestro-execute/SKILL.md +11 -8
  206. package/.codex/skills/maestro-fork/SKILL.md +4 -3
  207. package/.codex/skills/maestro-grill/SKILL.md +1 -1
  208. package/.codex/skills/maestro-guard/SKILL.md +1 -1
  209. package/.codex/skills/maestro-impeccable/SKILL.md +5 -5
  210. package/.codex/skills/maestro-init/SKILL.md +3 -2
  211. package/.codex/skills/maestro-milestone-audit/SKILL.md +21 -9
  212. package/.codex/skills/maestro-milestone-complete/SKILL.md +3 -3
  213. package/.codex/skills/maestro-milestone-release/SKILL.md +18 -1
  214. package/.codex/skills/maestro-next/SKILL.md +11 -10
  215. package/.codex/skills/maestro-overlay/SKILL.md +16 -6
  216. package/.codex/skills/maestro-player/SKILL.md +11 -5
  217. package/.codex/skills/maestro-quick/SKILL.md +2 -2
  218. package/.codex/skills/maestro-ralph/SKILL.md +44 -31
  219. package/.codex/skills/maestro-ralph-cli/SKILL.md +394 -0
  220. package/.codex/skills/maestro-ralph-cli-execute/SKILL.md +146 -0
  221. package/.codex/skills/maestro-ralph-execute/SKILL.md +105 -24
  222. package/.codex/skills/maestro-roadmap/SKILL.md +8 -2
  223. package/.codex/skills/maestro-tools-execute/SKILL.md +8 -4
  224. package/.codex/skills/maestro-tools-register/SKILL.md +10 -6
  225. package/.codex/skills/maestro-ui-codify/SKILL.md +14 -9
  226. package/.codex/skills/manage-codebase-rebuild/SKILL.md +36 -14
  227. package/.codex/skills/manage-codebase-refresh/SKILL.md +1 -1
  228. package/.codex/skills/manage-drift-realign/SKILL.md +15 -12
  229. package/.codex/skills/manage-harvest/SKILL.md +1 -1
  230. package/.codex/skills/manage-issue/SKILL.md +8 -4
  231. package/.codex/skills/manage-issue-discover/SKILL.md +15 -14
  232. package/.codex/skills/manage-knowhow/SKILL.md +3 -2
  233. package/.codex/skills/manage-knowhow-capture/SKILL.md +4 -3
  234. package/.codex/skills/manage-learn/SKILL.md +2 -2
  235. package/.codex/skills/odyssey-debug/SKILL.md +12 -7
  236. package/.codex/skills/odyssey-improve/SKILL.md +11 -6
  237. package/.codex/skills/odyssey-planex/SKILL.md +14 -8
  238. package/.codex/skills/odyssey-review-test-fix/SKILL.md +12 -7
  239. package/.codex/skills/odyssey-ui/SKILL.md +10 -5
  240. package/.codex/skills/quality-auto-test/SKILL.md +13 -5
  241. package/.codex/skills/quality-debug/SKILL.md +18 -11
  242. package/.codex/skills/quality-refactor/SKILL.md +4 -4
  243. package/.codex/skills/quality-retrospective/SKILL.md +5 -6
  244. package/.codex/skills/quality-review/SKILL.md +18 -11
  245. package/.codex/skills/quality-sync/SKILL.md +2 -2
  246. package/.codex/skills/quality-test/SKILL.md +7 -5
  247. package/.codex/skills/security-audit/SKILL.md +7 -5
  248. package/.codex/skills/spec-add/SKILL.md +9 -7
  249. package/.codex/skills/spec-load/SKILL.md +3 -2
  250. package/.codex/skills/spec-map/SKILL.md +10 -1
  251. package/.codex/skills/spec-remove/SKILL.md +3 -2
  252. package/.codex/skills/team-coordinate/SKILL.md +10 -4
  253. package/.codex/skills/team-lifecycle-v4/SKILL.md +33 -26
  254. package/.codex/skills/team-quality-assurance/SKILL.md +43 -0
  255. package/.codex/skills/team-review/SKILL.md +50 -6
  256. package/.codex/skills/team-tech-debt/SKILL.md +53 -7
  257. package/.codex/skills/team-testing/SKILL.md +50 -2
  258. package/.codex/skills/wiki-connect/SKILL.md +3 -1
  259. package/.codex/skills/wiki-digest/SKILL.md +6 -4
  260. package/dashboard/dist-server/dashboard/src/server/wiki/embedding.d.ts +16 -0
  261. package/dashboard/dist-server/dashboard/src/server/wiki/embedding.js +419 -44
  262. package/dashboard/dist-server/dashboard/src/server/wiki/embedding.js.map +1 -1
  263. package/dashboard/dist-server/dashboard/src/server/wiki/wiki-indexer.js +48 -10
  264. package/dashboard/dist-server/dashboard/src/server/wiki/wiki-indexer.js.map +1 -1
  265. package/dashboard/dist-server/src/graph/kg/credibility.d.ts +2 -2
  266. package/dashboard/dist-server/src/graph/kg/credibility.js +10 -5
  267. package/dashboard/dist-server/src/graph/kg/credibility.js.map +1 -1
  268. package/dashboard/dist-server/src/graph/kg/db/connection.d.ts +3 -2
  269. package/dashboard/dist-server/src/graph/kg/db/connection.js +28 -16
  270. package/dashboard/dist-server/src/graph/kg/db/connection.js.map +1 -1
  271. package/dashboard/dist-server/src/graph/kg/db/queries.js +4 -4
  272. package/dashboard/dist-server/src/graph/kg/db/queries.js.map +1 -1
  273. package/dashboard/dist-server/src/graph/kg/db/types.d.ts +3 -0
  274. package/dashboard/dist-server/src/graph/kg/embedding/code-embedding.d.ts +46 -0
  275. package/dashboard/dist-server/src/graph/kg/embedding/code-embedding.js +329 -0
  276. package/dashboard/dist-server/src/graph/kg/embedding/code-embedding.js.map +1 -0
  277. package/dashboard/dist-server/src/graph/kg/embedding/index.d.ts +2 -0
  278. package/dashboard/dist-server/src/graph/kg/embedding/index.js +3 -0
  279. package/dashboard/dist-server/src/graph/kg/embedding/index.js.map +1 -0
  280. package/dashboard/dist-server/src/graph/kg/engine.d.ts +20 -2
  281. package/dashboard/dist-server/src/graph/kg/engine.js +71 -1
  282. package/dashboard/dist-server/src/graph/kg/engine.js.map +1 -1
  283. package/dashboard/dist-server/src/graph/kg/extraction/knowledge/domain-extractor.d.ts +1 -1
  284. package/dashboard/dist-server/src/graph/kg/extraction/knowledge/domain-extractor.js +8 -4
  285. package/dashboard/dist-server/src/graph/kg/extraction/knowledge/domain-extractor.js.map +1 -1
  286. package/dashboard/dist-server/src/graph/kg/query/scoring.d.ts +5 -0
  287. package/dashboard/dist-server/src/graph/kg/query/scoring.js +85 -1
  288. package/dashboard/dist-server/src/graph/kg/query/scoring.js.map +1 -1
  289. package/dashboard/dist-server/src/graph/kg/query/search.d.ts +7 -0
  290. package/dashboard/dist-server/src/graph/kg/query/search.js +117 -1
  291. package/dashboard/dist-server/src/graph/kg/query/search.js.map +1 -1
  292. package/dashboard/dist-server/src/graph/kg/resolution/knowledge-resolver.d.ts +3 -3
  293. package/dashboard/dist-server/src/graph/kg/resolution/knowledge-resolver.js +3 -2
  294. package/dashboard/dist-server/src/graph/kg/resolution/knowledge-resolver.js.map +1 -1
  295. package/dashboard/dist-server/src/graph/kg/surface/hook-injector.js +2 -4
  296. package/dashboard/dist-server/src/graph/kg/surface/hook-injector.js.map +1 -1
  297. package/dashboard/dist-server/src/graph/kg/surface/mcp-tools.js +49 -0
  298. package/dashboard/dist-server/src/graph/kg/surface/mcp-tools.js.map +1 -1
  299. package/dashboard/dist-server/src/hooks/kg-sync-hook.js +3 -0
  300. package/dashboard/dist-server/src/hooks/kg-sync-hook.js.map +1 -1
  301. package/dashboard/dist-server/src/search/daemon-client.d.ts +3 -25
  302. package/dashboard/dist-server/src/search/daemon-client.js +3 -25
  303. package/dashboard/dist-server/src/search/daemon-client.js.map +1 -1
  304. package/dashboard/dist-server/src/search/daemon-types.d.ts +29 -0
  305. package/dashboard/dist-server/src/search/daemon-types.js +31 -0
  306. package/dashboard/dist-server/src/search/daemon-types.js.map +1 -0
  307. package/dist/src/agents/api-explore/agent-loop.d.ts +1 -1
  308. package/dist/src/agents/api-explore/agent-loop.d.ts.map +1 -1
  309. package/dist/src/agents/api-explore/agent-loop.js +32 -17
  310. package/dist/src/agents/api-explore/agent-loop.js.map +1 -1
  311. package/dist/src/agents/api-explore/prompt-parser.js +5 -5
  312. package/dist/src/agents/api-explore/prompt-parser.js.map +1 -1
  313. package/dist/src/agents/api-explore/runner.d.ts.map +1 -1
  314. package/dist/src/agents/api-explore/runner.js +0 -2
  315. package/dist/src/agents/api-explore/runner.js.map +1 -1
  316. package/dist/src/agents/api-explore/system-prompt.d.ts.map +1 -1
  317. package/dist/src/agents/api-explore/system-prompt.js +30 -22
  318. package/dist/src/agents/api-explore/system-prompt.js.map +1 -1
  319. package/dist/src/agents/api-explore/tools.d.ts +1 -0
  320. package/dist/src/agents/api-explore/tools.d.ts.map +1 -1
  321. package/dist/src/agents/api-explore/tools.js +219 -50
  322. package/dist/src/agents/api-explore/tools.js.map +1 -1
  323. package/dist/src/commands/search.d.ts.map +1 -1
  324. package/dist/src/commands/search.js +10 -4
  325. package/dist/src/commands/search.js.map +1 -1
  326. package/dist/src/commands/update.d.ts.map +1 -1
  327. package/dist/src/commands/update.js +89 -21
  328. package/dist/src/commands/update.js.map +1 -1
  329. package/dist/src/core/plugin-bridge.d.ts.map +1 -1
  330. package/dist/src/core/plugin-bridge.js +17 -0
  331. package/dist/src/core/plugin-bridge.js.map +1 -1
  332. package/dist/src/graph/db/connection.d.ts +3 -2
  333. package/dist/src/graph/db/connection.d.ts.map +1 -1
  334. package/dist/src/graph/db/connection.js +28 -16
  335. package/dist/src/graph/db/connection.js.map +1 -1
  336. package/dist/src/graph/db/queries.d.ts.map +1 -1
  337. package/dist/src/graph/db/queries.js.map +1 -1
  338. package/dist/src/graph/kg/credibility.d.ts +2 -2
  339. package/dist/src/graph/kg/credibility.d.ts.map +1 -1
  340. package/dist/src/graph/kg/credibility.js +10 -5
  341. package/dist/src/graph/kg/credibility.js.map +1 -1
  342. package/dist/src/graph/kg/db/connection.d.ts +3 -2
  343. package/dist/src/graph/kg/db/connection.d.ts.map +1 -1
  344. package/dist/src/graph/kg/db/connection.js +28 -16
  345. package/dist/src/graph/kg/db/connection.js.map +1 -1
  346. package/dist/src/graph/kg/db/queries.js +4 -4
  347. package/dist/src/graph/kg/db/queries.js.map +1 -1
  348. package/dist/src/graph/kg/db/types.d.ts +3 -0
  349. package/dist/src/graph/kg/db/types.d.ts.map +1 -1
  350. package/dist/src/graph/kg/embedding/code-embedding.d.ts +47 -0
  351. package/dist/src/graph/kg/embedding/code-embedding.d.ts.map +1 -0
  352. package/dist/src/graph/kg/embedding/code-embedding.js +329 -0
  353. package/dist/src/graph/kg/embedding/code-embedding.js.map +1 -0
  354. package/dist/src/graph/kg/embedding/index.d.ts +3 -0
  355. package/dist/src/graph/kg/embedding/index.d.ts.map +1 -0
  356. package/dist/src/graph/kg/embedding/index.js +3 -0
  357. package/dist/src/graph/kg/embedding/index.js.map +1 -0
  358. package/dist/src/graph/kg/engine.d.ts +20 -2
  359. package/dist/src/graph/kg/engine.d.ts.map +1 -1
  360. package/dist/src/graph/kg/engine.js +71 -1
  361. package/dist/src/graph/kg/engine.js.map +1 -1
  362. package/dist/src/graph/kg/extraction/knowledge/domain-extractor.d.ts +1 -1
  363. package/dist/src/graph/kg/extraction/knowledge/domain-extractor.d.ts.map +1 -1
  364. package/dist/src/graph/kg/extraction/knowledge/domain-extractor.js +8 -4
  365. package/dist/src/graph/kg/extraction/knowledge/domain-extractor.js.map +1 -1
  366. package/dist/src/graph/kg/query/scoring.d.ts +5 -0
  367. package/dist/src/graph/kg/query/scoring.d.ts.map +1 -1
  368. package/dist/src/graph/kg/query/scoring.js +85 -1
  369. package/dist/src/graph/kg/query/scoring.js.map +1 -1
  370. package/dist/src/graph/kg/query/search.d.ts +7 -0
  371. package/dist/src/graph/kg/query/search.d.ts.map +1 -1
  372. package/dist/src/graph/kg/query/search.js +117 -1
  373. package/dist/src/graph/kg/query/search.js.map +1 -1
  374. package/dist/src/graph/kg/resolution/knowledge-resolver.d.ts +3 -3
  375. package/dist/src/graph/kg/resolution/knowledge-resolver.d.ts.map +1 -1
  376. package/dist/src/graph/kg/resolution/knowledge-resolver.js +3 -2
  377. package/dist/src/graph/kg/resolution/knowledge-resolver.js.map +1 -1
  378. package/dist/src/graph/kg/surface/hook-injector.d.ts.map +1 -1
  379. package/dist/src/graph/kg/surface/hook-injector.js +2 -4
  380. package/dist/src/graph/kg/surface/hook-injector.js.map +1 -1
  381. package/dist/src/graph/kg/surface/mcp-tools.d.ts.map +1 -1
  382. package/dist/src/graph/kg/surface/mcp-tools.js +49 -0
  383. package/dist/src/graph/kg/surface/mcp-tools.js.map +1 -1
  384. package/dist/src/hooks/kg-sync-hook.d.ts.map +1 -1
  385. package/dist/src/hooks/kg-sync-hook.js +3 -0
  386. package/dist/src/hooks/kg-sync-hook.js.map +1 -1
  387. package/dist/src/search/daemon-client.d.ts +3 -25
  388. package/dist/src/search/daemon-client.d.ts.map +1 -1
  389. package/dist/src/search/daemon-client.js +3 -25
  390. package/dist/src/search/daemon-client.js.map +1 -1
  391. package/dist/src/search/daemon-types.d.ts +30 -0
  392. package/dist/src/search/daemon-types.d.ts.map +1 -0
  393. package/dist/src/search/daemon-types.js +31 -0
  394. package/dist/src/search/daemon-types.js.map +1 -0
  395. package/dist/src/search/daemon.d.ts +2 -27
  396. package/dist/src/search/daemon.d.ts.map +1 -1
  397. package/dist/src/search/daemon.js +4 -60
  398. package/dist/src/search/daemon.js.map +1 -1
  399. package/dist/src/tools/code-semantic-search.d.ts +10 -0
  400. package/dist/src/tools/code-semantic-search.d.ts.map +1 -0
  401. package/dist/src/tools/code-semantic-search.js +81 -0
  402. package/dist/src/tools/code-semantic-search.js.map +1 -0
  403. package/dist/src/tools/index.d.ts.map +1 -1
  404. package/dist/src/tools/index.js +4 -0
  405. package/dist/src/tools/index.js.map +1 -1
  406. package/dist/src/tools/wiki-search.d.ts +13 -0
  407. package/dist/src/tools/wiki-search.d.ts.map +1 -0
  408. package/dist/src/tools/wiki-search.js +120 -0
  409. package/dist/src/tools/wiki-search.js.map +1 -0
  410. package/dist/src/utils/update-notices.js +24 -0
  411. package/dist/src/utils/update-notices.js.map +1 -1
  412. package/package.json +4 -3
@@ -11,6 +11,19 @@ import { join } from 'node:path';
11
11
  import { homedir } from 'node:os';
12
12
  import { createHash } from 'node:crypto';
13
13
  import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync, renameSync } from 'node:fs';
14
+ let _zvecModule;
15
+ async function getZvec() {
16
+ if (_zvecModule !== undefined)
17
+ return _zvecModule;
18
+ try {
19
+ _zvecModule = await import('@zvec/zvec');
20
+ return _zvecModule;
21
+ }
22
+ catch {
23
+ _zvecModule = null;
24
+ return null;
25
+ }
26
+ }
14
27
  const API_CONFIG_PATH = join(homedir(), '.maestro', 'api-embedding.json');
15
28
  let _apiConfig;
16
29
  export function loadEmbeddingApiConfig() {
@@ -265,17 +278,18 @@ export async function detectDevice() {
265
278
  return _detectedConfig;
266
279
  const backends = await listBackends();
267
280
  const hasGpu = backends.some(b => b.name === 'dml' || b.name === 'cuda');
268
- // For small models (all-MiniLM-L6-v2, 22M params), CPU is consistently faster
269
- // due to CPU↔GPU data transfer overhead exceeding compute savings.
270
- // GPU only wins for models >100M params or batch sizes >500.
281
+ const envDevice = process.env.MAESTRO_EMBEDDING_DEVICE;
282
+ const envBatch = process.env.MAESTRO_EMBEDDING_BATCH_SIZE;
283
+ const useGpu = envDevice === 'cpu' ? false : hasGpu;
271
284
  _detectedConfig = {
272
- device: 'cpu',
273
- dtype: 'fp32',
274
- batchSize: 32,
285
+ device: useGpu ? 'gpu' : 'cpu',
286
+ dtype: useGpu ? 'fp16' : 'fp32',
287
+ batchSize: useGpu ? 128 : (hasGpu ? 64 : 32),
275
288
  };
276
- if (hasGpu) {
277
- // Store GPU availability for future large-model support
278
- _detectedConfig.batchSize = 64;
289
+ if (envBatch) {
290
+ const parsed = parseInt(envBatch, 10);
291
+ if (parsed > 0)
292
+ _detectedConfig.batchSize = parsed;
279
293
  }
280
294
  return _detectedConfig;
281
295
  }
@@ -290,13 +304,21 @@ export async function getHardwareInfo() {
290
304
  const backends = await listBackends();
291
305
  const hasGpu = backends.some(b => b.name === 'dml' || b.name === 'cuda');
292
306
  const config = await detectDevice();
307
+ let reason;
308
+ if (!hasGpu) {
309
+ reason = 'CPU only — no GPU backend detected';
310
+ }
311
+ else if (config.device === 'gpu') {
312
+ reason = 'GPU auto-selected (DML/CUDA detected) — set MAESTRO_EMBEDDING_DEVICE=cpu to force CPU';
313
+ }
314
+ else {
315
+ reason = 'GPU available but CPU forced via MAESTRO_EMBEDDING_DEVICE=cpu';
316
+ }
293
317
  return {
294
318
  backends,
295
319
  gpuAvailable: hasGpu,
296
320
  selectedDevice: config,
297
- reason: hasGpu
298
- ? 'GPU available (DML/CUDA) but CPU selected — small model (22M params) runs faster on CPU due to transfer overhead'
299
- : 'CPU only — no GPU backend detected',
321
+ reason,
300
322
  };
301
323
  }
302
324
  // ---------------------------------------------------------------------------
@@ -405,9 +427,55 @@ export async function embedQuery(query) {
405
427
  return new Float32Array(output.data);
406
428
  }
407
429
  // ---------------------------------------------------------------------------
408
- // Vector search (flat cosine no index structure needed for <10K docs)
430
+ // Vector search — zvec backend (default) with flat cosine fallback
409
431
  // ---------------------------------------------------------------------------
432
+ const ZVEC_DIR = 'embedding.zvec';
410
433
  export function vectorSearch(queryVector, index, limit) {
434
+ // Feature flag: force flat cosine scan (bypass zvec)
435
+ if (process.env.MAESTRO_EMBEDDING_FLAT_SCAN) {
436
+ return flatCosineSearch(queryVector, index, limit);
437
+ }
438
+ // Sync path — zvec requires async setup, so use flat scan here.
439
+ // For zvec-accelerated search, callers should use vectorSearchZvec.
440
+ return flatCosineSearch(queryVector, index, limit);
441
+ }
442
+ /**
443
+ * Async vector search using zvec collection.
444
+ * Falls back to flat cosine scan when zvec is unavailable or feature flag is set.
445
+ */
446
+ export async function vectorSearchZvec(queryVector, dir, limit) {
447
+ if (process.env.MAESTRO_EMBEDDING_FLAT_SCAN) {
448
+ return []; // caller handles fallback via sync vectorSearch
449
+ }
450
+ const zvec = await getZvec();
451
+ if (!zvec)
452
+ return []; // zvec not installed, caller handles fallback
453
+ const collectionPath = join(dir, ZVEC_DIR);
454
+ if (!existsSync(collectionPath))
455
+ return []; // no zvec collection yet
456
+ try {
457
+ const collection = zvec.ZVecOpen(collectionPath, { readOnly: true });
458
+ try {
459
+ const docs = collection.querySync({
460
+ fieldName: 'embedding',
461
+ vector: queryVector,
462
+ topk: limit,
463
+ outputFields: ['docId'],
464
+ });
465
+ return docs.map(d => ({
466
+ docId: d.fields.docId ?? d.id,
467
+ score: 1 - d.score,
468
+ }));
469
+ }
470
+ finally {
471
+ collection.closeSync();
472
+ }
473
+ }
474
+ catch {
475
+ return []; // zvec query failed, caller handles fallback
476
+ }
477
+ }
478
+ function flatCosineSearch(queryVector, index, limit) {
411
479
  const scored = [];
412
480
  for (let i = 0; i < index.docIds.length; i++) {
413
481
  const sim = cosineSimilarity(queryVector, index.vectors[i]);
@@ -418,7 +486,7 @@ export function vectorSearch(queryVector, index, limit) {
418
486
  return scored.slice(0, limit);
419
487
  }
420
488
  // ---------------------------------------------------------------------------
421
- // Persistence — SQLite binary BLOB (primary) with JSON fallback for migration
489
+ // Persistence — zvec collection (primary) + binary fallback + legacy migration
422
490
  // ---------------------------------------------------------------------------
423
491
  const SQLITE_FILE = 'embedding-index.db';
424
492
  import { createRequire } from 'node:module';
@@ -426,6 +494,7 @@ const _require = createRequire(import.meta.url);
426
494
  const BINARY_FILE = 'embedding-index.bin';
427
495
  export function saveEmbeddingIndex(index, dir) {
428
496
  mkdirSync(dir, { recursive: true });
497
+ // --- Binary format (kept for backward compat and feature flag fallback) ---
429
498
  const dim = index.dimension;
430
499
  const n = index.docIds.length;
431
500
  const docIdsJson = JSON.stringify(index.docIds);
@@ -438,6 +507,7 @@ export function saveEmbeddingIndex(index, dir) {
438
507
  deviceUsed: index.deviceUsed,
439
508
  buildTimeMs: index.buildTimeMs,
440
509
  contentHashes: index.contentHashes,
510
+ chunkDocIds: index.chunkDocIds,
441
511
  });
442
512
  const metaBytes = Buffer.from(metaJson, 'utf-8');
443
513
  // Format: [metaLen:4][meta][docIdsLen:4][docIds][packedVectors:n*dim*4]
@@ -462,6 +532,10 @@ export function saveEmbeddingIndex(index, dir) {
462
532
  const tmpPath = join(dir, BINARY_FILE + '.tmp');
463
533
  writeFileSync(tmpPath, buf);
464
534
  renameSync(tmpPath, join(dir, BINARY_FILE));
535
+ // --- zvec collection save (async, best-effort) ---
536
+ saveZvecIndex(index, dir).catch(() => {
537
+ // zvec save failed — binary format still available as fallback
538
+ });
465
539
  // Remove legacy files
466
540
  for (const f of [CACHE_FILE, SQLITE_FILE, SQLITE_FILE + '-shm', SQLITE_FILE + '-wal', SQLITE_FILE + '-journal']) {
467
541
  try {
@@ -471,8 +545,95 @@ export function saveEmbeddingIndex(index, dir) {
471
545
  catch { /* ignore */ }
472
546
  }
473
547
  }
548
+ /**
549
+ * Save embedding index to zvec collection format.
550
+ * Creates/replaces a zvec collection at `dir/embedding.zvec`.
551
+ */
552
+ async function saveZvecIndex(index, dir) {
553
+ const zvec = await getZvec();
554
+ if (!zvec)
555
+ return;
556
+ const collectionPath = join(dir, ZVEC_DIR);
557
+ const dim = index.dimension;
558
+ // Remove existing collection directory if present
559
+ if (existsSync(collectionPath)) {
560
+ try {
561
+ const existing = zvec.ZVecOpen(collectionPath);
562
+ existing.destroySync();
563
+ }
564
+ catch {
565
+ // If we can't open it, try to remove the directory manually
566
+ try {
567
+ const { rmSync } = await import('node:fs');
568
+ rmSync(collectionPath, { recursive: true, force: true });
569
+ }
570
+ catch { /* ignore */ }
571
+ }
572
+ }
573
+ const schema = new zvec.ZVecCollectionSchema({
574
+ name: 'embedding',
575
+ vectors: {
576
+ name: 'embedding',
577
+ dataType: zvec.ZVecDataType.VECTOR_FP32,
578
+ dimension: dim,
579
+ indexParams: {
580
+ indexType: zvec.ZVecIndexType.FLAT,
581
+ metricType: zvec.ZVecMetricType.COSINE,
582
+ },
583
+ },
584
+ fields: [
585
+ { name: 'docId', dataType: zvec.ZVecDataType.STRING },
586
+ ],
587
+ });
588
+ const collection = zvec.ZVecCreateAndOpen(collectionPath, schema);
589
+ try {
590
+ // Batch upsert all vectors
591
+ const BATCH_SIZE = 500;
592
+ for (let i = 0; i < index.docIds.length; i += BATCH_SIZE) {
593
+ const batch = [];
594
+ const end = Math.min(i + BATCH_SIZE, index.docIds.length);
595
+ for (let j = i; j < end; j++) {
596
+ batch.push({
597
+ id: index.docIds[j],
598
+ vectors: { embedding: index.vectors[j] },
599
+ fields: { docId: index.docIds[j] },
600
+ });
601
+ }
602
+ collection.upsertSync(batch);
603
+ }
604
+ // Save metadata as JSON sidecar (zvec doesn't store arbitrary metadata)
605
+ const metaSidecar = {
606
+ modelId: index.modelId,
607
+ dimension: dim,
608
+ builtAt: index.builtAt,
609
+ deviceUsed: index.deviceUsed,
610
+ buildTimeMs: index.buildTimeMs,
611
+ contentHashes: index.contentHashes,
612
+ chunkDocIds: index.chunkDocIds,
613
+ docIds: index.docIds,
614
+ };
615
+ writeFileSync(join(dir, ZVEC_DIR + '.meta.json'), JSON.stringify(metaSidecar));
616
+ }
617
+ finally {
618
+ collection.closeSync();
619
+ }
620
+ }
474
621
  export function loadEmbeddingIndex(dir) {
475
- // Primary: packed binary
622
+ // Primary: zvec collection + metadata sidecar
623
+ const zvecMetaPath = join(dir, ZVEC_DIR + '.meta.json');
624
+ const zvecCollPath = join(dir, ZVEC_DIR);
625
+ if (existsSync(zvecMetaPath) && existsSync(zvecCollPath)) {
626
+ try {
627
+ return loadFromZvecMeta(zvecMetaPath, zvecCollPath);
628
+ }
629
+ catch (e) {
630
+ if (process.env.DEBUG || process.env.MAESTRO_DEBUG) {
631
+ console.warn(`[embedding] zvec index load failed, falling back: ${e instanceof Error ? e.message : e}`);
632
+ }
633
+ // Fall through to binary
634
+ }
635
+ }
636
+ // Fallback: packed binary
476
637
  const binPath = join(dir, BINARY_FILE);
477
638
  if (existsSync(binPath)) {
478
639
  try {
@@ -509,6 +670,62 @@ export function loadEmbeddingIndex(dir) {
509
670
  }
510
671
  return null;
511
672
  }
673
+ /**
674
+ * Load EmbeddingIndex from zvec metadata sidecar.
675
+ * The sidecar stores everything needed to reconstruct the in-memory index;
676
+ * the actual zvec collection is used for vectorSearchZvec queries.
677
+ */
678
+ function loadFromZvecMeta(metaPath, _collectionPath) {
679
+ const meta = JSON.parse(readFileSync(metaPath, 'utf-8'));
680
+ // Use cached zvec module if available, otherwise try sync require
681
+ let zvec = _zvecModule ?? null;
682
+ if (!zvec) {
683
+ try {
684
+ zvec = _require('@zvec/zvec');
685
+ _zvecModule = zvec;
686
+ }
687
+ catch {
688
+ throw new Error('zvec not available for loading collection');
689
+ }
690
+ }
691
+ const collection = zvec.ZVecOpen(_collectionPath, { readOnly: true });
692
+ try {
693
+ const vectors = new Array(meta.docIds.length);
694
+ // Fetch vectors in batches by ID
695
+ const BATCH_SIZE = 500;
696
+ for (let i = 0; i < meta.docIds.length; i += BATCH_SIZE) {
697
+ const batchIds = meta.docIds.slice(i, Math.min(i + BATCH_SIZE, meta.docIds.length));
698
+ const fetched = collection.fetchSync({ ids: batchIds, includeVector: true, outputFields: [] });
699
+ const fetchedMap = Array.isArray(fetched)
700
+ ? Object.fromEntries(fetched.map((d) => [d.id, d]))
701
+ : fetched;
702
+ for (let j = 0; j < batchIds.length; j++) {
703
+ const doc = fetchedMap[batchIds[j]];
704
+ if (doc?.vectors?.embedding) {
705
+ const v = doc.vectors.embedding;
706
+ vectors[i + j] = v instanceof Float32Array ? v : new Float32Array(v);
707
+ }
708
+ else {
709
+ vectors[i + j] = new Float32Array(meta.dimension);
710
+ }
711
+ }
712
+ }
713
+ return {
714
+ modelId: meta.modelId,
715
+ dimension: meta.dimension,
716
+ docIds: meta.docIds,
717
+ vectors,
718
+ contentHashes: meta.contentHashes,
719
+ chunkDocIds: meta.chunkDocIds,
720
+ builtAt: meta.builtAt,
721
+ deviceUsed: meta.deviceUsed,
722
+ buildTimeMs: meta.buildTimeMs,
723
+ };
724
+ }
725
+ finally {
726
+ collection.closeSync();
727
+ }
728
+ }
512
729
  function loadFromBinary(filePath) {
513
730
  const raw = readFileSync(filePath);
514
731
  let offset = 0;
@@ -543,6 +760,7 @@ function loadFromBinary(filePath) {
543
760
  docIds,
544
761
  vectors,
545
762
  contentHashes: meta.contentHashes,
763
+ chunkDocIds: meta.chunkDocIds,
546
764
  builtAt: meta.builtAt,
547
765
  deviceUsed: meta.deviceUsed,
548
766
  buildTimeMs: meta.buildTimeMs,
@@ -590,68 +808,225 @@ function loadFromLegacyJson(filePath) {
590
808
  };
591
809
  }
592
810
  export function hashDocContent(d) {
593
- const text = [d.title, d.summary, d.tags.join(','), d.body?.slice(0, 500) ?? ''].join('|');
811
+ const text = [d.title, d.summary, d.tags.join(','), d.body ?? ''].join('|');
594
812
  return createHash('md5').update(text).digest('hex');
595
813
  }
814
+ /**
815
+ * Extract meaningful content from a markdown body: first paragraph + heading lines,
816
+ * up to `maxLen` characters.
817
+ */
818
+ function extractMeaningfulContent(body, maxLen) {
819
+ const lines = body.split('\n');
820
+ const parts = [];
821
+ let len = 0;
822
+ let firstParaDone = false;
823
+ for (const line of lines) {
824
+ if (len >= maxLen)
825
+ break;
826
+ const trimmed = line.trim();
827
+ // Always include heading lines
828
+ if (/^#{1,3}\s/.test(trimmed)) {
829
+ parts.push(trimmed);
830
+ len += trimmed.length + 1;
831
+ continue;
832
+ }
833
+ // Include non-empty lines until we hit the first blank line (first paragraph)
834
+ if (!firstParaDone) {
835
+ if (trimmed === '') {
836
+ if (parts.length > 0)
837
+ firstParaDone = true;
838
+ continue;
839
+ }
840
+ parts.push(trimmed);
841
+ len += trimmed.length + 1;
842
+ }
843
+ }
844
+ const result = parts.join('\n');
845
+ return result.length > maxLen ? result.slice(0, maxLen) : result;
846
+ }
596
847
  function docToText(d) {
597
- const parts = [d.title];
848
+ const parts = [`title: ${d.title}`];
598
849
  if (d.summary)
599
- parts.push(d.summary);
850
+ parts.push(`summary: ${d.summary}`);
600
851
  if (d.tags.length > 0)
601
- parts.push(d.tags.join(' '));
602
- if (d.body)
603
- parts.push(d.body.slice(0, 500));
604
- const text = parts.join('. ');
852
+ parts.push(`tags: ${d.tags.join(', ')}`);
853
+ if (d.body) {
854
+ const body = d.body.length > 500 ? extractMeaningfulContent(d.body, 450) : d.body;
855
+ parts.push(`content: ${body}`);
856
+ }
857
+ parts.push(`title: ${d.title}`);
858
+ const text = parts.join('\n');
605
859
  return isApiMode() ? text : 'passage: ' + text;
606
860
  }
861
+ /**
862
+ * Split a document into multiple chunks for embedding.
863
+ * Short docs (<500 chars body) produce a single chunk.
864
+ * Long docs are split by markdown heading regex /^#{1,3}\s/m, max 5 chunks.
865
+ * Each chunk inherits title+summary as context prefix.
866
+ */
867
+ export function splitDocToChunks(d) {
868
+ const contextPrefix = [`title: ${d.title}`];
869
+ if (d.summary)
870
+ contextPrefix.push(`summary: ${d.summary}`);
871
+ if (d.tags.length > 0)
872
+ contextPrefix.push(`tags: ${d.tags.join(', ')}`);
873
+ const prefix = contextPrefix.join('\n');
874
+ // Short or empty body — single chunk using docToText
875
+ if (!d.body || d.body.length < 500) {
876
+ return [{ chunkId: `${d.id}#0`, text: docToText(d) }];
877
+ }
878
+ // Split body by markdown headings
879
+ const sections = d.body.split(/^(?=#{1,3}\s)/m).filter(s => s.trim().length > 0);
880
+ // If splitting produced only one section, single chunk
881
+ if (sections.length <= 1) {
882
+ return [{ chunkId: `${d.id}#0`, text: docToText(d) }];
883
+ }
884
+ // Cap at 5 chunks
885
+ const capped = sections.slice(0, 5);
886
+ const apiMode = isApiMode();
887
+ return capped.map((section, i) => {
888
+ const parts = [prefix, `content: ${section.trim()}`, `title: ${d.title}`];
889
+ const text = parts.join('\n');
890
+ return {
891
+ chunkId: `${d.id}#${i}`,
892
+ text: apiMode ? text : 'passage: ' + text,
893
+ };
894
+ });
895
+ }
607
896
  export async function buildEmbeddingIndex(docs, existingIndex, precomputedHashes) {
608
897
  const apiMode = isApiMode();
609
898
  const config = apiMode ? null : await detectDevice();
610
899
  const t0 = Date.now();
611
900
  const currentHashes = precomputedHashes ?? docs.map(hashDocContent);
901
+ // Split all docs into chunks (1:N doc-to-chunk mapping)
902
+ const allChunkIds = [];
903
+ const allChunkDocIds = [];
904
+ const allChunkTexts = [];
905
+ // Track which doc index each chunk group belongs to (for incremental rebuild)
906
+ const docChunkRanges = [];
907
+ for (let i = 0; i < docs.length; i++) {
908
+ const chunks = splitDocToChunks(docs[i]);
909
+ const startSlot = allChunkIds.length;
910
+ for (const chunk of chunks) {
911
+ allChunkIds.push(chunk.chunkId);
912
+ allChunkDocIds.push(docs[i].id);
913
+ allChunkTexts.push(chunk.text);
914
+ }
915
+ docChunkRanges.push({ docIndex: i, startSlot, count: chunks.length });
916
+ }
612
917
  let vectors;
613
918
  const activeModel = getModelId();
614
919
  // Model changed → discard all cached vectors, force full rebuild
615
920
  const modelMatch = existingIndex && existingIndex.modelId === activeModel;
616
921
  if (modelMatch && existingIndex.docIds.length > 0) {
617
- // Incremental: reuse vectors only for docs with matching content hash
618
- const existingMap = new Map();
619
- for (let i = 0; i < existingIndex.docIds.length; i++) {
620
- existingMap.set(existingIndex.docIds[i], {
621
- vector: existingIndex.vectors[i],
622
- hash: existingIndex.contentHashes?.[i] ?? '',
623
- });
922
+ // Build existing chunk cache: chunkId { vector, parentDocId }
923
+ const existingChunkMap = new Map();
924
+ const existingDocHashes = new Map();
925
+ // Reconstruct per-doc hashes from existing index
926
+ if (existingIndex.chunkDocIds && existingIndex.contentHashes) {
927
+ for (let i = 0; i < existingIndex.docIds.length; i++) {
928
+ existingChunkMap.set(existingIndex.docIds[i], existingIndex.vectors[i]);
929
+ }
930
+ // contentHashes are per-doc; find unique doc→hash mapping
931
+ const seen = new Set();
932
+ for (let i = 0; i < existingIndex.chunkDocIds.length; i++) {
933
+ const parentId = existingIndex.chunkDocIds[i];
934
+ if (!seen.has(parentId) && existingIndex.contentHashes[i] !== undefined) {
935
+ // contentHashes in chunk-based index: stored per-doc in the order of docChunkRanges
936
+ seen.add(parentId);
937
+ }
938
+ }
939
+ }
940
+ else {
941
+ // Legacy index without chunkDocIds — docIds are direct doc IDs
942
+ for (let i = 0; i < existingIndex.docIds.length; i++) {
943
+ existingChunkMap.set(existingIndex.docIds[i], existingIndex.vectors[i]);
944
+ if (existingIndex.contentHashes?.[i]) {
945
+ existingDocHashes.set(existingIndex.docIds[i], existingIndex.contentHashes[i]);
946
+ }
947
+ }
624
948
  }
625
- const changedDocs = [];
626
- vectors = new Array(docs.length);
627
- for (let i = 0; i < docs.length; i++) {
628
- const cached = existingMap.get(docs[i].id);
629
- if (cached && cached.hash && cached.hash === currentHashes[i]) {
630
- vectors[i] = cached.vector;
949
+ // Determine which docs changed (hash comparison at doc level)
950
+ // Rebuild per-doc hash from existing contentHashes
951
+ const existingPerDocHash = new Map();
952
+ if (existingIndex.contentHashes) {
953
+ if (existingIndex.chunkDocIds) {
954
+ // Chunk-based: contentHashes[i] corresponds to the doc that produced chunk i
955
+ // Each doc's hash is stored on its first chunk
956
+ const docSeen = new Set();
957
+ for (let i = 0; i < existingIndex.chunkDocIds.length; i++) {
958
+ const pid = existingIndex.chunkDocIds[i];
959
+ if (!docSeen.has(pid)) {
960
+ docSeen.add(pid);
961
+ existingPerDocHash.set(pid, existingIndex.contentHashes[i] ?? '');
962
+ }
963
+ }
631
964
  }
632
965
  else {
633
- changedDocs.push({ index: i, doc: docs[i] });
966
+ // Legacy: docIds are 1:1 with docs
967
+ for (let i = 0; i < existingIndex.docIds.length; i++) {
968
+ existingPerDocHash.set(existingIndex.docIds[i], existingIndex.contentHashes[i] ?? '');
969
+ }
634
970
  }
635
971
  }
636
- if (changedDocs.length > 0) {
637
- const texts = changedDocs.map(nd => docToText(nd.doc));
972
+ vectors = new Array(allChunkIds.length);
973
+ const chunksToEmbed = [];
974
+ for (const range of docChunkRanges) {
975
+ const docId = docs[range.docIndex].id;
976
+ const cachedHash = existingPerDocHash.get(docId);
977
+ const currentHash = currentHashes[range.docIndex];
978
+ if (cachedHash && cachedHash === currentHash) {
979
+ // Doc unchanged — try to reuse cached chunk vectors
980
+ let allReused = true;
981
+ for (let s = range.startSlot; s < range.startSlot + range.count; s++) {
982
+ const cachedVec = existingChunkMap.get(allChunkIds[s]);
983
+ if (cachedVec) {
984
+ vectors[s] = cachedVec;
985
+ }
986
+ else {
987
+ allReused = false;
988
+ break;
989
+ }
990
+ }
991
+ if (!allReused) {
992
+ // Chunk structure changed (e.g., headings added/removed) — re-embed all chunks
993
+ for (let s = range.startSlot; s < range.startSlot + range.count; s++) {
994
+ chunksToEmbed.push({ slot: s, text: allChunkTexts[s] });
995
+ }
996
+ }
997
+ }
998
+ else {
999
+ // Doc changed — re-embed all its chunks
1000
+ for (let s = range.startSlot; s < range.startSlot + range.count; s++) {
1001
+ chunksToEmbed.push({ slot: s, text: allChunkTexts[s] });
1002
+ }
1003
+ }
1004
+ }
1005
+ if (chunksToEmbed.length > 0) {
1006
+ const texts = chunksToEmbed.map(c => c.text);
638
1007
  const newVectors = await embedTexts(texts);
639
- for (let j = 0; j < changedDocs.length; j++) {
640
- vectors[changedDocs[j].index] = newVectors[j];
1008
+ for (let j = 0; j < chunksToEmbed.length; j++) {
1009
+ vectors[chunksToEmbed[j].slot] = newVectors[j];
641
1010
  }
642
1011
  }
643
1012
  }
644
1013
  else {
645
1014
  // Full rebuild
646
- const texts = docs.map(docToText);
647
- vectors = await embedTexts(texts);
1015
+ vectors = await embedTexts(allChunkTexts);
1016
+ }
1017
+ // Build per-chunk contentHashes (each chunk gets its parent doc's hash)
1018
+ const parentToHash = new Map();
1019
+ for (const range of docChunkRanges) {
1020
+ parentToHash.set(docs[range.docIndex].id, currentHashes[range.docIndex]);
648
1021
  }
1022
+ const chunkContentHashes = allChunkDocIds.map(parentId => parentToHash.get(parentId) ?? '');
649
1023
  return {
650
1024
  modelId: activeModel,
651
1025
  dimension: vectors[0]?.length ?? 384,
652
- docIds: docs.map(d => d.id),
1026
+ docIds: allChunkIds,
653
1027
  vectors,
654
- contentHashes: currentHashes,
1028
+ contentHashes: chunkContentHashes,
1029
+ chunkDocIds: allChunkDocIds,
655
1030
  builtAt: Date.now(),
656
1031
  deviceUsed: apiMode ? 'api' : `${config.device}/${config.dtype}`,
657
1032
  buildTimeMs: Date.now() - t0,