@vpxa/kb 0.1.1

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 (275) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1140 -0
  3. package/bin/kb.mjs +10 -0
  4. package/package.json +67 -0
  5. package/packages/analyzers/dist/blast-radius-analyzer.d.ts +23 -0
  6. package/packages/analyzers/dist/blast-radius-analyzer.js +114 -0
  7. package/packages/analyzers/dist/dependency-analyzer.d.ts +29 -0
  8. package/packages/analyzers/dist/dependency-analyzer.js +425 -0
  9. package/packages/analyzers/dist/diagram-generator.d.ts +13 -0
  10. package/packages/analyzers/dist/diagram-generator.js +86 -0
  11. package/packages/analyzers/dist/entry-point-analyzer.d.ts +19 -0
  12. package/packages/analyzers/dist/entry-point-analyzer.js +239 -0
  13. package/packages/analyzers/dist/index.d.ts +14 -0
  14. package/packages/analyzers/dist/index.js +23 -0
  15. package/packages/analyzers/dist/knowledge-producer.d.ts +32 -0
  16. package/packages/analyzers/dist/knowledge-producer.js +113 -0
  17. package/packages/analyzers/dist/pattern-analyzer.d.ts +12 -0
  18. package/packages/analyzers/dist/pattern-analyzer.js +359 -0
  19. package/packages/analyzers/dist/regex-call-graph.d.ts +17 -0
  20. package/packages/analyzers/dist/regex-call-graph.js +428 -0
  21. package/packages/analyzers/dist/structure-analyzer.d.ts +11 -0
  22. package/packages/analyzers/dist/structure-analyzer.js +258 -0
  23. package/packages/analyzers/dist/symbol-analyzer.d.ts +10 -0
  24. package/packages/analyzers/dist/symbol-analyzer.js +442 -0
  25. package/packages/analyzers/dist/ts-call-graph.d.ts +27 -0
  26. package/packages/analyzers/dist/ts-call-graph.js +160 -0
  27. package/packages/analyzers/dist/types.d.ts +98 -0
  28. package/packages/analyzers/dist/types.js +1 -0
  29. package/packages/chunker/dist/call-graph-extractor.d.ts +22 -0
  30. package/packages/chunker/dist/call-graph-extractor.js +90 -0
  31. package/packages/chunker/dist/chunker-factory.d.ts +7 -0
  32. package/packages/chunker/dist/chunker-factory.js +36 -0
  33. package/packages/chunker/dist/chunker.interface.d.ts +10 -0
  34. package/packages/chunker/dist/chunker.interface.js +1 -0
  35. package/packages/chunker/dist/code-chunker.d.ts +14 -0
  36. package/packages/chunker/dist/code-chunker.js +134 -0
  37. package/packages/chunker/dist/generic-chunker.d.ts +12 -0
  38. package/packages/chunker/dist/generic-chunker.js +72 -0
  39. package/packages/chunker/dist/index.d.ts +8 -0
  40. package/packages/chunker/dist/index.js +21 -0
  41. package/packages/chunker/dist/markdown-chunker.d.ts +14 -0
  42. package/packages/chunker/dist/markdown-chunker.js +122 -0
  43. package/packages/chunker/dist/treesitter-chunker.d.ts +47 -0
  44. package/packages/chunker/dist/treesitter-chunker.js +234 -0
  45. package/packages/cli/dist/commands/analyze.d.ts +3 -0
  46. package/packages/cli/dist/commands/analyze.js +112 -0
  47. package/packages/cli/dist/commands/context-cmds.d.ts +3 -0
  48. package/packages/cli/dist/commands/context-cmds.js +155 -0
  49. package/packages/cli/dist/commands/environment.d.ts +3 -0
  50. package/packages/cli/dist/commands/environment.js +204 -0
  51. package/packages/cli/dist/commands/execution.d.ts +3 -0
  52. package/packages/cli/dist/commands/execution.js +137 -0
  53. package/packages/cli/dist/commands/graph.d.ts +3 -0
  54. package/packages/cli/dist/commands/graph.js +81 -0
  55. package/packages/cli/dist/commands/init.d.ts +8 -0
  56. package/packages/cli/dist/commands/init.js +87 -0
  57. package/packages/cli/dist/commands/knowledge.d.ts +3 -0
  58. package/packages/cli/dist/commands/knowledge.js +139 -0
  59. package/packages/cli/dist/commands/search.d.ts +3 -0
  60. package/packages/cli/dist/commands/search.js +267 -0
  61. package/packages/cli/dist/commands/system.d.ts +3 -0
  62. package/packages/cli/dist/commands/system.js +241 -0
  63. package/packages/cli/dist/commands/workspace.d.ts +3 -0
  64. package/packages/cli/dist/commands/workspace.js +388 -0
  65. package/packages/cli/dist/context.d.ts +5 -0
  66. package/packages/cli/dist/context.js +14 -0
  67. package/packages/cli/dist/helpers.d.ts +52 -0
  68. package/packages/cli/dist/helpers.js +458 -0
  69. package/packages/cli/dist/index.d.ts +8 -0
  70. package/packages/cli/dist/index.js +69 -0
  71. package/packages/cli/dist/kb-init.d.ts +57 -0
  72. package/packages/cli/dist/kb-init.js +82 -0
  73. package/packages/cli/dist/types.d.ts +7 -0
  74. package/packages/cli/dist/types.js +1 -0
  75. package/packages/core/dist/constants.d.ts +49 -0
  76. package/packages/core/dist/constants.js +43 -0
  77. package/packages/core/dist/content-detector.d.ts +9 -0
  78. package/packages/core/dist/content-detector.js +79 -0
  79. package/packages/core/dist/errors.d.ts +18 -0
  80. package/packages/core/dist/errors.js +40 -0
  81. package/packages/core/dist/index.d.ts +6 -0
  82. package/packages/core/dist/index.js +9 -0
  83. package/packages/core/dist/logger.d.ts +9 -0
  84. package/packages/core/dist/logger.js +34 -0
  85. package/packages/core/dist/types.d.ts +108 -0
  86. package/packages/core/dist/types.js +1 -0
  87. package/packages/embeddings/dist/embedder.interface.d.ts +24 -0
  88. package/packages/embeddings/dist/embedder.interface.js +1 -0
  89. package/packages/embeddings/dist/index.d.ts +3 -0
  90. package/packages/embeddings/dist/index.js +5 -0
  91. package/packages/embeddings/dist/onnx-embedder.d.ts +24 -0
  92. package/packages/embeddings/dist/onnx-embedder.js +82 -0
  93. package/packages/indexer/dist/file-hasher.d.ts +11 -0
  94. package/packages/indexer/dist/file-hasher.js +13 -0
  95. package/packages/indexer/dist/filesystem-crawler.d.ts +27 -0
  96. package/packages/indexer/dist/filesystem-crawler.js +125 -0
  97. package/packages/indexer/dist/graph-extractor.d.ts +22 -0
  98. package/packages/indexer/dist/graph-extractor.js +111 -0
  99. package/packages/indexer/dist/incremental-indexer.d.ts +47 -0
  100. package/packages/indexer/dist/incremental-indexer.js +278 -0
  101. package/packages/indexer/dist/index.d.ts +5 -0
  102. package/packages/indexer/dist/index.js +14 -0
  103. package/packages/server/dist/api.d.ts +8 -0
  104. package/packages/server/dist/api.js +9 -0
  105. package/packages/server/dist/config.d.ts +3 -0
  106. package/packages/server/dist/config.js +75 -0
  107. package/packages/server/dist/curated-manager.d.ts +86 -0
  108. package/packages/server/dist/curated-manager.js +357 -0
  109. package/packages/server/dist/index.d.ts +2 -0
  110. package/packages/server/dist/index.js +134 -0
  111. package/packages/server/dist/replay-interceptor.d.ts +11 -0
  112. package/packages/server/dist/replay-interceptor.js +38 -0
  113. package/packages/server/dist/resources/resources.d.ts +4 -0
  114. package/packages/server/dist/resources/resources.js +40 -0
  115. package/packages/server/dist/server.d.ts +21 -0
  116. package/packages/server/dist/server.js +247 -0
  117. package/packages/server/dist/tools/analyze.tools.d.ts +11 -0
  118. package/packages/server/dist/tools/analyze.tools.js +288 -0
  119. package/packages/server/dist/tools/forge.tools.d.ts +12 -0
  120. package/packages/server/dist/tools/forge.tools.js +501 -0
  121. package/packages/server/dist/tools/forget.tool.d.ts +4 -0
  122. package/packages/server/dist/tools/forget.tool.js +43 -0
  123. package/packages/server/dist/tools/graph.tool.d.ts +4 -0
  124. package/packages/server/dist/tools/graph.tool.js +110 -0
  125. package/packages/server/dist/tools/list.tool.d.ts +4 -0
  126. package/packages/server/dist/tools/list.tool.js +56 -0
  127. package/packages/server/dist/tools/lookup.tool.d.ts +4 -0
  128. package/packages/server/dist/tools/lookup.tool.js +53 -0
  129. package/packages/server/dist/tools/onboard.tool.d.ts +5 -0
  130. package/packages/server/dist/tools/onboard.tool.js +112 -0
  131. package/packages/server/dist/tools/produce.tool.d.ts +3 -0
  132. package/packages/server/dist/tools/produce.tool.js +74 -0
  133. package/packages/server/dist/tools/read.tool.d.ts +4 -0
  134. package/packages/server/dist/tools/read.tool.js +49 -0
  135. package/packages/server/dist/tools/reindex.tool.d.ts +7 -0
  136. package/packages/server/dist/tools/reindex.tool.js +70 -0
  137. package/packages/server/dist/tools/remember.tool.d.ts +4 -0
  138. package/packages/server/dist/tools/remember.tool.js +45 -0
  139. package/packages/server/dist/tools/replay.tool.d.ts +3 -0
  140. package/packages/server/dist/tools/replay.tool.js +89 -0
  141. package/packages/server/dist/tools/search.tool.d.ts +5 -0
  142. package/packages/server/dist/tools/search.tool.js +331 -0
  143. package/packages/server/dist/tools/status.tool.d.ts +4 -0
  144. package/packages/server/dist/tools/status.tool.js +68 -0
  145. package/packages/server/dist/tools/toolkit.tools.d.ts +35 -0
  146. package/packages/server/dist/tools/toolkit.tools.js +1674 -0
  147. package/packages/server/dist/tools/update.tool.d.ts +4 -0
  148. package/packages/server/dist/tools/update.tool.js +42 -0
  149. package/packages/server/dist/tools/utility.tools.d.ts +15 -0
  150. package/packages/server/dist/tools/utility.tools.js +461 -0
  151. package/packages/store/dist/graph-store.interface.d.ts +104 -0
  152. package/packages/store/dist/graph-store.interface.js +1 -0
  153. package/packages/store/dist/index.d.ts +6 -0
  154. package/packages/store/dist/index.js +9 -0
  155. package/packages/store/dist/lance-store.d.ts +32 -0
  156. package/packages/store/dist/lance-store.js +258 -0
  157. package/packages/store/dist/sqlite-graph-store.d.ts +43 -0
  158. package/packages/store/dist/sqlite-graph-store.js +374 -0
  159. package/packages/store/dist/store-factory.d.ts +9 -0
  160. package/packages/store/dist/store-factory.js +14 -0
  161. package/packages/store/dist/store.interface.d.ts +48 -0
  162. package/packages/store/dist/store.interface.js +1 -0
  163. package/packages/tools/dist/batch.d.ts +21 -0
  164. package/packages/tools/dist/batch.js +45 -0
  165. package/packages/tools/dist/changelog.d.ts +34 -0
  166. package/packages/tools/dist/changelog.js +112 -0
  167. package/packages/tools/dist/check.d.ts +26 -0
  168. package/packages/tools/dist/check.js +59 -0
  169. package/packages/tools/dist/checkpoint.d.ts +17 -0
  170. package/packages/tools/dist/checkpoint.js +43 -0
  171. package/packages/tools/dist/codemod.d.ts +37 -0
  172. package/packages/tools/dist/codemod.js +69 -0
  173. package/packages/tools/dist/compact.d.ts +41 -0
  174. package/packages/tools/dist/compact.js +60 -0
  175. package/packages/tools/dist/data-transform.d.ts +10 -0
  176. package/packages/tools/dist/data-transform.js +124 -0
  177. package/packages/tools/dist/dead-symbols.d.ts +21 -0
  178. package/packages/tools/dist/dead-symbols.js +71 -0
  179. package/packages/tools/dist/delegate.d.ts +34 -0
  180. package/packages/tools/dist/delegate.js +130 -0
  181. package/packages/tools/dist/diff-parse.d.ts +26 -0
  182. package/packages/tools/dist/diff-parse.js +153 -0
  183. package/packages/tools/dist/digest.d.ts +53 -0
  184. package/packages/tools/dist/digest.js +242 -0
  185. package/packages/tools/dist/encode.d.ts +14 -0
  186. package/packages/tools/dist/encode.js +46 -0
  187. package/packages/tools/dist/env-info.d.ts +28 -0
  188. package/packages/tools/dist/env-info.js +58 -0
  189. package/packages/tools/dist/eval.d.ts +13 -0
  190. package/packages/tools/dist/eval.js +79 -0
  191. package/packages/tools/dist/evidence-map.d.ts +79 -0
  192. package/packages/tools/dist/evidence-map.js +203 -0
  193. package/packages/tools/dist/file-summary.d.ts +32 -0
  194. package/packages/tools/dist/file-summary.js +106 -0
  195. package/packages/tools/dist/file-walk.d.ts +4 -0
  196. package/packages/tools/dist/file-walk.js +75 -0
  197. package/packages/tools/dist/find-examples.d.ts +25 -0
  198. package/packages/tools/dist/find-examples.js +48 -0
  199. package/packages/tools/dist/find.d.ts +47 -0
  200. package/packages/tools/dist/find.js +120 -0
  201. package/packages/tools/dist/forge-classify.d.ts +44 -0
  202. package/packages/tools/dist/forge-classify.js +319 -0
  203. package/packages/tools/dist/forge-ground.d.ts +64 -0
  204. package/packages/tools/dist/forge-ground.js +184 -0
  205. package/packages/tools/dist/git-context.d.ts +22 -0
  206. package/packages/tools/dist/git-context.js +46 -0
  207. package/packages/tools/dist/graph-query.d.ts +89 -0
  208. package/packages/tools/dist/graph-query.js +194 -0
  209. package/packages/tools/dist/health.d.ts +14 -0
  210. package/packages/tools/dist/health.js +118 -0
  211. package/packages/tools/dist/http-request.d.ts +23 -0
  212. package/packages/tools/dist/http-request.js +58 -0
  213. package/packages/tools/dist/index.d.ts +49 -0
  214. package/packages/tools/dist/index.js +273 -0
  215. package/packages/tools/dist/lane.d.ts +39 -0
  216. package/packages/tools/dist/lane.js +227 -0
  217. package/packages/tools/dist/measure.d.ts +38 -0
  218. package/packages/tools/dist/measure.js +119 -0
  219. package/packages/tools/dist/onboard.d.ts +41 -0
  220. package/packages/tools/dist/onboard.js +1139 -0
  221. package/packages/tools/dist/parse-output.d.ts +80 -0
  222. package/packages/tools/dist/parse-output.js +158 -0
  223. package/packages/tools/dist/process-manager.d.ts +18 -0
  224. package/packages/tools/dist/process-manager.js +69 -0
  225. package/packages/tools/dist/queue.d.ts +38 -0
  226. package/packages/tools/dist/queue.js +126 -0
  227. package/packages/tools/dist/regex-test.d.ts +31 -0
  228. package/packages/tools/dist/regex-test.js +39 -0
  229. package/packages/tools/dist/rename.d.ts +29 -0
  230. package/packages/tools/dist/rename.js +70 -0
  231. package/packages/tools/dist/replay.d.ts +56 -0
  232. package/packages/tools/dist/replay.js +108 -0
  233. package/packages/tools/dist/schema-validate.d.ts +23 -0
  234. package/packages/tools/dist/schema-validate.js +141 -0
  235. package/packages/tools/dist/scope-map.d.ts +52 -0
  236. package/packages/tools/dist/scope-map.js +72 -0
  237. package/packages/tools/dist/snippet.d.ts +34 -0
  238. package/packages/tools/dist/snippet.js +80 -0
  239. package/packages/tools/dist/stash.d.ts +12 -0
  240. package/packages/tools/dist/stash.js +60 -0
  241. package/packages/tools/dist/stratum-card.d.ts +31 -0
  242. package/packages/tools/dist/stratum-card.js +239 -0
  243. package/packages/tools/dist/symbol.d.ts +28 -0
  244. package/packages/tools/dist/symbol.js +87 -0
  245. package/packages/tools/dist/test-run.d.ts +23 -0
  246. package/packages/tools/dist/test-run.js +55 -0
  247. package/packages/tools/dist/text-utils.d.ts +16 -0
  248. package/packages/tools/dist/text-utils.js +31 -0
  249. package/packages/tools/dist/time-utils.d.ts +18 -0
  250. package/packages/tools/dist/time-utils.js +135 -0
  251. package/packages/tools/dist/trace.d.ts +24 -0
  252. package/packages/tools/dist/trace.js +114 -0
  253. package/packages/tools/dist/truncation.d.ts +22 -0
  254. package/packages/tools/dist/truncation.js +45 -0
  255. package/packages/tools/dist/watch.d.ts +30 -0
  256. package/packages/tools/dist/watch.js +61 -0
  257. package/packages/tools/dist/web-fetch.d.ts +45 -0
  258. package/packages/tools/dist/web-fetch.js +249 -0
  259. package/packages/tools/dist/web-search.d.ts +23 -0
  260. package/packages/tools/dist/web-search.js +46 -0
  261. package/packages/tools/dist/workset.d.ts +45 -0
  262. package/packages/tools/dist/workset.js +77 -0
  263. package/packages/tui/dist/App.d.ts +8 -0
  264. package/packages/tui/dist/App.js +52659 -0
  265. package/packages/tui/dist/index.d.ts +19 -0
  266. package/packages/tui/dist/index.js +54742 -0
  267. package/packages/tui/dist/panels/CuratedPanel.d.ts +8 -0
  268. package/packages/tui/dist/panels/CuratedPanel.js +34452 -0
  269. package/packages/tui/dist/panels/LogPanel.d.ts +3 -0
  270. package/packages/tui/dist/panels/LogPanel.js +51894 -0
  271. package/packages/tui/dist/panels/SearchPanel.d.ts +10 -0
  272. package/packages/tui/dist/panels/SearchPanel.js +34985 -0
  273. package/packages/tui/dist/panels/StatusPanel.d.ts +8 -0
  274. package/packages/tui/dist/panels/StatusPanel.js +34465 -0
  275. package/skills/knowledge-base/SKILL.md +316 -0
package/bin/kb.mjs ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import { resolve } from 'node:path';
3
+ import { fileURLToPath, pathToFileURL } from 'node:url';
4
+
5
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
6
+
7
+ // Dispatch to the CLI package
8
+ const cliPath = resolve(__dirname, '..', 'packages', 'cli', 'dist', 'index.js');
9
+ const cli = await import(pathToFileURL(cliPath).href);
10
+ await cli.run(process.argv.slice(2));
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@vpxa/kb",
3
+ "version": "0.1.1",
4
+ "type": "module",
5
+ "description": "Local-first AI developer toolkit — knowledge base, code analysis, context management, and developer tools for LLM agents",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/anvpx/kb.git"
10
+ },
11
+ "keywords": [
12
+ "knowledge-base",
13
+ "mcp",
14
+ "ai",
15
+ "developer-tools",
16
+ "local-first",
17
+ "embeddings",
18
+ "vector-search",
19
+ "code-analysis"
20
+ ],
21
+ "author": "AnVPX",
22
+ "files": [
23
+ "bin/",
24
+ "packages/*/dist/**/*.js",
25
+ "packages/*/dist/**/*.d.ts",
26
+ "skills/",
27
+ "README.md",
28
+ "LICENSE"
29
+ ],
30
+ "exports": {
31
+ ".": "./packages/core/dist/index.js",
32
+ "./tools": "./packages/tools/dist/index.js",
33
+ "./store": "./packages/store/dist/index.js",
34
+ "./embeddings": "./packages/embeddings/dist/index.js"
35
+ },
36
+ "types": "./packages/core/dist/index.d.ts",
37
+ "bin": {
38
+ "kb": "./bin/kb.mjs"
39
+ },
40
+ "devDependencies": {
41
+ "@biomejs/biome": "^2.x",
42
+ "@types/node": "^24.x",
43
+ "esbuild": "^0.x",
44
+ "glob": "^13.x",
45
+ "rimraf": "^6.x",
46
+ "typescript": "^5.x",
47
+ "vitest": "^4.x"
48
+ },
49
+ "engines": {
50
+ "node": ">=24"
51
+ },
52
+ "scripts": {
53
+ "build": "node scripts/build.mjs",
54
+ "typecheck": "tsc -b tsconfig.build.json --emitDeclarationOnly",
55
+ "clean": "rimraf --glob packages/*/dist packages/*/*.tsbuildinfo",
56
+ "lint": "biome check .",
57
+ "lint:fix": "biome check --write .",
58
+ "format": "biome format --write .",
59
+ "start": "node packages/server/dist/index.js",
60
+ "start:http": "node packages/server/dist/index.js --transport http",
61
+ "test": "vitest run",
62
+ "release": "node scripts/release.mjs",
63
+ "release:dry": "node scripts/release.mjs --dry-run",
64
+ "nodeprune": "pnpm clean && pnpm store prune && pnpm -s dlx npkill -D -y",
65
+ "test:watch": "vitest"
66
+ }
67
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Blast-radius analyzer.
3
+ *
4
+ * Given a set of changed files, traces the dependency graph to find all
5
+ * affected files (direct + transitive importers) and their associated tests.
6
+ * Returns a minimal review context optimized for token efficiency.
7
+ */
8
+ import type { AnalysisResult } from './types.js';
9
+ export interface BlastRadiusOptions {
10
+ /** Changed file paths (relative to root) */
11
+ files: string[];
12
+ /** Maximum depth of transitive dependency traversal (default: 5) */
13
+ maxDepth?: number;
14
+ /** Output format */
15
+ format?: 'json' | 'markdown';
16
+ }
17
+ export declare class BlastRadiusAnalyzer {
18
+ readonly name = "blast-radius";
19
+ private depAnalyzer;
20
+ analyze(rootPath: string, options: BlastRadiusOptions): Promise<AnalysisResult>;
21
+ private formatMarkdown;
22
+ }
23
+ //# sourceMappingURL=blast-radius-analyzer.d.ts.map
@@ -0,0 +1,114 @@
1
+ import { DependencyAnalyzer } from "./dependency-analyzer.js";
2
+ class BlastRadiusAnalyzer {
3
+ name = "blast-radius";
4
+ depAnalyzer = new DependencyAnalyzer();
5
+ async analyze(rootPath, options) {
6
+ const { files, maxDepth = 5, format = "markdown" } = options;
7
+ const startTime = Date.now();
8
+ const depResult = await this.depAnalyzer.analyze(rootPath, { format: "json" });
9
+ const depData = depResult.data;
10
+ const reverseGraph = depData.reverseGraph ?? {};
11
+ const testCoverage = depData.testCoverage ?? {};
12
+ const affected = /* @__PURE__ */ new Map();
13
+ const queue = [];
14
+ for (const file of files) {
15
+ affected.set(file, { path: file, reason: "changed", depth: 0 });
16
+ const norm = file.replace(/\.[jt]sx?$/, "");
17
+ queue.push({ path: norm, depth: 0 });
18
+ }
19
+ while (queue.length > 0) {
20
+ const item = queue.shift();
21
+ if (!item) break;
22
+ const { path, depth } = item;
23
+ if (depth >= maxDepth) continue;
24
+ const importers = reverseGraph[path] ?? [];
25
+ for (const importer of importers) {
26
+ if (affected.has(importer)) continue;
27
+ const reason = depth === 0 ? "direct-importer" : "transitive-importer";
28
+ affected.set(importer, { path: importer, reason, depth: depth + 1 });
29
+ const importerNorm = importer.replace(/\.[jt]sx?$/, "");
30
+ queue.push({ path: importerNorm, depth: depth + 1 });
31
+ }
32
+ }
33
+ const affectedTests = /* @__PURE__ */ new Set();
34
+ for (const [filePath] of affected) {
35
+ const norm = filePath.replace(/\.[jt]sx?$/, "");
36
+ const tests = testCoverage[norm] ?? [];
37
+ for (const test of tests) {
38
+ if (!affected.has(test)) {
39
+ affectedTests.add(test);
40
+ affected.set(test, { path: test, reason: "test", depth: 999 });
41
+ }
42
+ }
43
+ }
44
+ const affectedList = [...affected.values()].sort((a, b) => a.depth - b.depth);
45
+ const output = format === "json" ? JSON.stringify({ changedFiles: files, affected: affectedList }, null, 2) : this.formatMarkdown(files, affectedList, reverseGraph);
46
+ return {
47
+ output,
48
+ data: { changedFiles: files, affected: affectedList },
49
+ meta: {
50
+ analyzedAt: (/* @__PURE__ */ new Date()).toISOString(),
51
+ scope: rootPath,
52
+ fileCount: affectedList.length,
53
+ durationMs: Date.now() - startTime
54
+ }
55
+ };
56
+ }
57
+ formatMarkdown(changedFiles, affected, _reverseGraph) {
58
+ const lines = [];
59
+ lines.push("## Blast Radius Analysis\n");
60
+ lines.push(`**Changed files:** ${changedFiles.length}`);
61
+ lines.push(`**Total affected:** ${affected.length}
62
+ `);
63
+ const changed = affected.filter((a) => a.reason === "changed");
64
+ if (changed.length > 0) {
65
+ lines.push("### Changed Files\n");
66
+ for (const f of changed) {
67
+ lines.push(`- \`${f.path}\``);
68
+ }
69
+ }
70
+ const direct = affected.filter((a) => a.reason === "direct-importer");
71
+ if (direct.length > 0) {
72
+ lines.push(`
73
+ ### Direct Importers (${direct.length} files)
74
+ `);
75
+ for (const f of direct) {
76
+ lines.push(`- \`${f.path}\``);
77
+ }
78
+ }
79
+ const transitive = affected.filter((a) => a.reason === "transitive-importer");
80
+ if (transitive.length > 0) {
81
+ lines.push(`
82
+ ### Transitive Importers (${transitive.length} files)
83
+ `);
84
+ for (const f of transitive.slice(0, 20)) {
85
+ lines.push(`- \`${f.path}\` (depth ${f.depth})`);
86
+ }
87
+ if (transitive.length > 20) {
88
+ lines.push(`- ... and ${transitive.length - 20} more`);
89
+ }
90
+ }
91
+ const tests = affected.filter((a) => a.reason === "test");
92
+ if (tests.length > 0) {
93
+ lines.push(`
94
+ ### Affected Tests (${tests.length} files)
95
+ `);
96
+ for (const f of tests) {
97
+ lines.push(`- \`${f.path}\``);
98
+ }
99
+ }
100
+ lines.push("\n### Review Summary\n");
101
+ lines.push(`| Category | Count |`);
102
+ lines.push(`|----------|-------|`);
103
+ lines.push(`| Changed | ${changed.length} |`);
104
+ lines.push(`| Direct importers | ${direct.length} |`);
105
+ lines.push(`| Transitive importers | ${transitive.length} |`);
106
+ lines.push(`| Affected tests | ${tests.length} |`);
107
+ lines.push(`| **Total review scope** | **${affected.length}** |`);
108
+ return lines.join("\n");
109
+ }
110
+ }
111
+ export {
112
+ BlastRadiusAnalyzer
113
+ };
114
+ //# sourceMappingURL=blast-radius-analyzer.js.map
@@ -0,0 +1,29 @@
1
+ import type { AnalysisResult, DependencyAnalyzerOptions, IAnalyzer, ImportInfo } from './types.js';
2
+ export declare class DependencyAnalyzer implements IAnalyzer<DependencyAnalyzerOptions> {
3
+ readonly name = "dependencies";
4
+ /** Map of workspace package names to their relative entry point paths */
5
+ private workspacePackages;
6
+ analyze(rootPath: string, options?: DependencyAnalyzerOptions): Promise<AnalysisResult>;
7
+ private collectFiles;
8
+ private extractImports;
9
+ private groupExternalDeps;
10
+ private groupInternalDeps;
11
+ /**
12
+ * Build reverse graph: for each source file, who imports it?
13
+ */
14
+ buildReverseGraph(imports: ImportInfo[], _rootPath: string): Record<string, string[]>;
15
+ /**
16
+ * Build test coverage map: for each source file, which test files exercise it?
17
+ */
18
+ buildTestCoverage(imports: ImportInfo[], _rootPath: string): Record<string, string[]>;
19
+ /** Resolve a relative import path to a normalized file path (best-effort). */
20
+ private resolveImportPath;
21
+ /**
22
+ * Build a map of workspace package names → relative entry point paths.
23
+ * Scans for package.json files in common workspace dirs.
24
+ */
25
+ private buildWorkspaceMap;
26
+ private formatMarkdown;
27
+ private formatMermaid;
28
+ }
29
+ //# sourceMappingURL=dependency-analyzer.d.ts.map
@@ -0,0 +1,425 @@
1
+ import { readdir, readFile } from "node:fs/promises";
2
+ import { dirname, extname, join, relative, resolve } from "node:path";
3
+ const CODE_EXTENSIONS = /* @__PURE__ */ new Set([
4
+ ".ts",
5
+ ".tsx",
6
+ ".js",
7
+ ".jsx",
8
+ ".mjs",
9
+ ".cjs",
10
+ ".py",
11
+ ".java",
12
+ ".go",
13
+ ".cs",
14
+ ".kt",
15
+ ".scala",
16
+ ".rb",
17
+ ".rs",
18
+ ".php",
19
+ ".swift"
20
+ ]);
21
+ const IMPORT_PATTERNS = [
22
+ // ── JS/TS ──
23
+ // ES import: import { x } from 'module' / import x from 'module'
24
+ {
25
+ regex: /import\s+(?:(?:type\s+)?(?:(?:\{[^}]*\}|[\w*]+)\s+from\s+)?)['"]([^'"]+)['"]/g,
26
+ confidence: "high"
27
+ },
28
+ // Dynamic import: import('module')
29
+ {
30
+ regex: /import\(\s*['"]([^'"]+)['"]\s*\)/g,
31
+ confidence: "medium"
32
+ },
33
+ // CommonJS require: require('module')
34
+ {
35
+ regex: /require\(\s*['"]([^'"]+)['"]\s*\)/g,
36
+ confidence: "medium"
37
+ },
38
+ // ── Python ──
39
+ // from package import module
40
+ {
41
+ regex: /^from\s+([\w.]+)\s+import\b/gm,
42
+ confidence: "high",
43
+ lang: "python"
44
+ },
45
+ // import package
46
+ {
47
+ regex: /^import\s+([\w.]+)\s*$/gm,
48
+ confidence: "high",
49
+ lang: "python"
50
+ },
51
+ // ── Java / Kotlin / Scala ──
52
+ // import com.example.Class;
53
+ {
54
+ regex: /^import\s+(?:static\s+)?([\w.]+(?:\.\*)?)\s*;/gm,
55
+ confidence: "high",
56
+ lang: "java"
57
+ },
58
+ // ── Go ──
59
+ // import "package" or "package" inside import block
60
+ {
61
+ regex: /(?:^import\s+|^\s+)[""]([^""]+)[""]/gm,
62
+ confidence: "high",
63
+ lang: "go"
64
+ },
65
+ // ── C# ──
66
+ // using Namespace.Something;
67
+ {
68
+ regex: /^using\s+(?:static\s+)?([\w.]+)\s*;/gm,
69
+ confidence: "high",
70
+ lang: "csharp"
71
+ },
72
+ // ── Rust ──
73
+ // use crate::module; use std::io;
74
+ {
75
+ regex: /^use\s+([\w:]+(?:::\w+)*)/gm,
76
+ confidence: "high",
77
+ lang: "rust"
78
+ },
79
+ // ── PHP ──
80
+ // use Namespace\Class;
81
+ {
82
+ regex: /^use\s+([\w\\]+)\s*;/gm,
83
+ confidence: "high",
84
+ lang: "php"
85
+ },
86
+ // ── Ruby ──
87
+ // require 'gem' or require_relative 'file'
88
+ {
89
+ regex: /require(?:_relative)?\s+['"]([^'"]+)['"]/g,
90
+ confidence: "medium",
91
+ lang: "ruby"
92
+ },
93
+ // ── Swift ──
94
+ // import Foundation
95
+ {
96
+ regex: /^import\s+(\w+)\s*$/gm,
97
+ confidence: "high",
98
+ lang: "swift"
99
+ }
100
+ ];
101
+ const DEFAULT_EXCLUDES = /* @__PURE__ */ new Set([
102
+ "node_modules",
103
+ ".git",
104
+ "dist",
105
+ "build",
106
+ "coverage",
107
+ ".turbo",
108
+ ".cache",
109
+ "cdk.out"
110
+ ]);
111
+ const TEST_PATTERNS = [/\.(test|spec)\.[jt]sx?$/, /\/__tests__\//, /\/test\//, /\/tests\//];
112
+ const EXT_TO_LANG = {
113
+ ".ts": "js",
114
+ ".tsx": "js",
115
+ ".js": "js",
116
+ ".jsx": "js",
117
+ ".mjs": "js",
118
+ ".cjs": "js",
119
+ ".py": "python",
120
+ ".java": "java",
121
+ ".kt": "java",
122
+ ".scala": "java",
123
+ ".go": "go",
124
+ ".cs": "csharp",
125
+ ".rs": "rust",
126
+ ".php": "php",
127
+ ".rb": "ruby",
128
+ ".swift": "swift"
129
+ };
130
+ function classifyExternal(source, lang) {
131
+ if (!lang || lang === "js") {
132
+ return !source.startsWith(".") && !source.startsWith("/");
133
+ }
134
+ if (lang === "python") {
135
+ return !source.startsWith(".");
136
+ }
137
+ if (lang === "java") {
138
+ return !source.startsWith("com.") || source.startsWith("com.amazonaws") || source.startsWith("com.google") || source.startsWith("com.fasterxml");
139
+ }
140
+ if (lang === "go") {
141
+ return source.includes(".") && !source.startsWith(".");
142
+ }
143
+ if (lang === "csharp") {
144
+ return source.startsWith("System") || source.startsWith("Microsoft") || source.startsWith("Newtonsoft") || source.startsWith("Amazon");
145
+ }
146
+ if (lang === "rust") {
147
+ return !source.startsWith("crate::") && !source.startsWith("self::") && !source.startsWith("super::");
148
+ }
149
+ return true;
150
+ }
151
+ function isTestFile(filePath) {
152
+ return TEST_PATTERNS.some((p) => p.test(filePath));
153
+ }
154
+ class DependencyAnalyzer {
155
+ name = "dependencies";
156
+ /** Map of workspace package names to their relative entry point paths */
157
+ workspacePackages = /* @__PURE__ */ new Map();
158
+ async analyze(rootPath, options = {}) {
159
+ const { format = "markdown" } = options;
160
+ const startTime = Date.now();
161
+ this.workspacePackages = await this.buildWorkspaceMap(rootPath);
162
+ const files = await this.collectFiles(rootPath);
163
+ const imports = [];
164
+ for (const filePath of files) {
165
+ const content = await readFile(filePath, "utf-8");
166
+ const fileImports = this.extractImports(content, filePath, rootPath);
167
+ imports.push(...fileImports);
168
+ }
169
+ const external = this.groupExternalDeps(imports);
170
+ const internal = this.groupInternalDeps(imports, rootPath);
171
+ const reverseGraph = this.buildReverseGraph(imports, rootPath);
172
+ const testCoverage = this.buildTestCoverage(imports, rootPath);
173
+ const output = format === "json" ? JSON.stringify({ external, internal, reverseGraph, testCoverage }, null, 2) : format === "mermaid" ? this.formatMermaid(internal) : this.formatMarkdown(external, internal, rootPath, testCoverage);
174
+ return {
175
+ output,
176
+ data: { external, internal, reverseGraph, testCoverage, totalImports: imports.length },
177
+ meta: {
178
+ analyzedAt: (/* @__PURE__ */ new Date()).toISOString(),
179
+ scope: rootPath,
180
+ fileCount: files.length,
181
+ durationMs: Date.now() - startTime
182
+ }
183
+ };
184
+ }
185
+ async collectFiles(dirPath) {
186
+ const files = [];
187
+ const walk = async (dir) => {
188
+ const entries = await readdir(dir, { withFileTypes: true });
189
+ for (const entry of entries) {
190
+ if (DEFAULT_EXCLUDES.has(entry.name)) continue;
191
+ if (entry.name.startsWith(".")) continue;
192
+ const fullPath = join(dir, entry.name);
193
+ if (entry.isDirectory()) {
194
+ await walk(fullPath);
195
+ } else if (CODE_EXTENSIONS.has(extname(entry.name))) {
196
+ files.push(fullPath);
197
+ }
198
+ }
199
+ };
200
+ await walk(dirPath);
201
+ return files;
202
+ }
203
+ extractImports(content, filePath, rootPath) {
204
+ const results = [];
205
+ const ext = extname(filePath).toLowerCase();
206
+ const fileLang = EXT_TO_LANG[ext];
207
+ for (const pattern of IMPORT_PATTERNS) {
208
+ if (pattern.lang && pattern.lang !== fileLang) continue;
209
+ if (!pattern.lang && fileLang && fileLang !== "js") continue;
210
+ const regex = new RegExp(pattern.regex.source, pattern.regex.flags);
211
+ let match;
212
+ while ((match = regex.exec(content)) !== null) {
213
+ const source = match[1];
214
+ const isExternal = classifyExternal(source, fileLang);
215
+ results.push({
216
+ source,
217
+ specifiers: [],
218
+ filePath: relative(rootPath, filePath).replace(/\\/g, "/"),
219
+ isExternal,
220
+ confidence: pattern.confidence
221
+ });
222
+ }
223
+ }
224
+ return results;
225
+ }
226
+ groupExternalDeps(imports) {
227
+ const deps = {};
228
+ for (const imp of imports) {
229
+ if (!imp.isExternal) continue;
230
+ const ext = extname(imp.filePath).toLowerCase();
231
+ const lang = EXT_TO_LANG[ext];
232
+ let pkg;
233
+ if (lang === "java") {
234
+ const parts = imp.source.split(".");
235
+ while (parts.length > 1) {
236
+ const last = parts[parts.length - 1];
237
+ if (last === "*" || /^[A-Z]/.test(last)) {
238
+ parts.pop();
239
+ } else {
240
+ break;
241
+ }
242
+ }
243
+ if (parts.length >= 2) {
244
+ pkg = parts.slice(0, 2).join(".");
245
+ } else {
246
+ pkg = parts.join(".");
247
+ }
248
+ } else if (lang === "python") {
249
+ pkg = imp.source.split(".")[0];
250
+ } else if (lang === "go") {
251
+ pkg = imp.source;
252
+ } else if (lang === "csharp") {
253
+ const parts = imp.source.split(".");
254
+ pkg = parts.length >= 2 ? parts.slice(0, 2).join(".") : imp.source;
255
+ } else {
256
+ pkg = imp.source.startsWith("@") ? imp.source.split("/").slice(0, 2).join("/") : imp.source.split("/")[0];
257
+ }
258
+ if (!deps[pkg]) deps[pkg] = { count: 0, confidence: imp.confidence, usedBy: /* @__PURE__ */ new Set() };
259
+ deps[pkg].count++;
260
+ deps[pkg].usedBy.add(imp.filePath);
261
+ if (imp.confidence === "high") deps[pkg].confidence = "high";
262
+ else if (imp.confidence === "medium" && deps[pkg].confidence === "low")
263
+ deps[pkg].confidence = "medium";
264
+ }
265
+ const result = {};
266
+ for (const [pkg, data] of Object.entries(deps)) {
267
+ result[pkg] = { count: data.count, confidence: data.confidence, usedBy: [...data.usedBy] };
268
+ }
269
+ return result;
270
+ }
271
+ groupInternalDeps(imports, _rootPath) {
272
+ const deps = {};
273
+ for (const imp of imports) {
274
+ if (imp.isExternal) continue;
275
+ if (!deps[imp.filePath]) deps[imp.filePath] = /* @__PURE__ */ new Set();
276
+ deps[imp.filePath].add(imp.source);
277
+ }
278
+ const result = {};
279
+ for (const [file, sources] of Object.entries(deps)) {
280
+ result[file] = [...sources];
281
+ }
282
+ return result;
283
+ }
284
+ /**
285
+ * Build reverse graph: for each source file, who imports it?
286
+ */
287
+ buildReverseGraph(imports, _rootPath) {
288
+ const reverse = {};
289
+ for (const imp of imports) {
290
+ const importerDir = dirname(imp.filePath);
291
+ const resolved = this.resolveImportPath(imp.source, importerDir);
292
+ if (!resolved) continue;
293
+ if (!reverse[resolved]) reverse[resolved] = /* @__PURE__ */ new Set();
294
+ reverse[resolved].add(imp.filePath);
295
+ }
296
+ const result = {};
297
+ for (const [file, importers] of Object.entries(reverse)) {
298
+ result[file] = [...importers];
299
+ }
300
+ return result;
301
+ }
302
+ /**
303
+ * Build test coverage map: for each source file, which test files exercise it?
304
+ */
305
+ buildTestCoverage(imports, _rootPath) {
306
+ const coverage = {};
307
+ for (const imp of imports) {
308
+ if (!isTestFile(imp.filePath)) continue;
309
+ const importerDir = dirname(imp.filePath);
310
+ const resolved = this.resolveImportPath(imp.source, importerDir);
311
+ if (!resolved || isTestFile(resolved)) continue;
312
+ if (!coverage[resolved]) coverage[resolved] = /* @__PURE__ */ new Set();
313
+ coverage[resolved].add(imp.filePath);
314
+ }
315
+ const result = {};
316
+ for (const [file, tests] of Object.entries(coverage)) {
317
+ result[file] = [...tests];
318
+ }
319
+ return result;
320
+ }
321
+ /** Resolve a relative import path to a normalized file path (best-effort). */
322
+ resolveImportPath(source, fromDir) {
323
+ if (source.startsWith(".")) {
324
+ const resolved = join(fromDir, source).replace(/\\/g, "/");
325
+ return resolved.replace(/\.[jt]sx?$/, "");
326
+ }
327
+ const pkg = source.startsWith("@") ? source.split("/").slice(0, 2).join("/") : source.split("/")[0];
328
+ const entryPath = this.workspacePackages.get(pkg);
329
+ if (entryPath) {
330
+ return entryPath.replace(/\.[jt]sx?$/, "");
331
+ }
332
+ return null;
333
+ }
334
+ /**
335
+ * Build a map of workspace package names → relative entry point paths.
336
+ * Scans for package.json files in common workspace dirs.
337
+ */
338
+ async buildWorkspaceMap(rootPath) {
339
+ const map = /* @__PURE__ */ new Map();
340
+ const searchDirs = ["packages", "functions", "libs", "apps", "cdk"];
341
+ for (const dir of searchDirs) {
342
+ const dirPath = join(rootPath, dir);
343
+ try {
344
+ const entries = await readdir(dirPath, { withFileTypes: true });
345
+ for (const entry of entries) {
346
+ if (!entry.isDirectory() || DEFAULT_EXCLUDES.has(entry.name)) continue;
347
+ try {
348
+ const pkgJsonPath = join(dirPath, entry.name, "package.json");
349
+ const pkgJson = JSON.parse(await readFile(pkgJsonPath, "utf-8"));
350
+ if (pkgJson.name) {
351
+ const main = pkgJson.main ?? pkgJson.exports?.["."] ?? "src/index.ts";
352
+ const entryRelative = relative(rootPath, resolve(dirPath, entry.name, main)).replace(
353
+ /\\/g,
354
+ "/"
355
+ );
356
+ map.set(pkgJson.name, entryRelative);
357
+ }
358
+ } catch {
359
+ }
360
+ }
361
+ } catch {
362
+ }
363
+ }
364
+ return map;
365
+ }
366
+ formatMarkdown(external, internal, rootPath, testCoverage) {
367
+ const lines = [];
368
+ lines.push(`## Dependencies: ${rootPath}
369
+ `);
370
+ const sortedExternal = Object.entries(external).sort((a, b) => b[1].count - a[1].count);
371
+ const totalExternal = sortedExternal.length;
372
+ const totalImports = sortedExternal.reduce((sum, [, d]) => sum + d.count, 0);
373
+ const top5 = sortedExternal.slice(0, 5).map(([pkg]) => pkg);
374
+ lines.push(
375
+ `**${totalExternal} external packages**, **${totalImports} total imports**, **${Object.keys(internal).length} files** with internal imports.
376
+ `
377
+ );
378
+ if (top5.length > 0) {
379
+ lines.push(`**Top dependencies**: ${top5.join(", ")}
380
+ `);
381
+ }
382
+ lines.push("### External Dependencies\n");
383
+ lines.push("| Package | Imports | Used By |");
384
+ lines.push("|---------|---------|---------|");
385
+ for (const [pkg, data] of sortedExternal) {
386
+ lines.push(
387
+ `| ${pkg} | ${data.count} | ${data.usedBy.length} ${data.usedBy.length === 1 ? "file" : "files"} |`
388
+ );
389
+ }
390
+ if (testCoverage && Object.keys(testCoverage).length > 0) {
391
+ const totalTested = Object.keys(testCoverage).length;
392
+ const untested = Object.keys(internal).filter(
393
+ (f) => !isTestFile(f) && !testCoverage[f.replace(/\\.[jt]sx?$/, "")]
394
+ );
395
+ lines.push("\n### Test Coverage Summary\n");
396
+ lines.push(`**${totalTested} source modules** with test coverage.`);
397
+ if (untested.length > 0) {
398
+ lines.push(`**${untested.length} source files** with no detected test coverage.`);
399
+ }
400
+ const sorted = Object.entries(testCoverage).sort((a, b) => b[1].length - a[1].length);
401
+ lines.push("\n**Most-tested modules:**\n");
402
+ for (const [source, tests] of sorted.slice(0, 10)) {
403
+ const displayPath = source.replace(/\/dist\/[^/]*$/, "/src/index").replace(/\.mjs$/, ".ts");
404
+ lines.push(`- ${displayPath} (${tests.length} ${tests.length === 1 ? "test" : "tests"})`);
405
+ }
406
+ }
407
+ return lines.join("\n");
408
+ }
409
+ formatMermaid(internal) {
410
+ const lines = ["graph LR"];
411
+ const nodeId = (path) => path.replace(/[^a-zA-Z0-9]/g, "_");
412
+ for (const [file, deps] of Object.entries(internal).slice(0, 40)) {
413
+ const fromId = nodeId(file);
414
+ for (const dep of deps) {
415
+ const toId = nodeId(dep);
416
+ lines.push(` ${fromId}["${file}"] --> ${toId}["${dep}"]`);
417
+ }
418
+ }
419
+ return lines.join("\n");
420
+ }
421
+ }
422
+ export {
423
+ DependencyAnalyzer
424
+ };
425
+ //# sourceMappingURL=dependency-analyzer.js.map
@@ -0,0 +1,13 @@
1
+ import type { AnalysisResult, DiagramOptions, IAnalyzer } from './types.js';
2
+ /**
3
+ * Generates Mermaid diagrams by combining output from other analyzers.
4
+ */
5
+ export declare class DiagramGenerator implements IAnalyzer<DiagramOptions> {
6
+ readonly name = "diagrams";
7
+ private readonly structureAnalyzer;
8
+ private readonly dependencyAnalyzer;
9
+ analyze(rootPath: string, options?: DiagramOptions): Promise<AnalysisResult>;
10
+ private generateArchitectureDiagram;
11
+ private generateDependencyDiagram;
12
+ }
13
+ //# sourceMappingURL=diagram-generator.d.ts.map