sigmap 8.21.0 → 8.22.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.
- package/CHANGELOG.md +13 -0
- package/README.md +9 -9
- package/gen-context.js +93 -3
- package/llms-full.txt +5 -5
- package/llms.txt +5 -5
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/core/package.json +1 -1
- package/src/eval/corpus.js +83 -0
- package/src/eval/runner.js +2 -1
- package/src/mcp/server.js +1 -1
- package/src/tracking/pricing.js +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,19 @@ Format: [Semantic Versioning](https://semver.org/)
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
+
## [8.22.0] — 2026-07-28
|
|
14
|
+
|
|
15
|
+
Minor release — **"Hard Corpus" (v8.22)**: the benchmark corpus gains a no-leakage hard split with a deterministic leakage gate, and per-repo-size buckets stop tiny repos from flattering the average. The headline retrieval number gets harder — and honest.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- **Hard-split corpus + leakage gate + size buckets (#505, PR #506):** new `src/eval/corpus.js` — a task "leaks" when its BM25-tokenized query shares a stemmed token with the tokenized basenames of its expected files; `validateTasks` flags leaky `split: "hard"` tasks as violations, and `sizeBucket` groups repos at 200/1000 scanned files (tertiles of the 43-repo corpus). New CI gate `scripts/validate-task-corpus.mjs` (exit 1 on hard-split leakage). `loadTasks` carries the optional `split` field (default `easy`). `benchmark:honest` now reports hit@5/MRR per split and per size bucket — buckets use files scanned on disk, not the budget-capped context index. 15 hand-authored hard tasks (express, flask, axios, fastify, gin), all leak-free. 8 new integration tests (128 test files).
|
|
19
|
+
- **MiniMax LLM-ablation provider (PR #504)** — thanks @octo-patch: `MINIMAX_API_KEY` support in `scripts/run-llm-ablation.mjs` (OpenAI-compatible endpoint, default model MiniMax-M3, `MINIMAX_BASE_URL` override) plus a pricing entry and tests.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- **Headline honesty, again:** the leakage gate measured that **90 of 110 pre-existing easy tasks leak filename tokens**, and the new hard split scores **33.3% hit@5 vs the grep baseline's 53.3%** — with leakage removed, grep currently wins; that measured vocabulary-mismatch ceiling is what B2 (repo-mined expansion, v9.0) exists to attack. Overall corpus (125 tasks): 72.8% hit@5, honest lift 1.63× (+28pt).
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
13
26
|
## [8.21.0] — 2026-07-19
|
|
14
27
|
|
|
15
28
|
Minor release — **"Semantic Bridge II" (v8.21)**: doc-comment hints reach Go, Rust, and Java, and the import graph gains a principled centrality prior for ranking — flag-gated and measured.
|
package/README.md
CHANGED
|
@@ -59,10 +59,10 @@ That map is exactly what agentic grep is worst at: reproducible, auditable conte
|
|
|
59
59
|
|
|
60
60
|
**Proof it pays off** (full benchmark below):
|
|
61
61
|
<!--SM:whyMetrics-->
|
|
62
|
-
- **
|
|
62
|
+
- **82.2% hit@5** — right file in top 5 results (vs 44.8% single-shot grep baseline — 1.59× lift)
|
|
63
63
|
- **96.8% token reduction** — average across 21 real repos
|
|
64
|
-
- **
|
|
65
|
-
- **1.
|
|
64
|
+
- **64.8% task-success proxy** — modeled from retrieval tiers, not measured LLM sessions
|
|
65
|
+
- **1.53 prompts per task** — down from 2.84 (46.1% fewer retries, modeled)
|
|
66
66
|
<!--/SM:whyMetrics-->
|
|
67
67
|
- **<!--SM:languages-->33<!--/SM:languages--> languages supported** — TypeScript, Python, Go, Rust, Java, R, and more
|
|
68
68
|
- **No vendor lock-in** — works with any AI assistant or local LLM
|
|
@@ -98,7 +98,7 @@ sigmap verify answer.md --report # standalone red/amber/green HTML report
|
|
|
98
98
|
| Without SigMap | With SigMap |
|
|
99
99
|
|---|---|
|
|
100
100
|
| ❌ Non-reproducible agent guesses | ✅ Deterministic map — same input, same output, every time |
|
|
101
|
-
| ❌ "Trust me" AI answers | ✅ Grounded — right file in context <!--SM:hitWhole-->
|
|
101
|
+
| ❌ "Trust me" AI answers | ✅ Grounded — right file in context <!--SM:hitWhole-->82%<!--/SM:hitWhole--> of the time, every symbol on a real line anchor |
|
|
102
102
|
| ❌ Embeddings / vector DB required | ✅ Zero deps, no infra, fully offline |
|
|
103
103
|
|
|
104
104
|
---
|
|
@@ -122,13 +122,13 @@ Ask → Rank → Context → Validate → Judge → Learn
|
|
|
122
122
|
|
|
123
123
|
<!--SM:benchmarkBlock-->
|
|
124
124
|
```
|
|
125
|
-
Benchmark : sigmap-v8.
|
|
126
|
-
Date : 2026-07-
|
|
125
|
+
Benchmark : sigmap-v8.22-main (21 repositories, including R language)
|
|
126
|
+
Date : 2026-07-27
|
|
127
127
|
|
|
128
|
-
Hit@5 :
|
|
128
|
+
Hit@5 : 82.2% (grep-agent baseline 44.8% — 1.59× lift)
|
|
129
129
|
Token reduction: 96.8% (across 21 repos)
|
|
130
|
-
Prompt reduction :
|
|
131
|
-
Task success :
|
|
130
|
+
Prompt reduction : 46.1% (2.84 → 1.53 prompts per task, modeled)
|
|
131
|
+
Task success : 64.8% (proxy — modeled from retrieval tiers)
|
|
132
132
|
Repos tested : 21 (JavaScript, Python, Go, Rust, Java, R, C++, C#, Dart, Swift, Ruby, PHP, Scala, Kotlin, and more)
|
|
133
133
|
```
|
|
134
134
|
<!--/SM:benchmarkBlock-->
|
package/gen-context.js
CHANGED
|
@@ -4101,6 +4101,93 @@ __factories["./src/eval/analyzer"] = function(module, exports) {
|
|
|
4101
4101
|
|
|
4102
4102
|
};
|
|
4103
4103
|
|
|
4104
|
+
// ── ./src/eval/corpus ──
|
|
4105
|
+
__factories["./src/eval/corpus"] = function(module, exports) {
|
|
4106
|
+
|
|
4107
|
+
/**
|
|
4108
|
+
* Task-corpus hygiene (A3, v8.22 "Hard Corpus").
|
|
4109
|
+
*
|
|
4110
|
+
* A benchmark query "leaks" when it shares a token with the basenames of its
|
|
4111
|
+
* expected files — hit@5 then partly measures filename matching, not
|
|
4112
|
+
* retrieval. The criterion is deterministic and reuses the production
|
|
4113
|
+
* tokenizer (identifier splitting + stemming from src/retrieval/bm25.js), so
|
|
4114
|
+
* "payments" leaks against payment.js and "InterceptorManager" leaks against
|
|
4115
|
+
* "interceptor manager" the same way the ranker would see them.
|
|
4116
|
+
*
|
|
4117
|
+
* Tasks carry an optional `split` field: 'hard' tasks MUST be leak-free
|
|
4118
|
+
* (validateTasks reports them as violations); 'easy' tasks (the default) may
|
|
4119
|
+
* leak — that is what makes them easy.
|
|
4120
|
+
*
|
|
4121
|
+
* Size buckets group repos by indexed file count so large repos stop being
|
|
4122
|
+
* averaged away by tiny ones. Thresholds are the rough tertiles of the
|
|
4123
|
+
* current benchmarks/repos corpus (43 repos, 27–3450 source files).
|
|
4124
|
+
*/
|
|
4125
|
+
|
|
4126
|
+
const { tokenize } = __require('./src/retrieval/bm25');
|
|
4127
|
+
|
|
4128
|
+
const BUCKET_LIMITS = { small: 200, medium: 1000 }; // files; large = above medium
|
|
4129
|
+
|
|
4130
|
+
/**
|
|
4131
|
+
* Stemmed tokens of a file path's basename (extension stripped).
|
|
4132
|
+
* @param {string} filePath
|
|
4133
|
+
* @returns {string[]}
|
|
4134
|
+
*/
|
|
4135
|
+
function basenameTokens(filePath) {
|
|
4136
|
+
const base = String(filePath).split('/').pop() || '';
|
|
4137
|
+
return tokenize(base.replace(/\.[^.]*$/, ''));
|
|
4138
|
+
}
|
|
4139
|
+
|
|
4140
|
+
/**
|
|
4141
|
+
* Leaked tokens between a query and its expected files' basenames.
|
|
4142
|
+
* @param {string} query
|
|
4143
|
+
* @param {string[]} expectedFiles
|
|
4144
|
+
* @returns {{ leaked: string[], clean: boolean }}
|
|
4145
|
+
*/
|
|
4146
|
+
function queryLeakage(query, expectedFiles) {
|
|
4147
|
+
const qToks = new Set(tokenize(query));
|
|
4148
|
+
const leaked = new Set();
|
|
4149
|
+
for (const f of expectedFiles || []) {
|
|
4150
|
+
for (const t of basenameTokens(f)) {
|
|
4151
|
+
if (qToks.has(t)) leaked.add(t);
|
|
4152
|
+
}
|
|
4153
|
+
}
|
|
4154
|
+
return { leaked: [...leaked].sort(), clean: leaked.size === 0 };
|
|
4155
|
+
}
|
|
4156
|
+
|
|
4157
|
+
/**
|
|
4158
|
+
* Validate a task list: every task gets a leakage result; hard-split tasks
|
|
4159
|
+
* that leak are violations.
|
|
4160
|
+
* @param {Array<{id?:string, query:string, expected_files?:string[], split?:string}>} tasks
|
|
4161
|
+
* @returns {{ results: object[], hardViolations: object[] }}
|
|
4162
|
+
*/
|
|
4163
|
+
function validateTasks(tasks) {
|
|
4164
|
+
const results = [];
|
|
4165
|
+
const hardViolations = [];
|
|
4166
|
+
for (const t of tasks || []) {
|
|
4167
|
+
const split = t.split === 'hard' ? 'hard' : 'easy';
|
|
4168
|
+
const { leaked, clean } = queryLeakage(t.query, t.expected_files);
|
|
4169
|
+
const row = { id: t.id || '?', split, leaked, clean };
|
|
4170
|
+
results.push(row);
|
|
4171
|
+
if (split === 'hard' && !clean) hardViolations.push(row);
|
|
4172
|
+
}
|
|
4173
|
+
return { results, hardViolations };
|
|
4174
|
+
}
|
|
4175
|
+
|
|
4176
|
+
/**
|
|
4177
|
+
* Size bucket for a repo by indexed file count.
|
|
4178
|
+
* @param {number} fileCount
|
|
4179
|
+
* @returns {'small'|'medium'|'large'}
|
|
4180
|
+
*/
|
|
4181
|
+
function sizeBucket(fileCount) {
|
|
4182
|
+
if (fileCount < BUCKET_LIMITS.small) return 'small';
|
|
4183
|
+
if (fileCount <= BUCKET_LIMITS.medium) return 'medium';
|
|
4184
|
+
return 'large';
|
|
4185
|
+
}
|
|
4186
|
+
|
|
4187
|
+
module.exports = { basenameTokens, queryLeakage, validateTasks, sizeBucket, BUCKET_LIMITS };
|
|
4188
|
+
|
|
4189
|
+
};
|
|
4190
|
+
|
|
4104
4191
|
// ── ./src/eval/llm-ablation ──
|
|
4105
4192
|
__factories["./src/eval/llm-ablation"] = function(module, exports) {
|
|
4106
4193
|
|
|
@@ -4400,7 +4487,7 @@ __factories["./src/eval/runner"] = function(module, exports) {
|
|
|
4400
4487
|
|
|
4401
4488
|
/**
|
|
4402
4489
|
* Load tasks from a JSONL file.
|
|
4403
|
-
* Each line: { id, query, expected_files, repo }
|
|
4490
|
+
* Each line: { id, query, expected_files, repo, split? ('easy'|'hard') }
|
|
4404
4491
|
* Invalid or blank lines are silently skipped.
|
|
4405
4492
|
* @param {string} tasksFile - absolute or relative path
|
|
4406
4493
|
* @returns {Array<{id:string, query:string, expected:string[], repo:string}>}
|
|
@@ -4420,6 +4507,7 @@ __factories["./src/eval/runner"] = function(module, exports) {
|
|
|
4420
4507
|
query: obj.query,
|
|
4421
4508
|
expected: obj.expected_files,
|
|
4422
4509
|
repo: obj.repo || '.',
|
|
4510
|
+
split: obj.split === 'hard' ? 'hard' : 'easy',
|
|
4423
4511
|
});
|
|
4424
4512
|
}
|
|
4425
4513
|
} catch {
|
|
@@ -14850,7 +14938,7 @@ __factories["./src/mcp/server"] = function(module, exports) {
|
|
|
14850
14938
|
|
|
14851
14939
|
const SERVER_INFO = {
|
|
14852
14940
|
name: 'sigmap',
|
|
14853
|
-
version: '8.
|
|
14941
|
+
version: '8.22.0',
|
|
14854
14942
|
description: 'SigMap MCP server — code signatures on demand',
|
|
14855
14943
|
};
|
|
14856
14944
|
|
|
@@ -18544,6 +18632,8 @@ __factories["./src/tracking/pricing"] = function(module, exports) {
|
|
|
18544
18632
|
'gpt-4o-mini': 0.15,
|
|
18545
18633
|
'gemini-1.5-pro': 1.25,
|
|
18546
18634
|
'gemini-1.5-flash': 0.075,
|
|
18635
|
+
'minimax-m3': 0.6,
|
|
18636
|
+
'minimax-m2.7': 0.3,
|
|
18547
18637
|
};
|
|
18548
18638
|
|
|
18549
18639
|
const DEFAULT_MODEL = 'claude-sonnet';
|
|
@@ -20068,7 +20158,7 @@ function __tryGit(args, opts = {}) {
|
|
|
20068
20158
|
catch (_) { return ''; }
|
|
20069
20159
|
}
|
|
20070
20160
|
|
|
20071
|
-
const VERSION = '8.
|
|
20161
|
+
const VERSION = '8.22.0';
|
|
20072
20162
|
const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
|
|
20073
20163
|
|
|
20074
20164
|
function requireSourceOrBundled(key) {
|
package/llms-full.txt
CHANGED
|
@@ -11,20 +11,20 @@ ranking keeps the relevant context in scope (cutting tokens ~97% as a side
|
|
|
11
11
|
effect), with no LLM calls, embeddings, or vector database. Works with Claude,
|
|
12
12
|
Cursor, GitHub Copilot, Aider, Windsurf, local LLMs, and MCP.
|
|
13
13
|
|
|
14
|
-
# Version: 8.
|
|
14
|
+
# Version: 8.22.0 | Benchmark: sigmap-v8.22-main (2026-07-27)
|
|
15
15
|
# Source: auto-generated from package.json, version.json, benchmarks/latest.json, src/mcp/tools.js, src/config/defaults.js
|
|
16
16
|
# Regenerate: npm run generate:llms | Validate: npm run validate:llms
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
-
## Core metrics (benchmark: sigmap-v8.
|
|
20
|
+
## Core metrics (benchmark: sigmap-v8.22-main, 2026-07-27)
|
|
21
21
|
|
|
22
22
|
| Metric | Without SigMap | With SigMap |
|
|
23
23
|
|--------|----------------|-------------|
|
|
24
|
-
| Retrieval hit@5 |
|
|
24
|
+
| Retrieval hit@5 | 44.8% (single-shot grep) | 82.2% (1.59× lift) |
|
|
25
25
|
| Token reduction | — | 96.8% average |
|
|
26
|
-
| Task-success proxy (modeled) | — |
|
|
27
|
-
| Prompts per task | 2.84 | 1.
|
|
26
|
+
| Task-success proxy (modeled) | — | 64.8% |
|
|
27
|
+
| Prompts per task | 2.84 | 1.53 (46.1% fewer) |
|
|
28
28
|
| Supported languages | — | 33 |
|
|
29
29
|
| MCP tools | — | 20 |
|
|
30
30
|
| npm runtime dependencies | — | 0 |
|
package/llms.txt
CHANGED
|
@@ -11,7 +11,7 @@ ranking keeps the relevant context in scope (cutting tokens ~97% as a side
|
|
|
11
11
|
effect), with no LLM calls, embeddings, or vector database. Works with Claude,
|
|
12
12
|
Cursor, GitHub Copilot, Aider, Windsurf, local LLMs, and MCP.
|
|
13
13
|
|
|
14
|
-
# Version: 8.
|
|
14
|
+
# Version: 8.22.0 | Benchmark: sigmap-v8.22-main (2026-07-27)
|
|
15
15
|
# Source: auto-generated from package.json, version.json, benchmarks/latest.json, src/mcp/tools.js, src/config/defaults.js
|
|
16
16
|
# Regenerate: npm run generate:llms | Validate: npm run validate:llms
|
|
17
17
|
|
|
@@ -23,12 +23,12 @@ Cursor, GitHub Copilot, Aider, Windsurf, local LLMs, and MCP.
|
|
|
23
23
|
- No blast-radius awareness before editing a hub file — `--impact` shows every file a change touches.
|
|
24
24
|
- Pasted stack traces, CI logs, and JSON bloat the prompt — `squeeze` minimizes them and enriches the top frame from the symbol index.
|
|
25
25
|
|
|
26
|
-
## Core metrics (benchmark: sigmap-v8.
|
|
26
|
+
## Core metrics (benchmark: sigmap-v8.22-main, 2026-07-27)
|
|
27
27
|
|
|
28
|
-
- hit@5 retrieval:
|
|
28
|
+
- hit@5 retrieval: 82.2% vs 44.8% single-shot grep baseline (1.59× lift)
|
|
29
29
|
- Token reduction: 96.8% average across benchmark repos
|
|
30
|
-
- Task-success proxy:
|
|
31
|
-
- Prompts per task: 1.
|
|
30
|
+
- Task-success proxy: 64.8% (modeled from retrieval tiers, not measured LLM sessions)
|
|
31
|
+
- Prompts per task: 1.53 vs 2.84 baseline (46.1% fewer, modeled)
|
|
32
32
|
- Languages: 33 supported · MCP tools: 20
|
|
33
33
|
- Dependencies: zero npm runtime dependencies · fully offline
|
|
34
34
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sigmap",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.22.0",
|
|
4
4
|
"description": "The deterministic, verifiable grounding layer for AI code work — a zero-dependency signature-and-evidence map that grounds Claude, Cursor, Copilot, Aider, Windsurf, local LLMs & MCP agents against your real code (repo + installed libraries) so they stop hallucinating files, imports & APIs. Runs offline via npx; byte-stable output; ~97% token reduction as proof.",
|
|
5
5
|
"main": "packages/core/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Task-corpus hygiene (A3, v8.22 "Hard Corpus").
|
|
5
|
+
*
|
|
6
|
+
* A benchmark query "leaks" when it shares a token with the basenames of its
|
|
7
|
+
* expected files — hit@5 then partly measures filename matching, not
|
|
8
|
+
* retrieval. The criterion is deterministic and reuses the production
|
|
9
|
+
* tokenizer (identifier splitting + stemming from src/retrieval/bm25.js), so
|
|
10
|
+
* "payments" leaks against payment.js and "InterceptorManager" leaks against
|
|
11
|
+
* "interceptor manager" the same way the ranker would see them.
|
|
12
|
+
*
|
|
13
|
+
* Tasks carry an optional `split` field: 'hard' tasks MUST be leak-free
|
|
14
|
+
* (validateTasks reports them as violations); 'easy' tasks (the default) may
|
|
15
|
+
* leak — that is what makes them easy.
|
|
16
|
+
*
|
|
17
|
+
* Size buckets group repos by indexed file count so large repos stop being
|
|
18
|
+
* averaged away by tiny ones. Thresholds are the rough tertiles of the
|
|
19
|
+
* current benchmarks/repos corpus (43 repos, 27–3450 source files).
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const { tokenize } = require('../retrieval/bm25');
|
|
23
|
+
|
|
24
|
+
const BUCKET_LIMITS = { small: 200, medium: 1000 }; // files; large = above medium
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Stemmed tokens of a file path's basename (extension stripped).
|
|
28
|
+
* @param {string} filePath
|
|
29
|
+
* @returns {string[]}
|
|
30
|
+
*/
|
|
31
|
+
function basenameTokens(filePath) {
|
|
32
|
+
const base = String(filePath).split('/').pop() || '';
|
|
33
|
+
return tokenize(base.replace(/\.[^.]*$/, ''));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Leaked tokens between a query and its expected files' basenames.
|
|
38
|
+
* @param {string} query
|
|
39
|
+
* @param {string[]} expectedFiles
|
|
40
|
+
* @returns {{ leaked: string[], clean: boolean }}
|
|
41
|
+
*/
|
|
42
|
+
function queryLeakage(query, expectedFiles) {
|
|
43
|
+
const qToks = new Set(tokenize(query));
|
|
44
|
+
const leaked = new Set();
|
|
45
|
+
for (const f of expectedFiles || []) {
|
|
46
|
+
for (const t of basenameTokens(f)) {
|
|
47
|
+
if (qToks.has(t)) leaked.add(t);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return { leaked: [...leaked].sort(), clean: leaked.size === 0 };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Validate a task list: every task gets a leakage result; hard-split tasks
|
|
55
|
+
* that leak are violations.
|
|
56
|
+
* @param {Array<{id?:string, query:string, expected_files?:string[], split?:string}>} tasks
|
|
57
|
+
* @returns {{ results: object[], hardViolations: object[] }}
|
|
58
|
+
*/
|
|
59
|
+
function validateTasks(tasks) {
|
|
60
|
+
const results = [];
|
|
61
|
+
const hardViolations = [];
|
|
62
|
+
for (const t of tasks || []) {
|
|
63
|
+
const split = t.split === 'hard' ? 'hard' : 'easy';
|
|
64
|
+
const { leaked, clean } = queryLeakage(t.query, t.expected_files);
|
|
65
|
+
const row = { id: t.id || '?', split, leaked, clean };
|
|
66
|
+
results.push(row);
|
|
67
|
+
if (split === 'hard' && !clean) hardViolations.push(row);
|
|
68
|
+
}
|
|
69
|
+
return { results, hardViolations };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Size bucket for a repo by indexed file count.
|
|
74
|
+
* @param {number} fileCount
|
|
75
|
+
* @returns {'small'|'medium'|'large'}
|
|
76
|
+
*/
|
|
77
|
+
function sizeBucket(fileCount) {
|
|
78
|
+
if (fileCount < BUCKET_LIMITS.small) return 'small';
|
|
79
|
+
if (fileCount <= BUCKET_LIMITS.medium) return 'medium';
|
|
80
|
+
return 'large';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
module.exports = { basenameTokens, queryLeakage, validateTasks, sizeBucket, BUCKET_LIMITS };
|
package/src/eval/runner.js
CHANGED
|
@@ -124,7 +124,7 @@ function estimateTokens(sigs) {
|
|
|
124
124
|
|
|
125
125
|
/**
|
|
126
126
|
* Load tasks from a JSONL file.
|
|
127
|
-
* Each line: { id, query, expected_files, repo }
|
|
127
|
+
* Each line: { id, query, expected_files, repo, split? ('easy'|'hard') }
|
|
128
128
|
* Invalid or blank lines are silently skipped.
|
|
129
129
|
* @param {string} tasksFile - absolute or relative path
|
|
130
130
|
* @returns {Array<{id:string, query:string, expected:string[], repo:string}>}
|
|
@@ -144,6 +144,7 @@ function loadTasks(tasksFile) {
|
|
|
144
144
|
query: obj.query,
|
|
145
145
|
expected: obj.expected_files,
|
|
146
146
|
repo: obj.repo || '.',
|
|
147
|
+
split: obj.split === 'hard' ? 'hard' : 'easy',
|
|
147
148
|
});
|
|
148
149
|
}
|
|
149
150
|
} catch {
|
package/src/mcp/server.js
CHANGED