@jafreck/lore 0.1.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 (239) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +405 -0
  3. package/dist/cli.d.ts +19 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +345 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/index.d.ts +22 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +16 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/indexer/call-graph.d.ts +39 -0
  12. package/dist/indexer/call-graph.d.ts.map +1 -0
  13. package/dist/indexer/call-graph.js +193 -0
  14. package/dist/indexer/call-graph.js.map +1 -0
  15. package/dist/indexer/complexity.d.ts +9 -0
  16. package/dist/indexer/complexity.d.ts.map +1 -0
  17. package/dist/indexer/complexity.js +66 -0
  18. package/dist/indexer/complexity.js.map +1 -0
  19. package/dist/indexer/config-parser.d.ts +16 -0
  20. package/dist/indexer/config-parser.d.ts.map +1 -0
  21. package/dist/indexer/config-parser.js +261 -0
  22. package/dist/indexer/config-parser.js.map +1 -0
  23. package/dist/indexer/coverage.d.ts +13 -0
  24. package/dist/indexer/coverage.d.ts.map +1 -0
  25. package/dist/indexer/coverage.js +84 -0
  26. package/dist/indexer/coverage.js.map +1 -0
  27. package/dist/indexer/db.d.ts +38 -0
  28. package/dist/indexer/db.d.ts.map +1 -0
  29. package/dist/indexer/db.js +275 -0
  30. package/dist/indexer/db.js.map +1 -0
  31. package/dist/indexer/embedder.d.ts +70 -0
  32. package/dist/indexer/embedder.d.ts.map +1 -0
  33. package/dist/indexer/embedder.js +186 -0
  34. package/dist/indexer/embedder.js.map +1 -0
  35. package/dist/indexer/ensure-python-deps.d.ts +22 -0
  36. package/dist/indexer/ensure-python-deps.d.ts.map +1 -0
  37. package/dist/indexer/ensure-python-deps.js +47 -0
  38. package/dist/indexer/ensure-python-deps.js.map +1 -0
  39. package/dist/indexer/extractors/bash.d.ts +12 -0
  40. package/dist/indexer/extractors/bash.d.ts.map +1 -0
  41. package/dist/indexer/extractors/bash.js +57 -0
  42. package/dist/indexer/extractors/bash.js.map +1 -0
  43. package/dist/indexer/extractors/c.d.ts +12 -0
  44. package/dist/indexer/extractors/c.d.ts.map +1 -0
  45. package/dist/indexer/extractors/c.js +106 -0
  46. package/dist/indexer/extractors/c.js.map +1 -0
  47. package/dist/indexer/extractors/cpp.d.ts +12 -0
  48. package/dist/indexer/extractors/cpp.d.ts.map +1 -0
  49. package/dist/indexer/extractors/cpp.js +84 -0
  50. package/dist/indexer/extractors/cpp.js.map +1 -0
  51. package/dist/indexer/extractors/csharp.d.ts +12 -0
  52. package/dist/indexer/extractors/csharp.d.ts.map +1 -0
  53. package/dist/indexer/extractors/csharp.js +79 -0
  54. package/dist/indexer/extractors/csharp.js.map +1 -0
  55. package/dist/indexer/extractors/dart.d.ts +12 -0
  56. package/dist/indexer/extractors/dart.d.ts.map +1 -0
  57. package/dist/indexer/extractors/dart.js +80 -0
  58. package/dist/indexer/extractors/dart.js.map +1 -0
  59. package/dist/indexer/extractors/elixir.d.ts +12 -0
  60. package/dist/indexer/extractors/elixir.d.ts.map +1 -0
  61. package/dist/indexer/extractors/elixir.js +87 -0
  62. package/dist/indexer/extractors/elixir.js.map +1 -0
  63. package/dist/indexer/extractors/elm.d.ts +12 -0
  64. package/dist/indexer/extractors/elm.d.ts.map +1 -0
  65. package/dist/indexer/extractors/elm.js +87 -0
  66. package/dist/indexer/extractors/elm.js.map +1 -0
  67. package/dist/indexer/extractors/go.d.ts +12 -0
  68. package/dist/indexer/extractors/go.d.ts.map +1 -0
  69. package/dist/indexer/extractors/go.js +158 -0
  70. package/dist/indexer/extractors/go.js.map +1 -0
  71. package/dist/indexer/extractors/haskell.d.ts +12 -0
  72. package/dist/indexer/extractors/haskell.d.ts.map +1 -0
  73. package/dist/indexer/extractors/haskell.js +104 -0
  74. package/dist/indexer/extractors/haskell.js.map +1 -0
  75. package/dist/indexer/extractors/java.d.ts +12 -0
  76. package/dist/indexer/extractors/java.d.ts.map +1 -0
  77. package/dist/indexer/extractors/java.js +68 -0
  78. package/dist/indexer/extractors/java.js.map +1 -0
  79. package/dist/indexer/extractors/javascript.d.ts +13 -0
  80. package/dist/indexer/extractors/javascript.d.ts.map +1 -0
  81. package/dist/indexer/extractors/javascript.js +180 -0
  82. package/dist/indexer/extractors/javascript.js.map +1 -0
  83. package/dist/indexer/extractors/julia.d.ts +12 -0
  84. package/dist/indexer/extractors/julia.d.ts.map +1 -0
  85. package/dist/indexer/extractors/julia.js +94 -0
  86. package/dist/indexer/extractors/julia.js.map +1 -0
  87. package/dist/indexer/extractors/kotlin.d.ts +12 -0
  88. package/dist/indexer/extractors/kotlin.d.ts.map +1 -0
  89. package/dist/indexer/extractors/kotlin.js +71 -0
  90. package/dist/indexer/extractors/kotlin.js.map +1 -0
  91. package/dist/indexer/extractors/lua.d.ts +12 -0
  92. package/dist/indexer/extractors/lua.d.ts.map +1 -0
  93. package/dist/indexer/extractors/lua.js +68 -0
  94. package/dist/indexer/extractors/lua.js.map +1 -0
  95. package/dist/indexer/extractors/objc.d.ts +12 -0
  96. package/dist/indexer/extractors/objc.d.ts.map +1 -0
  97. package/dist/indexer/extractors/objc.js +129 -0
  98. package/dist/indexer/extractors/objc.js.map +1 -0
  99. package/dist/indexer/extractors/ocaml.d.ts +12 -0
  100. package/dist/indexer/extractors/ocaml.d.ts.map +1 -0
  101. package/dist/indexer/extractors/ocaml.js +92 -0
  102. package/dist/indexer/extractors/ocaml.js.map +1 -0
  103. package/dist/indexer/extractors/php.d.ts +12 -0
  104. package/dist/indexer/extractors/php.d.ts.map +1 -0
  105. package/dist/indexer/extractors/php.js +99 -0
  106. package/dist/indexer/extractors/php.js.map +1 -0
  107. package/dist/indexer/extractors/python.d.ts +12 -0
  108. package/dist/indexer/extractors/python.d.ts.map +1 -0
  109. package/dist/indexer/extractors/python.js +129 -0
  110. package/dist/indexer/extractors/python.js.map +1 -0
  111. package/dist/indexer/extractors/ruby.d.ts +12 -0
  112. package/dist/indexer/extractors/ruby.d.ts.map +1 -0
  113. package/dist/indexer/extractors/ruby.js +100 -0
  114. package/dist/indexer/extractors/ruby.js.map +1 -0
  115. package/dist/indexer/extractors/rust.d.ts +12 -0
  116. package/dist/indexer/extractors/rust.d.ts.map +1 -0
  117. package/dist/indexer/extractors/rust.js +82 -0
  118. package/dist/indexer/extractors/rust.js.map +1 -0
  119. package/dist/indexer/extractors/scala.d.ts +12 -0
  120. package/dist/indexer/extractors/scala.d.ts.map +1 -0
  121. package/dist/indexer/extractors/scala.js +91 -0
  122. package/dist/indexer/extractors/scala.js.map +1 -0
  123. package/dist/indexer/extractors/swift.d.ts +12 -0
  124. package/dist/indexer/extractors/swift.d.ts.map +1 -0
  125. package/dist/indexer/extractors/swift.js +90 -0
  126. package/dist/indexer/extractors/swift.js.map +1 -0
  127. package/dist/indexer/extractors/types.d.ts +118 -0
  128. package/dist/indexer/extractors/types.d.ts.map +1 -0
  129. package/dist/indexer/extractors/types.js +43 -0
  130. package/dist/indexer/extractors/types.js.map +1 -0
  131. package/dist/indexer/extractors/typescript.d.ts +14 -0
  132. package/dist/indexer/extractors/typescript.d.ts.map +1 -0
  133. package/dist/indexer/extractors/typescript.js +172 -0
  134. package/dist/indexer/extractors/typescript.js.map +1 -0
  135. package/dist/indexer/extractors/zig.d.ts +12 -0
  136. package/dist/indexer/extractors/zig.d.ts.map +1 -0
  137. package/dist/indexer/extractors/zig.js +95 -0
  138. package/dist/indexer/extractors/zig.js.map +1 -0
  139. package/dist/indexer/git-history.d.ts +23 -0
  140. package/dist/indexer/git-history.d.ts.map +1 -0
  141. package/dist/indexer/git-history.js +144 -0
  142. package/dist/indexer/git-history.js.map +1 -0
  143. package/dist/indexer/git-hooks.d.ts +19 -0
  144. package/dist/indexer/git-hooks.d.ts.map +1 -0
  145. package/dist/indexer/git-hooks.js +74 -0
  146. package/dist/indexer/git-hooks.js.map +1 -0
  147. package/dist/indexer/index.d.ts +83 -0
  148. package/dist/indexer/index.d.ts.map +1 -0
  149. package/dist/indexer/index.js +431 -0
  150. package/dist/indexer/index.js.map +1 -0
  151. package/dist/indexer/parser.d.ts +30 -0
  152. package/dist/indexer/parser.d.ts.map +1 -0
  153. package/dist/indexer/parser.js +114 -0
  154. package/dist/indexer/parser.js.map +1 -0
  155. package/dist/indexer/poller.d.ts +50 -0
  156. package/dist/indexer/poller.d.ts.map +1 -0
  157. package/dist/indexer/poller.js +140 -0
  158. package/dist/indexer/poller.js.map +1 -0
  159. package/dist/indexer/resolver.d.ts +52 -0
  160. package/dist/indexer/resolver.d.ts.map +1 -0
  161. package/dist/indexer/resolver.js +271 -0
  162. package/dist/indexer/resolver.js.map +1 -0
  163. package/dist/indexer/test-mapper.d.ts +6 -0
  164. package/dist/indexer/test-mapper.d.ts.map +1 -0
  165. package/dist/indexer/test-mapper.js +48 -0
  166. package/dist/indexer/test-mapper.js.map +1 -0
  167. package/dist/indexer/walker.d.ts +51 -0
  168. package/dist/indexer/walker.d.ts.map +1 -0
  169. package/dist/indexer/walker.js +100 -0
  170. package/dist/indexer/walker.js.map +1 -0
  171. package/dist/indexer/watcher.d.ts +51 -0
  172. package/dist/indexer/watcher.d.ts.map +1 -0
  173. package/dist/indexer/watcher.js +107 -0
  174. package/dist/indexer/watcher.js.map +1 -0
  175. package/dist/kb-server/db.d.ts +241 -0
  176. package/dist/kb-server/db.d.ts.map +1 -0
  177. package/dist/kb-server/db.js +659 -0
  178. package/dist/kb-server/db.js.map +1 -0
  179. package/dist/kb-server/server.d.ts +35 -0
  180. package/dist/kb-server/server.d.ts.map +1 -0
  181. package/dist/kb-server/server.js +240 -0
  182. package/dist/kb-server/server.js.map +1 -0
  183. package/dist/kb-server/tools/annotations.d.ts +40 -0
  184. package/dist/kb-server/tools/annotations.d.ts.map +1 -0
  185. package/dist/kb-server/tools/annotations.js +35 -0
  186. package/dist/kb-server/tools/annotations.js.map +1 -0
  187. package/dist/kb-server/tools/architecture.d.ts +60 -0
  188. package/dist/kb-server/tools/architecture.d.ts.map +1 -0
  189. package/dist/kb-server/tools/architecture.js +174 -0
  190. package/dist/kb-server/tools/architecture.js.map +1 -0
  191. package/dist/kb-server/tools/blame.d.ts +67 -0
  192. package/dist/kb-server/tools/blame.d.ts.map +1 -0
  193. package/dist/kb-server/tools/blame.js +162 -0
  194. package/dist/kb-server/tools/blame.js.map +1 -0
  195. package/dist/kb-server/tools/coverage.d.ts +67 -0
  196. package/dist/kb-server/tools/coverage.d.ts.map +1 -0
  197. package/dist/kb-server/tools/coverage.js +74 -0
  198. package/dist/kb-server/tools/coverage.js.map +1 -0
  199. package/dist/kb-server/tools/graph.d.ts +56 -0
  200. package/dist/kb-server/tools/graph.d.ts.map +1 -0
  201. package/dist/kb-server/tools/graph.js +188 -0
  202. package/dist/kb-server/tools/graph.js.map +1 -0
  203. package/dist/kb-server/tools/history.d.ts +47 -0
  204. package/dist/kb-server/tools/history.d.ts.map +1 -0
  205. package/dist/kb-server/tools/history.js +91 -0
  206. package/dist/kb-server/tools/history.js.map +1 -0
  207. package/dist/kb-server/tools/lookup.d.ts +36 -0
  208. package/dist/kb-server/tools/lookup.d.ts.map +1 -0
  209. package/dist/kb-server/tools/lookup.js +45 -0
  210. package/dist/kb-server/tools/lookup.js.map +1 -0
  211. package/dist/kb-server/tools/metrics.d.ts +73 -0
  212. package/dist/kb-server/tools/metrics.d.ts.map +1 -0
  213. package/dist/kb-server/tools/metrics.js +79 -0
  214. package/dist/kb-server/tools/metrics.js.map +1 -0
  215. package/dist/kb-server/tools/notes.d.ts +165 -0
  216. package/dist/kb-server/tools/notes.d.ts.map +1 -0
  217. package/dist/kb-server/tools/notes.js +175 -0
  218. package/dist/kb-server/tools/notes.js.map +1 -0
  219. package/dist/kb-server/tools/routes.d.ts +38 -0
  220. package/dist/kb-server/tools/routes.d.ts.map +1 -0
  221. package/dist/kb-server/tools/routes.js +38 -0
  222. package/dist/kb-server/tools/routes.js.map +1 -0
  223. package/dist/kb-server/tools/search.d.ts +60 -0
  224. package/dist/kb-server/tools/search.d.ts.map +1 -0
  225. package/dist/kb-server/tools/search.js +170 -0
  226. package/dist/kb-server/tools/search.js.map +1 -0
  227. package/dist/kb-server/tools/snippet.d.ts +44 -0
  228. package/dist/kb-server/tools/snippet.d.ts.map +1 -0
  229. package/dist/kb-server/tools/snippet.js +49 -0
  230. package/dist/kb-server/tools/snippet.js.map +1 -0
  231. package/dist/kb-server/tools/test-map.d.ts +38 -0
  232. package/dist/kb-server/tools/test-map.d.ts.map +1 -0
  233. package/dist/kb-server/tools/test-map.js +32 -0
  234. package/dist/kb-server/tools/test-map.js.map +1 -0
  235. package/dist/kb-server/tools/writeback.d.ts +49 -0
  236. package/dist/kb-server/tools/writeback.d.ts.map +1 -0
  237. package/dist/kb-server/tools/writeback.js +68 -0
  238. package/dist/kb-server/tools/writeback.js.map +1 -0
  239. package/package.json +92 -0
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @module kb-server/tools/blame
3
+ *
4
+ * MCP tool: line-level git blame for indexed files.
5
+ */
6
+ import type { Database } from '../db.js';
7
+ export declare const toolDef: {
8
+ readonly name: "kb_blame";
9
+ readonly description: string;
10
+ readonly inputSchema: {
11
+ readonly type: "object";
12
+ readonly properties: {
13
+ readonly path: {
14
+ readonly type: "string";
15
+ readonly description: "Absolute file path as stored in the knowledge-base index.";
16
+ };
17
+ readonly line: {
18
+ readonly type: "number";
19
+ readonly description: "Single line number to blame (1-based).";
20
+ };
21
+ readonly start_line: {
22
+ readonly type: "number";
23
+ readonly description: "Range start line (1-based, inclusive).";
24
+ };
25
+ readonly end_line: {
26
+ readonly type: "number";
27
+ readonly description: "Range end line (1-based, inclusive). Defaults to start_line.";
28
+ };
29
+ readonly ref: {
30
+ readonly type: "string";
31
+ readonly description: "Git ref to blame against (default: HEAD).";
32
+ };
33
+ readonly branch: {
34
+ readonly type: "string";
35
+ readonly description: "Optional indexed branch to disambiguate file lookup.";
36
+ };
37
+ };
38
+ readonly required: readonly ["path"];
39
+ };
40
+ };
41
+ export interface BlameArgs {
42
+ path: string;
43
+ line?: number;
44
+ start_line?: number;
45
+ end_line?: number;
46
+ ref?: string;
47
+ branch?: string;
48
+ }
49
+ export interface BlameLine {
50
+ line: number;
51
+ commit_sha: string;
52
+ author: string;
53
+ author_email: string;
54
+ timestamp: number;
55
+ summary: string;
56
+ text: string;
57
+ }
58
+ export interface BlameResult {
59
+ path: string;
60
+ ref: string;
61
+ start_line: number;
62
+ end_line: number;
63
+ lines: BlameLine[];
64
+ }
65
+ /** Resolve repository root and execute `git blame --line-porcelain` for the requested range. */
66
+ export declare function handler(db: Database.Database, args: BlameArgs): BlameResult;
67
+ //# sourceMappingURL=blame.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blame.d.ts","sourceRoot":"","sources":["../../../src/kb-server/tools/blame.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKzC,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCV,CAAC;AAIX,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AA2FD,gGAAgG;AAChG,wBAAgB,OAAO,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,GAAG,WAAW,CAsD3E"}
@@ -0,0 +1,162 @@
1
+ /**
2
+ * @module kb-server/tools/blame
3
+ *
4
+ * MCP tool: line-level git blame for indexed files.
5
+ */
6
+ import { execFileSync } from 'node:child_process';
7
+ import { dirname, relative } from 'node:path';
8
+ import { getFileByPath } from '../db.js';
9
+ // ─── Tool definition ──────────────────────────────────────────────────────────
10
+ export const toolDef = {
11
+ name: 'kb_blame',
12
+ description: 'Return git blame metadata for a file and line (or line range). ' +
13
+ 'The file path must exist in the indexed knowledge base.',
14
+ inputSchema: {
15
+ type: 'object',
16
+ properties: {
17
+ path: {
18
+ type: 'string',
19
+ description: 'Absolute file path as stored in the knowledge-base index.',
20
+ },
21
+ line: {
22
+ type: 'number',
23
+ description: 'Single line number to blame (1-based).',
24
+ },
25
+ start_line: {
26
+ type: 'number',
27
+ description: 'Range start line (1-based, inclusive).',
28
+ },
29
+ end_line: {
30
+ type: 'number',
31
+ description: 'Range end line (1-based, inclusive). Defaults to start_line.',
32
+ },
33
+ ref: {
34
+ type: 'string',
35
+ description: 'Git ref to blame against (default: HEAD).',
36
+ },
37
+ branch: {
38
+ type: 'string',
39
+ description: 'Optional indexed branch to disambiguate file lookup.',
40
+ },
41
+ },
42
+ required: ['path'],
43
+ },
44
+ };
45
+ function resolveRange(args) {
46
+ if (args.line != null) {
47
+ const line = Math.max(1, Math.floor(args.line));
48
+ return { start: line, end: line };
49
+ }
50
+ if (args.start_line != null || args.end_line != null) {
51
+ const start = Math.max(1, Math.floor(args.start_line ?? args.end_line ?? 1));
52
+ const end = Math.max(start, Math.floor(args.end_line ?? start));
53
+ return { start, end };
54
+ }
55
+ throw new Error('Provide either `line` or `start_line`/`end_line`.');
56
+ }
57
+ function parseBlamePorcelain(output) {
58
+ const lines = output.split('\n');
59
+ const results = [];
60
+ const metaBySha = new Map();
61
+ let currentSha = '';
62
+ let currentFinalLine = 0;
63
+ let remainingSourceLines = 0;
64
+ for (const rawLine of lines) {
65
+ const headerMatch = rawLine.match(/^([^\s]+)\s+\d+\s+(\d+)\s+(\d+)$/);
66
+ if (headerMatch) {
67
+ currentSha = headerMatch[1] ?? '';
68
+ currentFinalLine = parseInt(headerMatch[2] ?? '0', 10);
69
+ remainingSourceLines = parseInt(headerMatch[3] ?? '0', 10);
70
+ if (!metaBySha.has(currentSha))
71
+ metaBySha.set(currentSha, {});
72
+ continue;
73
+ }
74
+ if (!currentSha)
75
+ continue;
76
+ const meta = metaBySha.get(currentSha) ?? {};
77
+ if (rawLine.startsWith('author ')) {
78
+ meta.author = rawLine.slice('author '.length);
79
+ metaBySha.set(currentSha, meta);
80
+ continue;
81
+ }
82
+ if (rawLine.startsWith('author-mail ')) {
83
+ meta.author_email = rawLine.slice('author-mail '.length).replace(/^<|>$/g, '');
84
+ metaBySha.set(currentSha, meta);
85
+ continue;
86
+ }
87
+ if (rawLine.startsWith('author-time ')) {
88
+ const ts = parseInt(rawLine.slice('author-time '.length), 10);
89
+ if (Number.isFinite(ts))
90
+ meta.timestamp = ts;
91
+ metaBySha.set(currentSha, meta);
92
+ continue;
93
+ }
94
+ if (rawLine.startsWith('summary ')) {
95
+ meta.summary = rawLine.slice('summary '.length);
96
+ metaBySha.set(currentSha, meta);
97
+ continue;
98
+ }
99
+ if (rawLine.startsWith('\t') && remainingSourceLines > 0) {
100
+ results.push({
101
+ line: currentFinalLine,
102
+ commit_sha: currentSha,
103
+ author: meta.author ?? 'unknown',
104
+ author_email: meta.author_email ?? '',
105
+ timestamp: meta.timestamp ?? 0,
106
+ summary: meta.summary ?? '',
107
+ text: rawLine.slice(1),
108
+ });
109
+ currentFinalLine += 1;
110
+ remainingSourceLines -= 1;
111
+ }
112
+ }
113
+ return results;
114
+ }
115
+ /** Resolve repository root and execute `git blame --line-porcelain` for the requested range. */
116
+ export function handler(db, args) {
117
+ const fileRow = getFileByPath(db, args.path, args.branch);
118
+ if (!fileRow) {
119
+ throw new Error(`File not found in index: ${args.path}`);
120
+ }
121
+ const { start, end } = resolveRange(args);
122
+ const ref = args.ref?.trim() || 'HEAD';
123
+ let repoRoot = '';
124
+ try {
125
+ repoRoot = execFileSync('git', ['-C', dirname(args.path), 'rev-parse', '--show-toplevel'], {
126
+ encoding: 'utf8',
127
+ }).trim();
128
+ }
129
+ catch {
130
+ throw new Error(`Unable to resolve git repository root for path: ${args.path}`);
131
+ }
132
+ const relPath = relative(repoRoot, args.path);
133
+ if (relPath.startsWith('..')) {
134
+ throw new Error(`Path is outside git repository root: ${args.path}`);
135
+ }
136
+ let output = '';
137
+ try {
138
+ output = execFileSync('git', [
139
+ '-C',
140
+ repoRoot,
141
+ 'blame',
142
+ '--line-porcelain',
143
+ '-L',
144
+ `${start},${end}`,
145
+ ref,
146
+ '--',
147
+ relPath,
148
+ ], { encoding: 'utf8' });
149
+ }
150
+ catch {
151
+ throw new Error(`git blame failed for ${args.path}:${start}-${end} at ref ${ref}.`);
152
+ }
153
+ const parsed = parseBlamePorcelain(output);
154
+ return {
155
+ path: args.path,
156
+ ref,
157
+ start_line: start,
158
+ end_line: end,
159
+ lines: parsed,
160
+ };
161
+ }
162
+ //# sourceMappingURL=blame.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blame.js","sourceRoot":"","sources":["../../../src/kb-server/tools/blame.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @module kb-server/tools/coverage
3
+ *
4
+ * MCP tool: query symbol-level coverage and coverage staleness metadata.
5
+ */
6
+ import type { Database } from '../db.js';
7
+ export declare const toolDef: {
8
+ readonly name: "kb_coverage";
9
+ readonly description: string;
10
+ readonly inputSchema: {
11
+ readonly type: "object";
12
+ readonly properties: {
13
+ readonly symbol_id: {
14
+ readonly type: "number";
15
+ readonly description: "Optional symbol id to fetch exact coverage for.";
16
+ };
17
+ readonly symbol_name: {
18
+ readonly type: "string";
19
+ readonly description: "Optional symbol name filter (case-insensitive).";
20
+ };
21
+ readonly path: {
22
+ readonly type: "string";
23
+ readonly description: "Optional file path filter.";
24
+ };
25
+ readonly branch: {
26
+ readonly type: "string";
27
+ readonly description: "Optional branch filter.";
28
+ };
29
+ readonly limit: {
30
+ readonly type: "number";
31
+ readonly description: "Maximum symbols to return (default 50).";
32
+ };
33
+ };
34
+ readonly required: readonly [];
35
+ };
36
+ };
37
+ export interface CoverageArgs {
38
+ symbol_id?: number;
39
+ symbol_name?: string;
40
+ path?: string;
41
+ branch?: string;
42
+ limit?: number;
43
+ }
44
+ export interface CoverageSymbolResult {
45
+ symbol_id: number;
46
+ symbol_name: string;
47
+ file_path: string;
48
+ start_line: number;
49
+ end_line: number;
50
+ total_lines: number;
51
+ covered_lines: number;
52
+ uncovered_lines: number[];
53
+ coverage_percent: number | null;
54
+ }
55
+ export interface CoverageResult {
56
+ coverage_available: boolean;
57
+ coverage_commit: string | null;
58
+ current_commit: string | null;
59
+ commits_behind: number;
60
+ stale: boolean;
61
+ global_lines_found: number | null;
62
+ global_lines_hit: number | null;
63
+ global_coverage_percent: number | null;
64
+ symbols: CoverageSymbolResult[];
65
+ }
66
+ export declare function handler(db: Database.Database, args: CoverageArgs): CoverageResult;
67
+ //# sourceMappingURL=coverage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../../src/kb-server/tools/coverage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AASzC,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BV,CAAC;AAEX,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,cAAc;IAC7B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,OAAO,EAAE,oBAAoB,EAAE,CAAC;CACjC;AAID,wBAAgB,OAAO,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,cAAc,CAoCjF"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @module kb-server/tools/coverage
3
+ *
4
+ * MCP tool: query symbol-level coverage and coverage staleness metadata.
5
+ */
6
+ import { getCoverageStaleness, getLatestCoverageRun, getLatestCoverageTotals, getSymbolCoverageAggregates, getSymbolsByName, } from '../db.js';
7
+ export const toolDef = {
8
+ name: 'kb_coverage',
9
+ description: 'Return symbol-level coverage percentages, uncovered lines, and staleness metadata ' +
10
+ 'for the latest ingested coverage run.',
11
+ inputSchema: {
12
+ type: 'object',
13
+ properties: {
14
+ symbol_id: {
15
+ type: 'number',
16
+ description: 'Optional symbol id to fetch exact coverage for.',
17
+ },
18
+ symbol_name: {
19
+ type: 'string',
20
+ description: 'Optional symbol name filter (case-insensitive).',
21
+ },
22
+ path: {
23
+ type: 'string',
24
+ description: 'Optional file path filter.',
25
+ },
26
+ branch: {
27
+ type: 'string',
28
+ description: 'Optional branch filter.',
29
+ },
30
+ limit: {
31
+ type: 'number',
32
+ description: 'Maximum symbols to return (default 50).',
33
+ },
34
+ },
35
+ required: [],
36
+ },
37
+ };
38
+ const DEFAULT_LIMIT = 50;
39
+ export function handler(db, args) {
40
+ const latestRun = getLatestCoverageRun(db);
41
+ const staleness = getCoverageStaleness(db);
42
+ const totals = getLatestCoverageTotals(db);
43
+ const limit = Math.max(1, Math.floor(args.limit ?? DEFAULT_LIMIT));
44
+ let symbolIds;
45
+ if (args.symbol_id !== undefined) {
46
+ symbolIds = [args.symbol_id];
47
+ }
48
+ else if (args.symbol_name !== undefined) {
49
+ symbolIds = getSymbolsByName(db, args.symbol_name, args.branch).map((symbol) => symbol.id);
50
+ if (symbolIds.length === 0) {
51
+ symbolIds = [-1];
52
+ }
53
+ }
54
+ const symbols = latestRun
55
+ ? getSymbolCoverageAggregates(db, {
56
+ symbolIds,
57
+ path: args.path,
58
+ branch: args.branch,
59
+ limit,
60
+ })
61
+ : [];
62
+ return {
63
+ coverage_available: latestRun !== undefined,
64
+ coverage_commit: staleness.coverage_commit,
65
+ current_commit: staleness.current_commit,
66
+ commits_behind: staleness.commits_behind,
67
+ stale: staleness.stale,
68
+ global_lines_found: totals?.lines_found ?? null,
69
+ global_lines_hit: totals?.lines_hit ?? null,
70
+ global_coverage_percent: totals?.coverage_percent ?? null,
71
+ symbols,
72
+ };
73
+ }
74
+ //# sourceMappingURL=coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../../src/kb-server/tools/coverage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACvB,2BAA2B,EAC3B,gBAAgB,GACjB,MAAM,UAAU,CAAC;AAElB,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,IAAI,EAAE,aAAa;IACnB,WAAW,EACT,oFAAoF;QACpF,uCAAuC;IACzC,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,SAAS,EAAE;gBACT,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,iDAAiD;aAC/D;YACD,WAAW,EAAE;gBACX,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,iDAAiD;aAC/D;YACD,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,4BAA4B;aAC1C;YACD,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,yBAAyB;aACvC;YACD,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,yCAAyC;aACvD;SACF;QACD,QAAQ,EAAE,EAAE;KACb;CACO,CAAC;AAkCX,MAAM,aAAa,GAAG,EAAE,CAAC;AAEzB,MAAM,UAAU,OAAO,CAAC,EAAqB,EAAE,IAAkB;IAC/D,MAAM,SAAS,GAAG,oBAAoB,CAAC,EAAE,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,oBAAoB,CAAC,EAAE,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,uBAAuB,CAAC,EAAE,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,aAAa,CAAC,CAAC,CAAC;IAEnE,IAAI,SAA+B,CAAC;IACpC,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACjC,SAAS,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC/B,CAAC;SAAM,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QAC1C,SAAS,GAAG,gBAAgB,CAAC,EAAE,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC3F,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,SAAS;QACvB,CAAC,CAAC,2BAA2B,CAAC,EAAE,EAAE;YAC9B,SAAS;YACT,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK;SACN,CAAC;QACJ,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;QACL,kBAAkB,EAAE,SAAS,KAAK,SAAS;QAC3C,eAAe,EAAE,SAAS,CAAC,eAAe;QAC1C,cAAc,EAAE,SAAS,CAAC,cAAc;QACxC,cAAc,EAAE,SAAS,CAAC,cAAc;QACxC,KAAK,EAAE,SAAS,CAAC,KAAK;QACtB,kBAAkB,EAAE,MAAM,EAAE,WAAW,IAAI,IAAI;QAC/C,gBAAgB,EAAE,MAAM,EAAE,SAAS,IAAI,IAAI;QAC3C,uBAAuB,EAAE,MAAM,EAAE,gBAAgB,IAAI,IAAI;QACzD,OAAO;KACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @module kb-server/tools/graph
3
+ *
4
+ * MCP tool: query the call graph and import graph.
5
+ *
6
+ * Both queries return adjacency lists so callers can build their own
7
+ * traversals without additional round-trips.
8
+ */
9
+ import type { Database } from '../db.js';
10
+ export declare const toolDef: {
11
+ readonly name: "kb_graph";
12
+ readonly description: string;
13
+ readonly inputSchema: {
14
+ readonly type: "object";
15
+ readonly properties: {
16
+ readonly kind: {
17
+ readonly type: "string";
18
+ readonly enum: readonly ["call", "import", "module", "inheritance"];
19
+ readonly description: string;
20
+ };
21
+ readonly source_id: {
22
+ readonly type: "number";
23
+ readonly description: "Optional. If provided, only edges whose source matches this id are returned.";
24
+ };
25
+ readonly limit: {
26
+ readonly type: "number";
27
+ readonly description: "Maximum number of edges to return (default 200).";
28
+ };
29
+ readonly branch: {
30
+ readonly type: "string";
31
+ readonly description: "Optional branch name to filter edges by source branch.";
32
+ };
33
+ };
34
+ readonly required: readonly ["kind"];
35
+ };
36
+ };
37
+ export interface GraphArgs {
38
+ kind: 'call' | 'import' | 'module' | 'inheritance';
39
+ source_id?: number;
40
+ limit?: number;
41
+ branch?: string;
42
+ }
43
+ export interface GraphEdge {
44
+ source_id: number;
45
+ source_name: string;
46
+ source_branch: string;
47
+ target_id: number | null;
48
+ target_name: string;
49
+ callee_coverage_percent?: number | null;
50
+ }
51
+ export interface GraphResult {
52
+ edges: GraphEdge[];
53
+ }
54
+ /** Return adjacency-list edges from the call graph or import graph. */
55
+ export declare function handler(db: Database.Database, args: GraphArgs): GraphResult;
56
+ //# sourceMappingURL=graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../../src/kb-server/tools/graph.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKzC,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCV,CAAC;AAIX,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,aAAa,CAAC;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAED,uEAAuE;AACvE,wBAAgB,OAAO,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,GAAG,WAAW,CA0J3E"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * @module kb-server/tools/graph
3
+ *
4
+ * MCP tool: query the call graph and import graph.
5
+ *
6
+ * Both queries return adjacency lists so callers can build their own
7
+ * traversals without additional round-trips.
8
+ */
9
+ import { getCoveragePercentBySymbolIds } from '../db.js';
10
+ // ─── Tool definition ──────────────────────────────────────────────────────────
11
+ export const toolDef = {
12
+ name: 'kb_graph',
13
+ description: 'Query call, import, module, or inheritance graph edges stored in the knowledge-base index. ' +
14
+ 'Set `kind` to "call", "import", "module", or "inheritance". ' +
15
+ 'Optionally filter by a source node id.',
16
+ inputSchema: {
17
+ type: 'object',
18
+ properties: {
19
+ kind: {
20
+ type: 'string',
21
+ enum: ['call', 'import', 'module', 'inheritance'],
22
+ description: '"call" returns symbol → callee edges; "import" returns file → imported-file edges; ' +
23
+ '"module" returns module → imported-module edges; "inheritance" returns symbol → base-symbol edges.',
24
+ },
25
+ source_id: {
26
+ type: 'number',
27
+ description: 'Optional. If provided, only edges whose source matches this id are returned.',
28
+ },
29
+ limit: {
30
+ type: 'number',
31
+ description: 'Maximum number of edges to return (default 200).',
32
+ },
33
+ branch: {
34
+ type: 'string',
35
+ description: 'Optional branch name to filter edges by source branch.',
36
+ },
37
+ },
38
+ required: ['kind'],
39
+ },
40
+ };
41
+ /** Return adjacency-list edges from the call graph or import graph. */
42
+ export function handler(db, args) {
43
+ const limit = args.limit ?? 200;
44
+ if (args.kind === 'call') {
45
+ // Symbol-level: symbol_refs rows
46
+ const hasFilter = args.source_id !== undefined;
47
+ const branchClause = args.branch !== undefined ? ' AND f_caller.branch = ?' : '';
48
+ const sql = hasFilter
49
+ ? `SELECT sr.caller_id AS source_id,
50
+ s_caller.name AS source_name,
51
+ f_caller.branch AS source_branch,
52
+ sr.callee_id AS target_id,
53
+ sr.callee_name AS target_name
54
+ FROM symbol_refs sr
55
+ JOIN symbols s_caller ON s_caller.id = sr.caller_id
56
+ JOIN files f_caller ON f_caller.id = s_caller.file_id
57
+ WHERE sr.caller_id = ?${branchClause}
58
+ LIMIT ?`
59
+ : `SELECT sr.caller_id AS source_id,
60
+ s_caller.name AS source_name,
61
+ f_caller.branch AS source_branch,
62
+ sr.callee_id AS target_id,
63
+ sr.callee_name AS target_name
64
+ FROM symbol_refs sr
65
+ JOIN symbols s_caller ON s_caller.id = sr.caller_id
66
+ JOIN files f_caller ON f_caller.id = s_caller.file_id
67
+ WHERE 1=1${branchClause}
68
+ LIMIT ?`;
69
+ const edgeParams = hasFilter
70
+ ? (args.branch !== undefined ? [args.source_id, args.branch, limit] : [args.source_id, limit])
71
+ : (args.branch !== undefined ? [args.branch, limit] : [limit]);
72
+ const edges = db.prepare(sql).all(...edgeParams);
73
+ const calleeIds = Array.from(new Set(edges.map((edge) => edge.target_id).filter((id) => id !== null)));
74
+ const coverageBySymbolId = getCoveragePercentBySymbolIds(db, calleeIds, args.branch);
75
+ const edgesWithCoverage = edges.map((edge) => ({
76
+ ...edge,
77
+ callee_coverage_percent: edge.target_id !== null ? (coverageBySymbolId.get(edge.target_id) ?? null) : null,
78
+ }));
79
+ return { edges: edgesWithCoverage };
80
+ }
81
+ else if (args.kind === 'import') {
82
+ // File-level: file_imports rows
83
+ const hasFilter = args.source_id !== undefined;
84
+ const branchClause = args.branch !== undefined ? ' AND f_src.branch = ?' : '';
85
+ const sql = hasFilter
86
+ ? `SELECT fi.file_id AS source_id,
87
+ f_src.path AS source_name,
88
+ f_src.branch AS source_branch,
89
+ fi.resolved_id AS target_id,
90
+ COALESCE(f_dst.path, fi.raw_import) AS target_name
91
+ FROM file_imports fi
92
+ JOIN files f_src ON f_src.id = fi.file_id
93
+ LEFT JOIN files f_dst ON f_dst.id = fi.resolved_id
94
+ WHERE fi.file_id = ?${branchClause}
95
+ LIMIT ?`
96
+ : `SELECT fi.file_id AS source_id,
97
+ f_src.path AS source_name,
98
+ f_src.branch AS source_branch,
99
+ fi.resolved_id AS target_id,
100
+ COALESCE(f_dst.path, fi.raw_import) AS target_name
101
+ FROM file_imports fi
102
+ JOIN files f_src ON f_src.id = fi.file_id
103
+ LEFT JOIN files f_dst ON f_dst.id = fi.resolved_id
104
+ WHERE 1=1${branchClause}
105
+ LIMIT ?`;
106
+ const edgeParams = hasFilter
107
+ ? (args.branch !== undefined ? [args.source_id, args.branch, limit] : [args.source_id, limit])
108
+ : (args.branch !== undefined ? [args.branch, limit] : [limit]);
109
+ const edges = db.prepare(sql).all(...edgeParams);
110
+ return { edges };
111
+ }
112
+ else if (args.kind === 'module') {
113
+ // Module-level: inferred from file_imports + file_modules
114
+ const hasFilter = args.source_id !== undefined;
115
+ const branchClause = args.branch !== undefined ? ' AND f_src.branch = ?' : '';
116
+ const sql = hasFilter
117
+ ? `SELECT DISTINCT
118
+ m_src.id AS source_id,
119
+ m_src.name AS source_name,
120
+ f_src.branch AS source_branch,
121
+ m_dst.id AS target_id,
122
+ COALESCE(m_dst.name, fi.raw_import) AS target_name
123
+ FROM file_imports fi
124
+ JOIN files f_src ON f_src.id = fi.file_id
125
+ JOIN file_modules fm_src ON fm_src.file_id = f_src.id
126
+ JOIN modules m_src ON m_src.id = fm_src.module_id
127
+ LEFT JOIN files f_dst ON f_dst.id = fi.resolved_id
128
+ LEFT JOIN file_modules fm_dst ON fm_dst.file_id = f_dst.id
129
+ LEFT JOIN modules m_dst ON m_dst.id = fm_dst.module_id
130
+ WHERE m_src.id = ?${branchClause}
131
+ LIMIT ?`
132
+ : `SELECT DISTINCT
133
+ m_src.id AS source_id,
134
+ m_src.name AS source_name,
135
+ f_src.branch AS source_branch,
136
+ m_dst.id AS target_id,
137
+ COALESCE(m_dst.name, fi.raw_import) AS target_name
138
+ FROM file_imports fi
139
+ JOIN files f_src ON f_src.id = fi.file_id
140
+ JOIN file_modules fm_src ON fm_src.file_id = f_src.id
141
+ JOIN modules m_src ON m_src.id = fm_src.module_id
142
+ LEFT JOIN files f_dst ON f_dst.id = fi.resolved_id
143
+ LEFT JOIN file_modules fm_dst ON fm_dst.file_id = f_dst.id
144
+ LEFT JOIN modules m_dst ON m_dst.id = fm_dst.module_id
145
+ WHERE 1=1${branchClause}
146
+ LIMIT ?`;
147
+ const edgeParams = hasFilter
148
+ ? (args.branch !== undefined ? [args.source_id, args.branch, limit] : [args.source_id, limit])
149
+ : (args.branch !== undefined ? [args.branch, limit] : [limit]);
150
+ const edges = db.prepare(sql).all(...edgeParams);
151
+ return { edges };
152
+ }
153
+ else {
154
+ // Symbol-level inheritance edges (e.g., class extends)
155
+ const hasFilter = args.source_id !== undefined;
156
+ const branchClause = args.branch !== undefined ? ' AND f_src.branch = ?' : '';
157
+ const sql = hasFilter
158
+ ? `SELECT rel.source_symbol_id AS source_id,
159
+ s_src.name AS source_name,
160
+ f_src.branch AS source_branch,
161
+ rel.target_symbol_id AS target_id,
162
+ COALESCE(s_dst.name, rel.target_symbol_name) AS target_name
163
+ FROM symbol_relationships rel
164
+ JOIN symbols s_src ON s_src.id = rel.source_symbol_id
165
+ JOIN files f_src ON f_src.id = s_src.file_id
166
+ LEFT JOIN symbols s_dst ON s_dst.id = rel.target_symbol_id
167
+ WHERE rel.relationship_type = 'extends'
168
+ AND rel.source_symbol_id = ?${branchClause}
169
+ LIMIT ?`
170
+ : `SELECT rel.source_symbol_id AS source_id,
171
+ s_src.name AS source_name,
172
+ f_src.branch AS source_branch,
173
+ rel.target_symbol_id AS target_id,
174
+ COALESCE(s_dst.name, rel.target_symbol_name) AS target_name
175
+ FROM symbol_relationships rel
176
+ JOIN symbols s_src ON s_src.id = rel.source_symbol_id
177
+ JOIN files f_src ON f_src.id = s_src.file_id
178
+ LEFT JOIN symbols s_dst ON s_dst.id = rel.target_symbol_id
179
+ WHERE rel.relationship_type = 'extends'${branchClause}
180
+ LIMIT ?`;
181
+ const edgeParams = hasFilter
182
+ ? (args.branch !== undefined ? [args.source_id, args.branch, limit] : [args.source_id, limit])
183
+ : (args.branch !== undefined ? [args.branch, limit] : [limit]);
184
+ const edges = db.prepare(sql).all(...edgeParams);
185
+ return { edges };
186
+ }
187
+ }
188
+ //# sourceMappingURL=graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.js","sourceRoot":"","sources":["../../../src/kb-server/tools/graph.ts"],"names":[],"mappings":"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"}