sverklo 0.5.2 → 0.7.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 (34) hide show
  1. package/dist/bin/sverklo.js +194 -9
  2. package/dist/bin/sverklo.js.map +1 -1
  3. package/dist/src/index.d.ts +1 -1
  4. package/dist/src/index.js +1 -1
  5. package/dist/src/index.js.map +1 -1
  6. package/dist/src/registry/indexer-pool.d.ts +24 -0
  7. package/dist/src/registry/indexer-pool.js +97 -0
  8. package/dist/src/registry/indexer-pool.js.map +1 -0
  9. package/dist/src/registry/registry.d.ts +18 -0
  10. package/dist/src/registry/registry.js +69 -0
  11. package/dist/src/registry/registry.js.map +1 -0
  12. package/dist/src/registry/registry.test.d.ts +1 -0
  13. package/dist/src/registry/registry.test.js +79 -0
  14. package/dist/src/registry/registry.test.js.map +1 -0
  15. package/dist/src/search/cluster.d.ts +25 -0
  16. package/dist/src/search/cluster.js +216 -0
  17. package/dist/src/search/cluster.js.map +1 -0
  18. package/dist/src/server/dashboard-html.js +324 -183
  19. package/dist/src/server/dashboard-html.js.map +1 -1
  20. package/dist/src/server/http-server.js +29 -0
  21. package/dist/src/server/http-server.js.map +1 -1
  22. package/dist/src/server/mcp-server.d.ts +1 -0
  23. package/dist/src/server/mcp-server.js +319 -0
  24. package/dist/src/server/mcp-server.js.map +1 -1
  25. package/dist/src/server/tools/clusters.d.ts +20 -0
  26. package/dist/src/server/tools/clusters.js +92 -0
  27. package/dist/src/server/tools/clusters.js.map +1 -0
  28. package/dist/src/server/tools/list-repos.d.ts +9 -0
  29. package/dist/src/server/tools/list-repos.js +48 -0
  30. package/dist/src/server/tools/list-repos.js.map +1 -0
  31. package/dist/src/wiki/wiki-generator.d.ts +12 -0
  32. package/dist/src/wiki/wiki-generator.js +357 -0
  33. package/dist/src/wiki/wiki-generator.js.map +1 -0
  34. package/package.json +1 -1
@@ -0,0 +1,79 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
2
+ import { mkdirSync, writeFileSync, rmSync, readFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { tmpdir } from "node:os";
5
+ // We need to mock homedir() to isolate from the real ~/.sverklo
6
+ const testDir = join(tmpdir(), `sverklo-registry-test-${process.pid}`);
7
+ vi.mock("node:os", async () => {
8
+ const actual = await vi.importActual("node:os");
9
+ return {
10
+ ...actual,
11
+ homedir: () => testDir,
12
+ };
13
+ });
14
+ // Import after mock is set up
15
+ const { getRegistry, registerRepo, unregisterRepo, getRegistryPath, deriveRepoName, updateLastIndexed, } = await import("./registry.js");
16
+ describe("registry", () => {
17
+ beforeEach(() => {
18
+ mkdirSync(join(testDir, ".sverklo"), { recursive: true });
19
+ });
20
+ afterEach(() => {
21
+ rmSync(testDir, { recursive: true, force: true });
22
+ });
23
+ it("returns empty object when no registry file exists", () => {
24
+ expect(getRegistry()).toEqual({});
25
+ });
26
+ it("registers and retrieves a repo", () => {
27
+ registerRepo("my-app", "/dev/my-app");
28
+ const repos = getRegistry();
29
+ expect(repos["my-app"]).toBeDefined();
30
+ expect(repos["my-app"].path).toBe("/dev/my-app");
31
+ expect(repos["my-app"].name).toBe("my-app");
32
+ expect(repos["my-app"].lastIndexed).toBeDefined();
33
+ });
34
+ it("unregisters a repo", () => {
35
+ registerRepo("my-app", "/dev/my-app");
36
+ registerRepo("other", "/dev/other");
37
+ unregisterRepo("my-app");
38
+ const repos = getRegistry();
39
+ expect(repos["my-app"]).toBeUndefined();
40
+ expect(repos["other"]).toBeDefined();
41
+ });
42
+ it("updates lastIndexed timestamp", () => {
43
+ registerRepo("my-app", "/dev/my-app");
44
+ const before = getRegistry()["my-app"].lastIndexed;
45
+ // Small delay to ensure timestamp differs
46
+ updateLastIndexed("my-app");
47
+ const after = getRegistry()["my-app"].lastIndexed;
48
+ expect(after).toBeDefined();
49
+ // They may or may not differ depending on timing, but both should be valid ISO dates
50
+ expect(new Date(after).getTime()).toBeGreaterThanOrEqual(new Date(before).getTime());
51
+ });
52
+ it("getRegistryPath returns a path under ~/.sverklo", () => {
53
+ const p = getRegistryPath();
54
+ expect(p).toContain(".sverklo");
55
+ expect(p).toContain("registry.json");
56
+ });
57
+ it("deriveRepoName uses basename by default", () => {
58
+ expect(deriveRepoName("/dev/my-cool-project")).toBe("my-cool-project");
59
+ });
60
+ it("deriveRepoName deduplicates on collision", () => {
61
+ registerRepo("shared", "/dev/team-a/shared");
62
+ // Different path, same basename
63
+ const name = deriveRepoName("/dev/team-b/shared");
64
+ expect(name).not.toBe("shared");
65
+ expect(name).toContain("shared");
66
+ });
67
+ it("registry file is valid JSON", () => {
68
+ registerRepo("foo", "/dev/foo");
69
+ const raw = readFileSync(getRegistryPath(), "utf-8");
70
+ const parsed = JSON.parse(raw);
71
+ expect(parsed.repos).toBeDefined();
72
+ expect(parsed.repos.foo.path).toBe("/dev/foo");
73
+ });
74
+ it("handles corrupt registry file gracefully", () => {
75
+ writeFileSync(getRegistryPath(), "NOT JSON{{{");
76
+ expect(getRegistry()).toEqual({});
77
+ });
78
+ });
79
+ //# sourceMappingURL=registry.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.test.js","sourceRoot":"","sources":["../../../src/registry/registry.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ export interface FileCluster {
2
+ id: number;
3
+ name: string;
4
+ files: Array<{
5
+ path: string;
6
+ pagerank: number;
7
+ language: string;
8
+ }>;
9
+ hubFile: string;
10
+ size: number;
11
+ }
12
+ /**
13
+ * Detect functional clusters in the dependency graph using Label Propagation.
14
+ * Groups tightly-connected files into clusters based on import relationships.
15
+ */
16
+ export declare function detectClusters(files: Array<{
17
+ id: number;
18
+ path: string;
19
+ pagerank: number;
20
+ language: string;
21
+ }>, edges: Array<{
22
+ source: number;
23
+ target: number;
24
+ weight: number;
25
+ }>): FileCluster[];
@@ -0,0 +1,216 @@
1
+ // Functional cluster detection using Label Propagation Algorithm (LPA).
2
+ // Groups tightly-connected files into clusters based on import relationships.
3
+ // No external dependencies — pure TypeScript, O(E * iterations).
4
+ const MAX_ITERATIONS = 20;
5
+ const MIN_CLUSTER_SIZE = 3;
6
+ /**
7
+ * Detect functional clusters in the dependency graph using Label Propagation.
8
+ * Groups tightly-connected files into clusters based on import relationships.
9
+ */
10
+ export function detectClusters(files, edges) {
11
+ if (files.length === 0)
12
+ return [];
13
+ // Build adjacency list (undirected — imports go both ways for clustering)
14
+ const neighbors = new Map();
15
+ for (const f of files) {
16
+ neighbors.set(f.id, []);
17
+ }
18
+ for (const e of edges) {
19
+ neighbors.get(e.source)?.push({ neighbor: e.target, weight: e.weight });
20
+ neighbors.get(e.target)?.push({ neighbor: e.source, weight: e.weight });
21
+ }
22
+ // Initialize: each node gets its own label
23
+ const nodes = new Map();
24
+ for (const f of files) {
25
+ nodes.set(f.id, {
26
+ id: f.id,
27
+ path: f.path,
28
+ pagerank: f.pagerank,
29
+ language: f.language,
30
+ label: f.id,
31
+ });
32
+ }
33
+ // Iterate label propagation
34
+ const nodeIds = files.map(f => f.id);
35
+ for (let iter = 0; iter < MAX_ITERATIONS; iter++) {
36
+ let changed = false;
37
+ // Shuffle node order each iteration to break ties fairly
38
+ shuffleInPlace(nodeIds);
39
+ for (const nodeId of nodeIds) {
40
+ const node = nodes.get(nodeId);
41
+ const nbrs = neighbors.get(nodeId);
42
+ if (!nbrs || nbrs.length === 0)
43
+ continue;
44
+ // Count weighted votes for each label among neighbors
45
+ const labelWeights = new Map();
46
+ for (const { neighbor, weight } of nbrs) {
47
+ const nbrNode = nodes.get(neighbor);
48
+ if (!nbrNode)
49
+ continue;
50
+ const label = nbrNode.label;
51
+ labelWeights.set(label, (labelWeights.get(label) || 0) + weight);
52
+ }
53
+ // Pick the label with the highest total weight
54
+ let bestLabel = node.label;
55
+ let bestWeight = -1;
56
+ for (const [label, w] of labelWeights) {
57
+ if (w > bestWeight) {
58
+ bestWeight = w;
59
+ bestLabel = label;
60
+ }
61
+ }
62
+ if (bestLabel !== node.label) {
63
+ node.label = bestLabel;
64
+ changed = true;
65
+ }
66
+ }
67
+ if (!changed)
68
+ break;
69
+ }
70
+ // Group nodes by label
71
+ const labelGroups = new Map();
72
+ for (const node of nodes.values()) {
73
+ let group = labelGroups.get(node.label);
74
+ if (!group) {
75
+ group = [];
76
+ labelGroups.set(node.label, group);
77
+ }
78
+ group.push(node);
79
+ }
80
+ // Post-process: merge tiny clusters into nearest larger neighbor
81
+ const largeClusters = new Map();
82
+ const tinyClusters = [];
83
+ for (const [label, group] of labelGroups) {
84
+ if (group.length >= MIN_CLUSTER_SIZE) {
85
+ largeClusters.set(label, group);
86
+ }
87
+ else {
88
+ tinyClusters.push(group);
89
+ }
90
+ }
91
+ // For each tiny cluster, find the large cluster it's most connected to
92
+ for (const tinyGroup of tinyClusters) {
93
+ const connectionWeights = new Map();
94
+ for (const node of tinyGroup) {
95
+ const nbrs = neighbors.get(node.id);
96
+ if (!nbrs)
97
+ continue;
98
+ for (const { neighbor, weight } of nbrs) {
99
+ const nbrNode = nodes.get(neighbor);
100
+ if (!nbrNode)
101
+ continue;
102
+ // Only consider merging into large clusters
103
+ if (largeClusters.has(nbrNode.label)) {
104
+ connectionWeights.set(nbrNode.label, (connectionWeights.get(nbrNode.label) || 0) + weight);
105
+ }
106
+ }
107
+ }
108
+ // Find best large cluster to merge into
109
+ let bestLabel = -1;
110
+ let bestWeight = 0;
111
+ for (const [label, w] of connectionWeights) {
112
+ if (w > bestWeight) {
113
+ bestWeight = w;
114
+ bestLabel = label;
115
+ }
116
+ }
117
+ if (bestLabel !== -1) {
118
+ // Merge into the large cluster
119
+ const target = largeClusters.get(bestLabel);
120
+ for (const node of tinyGroup) {
121
+ node.label = bestLabel;
122
+ target.push(node);
123
+ }
124
+ }
125
+ else {
126
+ // No large neighbor — keep as its own cluster if it has edges,
127
+ // otherwise discard isolated singletons
128
+ if (tinyGroup.length > 1 || tinyGroup.some(n => (neighbors.get(n.id)?.length ?? 0) > 0)) {
129
+ const label = tinyGroup[0].label;
130
+ largeClusters.set(label, tinyGroup);
131
+ }
132
+ }
133
+ }
134
+ // Build final FileCluster array
135
+ const clusters = [];
136
+ let clusterId = 1;
137
+ // Sort clusters by total PageRank (most important first)
138
+ const sortedGroups = [...largeClusters.values()].sort((a, b) => {
139
+ const sumA = a.reduce((s, n) => s + n.pagerank, 0);
140
+ const sumB = b.reduce((s, n) => s + n.pagerank, 0);
141
+ return sumB - sumA;
142
+ });
143
+ for (const group of sortedGroups) {
144
+ // Sort files within cluster by PageRank descending
145
+ group.sort((a, b) => b.pagerank - a.pagerank);
146
+ const hubFile = group[0].path;
147
+ const name = computeClusterName(group.map(n => n.path));
148
+ clusters.push({
149
+ id: clusterId++,
150
+ name,
151
+ files: group.map(n => ({
152
+ path: n.path,
153
+ pagerank: n.pagerank,
154
+ language: n.language,
155
+ })),
156
+ hubFile,
157
+ size: group.length,
158
+ });
159
+ }
160
+ return clusters;
161
+ }
162
+ /**
163
+ * Compute a human-readable cluster name from the common directory prefix
164
+ * of its files. Falls back to the hub file's directory if no common prefix.
165
+ */
166
+ function computeClusterName(paths) {
167
+ if (paths.length === 0)
168
+ return "unknown";
169
+ if (paths.length === 1) {
170
+ const parts = paths[0].split("/");
171
+ return parts.slice(0, -1).join("/") || paths[0];
172
+ }
173
+ // Find common directory prefix
174
+ const segments = paths.map(p => p.split("/"));
175
+ const minLen = Math.min(...segments.map(s => s.length));
176
+ const common = [];
177
+ for (let i = 0; i < minLen - 1; i++) {
178
+ const seg = segments[0][i];
179
+ if (segments.every(s => s[i] === seg)) {
180
+ common.push(seg);
181
+ }
182
+ else {
183
+ break;
184
+ }
185
+ }
186
+ // If common prefix is too short (e.g., just "src"), try to find a
187
+ // majority directory that better describes the cluster
188
+ if (common.length <= 1 && segments[0].length > 2) {
189
+ const dirCounts = new Map();
190
+ for (const seg of segments) {
191
+ // Use the first 2-3 directory segments as the "directory identity"
192
+ const dir = seg.slice(0, Math.min(seg.length - 1, 3)).join("/");
193
+ dirCounts.set(dir, (dirCounts.get(dir) || 0) + 1);
194
+ }
195
+ let bestDir = "";
196
+ let bestCount = 0;
197
+ for (const [dir, count] of dirCounts) {
198
+ if (count > bestCount) {
199
+ bestCount = count;
200
+ bestDir = dir;
201
+ }
202
+ }
203
+ if (bestDir && bestCount > paths.length / 2) {
204
+ return bestDir;
205
+ }
206
+ }
207
+ return common.length > 0 ? common.join("/") : paths[0].split("/").slice(0, -1).join("/") || "root";
208
+ }
209
+ /** Fisher-Yates shuffle in place. */
210
+ function shuffleInPlace(arr) {
211
+ for (let i = arr.length - 1; i > 0; i--) {
212
+ const j = Math.floor(Math.random() * (i + 1));
213
+ [arr[i], arr[j]] = [arr[j], arr[i]];
214
+ }
215
+ }
216
+ //# sourceMappingURL=cluster.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cluster.js","sourceRoot":"","sources":["../../../src/search/cluster.ts"],"names":[],"mappings":"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"}