sverklo 0.2.12 → 0.2.13

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 (93) hide show
  1. package/README.md +102 -13
  2. package/dist/bin/sverklo.js +69 -1
  3. package/dist/bin/sverklo.js.map +1 -1
  4. package/dist/src/audit-prompt.d.ts +2 -0
  5. package/dist/src/audit-prompt.js +91 -0
  6. package/dist/src/audit-prompt.js.map +1 -0
  7. package/dist/src/doctor.js +55 -0
  8. package/dist/src/doctor.js.map +1 -1
  9. package/dist/src/indexer/embedding-providers.d.ts +34 -0
  10. package/dist/src/indexer/embedding-providers.js +215 -0
  11. package/dist/src/indexer/embedding-providers.js.map +1 -0
  12. package/dist/src/indexer/embedding-providers.test.d.ts +1 -0
  13. package/dist/src/indexer/embedding-providers.test.js +83 -0
  14. package/dist/src/indexer/embedding-providers.test.js.map +1 -0
  15. package/dist/src/indexer/indexer-freshness.test.d.ts +1 -0
  16. package/dist/src/indexer/indexer-freshness.test.js +109 -0
  17. package/dist/src/indexer/indexer-freshness.test.js.map +1 -0
  18. package/dist/src/indexer/indexer.d.ts +10 -0
  19. package/dist/src/indexer/indexer.js +46 -4
  20. package/dist/src/indexer/indexer.js.map +1 -1
  21. package/dist/src/indexer/watcher.js +4 -0
  22. package/dist/src/indexer/watcher.js.map +1 -1
  23. package/dist/src/memory/journal.d.ts +62 -0
  24. package/dist/src/memory/journal.js +136 -0
  25. package/dist/src/memory/journal.js.map +1 -0
  26. package/dist/src/memory/journal.test.d.ts +1 -0
  27. package/dist/src/memory/journal.test.js +98 -0
  28. package/dist/src/memory/journal.test.js.map +1 -0
  29. package/dist/src/modes.d.ts +16 -0
  30. package/dist/src/modes.js +104 -0
  31. package/dist/src/modes.js.map +1 -0
  32. package/dist/src/modes.test.d.ts +1 -0
  33. package/dist/src/modes.test.js +48 -0
  34. package/dist/src/modes.test.js.map +1 -0
  35. package/dist/src/search/hybrid-search.d.ts +22 -0
  36. package/dist/src/search/hybrid-search.js +167 -5
  37. package/dist/src/search/hybrid-search.js.map +1 -1
  38. package/dist/src/search/hybrid-search.test.d.ts +1 -0
  39. package/dist/src/search/hybrid-search.test.js +109 -0
  40. package/dist/src/search/hybrid-search.test.js.map +1 -0
  41. package/dist/src/search/token-budget.d.ts +1 -0
  42. package/dist/src/search/token-budget.js +1 -1
  43. package/dist/src/search/token-budget.js.map +1 -1
  44. package/dist/src/server/mcp-server.js +32 -25
  45. package/dist/src/server/mcp-server.js.map +1 -1
  46. package/dist/src/server/tool-overrides.d.ts +16 -0
  47. package/dist/src/server/tool-overrides.js +102 -0
  48. package/dist/src/server/tool-overrides.js.map +1 -0
  49. package/dist/src/server/tool-overrides.test.d.ts +1 -0
  50. package/dist/src/server/tool-overrides.test.js +124 -0
  51. package/dist/src/server/tool-overrides.test.js.map +1 -0
  52. package/dist/src/server/tools/context-budget.test.d.ts +1 -0
  53. package/dist/src/server/tools/context-budget.test.js +150 -0
  54. package/dist/src/server/tools/context-budget.test.js.map +1 -0
  55. package/dist/src/server/tools/context.d.ts +11 -1
  56. package/dist/src/server/tools/context.js +202 -8
  57. package/dist/src/server/tools/context.js.map +1 -1
  58. package/dist/src/server/tools/diff-heuristics.d.ts +28 -0
  59. package/dist/src/server/tools/diff-heuristics.js +213 -0
  60. package/dist/src/server/tools/diff-heuristics.js.map +1 -0
  61. package/dist/src/server/tools/diff-heuristics.test.d.ts +1 -0
  62. package/dist/src/server/tools/diff-heuristics.test.js +151 -0
  63. package/dist/src/server/tools/diff-heuristics.test.js.map +1 -0
  64. package/dist/src/server/tools/forget.js +3 -0
  65. package/dist/src/server/tools/forget.js.map +1 -1
  66. package/dist/src/server/tools/index-status.js +16 -0
  67. package/dist/src/server/tools/index-status.js.map +1 -1
  68. package/dist/src/server/tools/lookup.js +12 -13
  69. package/dist/src/server/tools/lookup.js.map +1 -1
  70. package/dist/src/server/tools/recall.d.ts +5 -1
  71. package/dist/src/server/tools/recall.js +66 -4
  72. package/dist/src/server/tools/recall.js.map +1 -1
  73. package/dist/src/server/tools/recall.test.d.ts +1 -0
  74. package/dist/src/server/tools/recall.test.js +116 -0
  75. package/dist/src/server/tools/recall.test.js.map +1 -0
  76. package/dist/src/server/tools/remember.js +14 -0
  77. package/dist/src/server/tools/remember.js.map +1 -1
  78. package/dist/src/server/tools/review-diff.js +31 -0
  79. package/dist/src/server/tools/review-diff.js.map +1 -1
  80. package/dist/src/server/tools/search.js +29 -4
  81. package/dist/src/server/tools/search.js.map +1 -1
  82. package/dist/src/server/tools/search.test.d.ts +1 -0
  83. package/dist/src/server/tools/search.test.js +118 -0
  84. package/dist/src/server/tools/search.test.js.map +1 -0
  85. package/dist/src/server/tools/tier.js +25 -1
  86. package/dist/src/server/tools/tier.js.map +1 -1
  87. package/dist/src/storage/chunk-store.d.ts +12 -0
  88. package/dist/src/storage/chunk-store.js +16 -0
  89. package/dist/src/storage/chunk-store.js.map +1 -1
  90. package/dist/src/storage/chunk-store.test.d.ts +1 -0
  91. package/dist/src/storage/chunk-store.test.js +69 -0
  92. package/dist/src/storage/chunk-store.test.js.map +1 -0
  93. package/package.json +5 -2
@@ -0,0 +1,124 @@
1
+ import { describe, it, expect, beforeEach } from "vitest";
2
+ import { applyToolOverrides, __resetToolOverrideCache } from "./tool-overrides.js";
3
+ // applyToolOverrides ships on every MCP session start and previously
4
+ // had zero test coverage. These tests lock in the env-var override +
5
+ // disable-list contract so a refactor can't silently change how tool
6
+ // visibility or descriptions are controlled.
7
+ const fixture = () => [
8
+ { name: "sverklo_search", description: "orig search", inputSchema: {} },
9
+ { name: "sverklo_refs", description: "orig refs", inputSchema: {} },
10
+ { name: "sverklo_forget", description: "orig forget", inputSchema: {} },
11
+ { name: "sverklo_remember", description: "orig remember", inputSchema: {} },
12
+ ];
13
+ describe("applyToolOverrides — description overrides", () => {
14
+ beforeEach(() => {
15
+ // Strip any SVERKLO_TOOL_* env vars from a previous test.
16
+ for (const key of Object.keys(process.env)) {
17
+ if (key.startsWith("SVERKLO_TOOL_") || key === "SVERKLO_DISABLED_TOOLS") {
18
+ delete process.env[key];
19
+ }
20
+ }
21
+ __resetToolOverrideCache();
22
+ });
23
+ it("returns tools unchanged when no env vars are set", () => {
24
+ const result = applyToolOverrides(fixture());
25
+ expect(result).toHaveLength(4);
26
+ expect(result.find((t) => t.name === "sverklo_search")?.description).toBe("orig search");
27
+ });
28
+ it("overrides a tool description via SVERKLO_TOOL_<NAME>_DESCRIPTION", () => {
29
+ process.env.SVERKLO_TOOL_SEARCH_DESCRIPTION = "use only for architecture decisions";
30
+ __resetToolOverrideCache();
31
+ const result = applyToolOverrides(fixture());
32
+ expect(result.find((t) => t.name === "sverklo_search")?.description).toBe("use only for architecture decisions");
33
+ // Other tools unchanged
34
+ expect(result.find((t) => t.name === "sverklo_refs")?.description).toBe("orig refs");
35
+ });
36
+ it("strips sverklo_ prefix when matching env var suffix", () => {
37
+ // Both SEARCH and REVIEW_DIFF-style names should work.
38
+ process.env.SVERKLO_TOOL_REMEMBER_DESCRIPTION = "project decision log only";
39
+ __resetToolOverrideCache();
40
+ const result = applyToolOverrides(fixture());
41
+ expect(result.find((t) => t.name === "sverklo_remember")?.description).toBe("project decision log only");
42
+ });
43
+ it("handles multi-word tool names (underscore-separated)", () => {
44
+ const tools = [
45
+ { name: "sverklo_review_diff", description: "orig", inputSchema: {} },
46
+ ];
47
+ process.env.SVERKLO_TOOL_REVIEW_DIFF_DESCRIPTION = "strict review";
48
+ __resetToolOverrideCache();
49
+ const result = applyToolOverrides(tools);
50
+ expect(result[0].description).toBe("strict review");
51
+ });
52
+ it("never mutates the input array or its objects", () => {
53
+ const input = fixture();
54
+ const inputRef = input[0];
55
+ const inputDescription = inputRef.description;
56
+ process.env.SVERKLO_TOOL_SEARCH_DESCRIPTION = "mutated";
57
+ __resetToolOverrideCache();
58
+ applyToolOverrides(input);
59
+ // Source object must be unchanged — overrides return fresh objects.
60
+ expect(inputRef.description).toBe(inputDescription);
61
+ });
62
+ it("ignores empty-string overrides (treats as unset)", () => {
63
+ process.env.SVERKLO_TOOL_SEARCH_DESCRIPTION = "";
64
+ __resetToolOverrideCache();
65
+ const result = applyToolOverrides(fixture());
66
+ expect(result.find((t) => t.name === "sverklo_search")?.description).toBe("orig search");
67
+ });
68
+ });
69
+ describe("applyToolOverrides — disable list", () => {
70
+ beforeEach(() => {
71
+ for (const key of Object.keys(process.env)) {
72
+ if (key.startsWith("SVERKLO_TOOL_") || key === "SVERKLO_DISABLED_TOOLS") {
73
+ delete process.env[key];
74
+ }
75
+ }
76
+ __resetToolOverrideCache();
77
+ });
78
+ it("hides a single tool named in SVERKLO_DISABLED_TOOLS", () => {
79
+ process.env.SVERKLO_DISABLED_TOOLS = "sverklo_forget";
80
+ __resetToolOverrideCache();
81
+ const result = applyToolOverrides(fixture());
82
+ expect(result.map((t) => t.name)).not.toContain("sverklo_forget");
83
+ expect(result).toHaveLength(3);
84
+ });
85
+ it("hides multiple comma-separated tools", () => {
86
+ process.env.SVERKLO_DISABLED_TOOLS = "sverklo_forget,sverklo_remember";
87
+ __resetToolOverrideCache();
88
+ const result = applyToolOverrides(fixture());
89
+ expect(result.map((t) => t.name)).toEqual(["sverklo_search", "sverklo_refs"]);
90
+ });
91
+ it("trims whitespace in the disabled list", () => {
92
+ process.env.SVERKLO_DISABLED_TOOLS = " sverklo_forget , sverklo_remember ";
93
+ __resetToolOverrideCache();
94
+ const result = applyToolOverrides(fixture());
95
+ expect(result).toHaveLength(2);
96
+ });
97
+ it("ignores unknown tool names in the disabled list (no-op)", () => {
98
+ process.env.SVERKLO_DISABLED_TOOLS = "sverklo_nonexistent,sverklo_search";
99
+ __resetToolOverrideCache();
100
+ const result = applyToolOverrides(fixture());
101
+ expect(result).toHaveLength(3);
102
+ expect(result.map((t) => t.name)).not.toContain("sverklo_search");
103
+ });
104
+ });
105
+ describe("applyToolOverrides — combined overrides", () => {
106
+ beforeEach(() => {
107
+ for (const key of Object.keys(process.env)) {
108
+ if (key.startsWith("SVERKLO_TOOL_") || key === "SVERKLO_DISABLED_TOOLS") {
109
+ delete process.env[key];
110
+ }
111
+ }
112
+ __resetToolOverrideCache();
113
+ });
114
+ it("applies description overrides and disable list together", () => {
115
+ process.env.SVERKLO_TOOL_SEARCH_DESCRIPTION = "custom";
116
+ process.env.SVERKLO_DISABLED_TOOLS = "sverklo_forget";
117
+ __resetToolOverrideCache();
118
+ const result = applyToolOverrides(fixture());
119
+ expect(result).toHaveLength(3);
120
+ expect(result.find((t) => t.name === "sverklo_search")?.description).toBe("custom");
121
+ expect(result.find((t) => t.name === "sverklo_forget")).toBeUndefined();
122
+ });
123
+ });
124
+ //# sourceMappingURL=tool-overrides.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-overrides.test.js","sourceRoot":"","sources":["../../../src/server/tool-overrides.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,150 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdtempSync, rmSync, writeFileSync, mkdirSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { Indexer } from "../../indexer/indexer.js";
6
+ import { getProjectConfig } from "../../utils/config.js";
7
+ import { handleContext } from "./context.js";
8
+ // Tests for the sverklo_context --budget N repo-map mode (issue #8).
9
+ // These lock in the deterministic-ordering contract (same index +
10
+ // same budget = same output), the budget clamping behavior, and the
11
+ // exclude filter. We build a tiny real project so the tests exercise
12
+ // the actual PageRank + chunk iteration, not a mock.
13
+ describe("handleContext (budget mode)", () => {
14
+ let tmpRoot;
15
+ let indexer;
16
+ beforeEach(async () => {
17
+ tmpRoot = mkdtempSync(join(tmpdir(), "sverklo-context-budget-"));
18
+ mkdirSync(join(tmpRoot, "src"), { recursive: true });
19
+ mkdirSync(join(tmpRoot, "test"), { recursive: true });
20
+ // Seed a few files with different sizes so PageRank has something
21
+ // to differentiate. The exact rankings don't matter — we only
22
+ // assert that output is stable and contains expected path markers.
23
+ writeFileSync(join(tmpRoot, "src", "core.ts"), [
24
+ "export function load() { return 1; }",
25
+ "export function save() { return 2; }",
26
+ "export function reset() { return 3; }",
27
+ ].join("\n"), "utf-8");
28
+ writeFileSync(join(tmpRoot, "src", "helpers.ts"), [
29
+ "import { load } from './core';",
30
+ "export function helper1() { return load(); }",
31
+ "export function helper2() { return load(); }",
32
+ ].join("\n"), "utf-8");
33
+ writeFileSync(join(tmpRoot, "test", "core.test.ts"), [
34
+ "export function runTests() { return 'all-green'; }",
35
+ "export function setupSuite() { return {}; }",
36
+ ].join("\n"), "utf-8");
37
+ const cfg = getProjectConfig(tmpRoot);
38
+ indexer = new Indexer(cfg);
39
+ await indexer.index();
40
+ });
41
+ afterEach(() => {
42
+ try {
43
+ indexer.close();
44
+ }
45
+ catch { }
46
+ try {
47
+ rmSync(tmpRoot, { recursive: true, force: true });
48
+ }
49
+ catch { }
50
+ });
51
+ it("returns a repo-map-shaped response when budget is set", async () => {
52
+ const out = await handleContext(indexer, { budget: 2000 });
53
+ expect(out).toContain("# Repo map");
54
+ expect(out).toContain("Budget: 2000 tokens");
55
+ expect(out).toContain("PageRank");
56
+ });
57
+ it("produces identical output for identical inputs (determinism contract)", async () => {
58
+ const a = await handleContext(indexer, { budget: 2000 });
59
+ const b = await handleContext(indexer, { budget: 2000 });
60
+ expect(a).toBe(b);
61
+ });
62
+ it("works without a task (pure PageRank ordering)", async () => {
63
+ const out = await handleContext(indexer, { budget: 2000 });
64
+ expect(out).not.toContain("centered on");
65
+ expect(out).toContain("PageRank");
66
+ });
67
+ it("accepts a task parameter and advertises the bias in the header", async () => {
68
+ const out = await handleContext(indexer, {
69
+ budget: 2000,
70
+ task: "understand loading logic",
71
+ });
72
+ expect(out).toContain("centered on: understand loading logic");
73
+ expect(out).toContain("task relevance");
74
+ });
75
+ it("respects the exclude filter", async () => {
76
+ const withTests = await handleContext(indexer, { budget: 4000, exclude: [] });
77
+ const withoutTests = await handleContext(indexer, {
78
+ budget: 4000,
79
+ exclude: ["test"],
80
+ });
81
+ // The test file should appear in the unfiltered version but not
82
+ // in the filtered one.
83
+ expect(withTests).toContain("core.test.ts");
84
+ expect(withoutTests).not.toContain("core.test.ts");
85
+ });
86
+ it("clamps budgets above the max and emits a warning line", async () => {
87
+ const out = await handleContext(indexer, { budget: 100_000 });
88
+ expect(out).toContain("clamped");
89
+ // The stated budget in the header should be the clamp ceiling,
90
+ // not the original request.
91
+ expect(out).toContain("32000");
92
+ });
93
+ it("rejects budgets below the minimum with a helpful message", async () => {
94
+ const out = await handleContext(indexer, { budget: 100 });
95
+ expect(out).toContain("Budget too small");
96
+ expect(out).toContain("Minimum");
97
+ });
98
+ it("scope filter restricts the map to matching paths", async () => {
99
+ const out = await handleContext(indexer, { budget: 2000, scope: "src/" });
100
+ expect(out).toContain("src/");
101
+ expect(out).not.toContain("test/core.test.ts");
102
+ });
103
+ it("reports a footer with rendered count and remaining-files hint", async () => {
104
+ const out = await handleContext(indexer, { budget: 2000 });
105
+ // "Rendered N of M files" footer is always present when the mode
106
+ // ran to completion.
107
+ expect(out).toMatch(/Rendered \d+ of \d+ files/);
108
+ });
109
+ it("falls back gracefully when task search fails internally", async () => {
110
+ // Even if search blows up, the map must still render in pure
111
+ // PageRank mode rather than returning an error. We can't easily
112
+ // force hybridSearch to throw here without monkey-patching, so
113
+ // we assert the contract indirectly: a task with zero meaningful
114
+ // matches should still produce a valid map.
115
+ const out = await handleContext(indexer, {
116
+ budget: 2000,
117
+ task: "zzzzz totally unrelated gibberish query",
118
+ });
119
+ expect(out).toContain("# Repo map");
120
+ expect(out).toMatch(/Rendered \d+ of \d+ files/);
121
+ });
122
+ });
123
+ // Separate suite: error / missing-task behavior when budget is NOT set.
124
+ describe("handleContext (non-budget mode)", () => {
125
+ let tmpRoot;
126
+ let indexer;
127
+ beforeEach(async () => {
128
+ tmpRoot = mkdtempSync(join(tmpdir(), "sverklo-context-nobudget-"));
129
+ mkdirSync(join(tmpRoot, "src"), { recursive: true });
130
+ writeFileSync(join(tmpRoot, "src", "a.ts"), "export const a = 1;\n", "utf-8");
131
+ const cfg = getProjectConfig(tmpRoot);
132
+ indexer = new Indexer(cfg);
133
+ await indexer.index();
134
+ });
135
+ afterEach(() => {
136
+ try {
137
+ indexer.close();
138
+ }
139
+ catch { }
140
+ try {
141
+ rmSync(tmpRoot, { recursive: true, force: true });
142
+ }
143
+ catch { }
144
+ });
145
+ it("still requires a task when budget is not set", async () => {
146
+ const out = await handleContext(indexer, {});
147
+ expect(out).toContain("required");
148
+ });
149
+ });
150
+ //# sourceMappingURL=context-budget.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-budget.test.js","sourceRoot":"","sources":["../../../../src/server/tools/context-budget.test.ts"],"names":[],"mappings":"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"}
@@ -18,8 +18,18 @@ export declare const contextTool: {
18
18
  type: string;
19
19
  description: string;
20
20
  };
21
+ budget: {
22
+ type: string;
23
+ description: string;
24
+ };
25
+ exclude: {
26
+ type: string;
27
+ items: {
28
+ type: string;
29
+ };
30
+ description: string;
31
+ };
21
32
  };
22
- required: string[];
23
33
  };
24
34
  };
25
35
  export declare function handleContext(indexer: Indexer, args: Record<string, unknown>): Promise<string>;
@@ -12,39 +12,65 @@
12
12
  // full — normal + dependency neighbours of top results
13
13
  import { hybridSearch } from "../../search/hybrid-search.js";
14
14
  import { handleRecall } from "./recall.js";
15
+ import { estimateTokens } from "../../utils/tokens.js";
15
16
  export const contextTool = {
16
17
  name: "sverklo_context",
17
18
  description: "Umbrella context bundler. Give a task description and get a single curated bundle: " +
18
19
  "codebase overview header, semantically relevant code, related symbols, and matching " +
19
20
  "saved memories — in one round trip. Use this as the FIRST call when you start working " +
20
- "on a new task and want to orient quickly. Drill down with the atomic tools (search, " +
21
- "lookup, refs, recall) only after this.",
21
+ "on a new task and want to orient quickly. " +
22
+ "PASS `budget` for a PageRank-pruned repo map fit to a token budget — the ideal way " +
23
+ "to give an agent a complete mental model of an unfamiliar codebase in one call.",
22
24
  inputSchema: {
23
25
  type: "object",
24
26
  properties: {
25
27
  task: {
26
28
  type: "string",
27
- description: "Free-form description of what you're trying to do, e.g. 'add rate limiting to the login endpoint' or 'understand how billing webhooks are processed'.",
29
+ description: "Free-form description of what you're trying to do, e.g. 'add rate limiting to the login endpoint' or 'understand how billing webhooks are processed'. When `budget` is set and no task is given, returns a pure PageRank-ordered repo map.",
28
30
  },
29
31
  detail_level: {
30
32
  type: "string",
31
33
  enum: ["minimal", "normal", "full"],
32
- description: "How much to return. minimal=fast/cheap (good for snap orientation); normal=balanced (default); full=adds dependency neighbours.",
34
+ description: "How much to return. minimal=fast/cheap (good for snap orientation); normal=balanced (default); full=adds dependency neighbours. Ignored when `budget` is set.",
33
35
  },
34
36
  scope: {
35
37
  type: "string",
36
38
  description: "Optional path prefix to constrain the search (e.g. 'src/api/').",
37
39
  },
40
+ budget: {
41
+ type: "number",
42
+ description: "When set, returns a PageRank-pruned repo map greedily filled to this token budget (inspired by aider's repo-map). Files are ordered by PageRank importance, optionally biased toward `task`. Only symbol signatures are rendered — use the atomic tools for full bodies. Typical values: 4000 (snap map), 8000 (full mental model), 16000 (deep context).",
43
+ },
44
+ exclude: {
45
+ type: "array",
46
+ items: { type: "string" },
47
+ description: "Path substrings to exclude from the repo map (e.g. ['test', 'migration']).",
48
+ },
38
49
  },
39
- required: ["task"],
40
50
  },
41
51
  };
42
52
  export async function handleContext(indexer, args) {
43
- const task = args.task?.trim();
44
- if (!task)
45
- return "Error: `task` is required.";
53
+ const task = args.task?.trim() || "";
46
54
  const detail = (args.detail_level || "normal");
47
55
  const scope = args.scope;
56
+ const budget = args.budget;
57
+ const exclude = args.exclude || [];
58
+ // ── Budget mode: PageRank-pruned repo map (issue #8) ──────────────
59
+ // When budget is set, we skip the standard search-based bundler and
60
+ // instead build a dense structural map greedily filled to the target
61
+ // token count. This is the "give the agent a complete mental model
62
+ // of an unfamiliar repo in one call" path — aider's repo-map pattern.
63
+ if (typeof budget === "number" && budget > 0) {
64
+ return await buildPrunedRepoMap(indexer, {
65
+ budget,
66
+ task,
67
+ scope,
68
+ exclude,
69
+ });
70
+ }
71
+ if (!task) {
72
+ return "Error: `task` is required (unless you pass `budget` for a pure repo map).";
73
+ }
48
74
  const searchLimit = detail === "minimal" ? 3 : detail === "normal" ? 5 : 8;
49
75
  const memoryLimit = detail === "minimal" ? 2 : 5;
50
76
  const tokenBudget = detail === "minimal" ? 1500 : detail === "normal" ? 3000 : 5000;
@@ -159,4 +185,172 @@ export async function handleContext(indexer, args) {
159
185
  }
160
186
  return parts.join("\n");
161
187
  }
188
+ // ─────────────────────────────────────────────────────────────────────
189
+ // Issue #8 — PageRank-pruned repo map fit to a token budget.
190
+ //
191
+ // Design (mirrors aider's repo-map, adapted to sverklo's symbol graph):
192
+ //
193
+ // 1. Rank files by PageRank DESC.
194
+ // 2. If a task was provided, run a semantic search and upweight files
195
+ // that contain strong matches. This lets the map center on the
196
+ // subsystem the user is working in, instead of always the global
197
+ // hub files.
198
+ // 3. Walk files in ranked order; for each, render signatures of its
199
+ // most important symbols (also ordered by PageRank proxy).
200
+ // 4. Greedily fill the budget. Stop the instant adding the next file
201
+ // would exceed the cap. The output is deterministic given the
202
+ // same index state and budget — important for caching.
203
+ //
204
+ // Determinism note: we break PageRank ties by file path to keep output
205
+ // stable across runs of the same input. This matters for caching and
206
+ // snapshot-testing downstream.
207
+ // ─────────────────────────────────────────────────────────────────────
208
+ // Upper bound on the repo-map budget. Anything above 32k tokens is
209
+ // almost certainly a mistake — the resulting map won't fit in any
210
+ // current model's context window and the wall-clock cost of walking
211
+ // every file climbs linearly. We cap and emit a warning in the
212
+ // output so the caller knows we trimmed.
213
+ const MAX_REPO_MAP_BUDGET = 32000;
214
+ const MIN_REPO_MAP_BUDGET = 500;
215
+ async function buildPrunedRepoMap(indexer, opts) {
216
+ let { budget } = opts;
217
+ const { task, scope, exclude } = opts;
218
+ // Clamp the budget to sane bounds. Sub-500 can't even fit a header
219
+ // + one file meaningfully; over 32k is nearly always unintentional.
220
+ let budgetWarning = "";
221
+ if (budget > MAX_REPO_MAP_BUDGET) {
222
+ budgetWarning = `_Budget ${budget} exceeded max ${MAX_REPO_MAP_BUDGET} — clamped. For larger maps, use multiple scoped calls._\n\n`;
223
+ budget = MAX_REPO_MAP_BUDGET;
224
+ }
225
+ else if (budget < MIN_REPO_MAP_BUDGET) {
226
+ return (`Budget too small: ${budget}. Minimum is ${MIN_REPO_MAP_BUDGET} tokens — ` +
227
+ `below that the repo map can't fit a useful number of files. ` +
228
+ `Try \`budget: ${MIN_REPO_MAP_BUDGET}\` for a snap view.`);
229
+ }
230
+ // Pull all files sorted by PageRank. file_store.getAll() already
231
+ // returns them in pagerank DESC order — see storage/file-store.ts.
232
+ let files = indexer.fileStore.getAll();
233
+ // Apply scope prefix and exclude substrings.
234
+ if (scope) {
235
+ files = files.filter((f) => f.path.startsWith(scope));
236
+ }
237
+ if (exclude.length > 0) {
238
+ files = files.filter((f) => !exclude.some((ex) => f.path.includes(ex)));
239
+ }
240
+ // Task-biased reranking: if the caller gave us a task, run a search
241
+ // and boost files that contain strong matches. We keep the PageRank
242
+ // signal as the primary order and only use the task signal as a
243
+ // tiebreaker / boost — so the output is still dominated by the
244
+ // structural importance of the codebase, not by query noise.
245
+ const taskBoost = new Map();
246
+ if (task) {
247
+ try {
248
+ const hits = await hybridSearch(indexer, {
249
+ query: task,
250
+ tokenBudget: 50000, // ask for a lot so boost is meaningful
251
+ scope,
252
+ type: "any",
253
+ });
254
+ // Accumulate score per file across all hits.
255
+ for (const h of hits) {
256
+ taskBoost.set(h.chunk.file_id, (taskBoost.get(h.chunk.file_id) || 0) + h.score);
257
+ }
258
+ }
259
+ catch {
260
+ // Fall back to pure PageRank if search fails — never block the map.
261
+ }
262
+ }
263
+ // Stable ranking: compose PageRank with the task boost, break ties
264
+ // by path so the same input always produces the same output.
265
+ const ranked = [...files].sort((a, b) => {
266
+ const ba = (taskBoost.get(a.id) || 0) * 0.5 + a.pagerank;
267
+ const bb = (taskBoost.get(b.id) || 0) * 0.5 + b.pagerank;
268
+ if (bb !== ba)
269
+ return bb - ba;
270
+ return a.path.localeCompare(b.path);
271
+ });
272
+ // Header first so the caller can still see the budget and ordering
273
+ // even when the budget is tiny and zero files fit.
274
+ const parts = [];
275
+ parts.push(`# Repo map${task ? ` · centered on: ${task}` : ""}${scope ? ` · scope: ${scope}` : ""}`);
276
+ parts.push(`_Budget: ${budget} tokens · ordered by PageRank${task ? " + task relevance" : ""}._`);
277
+ if (budgetWarning)
278
+ parts.push(budgetWarning);
279
+ parts.push("");
280
+ // Remaining budget after the header. 10% cushion for the trailing
281
+ // footer text and any rendering slack. Token estimates are rough —
282
+ // we use the same estimator as the indexer (chars / 3.5).
283
+ const headerCost = estimateTokens(parts.join("\n"));
284
+ let remaining = budget - headerCost - 100;
285
+ let filesRendered = 0;
286
+ let filesSkipped = 0;
287
+ for (const file of ranked) {
288
+ if (remaining <= 0) {
289
+ filesSkipped = ranked.length - filesRendered;
290
+ break;
291
+ }
292
+ // Pull the file's symbols. We only render symbol signatures
293
+ // (cheap) plus the symbol's name and type. Full bodies would
294
+ // blow the budget instantly — the point of a map is to be a
295
+ // legend, not the terrain.
296
+ const chunks = indexer.chunkStore
297
+ .getByFile(file.id)
298
+ .filter((c) => c.name);
299
+ if (chunks.length === 0)
300
+ continue;
301
+ // Render the file's entry. Symbols are ordered as they appear in
302
+ // the file (by start_line). Top-level types/classes come first in
303
+ // most codebases so this matches how a human skims.
304
+ const fileHeader = `## \`${file.path}\` · PR ${file.pagerank.toFixed(3)} · ${file.language || "?"}`;
305
+ const fileLines = [fileHeader];
306
+ // Soft cap on symbols-per-file so one massive file doesn't eat the
307
+ // whole budget. Files with >40 symbols render as "+ N more".
308
+ const CAP_PER_FILE = 40;
309
+ const shown = chunks.slice(0, CAP_PER_FILE);
310
+ for (const c of shown) {
311
+ const sig = c.signature ? c.signature.trim() : `${c.type} ${c.name}`;
312
+ // Keep each line short — the map should scan like an outline.
313
+ const truncated = sig.length > 110 ? sig.slice(0, 107) + "..." : sig;
314
+ fileLines.push(`- ${truncated}`);
315
+ }
316
+ if (chunks.length > CAP_PER_FILE) {
317
+ fileLines.push(`- _...and ${chunks.length - CAP_PER_FILE} more symbols_`);
318
+ }
319
+ const entry = fileLines.join("\n") + "\n";
320
+ const cost = estimateTokens(entry);
321
+ // If a single file's entry exceeds the remaining budget, render a
322
+ // truncated version (just the header + symbol count) so the caller
323
+ // still knows the file exists. Never render a partial entry with
324
+ // half its symbols cut off — that's confusing.
325
+ if (cost > remaining) {
326
+ const fallback = `## \`${file.path}\` · PR ${file.pagerank.toFixed(3)}\n` +
327
+ `- _${chunks.length} symbols (budget exhausted — use sverklo_lookup for details)_\n`;
328
+ const fallbackCost = estimateTokens(fallback);
329
+ if (fallbackCost <= remaining) {
330
+ parts.push(fallback);
331
+ remaining -= fallbackCost;
332
+ filesRendered++;
333
+ }
334
+ else {
335
+ filesSkipped = ranked.length - filesRendered;
336
+ break;
337
+ }
338
+ }
339
+ else {
340
+ parts.push(entry);
341
+ remaining -= cost;
342
+ filesRendered++;
343
+ }
344
+ }
345
+ // Footer
346
+ parts.push("");
347
+ parts.push(`_Rendered ${filesRendered} of ${ranked.length} files` +
348
+ (filesSkipped > 0
349
+ ? ` (${filesSkipped} skipped — budget exhausted; raise \`budget\` to see more)_`
350
+ : "_"));
351
+ if (filesRendered > 0) {
352
+ parts.push("_Use `sverklo_lookup name:<symbol>` or `sverklo_search query:<...>` to drill into any symbol._");
353
+ }
354
+ return parts.join("\n");
355
+ }
162
356
  //# sourceMappingURL=context.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","sourceRoot":"","sources":["../../../../src/server/tools/context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../../../src/server/tools/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ export interface DiffHunk {
2
+ filePath: string;
3
+ oldStart: number;
4
+ newStart: number;
5
+ /** Every line in the hunk, including context. Each entry is "+ ", "- ", " " followed by content. */
6
+ lines: string[];
7
+ }
8
+ export interface HeuristicFinding {
9
+ heuristic: string;
10
+ severity: "high" | "medium" | "low";
11
+ file: string;
12
+ line: number;
13
+ snippet: string;
14
+ message: string;
15
+ }
16
+ export declare function findUnguardedStreamCalls(hunks: DiffHunk[]): HeuristicFinding[];
17
+ export declare const ALL_HEURISTICS: ((hunks: DiffHunk[]) => HeuristicFinding[])[];
18
+ export declare function runAllHeuristics(hunks: DiffHunk[]): HeuristicFinding[];
19
+ /**
20
+ * Parse a unified-diff string (output of `git diff -U5 ref`) into hunks.
21
+ * Very permissive — anything that doesn't match the expected header is
22
+ * skipped rather than raising.
23
+ */
24
+ export declare function parseUnifiedDiff(diffText: string): DiffHunk[];
25
+ /**
26
+ * Convenience: pull a unified diff from git and parse it.
27
+ */
28
+ export declare function getDiffHunks(rootPath: string, ref: string): DiffHunk[];